我在使用 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 处于活动状态,依此类推。
您试图通过告诉调度程序在事件发生时激活哪个线程/任务来直接控制调度程序。我会用另一种方式来解决这个问题。
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。