(学习日记)2024.04.01:UCOSIII第二十九节:消息队列实验(待续)

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


点击此处进入学习日记的总目录

2024.04.01:UCOSIII第二十八节:消息队列实验

  • 四十三、UCOSIII:消息队列实验
    • 1、消息队列使用注意事项
    • 2、消息队列实验
    • 3、消息队列实验现象
    • 4、常见错误
      • 1. Default Compiler Version 5
      • 2. core_cm3.h(1213): error: unknown type name 'inline'
      • 3. 程序正常运行无报错,烧录到板子上无反应

四十三、UCOSIII:消息队列实验

1、消息队列使用注意事项

在使用μC/OS提供的消息队列函数的时候,需要了解以下几点:

  1. 使用OSQPend()、OSQPost()等这些函数之前应先创建需消息队列, 并根据队列句柄(队列控制块)进行操作。

  2. 队列读取采用的是先进先出(FIFO)模式,会先读取先存储在队列中的数据。 当然也μC/OS也支持后进先出(LIFO)模式,那么读取的时候就会读取到后进队列的数据。

  3. 无论是发送或者是接收消息都是以 数据引用的方式进行。

  4. 队列是具有自己独立权限的内核对象,并不属于任何任务。所有任务都可以向同一队列写入和读出。 一个队列由多任务或中断写入是经常的事,但由多个任务读出倒是用的比较少。

  5. 消息的传递实际上只是传递传送内容的指针和传送内容的字节大小。这在使用消息队列的时候就要注意了, 获取消息之前不能释放存储在消息中的指针内容,比如中断定义了一个局部变量,然后将其地址放在消息中进行传递, 中断退出之前消息并没有被其他任务获取,退出中断的时候 CPU已经释放了中断中的这个局部变量,后面任务获取这个地址的内容就会出错。 所以一定要保证在获取内容地址之前不能释放内容这个内存单元。有三种方式可以避免这种情况:

  • 将变量定义为静态变量,即在其前面加上 static,这样内存单元就不会被释放。
  • 将变量定义为全局变量。
  • 将要传递的内容当做指针传递过去。比如地址 0x12345678存放一个变量的值为 5, 常规是把0x12345678这个地址传递给接收消息的任务, 任务接收到这个消息后,取出这个地址的内容 5。
    但是如果我们把 5 当做“地址”传递给任务, 最后接收消息的任务直接拿着这个“地址”当做内容去处理即可。不过这种方法不能传递结构体等比较复杂的数据结构, 因为消息中存放地址的变量内存大小是有限的(一个指针大小)。

2、消息队列实验

消息队列实验是在μC/OS中创建了两个任务AppTaskPost()和 AppTaskPend()。

  • 任务 AppTaskPost() 用于发送消息。
  • 任务 AppTaskPend()用于接收消息。

两个任务独立运行,并把接收到的消息通过串口调试助手打印出来。

#include <includes.h>

/**************************************************************************
                                    LOCAL DEFINES
**************************************************************************/
OS_Q queue;                             //声明消息队列

/**************************************************************************
                                        TCB
************************************************************************/

static  OS_TCB   AppTaskStartTCB;      //任务控制块
static  OS_TCB   AppTaskPostTCB;
static  OS_TCB   AppTaskPendTCB;

/*************************************************************************
                                         STACKS
************************************************************************/

static  CPU_STK  AppTaskStartStk[APP_TASK_START_STK_SIZE];       //任务栈
static  CPU_STK  AppTaskPostStk [ APP_TASK_POST_STK_SIZE ];
static  CPU_STK  AppTaskPendStk [ APP_TASK_PEND_STK_SIZE ];

/*************************************************************************
                                  FUNCTION PROTOTYPES
*************************************************************************/

static  void  AppTaskStart  (void *p_arg);               //任务函数声明
static  void  AppTaskPost   ( void * p_arg );
static  void  AppTaskPend   ( void * p_arg );

/*
***********************************************************************
*                                                main()
*
* Description : This is the standard entry point for C code.  It is assumed that
*    your code will call main() once you have performed all necessary
*   initialization.
* Arguments   : none
*
* Returns     : none
**************************************************************************/

