FreeRTOS 定时器 延时 事件/线程Flag

前言

FreeRTOS STM32CubeMX配置 内存管理 任务管理
FreeRTOS 队列 信号量 互斥量
这是前两篇, 本篇继续, 主要总结下FreeRTOS或者更确切的说是 CMSIS_RTOS2 的Timer(软件定时器), Wait(延时), Event Flags(事件标志)和Thread Flags(线程标志).

Timer 软件定时器

软件定时器是FreeRTOS的一个组件, 虽不是那么精确但可以处理周期性的动作, 可以创建一次定时和周期定时. cmsis_os2.h中声明的定时器管理函数:

//  ==== Timer Management Functions ====

/// Create and Initialize a timer.
/// \param[in]     func          function pointer to callback function.
/// \param[in]     type          \ref osTimerOnce for one-shot or \ref osTimerPeriodic for periodic behavior.
/// \param[in]     argument      argument to the timer callback function.
/// \param[in]     attr          timer attributes; NULL: default values.
/// \return timer ID for reference by other functions or NULL in case of error.
osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr);

/// Get name of a timer.
/// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
/// \return name as NULL terminated string.
const char *osTimerGetName (osTimerId_t timer_id);

/// Start or restart a timer.
/// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
/// \param[in]     ticks         \ref CMSIS_RTOS_TimeOutValue "time ticks" value of the timer.
/// \return status code that indicates the execution status of the function.
osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks);

/// Stop a timer.
/// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
/// \return status code that indicates the execution status of the function.
osStatus_t osTimerStop (osTimerId_t timer_id);

/// Check if a timer is running.
/// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
/// \return 0 not running, 1 running.
uint32_t osTimerIsRunning (osTimerId_t timer_id);

/// Delete a timer.
/// \param[in]     timer_id      timer ID obtained by \ref osTimerNew.
/// \return status code that indicates the execution status of the function.
osStatus_t osTimerDelete (osTimerId_t timer_id);

用法和示例参考https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__TimerMgmt.html

周期性的定时行为如下图:
在这里插入图片描述
新建两个任务:
在这里插入图片描述
添加两个软件定时器, 前者是一次性的, 后者是周期性的:
在这里插入图片描述
生成代码, 补充freertos.c:

void Entry_Task1(void *argument)
{
  /* USER CODE BEGIN Entry_Task1 */
	osTimerStart(myTimer01Handle, 1000);
  /* Infinite loop */
  for(;;)
  {
		osDelay(1);
  }
  /* USER CODE END Entry_Task1 */
}

void Entry_Task2(void *argument)
{
  /* USER CODE BEGIN Entry_Task2 */
	osTimerStart(myTimer02Handle, 1000);
  /* Infinite loop */
  for(;;)
  {
		osDelay(1);
  }
  /* USER CODE END Entry_Task2 */
}

/* Callback01 function */
void Callback01(void *argument)
{
  /* USER CODE BEGIN Callback01 */
  HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
  /* USER CODE END Callback01 */
}

/* Callback02 function */
void Callback02(void *argument)
{
  /* USER CODE BEGIN Callback02 */
  HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
  /* USER CODE END Callback02 */
}

编译运行, 可以看到LED1亮一次后就保持常亮, LED2每1s翻转一次状态.

Wait 延时

osDelayosDelayUntil 两个函数. 在Include parameters配置选项卡中, 两个均默认使能. 在cmsis_os2.h中的声明:

//  ==== Generic Wait Functions ====

/// Wait for Timeout (Time Delay).
/// \param[in]     ticks         \ref CMSIS_RTOS_TimeOutValue "time ticks" value
/// \return status code that indicates the execution status of the function.
osStatus_t osDelay (uint32_t ticks);

/// Wait until specified time.
/// \param[in]     ticks         absolute time in ticks
/// \return status code that indicates the execution status of the function.
osStatus_t osDelayUntil (uint32_t ticks);

API及示例参考 https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__Wait.html
如果任务都没有延时, 系统将在Runing和Ready两个状态切换.
如果任务恰好都处在osDelay状态, 系统将运行在idle模式, 参考第一篇中的空闲任务.

