(学习日记)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 compilerwarning 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 的作用

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript代码小挑战

题目如下&#xff1a; 朱莉娅和凯特正在做一项关于狗的研究。于是&#xff0c;她们分别询问了 5 位狗主人他们的狗的年龄&#xff0c;并将数据存储到一个数组中&#xff08;每人一个数组&#xff09;。目前&#xff0c;她们只想知道一只狗是成年狗还是小狗。如果狗的年龄至少为…

动态规划(Dynamic Programming)详解

动态规划&#xff08;Dynamic Programming&#xff09;是一种重要的算法设计方法&#xff0c;适用于解决具有最优子结构和重叠子问题性质的问题。通过将问题分解为子问题&#xff0c;并利用子问题的解来构建原问题的解&#xff0c;动态规划在解决各种优化问题时展现了强大的效果…

工程监测振弦采集仪在振动监测中的应用与数据处理技术

工程监测振弦采集仪在振动监测中的应用与数据处理技术 振弦采集仪是一种用于振动监测和分析的仪器设备。它采用振弦传感器作为振动信号的采集元件&#xff0c;可以实时测量结构物或设备的振动状态&#xff0c;并将采集到的振动数据进行处理和分析&#xff0c;从而判断结构的工…

智慧数字乡村解决方案大全:标准规范顶层设计指南、供应商整体解决方案及售前PPT、数字乡村标准白皮书等全套460份,一次性打包下载

关键词&#xff1a;数字乡村解决方案&#xff0c;数字乡村标准白皮书&#xff0c;数字乡村建设成功案例&#xff0c;数字乡村发展行动计划&#xff0c;数字乡村建设方案&#xff0c;数字乡村云平台&#xff0c;数字乡村建设指南&#xff0c;智慧乡村建设解决方案&#xff0c;智…

线程安全--深入探究线程等待机制和死锁问题

꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱ ʕ̯•͡˔•̯᷅ʔ大家好&#xff0c;我是xiaoxie.希望你看完之后,有不足之处请多多谅解&#xff0c;让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客 本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转…

DasViewer中,像下图山坡是选择拟合平面还是自定义平面?还是其他的基准面?

问题如图 如若山坡是计算斜面的土方&#xff0c;可以选择用拟合平面模式&#xff0c;该模式适用斜坡。 DasViewer是由大势智慧自主研发的免费的实景三维模型浏览器,采用多细节层次模型逐步自适应加载技术,让用户在极低的电脑配置下,也能流畅的加载较大规模实景三维模型,提供方…

Windows XPSDrvSmpl.sln打印驱动项目编译问题汇总

官方参考配置看这里官方独家。如果不想看文档&#xff0c;可以看视频打印编译&#xff0c;安装测试视频不过上面只讲了一般流程&#xff0c;但是随着系统升级&#xff0c;架构变化会出现各种各样的问题。我汇总了一些我遇到的问题&#xff0c;以及解决办法。 error 1297: (NTar…

Mac安装配置Appium

一、安装 nodejs 与 npm 安装方式与 windows 类似 &#xff0c;官网下载对应的 mac 版本的安装包&#xff0c;双击即可安装&#xff0c;无须配置环境变量。官方下载地址&#xff1a;https://nodejs.org/en/download/ 二、安装 appium Appium 分为两个版本&#xff0c;一个是…

【JAVASE】带你了解instanceof和equals的魅力

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 1.instanceof instanceof 是 Java 的保留关键字。它的作用是测试…

2024.4.2-day07-CSS 盒子模型(显示模式、盒子模型)

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 作业 2024.4.2 学习笔记CSS标签元素显示模式1 块元素2 行内元素3 行内块元素4…

怎么用二维码来分享视频?视频二维码制作的简单方法

怎么用二维码来分享视频呢&#xff1f;为了能够更快速的将视频传递给其他人&#xff0c;所以现在很多人都使用生成二维码的方式&#xff0c;让其他人通过扫码来查看视频内容&#xff0c;从而实现多人同时扫码看视频的效果。这种方式也不会占用用户的内存和流量&#xff0c;通过…

“AI复活”背后的数字永生:被期待成为下一个电商,培育市场认知和用户心智还需时间

“AI复活”背后的数字永生&#xff1a;被期待成为下一个电商&#xff0c;培育市场认知和用户心智还需时间© 由 九派新闻 提供 数字永生&#xff0c;还是电子宠物&#xff1f;过去一个月&#xff0c;因包小柏用AI技术让爱女在数字世界“复活”一事&#xff0c;《流浪地球2…