首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在FreeRTOS中读取带有中断的电机编码器值?

如何在FreeRTOS中读取带有中断的电机编码器值?
EN

Stack Overflow用户
提问于 2022-03-26 07:36:33
回答 1查看 654关注 0票数 0

我正在做一个项目,我需要从四个电机编码器获得精确的角速度。我正在使用ESP32 DEVKIT-V1模块,并希望使用四个中断,这将触发当每个电机编码器开关状态。这产生约700赫兹的平方信号(周期为1,42毫秒)。由于时间限制,这需要在一个核上完成,因为处理器不能错过任何滴答。这就是我决定使用FreeRTOS的原因。由于ESP32的滴答率为1ms,它不能读取高于500 Hz (周期2 ms)的频率。

每次四次中断触发时,我都会调用getEncoderTickNumber()函数,但是,我只需要不断地重置ESP32。我还希望通过队列将蜱数(encoderValueA1 - A4)从函数getEncoderTickNumber()传递到getEncoderRPM()。

我仍然是C/C++的初学者,所以如果你能指出我正在犯的一些初学者的错误,我将非常感激。谢谢您抽时间见我。

代码语言:javascript
运行
复制
#include <Arduino.h>

// Motor encoder output pulse per rotation (AndyMark Neverest 60)
int ENC_COUNT_REV = 420;

// Pulse count from encoder
long encoderValueA1 = 0;
long encoderValueA2 = 0;
long encoderValueA3 = 0;
long encoderValueA4 = 0;

int currentStateMotorEncoderA1;
int currentStateMotorEncoderA2;
int currentStateMotorEncoderA3;
int currentStateMotorEncoderA4;

int previousStateMotorEncoderA1;
int previousStateMotorEncoderA2;
int previousStateMotorEncoderA3;
int previousStateMotorEncoderA4;

// Variable for RPM measuerment
int rpm1 = 0;
int rpm2 = 0;
int rpm3 = 0;
int rpm4 = 0;

#define INT_PIN1 17
#define INT_PIN2 18
#define INT_PIN3 19
#define INT_PIN4 16

#define PRIORITY_LOW 0
#define PRIORITY_HIGH 1

QueueHandle_t encoderQueueHandle;
#define QUEUE_LENGTH 4 //four rpm readings

long* pdata = &encoderValueA1;

void io_expander_interrupt()
{
   xQueueSendToBackFromISR(&encoderQueueHandle, &pdata, NULL);
}

///////////
// TASKS //
///////////

void getEncoderTickNumber(void *parameter)
{
  while (1)
  {

    if (xQueueReceiveFromISR(&encoderQueueHandle, &pdata, NULL) == pdTRUE)
    {

    currentStateMotorEncoderA1 = digitalRead(INT_PIN1);
    currentStateMotorEncoderA2 = digitalRead(INT_PIN2);
    currentStateMotorEncoderA3 = digitalRead(INT_PIN3);
    currentStateMotorEncoderA4 = digitalRead(INT_PIN4);

     if (currentStateMotorEncoderA1 != previousStateMotorEncoderA1)
    {
      encoderValueA1++;
    }

    if (currentStateMotorEncoderA2 != previousStateMotorEncoderA2)
    {
      encoderValueA2++;
    }

    if (currentStateMotorEncoderA3 != previousStateMotorEncoderA3)
    {
      encoderValueA3++;
    }

    if (currentStateMotorEncoderA4 != previousStateMotorEncoderA4)
    {
      encoderValueA4++;
    }

    previousStateMotorEncoderA1 = currentStateMotorEncoderA1;
    previousStateMotorEncoderA2 = currentStateMotorEncoderA2;
    previousStateMotorEncoderA3 = currentStateMotorEncoderA3;
    previousStateMotorEncoderA4 = currentStateMotorEncoderA4;
    }
  }
}

void getEncoderRPM(void *parameter)
{
 while (1)
  {
    rpm1 = (encoderValueA1 * 60) / ENC_COUNT_REV;
    rpm2 = (encoderValueA2 * 60) / ENC_COUNT_REV;
    rpm3 = (encoderValueA3 * 60) / ENC_COUNT_REV;
    rpm4 = (encoderValueA4 * 60) / ENC_COUNT_REV;

    encoderValueA1 = 0;
    encoderValueA2 = 0;
    encoderValueA3 = 0;
    encoderValueA4 = 0;

    vTaskDelay(1000 / portTICK_RATE_MS);
  }
}

void printData(void *parameter)
{
  while (1)
  {
    Serial.print("1:");
    Serial.print(rpm1);
    Serial.print("  2:");
    Serial.print(rpm2);
    Serial.print("  3:");
    Serial.print(rpm3);
    Serial.print("  4:");
    Serial.println(rpm4);
    vTaskDelay(500 / portTICK_RATE_MS);
  }
}

