ESP-32 中的 ISR(中断服务例程)是如何工作的,我们可以暂停或恢复 ISR 内部的任务吗?

问题描述 投票:0回答:1

我在使用 ISR (ESP-32) 切换任务时遇到问题。

下面是相同的代码。

struct Button {
  const uint8_t pin;
  volatile uint8_t numberKeyPresses;
};

# define buttonpin 15
# define ledpin 2
#define photopin 34
#define threshold 100
#define buffersize 16000
#define interval 1 //interval in milliseconds

TaskHandle_t(Rx1_handle);
TaskHandle_t(Rx2_handle);
TaskHandle_t(Tx_handle);

Button button1 = {buttonpin, 0};
volatile bool pressed = false;

void IRAM_ATTR isr() {
  static uint32_t lastPressTime = 0; // Store the last press time to debounce the button
  uint32_t currentTime = millis(); // Get the current time

  // Debounce logic to avoid multiple triggers in quick succession
  if (currentTime - lastPressTime > 400) {  // 200ms debounce time
    lastPressTime = currentTime;
    
    // Increment the press count (wrap around after 2 presses, for example)
    button1.numberKeyPresses = (button1.numberKeyPresses + 1) % 2;  // 2 total presses before wrapping around

    // Perform actions based on the number of presses
    switch (button1.numberKeyPresses) {
      case 0: // First press (or after 5 presses)

        vTaskResume(Rx1_handle);
        vTaskResume(Rx2_handle);
        vTaskSuspend(Tx_handle);

        // xTaskCreatePinnedToCore(Rx1, "Signal Recieving", 100000, NULL, 1, &Rx1_handle, 1);
        // xTaskCreatePinnedToCore(Rx2, "Signal Processing", 10000, NULL, 1, &Rx2_handle, 0);
        // vTaskDelete(Tx_handle);
        break;

      case 1: // Second press
        // Your custom logic for 2nd press, e.g., alternate functionality
        vTaskSuspend(Rx1_handle);
        vTaskSuspend(Rx2_handle);
        vTaskResume(Tx_handle);

        // vTaskDelete(Rx1_handle);
        // vTaskDelete(Rx2_handle);
        // xTaskCreatePinnedToCore(Tx, "Signal Transmitting", 10000, NULL, 1, &Tx_handle, 1);
        break;

      default:
        break;
    }
  }  
}


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

  pinMode(ledpin, OUTPUT);

  // Testing if LED is Working
  digitalWrite(ledpin, HIGH);
  delay(500);
  digitalWrite(ledpin, LOW);

  pinMode(buttonpin, INPUT_PULLUP);
  attachInterrupt(button1.pin, isr, RISING);

  xTaskCreatePinnedToCore(
    Rx1,         // Function to implement the task
    "Signal Recieving",       // Name of the task
    10000,           // Stack size in words
    NULL,            // Task input parameter
    1,               // Priority of the task
    &Rx1_handle,            // Task handle
    0               // Core where the task should run (Core 0)
  );

  xTaskCreatePinnedToCore(
    Rx2,         // Function to implement the task
    "Signal Recieving",       // Name of the task
    10000,           // Stack size in words
    NULL,            // Task input parameter
    1,               // Priority of the task
    &Rx2_handle,            // Task handle
    1                // Core where the task should run (Core 0)
  );

  xTaskCreatePinnedToCore(
    Tx,         // Function to implement the task
    "Signal Transmitting",       // Name of the task
    10000,           // Stack size in words
    NULL,            // Task input parameter
    1,               // Priority of the task
    &Tx_handle,            // Task handle
    1                // Core where the task should run (Core 0)
  );

  vTaskResume(Rx1_handle);
  vTaskResume(Rx2_handle);
  vTaskSuspend(Tx_handle);
}

String binData_rx = "";

char binaryToChar(String binary) {
  int value = 0;
  for (int i = 0; i < 8; i++) {
    value <<= 1;  // Shift left to make space for the next bit
    if (binary.charAt(i) == '1') {
      value = value | 1;  // Set the least significant bit if it's '1'
    }
  }
  return (char)value;  // Return the resulting character
}

void processData() {
  int indx = binData_rx.indexOf("00000010");
  // Serial.println(indx);
  binData_rx.remove(0, indx+8);
  while(binData_rx.length()) {
    String subData = binData_rx.substring(0, 8);
    binData_rx.remove(0, 8);
    if(subData == "00000011") break;
    char ch = binaryToChar(subData);
    // processedData += ch;
    Serial.print(ch);
    vTaskDelay(interval * 8 / portTICK_PERIOD_MS); //in milliseconds
    // vTaskDelay(interval * 8 ); // in microseconds
  }
  binData_rx.clear();
  Serial.println("");
}

