1、在采用消息邮箱进行任务之间数据通信时,发送消息的任务一般是将消息指针(即消息的存放地址)发送到消息邮箱中。
2、通过消息邮箱进行任务之间数据通信时,一般发送消息任务(生产者)的执行频率较慢,接收消息任务(消费者)的执行频率较快,否则可能引起消息丢失。
3、如果平均生产速度小于平均消费速度,但可能某个时间段生产速度大于消费速度,这时怎么办?引入消息队列。消息队列起到仓库的作用,用于缓存临时生产过剩的消息。 4、如何在任务之间传递结构体消息(上课示例、实验四、实验六:发送汉字区位码)
OSMboxPost(mbox,&qw);
qw = (_qwh *)OSMboxPend(mbox,0,&err);
5、理解上课示例和实验中所有与任务之间通信有关的程序代码。 三、任务管理和任务调度的实现
1、什么是任务调度?分析任务调度的时机(在什么情况下会发生任务调度)
所谓任务调度,就是通过一个算法在多个任务中确定该运行的任务(一般是所有就绪任务中优先级最高的任务),然后进行任务切换。
任务调度时机:新任务被创建、有任务被删除、处于等待状态的任务被唤醒;
由于异步事件发生,在中断服务程序中激活一个或几个任务、正在运行的任务需要等待某个事件的发生而进入等待状态、正在运行的任务调用延时函数或挂起函数而自愿进入等待状态。
2、μC/OS-II初始化时,会创建若干个空闲任务控制块,这些空闲任务控制块通过一个指针链接成单链表。认真理解该单链表的结构。
3、 在μC/OS-II中,已创建任务的任务控制块通过两个指针链接成一个双向链表。认真理解该双向链表的结构。
4、如果要将优先级为29的任务置为就绪状态,请问如何设置任务就绪表OSRdyTbl[]和OSRdyGrp?请写出相关的代码
OSRdyGrp |= OSMapTbl[29>>3];
OSRdyTbl[29>>3] |= OSMapTbl[29&0x07];
5、μC/OS-II将已创建任务的任务控制块指针保存在数组OSTCBPrioTbl[]中,则判断优先级为prio的任务是否已经创建的条件是什么?
OSTCBPrioTbl[prio] != (OS_TCB *)0
6、查找表OSMapTbl[]的值如下所示,请给出将优先级别为prio的任务设置为就绪状态或非
就绪状态的示意代码。
设置为就绪状态:
OSRdyGrp |= OSMapTbl[prio>>3];
OSRdyTbl[prio>>3] |= OSMapTbl[prio&0x07];
设置为非就绪状态:
if((OSRdyTbl[prio>>3] &= ~OSMapTbl[prio&0x07]) == 0) {
OSRdyGrp &= ~OSMapTbl[prio>>3]; }
7、查找表OSUnMapTbl[]下标为n的元素的值代表二进制数n第一个为1的位的位置(从低位看起),请给出利用OSUnMapTbl[]从任务就绪表中计算优先级别最高的就绪任务的示意代码。
y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
四、信号量和消息邮箱的实现
1、认真理解事件控制块的结构。在μC/OS-II中,信号量、互斥型信号量、消息邮箱等采用相同的数据结构——事件控制块来描述。
typedef struct {
INT8U OSEventType; //事件的类型 INT16U OSEventCnt; void *OSEventPtr; INT8U OSEventGrp;
//信号量计数器 //消息或消息队列的指针 //等待事件的任务组
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; //任务等待表
} OS_EVENT;
2、在一个中断服务程序ISR中可以调用发送信号量函数OSSemPost(),但不能调用请求信号量函数OSSemPend()。
能执行OSMboxPost()、但不能执行OSMboxPend()
3、通过信号量的事件控制块可以信号量是否有效(判断条件是pevent->OSEventCnt > 0),判定是否有任务在等待该信号量(判定条件是pevent->OSEventGrp != 0),还可以知道有哪些任务在等待该信号量。
4、通过消息邮箱的事件控制块可以知道消息邮箱中是否有消息(pevent->OSEventPtr!= (void *)0),是否有任务在等待该消息邮箱的消息(pevent->OSEventGrp != 0),还可以知道有哪些任务在等待该消息邮箱的消息。
? 如果调用时消息邮箱中有消息(.OSEventPtr不为NULL),则将该消息指针返回给
调用者,并从消息邮箱中清除该消息。同时*err的返回值为OS_NO_ERR;如果调用时消息邮箱中没有消息(.OSEventPtr是NULL),则使任务进入等待状态,并引发一次任务调度。
? 如果在指定的时钟节拍内没有收到消息,则函数返回空指针,同时*err的值为
OS_TIMEOUT。
? 如果有多个任务等待同一消息,则将优先级最该的任务将获得该消息。
5、理解OSSemPend()、OSSemPost()、OSMboxPend()、OSMboxPost()、OSMutexPend()、
OSMutexPost()等函数的实现思想和关键代码。
6、如果一个任务调用OSSemPost(Sem)系统服务函数,则信号量Sem的计数器OSEventCnt应如何变化?注意区分是否有其他任务在等待该信号量这两种情况(结合P/V操作理解)
OSSemPost ( )函数在对信号量的计数器操作之前,首先要检查是否还有等待该信号量的任务。如果没有,就把信号量计数器OSEventCnt加1;如果有,则调用调度器OS_Sched( )去运行等待任务中优先级别最高的任务。
7、如果一个任务调用OSSemPend(Sem,0, &err),则信号量Sem的计数器值OSEventCnt应如何变化?
如果信号量有效,则对信号量计数器OSEventCnt减1,否则任务进入等待状态,信号量计数器OSEventCnt不变。
8、当信号量用于实现两个任务单向同步时,它代表某个事件是否发生,这时创建该信号量
时应当将信号量计数器OSEventCnt初始值应设置为什么值?
Sem = OSSemCreate(0);
9、如果一个信号量的事件控制块指针为pevent,则判断信号量是否有效(即信号量计数器值是否大于0)的条件是什么?
pevent->OSEventCnt > 0
10、如果一个信号量的事件控制块指针为pevent,则判断是否有任务在等待这个信号量的判定条件是什么?
pevent->OSEventGrp != 0
11、如果一个消息邮箱的事件控制块指针为pevent,则判断消息邮箱中是否有消息的条件是什么?
pevent->OSEventPtr!= (void *)0
12、查找表OSUnMapTbl[]下标为n的元素的值代表二进制数n第一个为1的位的位置(从低位看起),请给出利用OSUnMapTbl[]从pevent指针指向的事件控制块的任务等待表中计算优先级别最高的等待任务的示意代码。
y = OSUnMapTbl[OSRdyGrp];
OSPrioHighRdy = (INT8U)((y << 3) + OSUnMapTbl[OSRdyTbl[y]]);
四、uC/OS 的初始化和启动
1、理解初始化函数OSInit( )的主要作用及其实现方法
OSInit( )将对μC/OS-II的所有全局变量和数据结构进行初始化,同时创建空闲任务OSTaskIdle,并赋之以最低优先级和永远的就绪状态。
2、理解启动函数OSStart( )的主要作用及其相关代码 把控制权交给操作系统,开始任务调度。 五、中断处理和时间管理
1、理解uc/OS中与时间处理有关的基础:时钟中断、时钟节拍、时钟中断处理程序OSTickISR( )以及时钟节拍处理程序OSTimeTick( )的关键代码。
2、理解OSTimeDly()和OSTimeDlyResume实现的主要思想和关键代码。 六、ucGUI
1、文本显示
2、图形绘制(含汉字和图像显示) 3、控件和控件处理。
4、相关示例代码的理解(包括涉及到任务以及任务之间的通信) 七、上课示例和实验示例
1、任务的挂起和恢复(上课示例、实验一)
实验一:定义两个任务:一个是LED显示控制任务,一个是按键检测任务,要求通过任务的挂起和回复实现每按键一次,8个LED以二进制的形式显示按键次数。写出两个任务的任务函数代码
void TaskLed(void *pdata) { pdata = pdata; IO1DIR = LEDCON; IO1SET = LEDCON; while(1) {
IO1SET = LEDCON; IO1CLR = (led<<16);
OSTaskResume(4);//恢复按键的任务 } }
void TaskKey(void *pdata) { pdata = pdata; while(1) {
if((IO0PIN&KEYCON)==0) }
{
while((IO0PIN&KEYCON) == 0); led++;
OSTaskSuspend(OS_PRIO_SELF); }}
2、任务的延时和取消延时
void MyTask(void *pdata) {
while(1) {
printf(\