FreeRTOS_软件定时器

news2024/11/26 20:38:52

目录

1. 软件定时器简介

2. 定时器服务/Daemon 任务

2.1 定时器服务任务与队列

2.2 定时器相关配置

2.2.1 configUSE_TIMERS

2.2.2 configTIMER_TASK_PRIORITY

2.2.3 configTIMER_QUEUE_LENGTH

2.2.4 configTIMER_TASK_STACK_DEPTH

2.3 单次定时器和周期定时器

2.4 复位软件定时器

2.4.1 函数 xTimerReset()

2.4.2 函数 xTimerResetFromISR()

2.5 创建软件定时器

2.5.1 函数 xTimerCreate()

2.5.2 函数 xTimerCreateStatic()

2.6 开启软件定时器

2.6.1 函数 xTimerStart()

2.6.2 函数 xTimerStartFromISR()

2.7 停止软件定时器

2.7.1 函数 xTimerStop()

2.7.2 函数 xTimerStopFromISR()

3. 软件定时器实验

3.1 main.c


        定时器可以说是每个 MCU 都有的外设,有的 MCU 其定时器功能异常强大,比如提供 PWM、输入捕获等功能。但是最常用的还是定时器最基本的功能——定时,通过定时器来完成需要周期性处理的事务。MCU 自带的定时器属于硬件定时器,不同的 MCU 其硬件定时器数量不同,因为要考虑成本的问题。FreeRTOS 提供了定时器功能,不过是软件定时器,软件定时器的精度没有硬件定时器那么高,但是对于普通的精度要求不高的周期性处理任务来说足够了。当 MCU 的硬件定时器不够的时候考虑使用软件定时器。

1. 软件定时器简介

        软件定时器运行设置一段时间,当设置的时间到达之后就执行指定的功能函数,被定时器调用的这个功能函数叫做定时器的回调函数。回调函数的两次执行间隔叫做定时器的定时周期,简而言之,当定时器的定时周期到了之后就会执行回调函数

        软件定时器的回调函数是在定时器服务任务中执行的,所以一定不能在回调函数中调用任何会阻塞任务的 API 函数!比如,定时器回调函数中千万不能调用 vTaskDelay()、vTaskDelayUnti(),还有一些访问队列或者信号量的非零阻塞时间的 API 函数也不能调用。

2. 定时器服务/Daemon 任务

2.1 定时器服务任务与队列

        定时器是一个可选的、不属于 FreeRTOS 内核的功能,它是由定时器服务(或 Daemon)任务来提供的。FreeRTOS 提供了很多定时器有关的 API 函数,这些 API 函数大多都使用 FreeRTOS 的队列发送命令给定时器服务任务。这个队列叫做定时器命令队列。定时器命令队列是提供给 FreeRTOS 的软件定时器使用的,用户不能直接访问!

        上图左侧部分属于用户应用程序的一部分,并且会在某个用户创建的用户任务中调用。图中右侧部分是定时器服务任务的任务函数,定时器命令队列将用户应用任务和定时器服务任务连接在一起。上图中,应用程序调用了函数 xTimerReset(),结果就是复位命令会被发送到定时器命令队列中,定时器服务任务会处理这个命令。应用程序是通过函数 xTimerReset() 间接的向定时器命令队列发送了复位命令,并不是直接调用类似 xQueueSend() 这样的队列操作函数发送的

2.2 定时器相关配置

        通过上图的学习我们知道软件定时器有一个定时器服务任务和定时器命令队列,这两个需要一定的配置。配置方法和我们之前的学习的 FreeRTOSConfig.h 一样。

2.2.1 configUSE_TIMERS

        如果要使用软件定时器的话宏 configUSE_TIMERS 一定要设置为 1,当设置为 1 的话定时器服务任务就会在启动 FreeRTOS 调度器的时候自动创建。

2.2.2 configTIMER_TASK_PRIORITY

        设置软件定时器服务任务的任务优先级,可以在 0~(configMAX_PRIORITIES-1)。优先级一定要根据实际的应用要求来设置。如果定时器服务任务的优先级设置的高的话,定时器命令队列中的命令和定时器回调函数就会及时的得到处理。

2.2.3 configTIMER_QUEUE_LENGTH

        此宏用来设置定时器命令队列的队列长度。

