源码下载链接:https://taileliekaishi.lanzoui.com/igXjrg6dipi
时间分辨率:也可以理解为是定时器的步长,假如现在要定时1s,时间的分辨率是100ms,计数器的值只需要设置为10,当从10减到0的时候是10次,1次是100ms,10 x 100 = 1000ms = 1s。
回调函数:有A、B两个函数,A这个函数是有参数的,将B函数名(地址)作为A函数的参数,当A函数在执行的过程中调用了B函数,则B函数就称为A函数的一个回调函数。
定时器的定义:
OS_TMR tmr1; //定时器1
定时器的创建:
//创建定时器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 *)&err); //返回的错误码
定时器的回调函数:定时完成自动调用这个函数
//定时器1的回调函数
void tmr1_callback(void *p_tmr, void *p_arg)
{
static u8 tmr1_num=0;
LCD_ShowxNum(62,111,tmr1_num,3,16,0x80); //显示定时器1的执行次数
LCD_Fill(6,131,114,313,lcd_discolor[tmr1_num%14]);//填充区域
tmr1_num++; //定时器1执行次数加1
}
单次定时器:
如果想再开启一次,必须再调用OSTmrCreate()这个函数
周期模式(无初始延迟):
周期模式(有初始延迟):
实验任务:
代码:
//任务优先级
#define START_TASK_PRIO 3
//任务堆栈大小
#define START_STK_SIZE 128
//任务控制块
OS_TCB StartTaskTCB;
//任务堆栈
CPU_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *p_arg);
//任务优先级
#define TASK1_TASK_PRIO 4
//任务堆栈大小
#define TASK1_STK_SIZE 128
//任务控制块
OS_TCB Task1_TaskTCB;
//任务堆栈
CPU_STK TASK1_TASK_STK[TASK1_STK_SIZE];
void task1_task(void *p_arg);
OS_TMR tmr1; //定时器1
OS_TMR tmr2; //定时器2
void tmr1_callback(void *p_tmr, void *p_arg); //定时器1回调函数
void tmr2_callback(void *p_tmr, void *p_arg); //定时器2回调函数
//LCD刷屏时使用的颜色
int lcd_discolor[14]={ WHITE, RED, BLUE, BRED,
GRED, GBLUE, BLACK, MAGENTA,
GREEN, CYAN, YELLOW,BROWN,
BRRED, GRAY };
//主函数
int main(void)
{
OS_ERR err;
CPU_SR_ALLOC();
delay_init(); //时钟初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组配置
uart_init(115200); //串口初始化
LED_Init(); //LED初始化
LCD_Init(); //LCD初始化
KEY_Init(); //按键初始化
POINT_COLOR = RED;
LCD_ShowString(30,10,200,16,16,"ALIENTEK STM32F1");
LCD_ShowString(30,30,200,16,16,"UCOSIII Examp 9-1");
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, "TIMER1:000");
LCD_ShowString(126,111,110,16,16,"TIMER2:000");
OSInit(&err); //初始化UCOSIII
OS_CRITICAL_ENTER(); //进入临界区
//创建开始任务
OSTaskCreate((OS_TCB * )&StartTaskTCB, //任务控制块
(CPU_CHAR * )"start task", //任务名字
(OS_TASK_PTR )start_task, //任务函数
(void * )0, //传递给任务函数的参数
(OS_PRIO )START_TASK_PRIO, //任务优先级
(CPU_STK * )&START_TASK_STK[0], //任务堆栈基地址
(CPU_STK_SIZE)START_STK_SIZE/10, //任务堆栈深度限位
(CPU_STK_SIZE)START_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 * )&err); //存放该函数错误时的返回值
OS_CRITICAL_EXIT(); //退出临界区
OSStart(&err); //开启UCOSIII
}
//开始任务函数
void start_task(void *p_arg)
{
OS_ERR err;
CPU_SR_ALLOC();
p_arg = p_arg;
CPU_Init();
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); //统计任务
#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,&err);
#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 *)&err); //返回的错误码
//创建定时器2
OSTmrCreate((OS_TMR *)&tmr2,
(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,
(OS_ERR *)&err);
OS_CRITICAL_ENTER(); //进入临界区
//创建TASK1任务
OSTaskCreate((OS_TCB * )&Task1_TaskTCB,
(CPU_CHAR * )"Task1 task",
(OS_TASK_PTR )task1_task,
(void * )0,
(OS_PRIO )TASK1_TASK_PRIO,
(CPU_STK * )&TASK1_TASK_STK[0],
(CPU_STK_SIZE)TASK1_STK_SIZE/10,
(CPU_STK_SIZE)TASK1_STK_SIZE,
(OS_MSG_QTY )0,
(OS_TICK )0,
(void * )0,
(OS_OPT )OS_OPT_TASK_STK_CHK|OS_OPT_TASK_STK_CLR,
(OS_ERR * )&err);
OS_CRITICAL_EXIT(); //退出临界区
OSTaskDel((OS_TCB*)0,&err); //删除start_task任务自身
}
//任务1的任务函数
void task1_task(void *p_arg)
{
u8 key,num;
OS_ERR err;
while(1)
{
key = KEY_Scan(0);
switch(key)
{
case WKUP_PRES: //当key_up按下的话打开定时器1
OSTmrStart(&tmr1,&err); //开启定时器1
printf("开启定时器1\r\n");
break;
case KEY0_PRES: //当key0按下的话打开定时器2
OSTmrStart(&tmr2,&err); //开启定时器2
printf("开启定时器2\r\n");
break;
case KEY1_PRES: //当key1按下话就关闭定时器
OSTmrStop(&tmr1,OS_OPT_TMR_NONE,0,&err); //关闭定时器1
OSTmrStop(&tmr2,OS_OPT_TMR_NONE,0,&err); //关闭定时器2
printf("关闭定时器1和2\r\n");
break;
}
num++;
if(num==50) //每500msLED0闪烁一次
{
num = 0;
LED0 = ~LED0;
}
OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err); //延时10ms
}
}
//定时器1的回调函数
void tmr1_callback(void *p_tmr, void *p_arg)
{
static u8 tmr1_num=0;
LCD_ShowxNum(62,111,tmr1_num,3,16,0x80); //显示定时器1的执行次数
LCD_Fill(6,131,114,313,lcd_discolor[tmr1_num%14]);//填充区域
tmr1_num++; //定时器1执行次数加1
}
//定时器2的回调函数
void tmr2_callback(void *p_tmr,void *p_arg)
{
static u8 tmr2_num = 0;
tmr2_num++; //定时器2执行次数加1
LCD_ShowxNum(182,111,tmr2_num,3,16,0x80); //显示定时器1执行次数
LCD_Fill(126,131,233,313,lcd_discolor[tmr2_num%14]); //填充区域
LED1 = ~LED1;
printf("定时器2运行结束\r\n");
}
串口实验结果: