原创 九、freeRTOS 二值信号量

2020-8-23 16:54 2218 23 4 分类: 汽车电子 文集: FreeRTOS

信号量

1 信号量用于共享资源的访问:

2 信号量用于任务同步:

为什么一直说在中断服务函数中,不能够做太多的事情?

在进入中断服务函数时,低优先级的中断就不能响应,同类型的中断也无法响应,所以就要求ISR一定要短,快进快出。

最好的解决方案时,在中断服务函数中发送一个信号量,在任务中等待信号量,实现任务同步。

 

二值信号量

二值信号量简介:

二值信号量其实就是一个只有一个队列项的队列,这个特殊的队列要么是满的,要么是空的,这不正好就是二值的吗? 任务和中断使用这个特殊队列不用在乎队列中存的是什么消息,只需要知道这个队列是满的还是空的。可以利用这个机制来完成任务与中断之间的同步。

二值信号量执行流程:
 

创建信号量:

动态创建二值信号量:

实际上,信号量就是通过队列来实现的,源码如下:

  1. #define semSEMAPHORE_QUEUE_ITEM_LENGTH ((uint8_t)0U)
  2. #if (configSUPPORT_DYNAMIC_ALLOCATION == 1)
  3. #define xSemaphoreCreateBinary() xQueueGenericCreate((UBaseType_t)1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE)
  4. #endif

实际上,就是调用创建队列的函数。

信号量的创建方式如下所示:

释放信号量:

获取信号量:

获取函数参数说明:

中断中获取信号量:

 

二值信号量测试:

串口中断服务函数中接收数据,接收完成后(IDLE)释放二值信号量,任务中获取信号量,根据串口数据来响应。

程序如下所示:

  1. uint8_t RX_BUFFER[USART_BUFFER_LEN]; // 串口接收缓冲区
  2. SemaphoreHandle_t binary_semaphore = NULL; // 二值信号量句柄
  3. void start_task(void *pvParameters)
  4. {
  5. taskENTER_CRITICAL();
  6. binary_semaphore = xSemaphoreCreateBinary(); // 创建信号量
  7. if (binary_semaphore != NULL)
  8. {
  9. printf("信号量创建成功!\n");
  10. }
  11. else
  12. {
  13. printf("信号量创建失败!\n");
  14. }
  15. // 创建任务1
  16. xTaskCreate((TaskFunction_t )task1_task,
  17. (char * )"task1_task",
  18. (uint16_t )TASK1_TASK_SIZE,
  19. (void * )NULL,
  20. (UBaseType_t )TASK1_TASK_PRIO,
  21. (TaskHandle_t * )&task1_task_Handle);
  22. // 创建任务2
  23. xTaskCreate((TaskFunction_t )task2_task,
  24. (char * )"task2_task",
  25. (uint16_t )TASK2_TASK_SIZE,
  26. (void * )NULL,
  27. (UBaseType_t )TASK2_TASK_PRIO,
  28. (TaskHandle_t * )&task2_task_Handle);
  29. taskEXIT_CRITICAL();
  30. // 删除开始任务
  31. vTaskDelete(start_Task_Handle);
  32. }
  33. void task1_task(void *pvParameters)
  34. {
  35. for (;;)
  36. {
  37. printf("task1 running\r\n");
  38. vTaskDelay(1000);
  39. }
  40. }
  41. void task2_task(void *pvParameters)
  42. {
  43. uint16_t count = 0;
  44. BaseType_t err_state;
  45. for (;;)
  46. {
  47. if (binary_semaphore != NULL)
  48. {
  49. // 一直等待,直到获取到二值信号量
  50. err_state = xSemaphoreTake(binary_semaphore, portMAX_DELAY);
  51. if (err_state == pdTRUE)
  52. {
  53. if (strcmp((char *)RX_BUFFER, "LED_ON") == 0)
  54. {
  55. LED_RED;
  56. }
  57. if (strcmp((char *)RX_BUFFER, "LED_OFF") == 0)
  58. {
  59. LED_ALL_OFF;
  60. }
  61. if (strcmp((char *)RX_BUFFER, "BEEP_ON") == 0)
  62. {
  63. BEEP_ON;
  64. }
  65. if (strcmp((char *)RX_BUFFER, "BEEP_OFF") == 0)
  66. {
  67. BEEP_OFF;
  68. }
  69. memset(RX_BUFFER, 0, USART_BUFFER_LEN);
  70. }
  71. }
  72. printf("we get %d times binary\n", ++count);
  73. vTaskDelay(20);
  74. }
  75. }
  76. void USART1_IRQHandler(void)
  77. {
  78. static uint16_t i = 0;
  79. uint32_t temp;
  80. BaseType_t pxHigherPriorityTaskWoken;
  81. BaseType_t error_state;
  82. // 保存接收数据到RX_BUFFER缓冲区
  83. if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))
  84. {
  85. RX_BUFFER[i++] = huart1.Instance->DR;
  86. __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
  87. }
  88. // 串口数据接收完成,串口空闲时,释放信号量
  89. if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
  90. {
  91. i = 0;
  92. if (binary_semaphore != NULL)
  93. {
  94. error_state = xSemaphoreGiveFromISR(binary_semaphore, &pxHigherPriorityTaskWoken);
  95. if (error_state != pdTRUE)
  96. {
  97. printf("二值信号量释放失败!\n");
  98. }
  99. // 判断是否需要进行任务切换
  100. if (pxHigherPriorityTaskWoken == pdTRUE)
  101. {
  102. taskYIELD();
  103. }
  104. }
  105. // 清除空闲中断(依次读取SR DR)
  106. temp = huart1.Instance->SR;
  107. temp = huart1.Instance->DR;
  108. }
  109. }

测试结果:

 转载于:https://blog.csdn.net/dingyc_ee/article/details/104108665

文章评论0条评论)

登录后参与讨论
我要评论
0
23
关闭 站长推荐上一条 /2 下一条