void Rx1(void *parameter) { // Recieves Signal
  Serial.println("Signal Recieving");
  for(;;) {
    int value = analogRead(photopin);
    if(value > threshold) binData_rx += '0';
    else binData_rx += '1';

    vTaskDelay(interval / portTICK_PERIOD_MS); // in milli seconds
    // vTaskDelay(interval); // in micro seconds
  }
}

void Rx2(void *parameter) { // Processes the Signal
  Serial.println("Singal Processing");
  for(;;) {
    if(binData_rx.length() > buffersize) {
    binData_rx.remove(0, 15900);
    }
    else if(binData_rx.indexOf("00000010") > -1) {
      binData_rx.remove(0, binData_rx.indexOf("00000010"));
      vTaskDelay(interval * 10 / portTICK_PERIOD_MS); // in milli seconds
      // vTaskDelay(interval * 10); // in micro seconds

      processData();
    }

    vTaskDelay(500 / portTICK_PERIOD_MS); // in milli seconds
    // vTaskDelay(500 * 1000); // in micro seconds
  }
}

// Tx part

String stringToBinary(String str) {
  String output = "";
  for (int i = 0; i < str.length(); i++) {
    char c = str.charAt(i);
    // Print the binary representation of each character
    for (int j = 7; j >= 0; j--) {
      
      output += String((c >> j) & 1);
    }
    // output += " ";
  }
  return output;
}

void Tx(void *parameter) {
  Serial.println("Signal Transmitting");
  for(;;) {
    if(Serial.available() > 0) {

      String input = Serial.readStringUntil('\n');
      String binData_tx = "00000010"+stringToBinary(input)+"0000001100000011";
      //Serial.println(2);
      Serial.print( binData_tx);

      for(int i=0; i<binData_tx.length(); i++) {
        if(binData_tx.charAt(i) == '1') {
          digitalWrite(ledpin, HIGH);
        
          //delayMicroseconds(interval);
        } 
        else {
          digitalWrite(ledpin, LOW);
          //delayMicroseconds(interval);
        }

        // digitalWrite(ledPin, (binData[i] == '1') ? HIGH : LOW);
        delay(interval); // delay of 200ms
      }

      binData_tx.clear();
      Serial.println();

      digitalWrite(ledpin, LOW);
    }
  }
}

void loop() {

}

我一直在从事Li-Fi 通信项目。我在 Tx 和 Rx 端使用 ESP-32。出现的主要问题是我创建了多个任务,而且我希望单个任务应该在两个核心中都处于活动状态。

我已经创建了 任务1:信号接收 任务 2:信号处理 任务3:信号传输

我想使用 ISR 在这些任务之间切换,以便同时任务 1 和任务 2 处于活动状态,按下按钮时只有任务 3 处于活动状态,依此类推。

arduino esp32 communication freertos
1个回答
0
投票

您试图通过告诉调度程序在事件发生时激活哪个线程/任务来直接控制调度程序。我会用另一种方式来解决这个问题。

FreeRTOS(以及许多其他 RTOS)中的标准模式使用线程信号工具解决了这个问题。简而言之,您的高优先级任务(在本例中为

Tx
)被阻塞,正在等待线程通信对象 - 例如活动组。当发生中断并且其 ISR 想要启动某些处理时,它会向事件组发出信号,表明您的高优先级
Tx
任务正在等待。假设
Tx
比其他就绪任务具有更高的优先级,当 ISR 退出时,调度程序立即切换到它。

// Create an event flag that signifies button press
const uint32_t EVENT_BUTTON = 0x01;
// Create an event group for task communication
EventGroupHandle_t g_evGroup = xEventGroupCreate();

// Create task Tx with higher priority than other tasks
xTaskCreate(Tx, "Signal Transmitting", 10000, NULL, 2, &Tx_handle);

void IRAM_ATTR isr() {
  BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  if (buttonPressed()) {
    // Signal event group to wake up task Tx
    if (xEventGroupSetBitsFromISR(g_evGroup, g_evGroup, &xHigherPriorityTaskWoken)) {
      // See portYIELD_FROM_ISR() documentation for the details
      portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }
  }
}

void Tx(void *parameter) {
  while (true) {
    // Waiting for ISR to signal us
    xEventGroupWaitBits(g_evGroup, EVENT_BUTTON, pdTRUE, pdFALSE, portMAX_DELAY);
    // Do processing
  }
}

作为参考资料,我推荐他们的书 Mastering the FreeRTOS Real Time Kernel - A Hands On Tutorial Guide

© www.soinside.com 2019 - 2024. All rights reserved.