int  main (void)
{
    OS_ERR  err;
    OSInit(&err);                                     //初始化 μC/OS-III

    /* 创建起始任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskStartTCB,       //任务控制块地址
                (CPU_CHAR   *)"App Task Start",             //任务名称
                (OS_TASK_PTR ) AppTaskStart,                  //任务函数
                (void       *) 0,
                //传递给任务函数(形参p_arg)的实参
                (OS_PRIO     ) APP_TASK_START_PRIO,         //任务的优先级
                (CPU_STK    *)&AppTaskStartStk[0],
                //任务栈的基地址
                (CPU_STK_SIZE) APP_TASK_START_STK_SIZE / 10,
                //任务栈空间剩下1/10时限制其增长
                (CPU_STK_SIZE) APP_TASK_START_STK_SIZE,
                //任务栈空间(单位:sizeof(CPU_STK))
                (OS_MSG_QTY  ) 5u,
                //任务可接收的最大消息数
                (OS_TICK     ) 0u,
                //任务的时间片节拍数(0表默认值OSCfg_TickRate_Hz/10)
                (void       *) 0,
                //任务扩展(0表不扩展)
                (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                (OS_ERR     *)&err);  //返回错误类型

    OSStart(&err);
    //启动多任务管理(交由μC/OS-III控制)

}


/*************************************************************************
*                         STARTUP TASK
*
* Description : This is an example of a startup task.  As mentioned in
* the book's text, you MUST initialize the ticker only once mu
*           ltitasking has started.
* Arguments   : p_arg   is the argument passed to 'AppTaskStart()' by
*           'OSTaskCreate()'.
* Returns     : none
*
* Notes       : 1) The first line of code is used to prevent a compiler
        warning because 'p_arg' is not
*                  used.  The compiler should not generate any code for
this statement.
***********************************************************
*/

static  void  AppTaskStart (void *p_arg)
{
    CPU_INT32U  cpu_clk_freq;
    CPU_INT32U  cnts;
    OS_ERR      err;


    (void)p_arg;

    BSP_Init();                                    //板级初始化
    CPU_Init();
    //初始化 CPU组件(时间戳、关中断时间测量和主机名)

    cpu_clk_freq = BSP_CPU_ClkFreq();
    //获取 CPU内核时钟频率(SysTick 工作时钟)
    cnts = cpu_clk_freq / (CPU_INT32U)OSCfg_TickRate_Hz;
    //根据用户设定的时钟节拍频率计算 SysTick 定时器的计数值
    OS_CPU_SysTickInit(cnts);
    //调用 SysTick初始化函数,设置定时器计数值和启动定时器

    Mem_Init();
    //初始化内存管理组件(堆内存池和内存池表)

#if OS_CFG_STAT_TASK_EN > 0u
    //如果启用(默认启用)了统计任务
    OSStatTaskCPUUsageInit(&err);
    //计算没有应用任务(只有空闲任务)运行时 CPU的(最大)

#endif//容量(决定 OS_Stat_IdleCtrMax的值,为后面计算 CPU使用率使用)。
    CPU_IntDisMeasMaxCurReset();
    //复位(清零)当前最大关中断时间


    /* 创建消息队列 queue */
    OSQCreate ((OS_Q         *)&queue,            //指向消息队列的指针
                (CPU_CHAR     *)"Queue For Test",  //队列的名字
                (OS_MSG_QTY    )20,                //最多可存放消息的数目
                (OS_ERR       *)&err);             //返回错误类型


    /* 创建 AppTaskPost 任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskPostTCB,           //任务控制块地址
                (CPU_CHAR   *)"App Task Post",           //任务名称
                (OS_TASK_PTR ) AppTaskPost,             //任务函数
                (void       *) 0,
                //传递给任务函数(形参p_arg)的实参
                (OS_PRIO     ) APP_TASK_POST_PRIO,  //任务的优先级
                (CPU_STK    *)&AppTaskPostStk[0],
                //任务栈的基地址
                (CPU_STK_SIZE) APP_TASK_POST_STK_SIZE / 10,
                //任务栈空间剩下1/10时限制其增长
                (CPU_STK_SIZE) APP_TASK_POST_STK_SIZE,
                //任务栈空间(单位:sizeof(CPU_STK))
                (OS_MSG_QTY  ) 5u,
                //任务可接收的最大消息数
                (OS_TICK     ) 0u,
                //任务的时间片节拍数(0表默认值OSCfg_TickRate_Hz/10)
                (void       *) 0,
                //任务扩展(0表不扩展)
                (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                (OS_ERR     *)&err);                   //返回错误类型

    /* 创建 AppTaskPend 任务 */
    OSTaskCreate((OS_TCB     *)&AppTaskPendTCB,           //任务控制块地址
                (CPU_CHAR   *)"App Task Pend",               //任务名称
                (OS_TASK_PTR ) AppTaskPend,                //任务函数
                (void       *) 0,
                //传递给任务函数(形参p_arg)的实参
                (OS_PRIO     ) APP_TASK_PEND_PRIO,//任务的优先级
                (CPU_STK    *)&AppTaskPendStk[0],
                //任务栈的基地址
                (CPU_STK_SIZE) APP_TASK_PEND_STK_SIZE / 10,
                //任务栈空间剩下1/10时限制其增长
                (CPU_STK_SIZE) APP_TASK_PEND_STK_SIZE,
                //任务栈空间(单位:sizeof(CPU_STK))
                (OS_MSG_QTY  ) 5u,
                //任务可接收的最大消息数
                (OS_TICK     ) 0u,
                //任务的时间片节拍数(0表默认值OSCfg_TickRate_Hz/10)
                (void       *) 0,
                //任务扩展(0表不扩展)
                (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                (OS_ERR     *)&err);                     //返回错误类型

    OSTaskDel ( & AppTaskStartTCB, & err );
    //删除起始任务本身,该任务不再运行


}


/************************************************************************
                                     POST TASK
***********************************************************************/
static  void  AppTaskPost ( void * p_arg )
{
    OS_ERR      err;
    (void)p_arg;

    while (DEF_TRUE)                            //任务体
    {
        /* 发布消息到消息队列 queue */
        OSQPost ((OS_Q        *)&queue,          //消息变量指针
                (void        *)"Fire μC/OS-III",
                //要发送的数据的指针,将内存块首地址通过队列“发送出去”
                (OS_MSG_SIZE  )sizeof ( "Fire μC/OS-III" ),//数据字节大小
                (OS_OPT       )OS_OPT_POST_FIFO | OS_OPT_POST_ALL,
                //先进先出和发布给全部任务的形式
                (OS_ERR      *)&err);               //返回错误类型

        OSTimeDlyHMSM ( 0, 0, 0, 500, OS_OPT_TIME_DLY, & err );
    }
}


/*************************************************************************
                                     PEND TASK
*************************************************************************/
static  void  AppTaskPend ( void * p_arg )
{
    OS_ERR      err;
    OS_MSG_SIZE msg_size;
    CPU_SR_ALLOC(); //使用到临界段(在关/开中断时)时必须用到该宏,该宏声明和
    //定义一个局部变量,用于保存关中断前的 CPU 状态寄存器
    // SR(临界段关中断只需保存SR),开中断时将该值还原。
    char * pMsg;
    (void)p_arg;

    while (DEF_TRUE)                                         //任务体
    {
        /* 请求消息队列 queue 的消息 */
        pMsg = OSQPend ((OS_Q         *)&queue,          //消息变量指针
                        (OS_TICK       )0,               //等待时长为无限
                        (OS_OPT        )OS_OPT_PEND_BLOCKING,
                        //如果没有获取到信号量就等待
                        (OS_MSG_SIZE  *)&msg_size,     //获取消息的字节大小
                        (CPU_TS       *)0,         //获取任务发送时的时间戳
                        (OS_ERR       *)&err);         //返回错误

        if ( err == OS_ERR_NONE )                       //如果接收成功
        {
            OS_CRITICAL_ENTER();                      //进入临界段
            printf ( "\r\n接收消息的长度:%d字节,内容:%s\r\n", msg_size, pMsg );
            OS_CRITICAL_EXIT();
        }
    }
}

3、消息队列实验现象

将程序编译好,用USB线连接计算机和开发板的USB接口(对应丝印为USB转串口), 用DAP仿真器把配套程序下载到野火STM32开发板。
在计算机上打开串口调试助手,然后复位开发板就可以在调试助手中看到串口的打印信息,具体如下
在这里插入图片描述

4、常见错误

1. Default Compiler Version 5

*** Target 'Fire_uCOS' uses ARM-Compiler 'Default Compiler Version 5' which is not available.

此错误是ARM编译器缺失导致的,解决办法是换成已安装的编译器
在这里插入图片描述

2. core_cm3.h(1213): error: unknown type name ‘inline’

错误是找不到 inline变量或函数,这个inline是在core_cm3.h里第1213行用到的
解决办法是把包含 inline的文件加入到工程里

inline可以是别的值,core_cm3.h也可以是别的文件
这些都是可以更改的

3. 程序正常运行无报错,烧录到板子上无反应

可能是库的问题,试试改成Micro Lib
在这里插入图片描述

Micro Lib是一个针对用C编写的基于ARM的嵌入式应用程序的高度优化的库。
与包含在ARM编译器工具链中的标准C库相比,MicroLib提供了许多嵌入式系统所需的代码大小的显著优势。

下图对使用标准库和使用微库代码大小进行了对比
在这里插入图片描述

MicroLib和标准C库之间的主要区别是:

1、MicroLib是专为深度嵌入式应用程序而设计的。

2、MicroLib经过优化,比使用ARM标准库使用更少的代码和数据内存。

3、MicroLib被设计成在没有操作系统的情况下工作,但是这并不妨碍它与任何操作系统或RTOS一起使用,如Keil RTX。

4、MicroLib不包含文件I/O或宽字符支持。

5、由于MicroLib已经优化到最小化代码大小,一些函数将比ARM编译工具中可用的标准C库例程执行得更慢。

6、MicroLib和ARM标准库都包含在Keil MDK-ARM中。

参考链接:keil勾选Use MicroLIB 的作用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/520631.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

独角数卡对接码支付收款教程

1、到码支付后台找到支付配置。2、将上面的复制依次填入&#xff0c;具体看下图&#xff0c;随后点立即添加 商户ID商户PID 商户KEY异步不能为空 商户密钥商户密钥

jenkins_Pipeline使用测试

jenkins—Pipeline使用测试 安装jenkins # jar包启动 https://sg.mirror.servanamanaged.com/jenkins/war-stable/2.346.1/jenkins.war https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz [rootvm ~]# tail /etc/profile ... export JAVA_HOME/opt…

51单片机入门:LED点阵屏

LED点阵屏介绍 LED点阵屏由若干个独立的LED组成&#xff0c;LED以矩阵的形式排列&#xff0c;以灯珠亮灭来显示文字、图片、视频等。LED点阵屏广泛应用于各种场合&#xff0c;如&#xff1a;广告屏、公告牌等。 分类&#xff1a; 按颜色&#xff1a;单色、双色、全彩&#x…

GPT4解除限制使用次数了!GPT5预计要推出了!

今天登录GPT Plus的时候&#xff0c;出现了如下提示&#xff1a; With DALLE,browing and analysis Usage limits may apply GPT4已经没有了数量和时间限制的提示。 更改前&#xff1a;每 3 小时限制 40 次&#xff08;团队计划为 100 次&#xff09;&#xff1b;更改后&#…

尚硅谷html5+css3(1)

1.基本标签&#xff1a; <h1>最大的标题字号 <h2>二号标题字号 <p>换行 2.根标签<html> 包括<head>和<body> <html><head><title>title</title><body>body</body></head> </html> 3…

C语言-预定义符号

编译和链接&#xff08;基础速通版&#xff09;-CSDN博客https://blog.csdn.net/Jason_from_China/article/details/137182220 预定义符号 包含 C语⾔设置了⼀些预定义符号&#xff0c;可以直接使⽤&#xff0c;预定义符号也是在预处理期间处理的。 __FILE__ //进⾏编译的…

二叉树中所有距离为k的节点

题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 从目标节点的左孩子&#xff0c;右孩子&#xff0c;父亲节点出发去找&#xff0c;左孩子 右孩子 做法简单 &#xff0c; 主要是父亲节点 &#xff0c;因此我们需要知道每个节点的父亲节点&am…

我的C++奇迹之旅:内联函数和auto关键推导和指针空值

文章目录 &#x1f4dd;内联函数&#x1f320; 查看内联函数inline方式&#x1f309;内联函数特性&#x1f309;面试题 &#x1f320;auto关键字(C11)&#x1f320; auto的使用细则&#x1f309;auto不能推导的场景 &#x1f320;基于范围的for循环(C11)&#x1f320;范围for的…

测距神器——无影无踪的超声波!

原文来自微信公众号&#xff1a;工程师看海&#xff0c;与我联系&#xff1a;chunhou0820 看海原创视频教程&#xff1a;《运放秘籍》 大家好&#xff0c;我是工程师看海&#xff0c;原创文章欢迎点赞分享&#xff01; 1880年居里兄弟发现&#xff0c;在石英晶体的特定方向上施…

AI Agent在芯片设计领域的未来应用

文章目录 (一)首先是“AI Agent”的Agent怎么理解(二)其次是“AI Agent”的AI怎么理解1) 联邦学习/密文计算/密码学算法/MPC2) sklearn 库所有算法的MPC化实现密文计算安全改造和性能优化3 )NLP Bert 推荐召回(三)最后,“AI Agent”+芯片设计,怎么理解认识一个新概念…

