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--消息队列和信号量集 的相关文章

  • c项目makefile多重定义错误

    这个问题是一个对应于创建的repexthis问题 在我的嵌入式 C 项目中 我有两个独立的板 我想为每个板创建两个 c 文件 master c 和 Slave c 其中包含自己的特定main 功能 我使用 stm32cumbemx 生成带有
  • 在没有 IDE 的情况下如何使用 CMSIS?

    我正在使用 STM32F103C8T6 并想使用 CMSIS 这本质上只是寄存器定义 没有代码 让我的生活更轻松 同时仍保持在较低水平 问题是我不知道如何安装该库以便在命令行上使用 Makefile 使用 所有文档似乎都与特定于供应商的 I
  • 如何让printf在STM32F103上工作?

    我是 STM32F103 世界的新手 我有一个STM32F103的演示代码 我正在使用arm none eabi来编译它 我尝试了在谷歌上可以找到的内容 但到目前为止没有任何效果 我已经花了三天时间来解决这个问题 任何人都可以给我一个运行良
  • CMSIS 库是否应该包含在版本控制中? [复制]

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

    我有一个 C 函数 它尝试将帧缓冲区复制到 FSMC RAM 这些函数将游戏循环的帧速率降低至 10FPS 我想知道如何分析反汇编的函数 我应该计算每个指令周期吗 我想知道CPU把时间花在哪里 在哪个部分 我确信该算法也是一个问题 因为它的
  • Push_back() 导致程序在进入 main() 之前停止

    我正在为我的 STM32F3 Discovery 板使用 C 进行开发 并使用 std deque 作为队列 在尝试调试我的代码 直接在带有 ST link 的设备上或在模拟器中 后 代码最终在 main 中输入我的代码之前在断点处停止 然
  • STM32F4 通过软复位跳转到引导加载程序,无需 BOOT0 和 BOOT1 引脚

    我问这个问题是因为可以在这里找到类似问题的答案 通过应用程序跳转到 STM32 中的引导加载程序 即从用户闪存在引导模式下使用引导 0 和引导 1 引脚 用户 JF002 JF002回答 当我想跳转到引导加载程序时 我在其中一个备份寄存器中
  • STM32用一个定时器执行多任务写法

    文章目录 main c include stm32f4xx h uint32 t Power check times 电量检测周期 uint32 t RFID Init Check times RFID检测周期 int main Timer
  • STM32F103

    提示 来源正点原子 参考STM32F103 战舰开发指南V1 3PDF资料 文章目录 前言 一 pandas是什么 二 使用步骤 1 引入库 2 读入数据 总结 前言 提示 这里可以添加本文要记录的大概内容 开发环境硬件普中科技 接线图在g
  • 物联网网关

    物联网网关是 连接物联网设备和互联网的重要桥梁 它负责将物联网设备采集到的数据进行处理 存储和转发 使其能够与云端或其它设备进行通信 物联网网关的作用是实现物联网设备与云端的无缝连接和数据交互 物联网网关功能 数据采集 物联网网关可以从物联
  • [屏驱相关]【SWM166-SPI-Y1.28C1测评】+ 有点惊艳的开箱

    耳闻华芯微特许久了 看到论坛得评测活动赶紧上了末班车 毕竟对有屏幕得板子也是很喜欢得 京东快递小哥客客气气 微笑着把快递给了我 好评 直接拆了包 在此之前没看过视频号 所以这个圆盘盘得模具还是有点惊喜的 正面照如下 开机有灯光秀 还有动画
  • 跟着野火学FreeRTOS:第一段(任务定义,切换以及临界段)

    在裸机系统中 系统的主体就是 C P U CPU CP U 按照预先设定的程序逻辑在 m a i n
  • 1.69寸SPI接口240*280TFT液晶显示模块使用中碰到的问题

    1 69寸SPI接口240 280TFT液晶显示模块使用中碰到的问题说明并记录一下 在网上买了1 69寸液晶显示模块 使用spi接口 分辨率240 280 给的参考程序是GPIO模拟的SPI接口 打算先移植到FreeRtos测试 再慢慢使用
  • STM32H5 Nucleo-144 board开箱

    文章目录 开发板资料下载 目标 点亮LD1 绿 LD2 黄 和LD3 红 三个LED灯 开箱过程 博主使用的是STM32CubeMX配置生成代码 具体操作如下 打开STM32CubeMX File gt New project 选择开发板型
  • 通过JTAG恢复STM32 MCU磨掉的标记

    我有一块可能带有 STM32 MCU 的板 我想为该板制作定制固件 因为库存板有很多问题 不幸的是 电路板制造商很友善地磨掉了所有标记 有没有办法通过 jtag 获取设备 系列 ID 并将其交叉引用到型号 我能找到的一切都是关于获取芯片的唯
  • 嵌入式 C++11 代码 — 我需要 volatile 吗?

    采用 Cortex M3 MCU STM32F1 的嵌入式设备 它具有嵌入式闪存 64K MCU固件可以在运行时重新编程闪存扇区 这是由闪存控制器 FMC 寄存器完成的 所以它不像a b那么简单 FMC 获取缓冲区指针并将数据刻录到某个闪存
  • PWM DMA 到整个 GPIO

    我有一个 STM32F4 我想对一个已与掩码进行 或 运算的 GPIO 端口进行 PWM 处理 所以 也许我们想要 PWM0b00100010一段时间为 200khz 但随后 10khz 后 我们现在想要 PWM0b00010001 然后
  • HAL_Delay() 陷入无限循环

    我被 HAL Delay 函数困住了 当我调用此函数 HAL Delay 时 控制陷入无限循环 在寻找问题的过程中 我发现了这个 http www openstm32 org forumthread2145 threadId2146 htt
  • 使用 STM32 USB 设备库将闪存作为大容量存储设备

    我的板上有这个闪存IC 它连接到我的STM32F04 ARM处理器 处理器的USB端口可供用户使用 我希望我的闪存在通过 USB 连接到 PC 时被检测为存储设备 作为第一步 我在程序中将 USB 类定义为 MSC 效果很好 因为当我将主板
  • stm32l0: 执行MI命令失败。使用 vFlashErase 数据包擦除闪存时出错

    我正在使用 Nucleo STM32L031 和 AC6 STM32 工作台 eclipse 我编写应用程序并进入调试模式 一切正常 直到我在应用程序中添加另一个功能 我注意到当我删除 评论 新函数 软件可以再次进入调试模式 但是当我添加

随机推荐