本文结构

  • 1.UCOSII原理
  • 2.UCOSII实验代码

1.UCOSII原理

UCOSII 是一个可以基于ROM 运行的、可裁减的、抢占式、实时多任务内核,具有高度可
移植性,特别适合于微处理器和控制器,是和很多商业操作系统性能相当的实时操作系统
(RTOS)。

UCOSII 是专门为计算机的嵌入式应用设计的, 绝大部分代码是用C 语言编写的。CPU 硬
件相关部分是用汇编语言编写的、总量约200 行的汇编语言部分被压缩到最低限度,为的是便
于移植到任何一种其它的CPU 上。用户只要有标准的ANSI 的C 交叉编译器,有汇编器、连
接器等软件工具,就可以将UCOSII 嵌人到开发的产品中。UCOSII 具有执行效率高、占用空间
小、实时性能优良和可扩展性强等特点, 最小内核可编译至 2KB 。UCOSII 已经移植到了几
乎所有知名的CPU 上。

UCOSII体系结构如图所示

UCOSII在版本2.80后,支持任务数提高到255个。
任务,其实就是一个死循环函数,该函数实现一定的功能,一个工程可以有很多这样的任务(最多255个),UCOSII对这些任务进行调度管理,让这些任务可以并发工作(并发的意思是:各任务轮流占用CPU,而不是同时占用,任何时候还是只有1个任务能够占用CPU),这就是UCOSII最基本的功能。Ucos任务的一般格式为:

void MyTask(void *pdata){//任务准备工作while(1){//任务MyTask实际代码...OSTimeDlyHMSM();//调用任务延时函数,释放cpu控制权}
}

下面有几个概念需要掌握
1.任务优先级
每个任务都有一个唯一的优先级,换言之,每个任务的优先级都不一样。在UCOSII中,优先级高的任务比优先级低的任务有CPU优先使用权,只有高优先级的任务让出使用权时(用的多的是函数OSTimeDlyHMSM();//调用任务延时函数,释放cpu控制权),低优先级的任务才可以使用CPU。

2.任务堆栈
任务堆栈是存储器中的一块连续区域,每个任务都有自己的堆栈,主要是为了满足任务切换和响应中断时保存CPU寄存器中的内容。

3.任务控制块
任务控制块OS_TCB,用来记录任务堆栈指针,任务当前状态以及任务优先级等任务属性。UCOSII的任何任务都是通过任务控制块(TCB)来控制,一旦任务创建,任务控制块OS_TCB就会被赋值。每个任务管理块有3个最重要的参数:任务函数指针;任务堆栈指针;任务优先级。任务控制块就是任务在系统里面的身份证(UCOSII通过优先级识别任务)。

4 .任务就绪表
任务就绪表,用来记录系统中所有处于就绪状态的任务。它是一个位图,系统中每个任务都在这个位图中占据一个进制位,该位置的状态(1或者0)就表示任务是否处于就绪状态。

5.任务调度
任务调度的作用一是在任务就绪表中查找优先级最高的就绪任务,二是实现任务的切换。比如说,当一个任务释放cpu控制权后,进行一次任务调度,这个时候任务调度器首先要去任务就绪表查询优先级最高的就绪任务,查到之后,进行一次任务切换,转而去执行下一个任务。

下面是几个关于任务的函数:
1)任务建立函数
一般使用OSTaskCreate
定义为


INT8U  OSTaskCreate (void   (*task)(void *p_arg),void    *p_arg,OS_STK  *ptos,INT8U    prio)

解释如下
该函数包括4个参数:task:是指向任务代码的指针;p_arg:是任务开始执行时,传递给任务参数的指针;ptos:是分配给任务的堆栈的栈顶指针;prio是分配给任务的优先级。