2.2.4 configTIMER_TASK_STACK_DEPTH

        此宏用来设置定时器服务任务的任务堆栈大小,单位为字,不是字节!,对于 STM32 来说一个字是 4 个字节。由于定时器服务任务中会执行定时器的回调函数,因此任务堆栈的大小一定要根据定时器的回调函数来设置。

2.3 单次定时器和周期定时器

        软件定时器分为两种:单次定时器和周期定时器单次定时器的话定时器回调函数就执行一次,比如定时 1s,当定时时间到了以后就会执行一次回调函数,然后定时器就会停止运行。对于单次定时器我们可以再次手动重新启动(调用相应的 API 函数即可),但是单次定时器不能自动重启。相反的,周期定时器一旦启动以后就会在执行完回调函数以后自动的重新启动,这样回调函数就会周期性的执行。

        上图中 Timer1 为单次定时器,定时器周期为 100,Timer2 为周期定时器,定时器周期为 200.

2.4 复位软件定时器

        有时候我们可能会在定时器正在运行的时候需要复位软件定时器,复位软件定时器的话会重新计算定时周期到达的时间点,这个新的时间点是相对于复位定时器的那个时刻计算的,并不是第一次启动软件定时器的那个时间点。如下图所示,Timer1 是单次定时器,定时周期是 5s:

        上图中展示了定时器的复位过程,这是一个通过按键打开 LCD 背光的例子,我们假定当唤醒键被按下的时候应用程序打开 LCD 背光,当 LCD 背光点亮以后如果 5s 之内唤醒键没有再次按下就自动熄灭。如果在这 5s 之内唤醒键被按下了,LCD 背光就从按下的这个时刻起再亮 5s。

        FreeRTOS 提供了两个 API 函数来完成软件定时器的复位:

函数:

        xTimerReset()                                复位软件定时器,用在任务中。

        xTimerResetFromISR()                  复位软件定时器,用在中断服务函数中。

2.4.1 函数 xTimerReset()

        复位一个软件定时器,此函数只能用在任务中,不能用于中断服务函数中!此函数是一个宏,真正执行的是函数 xTimerGenericCommand(),函数原型如下:

BaseType_t xTimerReset(TimerHandle_t xTimer,
                       TickType_t    xTicksToWait)

参数:

        xTimer:                要复位的软件定时器的句柄。

        xTicksToWait:      设置阻塞时间,调用函数 xTimerReset() 开启软件定时器其实就是向定时器命令队列发送一条 tmrCOMMAND_RESET 命令,既然是向队列发送消息,那么

                                       必然会涉及到入队阻塞时间的设置。

返回值:

        pdPASS:                软件定时器复位成功,其实就是命令发送成功。

        pdFAIL:                  软件定时器复位失败,命令发送失败。

2.4.2 函数 xTimerResetFromISR()

        此函数是 xTimerReset() 的中断版本,此函数用于中断服务函数中!此函数是一个宏,真正执行的是函数 xTimerGenericCommand(),函数原型如下:

BaseType_t xTimerResetFromISR(TimerHandle_t xTimer,
                              BaseType_t*   pxHigherPriorityTaskWoken);

参数:

        xTimer:                要复位的软件定时器的句柄。

        pxHigherPriorityTaskWoken:                记录退出此函数以后是否进行任务切换,这个变量的值函数会自动设置的,用户不用进行设置,用户只需要提供一个变量来保存

                                                                        这个值就行了。当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。

返回值:

        pdPASS:              软件定时器复位成功,其实就是命令发送成功。

        pdFAIL:                软件定时器复位失败,命令发送失败。

2.5 创建软件定时器

        使用软件定时器之前要先创建软件定时器。

函数:

        xTimerCreate():                使用动态方法创建软件定时器

        xTimerCreateStatic():       使用静态方法创建软件定时器

2.5.1 函数 xTimerCreate()

        此函数用于创建一个软件定时器,所需要的内存通过动态内存管理方法分配。新创建的软件定时器处于休眠状态,也就是未运行的函数 xTimerStart()、xTimerReset()、xTimerStartFromISR()、xTimerResetFromISR()、xTimerChangePeriod() 和 xTimerChangePeriodFromISR() 可以使新创建的定时器进入活动状态,此函数的原型如下:

