目录

软件定时器概述

使用步骤:

创建软件定时器:

启动软件定时器:

停止软件定时器:

删除软件定时器:

单次定时器:

​编辑周期定时器:

无初始化延时:

有初始化延时:

软件定时器实验:


软件定时器概述

在学习单片机的的时候,会使用定时器来做很多事情,这个定时器时单片机自带的也就是硬件定时器,而UCOSIII内核提供了一个模拟定时器的机制类似于任务,但是占用资源少,只能做一些简单的定时控制,如可以定时器喂狗控灯。在软件定时器中绝对不能添加事件管理函数,阻塞等待函数。

使用步骤:

创建软件定时器:

利用OSTmrCreate()函数,函数原型如下:

参数:

 p_tmr,                软件定时器对象

p_name,              软件定时器的名字

dly,                      启动定时器后,延迟多长时间执行,默认隐含dly10ms

period,                 定时周期,默认隐含period10ms

opt:                      模式

OS_OPT_TMR_ONE_SHOT,软件定时器执行一遍

OS_OPT_TMR_PERIODIC,软件定时器周期性执行

p_callback,          软件定时器执行的回调函数 void MyCallback (OS_TMR *p_tmr, void *p_arg);

p_callback_arg,   传递参数给软件定时器的回调函数

p_err,                   返回错误码,没有错误的就返回OS_ERR_NONE

启动软件定时器:

函数原型如下:

参数:

p_tmr :软件定时器对象

p_err  :返回错误码,没有错误就返回OS_ERR_NONE

返回值:

 DEF_TRUE is the timer was started

DEF_FALSE if not or upon an error

停止软件定时器:

函数原型如下:

参数:

p_tmr 软件定时器对象

os_opt 默认参数,OS_OPT_TMR_NONE

p_callback_arg 填写OSTmrCreate创建时传递给软件定时器arg的参数

p_err 返回错误码,没有错误就返回OS_ERR_NONE

删除软件定时器:

函数原型:

参数:

 p_tmr,软件定时器对象

 p_err,返回错误码,没有错误的就返回OS_ERR_NONE

单次定时器:

使用OSTmrCreate()函数创建定时器参数时候把参数opt设置为OS_OPT_TMR_ONE_SHOT,就是创建的单次定时器。创建一个单次定时器以后,我们一旦调用OSTmrStart()函数定时器就会是从创建定义的dly开始倒计时直到减为0调用回调函数。

上图展示了单次定时器的运行,dly减到0的时候调用回调函数,到这里定时器就停止运行了不再做任何事,我们可以调用OSTmrStop()函数来删除这个运行完成的定时器,也可以重新调用OSTmrStart()函数来重新开启,如下图

周期定时器:

无初始化延时:

使用OSTmrCreate()函数创建定时器时把参数opt设置为OS_OPT_TMR_PERIODIC ,就是创建周期定时器。当计时器倒计数完成之后,定时器就会调用周期函数,并重置计数器开始下一轮定时,这样一直循环下去。如果使用OSTmrCreate函数创建定时器的时候,参数dly为0的话,那么定时器在每个周期开始时计数器的初始值就是period,如下图

有初始化延时:

在创建任务的时候可以创建带有初始化延时,初始化初始化延时就是使用OSTmrCreate()函数中的参数dly就是初始化延时,定时器的第一个周期是dly。当第一个周期完成后就用参数period作为周期值,主要流程如下图:

软件定时器实验:

任务要求:先两个任务,任务A和任务B,任务A用于创建两个定时器:是定时器1和定时器2,任务A还创建了另一个任务B。其中定时器 1 为周期定时器,初始延时为 200ms,以后的定时器周期为 1000ms,定时器 2 为单次定时器,延时为2000ms。

任务 B 作为按键检测任务,当 KEY_UP 键按下的时候,打开定时器 1;当 KEY0 按下的时候打开定时器 2;当 KEY1 按下的时候,同时关闭定时器 1 和 2;任务 B 还用来控制 LED0,使其闪烁,提示系统正在运行。

定时器 1 定时完成以后调用回调函数串口输出定时器1进入一次。定时器 2 是单次定时器,我们通过串口打印来观察单次定时器的运行情况。

