S.D.Lu的uCOSII入门学习笔记消息队列
uCOS-II一些入门资料(内核架构解析等)

嵌入式系统——基础知识操作系统OS控制和管理计算机软硬件资源,合理组织计算机工作流程,方便用户使用计算机的系统软件。
可将OS看成是应用程序与硬件间的接口或虚拟机。
OS功能:进程管理、存储管理、文件管理、设备管理、网络和通信管理等。
嵌入式操作系统EOS运行在嵌入式硬件平台上,对整个系统及其所操作的部件装置等资源进行统一协调、指挥和控制的系统软件。
EOS特点:微型化、可裁剪性、实时性、高可靠性、易移植性重点关注:高实时性、硬件相关依赖性、软件固化、应用专用性、网络功能。
实时操作系统TROS能使计算机及时响应外部事件请求,并能及时控制所有实时设备与实时任务协调运行,且能在规定时间内完成事件处理的OS。
RTOS基本要求:1、逻辑功能正确:RTOS的计算必须产生正确的结果;2、时间正确:RTOS的计算必须在预定的周期内完成。
RTOS应满足条件:1、多任务系统;2、任务的切换时间应与系统中的任务书无关;3、中断延时的时间可预知并尽可能短。
无论在什么情况下,OS完成任务所需的时间应该是在程序设计时就可预知的。
嵌入式实时操作系统ERTOS用于嵌入式系统,对系统资源和多个任务进行管理,且具有高可靠性、良好可裁剪性等优良性能的,为应用程序提供运行平台和实时服务的微型系统软件。
ERTOS最重要的三项服务:1、多任务管理2、内存管理3、外围资源管理嵌入式微处理器(特点)1、对实时多任务OS有很强的支持能力;2、具有功能很强的存储区域保护功能;3、处理器结构可扩展;4、低功耗;微处理器主要发展方向:小体积、高性能、低功耗微处理器分类:MCU、MPU、DSP、SOC嵌入式系统发展方向1、嵌入式开发是一项系统工程,嵌入式系统厂商不仅要提供嵌入式软硬件系统本身,还需要提供强大的硬件开发工具与软件支持包;2、网络化、信息化的要求随着因特网技术的成熟、宽带的提高而日益提高,使得以往单一功能的设备功能不再单一,结构更加复杂;3、网络互连成为必然趋势(IEEE1394、USB、CAN、Bluetooth等网络接口);4、精简系统内核、算法、降低功耗和软硬件成本;5、提供友好的多媒体人机界面。
ucosII实验报告-消息队列