解压缩软件哪个好用 Mac免费解压软件哪个好 解压软件推荐 beeterzip免费下载

解压缩软件在Mac办公中是必不可少的&#xff0c;不仅能够节省时间和内存&#xff0c;更能提升传输效率。虽然Mac自带的解压缩软件归档实用工具可以对zip文件进行解压&#xff0c;但是对于他格式文件就无能为力了。 因此&#xff0c;想要满足多类型文件解压缩需求&#xff0c;可…

基于vue+node.js导师选择分配管理系统

开发语言 node.js 框架&#xff1a;Express 前端:Vue.js 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发软件&#xff1a;VScode .设计一套导师选择管理系统&#xff0c;帮助学校进行导师选择管理等繁琐又重复的工作&#xff0c;提高工作效率的同时&#xff0c…

多线程-相关概念

程序、进程与线程 程序&#xff08;program&#xff09;&#xff1a;为完成特定任务&#xff0c;用某种语言编写的一组指令的集合。即指一段静态的代码&#xff0c;静态对象。 进程&#xff08;process&#xff09;&#xff1a;程序的一次执行过程&#xff0c;或是正在内存中运…

linux文件权限与数字转化

chmod命令——change mode&#xff0c;可以对特定文件文件夹权限进行更改 这里我们看到&#xff0c;当执行了chmod u-x try.sh后&#xff0c;try文件底色变为白色&#xff0c;即为其执行权限被“减去” 在linux系统中&#xff0c;权限的减去是通过权限的数字表示来实现的&#…

