本文介绍RTOS事件集的使用。
RTOS事件集是常用的系统组件。本文介绍事件集的基础知识,并以一个按键检测案例来说明事件集的使用方法。
1.基础知识
1)概念
事件集主要用于线程间的同步,它的特点是可以实现一对多,多对多的同步。即多个事件可以实现“或”或“与”的运算。另外,事件的发送操作在事件未清除前,是不可累计的,注意和信号量区别。事件集常用来处理外部异步事件,如按键,通信等。
2)主要接口
这里以CMSIS-RTOS2通用API来介绍事件集常用接口。
a)创建:
osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr)
b)设置:
uint32_t osEventFlagsSet(osEventFlagsId_t ef_id,
uint32_t flags
)
其中,flags为某一位或几位,如:((1 << 2) | (1 << 3)),表示将第2位和第3位置位。
c)清除:
uint32_t osEventFlagsClear(osEventFlagsId_t ef_id,
uint32_t flags
)
d)等待:
uint32_t osEventFlagsWait(osEventFlagsId_t ef_id,
uint32_t flags,
uint32_t options,
uint32_t timeout
)
等待的信号被置位后,默认会被自动清零,若想手动清零,可设置“options”参数。
2.案例
这里以外部按键触发中断,按键检测任务检测按键并进行相应的处理为例来说明事件集的使用方法。
1)按键驱动
按键驱动主要包括按键的初始化,这里配置为下降沿中断,检测按键当前是否按下函数。参考代码如下:
void Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
/*Configure GPIO pin : PC8 */
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI9_5_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(EXTI9_5_IRQn);
}
uint32_t Key_IsPressed(void)
{
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_8) == GPIO_PIN_RESET)
{
return 1;
}
return 0;
}
2)中断服务程序
中断服务程序检测到下降沿后发信号,参考代码如下:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_8)
{
osEventFlagsSet(evt_id, KEY_EVENT);
}
}
3)按键任务
按键任务负责接收按键事件,消抖,按键处理,在无按键事件时,此任务处于阻塞状态,一旦有按键事件发生,立即被唤醒,若优先级最高则被调度。参考代码如下:
#define KEY_EVENT (1UL << 0)
osEventFlagsId_t evt_id;
void KeyTask(void *argument)
{
(void)argument;
uint32_t flags = 0;
while (1)
{
flags = osEventFlagsWait(evt_id, KEY_EVENT, osFlagsWaitAny | osFlagsNoClear, osWaitForever);
if ((flags & KEY_EVENT) != 0)
{
osDelay(10); //10ms
if (Key_IsPressed() != 0)
{
//Function
}
osEventFlagsClear(flags, KEY_EVENT);
}
}
}
其中,
a)延时10ms为软件消抖。
b)事件标志在最后被手动清零,主要是考虑到消抖的原因。
总结,本文介绍了RTOS事件集的使用。