实验效果:

代码历程:

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "includes.h"
#include "os_app_hooks.h"
#include "key.h"
//UCOSIII中以下优先级用户程序不能使用,ALIENTEK
//将这些优先级分配给了UCOSIII的5个系统内部任务
//优先级0:中断服务服务管理任务 OS_IntQTask()
//优先级1:时钟节拍任务 OS_TickTask()
//优先级2:定时任务 OS_TmrTask()
//优先级OS_CFG_PRIO_MAX-2:统计任务 OS_StatTask()
//优先级OS_CFG_PRIO_MAX-1:空闲任务 OS_IdleTask()

//创建任务A
//定义任务优先级
#define TASK_A_PRIO 3
//定义任务控制块
OS_TCB TASK_A_TCB;
//定义任务堆栈大小
#define TASK_A_STK_SIZE 128
//定义任务堆栈
CPU_STK TASK_A_STK[TASK_A_STK_SIZE];
//定义任务函数
void TASK_A(void *arg);

//创建任务B
//定义任务优先级
#define TASK_B_PRIO 4
//定义任务控制块
OS_TCB TASK_B_TCB;
//定义任务堆栈大小
#define TASK_B_STK_SIZE 128
//定义任务堆栈
CPU_STK TASK_B_STK[TASK_B_STK_SIZE];
//定义任务函数
void TASK_B(void *arg);

/
OS_TMR tmr1;//定时器1
OS_TMR tmr2;//定时器1
void tmr1_callback(void *p_tmr, void *p_arg); //定时器1回调函数
void tmr2_callback(void *p_tmr, void *p_arg); //定时器1回调函数