【可靠性】陷阱电荷对TDDB影响的多尺度模拟

【From Accelerated to Operating Conditions: How Trapped Charge Impacts on TDDB in SiO2 and HfO2 Stacks】 文章总结&#xff1a; 本研究深入探讨了在SiO2和HfO2介质堆叠中&#xff0c;陷阱电荷对时间依赖介电击穿&#xff08;TDDB&#xff09;现象的影响。通过引入载流子…

【MySQL的详细使用教程】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

Redis高可用和持久化

一、Redis高可用 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务&#xff08;99.9%、99.99%、99.999%等等&#xff09;。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&#xff0c;除了保证提…

Pytorch转onnx

pytorch 转 onnx 模型需要函数 torch.onnx.export。 def export(model: Union[torch.nn.Module, torch.jit.ScriptModule, torch.jit.ScriptFunction],args: Union[Tuple[Any, ...], torch.Tensor],f: Union[str, io.BytesIO],export_params: bool True,verbose: bool False…

《QT实用小工具·十六》IP地址输入框控件

1、概述 源码放在文章末尾 该项目为IP地址输入框控件&#xff0c;主要包含如下功能&#xff1a; 可设置IP地址&#xff0c;自动填入框。 可清空IP地址。 支持按下小圆点自动切换。 支持退格键自动切换。 支持IP地址过滤。 可设置背景色、边框颜色、边框圆角角度。 下面…

网址打包微信小程序源码 wap转微信小程序 网站转小程序源码 网址转小程序开发

内容目录 一、详细介绍二、效果展示2.效果图展示 三、学习资料下载 一、详细介绍 我们都知道微信小程序是无法直接打开网址的。 这个小程序源码提供了一种将网址直接打包成微信小程序的方法&#xff0c; 使得用户可以在微信小程序中直接访问这些网址内容。 这个源码没有进行加…