uc/os -Ⅱ操作系统实验
- 1.基础实验
- 2. 系统设计
- 3.系统实现
- 4.调试分析
1.基础实验
1.1 跑马灯 两个任务,即按键和灯,按键控制跑马灯任务开始运行并停止悬挂,跑马灯任务重4个LED灯轮亮起熄灭。 1.夜间自动照明系统 采集光敏传感器信号,将光照度大小显示在 LCD 在显示屏上,判断光线是否为 是否小于预设阈值,如果小于,则亮度较高 LED 灯亮且维持 5 秒,并在 LCD 如果大于设定阈值,则在显示屏上提示光线不足,打开照明 LED 灯,在LCD 显示屏上提示光线充足,照明关闭。 1、2 调整阈值光强。
2. 系统设计
2.1 模块图 系统初始化任务有三个实验任务,LED显示任务以及键盘扫描任务。 实验二有四个任务,分别为:光敏传感器监听任务,键盘扫描任务,系统初始化任务,LED显示任务。 2.2 流程图 内容是实现的LED每个灯的跑马灯DX_off()函数后面的延迟可以取消。 该内容是实验1的键盘扫描函数,键盘输入1可以挂起LED键盘输入2可以恢复任务LED任务。 光敏传感器监听任务与LED通过显示任务GtoLbox通过邮箱通信、键盘扫描和光敏传感器监控msg_key邮箱通信。 这项任务是基于接收光敏任务的信息LED进行控制,LED灯亮后,会持续五秒钟。 该任务的功能是通过判断键盘输入值来改变预设的光敏任务阈值。 根据键盘扫描任务发送的信息,改变预定阈值,始终读取传感器值,判断是否正确LED发送显示任务LED亮点任务,是否在LCD提醒文本显示在屏幕上。 2.3 开发环境 windows10
3.系统实现
3.1实验一 LED显示任务 算法描述: 1.D5_on(),睡眠0.25秒 2.D5_off(),睡眠0.25秒 3.D6_on(),睡眠0.25秒 4.D6_off(),睡眠0.25秒 5.D7_on(),睡眠0.25秒 6.D7_off(),睡眠0.25秒 7.D8_on(),睡眠0.25秒 8.D8_off(),睡眠0.25秒 9.回到步骤1 代码:
void TaskMy(void *p_arg) {
(void)p_arg; while (1) {
// OS_ENTER_CRITICAL(); ///进入临界段(关中断) // USART1Write("hello\n", sizeof("hello\n")); // OS_EXIT_CRITICAL(); ///退出临界段(开中断) D5_on(); OSTimeDlyHMSM(0, 0, 0, 250); D5_off(); OSTimeDlyHMSM(0, 0, 0, 250); D6_on(); OSTimeDlyHMSM(0, 0, 0, 250); D6_off(); OSTimeDlyHMSM(0, 0, 0, 250);
D7_on();
OSTimeDlyHMSM(0, 0, 0, 250);
D7_off();
OSTimeDlyHMSM(0, 0, 0, 250);
D8_on();
OSTimeDlyHMSM(0, 0, 0, 250);
D8_off();
OSTimeDlyHMSM(0, 0, 0, 250);
}
}
3.2实验一 键盘扫描任务 算法描述: 1.使用key=key_board_scan();获取键盘输入值 2.判断key的值 2.1如果key等于1,挂起LED显示任务 2.2如果key等于2,复苏LED显示任务 3.回到步骤1 代码:
void TaskYou(void *p_arg)
{
(void)p_arg;
u8 key;
INT8U err;
while (1)
{
key=key_board_scan();
if(key == 8){
err = OSTaskSuspend(1);
}
if(key == 12)
{
err = OSTaskResume(1);
}}
}
3.3实验二 LED显示任务系统实现 初始设置: //LED任务 //设置任务优先级 #define LED_TASK_PRIO 8 //设置任务堆栈大小 #define LED_STK_SIZE 512 //创建任务堆栈空间 OS_STK LED_TASK_STK[LED_STK_SIZE]; //任务函数接口 void led_task(void pdata); 算法描述: 1.使用OSMboxPend函数接收GtoLbox邮箱的值,并赋值给指针Led 2.判断Led指针指向的内容 2.1如果Led 为1,调用D5_on(),持续五秒 3.睡眠1一秒 4.回到步骤1 代码:
void led_task(void *pdata)
{
(void)pdata;
INT8U *Led;
INT8U err;
while(1)
{
Led = (INT8U *)OSMboxPend( ,0,&err);
printf("Led %d",*Led);
if(*Led == 1){
D5_on();
OSTimeDlyHMSM(0, 0, 5, 0);
D5_off();
}
OSTimeDlyHMSM(0, 0, 1, 0);
}
}
3.4 实验二 光敏传感器监听系统任务实现 初始设置: //光照任务 //设置任务优先级 #define Gmin_TASK_PRIO 9 //设置任务堆栈大小 #define Gmin_STK_SIZE 512 //创建任务堆栈空间 OS_STK Gmin_TASK_STK[BEEP_STK_SIZE]; //任务函数接口 void Gmin_task(void *pdata); OS_EVENT GtoLbox; 算法描述: 1.使用OSMboxAccept接收邮箱msg_key的值并赋值给指针Limit 2.使用read_ADC()函数读取光敏传感器的值,fPhotoRes/ 4096.0 * 3.3并赋值给fPhotoRes 3.判断 Limit的值 3.1如果Limit的值是1,阈值减小0.1 3.2如果Limit的值是2,阈值增加0.1 4.如果fPhotoRes的值大于阈值 4.1LCD屏幕显示“光照不足,开启照明”,使用OSMboxPost(GtoLbox,(INT8U *)&Gmin)向LED任务,传递消息。 4.2LCD屏幕显示“光照充足,关闭照明”,使用OSMboxPost(GtoLbox,(INT8U *)&Gmin)向LED任务,传递消息。 5.睡眠1秒。 6.回到步骤1 代码:
void gmin_task(void *pdata)
{
(void)pdata;
float fPhotoRes;
INT8U err;
INT8U Gmin;
INT8U *Limit;
float doit = 2;
while(1)
{
Limit = (INT8U *)OSMboxAccept(msg_key);
fPhotoRes = read_ADC();
fPhotoRes = fPhotoRes/ 4096.0 * 3.3;
if(*Limit == 1)
{
doit += 0.1;
//printf("%.lf xianzhi %.2f \n\r", fPhotoRes, doit);
}
if(*Limit == 2)
{
doit -= 0.1;
}
if(fPhotoRes >= doit)
{
lcd_var_write(TEXT_TITLE, msg1, strlen(msg1));
Gmin = 1;
OSMboxPost(GtoLbox,(INT8U *)&Gmin);
}
else
{
lcd_var_write(TEXT_TITLE, msg2, strlen(msg2));
Gmin = 0;
OSMboxPost(GtoLbox,(INT8U *)&Gmin);
}
printf("doit = %.2f fPhotoRes = %.2f",doit,fPhotoRes);
OSTimeDlyHMSM(0, 0, 1, 0);
}
}
3.5实验二 键盘扫描系统任务实现 初始设置: //按键扫描任务 //设置任务优先级 #define KEY_TASK_PRIO 10 //设置任务堆栈大小 #define KEY_STK_SIZE 512 //创建任务堆栈空间 OS_STK KEY_TASK_STK[KEY_STK_SIZE]; //任务函数接口 void key_task(void *pdata); OS_EVENT *msg_key; //按键邮箱事件块指针 算法描述: 1.调用key_board_scan()获取键盘输入值 2.判断输入值 2.1如果输入值是1就向光敏传感器监听任务发送消息 1 2.2如果输入值是2就向光敏传感器监听任务发送消息2 3.回到步骤1 代码:
void key_task(void *pdata)
{
(void)pdata;
u8 key;
INT8U Keys;
while(1)
{
key=key_board_scan();
if(key == 8)
{
Keys = 1;
OSMboxPost(msg_key,(INT8U *)&Keys);
}
if(key == 12)
{
Keys = 2;
OSMboxPost(msg_key,(INT8U *)&Keys);
}
}
}
3.6 实验二 开始任务 初始设置: //START 任务 //设置任务优先级 #define START_TASK_PRIO 18 //开始任务的优先级设置为最低 //设置任务堆栈大小 #define START_STK_SIZE 512 //创建任务堆栈空间 OS_STK START_TASK_STK[START_STK_SIZE]; //任务函数接口 void start_task(void pdata); 算法描述: 1.创建两个邮箱GtoLbox ,msg_key 使用函数OSMboxCreate((void)0); 2.创建三个任务,分别为led_task,key_task,gmin_task。 代码:
OSStatInit(); //初始化统计任务.这里会延时1秒钟左右
OS_ENTER_CRITICAL(); //进入临界区(无法被中断打断)
GtoLbox = OSMboxCreate((void*)0); // 创建邮箱
msg_key = OSMboxCreate((void*)0);
OSTaskCreate(led_task,(void*)0,(OS_STK*)&LED_TASK_STK[LED_STK_SIZE-1],LED_TASK_PRIO);
OSTaskCreate(key_task,(void*)0,(OS_STK*)&KEY_TASK_STK[KEY_STK_SIZE-1],KEY_TASK_PRIO);
OSTaskCreate(gmin_task,(void*)0,(OS_STK*)&Gmin_TASK_STK[Gmin_STK_SIZE-1],Gmin_TASK_PRIO);
OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断)
4.调试分析
4.1原理分析 实验一: 在实验一中,LED显示任务的优先级高于键盘扫描任务,键盘扫描任务在LED显示任务睡眠后,运行。 实验二: 整个项目从main函数开始运行,然后在main函数中创建了开始任务,以及所用设备的初始化,开始任务创建后开始执行开始任务,开始任务的内容是创建了两个邮箱,以及三个新任务,三个新任务的优先级都是高于开始任务的,此时任务队列中有四个函数,优先级关系为:LED显示任务>光敏传感器扫描任务>键盘扫描任务>开始任务。 因为LED显示任务执行了OSMboxPend()函数,但此时没有任务向其传递消息,所以LED任务被挂起,然后执行了光敏传感器扫描任务,执行完成后睡眠一秒,并向LED任务传递了消息,然后执行了LED任务,然后LED任务睡眠,然后在上述两个任务苏醒之前,执行键盘扫描任务。 4.2分析 实验一: 实验一调试过程十分流畅,任务挂起函数为OSTaskSuspend(),任务复苏函数为OSTaskResume(). 实验二: 光敏传感器的使用样例在《STM32+ucosii试验箱光盘内容》中,该样例能正常运行,直接使用可移植模板会报错,需要将样例中的abc.c文件覆盖模板中的该文件,这样就可以正常运行,但是出现了任务一直处于睡眠的情况,原因是堆栈空间过小,增加空间后就可规避该问题。再后来就是OSMboxPend()函数和OSMboxAccept()函数的使用区别,OSMboxPend()函数如果没有收到消息会让任务挂起,但是OSMboxAccept()函数不会,实验要求是可以通过键盘来改变设定的阈值大小,如果光敏传感器监听任务使用OSMboxPend()函数来接收键盘扫描任务的消息,会变成只有键盘扫描任务向光敏任务发送消息,光敏任务才能执行。通过实践,这种方式带来的用户体验很差,使用OSMboxAccept()函数就可规避这个问题,并且光敏任务优先级高于键盘任务,并且执行完成后睡眠1秒,光敏任务的实际执行时间很短,光敏任务睡眠和LED任务睡眠的时间占了很大一部分比例,这也就说明键盘扫描函数的执行时间远远高于其余任务,这样可以让用户感觉不到输入时延,提高用户体验。最终持续在这样的逻辑下能够正常运行。