STM32上使用UCOSII--消息队列和信号量集

2023-05-16

有关UCOS任务的介绍:
STM32上使用UCOSII–任务
有关UCOS信号量和邮箱的介绍:
STM32上使用UCOSII–信号量和邮箱

一、 消息队列

使用消息队列可以在任务之间传递多条消息。消息队列由三个部分组成:事件控制块、消息队列和消息。当把事件控制块成员 OSEventType 的值置为 OS_EVENT_TYPE_Q 时,该事件控制块描述的就是一个消息队列。

消息队列的数据结构如图:

duilie

消息队列相当于一个共用一个任务等待列表的消息邮箱数组,事件控制块成员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 相等时,被调整到指向数组的起始单元

其中,可以移动的指针为 OSQIn 和 OSQOut,而指针 OSQStart 和 OSQEnd 只是一个标志(常指针)。当可移动的指针 OSQIn 或 OSQOut 移动到数组末尾,也就是与OSQEnd相等时,可移动的指针将会被调整到数组的起始位置OSQStart。也就是说,从效果上来看,指针 OSQEnd与 OSQStart 等值。于是,这个由消息指针构成的数组就头尾衔接起来形成了一个循环的队列

消息队列相关函数

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_AND0信号全部有效(全 0)
WAIT_CLR_ANY 或WAIT_CLR_OR0信号有一个或一个以上有效(有 0)
WAIT_SET_ALL 或WAIT_SET_AND1信号全部有效(全 1)
WAIT_SET_ANY 或WAIT_SET_OR1信号有一个或一个以上有效(有 1)

OSFlagFlags、 OSFlagNodeFlags、 OSFlagNodeWaitType 三者的关系如图
duilie

信号量相关函数

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);
    }
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32上使用UCOSII--消息队列和信号量集 的相关文章

  • 初始化 ST-Link 设备时出错 - 无法连接到设备

    我目前正在使用 ST Link 调试器对我的 STM32F3 Discovery 板进行编程 我使用的IDE是Atollic TrueStudio 5 5 2 现在我面临一个非常奇怪的问题 那就是我不断收到消息 初始化 ST Link 设备
  • STM32 F072上的软件如何跳转到bootloader(DFU模式)?

    STM32应用笔记2606对此进行了讨论 但没有简单的代码示例 该答案已使用 IAR EWARM 在 STM32F072 Nucleo 板上进行了测试 这个答案使用 STM32标准外设库 仅此而已 请注意 验证您是否成功进入引导加载程序模式
  • CMSIS 库是否应该包含在版本控制中? [复制]

    这个问题在这里已经有答案了 通常 我曾经在版本控制中包含芯片供应商 ST 提供的设备特定标头和源以及 CMSIS Core 标头 数量不多 也没有更新的习惯 我使用STM32微控制器 但我不使用立方体框架 or the 标准外设库 最近 我
  • rt-thread studio中新建5.02版本报错

    先吐槽一下 rt thread studio出现BUG真多 好多时间都是在找BUG 但里面用好多控件还是挺好用的 真是又爱又恨 所以一般使用功能不多的话还是用keil多一点 创建5 02版本工程之后直接进行编译 直接会报下面这个错误 资源
  • STM32F4 通过软复位跳转到引导加载程序,无需 BOOT0 和 BOOT1 引脚

    我问这个问题是因为可以在这里找到类似问题的答案 通过应用程序跳转到 STM32 中的引导加载程序 即从用户闪存在引导模式下使用引导 0 和引导 1 引脚 用户 JF002 JF002回答 当我想跳转到引导加载程序时 我在其中一个备份寄存器中
  • 硬件基础-电容

    电容 本质 电容两端电压不能激变 所以可以起到稳定电压作用 充放电 电容量的大小 想使电容容量大 使用介电常数高的介质 增大极板间的面积 减小极板间的距离 品牌 国外 村田 muRata 松下 PANASONIC 三星 SAMSUNG 太诱
  • 跟着野火学FreeRTOS:第一段(任务定义,切换以及临界段)

    在裸机系统中 系统的主体就是 C P U CPU CP U 按照预先设定的程序逻辑在 m a i n
  • 串口通讯第一次发送数据多了一字节

    先初始化IO再初始化串口 导致第一次发送时 多出一个字节数据 优化方案 先初始化串口再初始化IO 即可正常通讯
  • STM32F207 I2C 测试失败

    我正在使用 STM32F207 微控制器在 STM3220G EVAL 板上学习嵌入式开发 我尝试通过连接同一芯片上的两个 I2C2 和 I2C3 模块并发送 接收字符来测试 I2C 接口 这是我当前编写的代码 使用 mdk arm 5 i
  • 无法使用 OpenOCD 找到脚本文件

    我正在尝试按照本教程将 OpenOCD 与我的 ST 发现板一起使用 https japaric github io discovery README html https japaric github io discovery READM
  • STM32F4XX的12位ADC采集数值超过4096&右对齐模式设置失败

    文章目录 一 前言 二 问题1 数值超过4096 三 问题1的排错过程 四 问题2 右对齐模式设置失败 五 问题2的解决方法 5 1 将ADC ExternalTrigConv设置为0 5 2 使用ADC StructInit 函数 一 前
  • 嵌入式开发--STM32G4系列片上FLASH的读写

    这个玩意吧 说起来很简单 就是几行代码的事 但楞是折腾了我大半天时间才搞定 原因后面说 先看代码吧 读操作 读操作很简单 以32位方式读取的时候是这样的 data IO uint32 t 0x0800F000 需要注意的是 当以32位方式读
  • 库函数点亮Led

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 提示 这里可以添加本文要记录的大概内容 例如 随着人工智能的不断发展 机器学习这门
  • STM32H5 Nucleo-144 board开箱

    文章目录 开发板资料下载 目标 点亮LD1 绿 LD2 黄 和LD3 红 三个LED灯 开箱过程 博主使用的是STM32CubeMX配置生成代码 具体操作如下 打开STM32CubeMX File gt New project 选择开发板型
  • 特殊寄存器

    特殊寄存器 文章目录 前言 一 背景 二 2 1 2 2 总结 前言 前期疑问 STM32特殊寄存器到底是什么 特殊寄存器怎么查看和调试代码 本文目标 记录和理解特殊寄存器 一 背景 最近在看ucosIII文章是 里面提到特殊寄存器 这就进
  • STM32 上的位置无关代码 - 指针

    我已成功在 STM32 上构建并运行位置无关的代码 向量表和 GOT 已修补 一切正常 但我对这样的代码有问题 double myAdd double x return x 0 1 double ptrmyAdd double myAdd
  • PWM DMA 到整个 GPIO

    我有一个 STM32F4 我想对一个已与掩码进行 或 运算的 GPIO 端口进行 PWM 处理 所以 也许我们想要 PWM0b00100010一段时间为 200khz 但随后 10khz 后 我们现在想要 PWM0b00010001 然后
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d
  • STM32 传输结束时,循环 DMA 外设到存储器的行为如何?

    我想问一下 在以下情况下 STM32 中的 DMA SPI rx 会如何表现 我有一个指定的 例如 96 字节数组 名为 A 用于存储从 SPI 接收到的数据 我打开循环 SPI DMA 它对每个字节进行操作 配置为 96 字节 是否有可能
  • GCC 变量映射和 MISRA-C

    我主要知道两种使用 GCC 声明内存映射寄存器的方法 有许多变体 使用双字段 每个外设的数据结构等 要么使用初始化为正确地址的指针 例如volatile uint32 t pMyRegister uint32 t 0xDEADBEEFUL

随机推荐