/*
*********************************************************************************************************
*                                            CREATE A TASK
*
* Description: This function is used to have uC/OS-II manage the execution of a task.  Tasks can either
*              be created prior to the start of multitasking or by a running task.  A task cannot be
*              created by an ISR.
*
* Arguments  : task     is a pointer to the task's code
*
*              p_arg    is a pointer to an optional data area which can be used to pass parameters to
*                       the task when the task first executes.  Where the task is concerned it thinks
*                       it was invoked and passed the argument 'p_arg' as follows:
*
*                           void Task (void *p_arg)
*                           {
*                               for (;;) {
*                                   Task code;
*                               }
*                           }
*
*              ptos     is a pointer to the task's top of stack.  If the configuration constant
*                       OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high
*                       memory to low memory).  'pstk' will thus point to the highest (valid) memory
*                       location of the stack.  If OS_STK_GROWTH is set to 0, 'pstk' will point to the
*                       lowest memory location of the stack and the stack will grow with increasing
*                       memory locations.
*
*              prio     is the task's priority.  A unique priority MUST be assigned to each task and the
*                       lower the number, the higher the priority.
*
* Returns    : OS_ERR_NONE             if the function was successful.
*              OS_PRIO_EXIT            if the task priority already exist
*                                      (each task MUST have a unique priority).
*              OS_ERR_PRIO_INVALID     if the priority you specify is higher that the maximum allowed
*                                      (i.e. >= OS_LOWEST_PRIO)
*              OS_ERR_TASK_CREATE_ISR  if you tried to create a task from an ISR.
*********************************************************************************************************
*/

2)任务删除函数
任务删除,是把任务置于睡眠状态。一般使用OSTaskDel
原型为

INT8U OSTaskDel(INT8U prio);

其中参数prio就是要删除任务的优先级
特别注意:任务不能随便删除,必须在确保被删除任务的资源被释放的前提下才能删除!

3)请求任务删除函数
向被删除任务发送删除请求,实现任务释放自身占用的资源并删除。函数为OSTaskDelReq,原型如下

INT8U OSTaskDelReq(INT8U prio);

其中参数prio就是要删除任务的优先级
4)优先级更改函数
函数为OSTaskChangePrio,其原型如下

INT8U OSTaskChangePrio(INT8U oldprio,INT8U newprio);

其中参数oldprio是要任务的之前的优先级,newprio是更改之后的优先级。

5)任务挂起函数
任务挂起函数把任务的就绪标志删除,做好任务挂起记录,被挂起的任务,在解挂之后可以继续运行。任务观其函数为OsTaskSuspend
定义为

INT8U  OSTaskSuspend (INT8U prio)
{BOOLEAN    self;OS_TCB    *ptcb;INT8U      y;
#if OS_CRITICAL_METHOD == 3u                     /* Allocate storage for CPU status register           */OS_CPU_SR  cpu_sr = 0u;
#endif#if OS_ARG_CHK_EN > 0uif (prio == OS_TASK_IDLE_PRIO) {                            /* Not allowed to suspend idle task    */return (OS_ERR_TASK_SUSPEND_IDLE);}if (prio >= OS_LOWEST_PRIO) {                               /* Task priority valid ?               */if (prio != OS_PRIO_SELF) {return (OS_ERR_PRIO_INVALID);}}
#endifOS_ENTER_CRITICAL();if (prio == OS_PRIO_SELF) {                                 /* See if suspend SELF                 */prio = OSTCBCur->OSTCBPrio;self = OS_TRUE;} else if (prio == OSTCBCur->OSTCBPrio) {                   /* See if suspending self              */self = OS_TRUE;} else {self = OS_FALSE;                                        /* No suspending another task          */}ptcb = OSTCBPrioTbl[prio];if (ptcb == (OS_TCB *)0) {                                  /* Task to suspend must exist          */OS_EXIT_CRITICAL();return (OS_ERR_TASK_SUSPEND_PRIO);}if (ptcb == OS_TCB_RESERVED) {                              /* See if assigned to Mutex            */OS_EXIT_CRITICAL();return (OS_ERR_TASK_NOT_EXIST);}y            = ptcb->OSTCBY;OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;                   /* Make task not ready                 */if (OSRdyTbl[y] == 0u) {OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;}ptcb->OSTCBStat |= OS_STAT_SUSPEND;                         /* Status of task is 'SUSPENDED'       */OS_EXIT_CRITICAL();if (self == OS_TRUE) {                                      /* Context switch only if SELF         */OS_Sched();                                             /* Find new highest priority task      */}return (OS_ERR_NONE);
}