创建两个任务:
在这里插入图片描述
生成代码, 补充freertos.c:

void Entry_Task1(void *argument)
{
  /* USER CODE BEGIN Entry_Task1 */
  /* Infinite loop */
  for(;;)
  {
		HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
    	osDelay(1000);
  }
  /* USER CODE END Entry_Task1 */
}

void Entry_Task2(void *argument)
{
  /* USER CODE BEGIN Entry_Task2 */
  uint32_t tick;
  tick = osKernelGetTickCount();
  /* Infinite loop */
  for(;;)
  {
		HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin); 
		tick += 1000U;
		osDelayUntil(tick);
  }
  /* USER CODE END Entry_Task2 */
}

上面两种延时等效, 两个LED同时翻转.

Event Flags

下面是两个线程用event flags通信的简单示例:
在这里插入图片描述
cmsis_os2.h中声明的Event Flags管理函数:

//  ==== Event Flags Management Functions ====

/// Create and Initialize an Event Flags object.
/// \param[in]     attr          event flags attributes; NULL: default values.
/// \return event flags ID for reference by other functions or NULL in case of error.
osEventFlagsId_t osEventFlagsNew (const osEventFlagsAttr_t *attr);

/// Get name of an Event Flags object.
/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
/// \return name as NULL terminated string.
const char *osEventFlagsGetName (osEventFlagsId_t ef_id);

/// Set the specified Event Flags.
/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
/// \param[in]     flags         specifies the flags that shall be set.
/// \return event flags after setting or error code if highest bit set.
uint32_t osEventFlagsSet (osEventFlagsId_t ef_id, uint32_t flags);

/// Clear the specified Event Flags.
/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
/// \param[in]     flags         specifies the flags that shall be cleared.
/// \return event flags before clearing or error code if highest bit set.
uint32_t osEventFlagsClear (osEventFlagsId_t ef_id, uint32_t flags);

/// Get the current Event Flags.
/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
/// \return current event flags.
uint32_t osEventFlagsGet (osEventFlagsId_t ef_id);

/// Wait for one or more Event Flags to become signaled.
/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
/// \param[in]     flags         specifies the flags to wait for.
/// \param[in]     options       specifies flags options (osFlagsXxxx).
/// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
/// \return event flags before clearing or error code if highest bit set.
uint32_t osEventFlagsWait (osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout);

/// Delete an Event Flags object.
/// \param[in]     ef_id         event flags ID obtained by \ref osEventFlagsNew.
/// \return status code that indicates the execution status of the function.
osStatus_t osEventFlagsDelete (osEventFlagsId_t ef_id);

用例参考 https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__EventFlags.html

一个线程:

  • 可以用osEventFlagsWait等待event flags被设置, 进入BLOCKED状态
  • 可以用osEventFlagsSet设置一个或多个flags
  • 可以用osEventFlagsClear清除自身或者其它线程的signals

注意每个信号有31个Event Flags

创建三个任务:
在这里插入图片描述
生成代码, freertos.c中添加代码:

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define BIT_0	( 1 << 0 )
#define BIT_1	( 1 << 1 )
#define BIT_2	( 1 << 2 )
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
osEventFlagsId_t led_evt_id;	//message queue id
/* USER CODE END Variables */

void Entry_Task1(void *argument)
{
  /* USER CODE BEGIN Entry_Task1 */
	uint32_t result;
  /* Infinite loop */
  for(;;)
  {
		result = osEventFlagsWait(led_evt_id, BIT_0, osFlagsWaitAny, osWaitForever); 
		if(result==BIT_0) {
			HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
		}
  }
  /* USER CODE END Entry_Task1 */
}

void Entry_Task2(void *argument)
{
  /* USER CODE BEGIN Entry_Task2 */
	uint32_t result;
  /* Infinite loop */
  for(;;)
  {
		result = osEventFlagsWait(led_evt_id, BIT_1 | BIT_2, osFlagsWaitAny, osWaitForever); 
		if(result == (BIT_1 | BIT_2)) {
			HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
		}
  }
  /* USER CODE END Entry_Task2 */
}