TimerHandle_t xTimerCreate(const char* const        pcTimerName,
                           TickType_t               xTimerPeriodInTicks,
                           UBaseType_t              uxAutoReload,
                           void*                    pvTimerID,
                           TimerCallbackFunction_t  pxCallbackFunction)

参数:

        pcTimerName:                软件定时器名字,名字是一串字符串,用于调试使用。

        xTimerPeriodInTicks:      软件定时器的定时器周期,单位是时钟节拍数。可以借助 portTICK_PERIOD_MS 将 ms 单位转换为时钟节拍数。比如说,定时器的周期为 100 个时钟节拍的

                                                   话,那么 xTimerPeriodInTicks 就为 100,当定时器周期为 500ms 的时候 xTimerPeriodInTicks 就可以设置为 (500/portTICK_PERIOD_MS)

        uxAutoReload:                设置定时器模式,单次定时器还是周期定时器。当参数为 pdTRUE 的时候表示创建的是周期定时器。如果为 pdFALSE 的话表示创建的是单次定时器。

        pvTimerID:                      定时器 ID 号,一般情况下每个定时器都有一个回调函数,当定时器定时周期到了以后就会执行这个回调函数。但是 FreeRTOS 也支持多个定时器共用同一个回

                                                  调函数,在回调函数中根据定时器的 ID 号来处理不同的定时器。

        pxCallbackFunction:       定时器回调函数,当定时器定时周期到了以后就会调用这个函数。

返回值:

        NULL:                              软件定时器创建失败。

        其他值:                             创建成功的软件定时器句柄。

2.5.2 函数 xTimerCreateStatic()

        此函数用于创建一个软件定时器,所需要的内存需要用户自行分配。新创建的软件定时器处于休眠状态,也就是未运行的函数 xTimerStart()、xTimerReset()、xTimerStartFromISR()、xTimerResetFromISR()、xTimerChangePeriod() 和 xTimerChangePeriodFromISR() 可以使新创建的定时器进入活动状态,此函数的原型如下:

TimerHandle_t xTimerCreate(const char* const        pcTimerName,
                           TickType_t               xTimerPeriodInTicks,
                           UBaseType_t              uxAutoReload,
                           void*                    pvTimerID,
                           TimerCallbackFunction_t  pxCallbackFunction,
                           StaticTimer_t*           pxTimerBuffer)

参数:

        pcTimerName:                软件定时器名字,名字是一串字符串,用于调试使用。

        xTimerPeriodInTicks:      软件定时器的定时器周期,单位是时钟节拍数。可以借助 portTICK_PERIOD_MS 将 ms 单位转换为时钟节拍数。比如说,定时器的周期为 100 个时钟节拍的

                                                   话,那么 xTimerPeriodInTicks 就为 100,当定时器周期为 500ms 的时候 xTimerPeriodInTicks 就可以设置为 (500/portTICK_PERIOD_MS)

        uxAutoReload:                设置定时器模式,单次定时器还是周期定时器。当参数为 pdTRUE 的时候表示创建的是周期定时器。如果为 pdFALSE 的话表示创建的是单次定时器。

        pvTimerID:                      定时器 ID 号,一般情况下每个定时器都有一个回调函数,当定时器定时周期到了以后就会执行这个回调函数。但是 FreeRTOS 也支持多个定时器共用同一个回

                                                  调函数,在回调函数中根据定时器的 ID 号来处理不同的定时器。

        pxCallbackFunction:       定时器回调函数,当定时器定时周期到了以后就会调用这个函数。

        pxTimerBuffer:                参数指向一个 StaticTimer_t 类型的变量,用来保存定时器结构体。

返回值:

        NULL:                              软件定时器创建失败。

        其他值:                             创建成功的软件定时器句柄。

2.6 开启软件定时器

        如果软件定时器停止运行的话可以使用 FreeRTOS 提供的两个开启函数来重新启动软件定时器。

函数:

        xTimerStart():                        开启软件定时器,用于任务中。

        xTimerStartFromISR():          开启软件定时器,用于中断中。