解释如下

/*
*********************************************************************************************************
*                                            SUSPEND A TASK
*
* Description: This function is called to suspend a task.  The task can be the calling task if the
*              priority passed to OSTaskSuspend() is the priority of the calling task or OS_PRIO_SELF.
*
* Arguments  : prio     is the priority of the task to suspend.  If you specify OS_PRIO_SELF, the
*                       calling task will suspend itself and rescheduling will occur.
*
* Returns    : OS_ERR_NONE               if the requested task is suspended
*              OS_ERR_TASK_SUSPEND_IDLE  if you attempted to suspend the idle task which is not allowed.
*              OS_ERR_PRIO_INVALID       if the priority you specify is higher that the maximum allowed
*                                        (i.e. >= OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF.
*              OS_ERR_TASK_SUSPEND_PRIO  if the task to suspend does not exist
*              OS_ERR_TASK_NOT_EXITS     if the task is assigned to a Mutex PIP
*
* Note       : You should use this function with great care.  If you suspend a task that is waiting for
*              an event (i.e. a message, a semaphore, a queue ...) you will prevent this task from
*              running when the event arrives.
*********************************************************************************************************
*/

6)任务恢复函数
有任务挂起函数,就有任务恢复函数,通过该函数将被挂起的任务恢复,让调度器能够重新调度该函数。函数为OSTaskResume
原型为

INT8U OSTaskResume(INT8U prio);

UCOSII信号量和邮箱
任务间的同步依赖于任务间的通信。在UCOSII 中,是使用信号量、邮箱(消息邮箱)和消息队列这些被称作事件的中间环节来实现任务之间的通信。使用事件控制块来描述具体的信息,事件控制块结构体

typedef struct{INT8U OSEventType;//事件的类型INT16U OSEventCnt;//信号量计数器void *OSEventPtr; //消息或消息队列的指针INT8U OSEventGrp; //等待事件的任务组INT8U OSEventTbl[OS_EVENT_TBL_SIZE];//任务等待表
#if OS_EVENT_NAME_EN > 0uINT8U *OSEventName; //事件名
#endif
}OS_EVENT;

信号量
信号量是一类事件,它是为了给共享资源设立一个标志,该标志表示该共享资源的占用情况。这样,当一个任务在访问共享资源之前,就可以先对这个标志进行查询,从而在了解资源被占用的情况之后,再来决定自己的行为。

信号量可以分为两种:一种是二值型信号量(也称为互斥信号量),另外一种是N 值信号量。

邮箱
在多任务操作系统中,常常需要在任务与任务之间通过传递“消息”的方式来进行通信。为此需要在内存中创建一个存储空间作为该消息的缓冲区,称为消息缓冲区,这样在任务间传递数据(消息)的最简单办法就是传递消息缓冲区的指针。把用来传递消息缓冲区指针的数据结构叫做邮箱(消息邮箱)。
在UCOSII中,通过事件控制块的OSEventPrt来传递消息缓冲区指针,同时使事件控制块的成员OSEventType为常数OS_EVENT_TYPE_MBOX,则该事件控制块就叫做消息邮箱。

下面看一下关于信号量的函数
1)创建信号量
函数为OSSemCreate

OS_EVENT *OSSemCreate (INT16U cnt);

该函数返回值为已创建的信号量的指针,而参数cnt则是信号量计数器(OSEventCnt)的初始值。
2)请求信号量函数
函数为OSSemPend

void OSSemPend ( OS_EVENT *pevent, INT16U timeout, INT8U *err);

其中,参数pevent是被请求信号量的指针,timeout为等待时限,err为错误信息。
为防止任务因得不到信号量而处于长期的等待状态,函数OSSemPend允许用参数timeout设置一个等待时间的限制,当任务等待的时间超过timeout时可以结束等待状态而 进入就绪状态。如果参数timeout被设置为0,则表明任务的等待时间为无限长。

