STM32上使用UCOSII--消息队列和信号量集
2017-07-22 21:09
239 查看
有关UCOS任务的介绍:
STM32上使用UCOSII–任务
有关UCOS信号量和邮箱的介绍:
STM32上使用UCOSII–信号量和邮箱
消息队列的数据结构如图:
消息队列相当于一个共用一个任务等待列表的消息邮箱数组,事件控制块成员OSEventPtr指向了一个叫做队列控制块(OS_Q)的结构,该结构管理了一个数组 MsgTbl[],该数组中的元素都是一些指向消息的指针
队列控制块( OS_Q)的结构定义如下:
其中,可以移动的指针为 OSQIn 和 OSQOut,而指针 OSQStart 和 OSQEnd 只是一个标志(常指针)。当可移动的指针 OSQIn 或 OSQOut 移动到数组末尾,也就是与OSQEnd相等时,可移动的指针将会被调整到数组的起始位置OSQStart。也就是说,从效果上来看,指针 OSQEnd与 OSQStart 等值。于是,这个由消息指针构成的数组就头尾衔接起来形成了一个循环的队列
start 为存放消息缓冲区指针数组的地址
size 为该数组大小
pevent 为所请求的消息队列的指针
timeout 为任务等待时限
err 为错误信息
pevent 为消息队列的指针
msg 为待发消息的指针
不同于信号量、消息邮箱、消息队列等事件, UCOSII 不使用事件控制块来描述信号量集,而使用了一个叫做标志组的结构 OS_FLAG_GRP 来描述。 OS_FLAG_GRP 结构如下:
成员 OSFlagWaitList 是一个指针,当一个信号量集被创建后,这个指针指向了这个信号量集的等待任务链表
与其他前面介绍过的事件不同,信号量集用一个双向链表来组织等待任务,每一个等待任务都是该链表中的一个节点( Node)。标志组 OS_FLAG_GRP 的成员 OSFlagWaitList 就指向了信号量集的这个等待任务链表。等待任务链表节点 OS_FLAG_NODE 的结构如下:
其中 OSFlagNodeWaitType 是定义逻辑运算关系的一个常数(根据需要设置),其可选值和对应的逻辑关系如表
OSFlagFlags、 OSFlagNodeFlags、 OSFlagNodeWaitType 三者的关系如图
flags 为信号量的初始值(即 OSFlagFlags 的值)
err 为错误信息
返回值为该信号量集的标志组的指针,应用程序根据这个指针对信号量集进行相应的操作
pgrp 为所请求的信号量集指针
flags 为滤波器(即 OSFlagNodeFlags 的值)
wait_type 为逻辑运算类型(即 OSFlagNodeWaitType 的值)
timeout 为等待时限
err 为错误信息
pgrp 为所请求的信号量集指针
flags 为选择所要发送的信号
opt 为信号有效选项
err 为错误信息
STM32上使用UCOSII–任务
有关UCOS信号量和邮箱的介绍:
STM32上使用UCOSII–信号量和邮箱
一、 消息队列
使用消息队列可以在任务之间传递多条消息。消息队列由三个部分组成:事件控制块、消息队列和消息。当把事件控制块成员 OSEventType 的值置为 OS_EVENT_TYPE_Q 时,该事件控制块描述的就是一个消息队列。消息队列的数据结构如图:
消息队列相当于一个共用一个任务等待列表的消息邮箱数组,事件控制块成员OSEventPtr指向了一个叫做队列控制块(OS_Q)的结构,该结构管理了一个数组 MsgTbl[],该数组中的元素都是一些指向消息的指针
队列控制块( OS_Q)的结构定义如下:
typedef struct os_q { struct os_q *OSQPtr; void **OSQStart; void **OSQEnd; void **OSQIn; void **OSQOut; INT16U OSQSize; INT16U OSQEntries; } OS_Q;
参数 | 说明 |
---|---|
OSQPtr | 指向下一个空的队列控制块 |
OSQSize | 数组的长度 |
OSQEntres | 已存放消息指针的元素数目 |
OSQStart | 指向消息指针数组的起始地址 |
OSQEnd | 指向消息指针数组结束单元的下一个单元。它使得数组构成了一个循环的缓冲区 |
OSQIn | 指向插入一条消息的位置。当它移动到与 OSQEnd 相等时,被调整到指向数组的起始单元 |
OSQOut | 指向被取出消息的位置。当它移动到与 OSQEnd 相等时,被调整到指向数组的起始单元 |
消息队列相关函数
1. 创建消息队列函数
OS_EVENT *OSQCreate(void**start,INT16U size);
start 为存放消息缓冲区指针数组的地址
size 为该数组大小
2. 请求消息队列函数
void*OSQPend(OS_EVENT*pevent,INT16U timeout,INT8U *err);
pevent 为所请求的消息队列的指针
timeout 为任务等待时限
err 为错误信息
3. 向消息队列发送消息函数
INT8U OSQPost(OS_EVENT *pevent,void *msg);//先进先出 INT8U OSQPostFront(OS_EVENT *pevent,void*msg); //后进先出
pevent 为消息队列的指针
msg 为待发消息的指针
二、 信号量集
UCOSII 为了实现多个信号量组合的功能定义了一种特殊的数据结构——信号量集不同于信号量、消息邮箱、消息队列等事件, UCOSII 不使用事件控制块来描述信号量集,而使用了一个叫做标志组的结构 OS_FLAG_GRP 来描述。 OS_FLAG_GRP 结构如下:
typedef struct { INT8U OSFlagType; //识别是否为信号量集的标志 void *OSFlagWaitList; //指向等待任务链表的指针 OS_FLAGS OSFlagFlags; //所有信号列表 }OS_FLAG_GRP;
成员 OSFlagWaitList 是一个指针,当一个信号量集被创建后,这个指针指向了这个信号量集的等待任务链表
与其他前面介绍过的事件不同,信号量集用一个双向链表来组织等待任务,每一个等待任务都是该链表中的一个节点( Node)。标志组 OS_FLAG_GRP 的成员 OSFlagWaitList 就指向了信号量集的这个等待任务链表。等待任务链表节点 OS_FLAG_NODE 的结构如下:
typedef struct { void *OSFlagNodeNext; //指向下一个节点的指针 void *OSFlagNodePrev; //指向前一个节点的指针 void *OSFlagNodeTCB; //指向对应任务控制块的指针 void *OSFlagNodeFlagGrp; //反向指向信号量集的指针 OS_FLAGS OSFlagNodeFlags; //信号过滤器 INT8U OSFlagNodeWaitType; //定义逻辑运算关系的数据 } OS_FLAG_NODE;
其中 OSFlagNodeWaitType 是定义逻辑运算关系的一个常数(根据需要设置),其可选值和对应的逻辑关系如表
常数 | 信号有效状态 | 等待任务的就绪条件 |
---|---|---|
WAIT_CLR_ALL 或WAIT_CLR_AND | 0 | 信号全部有效(全 0) |
WAIT_CLR_ANY 或WAIT_CLR_OR | 0 | 信号有一个或一个以上有效(有 0) |
WAIT_SET_ALL 或WAIT_SET_AND | 1 | 信号全部有效(全 1) |
WAIT_SET_ANY 或WAIT_SET_OR | 1 | 信号有一个或一个以上有效(有 1) |
信号量相关函数
1. 创建信号量集函数
OS_FLAG_GRP *OSFlagCreate (OS_FLAGS flags,INT8U *err );
flags 为信号量的初始值(即 OSFlagFlags 的值)
err 为错误信息
返回值为该信号量集的标志组的指针,应用程序根据这个指针对信号量集进行相应的操作
2. 请求信号量集函数
OS_FLAGS OSFlagPend(OS_FLAG_GRP*pgrp, OS_FLAGS flags,INT8U wait_type, INT16U timeout, INT8U *err);
pgrp 为所请求的信号量集指针
flags 为滤波器(即 OSFlagNodeFlags 的值)
wait_type 为逻辑运算类型(即 OSFlagNodeWaitType 的值)
timeout 为等待时限
err 为错误信息
3. 向信号量集发送信号函数
OS_FLAGS OSFlagPost (OS_FLAG_GRP *pgrp, OS_FLAGS flags, INT8U opt, INT8U *err);
pgrp 为所请求的信号量集指针
flags 为选择所要发送的信号
opt 为信号有效选项
err 为错误信息
三、 stm32上使用uucos信号量集
#include "led.h" #include "delay.h" #include "sys.h" #include "includes.h" #include "key.h" #include "oled.h" /////////////////////////UCOSII任务设置/////////////////////////////////// //START 任务 //设置任务优先级 #define START_TASK_PRIO 10 //开始任务的优先级设置为最低 //设置任务堆栈大小 #define START_STK_SIZE 64 //任务堆栈 OS_STK START_TASK_STK[START_STK_SIZE]; //任务函数 void start_task(void *pdata); //信号量处理任务 //设置任务优先级 #define FLAG_TASK_PRIO 5 //设置任务堆栈大小 #define FLAG_STK_SIZE 64 //任务堆栈 OS_STK FLAG_TASK_STK[FLAG_STK_SIZE]; //任务函数 void flag_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); /////////////////////////////////////////////////////////////////////////////////////////////// OS_FLAG_GRP *flags_key;//按键信号量集 int main(void) { delay_init(); //延时函数初始化 NVIC_Configuration(); LED_Init(); //初始化与LED连接的硬件接口 KEY_Init(); OLED_Init(); OSInit(); OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务 OSStart(); } //开始任务 void start_task(void *pdata) { u8 err; OS_CPU_SR cpu_sr=0; pdata = pdata; // msg_key=OSMboxCreate((void *)0);//创建消息邮箱 flags_key=OSFlagCreate(0,&err); //创建信号量集 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(flag_task,(void *)0,(OS_STK*)&FLAG_TASK_STK[FLAG_STK_SIZE-1],FLAG_TASK_PRIO); OSTaskCreate(scan_task,(void *)0,(OS_STK*)&SCAN_TASK_STK[SCAN_STK_SIZE-1],SCAN_TASK_PRIO); OSTaskSuspend(START_TASK_PRIO); //挂起起始任务. OS_EXIT_CRITICAL(); //退出临界区(可以被中断打断) } void flag_task(void *pdata) { int flags=0; u8 err; while(1) { flags=OSFlagPend(flags_key,0X001F,OS_FLAG_WAIT_SET_ANY,0,&err);//等待信号量 OLED_Clear(); if(flags&0X0001) {OLED_ShowString(0,0,"LED0",12);LED0=0;delay_ms(500);LED0=1;delay_ms(500);} if(flags&0X0002) {OLED_ShowString(0,0,"LED1",12);LED1=0;delay_ms(500);LED1=1;delay_ms(500);} if(flags&0X0004) {OLED_ShowString(0,0,"LED0 and LED1",12);LED0=0;LED1=0;delay_ms(500);LED0=1;LED1=1;delay_ms(500);} OLED_Refresh_Gram(); OSFlagPost(flags_key,0X0007,OS_FLAG_CLR,&err);//全部信号量清零 } } //按键扫描任务 void scan_task(void *pdata) { u8 key; u8 err; while(1) { key=KEY_Scan(0); if(key)OSFlagPost(flags_key,1<<(key-1),OS_FLAG_SET,&err);//发送消息 delay_ms(10); } }
相关文章推荐
- boost进程间通信经常使用开发一篇全(消息队列,共享内存,信号)
- boost进程间通信经常使用开发一篇全(消息队列,共享内存,信号)
- Linux定时器处理之实时信号使用,消息队列阻塞模型,避免超时等待
- Posix消息队列使用非阻塞mq_receive的信号通知
- 消息队列(Message Queue)简介及其使用
- ELK之使用消息队列收取日志
- Java使用Rabbitmq惊喜队列queue和消息内容的本地持久化核心方法。(内容存储在硬盘)
- 使用消息队列的理由
- 使用消息队列实现分布式事物---公认较为理想的分布式事物解决方案
- Linux进程间通信——使用消息队列
- 使用消息队列 异步插入数据,能发送消息,但是无法读取消息
- 消息队列(Message Queue)简介及其使用 [转]
- 消息队列的使用
- Linux 下开源消息队列系统 RabbitMQ 安装使用
- 进程间通信的几种方式:管道、信号、消息队列、共享内存
- 使用一个消息队列作为计数信号量
- NoSQL初探之人人都爱Redis:(3)使用Redis作为消息队列服务场景应用案例
- laravel中如何使用消息队列
- 使用PHP访问RabbitMQ消息队列
- 如何使用Jedis操作Redis消息队列