2.6.1 函数 xTimerStart()

        启动软件定时器,函数 xTimerStartFromISR() 是这个函数的中断版本,可以用在中断服务函数中。如果软件定时器没有运行的话调用函数 xTimerStart() 就会计算定时器到期时间,如果软件定时器正在运行的话调用函数 xTimerStart() 的结果和 xTimerReset() 一样。此函数是个宏,真正执行的是函数 xTimerGenericCommand,函数原型如下:

BaseType_t xTimerStart(TimerHandle_t     xTimer,
                       TickType_t        xTicksToWait)

参数:

        xTimer:                要开启的软件定时器的句柄。

        xTicksToWait:      设置阻塞时间,调用函数 xTimerStart() 开启软件定时器其实就是向定时器命令队列发送一条 tmrCOMMAND_START 命令,既然是向队列发送消息,必然会涉及到

                                       入队阻塞时间的设置。

返回值:

        pdPASS:              软件定时器开启成功,其实就是命令发送成功。

        pdFAIL:                软件定时器开启失败,命令发送失败。

2.6.2 函数 xTimerStartFromISR()

        此函数是函数 xTimerStart() 的中断版本,用在中断服务函数中,此函数是个宏,真正执行的是函数 xTimerGenericCommand(),此函数原型如下:

BaseType_t xTimerStartFromISR(TimerHandle_t    xTimer,
                              BaseType_t*      pxHigherPriorityTaskWoken);

参数:

        xTimer:                                        要开启的软件定时器的句柄

        pxHigherPriorityTaskWoken:       标记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。

                                                               当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。

返回值:

        pdPASS:                                      软件定时器开启成功,其实就是命令发送成功。

        pdFAIL:                                        软件定时器开启失败,命令发送失败。

2.7 停止软件定时器

        软件定时器有开启的 API 函数,也有停止的 API 函数。

函数:

        xTimerStop():                停止软件定时器,用于任务中。

        xTimerStopFromISR():  停止软件定时器,用于中断服务函数中。

2.7.1 函数 xTimerStop()

        此函数用于停止一个软件定时器,此函数用于任务中,不能用在中断服务函数中!此函数是一个宏,真正调用的是函数 xTimerGenericCommand(),函数原型如下:

BaseType_t xTimerStop(TimerHandle_t xTimer,
                      TickType_t    xTicksToWait)

参数:

        xTimer:                        要停止的软件定时器的句柄。

        xTicksToWait:              设置阻塞时间,调用函数 xTimerStop() 停止软件定时器其实就是向定时器命令队列发送一条 tmrCOMMAND_STOP 命令,向队列发送消息,必然会涉及到入

                                               队阻塞时间的设置。

返回值:

        pdPASS:                      软件定时器停止成功,其实就是命令发送成功。

        pdFAIL:                        软件定时器停止失败,命令发送失败。

2.7.2 函数 xTimerStopFromISR()

        此函数是 xTimerStop() 的中断版本,此函数用于中断服务函数中!此函数是一个宏,真正执行的是函数 xTimerGenericCommand(),函数原型如下:

BaseType_t xTimerStopFromISR(TimerHandle_t    xTimer,
                             BaseType_t*      pxHigherPriorityTaskWoken);

参数:

        xTimer:                要停止的软件定时器句柄。

        pxHigherPriorityTaskWoken:                标记退出此函数以后是否进行任务切换,这个变量的值函数会自动设置,用户不用进行设置,用户只需要提供一个变量来保存这个值。

                                                                        当此值为 pdTRUE 的时候在退出中断服务函数之前一定要进行一次任务切换。

返回值:

        pdPASS:              软件定时器停止成功,其实就是命令发送成功。

        pdFAIL:                软件定时器停止失败,命令发送失败。

3. 软件定时器实验

        本实验设计两个任务:start_task 和 timercontrol_task 这两个任务的任务功能如下:

        start_task:用来创建任务 timercontrol_task() 和两个软件定时器。

        timercontrol_task:控制两个软件定时器的开启和停止。

        实验中还创建了两个软件定时器:AutoReloadTimer_Handle OneShotTimer_Handle,这两个定时器分别为周期定时器和单次定时器。定时器 AutoReloadTimer_Handle 的定时器周期为 1000 个时钟节拍(1s),定时器 OneShotTimer_Handle 的定时器周期为 2000 个时钟节拍(2s)。