3)发送信号量函数
任务获得信号量,并在访问共享资源结束以后要释放信号量,释放信号量也叫做发送信号量,发送信号通过OSSemPost函数实现 。OSSemPost 函数在对信号量的计数器操作之前,首先要检查是否还有等待该信号量的任务。如果没有,就把信号量计数器OSEventCnt加一;如果有,则调用调度器OS_Sched( )去运行等待任务中优先级别最高的任务。函数OSSemPost的原型为:

INT8U OSSemPost(OS_EVENT *pevent);

其中,pevent为信号量指针,该函数在调用成功后,返回值为OS_ON_ERR,否则会根据具体错误返回OS_ERR_EVENT_TYPE、OS_SEM_OVF。

4)删除信号量
应用程序如果不需要某个信号量,可以调用函数OSSemDel来删除该信号量,该函数的原型为:

OS_EVENT *OSSemDel (OS_EVENT *pevent,INT8U opt, INT8U *err);

其中,pevent为要删除的信号量指针,opt为删除条件选项,err为错误信息。

下面是关于邮箱的函数

1)创建邮箱
创建邮箱通过函数OSMboxCreate实现,该函数原型为:

OS_EVENT *OSMboxCreate (void *msg);

函数中的参数msg为消息的指针,函数的返回值为消息邮箱的指针。

调用函数OSMboxCreate需先定义msg的初始值。在一般的情况下,这个初始值为NULL;但也可以事先定义一个邮箱,然后把这个邮箱的指针作为参数传递到函数OSMboxCreate 中,使之一开始就指向一个邮箱。

2) 向邮箱发送消息函数
任务可以通过调用函数OSMboxPost向消息邮箱发送消息,这个函数的原型为:

 INT8U OSMboxPost (OS_EVENT *pevent,void *msg);

其中pevent为消息邮箱的指针,msg为消息指针。
3) 请求邮箱函数
当一个任务请求邮箱时需要调用函数OSMboxPend,这个函数的主要作用就是查看邮箱指针OSEventPtr是否为NULL,如果不是NULL就把邮箱中的消息指针返回给调用函数的任务,同时用OS_NO_ERR通过函数的参数err通知任务获取消息成功;如果邮箱指针OSEventPtr是NULL,则使任务进入等待状态,并引发一次任务调度。
函数OSMboxPend的原型为:

 void *OSMboxPend (OS_EVENT *pevent, INT16U timeout, INT8U *err);

其中pevent为请求邮箱指针,timeout为等待时限,err为错误信息。

4) 查询邮箱状态函数
任务可以通过调用函数OSMboxQuery查询邮箱的当前状态。该函数原型为:

 INT8U OSMboxQuery(OS_EVENT *pevent,OS_MBOX_DATA *pdata);

其中pevent为消息邮箱指针,pdata为存放邮箱信息的结构。

5) 删除邮箱函数
在邮箱不再使用的时候,我们可以通过调用函数OSMboxDel来删除一个邮箱,该函数原型为:

OS_EVENT *OSMboxDel(OS_EVENT *pevent,INT8U opt,INT8U *err);

其中pevent为消息邮箱指针,opt为删除选项,err为错误信息。

2.UCOSII实验代码

下面是一个STM32mini板实例:
主要功能:程序初始时,LED0灯闪烁,表示任务1在运行;串口显示表示任务2在运行。
通过信号量和邮箱,实现KEY0控制LED0任务(任务1)的挂起,KEY1实现串口显示任务(任务2)的删除,并且实现LED1灯的亮灭;WK_UP实现LED0任务(任务1)的恢复。

实验结果:只有窗口显示部分

