1. 定时器的理论讲解
1.1 定时器三要素
- 超时时间
- 函数
- 单次触发还是周期性触发
1.2 使用动态分配内存的方法创建定时器
/* pcTimerName:定时器名字, 用处不大, 尽在调试时用到
* xTimerPeriodInTicks: 周期, 以 Tick 为单位
* uxAutoReload: 类型, pdTRUE 表示周期, pdFALSE 表示一次性
* pvTimerID: 回调函数可以使用此参数, 比如分辨是哪个定时器
* pxCallbackFunction: 回调函数
* 返回值: 成功则返回 TimerHandle_t, 否则返回 NULL*/
TimerHandle_t xTimerCreate( const char * const pcTimerName,
const TickType_t xTimerPeriodInTi
cks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbac
kFunction );
1.3 启动定时器
/* xTimer: 哪个定时器
* xTicksToWait: 超时时间
* 返回值: pdFAIL 表示"启动命令"在 xTicksToWait 个 Tick 内无法写入队列
* pdPASS 表示成功
*/
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );
1.4 定时器函数执行的上下文
在中断里执行?在任务里执行?(守护任务)
FreeRTOS 是 RTOS,它不允许在内核、在中断中执行不确定的代码:如果定时器函数很耗时,会影响整个系统。
所以, FreeRTOS 中,不在 Tick 中断中执行定时器函数。
在哪里执行?在某个任务里执行,这个任务就是: RTOS Damemon Task, RTOS 守护任务。以前被称为"Timer server",但是这个任务要做并不仅仅是定时器相关,所以改名为:RTOS Damemon Task。
我们自己编写的任务函数要使用定时器时,是通过"定时器命令队列"(timer command queue)和守护任务交互,
- 守护任务的优先级为: configTIMER_TASK_PRIORITY ;
- 定时器命令队列长度为:configTIMER_QUEUE_LENGTH。
1.5 定时器状态转换
2. 定时器防抖(消除按键抖动)
- 在中断函数中启动、复位定时器
- 每次抖动都会推迟定时器的超时时间
- 多次抖动只导致定时器超时一次:消除了抖动