一、概述
软件:
1、MDK-ARM 5
2、STM32CubeMX
3、开发板:STM32F106ZET6
二、主要内容
计数信号量的使用场景:一个二值信号量最多只可以锁存一个中断事件。在锁存的事件还未被处理之前,如果还有中断事件发生,那么后续发生的中断事件将会丢失。如果 用计数信号量代替二值信号量,那么,这种丢中断的情形将可以避免。
cubemx:版本5.2.1
STM32:stm32f103zet6
系统时钟:72M
1、RCC配置
2、SYS配置,注意Timebase Source的选择
3、FreeRTOS:创建两个任务
4、FreeRTOS:创建深度为10的计数信号量
5、根据原理图,将LED对应引脚设置为输出模式
三、程序实现
- 添加freertos.c 中task01内容,StartTask01功能是:发送 1 次信号量,间隔一秒后发送 2 次,再间隔一秒发送 3 次,然后等待 2秒。
/* USER CODE END Header_StartTask01 */
void StartTask01(void const * argument)
{
/* USER CODE BEGIN StartTask01 */
/* Infinite loop */
for(;;)
{
osDelay(1000);
osSemaphoreRelease(myCountingSem01Handle);
osDelay(1000);
osSemaphoreRelease(myCountingSem01Handle);
osSemaphoreRelease(myCountingSem01Handle);
osDelay(1000);
osSemaphoreRelease(myCountingSem01Handle);
osSemaphoreRelease(myCountingSem01Handle);
osSemaphoreRelease(myCountingSem01Handle);
osDelay(2000);
}
/* USER CODE END StartTask01 */
}
- 添加freertos.c 中task02内容,等待信号量,然后控制 LED0 和 LED1 闪烁一次。
/* USER CODE END Header_StartTask02 */
void StartTask02(void const * argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
for(;;)
{
osSemaphoreWait(myCountingSem01Handle,osWaitForever);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_13,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_14,GPIO_PIN_SET);
osDelay(100);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_13,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_14,GPIO_PIN_RESET);
osDelay(100);
}
/* USER CODE END StartTask02 */
}
四、结果分析
编译下载运行。
现象是: LED 闪 1 次,一秒后闪 2 次,再过一秒闪 3 次,再等三秒, LED 闪 1次…如此循环。
程序分析:
在 StartTask01()任务中,连续调用 osSemaphoreRelease(myCountingSem01Handle);两次或者三次耗时是很短的,而StartTask02()任务执行一次 LED 闪烁耗时大约是 200 毫秒,会造成信号量值的累积。
如果把信号量的定义语句:
myCountingSem01Handle = osSemaphoreCreate(osSemaphore(myCountingSem01), 10);
的最后一个参数改为 1,即改为:
myCountingSem01Handle = osSemaphoreCreate(osSemaphore(myCountingSem01), 1);
这样就变成了二值信号量。
运行结果是, LED 闪 1 次,一秒后闪 1 次,再过一秒闪 1 次,再等三秒, LED 闪 1次…如此循环。
由此可知,在连续释放二值信号时,如果处理信号量相关事件的函数来不及处理,就会造成事件的丢失。
从而也可以看出,计数信号量相对于二值信号量的优势。