main.c文件

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "includes.h"
#include "key.h"
#include "usart.h"
//START 任务
//设置任务优先级
#define START_TASK_PRIO         10  ///开始任务的优先级为最低
//设置任务堆栈大小
#define START_STK_SIZE          128
//任务任务堆栈
OS_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *pdata);//LED0任务
//设置任务优先级
#define LED0_TASK_PRIO          7
//设置任务堆栈大小
#define LED0_STK_SIZE           64
//任务堆栈
OS_STK LED0_TASK_STK[LED0_STK_SIZE];
//任务函数
void led0_task(void *pdata);//LED1任务
//设置任务优先级
#define LED1_TASK_PRIO                  6
//设置任务堆栈大小
#define LED1_STK_SIZE                   64
//任务堆栈
OS_STK LED1_TASK_STK[LED1_STK_SIZE];
//任务函数
void led1_task(void *pdata);//key传递函数
//设置任务优先级
#define KEY_TASK_PRIO                   5
//设置任务堆栈大小
#define KEY_STK_SIZE                        64
//任务堆栈
OS_STK KEY_TASK_STK[KEY_STK_SIZE];
//任务函数
void key_task(void *pdata);//按键扫描任务
//设置任务优先级
#define SCAN_TASK_PRIO                  4
//设置任务堆栈大小
#define SCAN_STK_SIZE                   64
//任务堆栈
OS_STK SCAN_TASK_STK[SCAN_STK_SIZE];
//任务函数
void scan_task(void *pdata);    //串口显示任务
#define FLOAT_TASK_PRIO         8
//设置任务堆栈大小
#define FLOAT_STK_SIZE          128
//任务堆栈
//如果任务中使用printf来打印浮点数据的话一点要8字节对齐
__align(8) OS_STK FLOAT_TASK_STK[FLOAT_STK_SIZE];
//任务函数
void float_task(void *pdata);OS_EVENT * msg_key; //按键邮箱时间块指针
OS_EVENT * sem_led0; //LED0信号量指针
OS_EVENT * sem_led1; //LED1信号量指针
OS_EVENT * sem_print;//WK_UP信号量指针int main(void)
{delay_init();       //延时初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组配置uart_init(115200);    //串口波特率设置LED_Init();      //LED初始化KEY_Init();OSInit();        //UCOS初始化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;pdata = pdata; msg_key=OSMboxCreate((void *)0);//创建消息邮箱sem_led0=OSSemCreate(0);sem_led1=OSSemCreate(0);//创建信号量sem_print=OSSemCreate(0);OS_ENTER_CRITICAL();            //进入临界区(无法被中断打断)    OSTaskCreate(led0_task,(void *)0,(OS_STK*)&LED0_TASK_STK[LED0_STK_SIZE-1],LED0_TASK_PRIO);                         OSTaskCreate(led1_task,(void *)0,(OS_STK*)&LED1_TASK_STK[LED1_STK_SIZE-1],LED1_TASK_PRIO);OSTaskCreate(key_task,(void *)0,(OS_STK*)&KEY_TASK_STK[KEY_STK_SIZE-1],KEY_TASK_PRIO);OSTaskCreate(scan_task,(void *)0,(OS_STK*)&SCAN_TASK_STK[SCAN_STK_SIZE-1],SCAN_TASK_PRIO);OSTaskCreate(float_task,(void *)0,(OS_STK*)&FLOAT_TASK_STK[FLOAT_STK_SIZE],FLOAT_TASK_PRIO);OSTaskSuspend(START_TASK_PRIO); //挂起起始任务.OS_EXIT_CRITICAL();             //退出临界区(可以被中断打断)
}//LED0任务
void led0_task(void *pdata)
{//u8 err; while(1){// OSSemPend(sem_led0,0,&err);LED0=0;delay_ms(500);LED0=1;delay_ms(500);};
}//LED1任务
void led1_task(void *pdata)
{   u8 err;while(1){OSSemPend(sem_led1,0,&err);LED1=0;delay_ms(500);LED1=1;delay_ms(500);}
}//按键扫描任务
void key_task(void *pdata)
{int key=0;u8 err;while(1){key=(int)OSMboxPend(msg_key,10,&err);switch(key){case KEY0_PRES://发送信号量0OSSemPost(sem_led0);OSTaskSuspend(LED0_TASK_PRIO);//led0任务挂起break;case KEY1_PRES://发送信号量1OSSemPost(sem_led1);OSTaskDel(FLOAT_TASK_PRIO);//删除串口显示任务break;case WKUP_PRES://OSSemPost(sem_print);// OSSemPost(sem_led1);OSTaskResume(LED0_TASK_PRIO);//led1任务挂起后恢复break;}}
}//串口显示任务
void float_task(void *pdata)
{//u8 err;OS_CPU_SR cpu_sr=0;while(1){//    OSSemPend(sem_print,0,&err);OS_ENTER_CRITICAL();   //进入临界区(关闭中断)printf("串口显示程序正在运行:\r\n\n"); //串口打印结果printf("这是任务2:\r\n\n"); //串口打印结果OS_EXIT_CRITICAL();       //退出临界区(开中断)delay_ms(500);}
}//按键扫描任务
void scan_task(void *pdata)
{u8 key;while(1){key=KEY_Scan(0);if(key)OSMboxPost(msg_key,(void*)key);//发送消息delay_ms(10);}
}

key.c文件

#include "key.h"
#include "delay.h"//按键初始化函数
//PA0.15和PC5 设置成输入
void KEY_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC,ENABLE);//使能PORTA,PORTC时钟GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);//关闭jtag,使能SWD,可以用SWD模式调试GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_15;//PA15GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA15GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;//PC5GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC5GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;//PA0GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0设置成输入,默认下拉      GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.0}
//按键处理函数
//返回按键值
//mode:0,不支持连续按;1,支持连续按;
//返回值:
//0,没有任何按键按下
//KEY0_PRES,KEY0按下
//KEY1_PRES,KEY1按下
//WKUP_PRES,WK_UP按下
//注意此函数有响应优先级,KEY0>KEY1>WK_UP!!
u8 KEY_Scan(u8 mode)
{    static u8 key_up=1;//按键按松开标志if(mode)key_up=1;  //支持连按          if(key_up&&(KEY0==0||KEY1==0||WK_UP==1)){delay_ms(10);//去抖动 key_up=0;if(KEY0==0)return KEY0_PRES;else if(KEY1==0)return KEY1_PRES;else if(WK_UP==1)return WKUP_PRES; }else if(KEY0==1&&KEY1==1&&WK_UP==0)key_up=1;         return 0;// 无按键按下
}

led.c文件

#include "led.h"//初始化PA8和PD2为输出口.并使能这两个口的时钟
//LED IO初始化
void LED_Init(void)
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE);     //使能PA,PD端口时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;                 //LED0-->PA.8 端口配置GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;        //IO口速度为50MHzGPIO_Init(GPIOA, &GPIO_InitStructure);                     //根据设定参数初始化GPIOA.8GPIO_SetBits(GPIOA,GPIO_Pin_8);                       //PA.8 输出高GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;                //LED1-->PD.2 端口配置, 推挽输出GPIO_Init(GPIOD, &GPIO_InitStructure);                   //推挽输出 ,IO口速度为50MHzGPIO_SetBits(GPIOD,GPIO_Pin_2);                       //PD.2 输出高
}