使用软件定时器之前一定先设置相关的宏!!!

#ifndef configUSE_TIMERS
	#define configUSE_TIMERS 1      //如果要使用软件定时器的话 configUSE_TIMERS 一定要设置为 1,当设置为 1 的时候定时器服务任务就会在启动 FreeRTOS 调度器时自动创建。
#endif
/* The timers module relies on xTaskGetSchedulerState(). */
#if configUSE_TIMERS == 1

	#ifndef configTIMER_TASK_PRIORITY
		#error If configUSE_TIMERS is set to 1 then configTIMER_TASK_PRIORITY must also be defined.
	#endif /* configTIMER_TASK_PRIORITY */

	#ifndef configTIMER_QUEUE_LENGTH
		#error If configUSE_TIMERS is set to 1 then configTIMER_QUEUE_LENGTH must also be defined.
	#endif /* configTIMER_QUEUE_LENGTH */

	#ifndef configTIMER_TASK_STACK_DEPTH
		#error If configUSE_TIMERS is set to 1 then configTIMER_TASK_STACK_DEPTH must also be defined.
	#endif /* configTIMER_TASK_STACK_DEPTH */

#endif /* configUSE_TIMERS */

3.1 main.c

#include "stm32f4xx.h"  
#include "FreeRTOS.h" //这里注意必须先引用FreeRTOS的头文件,然后再引用task.h
#include "task.h"     //存在一个先后的关系
#include "LED.h"
#include "LCD.h"
#include "Key.h"
#include "usart.h"
#include "delay.h"
#include "string.h"
#include "beep.h"
#include "malloc.h"
#include "timer.h"
#include "timers.h"   //必须使用这个头文件


//任务优先级
#define START_TASK_PRIO     1       //用于创建其他任务
//任务堆栈大小
#define START_STK_SIZE      256
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define TIMERCONTROL_TASK_PRIO     2       //定时器控制任务
//任务堆栈大小 
#define TIMERCONTROL_STK_SIZE      256
//任务句柄
TaskHandle_t TimerControlTask_Handler;
//任务函数
void timercontrol_task(void *pvParameters);

TimerHandle_t   AutoReloadTimer_Handle;     //周期定时器句柄
TimerHandle_t   OneShotTimer_Handle;        //单次定时器句柄

void AutoReloadCallback(TimerHandle_t xTimer);  //周期定时器回调函数
void OneShotCallback(TimerHandle_t xTimer);     //单次定时器回调函数

//LCD刷屏时使用的颜色
int lcd_discolor[14]={	WHITE, BLACK, BLUE,  BRED,      
						GRED,  GBLUE, RED,   MAGENTA,       	 
						GREEN, CYAN,  YELLOW,BROWN, 			
						BRRED, GRAY };