【实验目的】1.了解ADS集成开发环境,完成ADS的安装;2. 嵌入式实时操作系统µC/OS-II中消息队列机制的基本原理和使用方法。
【实验原理】1. 操作系统配置如下:#define TASK_STACK_SIZE 10*1024#define TASK_PRIO 10#define TSK_NUM 5#define N_MSG 10#define TASK1 1#define TASK2 22.相关系统调用如下:OSTaskCreate():建立一个新任务OSQCreate():建立一个消息队列OSQPend():等待消息OSQPostFront() :向消息队列发送消息OSQPost():向消息队列发送消息OSQQuery() :取得消息队列的信息OSQFlush ():清空消息队列OSQDel() :删除消息队列OSTimeDly ():任务延时3. 设计消息结构。
定义如下结构体:typedef struct msg_type{ // 定义消息结构体INT8U num; // 数据INT8U who; // 标记发送方}MY_MSG;对于who 可取的值,定义如下宏:#define TASK1 1#define TASk2 24. 定义消息指针数组与事件控制块void *MsgGrp[N_MSG]; //定义消息指针数组OS_EVENT* Msg_Q;//定义事件控制块事件控制块的初始化:(在主函数中)Msg_Q = OSQCreate( &MsgGrp[0], N_MSG); // create msg queue【实验要求】通过消息队列在任务间传递数据:1.任务TA1以随机(或固定)时间间隔依次将数据1、2、3、...发送至消息队列q1,每次发送一个数据。
2.TA2以随机(或固定)时间间隔将随机数据发送至q1。
3.TA3从消息队列q1中每次接收一个数据:如果数据来自TA1,则计算出所有已接收的来自TA1的数据之和,然后延时;如果数据来自TA2,则将数据输出到屏幕,然后延时(模拟处理数据所需的时间);调整发送数据和处理数据的速度,观察发送速度大于处理速度的结果。
ucos-ii学习笔记——消息队列的原理及使用

ucos-ii学习笔记——消息队列的原理及使用Created on: 2012-10-7Author: zhang bin学习笔记for ucos-ii PCredesigned by zhang bin2012-10-7versions:V-0.1All Rights Reserved/*下面是一个应用消息队列进行通信的应用程序,运行该程序并观察其运行结果*/#include"includes.h"#define TASK_STK_SIZE 512 /* 定义任务堆栈长度*/#define N_MESSAGES 128 /* 定义消息队列长度,消息指针数组存储的最大长度,可以存放128个消息*/OS_STK StartTaskStk[TASK_STK_SIZE];OS_STK MyTaskStk[TASK_STK_SIZE];OS_STK Y ouTaskStk[TASK_STK_SIZE];char*s_flag; //该字符串指示哪个任务在运行//char *s_1;char*ss; //存放接收到的消息指针char*s100; //存放发送消息的指针char*s;char*s500;void*MsgGrp[N_MESSAGES]; //定义消息指针数组//创建消息队列,首先需要定义一个指针数组(用于存放消息邮箱),然后把各个消息数据缓冲区的首地址存入这个数组中//最后再调用函数OSQCreate()来创建消息队列INT8U err;INT8U y=0;OS_EVENT *Str_Q; //定义事件控制块指针队列的事件控制块指针用于存放创建的消息队列的指针void MyTask(void*data);void StartTask(void*data);void Y ouTask(void*data);/********************************************************************** ************************************* MAIN********************************************************************* *************************************/void main (void){OSInit(); /* Initialize uC/OS-II */PC_DOSSaveReturn(); /* 保存DOS环境*/PC_V ectSet(uCOS, OSCtxSw); /* 安装uC/OS-II中断*/Str_Q=OSQCreate(&MsgGrp[0],N_MESSAGES); //创建消息队列//函数的第一个参数&MsgGrp[0]是void **start,是存放消息缓冲区指针数组的地址,它是指向指针数组的指针//可以用指针数组的首个元素的地址表示//N_MESSAGES是该数组的大小//返回值是消息队列的指针Str_Q是OS_EVENT型的指针,是事件控制块型的指针OSTaskCreate(StartTask, (void*)0, &StartTaskStk[TASK_STK_SIZE - 1], 0);OSStart(); /* Start multitasking */}/********************************************************************** ************************************* STARTUP TASK********************************************************************* *************************************/void StartTask (void*pdata){#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */OS_CPU_SR cpu_sr;#endifINT16S key;pdata = pdata; /* Prevent compiler warning*/OS_ENTER_CRITICAL();PC_V ectSet(0x08, OSTickISR); /* 安装时钟向量中断*/PC_SetTickRate(OS_TICKS_PER_SEC); /* 设置时钟频率*/OS_EXIT_CRITICAL();OSStatInit(); /* Initialize uC/OS-II's statistics */OSTaskCreate(MyTask, (void*)0, &MyTaskStk[TASK_STK_SIZE - 1], 3);OSTaskCreate(Y ouTask, (void*)0, &Y ouTaskStk[TASK_STK_SIZE - 1], 4);// s="How many strings could be geted?";//OSQPostFront(Str_Q,s); //发送消息以LIFO后进先出的方式发送//第一个参数Str_Q是消息队列的指针,是OSQCreate的返回值,第二个参数s 是消息指针for (;;){s_flag="The StartTask is running!";PC_DispStr(50,++y, s_flag, DISP_FGND_RED + DISP_BGND_LIGHT_GRAY); //提示哪个任务在运行if(OSTimeGet()>100&&OSTimeGet()<500){s100="The value of OSTIME is from 100 to 500 NOW!!";OSQPostFront(Str_Q,s100); //发送消息以LIFO后进先出的方式发送//发送消息以LIFO后进先出的方式发送//第一个参数Str_Q是消息队列的指针,是OSQCreate的返回值,第二个参数s是消息指针s="The string belongs to which task.";OSQPostFront(Str_Q,s); //发送消息以LIFO方式发送所以如果要申请消息时,会先得到s,然后才是s100}if(OSTimeGet()>1000&&OSTimeGet()<1500){s500="The value of OSTIME is from 1000 to 1500 NOW!!";OSQPostFront(Str_Q,s500); //发送消息}if (PC_GetKey(&key) == TRUE) /* See if key has been pressed*/{if (key == 0x1B){/* Y es, see if it's the ESCAPE key */PC_DOSReturn(); /* Return to DOS */}}OSTimeDlyHMSM(0, 0, 1, 0); /* Wait one second*/ }}void MyTask(void*pdata){#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */OS_CPU_SR cpu_sr;#endifpdata=pdata;for (;;){s_flag="The MyTask is running!";PC_DispStr(50,++y, s_flag, DISP_FGND_RED + DISP_BGND_LIGHT_GRAY); //提示哪个任务在运行ss=OSQPend(Str_Q,0,&err); //请求消息队列,参数分别是:Str_Q为所请求消息队列的指针第二个参数为等待时间//0表示无限等待,&err为错误信息,返回值为队列控制块OS_Q成员OSQOut指向的消息(如果队列中有消息可用的话),如果//没有消息可用,在使调用OSQPend的任务挂起,使之处于等待状态,并引发一次任务调度//因为前面发送消息时使用的是LIFO的方式,所以此处第一次得到的消息是上面最后发送的消息PC_DispStr(3,y, ss, DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY); //显示得到的消息//s_1="M";PC_DispStr(0,y,"My",DISP_FGND_RED +DISP_BGND_LIGHT_GRAY); //显示是哪一个任务显示的OSTimeDlyHMSM(0, 0, 1, 0);}}void Y ouTask(void*pdata){#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */OS_CPU_SR cpu_sr;#endifpdata=pdata;for (;;){s_flag="The Y ouTask is running!";PC_DispStr(50,++y, s_flag, DISP_FGND_RED + DISP_BGND_LIGHT_GRAY); //提示哪个任务在运行ss=OSQPend(Str_Q,0,&err); //请求消息队列PC_DispStr(3,y, ss, DISP_FGND_BLACK + DISP_BGND_LIGHT_GRAY); //显示得到的消息//s_1="Y";PC_DispStr(0,y,"Y ou",DISP_FGND_RED + DISP_BGND_LIGHT_GRAY); //显示是哪一个任务显示的OSTimeDlyHMSM(0, 0, 1, 0);}}//运行的现象说明上面分析是正确的,因为当时钟节拍数大于100,小于500时,会发送第一个if语句中的两个字符串s100和s//下面运行的任务接收到并且显示。
uCOSII消息队列的使用方法

uCOSII消息队列的使用方法uCOS II 消息队列的使用方法2010-03-14 02:421、需在以下文件中配置如下内容OS_CFG.HOS_MAX_QS N 你需要的值根据需要自己配置#define OS_Q_EN 1 /* Enable (1) or Disable (0) code generation for QUEUES */#define OS_Q_ACCEPT_EN 1 /* Include code for OSQAccept() */#define OS_Q_DEL_EN 1 /* Include code for OSQDel() */#define OS_Q_FLUSH_EN 1 /* Include code for OSQFlush() */ #define OS_Q_POST_EN 1 /* Include code for OSQPost() */ #define OS_Q_POST_FRONT_EN 1 /* Include code for OSQPostFront() */#define OS_Q_POST_OPT_EN 1 /* Include code for OSQPostOpt() */#define OS_Q_QUERY_EN 1 /* Include code for OSQQuery() */2、建立一个指向消息数组的指针和数组的大小,该指针数组必须申明为void类型,如下:void *MyArrayOfMsg[SIZE];3、声明一个OS_EVENT类型的指针指向生成的队列,如下:OS_EVENT *QSem;4、调用OSQcreate()函数创建消息队列,如下:QSem = OSQcreate(&MyArrayOfMsg[0],SIZE);5、等待消息队列中的消息,OSQPend()。
void *OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err):必须保证消息队列已经被建立。
S.D.Lu的uCOSII入门学习笔记多任务