void setup()
{
  Serial.begin(115200);

  pinMode(INT_PIN1, INPUT);
  attachInterrupt(INT_PIN1, getEncoderTickNumber, RISING); 
  pinMode(INT_PIN2, INPUT);
  attachInterrupt(INT_PIN2, getEncoderTickNumber, RISING);
  pinMode(INT_PIN3, INPUT);
  attachInterrupt(INT_PIN3, getEncoderTickNumber, RISING);
  pinMode(INT_PIN4, INPUT);
  attachInterrupt(INT_PIN4, getEncoderTickNumber, RISING);

  // Create the queue
  encoderQueueHandle = xQueueCreate(QUEUE_LENGTH, sizeof(uint32_t));

  xTaskCreatePinnedToCore(    // Use xTaskCreate() in vanilla FreeRTOS
      getEncoderTickNumber,   // Function to be called
      "getEncoderTickNumber", // Name of task
      1024,                   // Stack size (bytes in ESP32, words in FreeRTOS) inside the heap
      NULL,                   // Parameter to pass to function
      PRIORITY_LOW,           // Task priority (0 to configMAX_PRIORITIES - 1)
      NULL,                   // Task handle
      1);                     // Run on one core for demo purposes (ESP32 only)

  xTaskCreatePinnedToCore( // Use xTaskCreate() in vanilla FreeRTOS
      printData,           // Function to be called
      "printData",         // Name of task
      1024,                // Stack size (bytes in ESP32, words in FreeRTOS) inside the heap
      NULL,                // Parameter to pass to function
      PRIORITY_LOW,        // Task priority (0 to configMAX_PRIORITIES - 1)
      NULL,                // Task handle
      0);                  // Run on one core for demo purposes (ESP32 only)

  xTaskCreatePinnedToCore( // Use xTaskCreate() in vanilla FreeRTOS
      getEncoderRPM,       // Function to be called
      "getEncoderRPM",     // Name of task
      1024,                // Stack size (bytes in ESP32, words in FreeRTOS)
      NULL,                // Parameter to pass to function
      PRIORITY_HIGH,       // Task priority (0 to configMAX_PRIORITIES - 1)
      NULL,                // Task handle
      0);                  // Run on one core for demo purposes (ESP32 only)

  vTaskDelete(NULL); // Deletes the setup/loop task now that we are finished setting up (optional)
}

void loop()
{

}
EN

回答 1

Stack Overflow用户

发布于 2022-03-26 08:33:22

在您的代码中有很多问题。让我们一个一个地检查一下,看看能不能把事情弄清楚。

首先,不要删除setup()中的任务

代码语言:javascript
运行
复制
vTaskDelete(NULL); // Deletes the setup/loop task now that we are finished setting up (optional)

Arduino将独自管理FreeRTOS任务,不要干预它。你可能只是用那条线造成了你的坠机。

其次是,您正在创建堆栈大小为1024字节的任务,这太小了。该任务可能会损坏堆栈并崩溃。对于简单的任务,从4096字节的堆栈大小开始,看看以后是否可以优化。顺便说一句,对于一个简单的实现来说,您根本不需要任何任务。

第三,您似乎不知道什么是中断,以及如何处理它。通过调用它,您将函数getEncoderTickNumber()作为中断处理程序附加到所有4个GPIO输入:

代码语言:javascript
运行
复制
  attachInterrupt(INT_PIN1, getEncoderTickNumber, RISING);
  attachInterrupt(INT_PIN2, getEncoderTickNumber, RISING);
  attachInterrupt(INT_PIN3, getEncoderTickNumber, RISING);
  attachInterrupt(INT_PIN4, getEncoderTickNumber, RISING);

函数getEncoderTickNumber()不能作为中断处理程序,因为它使用while(1)循环进行阻塞-它将快速触发看门狗并重新启动。此外,您已经将此函数用作在后台运行的任务(并且似乎期望来自中断处理程序的输入)。

最后,,您似乎有了一个更适合于中断处理程序的位置--函数io_expander_interrupt() --它目前没有任何有用的功能。我们来解决这个问题。

您需要4个中断处理程序,每个正在监视的GPIO中有一个。每个处理程序都附加到其各自的GPIO引脚上,当IO上升时触发,并且每个处理程序都进行自己的编码器计算。没有额外任务的简单实现如下所示:

代码语言:javascript
运行
复制
#include <Arduino.h>

// Motor encoder output pulse per rotation (AndyMark Neverest 60)
int ENC_COUNT_REV = 420;

// Pulse count from encoder. Must be volatile as it's shared between ISR and main task
volatile int encoderValueA1 = 0;
volatile int encoderValueA2 = 0;
volatile int encoderValueA3 = 0;
volatile int encoderValueA4 = 0;

#define INT_PIN1 17
#define INT_PIN2 18
#define INT_PIN3 19
#define INT_PIN4 16

void isr_rising_gpio1() {
  encoderValueA1++
}

void isr_rising_gpio2() {
  encoderValueA2++
}

void isr_rising_gpio3() {
  encoderValueA3++
}

void isr_rising_gpio4() {
  encoderValueA4++
}

void setup()
{
  Serial.begin(115200);

  pinMode(INT_PIN1, INPUT);
  attachInterrupt(INT_PIN1, isr_rising_gpio1, RISING); 
  pinMode(INT_PIN2, INPUT);
  attachInterrupt(INT_PIN2, isr_rising_gpio2, RISING);
  pinMode(INT_PIN3, INPUT);
  attachInterrupt(INT_PIN3, isr_rising_gpio3, RISING);
  pinMode(INT_PIN4, INPUT);
  attachInterrupt(INT_PIN4, isr_rising_gpio4, RISING);
}

void loop()
{
    int rpm1 = (encoderValueA1 * 60) / ENC_COUNT_REV;
    encoderValueA1 = 0;
    int rpm2 = (encoderValueA2 * 60) / ENC_COUNT_REV;
    encoderValueA2 = 0;
    int rpm3 = (encoderValueA3 * 60) / ENC_COUNT_REV;
    encoderValueA3 = 0;
    int rpm4 = (encoderValueA4 * 60) / ENC_COUNT_REV;
    encoderValueA4 = 0;

    Serial.print("1:");
    Serial.print(rpm1);
    Serial.print("  2:");
    Serial.print(rpm2);
    Serial.print("  3:");
    Serial.print(rpm3);
    Serial.print("  4:");
    Serial.println(rpm4);

    vTaskDelay(pdMS_TO_TICKS(1000));
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71626162

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档