目录
1 软件定时器
定时器是MCU常用的外设,我们在学习各种单片机时必然会学习它的硬件定时器。但是,MCU自带的硬件定时器资源是有限的,而且一般会用在实时性要求很强的地方。 在freeRTOS中提供了软件定时器的功能,来实现更多的定时器资源。
1. 软件定时器的特性
使用定时器跟使用手机闹钟是类似的:
- 指定时间:启动定时器和运行回调函数,两者的间隔被称为定时器的周期(period)。
- 指定类型,定时器有两种类型:
- 一次性(One-shot timers): 这类定时器启动后,它的回调函数只会被调用一次; 可以手工再次启动它,但是不会自动启动它。
- 自动加载定时器(Auto-reload timers ): 这类定时器启动后,时间到之后它会自动启动它; 这使得回调函数被周期性地调用。
- 指定要做什么事,就是指定回调函数
实际的闹钟分为:有效、无效两类。软件定时器也是类似的,它由两种状态:
- 运行(Running、Active):运行态的定时器,当指定时间到达之后,它的回调函数会被调用
- 冬眠(Dormant):冬眠态的定时器还可以通过句柄来访问它,但是它不再运行,它的回调函数不会 被调用
2.回调函数
定时器的回调函数的原型如下:
void ATimerCallback( TimerHandle_t xTimer );
定时器的回调函数是在守护任务中被调用的,守护任务不是专为某个定时器服务的,它还要处理其他定时器。 所以,定时器的回调函数不要影响其他人:
- 回调函数要尽快实行,不能进入阻塞状态
- 不要调用会导致阻塞的API函数,比如 vTaskDelay()
- 可以调用 xQueueReceive() 之类的函数,但是超时时间要设为0:即刻返回,不可阻塞
2 示例程序
2.1 例程功能
创建周期定时器,在定时器回调函数中添加串口打印的程序,定时器计数时间到了就打印当前计数值。
2.2 步骤
默认任务保持不变
在Config parameters中使能定时器,定时器的优先级、队列长度和栈的深度按默认的来,注意定时器的优先级要比默认仍无的优先级高
添加一个周期定时器
在FREERTOS初始化函数中开启定时器,定时时间设置为1s
void MX_FREERTOS_Init(void) {
//..........
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
osTimerStart(myTimer01Handle,1000);
/* USER CODE END RTOS_TIMERS */
//..........
}
在定时器回调中打印当前定时器的计数值
/* Callback01 function */
void Callback01(void const * argument)
{
/* USER CODE BEGIN Callback01 */
printf("\n定时器%d\n",osKernelSysTick());
/* USER CODE END Callback01 */
}
2.3 实验结果
可见回调函数每隔1000ms执行一次
2.4 函数讲解
1 osStatus osTimerStart (osTimerId timer_id, uint32_t millisec)
/**
@brief Start or restart a timer.
@param timer_id timer ID obtained by \ref osTimerCreate.
@param millisec time delay value of the timer.
@retval status code that indicates the execution status of the function
@note MUST REMAIN UNCHANGED: \b osTimerStart shall be consistent in every CMSIS-RTOS.
*/
osStatus osTimerStart (osTimerId timer_id, uint32_t millisec)
- 函数功能:开始或重启定时器
- 传入参数:1、timer_id(要开启定时器的句柄)2、millisec(定时器记时时间)
2 uint32_t osKernelSysTick(void)
/**
@brief Get the value of the Kernel SysTick timer
@param None
@retval None
@note MUST REMAIN UNCHANGED: \b osKernelSysTick shall be consistent in every CMSIS-RTOS.
*/
uint32_t osKernelSysTick(void)
- 函数功能:获取内核SysTick定时器的值
自我感悟
typedef enum {
osPriorityIdle = -3, ///< priority: idle (lowest)
osPriorityLow = -2, ///< priority: low
osPriorityBelowNormal = -1, ///< priority: below normal
osPriorityNormal = 0, ///< priority: normal (default)
osPriorityAboveNormal = +1, ///< priority: above normal
osPriorityHigh = +2, ///< priority: high
osPriorityRealtime = +3, ///< priority: realtime (highest)
osPriorityError = 0x84 ///< system cannot determine priority or thread has illegal ///<priority
} osPriority;
defaultTask的优先级为,即为0,myTimer01的优先级为2,满使用FreeRtos的定时器的编程规范