工程目录

参考博客STM32上使用UCOSII–信号量和邮箱

STM32mini使用UCOSII信号量和邮箱实现任务挂起和恢复相关推荐

  1. UCOSII信号量和邮箱

    在UCOSII中,是使用信号量.邮箱(消息邮箱)和消息队列这些被称作事件的中间环节来实现任务之间的通信的. 1.事件 PS: 任务1是发信方,任务2是收信方: 任务1:负责把信息发送到事件上,这项操作 ...

  2. ucosii事件控制块------消息邮箱与消息队列

    UCOSII 使用叫做事件控制块(ECB)的数据结构来描述诸如信号量.邮箱(消息邮箱)和消息队列这些事件 #define OS_EVENT_EN (((OS_Q_EN > 0u) &&a ...

  3. UCOSII中消息邮箱的使用方法详解

    UCOSII中到底如何使用邮箱来进行任务间通信? 前言:什么是行为同步,什么是资源同步? 行为同步: 资源同步: 1.在中断服务程序中(ISR)可不可以发送消息? 在ISR中,是可以发送消息的.类似的 ...

  4. UCOSII 信号量和互斥信号量(保姆级别讲解)----看完不后悔系列!!!

    UCOSII 任务的同步与通信状态(保姆级别讲解)----看完不后悔系列!!! 添加链接描述 在前一篇文章基础背景下,我们为了解决对共享资源访问出现线程冲突的问题,引入了几个概念,分别是计数型信号量和 ...

  5. linux信号量参数能在线改吧,UCOSII信号量有问题,CNT值会自己变化

    我移植通过了,创建任务.删除任务这些实验也做过,没问题,然后我就准备来学习信号量,就发现问题了. //这个是起始任务 void TaskStart(void * pdata) { pdata = pd ...

  6. uCOS-II任务的挂起和恢复

    函数描述 OSTaskSuspend() 功能描述:无条件挂起一个任务.调用此函数的任务也可以传递参数OS_PRIO_SELF,挂起调用任务本身. 函数原型:INT8U OSTaskSuspend ( ...

  7. 【正点原子STM32连载】 第六十二章 UCOSII实验2-信号量和邮箱 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1

    1)实验平台:正点原子MiniPro H750开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=677017430560 3)全套实验源码+手册+视频 ...

  8. FreeRTOS记录(七、FreeRTOS信号量、事件标志组、邮箱和消息队列、任务通知的关系)

    我们在前面单独介绍过FreeRTOS的任务通知和消息队列, 但是在FreeRTOS中任务间的通讯还有信号量,邮箱,事件组标志等可以使用 这篇文章就这些成员与消息队列和任务通知的关系进行说明分析 ..增 ...

  9. ucos-ii嵌入式操作系统(四)---任务间同步之信号量

    先给自己打个广告,本人的微信公众号正式上线了,搜索:张笑生的地盘,主要关注嵌入式软件开发,股票基金定投,足球等等,希望大家多多关注,有问题可以直接留言给我,一定尽心尽力回答大家的问题,二维码如下: 一 ...

