|
本例用了BC4.5软件,在DOS环境模拟uc/os-ii ,这是本人发表在论坛上的一篇笔记;放到这里以便常温故。
最近本人在学习uc/os-ii操作系统,收获真的很大,uc/os-ii系统中我觉得任务间的同步与通信是有点难;本人将学习笔记整理出来放在这里,希望有高人能指出错误的地方,欢迎指教,谢谢!
/*建立两个用户任务:MyTask和YouTask。这两个任务都要访问一个共享资源S,但是YouTask访问需要的时间要长一些,而MYTASK访问的时间要短点,这样就不可避免的出现了在任务YOUTASK访问S期间,任务MYTASK也来访问S,从而出现干扰*/#include "INCLUDES.h"
#define TASK_STK_SIZE 512 /* 任务堆栈长度*/
char ss;
OS_STK MyTaskStk[TASK_STK_SIZE];
OS_STK YouTaskStk[TASK_STK_SIZE];
INT8U y1=0,y2=0; //字符显示位置
char *s="原始数据";
void MyTask(void *data); /* 声明任务 */
void YouTask(void *data);
/*
****************************************************************************
* MAIN主函数
***************************************************************************
*/
void main (void)
{
OSInit(); /* 初始化uC/OS-II */
PC_DOSSaveReturn(); /* 保存DOS环境 */
PC_VectSet(uCOS, OSCtxSw); /* 安装uC/OS-II的中断 */
OSTaskCreate(MyTask,(void *)0, &MyTaskStk[TASK_STK_SIZE - 1], 0); /*创建起始函数*/
OSStart(); /* 启动多任务管理 */
}
/*
**************************************************************************
* STARTUP TASK
************************************************************************
*/
void MyTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
INT16S key; /*用于退出的建*/
pdata = pdata; /* Prevent compiler warning */
OS_ENTER_CRITICAL();
PC_VectSet(0x08, OSTickISR); /* 安装时钟中断向量 */
PC_SetTickRate(OS_TICKS_PER_SEC); /* 设置时钟频率 */
OS_EXIT_CRITICAL();
OSStatInit(); /* 初始化统计任务 */
OSTaskCreate(YouTask,(void *)0, &YouTaskStk[TASK_STK_SIZE - 1], 2); /*创建任务函数*/
for (;;)
{
s = "MyTask get source S";
PC_DispStr(2,++y1,s,DISP_BGND_BLACK+DISP_FGND_WHITE);/*任务*/
//如果恩下ESC键,则退出UC/OS-II
if (PC_GetKey(&key) == TRUE)
{
if (key == 0x1B)
{
PC_DOSReturn(); /* Return to DOS */
}
}
OSTimeDly(500); /* 等待500个时钟节拍 */
}
}
void YouTask(void *pdata)
{
#if OS_CRITICAL_METHOD == 3 /*Allocate storage for CPU status register */
OS_CPU_SR cpu_sr;
#endif
INT8U err;
pdata=pdata;
for (;;)
{
s = "YouTask get source S";
PC_DispStr(28,++y2,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
OSTimeSet(0); /*置OSTime为0,注意此句的作用*/
while(OSTime<1000) /*条件语句“OSTime<1000”非常重要!*/
{
//sprintf(ss,"%d",OSTimeGet());
PC_DispStr(55,y2,s,DISP_BGND_BLACK+DISP_FGND_WHITE);/*本实验的精髓语句*/
}
OSTimeDly(100); //等待100个时钟节拍
}
}
/*在YOUTASK访问资源S期间高优先级的任务MYTASK也访问了S,从而干扰了任务YOUTASK对共享资源S的访问,运行后显示表明在任务YOUTASK的延时期间前,共享资源S的内容发生了变化。笔记:
YouTask任务分析:在YouTask任务中程序代码虽然较少但是程序流程相当复杂!必须搞懂每句的含义,提高程序分析能力!分析程序一定要注意流程!下面将YouTask任务中重要部分语句(红色注释部分)分析如下:
1,在MyTask任务挂起同时执行“PC_DispStr(28,++y2,s,DISP_BGND_BLACK+DISP_FGND_WHITE);”语句,所以在显示屏相应的位置几乎同时显示"MyTask get source S"和"YouTask get source S";
2,操作系统的每个任务都在for死循环里完成;“OSTimeSet(0);”语句的意思是,每进入一次for循环里就给系统时间全局变量OSTime重新赋值,在这里就是将OSTime清零;为下一语句“while(OSTime<1000)”做铺垫;
3,本任务中有两个循环体,另一个就是“while(OSTime<1000)”,因为前面有“OSTimeSet(0);”语句,所以系统每次进入YOUTASK任务的for循环里都会执行“while(OSTime<1000)”语句,进入“while(OSTime<1000)”语句之后,全局变量OSTime会以设定的时钟节拍不断自加1,当全局变量OSTime等于1000时,系统就会退出“while(OSTime<1000)”语句,执行“ OSTimeDly(100);”语句,也就是说在OSTime的值在0到1000的时间段里程序会一直执行“PC_DispStr(55,y2,s,DISP_BGND_BLACK+DISP_FGND_WHITE);”语句,即显示相应的内容;
4,因为在YouTask任务中有两句即“PC_DispStr(28,y2,s,DISP_BGND_BLACK+DISP_FGND_WHITE);”语句和
“PC_DispStr(55,y2,s,DISP_BGND_BLACK+DISP_FGND_WHITE);”语句,这样就会在同一个任务中出现争抢s资源的现象(即在内存同一位置几乎同时被赋不同的值)而造成程序出错干扰,这是不允许的!。所以在实验现象中在“55,y2”坐标处先显示“YouTask get source S”再变成显示"MyTask get source SS"的现象。
5,注意:a,在死循环for里才是要创建任务的内容,换句话说任务需要执行的内容只能写在死循环for里;b,本实验中,两个任务都应用了“OSTimeDly(ticks)”函数,当两个任务同时挂起时系统运行哪个任务呢?操作系统不会让cpu闲着,这时会选择优先级最高的任务运行!
6,系统进入YouTask任务时,执行“PC_DispStr(28,++y2,s,DISP_BGND_BLACK+DISP_FGND_WHITE);”语句,在显示屏相应的位置显示"MyTask get source S",接着进入while循环执行
“PC_DispStr(55,y2,s,DISP_BGND_BLACK+DISP_FGND_WHITE);”语句即显示"YouTask get source S",程序很快就会退出while循环执行下面的“ OSTimeDly(100);”语句即挂起YouTask任务,就在挂起YouTask任务的同时系统选择运行MyTask任务,s同时被赋值为"MyTask get source S",所以在实验现象中就出现在“55,y2”坐标处先显示“YouTask get source S”再马上变成显示"MyTask get source SS"的现象(为什么是两个“SS”?)。
7,本实验中MyTask任务占用CPU的时长由程序代码的精度决定。可以通过实验验证。
8,在时序上,s先在MyTask任务中被赋值,再执行YouTask任务s再次被赋值,接着还是在YouTask任务的while中s 再次被赋值;在这个过程中两个任务没有对s资源发生争抢,而在YouTask任务的“ OSTimeDly(100);”语句中两个任务对s资源发生了争抢,导致出现“55,y2”处出现干扰。
|
|