使用 FreeRTOS 进行基于事件的任务管理
Event-based task management using FreeRTOS
我正在尝试使用 esp32 学习 C。在查看 FreeRTOS 的确切工作原理时,我发现了以下关于如何使用任务和最佳实践等的页面。
https://www.freertos.org/implementing-a-FreeRTOS-task.html
根据此页面,为防止饥饿,任务应基于事件。关于我要实现的目标,我将尝试提供一个非常简化的示例。
背景
我有一个 LCD 屏幕,它应该显示来自传感器的数据。 LCD 上显示的数据将使用一项任务完成,根据文档,该任务不应退出,并且应由事件驱动以防止饥饿。
我有一种方法可以控制液晶屏上显示的数据,那就是旋转编码器。可以点击这个编码器,这应该会刷新传感器的数据。
问题
在此特定上下文中,我将如何实施 FreeRTOS 页面上描述的基于事件的任务?我查看了他们 github 上的文档和“简单”示例项目,但作为 C 语言和嵌入式领域的初学者,它们非常令人难以抗拒。
简单的演示代码
void update_sensor_task(void *pvParameters)
{
// Ensure the task keeps on running
for( ; ; )
{
if(event_update_sensor) // How would I be able to notify the task that this should be run?
{
// update the data
}
}
// Tasks should not be returning, but if they happen to do so, ensure a clean exit
vTaskDelete(NULL);
}
void screen_temperature_task(void *pvParameters)
{
for(; ;)
{
if(event_sensor_updated)
{
// Update the lcd screen with the new data
}
}
vTaskDelete(NULL);
}
void on_rotary_clicked(void *pvParameters)
{
// Notify the sensor task that it should be updating?
}
编辑:
通过使用被标记为正确答案的内容,我已经通过以下方式实现它:
/* Queue used to send and receive the data */
QueueHandle_t xStructQueue = NULL;
/* Struct which shall be used to hold and pass around the data for the LCD screen*/
struct LcdData
{
int current_temp;
int current_humidity;
} xLcdData;
void initialize_queues(void)
{
xLcdData.current_humidity = 0;
xLcdData.current_temp = 0;
xStructQueue = xQueueCreate(
/* The maximum number of items the queue can hold*/
5,
/* The size of each struct, which the queue should be able to hold */
sizeof( xLcdData )
);
if(xStructQueue == NULL)
{
ESP_LOGE(TAG, "Queue has not been initialized successfully");
}
}
void screen_temperature_task_simplified(void *pvParameters)
{
int counter = 0;
for(; ;)
{
struct LcdData xReceivedStructure;
BaseType_t result;
result = xQueueReceive(xStructQueue, &xReceivedStructure, ( TickType_t ) 10);
if(result == pdPASS)
{
counter = counter + 1;
char snum_current_counter[12];
sprintf(snum_current_counter, "%d", counter);
i2c_lcd1602_clear (lcd_info);
i2c_lcd1602_write_string (lcd_info, snum_current_counter);
}
}
vTaskDelete(NULL);
}
void update_sensor_struct(void)
{
xLcdData.current_temp = DHT11_read().temperature;
xLcdData.current_humidity = DHT11_read().humidity;
// Log the results in the console
printf("Temperature is %d \n", xLcdData.current_temp);
printf("Humidity is %d\n", xLcdData.current_humidity);
ESP_LOGI(TAG, "Data has been updated");
}
void on_rotary_clicked_simplified()
{
ESP_LOGI(TAG, "Rotary encoder has been clicked!");
// Update the struct which holds the data
update_sensor_struct();
/* Send the entire struct to the queue */
xQueueSend(
/* The handle of the queue */
xStructQueue,
/* The adress of the struct which should be sent */
(void *) &xLcdData,
/* Block time of 0 says don't block if the queue is already full.
Check the value returned by xQueueSend() to know if the message
was sent to the queue successfully. */
( TickType_t ) 0
);
}
我使用 FRTOS 和事件驱动开发。
这里的典型流程是:
for(;;)
{
BaseType_t result;
result = xQueueReceive(LCD_Event_Queue, &someLCDEvent, QUEUE_TIMEOUT);
if (result == pdPASS)
{
/* We have new event data in someLCDEvent; Use that data to update the LCD */
}
else
{
/* No new event, do some brief idle-time processing if necessary */
}
}
简而言之,等待新事件到达 QUEUE_TIMEOUT 时间。
如果新事件在该时间范围内成功到达,则处理该事件中的数据并更新您的屏幕。
如果新事件没有到来,您还有机会做一些其他的维护工作。
设计和定义someLCDEvent的结构类型,并将数据放入队列是一个很大的话题,具体取决于你的具体项目。
我正在尝试使用 esp32 学习 C。在查看 FreeRTOS 的确切工作原理时,我发现了以下关于如何使用任务和最佳实践等的页面。
https://www.freertos.org/implementing-a-FreeRTOS-task.html
根据此页面,为防止饥饿,任务应基于事件。关于我要实现的目标,我将尝试提供一个非常简化的示例。
背景
我有一个 LCD 屏幕,它应该显示来自传感器的数据。 LCD 上显示的数据将使用一项任务完成,根据文档,该任务不应退出,并且应由事件驱动以防止饥饿。
我有一种方法可以控制液晶屏上显示的数据,那就是旋转编码器。可以点击这个编码器,这应该会刷新传感器的数据。
问题
在此特定上下文中,我将如何实施 FreeRTOS 页面上描述的基于事件的任务?我查看了他们 github 上的文档和“简单”示例项目,但作为 C 语言和嵌入式领域的初学者,它们非常令人难以抗拒。
简单的演示代码
void update_sensor_task(void *pvParameters)
{
// Ensure the task keeps on running
for( ; ; )
{
if(event_update_sensor) // How would I be able to notify the task that this should be run?
{
// update the data
}
}
// Tasks should not be returning, but if they happen to do so, ensure a clean exit
vTaskDelete(NULL);
}
void screen_temperature_task(void *pvParameters)
{
for(; ;)
{
if(event_sensor_updated)
{
// Update the lcd screen with the new data
}
}
vTaskDelete(NULL);
}
void on_rotary_clicked(void *pvParameters)
{
// Notify the sensor task that it should be updating?
}
编辑:
通过使用被标记为正确答案的内容,我已经通过以下方式实现它:
/* Queue used to send and receive the data */
QueueHandle_t xStructQueue = NULL;
/* Struct which shall be used to hold and pass around the data for the LCD screen*/
struct LcdData
{
int current_temp;
int current_humidity;
} xLcdData;
void initialize_queues(void)
{
xLcdData.current_humidity = 0;
xLcdData.current_temp = 0;
xStructQueue = xQueueCreate(
/* The maximum number of items the queue can hold*/
5,
/* The size of each struct, which the queue should be able to hold */
sizeof( xLcdData )
);
if(xStructQueue == NULL)
{
ESP_LOGE(TAG, "Queue has not been initialized successfully");
}
}
void screen_temperature_task_simplified(void *pvParameters)
{
int counter = 0;
for(; ;)
{
struct LcdData xReceivedStructure;
BaseType_t result;
result = xQueueReceive(xStructQueue, &xReceivedStructure, ( TickType_t ) 10);
if(result == pdPASS)
{
counter = counter + 1;
char snum_current_counter[12];
sprintf(snum_current_counter, "%d", counter);
i2c_lcd1602_clear (lcd_info);
i2c_lcd1602_write_string (lcd_info, snum_current_counter);
}
}
vTaskDelete(NULL);
}
void update_sensor_struct(void)
{
xLcdData.current_temp = DHT11_read().temperature;
xLcdData.current_humidity = DHT11_read().humidity;
// Log the results in the console
printf("Temperature is %d \n", xLcdData.current_temp);
printf("Humidity is %d\n", xLcdData.current_humidity);
ESP_LOGI(TAG, "Data has been updated");
}
void on_rotary_clicked_simplified()
{
ESP_LOGI(TAG, "Rotary encoder has been clicked!");
// Update the struct which holds the data
update_sensor_struct();
/* Send the entire struct to the queue */
xQueueSend(
/* The handle of the queue */
xStructQueue,
/* The adress of the struct which should be sent */
(void *) &xLcdData,
/* Block time of 0 says don't block if the queue is already full.
Check the value returned by xQueueSend() to know if the message
was sent to the queue successfully. */
( TickType_t ) 0
);
}
我使用 FRTOS 和事件驱动开发。
这里的典型流程是:
for(;;)
{
BaseType_t result;
result = xQueueReceive(LCD_Event_Queue, &someLCDEvent, QUEUE_TIMEOUT);
if (result == pdPASS)
{
/* We have new event data in someLCDEvent; Use that data to update the LCD */
}
else
{
/* No new event, do some brief idle-time processing if necessary */
}
}
简而言之,等待新事件到达 QUEUE_TIMEOUT 时间。
如果新事件在该时间范围内成功到达,则处理该事件中的数据并更新您的屏幕。
如果新事件没有到来,您还有机会做一些其他的维护工作。
设计和定义someLCDEvent的结构类型,并将数据放入队列是一个很大的话题,具体取决于你的具体项目。