最新文章

  1. easyswoole数据库连接池_easyswoole redis连接池:集群迁移教程
  2. [置顶] Java程序员们读什么书决定了对未来职业方向的选择
  3. thinkphp隐藏后台地址
  4. 延大计算机文化基础课程作业,基于项目学习的大学《计算机文化基础课》教学设计...
  5. SKIP-NAME-RESOLVE ——错误的使用时机造成用户权限
  6. Windows Phone 7知识锦分享
  7. oracle 0 函数吗,Oracle9.2.0.1版函数编译一个小问题
  8. win7下 apache2.2 +php5.4 环境搭建
  9. php 模型 关联,PHP模型关联一对多如何给关联表加条件?
  10. Kubernetes学习总结(12)—— 学习 kubernetes 的10个技巧或建议
  11. Coin98 Finance获Alameda Research 400万美元投资
  12. java_oop_三大特性
  13. Intouch/ifix语音报警系统制作(3-利用自定义过程和函数,重构先前版本)
  14. 慕课java工程师2020版_2020年Java工程师就业前景怎么样?
  15. 计算机编程英语词汇大全
  16. JAVA蓝桥杯基础练习 Fibonacci数列
  17. 计算机如何切换显卡,Win7系统双显卡怎么切换独立显卡?电脑双显卡切换方法...
  18. 关于“访问映射网络驱动器提示 本地设备名已在使用中,此连接尚未还原”的解决方法
  19. 电子计算机off键是什么意思,off键是什么意思
  20. 新睿云教您easypanel的安装使用——使用篇(中)

热门文章

  1. CentOS 7 安装配置 NFS
  2. Visual Studio 压力测试注意点
  3. javaweb学习总结(四)——Http协议
  4. php图片去噪,python 图片去噪的方法示例
  5. source tree 递归子模块_每日刷题3--漫谈二叉树的递归遍历
  6. 满足什么条件的两个量才可以被分类?
  7. python class 属性是什么_python class 的属性
  8. 【控制】贪心算法(GA,Greedy Algorithm)及 Matlab 实现
  9. 【控制】《复杂运动体系统的分布式协同控制与优化》-方浩老师-第10章-基于模型预测控制的人机协同控制
  10. FPGA实现序列检测(训练testbench写法)