S.D.Lu的uC/OS II 入门学习笔记(2):多任务初学者的疑惑对于一个单片机学习者,如果从未接触过嵌入式操作系统,就会觉得它是非常复杂而神秘的。
从我个人的经历说起,之前写的所有程序都是在单片机上“裸奔”的。
开始学习OS之前,对OS存在几个疑惑:1.一个CPU如何同时执行多个任务?答:CPU不能同时执行多个任务,甚至不能同时执行两个任务。
每一个时刻,CPU 只能执行一个任务。
2.CPU如何运行多个任务呢?答:CPU是通过分时复用的方法运行多个任务的。
也就是把时间切分成一个一个的时间片段,一个时间片段运行一个任务,然后下一个时间片段运行另一个任务。
应注意的是,一个时间片段并不一定能完整的运行一个任务,一个任务可能需要若干个时间片段才能从头到尾将代码运行一遍。
3.这些任务是相互独立的吗?如果不是独立的,它们之间又有什么联系?答:这些任务可以是相互独立的,也可以是相互联系的。
举两个简单的例子。
(1):假设有两个任务,一个是用P1.0口控制LED闪烁,3次/秒;另一个是用P1.1口控制LED闪烁,2次/秒。
那么这两个任务就是相互独立的。
(2): 假设有两个任务,一个是测量外部输入的方波信号的频率;另一个是控制一个LCD显示模块,显示该方波信号的频率值。
那么这两个任务就是有联系的,它们有公共的资源,即(数据)频率值。
当然,这里的例子并不准确,因为这些任务太简单了,完全可以用一个任务来完成,根本不需要OS。
这里只是用于说明,两个任务之间存在联系的情况。
如果出现多个任务访问同一资源时,比如两个任务都可以对一个变量进行赋值,就会发生冲突。
如何解决这些冲突呢?这就是需要OS来进行管理。
这只是OS的工作之一,其最重要的工作是进行任务之间的切换。
本篇实验将在上一篇的基础上进行,将运行两个任务,每个任务控制一个LED的亮灭。
例2-1先修改程序,编译运行。
main文件不用修改。
增加一个任务Task_LED2()。
1.修改app_cfg.h文件增加新增任务Task_LED2的一些设置项定义。
ucos II消息队列处理多按键_ _适合初学者

