2019-10-16 05:47发布
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
uart_init(72,9600); //串口初始化为9600
delay_init(72); //延时初始化
LED_Init(); //初始化与LED连接的硬件接口
LCD_Init(); //初始化LCD
usmart_dev.init(72); //初始化USMART
BEEP_Init(); //蜂鸣器初始化
KEY_Init(); //按键初始化
TPAD_Init(72); //初始化TPAD
FSMC_SRAM_Init(); //初始化外部SRAM
mem_init(SRAMIN); //初始化内部内存池
mem_init(SRAMEX); //初始化外部内存池
tp_dev.init();
ucos_load_main_ui();
OSInit(); //初始化UCOSII
OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE
-1],START_TASK_PRIO );//创建起始任务
OSStart();
}
//开始任务
void start_task(void *pdata)
OS_CPU_SR cpu_sr=0; u8 err;
pdata = pdata;
msg_key=OSMboxCreate((void*)0); //创建消息邮箱
q_msg=OSQCreate(&MsgGrp[0],256); //创建消息队列
flags_key=OSFlagCreate(0,&err); //创建信号量集
OSStatInit(); //初始化统计任务.这里会延时1秒钟左右
OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断)
OSTaskCreate(led_task,(void *)0,(OS_STK*)&LED_TASK_STK[LED_STK_SIZE-1],
LED_TASK_PRIO);
OSTaskCreate(touch_task,(void *)0,(OS_STK*)&TOUCH_TASK_STK
[TOUCH_STK_SIZE-1],TOUCH_TASK_PRIO);
OSTaskCreate(qmsgshow_task,(void *)0,(OS_STK*)&QMSGSHOW_TASK_STK
[QMSGSHOW_STK_SIZE-1],QMSGSHOW_TASK_PRIO);
OSTaskCreate(main_task,(void *)0,(OS_STK*)&MAIN_TASK_STK[MAIN_STK_SIZE
-1],MAIN_TASK_PRIO);
OSTaskCreate(flags_task,(void *)0,(OS_STK*)&FLAGS_TASK_STK
[FLAGS_STK_SIZE-1],FLAGS_TASK_PRIO);
OSTaskCreate(key_task,(void *)0,(OS_STK*)&KEY_TASK_STK[KEY_STK_SIZE-1]
,KEY_TASK_PRIO);
OSTaskSuspend(START_TASK_PRIO); //挂起起始任务.
OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断)
//LED任务
void led_task(void *pdata)
u8 t;
while(1)
t++; delay_ms(10);
if(t==8)LED0=1; //LED0灭
if(t==100) {t=0; LED0=0; } //LED0亮
//触摸屏任务
void touch_task(void *pdata)
tp_dev.scan(0);
if(tp_dev.sta&TP_PRES_DOWN) //触摸屏被按下
if(tp_dev.x<120&&tp_dev.y<lcddev.height&&tp_dev.y>220)
TP_Draw_Big_Point(tp_dev.x,tp_dev.y,BLUE); //画图
delay_ms(2);
}else delay_ms(10); //没有按键按下的时候
//队列消息显示任务
void qmsgshow_task(void *pdata)
u8 *p; u8 err;
p=OSQPend(q_msg,0,&err);//请求消息队列
LCD_ShowString(5,170,240,16,16,p);//显示消息
myfree(SRAMIN,p); delay_ms(500);
//主任务
void main_task(void *pdata)
u32 key=0; u8 err;
u8 tmr2sta=1; //软件定时器2开关状态
u8 tmr3sta=0; //软件定时器3开关状态
u8 flagsclrt=0; //信号量集显示清零倒计时
tmr1=OSTmrCreate(10,10,OS_TMR_OPT_PERIODIC,
(OS_TMR_CALLBACK)tmr1_callback,0,"tmr1",&err); //100ms执行一次
tmr2=OSTmrCreate(10,20,OS_TMR_OPT_PERIODIC,
(OS_TMR_CALLBACK)tmr2_callback,0,"tmr2",&err); //200ms执行一次
tmr3=OSTmrCreate(10,10,OS_TMR_OPT_PERIODIC,
(OS_TMR_CALLBACK)tmr3_callback,0,"tmr3",&err); //100ms执行一次
OSTmrStart(tmr1,&err); //启动软件定时器1
OSTmrStart(tmr2,&err); //启动软件定时器2
key=(u32)OSMboxPend(msg_key,10,&err);
if(key)
flagsclrt=51;//500ms后清除
OSFlagPost(flags_key,1<<(key-1),OS_FLAG_SET,&err);//设置信号量为1
if(flagsclrt)//倒计时
flagsclrt--;
if(flagsclrt==1)LCD_Fill(140,162,239,162+16,WHITE);//清除显示
switch(key)
case 1: LED1=!LED1; break;//控制DS1
case 2://控制软件定时器3
tmr3sta=!tmr3sta;
if(tmr3sta)OSTmrStart(tmr3,&err);
else OSTmrStop(tmr3,OS_TMR_OPT_NONE,0,&err);//关闭软件定时器3
break;
case 3: LCD_Fill(0,221,119,lcddev.height,WHITE); break;//清除
case 4://校准
OSTaskSuspend(TOUCH_TASK_PRIO); //挂起触摸屏任务
OSTaskSuspend(QMSGSHOW_TASK_PRIO); //挂起队列信息显示任务
OSTmrStop(tmr1,OS_TMR_OPT_NONE,0,&err); //关闭软件定时器1
if(tmr2sta)OSTmrStop(tmr2,OS_TMR_OPT_NONE,0,&err);//关闭定时器2 TP_Adjust();
OSTmrStart(tmr1,&err); //重新开启软件定时器1
if(tmr2sta)OSTmrStart(tmr2,&err); //重新开启软件定时器2
OSTaskResume(TOUCH_TASK_PRIO); //解挂
OSTaskResume(QMSGSHOW_TASK_PRIO);//解挂
ucos_load_main_ui(); //重新加载主界面
case 5://软件定时器2 开关
tmr2sta=!tmr2sta;
if(tmr2sta)OSTmrStart(tmr2,&err); //开启软件定时器2
else
OSTmrStop(tmr2,OS_TMR_OPT_NONE,0,&err);//关闭软件定时器2
LCD_ShowString(148,262,240,16,16,"TMR2 STOP");
delay_ms(10);
//信号量集处理任务
void flags_task(void *pdata)
u16 flags; u8 err;
flags=OSFlagPend(flags_key,0X001F,OS_FLAG_WAIT_SET_ANY,0,&err);
//等待信号量
if(flags&0X0001)LCD_ShowString(140,162,240,16,16,"KEY0 DOWN ");
if(flags&0X0002)LCD_ShowString(140,162,240,16,16,"KEY1 DOWN ");
if(flags&0X0004)LCD_ShowString(140,162,240,16,16,"KEY2 DOWN ");
if(flags&0X0008)LCD_ShowString(140,162,240,16,16,"KEY_UP DOWN");
if(flags&0X0010)LCD_ShowString(140,162,240,16,16,"TPAD DOWN ");
BEEP=1; delay_ms(50); BEEP=0;
OSFlagPost(flags_key,0X001F,OS_FLAG_CLR,&err);//全部信号量清零
//按键扫描任务
void key_task(void *pdata)
u8 key;
delay_ms(10); key=KEY_Scan(0);
if(key==0) if(TPAD_Scan(0))key=5;
if(key)OSMboxPost(msg_key,(void*)key);//发送消息
本章test.c的代码有点多,因为我们创建了7个任务,3个软件定时器及其回调函数,所以,整个代码有点多,我们创建的7个任务为:start_task、led_task、touch_task、qmsgshow_task 、flags_task 、main_task和key_task,优先级分别是10和7~2,堆栈大小除了main_task是128,其他都是64。
我们还创建了3个软件定时器tmr1、tmr2和tmr3,tmr1用于显示CPU使用率和内存使用率,每100ms执行一次;tmr2用于在LCD的右下角区域不停的显示各种颜 {MOD},每200ms执行一次;tmr3用于定时向队列发送消息,每100ms发送一次。
本章,我们依旧使用消息邮箱msg_key在按键任务和主任务之间传递键值数据,我们创建信号量集flags_key,在主任务里面将按键键值通过信号量集传递给信号量集处理任务flags_task,实现按键信息的显示以及发出按键提示音。
本章,我们还创建了一个大小为256的消息队列q_msg,通过软件定时器tmr3的回调函数向消息队列发送消息,然后在消息队列显示任务qmsgshow_task里面请求消息队列,并在LCD上面显示得到的消息。消息队列还用到了动态内存管理。
在主任务main_task里面,我们实现了60.2节介绍的功能:KEY0控制LED1亮灭;KEY1控制软件定时器tmr3的开关,间接控制队列信息的发送;KEY2清除触摸屏输入;WK_UP用于触摸屏校准,在校准的时候,要先挂起触摸屏任务、队列消息显示任务,并停止软件定时器tmr1和tmr2,否则可能对校准时的LCD显示造成干扰;TPAD按键用于控制软件定时器tmr2的开关,间接控制屏幕显示。
软件设计部分就为大家介绍到这里。
60.4 下载验证
在代码编译成功之后,我们通过下载代码到战舰STM32开发板上,可以看到LCD显示界面如图60.4.1所示:
图60.4.1 初始界面
从图中可以看出,默认状态下,CPU使用率为21%左右。比上一章多出很多,这主要是key_task里面增加了触摸按键TPAD的检测,而TPAD检测是一个比较耗资源(主要是延时不是2ms的倍数)的过程,另外不停的刷屏(tmr2)也需要一定资源。
通过按KEY0,可以控制DS1的亮灭;
通过按KEY1则可以启动tmr3控制消息队列发送,可以在LCD上面看到Q和MEM的值慢慢变大(说明队列消息在增多,占用内存也随着消息增多而增大),在QUEUE MSG区,开始显示队列消息,再按一次KEY1停止tmr3,此时可以看到Q和MEM逐渐减小。当Q值变为0的时候,QUEUE MSG也停止显示(队列为空)。
通过KEY2按键,清除TOUCH区域的输入。
通过WK_UP按键,可以进行触摸屏校准。
通过TPAD按键,可以启动/停止tmr2,从而控制屏幕的刷新。
在TOUCH区域,可以输入手写内容。
任何按键按下,蜂鸣器都会发出“滴”的一声,提示按键被按下,同时在FLAGS区域显示按键信息。
最多设置5个标签!
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
uart_init(72,9600); //串口初始化为9600
delay_init(72); //延时初始化
LED_Init(); //初始化与LED连接的硬件接口
LCD_Init(); //初始化LCD
usmart_dev.init(72); //初始化USMART
BEEP_Init(); //蜂鸣器初始化
KEY_Init(); //按键初始化
TPAD_Init(72); //初始化TPAD
FSMC_SRAM_Init(); //初始化外部SRAM
mem_init(SRAMIN); //初始化内部内存池
mem_init(SRAMEX); //初始化外部内存池
tp_dev.init();
ucos_load_main_ui();
OSInit(); //初始化UCOSII
OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE
-1],START_TASK_PRIO );//创建起始任务
OSStart();
}
//开始任务
void start_task(void *pdata)
{
OS_CPU_SR cpu_sr=0; u8 err;
pdata = pdata;
msg_key=OSMboxCreate((void*)0); //创建消息邮箱
q_msg=OSQCreate(&MsgGrp[0],256); //创建消息队列
flags_key=OSFlagCreate(0,&err); //创建信号量集
OSStatInit(); //初始化统计任务.这里会延时1秒钟左右
OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断)
OSTaskCreate(led_task,(void *)0,(OS_STK*)&LED_TASK_STK[LED_STK_SIZE-1],
LED_TASK_PRIO);
OSTaskCreate(touch_task,(void *)0,(OS_STK*)&TOUCH_TASK_STK
[TOUCH_STK_SIZE-1],TOUCH_TASK_PRIO);
OSTaskCreate(qmsgshow_task,(void *)0,(OS_STK*)&QMSGSHOW_TASK_STK
[QMSGSHOW_STK_SIZE-1],QMSGSHOW_TASK_PRIO);
OSTaskCreate(main_task,(void *)0,(OS_STK*)&MAIN_TASK_STK[MAIN_STK_SIZE
-1],MAIN_TASK_PRIO);
OSTaskCreate(flags_task,(void *)0,(OS_STK*)&FLAGS_TASK_STK
[FLAGS_STK_SIZE-1],FLAGS_TASK_PRIO);
OSTaskCreate(key_task,(void *)0,(OS_STK*)&KEY_TASK_STK[KEY_STK_SIZE-1]
,KEY_TASK_PRIO);
OSTaskSuspend(START_TASK_PRIO); //挂起起始任务.
OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断)
}
//LED任务
void led_task(void *pdata)
{
u8 t;
while(1)
{
t++; delay_ms(10);
if(t==8)LED0=1; //LED0灭
if(t==100) {t=0; LED0=0; } //LED0亮
}
}
//触摸屏任务
void touch_task(void *pdata)
{
while(1)
{
tp_dev.scan(0);
if(tp_dev.sta&TP_PRES_DOWN) //触摸屏被按下
{
if(tp_dev.x<120&&tp_dev.y<lcddev.height&&tp_dev.y>220)
{
TP_Draw_Big_Point(tp_dev.x,tp_dev.y,BLUE); //画图
delay_ms(2);
}
}else delay_ms(10); //没有按键按下的时候
}
}
//队列消息显示任务
void qmsgshow_task(void *pdata)
{
u8 *p; u8 err;
while(1)
{
p=OSQPend(q_msg,0,&err);//请求消息队列
LCD_ShowString(5,170,240,16,16,p);//显示消息
myfree(SRAMIN,p); delay_ms(500);
}
}
//主任务
void main_task(void *pdata)
{
u32 key=0; u8 err;
u8 tmr2sta=1; //软件定时器2开关状态
u8 tmr3sta=0; //软件定时器3开关状态
u8 flagsclrt=0; //信号量集显示清零倒计时
tmr1=OSTmrCreate(10,10,OS_TMR_OPT_PERIODIC,
(OS_TMR_CALLBACK)tmr1_callback,0,"tmr1",&err); //100ms执行一次
tmr2=OSTmrCreate(10,20,OS_TMR_OPT_PERIODIC,
(OS_TMR_CALLBACK)tmr2_callback,0,"tmr2",&err); //200ms执行一次
tmr3=OSTmrCreate(10,10,OS_TMR_OPT_PERIODIC,
(OS_TMR_CALLBACK)tmr3_callback,0,"tmr3",&err); //100ms执行一次
OSTmrStart(tmr1,&err); //启动软件定时器1
OSTmrStart(tmr2,&err); //启动软件定时器2
while(1)
{
key=(u32)OSMboxPend(msg_key,10,&err);
if(key)
{
flagsclrt=51;//500ms后清除
OSFlagPost(flags_key,1<<(key-1),OS_FLAG_SET,&err);//设置信号量为1
}
if(flagsclrt)//倒计时
{
flagsclrt--;
if(flagsclrt==1)LCD_Fill(140,162,239,162+16,WHITE);//清除显示
}
switch(key)
{
case 1: LED1=!LED1; break;//控制DS1
case 2://控制软件定时器3
tmr3sta=!tmr3sta;
if(tmr3sta)OSTmrStart(tmr3,&err);
else OSTmrStop(tmr3,OS_TMR_OPT_NONE,0,&err);//关闭软件定时器3
break;
case 3: LCD_Fill(0,221,119,lcddev.height,WHITE); break;//清除
case 4://校准
OSTaskSuspend(TOUCH_TASK_PRIO); //挂起触摸屏任务
OSTaskSuspend(QMSGSHOW_TASK_PRIO); //挂起队列信息显示任务
OSTmrStop(tmr1,OS_TMR_OPT_NONE,0,&err); //关闭软件定时器1
if(tmr2sta)OSTmrStop(tmr2,OS_TMR_OPT_NONE,0,&err);//关闭定时器2 TP_Adjust();
OSTmrStart(tmr1,&err); //重新开启软件定时器1
if(tmr2sta)OSTmrStart(tmr2,&err); //重新开启软件定时器2
OSTaskResume(TOUCH_TASK_PRIO); //解挂
OSTaskResume(QMSGSHOW_TASK_PRIO);//解挂
ucos_load_main_ui(); //重新加载主界面
break;
case 5://软件定时器2 开关
tmr2sta=!tmr2sta;
if(tmr2sta)OSTmrStart(tmr2,&err); //开启软件定时器2
else
{
OSTmrStop(tmr2,OS_TMR_OPT_NONE,0,&err);//关闭软件定时器2
LCD_ShowString(148,262,240,16,16,"TMR2 STOP");
}
break;
}
delay_ms(10);
}
}
//信号量集处理任务
void flags_task(void *pdata)
{
u16 flags; u8 err;
while(1)
{
flags=OSFlagPend(flags_key,0X001F,OS_FLAG_WAIT_SET_ANY,0,&err);
//等待信号量
if(flags&0X0001)LCD_ShowString(140,162,240,16,16,"KEY0 DOWN ");
if(flags&0X0002)LCD_ShowString(140,162,240,16,16,"KEY1 DOWN ");
if(flags&0X0004)LCD_ShowString(140,162,240,16,16,"KEY2 DOWN ");
if(flags&0X0008)LCD_ShowString(140,162,240,16,16,"KEY_UP DOWN");
if(flags&0X0010)LCD_ShowString(140,162,240,16,16,"TPAD DOWN ");
BEEP=1; delay_ms(50); BEEP=0;
OSFlagPost(flags_key,0X001F,OS_FLAG_CLR,&err);//全部信号量清零
}
}
//按键扫描任务
void key_task(void *pdata)
{
u8 key;
while(1)
{
delay_ms(10); key=KEY_Scan(0);
if(key==0) if(TPAD_Scan(0))key=5;
if(key)OSMboxPost(msg_key,(void*)key);//发送消息
}
}
本章test.c的代码有点多,因为我们创建了7个任务,3个软件定时器及其回调函数,所以,整个代码有点多,我们创建的7个任务为:start_task、led_task、touch_task、qmsgshow_task 、flags_task 、main_task和key_task,优先级分别是10和7~2,堆栈大小除了main_task是128,其他都是64。
我们还创建了3个软件定时器tmr1、tmr2和tmr3,tmr1用于显示CPU使用率和内存使用率,每100ms执行一次;tmr2用于在LCD的右下角区域不停的显示各种颜 {MOD},每200ms执行一次;tmr3用于定时向队列发送消息,每100ms发送一次。
本章,我们依旧使用消息邮箱msg_key在按键任务和主任务之间传递键值数据,我们创建信号量集flags_key,在主任务里面将按键键值通过信号量集传递给信号量集处理任务flags_task,实现按键信息的显示以及发出按键提示音。
本章,我们还创建了一个大小为256的消息队列q_msg,通过软件定时器tmr3的回调函数向消息队列发送消息,然后在消息队列显示任务qmsgshow_task里面请求消息队列,并在LCD上面显示得到的消息。消息队列还用到了动态内存管理。
在主任务main_task里面,我们实现了60.2节介绍的功能:KEY0控制LED1亮灭;KEY1控制软件定时器tmr3的开关,间接控制队列信息的发送;KEY2清除触摸屏输入;WK_UP用于触摸屏校准,在校准的时候,要先挂起触摸屏任务、队列消息显示任务,并停止软件定时器tmr1和tmr2,否则可能对校准时的LCD显示造成干扰;TPAD按键用于控制软件定时器tmr2的开关,间接控制屏幕显示。
软件设计部分就为大家介绍到这里。
60.4 下载验证
在代码编译成功之后,我们通过下载代码到战舰STM32开发板上,可以看到LCD显示界面如图60.4.1所示:
图60.4.1 初始界面
从图中可以看出,默认状态下,CPU使用率为21%左右。比上一章多出很多,这主要是key_task里面增加了触摸按键TPAD的检测,而TPAD检测是一个比较耗资源(主要是延时不是2ms的倍数)的过程,另外不停的刷屏(tmr2)也需要一定资源。
通过按KEY0,可以控制DS1的亮灭;
通过按KEY1则可以启动tmr3控制消息队列发送,可以在LCD上面看到Q和MEM的值慢慢变大(说明队列消息在增多,占用内存也随着消息增多而增大),在QUEUE MSG区,开始显示队列消息,再按一次KEY1停止tmr3,此时可以看到Q和MEM逐渐减小。当Q值变为0的时候,QUEUE MSG也停止显示(队列为空)。
通过KEY2按键,清除TOUCH区域的输入。
通过WK_UP按键,可以进行触摸屏校准。
通过TPAD按键,可以启动/停止tmr2,从而控制屏幕的刷新。
在TOUCH区域,可以输入手写内容。
任何按键按下,蜂鸣器都会发出“滴”的一声,提示按键被按下,同时在FLAGS区域显示按键信息。
{
key=(u32)OSMboxPend(msg_key,10,&err);
if(key)
{
flagsclrt=51;//500ms后清除
OSFlagPost(flags_key,1<<(key-1),OS_FLAG_SET,&err);//设置信号量为1
}
if(flagsclrt)//倒计时
{
flagsclrt--;
if(flagsclrt==1)LCD_Fill(140,162,239,162+16,WHITE);//清除显示
}
switch(key)
{
请教一下,这里如果没有按键按下,key=(u32)OSMboxPend(msg_key,10,&err);会超时,任务进入就绪状态,这时候是不是任务就不会往下执行了?下一次的时候到达它的优先级又变成运行状态再次去查询邮箱?相当于只有key=(u32)OSMboxPend(msg_key,10,&err)OK才会运行后面代码?
---------------------------------
是的,继续往下面运行。
---------------------------------
原子哥,不用软定时器,直接使用芯片的滴答定时器做延时,可以实现软定时器的功能吗
一周热门 更多>