void Entry_Task3(void *argument)
{
  /* USER CODE BEGIN Entry_Task3 */
	led_evt_id = osEventFlagsNew(NULL);
  /* Infinite loop */
  for(;;)
  {
		osEventFlagsSet(led_evt_id, BIT_0);
    	osDelay(1000);
		osEventFlagsSet(led_evt_id, BIT_1 | BIT_2);
    	osDelay(1000);
  }
  /* USER CODE END Entry_Task3 */
}

Task_3创建了信号led_evt_id, 设置相应的位, Task_1和Task_2等待相应的位置位后才往下运行(会自动清除位). 编译运行, 两个LED都是2s的周期翻转, LED1比LED2先亮1s.

注意osFlagsWaitAny可替换的参数为:
在这里插入图片描述

Thread Flags

Thread FlagsEvent Flags的一个特别版, Event Flags可以用于多个线程的全局信号, 而Thread Flags仅仅发给单个的特定线程. 每个线程实例都可以接受therad flags, 无需额外分配therad flags对象, 意思是不用像上面event flags那样还要创建一个led_evt_id.

cmsis_os2.h中声明的Thread Flags 函数:

//  ==== Thread Flags Functions ====

/// Set the specified Thread Flags of a thread.
/// \param[in]     thread_id     thread ID obtained by \ref osThreadNew or \ref osThreadGetId.
/// \param[in]     flags         specifies the flags of the thread that shall be set.
/// \return thread flags after setting or error code if highest bit set.
uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags);

/// Clear the specified Thread Flags of current running thread.
/// \param[in]     flags         specifies the flags of the thread that shall be cleared.
/// \return thread flags before clearing or error code if highest bit set.
uint32_t osThreadFlagsClear (uint32_t flags);

/// Get the current Thread Flags of current running thread.
/// \return current thread flags.
uint32_t osThreadFlagsGet (void);

/// Wait for one or more Thread Flags of the current running thread to become signaled.
/// \param[in]     flags         specifies the flags to wait for.
/// \param[in]     options       specifies flags options (osFlagsXxxx).
/// \param[in]     timeout       \ref CMSIS_RTOS_TimeOutValue or 0 in case of no time-out.
/// \return thread flags before clearing or error code if highest bit set.
uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout);

用例参考 https://www.keil.com/pack/doc/CMSIS/RTOS2/html/group__CMSIS__RTOS__ThreadFlagsMgmt.html

仍然是上小节三个任务, freertos.c中添加代码:

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
#define BIT_0	( 1 << 0 )
#define BIT_1	( 1 << 1 )
#define BIT_2	( 1 << 2 )
/* USER CODE END PM */

void Entry_Task1(void *argument)
{
  /* USER CODE BEGIN Entry_Task1 */
	uint32_t result;
  /* Infinite loop */
  for(;;)
  {
		result = osThreadFlagsWait(BIT_0, osFlagsWaitAny, osWaitForever); 
		if(result==BIT_0) {
			HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
		}
  }
  /* USER CODE END Entry_Task1 */
}

void Entry_Task2(void *argument)
{
  /* USER CODE BEGIN Entry_Task2 */
	uint32_t result;
  /* Infinite loop */
  for(;;)
  {
		result = osThreadFlagsWait(BIT_1 | BIT_2, osFlagsWaitAny, osWaitForever); 
		if(result == (BIT_1 | BIT_2)) {
			HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
		}
  }
  /* USER CODE END Entry_Task2 */
}

void Entry_Task3(void *argument)
{
  /* USER CODE BEGIN Entry_Task3 */
  /* Infinite loop */
  for(;;)
  {
		osThreadFlagsSet(Task1Handle, BIT_0);
    	osDelay(1000);
		osThreadFlagsSet(Task2Handle, BIT_1 | BIT_2);
    	osDelay(1000);
  }
  /* USER CODE END Entry_Task3 */
}

编译下载, 现象与上小节一样.

微信公众号

欢迎扫描二维码关注本人微信公众号, 及时获取或者发送给我最新消息:
在这里插入图片描述

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值