本帖最后由 slytherinsun 于 2025-8-17 22:25 编辑
1.FreeRTOS软件定时器(xTimer)
FreeRTOS的软件定时器可以提供类似MCU的硬件定时器相同的功能,不过精度不如硬件定时器,但不需要占用额外的硬件定时器,
并且可以创建多个软件定时器,常用于单次或周期性的执行一段回调函数。
APM32的SDK用CMSIS-OS2封装了FreeRTOS接口,原FreeRTOS中使用软件定时器的相关API也被封装为了CMSIS-OS2的接口类型。
软件定时器需要在osKernelStart(void)(封装了vTaskStartScheduler(void)接口)运行前进行创建。
创建软件定时器:
要使用软件定时器需要先创建一个软件定时器,CMSIS-OS2下创建定时器的接口为:
osTimerId_t osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr)
其返回值为软件定时器的ID,用来标识是哪个定时器,后续使用此ID操作定时器。
第一个参数"osTimerFunc_t func"是软件定时器的回调函数,是一个函数指针,其原型为:"typedef void (*osTimerFunc_t ) (void *argument)"。
第二个参数"osTimerType_t type"是软件定时器的类型,用来说明软件定时器是单次运行(osTimerOnce)还是周期运行(osTimerPeriodic)。
第三个参数"void *argument"是软件定时器回调函数的参数,用于给软件定时器传递参数,可以置空"NULL"。
第四个参数"const osTimerAttr_t *attr"是指向软件定时器属性"osTimerAttr_t "的指针,用于设置定时器名字,属性位,内存等选项,可以置空"NULL"。
开启软件定时器:
定时器创建后即可开启执行,开启接口为:
osStatus_t osTimerStart (osTimerId_t timer_id, uint32_t ticks)
返回值为"osStatus_t"类型,用来指示函数执行结果。
第一个参数"osTimerId_t timer_id"即创建定时器"osThreadNew()"的返回值,用来标识是哪个定时器。
第二个参数"uint32_t ticks"是定时器的周期,单位为系统的时钟周期。
停止软件定时器:
软件定时器运行后可以进行删除,删除接口为:
osStatus_t osTimerStop (osTimerId_t timer_id)
返回值"osStatus_t"类型,用来指示函数执行结果。
第一个参数"osTimerId_t timer_id"即创建定时器"osThreadNew()"的返回值,用来标识是哪个定时器。
2.FreeRTOS任务通知(xTaskNotify)
可用于任务与任务,中断与任务之间的消息传递,封装为CMSIS-OS2的接口类型的FreeRTOS的任务通知可以传递32Bit的任务值,
相较于使用队列、事件标志组或信号量快的多,同时任务通知本身就包含在任务属性中,不用额外创建结构体,不占用额外内存。
但只有在任务中才能等待通知,同时任务通知只能一对一,传递时需要指定接受通知的任务。
发送任务通知:
任务通知的发送接口为:
uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags)
返回值为设置后的标志和状态。
第一个参数"osThreadId_t thread_id"为发送的目的任务。
第二个参数"uint32_t flags"为任务通知的32Bit值。
接收任务通知:
接收任务通知时调用此函数会进入阻塞态,直到收到通知或到达超时时间后就绪可以运行。
接收通知的函数为:
uint32_t osThreadFlagsWait (uint32_t flags, uint32_t options, uint32_t timeout)
返回值为函数执行结果。
第一个参数"uint32_t flags"为要等待的通知的32Bit值。
第二个参数"uint32_t options"为等待通知的方式,"osFlagsWaitAny"表示收到"flags"中中设置的任意比特即返回,"osFlagsWaitAll"表示收到"flags"中设置的所有比特再返回,"osFlagsNoClear"表示此函数返回后不清除收到的"flags"。
第三个参数"uint32_t timeout"为等待通知的阻塞超时值,到达超时值后还未接收到通知,此函数会返回。
清除任务通知:
如果接收任务通知时设置了收到通知后不清除,后续可以手动清除任务通知,
清除通知的接口为:
uint32_t osThreadFlagsClear (uint32_t flags)
返回值为通知位及函数执行结果。
参数"uint32_t flags"为要清除的通知。
3.FreeRTOS综合例程
本例程基于官方的CMSIS_FreeRTOS例程。
修改例程中的"Usart_TestThread"任务,在任务中等待一个任务通知,收到通知后打印收到的通知值。
同时创建一个周期为1500Ticks的软件定时器,在定时器回调函数"Timer1_CallBack"中反转LED3,并给"Usart_TestThread"发送值为"0x00000002"的任务通知。
在官方的CMSIS_FreeRTOS例程的main.c文件中修改Usart任务为以下内容:
- void Usart_TestThread(void *argument)
- {
- UNUSED(argument);
- volatile uint32_t uartflags = 0;
- while (1)
- {
- /* Print message */
- uartflags = osThreadFlagsWait(0x00000002, osFlagsWaitAny, osWaitForever);
- osThreadFlagsClear(uartflags);
- printf("getflag:0x%lx\r\n", uartflags);
- // osDelay(1000);
- }
- }
同时在main.c文件中定义定时器ID"osTimerId_t SoftTimerID",声明并定义定时器回调函数"void Timer1_CallBack(void *arg)":
- static osTimerId_t SoftTimerID;
- void Timer1_CallBack(void *arg);
- void Timer1_CallBack(void *argument)
- {
- UNUSED(argument);
- BOARD_LED_Toggle(LED3);
- osThreadFlagsSet(usartThreadID, 0x00000002);
- }
最后修改main函数初始化并启用定时器:
- int main(void)
- {
- USART_Config_T USART_ConfigStruct;
- osStatus_t ret_val;
- /* USART config */
- USART_ConfigStructInit(&USART_ConfigStruct);
- USART_ConfigStruct.baudRate = 115200;
- USART_ConfigStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
- USART_ConfigStruct.mode = USART_MODE_TX;
- USART_ConfigStruct.parity = USART_PARITY_NONE;
- USART_ConfigStruct.stopBits = USART_STOP_BIT_1;
- USART_ConfigStruct.wordLength = USART_WORD_LEN_8B;
- BOARD_COM_Config(COM1, &USART_ConfigStruct);
- /* Configures LED 2,3 */
- BOARD_LED_Config(LED2);
- BOARD_LED_Config(LED3);
- /* Initialize the RTOS scheduler */
- osKernelInitialize();
- /* Create the thread */
- ledThreadID = osThreadNew(Led_Thread, NULL, &ledThreadattr);
- if (ledThreadID == NULL)
- {
- printf("Create led thread failed!\r\n");
- }
- usartThreadID = osThreadNew(Usart_TestThread, NULL, &usartThreadattr);
- if (usartThreadID == NULL)
- {
- printf("Create usart thread failed!\r\n");
- }
- SoftTimerID = osTimerNew(Timer1_CallBack, osTimerPeriodic, NULL, NULL);
- if(NULL != SoftTimerID) {
- ret_val = osTimerStart(SoftTimerID, 1500);
- if(osOK != ret_val) {
- printf("Create osft timer failed!\n");
- }
- }
- /* Start the RTOS scheduler */
- osKernelStart();
- /* Infinite loop */
- while (1);
- }
编译代码后烧录并运行,打开串行监视器即可看到"Usart_TestThread"任务被定时器周期触发后打印的任务通知:

|