ucos II消息队列处理多按键_ _适合初学者ucos-ii消息队列处理多按键_--_适合初学者2021-08-2417:36ucos-ii消息队列处置多按键上一次采用信号量的方式处理一个按键,采用发送和等待信号量的方式来实现该按键的扫描。
但是如果系统有多个按键需要处理呢?是否还可以用信号量呢?当然其实也可以的,多个按键就创建对个信号量呗!这样处理可是可以,不过很繁琐。
本文介绍另外一种处理方案:采用消息队列的方式。
将每一个按键对应一条消息,当某个按键按下时,就发送该按键的消息到消息队列:osqpost(keyqevent,qmsg_ka);然后在按键处理任务重一直调用q_keymsg=(int8u*)osqpend(keyqevent,10,&err);加载消息队列,也就是推论该函数的返回值是否是按键消息qmsg_ka,如果就是则适当,如果不是则延时任务。
/*消息队列有关变量定义初始化-------------------------------------------------*/os_event*keyqevent;/*定义消息队列的事件掌控块,用作发送消息队列返回值,如果消息队列创建成功,则返回一个指针,这个指针用于以后对消息队列的操作因此,该指针可以看作就是适当消息队列的句柄。
qevent=osqcreate(&qstart[0],10);*/int8uerr;/*定义消息队列的错误变量osqpend(qevent,2000,&err);发送消息等候错误*/void*qstart[10];/*定义消息队列的指针数组,可容纳10则消息*/int8u*qmsg_ka=\定义一则消息,*/int8u*qmsg_kb=\定义一则消息,*/keyqevent=osqcreate(&qstart[0],10);/*建立一个消息队列,可容纳10则消息*/voidtaskkeyscan(void*pdata)/*按键扫描任务*/{int8ukeyastate;int8ukeybstate;int8ukeya_release=0;int8ukeyb_release=0;pdata=pdata;for(;;){ostimedlyhmsm(0,0,0,50);keyastate=gpio_readinputdatabit(gpioc,gpio_pin_13);/*按键按下回到0*/keybstate=gpio_readinputdatabit(gpiob,gpio_pin_2);/*按键按下返回1*//*按键keya有效率--------------------*/if(keyastate==0){ostimedlyhmsm(0,0,0,20);/*20ms去抖动*/keyastate=gpio_readinputdatabit(gpioc,gpio_pin_13);if(keyastate==0){keya_release=1;}}if(keyastate==1&&keya_release==1)/*本次按键有效率*/{osqpost(keyqevent,qmsg_ka);/*发送按键keya被按下消息*/keya_release=0;/*按键释放标识清除*/printf(\}/*按键keyb有效率---------------------*/if(keybstate==1){ostimedlyhmsm(0,0,0,20);keybstate=gpio_readinputdatabit(gpiob,gpio_pin_2);if(keybstate==1){keyb_release=1;}}if(keybstate==0&&keyb_release==1)/*本次按键有效率*/{osqpost(keyqevent,qmsg_kb);/*发送按键keyb被按下消息*/keyb_release=0;/*按键释放标识清除*/printf(\}}}voidtaskled(void*pdata)/*按键相应任务*/{int8u*q_keymsg;pdata=pdata;for(;;){q_keymsg=(int8u*)osqpend(keyqevent,10,&err);/*读取消息队列*/if(err==os_no_err){if(q_keymsg==qmsg_kb)/*如果按键b被按键,则相应相关处理函数*/{led4_toggle();num++;}elseif(q_keymsg==qmsg_ka)/*如果按键a被按键*/{led4_toggle();num--;}}}}。
S.D.Lu的uCOSII入门学习笔记互斥信号量

S.D.Lu的uC/OS II 入门学习笔记(6):互斥信号量在该系列笔记前面篇章中,我刻意跳过了互斥信号量的介绍,是有原因的。
该系列笔记面向的是初学者,信号量通信是学习者初次接触任务同步的相关内容,后面还有消息邮箱和消息队列。
因为互斥信号量的内容还会涉及到优先级反转的内容,对初学者来说相对复杂。
所以,先学习完消息邮箱和消息队列的基本应用之后,再回过头学习互斥信号量的内容会比较好。
本篇实验将在第(3)篇的基础上进行,仍然是运行两个任务,每个任务控制一个LED的亮灭。
问题的提出在可剥夺型内核中,当任务以独占式使用共享资源时,会出现低优先级任务先于高优先级任务被运行的现象,这就是任务优先级反转。
一般来说,在实时系统中不允许出现这种现象,因为它破坏了任务执行的预期顺序,可能要导致严重后果。
关于这个现象的详细描述,请仔细阅读任哲《嵌入式实时操作系统μCOS-II原理及应用》(第2版)第五章5.4.1节。
其中例子基本描述是这样的,有A、B、C三个任务,它们的优先级别A>B>C,而且A和C共享一个独占式资源S。
当C占用该资源时,如果此时A 申请访问资源S,那么A由于等待资源S而得不到运行。
这样,任务B就可能超越任务A 优先得到运行。
任务C占用资源的时间越长,A就会被阻塞越久。
解决问题的办法之一是,使获得信号量任务的优先级别在使用共享资源期间暂时提升到所有任务最高优先级的高一个级别上,以使该任务不被其他任务所打断,从而能尽快地使用完共享资源并释放信号量,然后再回复该任务原来的优先级别。
引入互斥型信号量,就是为了解决上述问题的。
在上一篇例3-2的基础上进行修改。
例6-1将app.c中的内容改为如下:编译下载,运行程序,结果和例3-2相同,LED2闪烁2次后LED1闪烁1次,如此循环,而且两路LED不会同时被点亮(刚开始上电的时候有可能同时被点亮,取决于初始化函数)。
需要注意的是,本例中用到了互斥信号量及相关函数等,所以在os_cfg.h配置文件中必须将OS_MUTEX_EN置1,如下图:几个相关的函数原型如下:本例非常简单,而且并没有体现互斥信号量的作用。
UCOS-II学习笔记

事件标志管理 (EVENT FLAGS MANAGEMENT)* OSFlagAccept()检查事件标志组函数(标志组的指针、事件标志位、等待事件标志位的方式、错误码指针)* OSFlagCreate()建立一个事件标志组(初值、错误码)* OSFlagDel()删除一个事件标志组(指针、条件值、错误值)* OSFlagPend() 等待事件标志组的事件标志位(事件组指针、需要检查的标志位、等待事件标志位的方式、允许等待的时钟节拍、出错代码的时钟节拍)* OSFlagPost()置位或清0事件标志组中的标志位(指针、标志位、条件值、错误码)operating system\flag标记\accept接受\create创建\pend悬而未决\post布置消息邮箱管理 (MESSAGE MAILBOX MANAGEMENT)* OSMboxAccept ()查看消息邮箱(消息邮箱指针)* OSMboxCreate ()建立并初始化一个消息邮箱(msg 参数不为空含内容)* OSMboxDel ()删除消息邮箱(消息邮箱指针、删除条件、出错代码指针)* OSMboxPend ()等待一个消息邮箱函数(消息邮箱指针、允许等待的时钟节拍、代码错误指针)* OSMboxPost ()发送消息函数(消息邮箱指针、即将实际发送给任务的消息)* OSMboxPostOpt() 向邮箱发送一则消息(邮箱指针、消息、条件)* OSMboxQuery () 查询一个邮箱的当前状态(信号量指针、状态数据结构指针)Mail邮件\box盒子\opt选择\query询问内存管理项 (MEMORY MANAGEMENT)* OSMemCreate ()建立并初始化一块内存区(起始地址、需要的内存块数目、内存块大小、返回错误的指针)* OSMemGet ()从内存区分配一个内存块* OSMemPut () 释放一个内存块,内存块必须释放回原先申请的内存区* OSMemQuery ()得到内存区的信息Get获得\put放互斥型信号量项管理 (MUTUAL EXCLUSION SEMAPHORE MANAGEMENT)* OSMutexAccept ()无等待地获取互斥型信号量[任务不挂起](信号量指针、错误代码)* OSMutexCreate () 建立并初始化一个互斥型信号量(优先级继承优先级(PIP)、出错代码指针)* OSMutexDel ()删除互斥型信号量(信号指针、删除条件、错误指针)* OSMutexPend ()等待一个互斥型信号量(指针、等待超时时限、出错代码指针)* OSMutexPost () 释放一个互斥型信号量(互斥型信号量指针)* OSMutexQuery () 查询一个互斥型信号量的当前状态(互斥型信号量指针,状态数据结构指针)消息队列管理 (MESSAGE QUEUE MANAGEMENT)* OSQAccept ()检查消息队列中是否已经有需要的消息(消息队列的指针)* OSQCreate ()建立一个消息队列(消息内存区的基地址(指针数组)、消息内存区的大小)* OSQDel ()删除一个消息队列(消息队列指针、删除条件、错误指针)* OSQFlush ()清空消息队列(指向得到消息队列的指针)* OSQPend ()任务等待消息队列中的消息(消息队列指针、允许等待的时钟节拍、代码错误指针)* OSQPost ()向消息队列发送一则消息FIFO(消息队列指针、发送的消息)* OSQPostFront ()向消息队列发送一则消息LIFO(消息队列指针、发送的消息)* OSQPostOpt ()向消息队列发送一则消息LIFO(消息队列指针、发送的消息、发送条件)Flush清洗\front前面信号量管理 (SEMAPHORE MANAGEMENT)* OSSemAccept()无条件地等待请求一个信号量函数* OSSemCreate()建立并初始化一个信号量(输入一个信号量值)* OSSemDel()删除一个信号量(信号指针、删除条件、错误指针)* OSSemPend ()等待一个信号量函数(信号量指针、允许等待的时钟节拍、代码错误指针)* OSSemPost () 发出一个信号量函数(信号量指针)* OSSemQuery ()查询一个信号量的当前状态(信号量指针、状态数据结构指针)任务管理 (TASK MANAGEMENT)* OSTaskChangePrio()改变一个任务的优先级(任务旧的优先级、任务新的优先级)* OSTaskCreate ()建立任务(任务代码指针、传递参数指针、分配任务堆栈栈顶指针、任务优先级)* OSTaskCreateExt ()建立扩展任务(任务代码指针/传递参数指针/分配任务堆栈栈顶指针/分配任务优先级* OSTaskDel ()删除任务(任务的优先级)* OSTaskDelReq ()请求一个任务删除其它任务或自身?(任务的优先级)* OSTaskResume ()唤醒一个用OSTaskSuspend()函数挂起的任务(任务的优先级)* OSTaskStkChk ()检查任务堆栈状态(任务优先级、检验堆栈数据结构)* OSTaskSuspend () 无条件挂起一个任务(任务优先级)change改变\priority优先权\extend扩展\req请求\resume继续\check检查\suspend延缓时钟管理项 (TIME MANAGEMENT)* OSTimeDly ()任务延时函数(时钟节拍数)* OSTimeDlyHMSM ()将一个任务延时若干时间(设定时、分、秒、毫秒)* OSTimeDlyResume ()唤醒一个用OSTimeDly()或OSTimeDlyHMSM()函数的任务(优先级)* OSTimeGet ()获取当前系统时钟数值* OSTimeSet () 设置当前系统时钟数值混杂函数定义* OSInit()初始化UCOS-II函数* OSIntEnter()中断函数正在执行* OSIntExit()中断函数已经完成(脱离中断)* OSSchedLock()给调度器上锁* OSSchedUnlock()给调度器解锁* OSStart() 启动多个任务* OSStatInit()统计任务初始化* OSVersion()获得版本号Version版本\ lock锁定\unlock解锁各变量初始化情况变量值类型变量的说明*OSPrioCur 0 INT8U 正在运行的任务的优先级*OSPrioHighRdy 0 INT8U 具有最高优先级别的就绪任务的优先级*OSTCBDly INT16U 允许任务等待时的最多节拍数*OSTCBPrioTbl[ ] 任务控制块优先级表*OSTime 0L INT32U 表示系统当前时间(节拍数)*OSIntNesting 0 INT32U 存放中断嵌套的层数(0~255)*OSLockNesting 0 INT8U 调用了OSSchededLock的嵌套数*OSCtxSwCtr 0 INT32U 上下文切换的次数(统计任务计数器)*OSTtaskCtr 2 INT8U 已经建立的任务数*OSRunning FALSE BOOLEAN OS-II是否正在运行的标志*OSCPUUsage 0 INT8S 存放CPU的利用率(%)的变数*OSIdleCtrMax 0L INT32U 表示每秒空闲任务计数的最大值*OSIdleCtrRun 0L INT32U 表示空闲任务计数器每秒的计数值-----精心整理,希望对您有所帮助!。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
S.D.Lu的uC/OS II入门学习笔记(5):消息队列
本篇实验在上一篇的基础上进行,仍然是运行两个任务,每个任务控制一个LED的亮灭。
但是这两个任务使用了消息队列进行通信。
任务Task_LED2通过消息队列发送消息,Task_LED根据接收到的消息内容选择执行不同的代码。
例5-1将app.c中的内容改为如下:(红框标识了消息队列的相关操作)
编译下载,运行后LED2以固定的频率闪烁。
LED2闪烁10次后,LED1闪一下,点亮时间很短;LED2继续闪烁10次后,LED1再闪一下,点亮时间比第一次稍长;LED2再闪烁10次后,LED1再闪一下,点亮时间比前两次都长。
三种点亮时间反复循环,和上一篇的例4-2实验运行结果相同。
注意,因为用到了消息队列及相关函数,所以在配置文件os_cfg.h中必须使能相应的宏定义。
本例中,将第20行的代码改为LED_Q = OSQCreate(&Msg_Grp[0],1);,其运行结果不变。
?问题?
如果用消息邮箱,或者消息队列中只有1个邮箱,就能完成任务之间的通信,那么还要消息队列有什么用?
答:消息队列相当于多个邮箱组成的邮箱数组,可以存储多条消息。
假设几个优先级别较高的任务负责信息的采集,然后通过消息队列发送给一个优先级别较低的任务进一步处理。
那么当采集信息的任务比较繁忙的时候,不断地采集和发送消息到消息队列中,低优先级的任务会得不到运行,从而不能及时处理消息队列中的消息。
此时,消息队列对发来的消息进行排队、暂时缓存起来,等到处理信息的低优先级任务得到运行的时候再把消息依次读出来,进行处理。
由于例5-1太简单,并没有体现消息队列的作用。
下面在例5-1的基础上进行修改,模拟消息在队列中发生缓存的情况。
例5-2将app.c中的内容改为如下:
编译下载,运行后LED2以固定的频率闪烁,LED1为熄灭状态。
LED2闪烁10次之后,LED1以较快的速度闪烁,LED1闪烁10次后闪烁速度变慢,LED1再闪烁10次后闪烁速度变得更慢,然后再闪烁10次后熄灭。
本例中,Task_LED2运行LED2闪烁10次后向消息队列连续发送了3条消息,然后循环控制LED2闪烁。
Task_LED在创建完消息队列和Task_LED2之后,就请求消息队列,并根据消息队列中消息的内容对LED2进行控制。
消息队列中存储了Task_LED2发送的3条消息。
Task_LED2调用的发送函数是OSQPost(),所以消息队列中消息是按照FIFO顺序进行排列的。
所以Task_LED第一次请求消息队列时,得到的消息是msg1,然后进入switch语句,根据msg1[0]的内容,运行case 1:的分支,LED1闪烁10次。
然后请求消息队列,得到msg2,根据msg2[0]的内容,运行case 2:的分支。
之后再次请求消息队列,得到msg3,根据msg3[0]的内容,运行case 3:的分支。
此时,3条消息已经全部被读取出来,所以消息队列为空,Task_LED第四次请求消息队列时,任务被挂起。
调换75~77行代码的次序,就可以得到LED1不同的控制次序。
很显然,Task_LED2发送3条消息所用的时间是很短的。
而Task_LED读取第一条消息之后,对LED1进行了10次闪烁的控制,然后才请求第二条消息,在此期间,Task_LED2已经完成3条消息的发送。
这样,Task_LED2发送后Task_LED未及时处理的消息就存储在消息队列中。
由此可知,消息队列是用于缓冲未被及时处理的消息的。
(这一点,任哲老师的书中所举的例子并没有体现出来。
)
深入了解消息队列的相关知识,请参考任哲《嵌入式实时操作系统μCOS-II原理及应用》(第2版)第五章 5.1、5.6节关于消息队列的内容。
作者:S.D.Lu
深圳
2014-6-3。