int main(void)
{
	OS_ERR err1;//错误码变量
	CPU_SR_ALLOC();//定义临界区需要的变量
	
	//硬件初始化
	delay_init();       //延时初始化
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组配置
	uart_init(115200);    //串口波特率设置
	LED_Init();
	KEY_Init();
	
	OSInit(&err1);//初始化UCOSIII
	OS_CRITICAL_ENTER();//进入临界区代码
	
	//创建定时器1
	
	//创建开始任务1
	OSTaskCreate((OS_TCB 	* )&TASK_A_TCB,		//任务控制块
				 (CPU_CHAR	* )"main TASKA", 		//任务名字
                 (OS_TASK_PTR )TASK_A, 			//任务函数
                 (void		* )0,					//传递给任务函数的参数
                 (OS_PRIO	  )TASK_A_PRIO,     //任务优先级
                 (CPU_STK   * )&TASK_A_STK[0],	//任务堆栈基地址
                 (CPU_STK_SIZE)TASK_A_STK_SIZE/10,	//任务堆栈深度限位
                 (CPU_STK_SIZE)TASK_A_STK_SIZE,		//任务堆栈大小
                 (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                 (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                 (void   	* )0,					//用户补充的存储区
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                 (OS_ERR 	* )&err1);				//存放该函数错误时的返回值
	
	OS_CRITICAL_EXIT();//退出临界区代码
	OSStart(&err1);//开启UCOSIII

	while(1);
}

//开始任务函数
void TASK_A(void *arg)
{
	OS_ERR err2_3;//错误码变量
	CPU_SR_ALLOC();//定义临界区需要的变量
	arg = arg;
	
	CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
   OSStatTaskCPUUsageInit(&err2_3);  	//统计任务                
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN		//如果使能了测量中断关闭时间
    CPU_IntDisMeasMaxCurReset();	
#endif
	
#if	OS_CFG_SCHED_ROUND_ROBIN_EN  //当使用时间片轮转的时候
	 //使能时间片轮转调度功能,时间片长度为1个系统时钟节拍,既1*5=5ms
	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err2_3);  
#endif	
	
//#if OS_CFG_APP_HOOKS_EN				//使用钩子函数
//	App_OS_SetAllHooks();			
//#endif
	
#if OS_CFG_SCHED_ROUND_ROBIN_EN
	//使用时间片轮转调度功能,时间片长度为一个时钟节拍即1*5=5ms
	OSSchedRoundRobinCfg(DEF_ENABLED,1,&err2_3);
#endif
	
	//创建定时器1 
	OSTmrCreate((OS_TMR		*)&tmr1,		//定时器1
                (CPU_CHAR	*)"tmr1",		//定时器名字
                (OS_TICK	 )20,			//20*10=200ms
                (OS_TICK	 )100,          //100*10=1000ms
                (OS_OPT		 )OS_OPT_TMR_PERIODIC, //周期模式
                (OS_TMR_CALLBACK_PTR)tmr1_callback,//定时器1回调函数
                (void	    *)0,			//参数为0
                (OS_ERR	    *)&err2_3);		//返回的错误
	//创建定时器2
	OSTmrCreate((OS_TMR		*)&tmr2,		//定时器1
                (CPU_CHAR	*)"tmr2",		//定时器名字
                (OS_TICK	 )200,			//200*10=2000ms
                (OS_TICK	 )0,          //
                (OS_OPT		 )OS_OPT_TMR_ONE_SHOT, //单次延时
                (OS_TMR_CALLBACK_PTR)tmr2_callback,//定时器2回调函数
                (void	    *)0,			//参数为0
                (OS_ERR	    *)&err2_3);		//返回的错误码
				

	OS_CRITICAL_ENTER();//进入临界区代码
	//创建开始任务B
	OSTaskCreate((OS_TCB 	* )&TASK_B_TCB,		//任务控制块
				 (CPU_CHAR	* )"main TASKB", 		//任务名字
                 (OS_TASK_PTR )TASK_B, 			//任务函数
                 (void		* )0,					//传递给任务函数的参数
                 (OS_PRIO	  )TASK_B_PRIO,     //任务优先级
                 (CPU_STK   * )&TASK_B_STK[0],	//任务堆栈基地址
                 (CPU_STK_SIZE)TASK_B_STK_SIZE/10,	//任务堆栈深度限位
                 (CPU_STK_SIZE)TASK_B_STK_SIZE,		//任务堆栈大小
                 (OS_MSG_QTY  )0,					//任务内部消息队列能够接收的最大消息数目,为0时禁止接收消息
                 (OS_TICK	  )0,					//当使能时间片轮转时的时间片长度,为0时为默认长度,
                 (void   	* )0,					//用户补充的存储区
                 (OS_OPT      )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR, //任务选项
                 (OS_ERR 	* )&err2_3);				//存放该函数错误时的返回值
			 
								 
	OS_CRITICAL_EXIT();//退出临界区代码
	
	//任务一执行完函数之后删掉自身
	OSTaskDel((OS_TCB *)0,&err2_3);			 
}



void TASK_B(void *arg)
{
	u8 key,num;
	OS_ERR err_B;
	while(1)
	{
		key = KEY_Scan(0);
		switch(key)
		{
			case WKUP_PRES: //当key_up按下的话打开定时器1
					OSTmrStart(&tmr1,&err_B); //开启定时器1
					printf("开启定时器1\r\n");
			break ;
			
			case KEY0_PRES://当key0按下的话打开定时器2
					OSTmrStart(&tmr2,&err_B); //开启定时器2
					printf("开启定时器2\r\n");
			break ;
			
			case KEY1_PRES:
					OSTmrStop(&tmr1,OS_OPT_TMR_NONE,0,&err_B); //关闭定时器1
					OSTmrStop(&tmr2,OS_OPT_TMR_NONE,0,&err_B); //关闭定时器2
					printf("关闭定时器1和2\r\n");
			break ;	
		}
		num++;
		if(num==50)//每500msled闪烁一次
		{
			num=0;
			LED0 = ~LED0;
		}
		OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err_B);//延时10ms
	}
	
}


//定时器1回调函数
void tmr1_callback(void *p_tmr, void *p_arg)
{
	static u8 tmr1_num=0;
	tmr1_num++; //定时器1执行次数加1
	printf("定时器1进入一次\r\n");
}


//定时器2回调函数
void tmr2_callback(void *p_tmr, void *p_arg)
{
	static u8 tmr2_num = 0;
	tmr2_num++; //定时器2执行次数加1
	LED1 = ~LED1;
	printf("定时器2运行结束\r\n");
}


Logo

鸿蒙生态一站式服务平台。

更多推荐