int main(void)
{
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);  
    delay_init(168);
    uart_init(115200);
    LED_Init();
    KEY_Init();
    BEEP_Init();
    LCD_Init();
    my_mem_init(SRAMIN);        //初始化内部内存池
    
    POINT_COLOR=RED;
    LCD_ShowString(30,10,200,16,16,"ATK STM32F407");
    LCD_ShowString(30,30,200,16,16,"FreeRTOS Software Timer");
    LCD_ShowString(30,50,200,16,16,"KEY_UP:Start Tmr1");
    LCD_ShowString(30,70,200,16,16,"KEY0:Start Tmr2");
    LCD_ShowString(30,90,200,16,16,"KEY1:Stop Tmr1 and Tmr2");
    
    LCD_DrawLine(0,108,239,108);    //画线
    LCD_DrawLine(119,108,119,319);  //画线
    
    POINT_COLOR = BLACK;
    LCD_DrawRectangle(5,110,115,314);   //画一个矩形
    LCD_DrawLine(5,130,115,130);    //画线
    
    LCD_DrawRectangle(125,110,234,314); //画一个矩形
    LCD_DrawLine(125,130,234,130);  //画线
    POINT_COLOR = BLUE;
    LCD_ShowString(6,111,110,16,16,"AutoTim:000");
    LCD_ShowString(126,111,110,16,16,"OneTim: 000");
    
    //创建开始任务
    xTaskCreate((TaskFunction_t)start_task,         //任务函数
                (const char*   )"start_task",       //任务名称
                (uint16_t      )START_STK_SIZE,     //任务堆栈大小
                (void*         )NULL,               //传递给任务函数的参数
                (UBaseType_t   )START_TASK_PRIO,    //任务优先级
                (TaskHandle_t* )&StartTask_Handler);//任务句柄
    vTaskStartScheduler();          //开启任务调度
}

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();       //进入临界区
    //创建软件周期定时器
    AutoReloadTimer_Handle=xTimerCreate((const char*        )"AutoReloadTimer",     //软件定时器名字,一串字符串,用于调试
                                        (TickType_t         )1000,                  //周期数,1000个时钟节拍,1s
                                        (UBaseType_t        )pdTRUE,                //pdTRUE表示周期定时器
                                        (void*              )1,                     //定时器 ID 号
                                        (TimerCallbackFunction_t)AutoReloadCallback);   //周期定时器回调函数   
    //创建软件单次定时器
    OneShotTimer_Handle=xTimerCreate((const char*        )"OneShotTimer",     //软件定时器名字,一串字符串,用于调试
                                     (TickType_t         )2000,               //周期数,2000个时钟节拍,2s
                                     (UBaseType_t        )pdFALSE,            //pdFALSE表示单次定时器
                                     (void*              )2,                  //定时器 ID 号
                                     (TimerCallbackFunction_t)OneShotCallback);   //单次定时器回调函数                            
    //创建开始任务
    xTaskCreate((TaskFunction_t)timercontrol_task,         //任务函数
                (const char*   )"timercontrol_task",       //任务名称
                (uint16_t      )TIMERCONTROL_STK_SIZE,     //任务堆栈大小
                (void*         )NULL,                      //传递给任务函数的参数
                (UBaseType_t   )TIMERCONTROL_TASK_PRIO,    //任务优先级
                (TaskHandle_t* )&TimerControlTask_Handler);//任务句柄   
    vTaskDelete(StartTask_Handler);   //删除开始任务
    taskEXIT_CRITICAL();        //退出临界区
}

//TimerControl的任务函数
void timercontrol_task(void *pvParameters)
{
    u8 key,num;
    while(1)
    {
        //只有两个定时器都创建成功了才能对其进行操作
        if((AutoReloadTimer_Handle!=NULL)&&(OneShotTimer_Handle!=NULL))
        {
            key = KEY_Scan(0);
            switch(key)
            {
                case WKUP_PRES: //当KEY_UP按键按下的时候打开周期定时器
                    xTimerStart(AutoReloadTimer_Handle,0);  //开启周期定时器
                    printf("开启定时器1\r\n");
                    break;
                case KEY0_PRES: //当KEY0按键按下的时候打开单次定时器
                    xTimerStart(OneShotTimer_Handle,0);  //开启单次定时器
                    printf("开启定时器2\r\n");
                    break;
                case KEY1_PRES: //当KEY1按键按下的时候关闭定时器1和定时器2
                    xTimerStop(OneShotTimer_Handle,0);     //关闭单次定时器
                    xTimerStop(AutoReloadTimer_Handle,0);  //关闭周期定时器
                    printf("关闭定时器1和定时器2\r\n");
                    break;
            }
        }
        num++;
        if(num==50) //每500msLED0闪烁一次
        {
            num=0;
            LED0=!LED0;
        }
        vTaskDelay(10); //延时10ms,10个时钟节拍
    }
}

//周期定时器回调函数
void AutoReloadCallback(TimerHandle_t xTimer)
{
    static u8 tmr1_num=0;
    tmr1_num++;                                         //周期定时器执行次数加1
    LCD_ShowxNum(70,111,tmr1_num,3,16,0x80);            //显示周期定时器的执行次数
    LCD_Fill(6,131,114,313,lcd_discolor[tmr1_num%14]);  //填充区域
}

