关于FreeRTOS中断服务函数发送二值信号量之后的任务切换理解

在串口中断服务函数中,发送完二值信号量之后,调用了函数

portYIELD_FROM_ISR(xHigherPriorityTaskWoken);         //如果需要的话进行一次任务切换


那么在任务间发送信号量,是否也需要调用某个函数,实现“如果需要的话进行一次任务切换”呢?


首先先查看这个函数的定义,此函数是个宏定义:
#define portEND_SWITCHING_ISR( xSwitchRequired ) if( xSwitchRequired != pdFALSE ) portYIELD()
#define portYIELD_FROM_ISR( x ) portEND_SWITCHING_ISR( x )
通过上面两句话,可以得出,此函数的作用是判断变量xSwitchRequired 是否为pdFALSE ,如果不等于pdFALSE ,则调用一次portYIELD(),这个函数的作用是进行上下文切换,其实就是开启一次任务调度。那么是否开启任务调度,关键就看变量xSwitchRequired 是否为pdFALSE,而通过查询所有对变量xSwitchRequired 赋值的语句都集中在函数BaseType_t xTaskIncrementTick( void )中,通过对此函数解析,得出结论:如果变量xSwitchRequired 不等于pdFALSE,就代表处于就绪态任务的优先级比当前运行的任务优先级高。

然后,要搞清楚为什么中断服务函数中释放完信号量需要添加这个函数,我个人的理解是,因为中断结束之后,此时处于运行态的任务肯定是发生中断前的任务,而中断服务函数中发送的信号量,肯定是希望需要接收的任务第一时间接收到,那么最快的办法肯定是从最高优先级的任务开始运行,为了达到这个目的,就需要进行一次任务调度,这样就绪态列表中优先级最高的任务将在这个函数运行之后开始运行。

最后,任务中如果也有释放信号量的操作,那么之后是否也要添加这个函数,我个人理解是可用可不用,如果希望及时得到响应,就加上,如果不急的话,也可以不用。而中断如果不用的话,将得不到及时响应,那么就会漏掉下一次中断的数据。


总结:此函数的目的就是希望最高优先级可以及时的和发送信号量的中断或任务同步,看实际应用中是否需要而判断是否需要添加,

 

以上都是我个人的理解,在网上找了很多资料,也没有哪个写到任务中发送完二值信号量之后是否需要添加任务切换的函数。野火,正点原子,安富莱的例程中,都是中断中加了,但是任务中没加,具体的也没有解释。本人对于FreeRTOS的源码理解水平还处于小白级别,如果有大神看到本文,如果有什么高见,麻烦给与点评,不胜感激。

 

参考资料:正点原子的FreeRTOS源码解析教程

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是使用FreeRTOS和STM32HAL库实现二进制信号量和串口3中断释放信号量的例程: ```c #include "FreeRTOS.h" #include "task.h" #include "semphr.h" #include "stm32f4xx_hal.h" #include "string.h" // 定义二进制信号量 SemaphoreHandle_t xBinarySemaphore; // 定义串口3句柄 UART_HandleTypeDef huart3; // 串口3中断处理函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { // 发送信号量 BaseType_t xHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken); // 如果发生了任务调度,则需要进行上下文切换 portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } // 任务1:等待二进制信号量 void vTask1(void *pvParameters) { for (;;) { // 等待信号量 xSemaphoreTake(xBinarySemaphore, portMAX_DELAY); // 处理数据 char buffer[50]; memset(buffer, 0, sizeof(buffer)); sprintf(buffer, "Received data: %c\r\n", (char)huart3.Instance->DR); HAL_UART_Transmit(&huart3, (uint8_t *)buffer, strlen(buffer), HAL_MAX_DELAY); } } // 任务2:发送数据 void vTask2(void *pvParameters) { char data = 'A'; for (;;) { // 发送数据 HAL_UART_Transmit(&huart3, (uint8_t *)&data, 1, HAL_MAX_DELAY); // 等待一段时间 vTaskDelay(pdMS_TO_TICKS(1000)); } } int main(void) { // 初始化FreeRTOS内核 HAL_Init(); SystemClock_Config(); // 初始化二进制信号量 xBinarySemaphore = xSemaphoreCreateBinary(); // 初始化串口3 huart3.Instance = USART3; huart3.Init.BaudRate = 115200; huart3.Init.WordLength = UART_WORDLENGTH_8B; huart3.Init.StopBits = UART_STOPBITS_1; huart3.Init.Parity = UART_PARITY_NONE; huart3.Init.Mode = UART_MODE_TX_RX; huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE; HAL_UART_Init(&huart3); // 启动任务 xTaskCreate(vTask1, "Task 1", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, NULL); // 启动调度器 vTaskStartScheduler(); // 永远不会执行到这里 return 0; } ``` 在上面的例程中,我们使用`xSemaphoreCreateBinary()`函数创建了一个二进制信号量,并在串口3接收到数据时通过`xSemaphoreGiveFromISR()`函数发送信号量。此外,我们还定义了两个任务任务1等待二进制信号量并处理数据,任务2定时发送数据。当任务1等待信号量时,它会被阻塞直到信号量发送。当任务2发送数据时,它会在发送完数据后等待一段时间,然后再次发送数据。 请注意,上面的代码只是一个示例,您需要根据自己的需求进行修改。特别是在使用HAL库时,请根据您的实际情况修改相应的函数调用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值