//单次定时器的回调函数
void OneShotCallback(TimerHandle_t xTimer)
{
    static u8 tmr2_num=0;
    tmr2_num++;
    LCD_ShowxNum(190,111,tmr2_num,3,16,0x80);   //显示单次定时器的执行次数
    LCD_Fill(126,131,233,313,lcd_discolor[tmr2_num%14]);
    LED1=!LED1;
    printf("定时器2运行结束\r\n");
}





        当按下 KEY0 键以后,xTimerStart 会使单次定时器开始执行,当定时器计时的 2s 时间到了之后就会调用回调函数 OneShotCallback(),屏幕右侧区域的背景色会被刷新为其他颜色,背景颜色逐渐刷新完成以后定时器 OneShotTimer_Handle 就会停止运行。

        当按下 KEY_UP 键的话周期定时器就会开始运行,屏幕左侧区域的背景色会被刷新为其他颜色。由于定时器 AutoReloadTimer_Handle 是周期定时器,所以不会停止运行,除非按下 KEY1 键同时关闭定时器 AutoReloadTimer_Handle 和 OneShotTimer_Handle。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1167102.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在公共安全场景下,智能监控如何做到保障安全的同时又最大化地提供便利?

智能监控系统应用的场景十分广泛,其中,公共安全场所的需求尤为重要,为保障公共区域的安全,提升人民群众的归属感,增强公共场所的安全性,智慧安防EasyCVR智能视频监控系统做出了极大努力。具体细节如下&…

33 mysql find_in_set 的实现

前言 这里我们主要是来探讨一下 mysql 中 in 的使用, find_in_set 的使用 这两者 在我们实际应用中应该也是 非常常用的了 测试数据表如下 CREATE TABLE tz_test (id int(11) unsigned NOT NULL AUTO_INCREMENT,field1 varchar(16) DEFAULT NULL,field2 varchar(16) DEFAU…

MobPush智能推送:数智化运营加速用户转化

随着移动应用市场竞争日益激烈,如何保持APP用户活跃度实现商业价值成为无数APP运营者的烦恼。是继续加大力度拉新促活,用庞大的用户体量获得平台商业价值?还是加强对存量用户的精细化运营,激发存量用户付费转化实现弯道超车&#…

python爬虫实战——今日头条新闻数据获取

大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 第三方库: requests >>> pip install requests 第三方模块安装: win R 输入cmd 输入安装命令 pip install 模块名 (如果你觉得安装速度比较慢, 你…

【前端周报11.03】

前端周汇报11.03 那我们接着上一周的继续往下进行推进上周总结本周工作下周内容 那我们接着上一周的继续往下进行推进 上周总结 上一周的话我其实最主要的工作还是进行了一系列的调研主要的话是针对于我们未来要做的小程序的项目的,为未来开发这个小程序做好一系列…

一整套智慧工地源码,劳务实名制、施工安全管理、绿色施工、危大工程设备监测、视频AI识别功能

智慧工地系统充分利用计算机技术、互联网、物联网、云计算、大数据等新一代信息技术,以PC端,移动端,设备端三位一体的管控方式为企业现场工程管理提供了先进的技术手段。让劳务、设备、物料、安全、环境、能源、资料、计划、质量、视频监控等…

c 函数调用过程中,调用函数的栈帧一旦被修改,被调用函数则无法正确返回。( X )

当一个函数被调用时,它的栈帧会被创建并压入调用栈中。栈帧包含了函数的局部变量、参数以及返回地址等信息。当函数执行完毕后,栈帧会被弹出,返回到调用函数的位置继续执行。 下面是一个示例代码,展示了调用函数栈帧被修改但不影…

【Python_GraphicsView 学习笔记(一)】Graphics View框架的基本介绍

【Python_GraphicsView 学习笔记(一)】Graphics View框架的基本介绍 前言正文1、Graphics View框架简介2、Graphics View框架与QPainter类的区别3、Graphics View框架的三个组成部分4、场景QGraphicsScene类5、视图QGraphicsView类6、图形项QGraphicsIte…

解析电源模块功能测试项目 电源模块测试系统助力功能测试

电源测试一般包括保护特性测试、安规测试、电磁兼容测试、可靠性测试、功能测试以及其它一些特定测试。电源功能测试是评估电源质量好坏、性能、响应等的重要测试方法,也是电源的常规测试内容。 电源功能测试项目 电源功能测试是确保电源稳定性和可靠性的重要测试指…

使用android studio开发flutter应用,10分钟环境配置

1.安装flutter sdk 安装中文官网配置环境即可:安装和环境配置 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 然后如果你的网络不好的话,可以修改flutter的源地址,将下面的变量创建成新的环境变量 FLUTTER_STORAGE_BASE_URLhttp…

接口测试框架中的鉴权处理!

接口自动化测试中通常都有鉴权机制,就是判断是否在登录状态下,已登录方可调用接口,未登录则不可调用。本文将带领大家学习使用rest-assured框架实现基于cookies和token的鉴权关联,实现接口自动化测试。 1、基于cookies的鉴权关联…

创建自定义美颜滤镜:使用第三方美颜SDK的步骤指南

美颜滤镜在现代移动应用和直播平台中变得越来越受欢迎。它们可以让用户在自拍照片、视频聊天或实时直播中看起来更加美丽和自信。如果您是一位应用开发者,想要增加美颜滤镜功能,但又不想从头开始构建整个系统,那么使用第三方美颜SDK可能是一个…

【C++ 学习 ㉚】- 超详解 C++11 的右值引用

目录 一、左值和右值 二、左值引用和右值引用 三、移动语义 3.1 - 左值引用的短板 3.2 - 移动构造和移动赋值 四、move 函数 4.1 - remove_reference 的实现 4.2 - move 的实现 五、完美转发 5.1 - forward 的实现 5.2 - 使用场景 很多初学者都感觉右值引用晦涩难懂…

宽以光电厚以激光 组合式测宽测厚仪 性价比更高

对于板材类产品而言,对其几何尺寸的品质检测,往往是宽度与厚度兼具的,为了同时满足两种检测需求,制造了组合式测宽测厚仪。 单独的测宽仪的原理有光电、机器视觉、激光等,光电测宽仪不仅可选择的测量原理多&#xff0c…

若依分离版——配置多数据源(mysql和oracle),实现一个方法操作多个数据源

目录 一、若依平台配置 二、编写oracle数据库访问的各类文件 三. 一个方法操作多个数据源 一、若依平台配置 1、在ruoyi-admin的pom.xml添加依赖 <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version…

tensorflow-gpu 找不到指定模块

排除&#xff1a; 1.python编译器是64位 查询教程 2. cuda cudnn版本 均是12.2 可以向下兼容 cmd&#xff1a; nvcc -V即可 另一种方法 tensorflow官网教程 pip install tensorflow_gpu1.12.0 4.安装torch-gpu 检查所在环境 解决&#xff01;&#xff01; conda install …

瑞禧生物分享~今天是 碲化银粉体 Ag2Te CAS:12002-99-2

碲化银粉体 Ag2Te CAS&#xff1a;12002-99-2 纯度&#xff1a;99% 仅用于科研 储藏条件&#xff1a;冷藏-20℃ 简介&#xff1a;碲化银是一种无机化合物&#xff0c;化学式是Ag2Te。它是一种单斜晶体&#xff0c;并以矿物的形式存在于自然界中。化学计量的碲化银具有n型半导…

生成第一个 Blazor 应用

前言&#xff1a;博主文章仅用于学习、研究和交流目的&#xff0c;不足和错误之处在所难免&#xff0c;希望大家能够批评指出&#xff0c;博主核实后马上更改。 概述&#xff1a;Blazor 是一个使用 Blazor 生成交互式客户端 Web UI 的框架使用 C# 创建丰富的交互式 UI。共享使…

rabbitmq的confirm模式获取correlationData为null解决办法

回调函数confirm中的correlationDatanull // 实现confirm回调,发送到和没发送到exchange,都触发 Override public void confirm(CorrelationData correlationData, boolean ack, String cause) {// 参数说明:// correlationData: 相关数据,可以在发送消息时,进行设置该参数// …

重大喜讯 | UMS攸信技术斩获厦门5G应用大赛三等奖!

近日&#xff0c;第三届厦门5G应用大赛获奖项目名单公示&#xff0c;攸信技术的“AI5G柔性生产缺陷检测示范线”项目脱颖而出&#xff0c;荣获「第三届厦门5G应用大赛三等奖」&#xff01; 第三届厦门5G应用大赛获奖项目名单 本次获奖既是对攸信技术5G技术创新的鼓励&#xff0…