STM32F4X UCOSIII 消息队列

2023-09-20 17:35:26

消息队列

消息队列的作用

消息队列是一种常用于任务间通信的数据结构,用户可以自定义传输的消息结构。消息队列可以在任务与任务之间,中断与任务之间进行传输。。消息发送方需要把发送消息的数据指针传递给消息队列,接收方就通过消息队列获取数据。

消息队列工作机制

下图画出了消息队列的工作机制
在这里插入图片描述

消息队列创建

消息队列在创建时,需要用户自定义消息队列可存放的数据个数,当消息队列创建成功时,消息队列的数据存放个数就不能改变。

消息发送

中断和任务都可以往消息队列里面发送消息,在消息发送之前,消息列队会先判断当前的消息队列列表里面是否已经满,当消息队列还没满的时候,会把要发送的数据放到消息队列的消息列表中,如果当前消息队列的列表已经满,则会返回一个错误代码,同时入队失败。

消息发送模式

UCOSIII的消息队列有两种入队模式,分别是FIFO(先进先出)模式和LIFO(后进先出)模式

FIFO(先进先出)

在这里插入图片描述

  • 1:定义了4个数据的队列,此时队列为空,队列指针指向队列底部
  • 2:插入数据A,队列指针向上加1
  • 3:插入数据B,队列指针向上加1
  • 4:插入数据C,队列指针向上加1
  • 5:插入数据D,此时队列已经满,不能再插入新数据
  • 6:数据D出队,队列指针向下减1
  • 7:数据C出队,队列指针向下减1
  • 8:数据B出队,队列指针向下减1
  • 9:数据A出队,此时队列为空
    从上图可以知道,FIFO的数据特点就是先进来的数据先出去,后进来的数据后出去。

LIFO(后进先出)

在这里插入图片描述

  • 1:定义了4个数据的队列,此时队列为空,队列指针指向队列顶部
  • 2:插入数据A,队列指针向下减1
  • 3:插入数据B,队列指针向下减1
  • 4:插入数据C,队列指针向下减1
  • 5:插入数据D,此时队列已经满,不能再插入新数据
  • 6:数据D出队,队列指针向上加1
  • 7:数据C出队,队列指针向上加1
  • 8:数据B出队,队列指针向上加1
  • 9:数据A出队,此时队列为空
  • 从上图可以知道,LIFO的数据特点跟FIFO正好相反,LIFO是先进来的数据最后出去,后进来的数据最先出去。

消息接收

UCOSIII的消息接收也有两种模式,分别阻塞接收和超时接收模式

  • 阻塞接收模式:当消息队列中没有数据的时候,接收数据的任务进入阻塞状态,除非消息队列中有消息,否则阻塞的任务不会退出。
  • 超时接收:接收数据的任务可以设置超时时间,当消息队列中没有数据的时候,接收数据的任务进入阻塞状态,如果阻塞时间超过了设置的超时时间,阻塞的任务会主动退出,并返回一个接收错误的标志位。

消息队列删除

当消息队列不再使用时,可以调用消息队列删除函数,删除消息队列,此时消息队列中的所有数据都会删除,删除后的消息队列不能再次使用。
消息队列删除也有两种方式,分别是立刻删除和等待没有任务挂起删除

  • 立刻删除:不管有没有任务在等待消息队列,都立刻删除
  • 等待没有任务挂起删除:如果有任务在等待消息队列数据,暂时不删除消息队列,直到没有任务等待再删除

消息队列常用函数

消息队列创建函数

/*
p_q:消息队列指针
p_name:消息队列名字
max_qty:接收的最大消息个数
p_err:错误代码
*/
void  OSQCreate (OS_Q        *p_q,
                 CPU_CHAR    *p_name,
                 OS_MSG_QTY   max_qty,
                 OS_ERR      *p_err)

消息队列发送函数

/*
p_q:消息队列指针
p_void:发送的消息的指针
msg_size:发送的消息的大小
opt:用户选项
p_err:错误代码
*/
void  OSQPost (OS_Q         *p_q,
               void         *p_void,
               OS_MSG_SIZE   msg_size,
               OS_OPT        opt,
               OS_ERR       *p_err)

消息队列接收函数

/*
p_q:消息队列指针
timeout:超时时间
opt:用户选项
p_msg_size:接收到的消息的大小
p_ts:时间戳
p_err:错误代码

返回值:成功则返回获取到的消息指针,错误则返回0
*/
void  *OSQPend (OS_Q         *p_q,
                OS_TICK       timeout,
                OS_OPT        opt,
                OS_MSG_SIZE  *p_msg_size,
                CPU_TS       *p_ts,
                OS_ERR       *p_err)

消息队列删除函数

/*
p_q:消息队列指针
opt:用户选项
p_err:错误代码
*/
OS_OBJ_QTY  OSQDel (OS_Q    *p_q,
                    OS_OPT   opt,
                    OS_ERR  *p_err)

UCOSIII 消息队列例程

在例程中,任务1会每个500ms发送一次消息,任务2则会阻塞等待消息

/*
*********************************************************************************************************
*                                              EXAMPLE CODE
*
*                             (c) Copyright 2013; Micrium, Inc.; Weston, FL
*
*                   All rights reserved.  Protected by international copyright laws.
*                   Knowledge of the source code may not be used to write a similar
*                   product.  This file may only be used in accordance with a license
*                   and should not be redistributed in any way.
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*
*                                            EXAMPLE CODE
*
*                                       IAR Development Kits
*                                              on the
*
*                                    STM32F429II-SK KICKSTART KIT
*
* Filename      : app.c
* Version       : V1.00
* Programmer(s) : YS
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                             INCLUDE FILES
*********************************************************************************************************
*/

#include  <includes.h>

/*
*********************************************************************************************************
*                                            LOCAL DEFINES
*********************************************************************************************************
*/


/*
*********************************************************************************************************
*                                       LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/

                                                                /* ----------------- APPLICATION GLOBALS -------------- */
static  OS_TCB   AppTaskStartTCB;
static  CPU_STK  AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE];

#define APPTASK1NAME    "App Task1"
#define APP_TASK1_PRIO          3   
#define APP_TASK1_STK_SIZE 1024
static OS_TCB AppTask1TCB;
static void  AppTask1  (void *p_arg);
static CPU_STK AppTask1Stk[APP_TASK1_STK_SIZE];

#define APPTASK2NAME    "App Task2"
#define APP_TASK2_PRIO          4   
#define APP_TASK2_STK_SIZE 1024
static OS_TCB AppTask2TCB;
static void  AppTask2  (void *p_arg);
static CPU_STK AppTask2Stk[APP_TASK2_STK_SIZE];


static OS_Q  queue;

struct msg
{
	char msg_string[50];
	int value;
};

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

static  void  AppTaskStart          (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);                                               /* Init uC/OS-III.                                      */
   
    OSTaskCreate((OS_TCB       *)&AppTaskStartTCB,              /* Create the start task                                */
                 (CPU_CHAR     *)"App Task Start",
                 (OS_TASK_PTR   )AppTaskStart,
                 (void         *)0u,
                 (OS_PRIO       )APP_CFG_TASK_START_PRIO,
                 (CPU_STK      *)&AppTaskStartStk[0u],
                 (CPU_STK_SIZE  )AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE / 10u],
                 (CPU_STK_SIZE  )APP_CFG_TASK_START_STK_SIZE,
                 (OS_MSG_QTY    )0u,
                 (OS_TICK       )0u,
                 (void         *)0u,
                 (OS_OPT        )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
                 (OS_ERR       *)&err);

    OSStart(&err);                                              /* Start multitasking (i.e. give control to uC/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 multitasking 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();                                                 /* Initialize the uC/CPU services                       */

    cpu_clk_freq = BSP_CPU_ClkFreq();                           /* Determine SysTick reference freq.                    */
    cnts         = cpu_clk_freq                                 /* Determine nbr SysTick increments                     */
                 / (CPU_INT32U)OSCfg_TickRate_Hz;

    OS_CPU_SysTickInit(cnts);                                   /* Init uC/OS periodic time src (SysTick).              */

    Mem_Init();                                                 /* Initialize memory managment module                   */
    Math_Init();                                                /* Initialize mathematical module                       */


#if OS_CFG_STAT_TASK_EN > 0u
    OSStatTaskCPUUsageInit(&err);                               /* Compute CPU capacity with no task running            */
#endif

#ifdef CPU_CFG_INT_DIS_MEAS_EN
    CPU_IntDisMeasMaxCurReset();
#endif


#if (APP_CFG_SERIAL_EN == DEF_ENABLED)
    App_SerialInit();                                           /* Initialize Serial communication for application ...  */
#endif
	

	OSTaskCreate((OS_TCB     *)&AppTask1TCB,  // 线程TCB              
			 (CPU_CHAR   *)APPTASK1NAME, // 线程名字
			 (OS_TASK_PTR ) AppTask1, // 线程入口函数
			 (void       *) "TASK1", // 线程参数
			 (OS_PRIO     ) APP_TASK1_PRIO, // 线程优先级
			 (CPU_STK    *)&AppTask1Stk[0], // 线程栈起始地址
			 (CPU_STK_SIZE) APP_TASK1_STK_SIZE / 10, // 栈深度的限制位置
			 (CPU_STK_SIZE) APP_TASK1_STK_SIZE, // 栈大小
			 (OS_MSG_QTY  ) 20u, // 最大的消息个数
			 (OS_TICK     ) 0u, // 时间片
			 (void       *) 0, // 向用户提供的内存位置的指针
			 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), // 线程特定选项
			 (OS_ERR     *)&err); // 错误标志
	if(OS_ERR_NONE == err)
		printf("%s Create Success\r\n",APPTASK1NAME);
	else
		printf("%s Create Error\r\n",APPTASK1NAME);
	
			 
	OSTaskCreate((OS_TCB     *)&AppTask2TCB,  // 线程TCB              
			 (CPU_CHAR   *)APPTASK2NAME, // 线程名字
			 (OS_TASK_PTR ) AppTask2, // 线程入口函数
			 (void       *) "TASK2", // 线程参数
			 (OS_PRIO     ) APP_TASK2_PRIO, // 线程优先级
			 (CPU_STK    *)&AppTask2Stk[0], // 线程栈起始地址
			 (CPU_STK_SIZE) APP_TASK2_STK_SIZE / 10, // 栈深度的限制位置
			 (CPU_STK_SIZE) APP_TASK2_STK_SIZE, // 栈大小
			 (OS_MSG_QTY  ) 20u, // 最大的消息个数
			 (OS_TICK     ) 0u, // 时间片
			 (void       *) 0, // 向用户提供的内存位置的指针
			 (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), // 线程特定选项
			 (OS_ERR     *)&err); // 错误标志
	if(OS_ERR_NONE == err)
		printf("%s Create Success\r\n",APPTASK2NAME);
	else
		printf("%s Create Error\r\n",APPTASK2NAME);
		

	OSQCreate(&queue,"queue",20,&err); // 创建消息队列对象
	if(OS_ERR_NONE == err)
		printf("msg Create Success\r\n");
	else
		printf("msg Create Error\r\n");
	
	OSTaskDel ( & AppTaskStartTCB, & err );		 

}

static void  AppTask1  (void *p_arg)
{
    OS_ERR      err;
	static struct msg msg_send = {0};

	int i = 0;
	char name[50];
	while(DEF_TRUE)
	{
		
		Str_Copy_N(msg_send.msg_string,"hello this is a msg1",sizeof(msg_send.msg_string)); // 填充消息
		msg_send.value++;
		OSQPost(&queue,(struct msg*)&msg_send,sizeof(struct msg),OS_OPT_POST_FIFO,&err); // 发送消息
		if(OS_ERR_NONE == err)
			printf("msg Send Success\r\n");
		else
			printf("msg Send Error\r\n");
		
		
		OSTimeDly ( 500, OS_OPT_TIME_DLY, & err ); // 500ms运行一次
		
	}
	
}
static void  AppTask2  (void *p_arg)
{
    OS_ERR      err;
	struct msg *pmsg;
	OS_MSG_SIZE msg_size;
	while(DEF_TRUE)
	{
		pmsg = OSQPend(&queue,0,OS_OPT_PEND_BLOCKING,&msg_size,0,&err); // 接收消息
		if(OS_ERR_NONE == err)
			printf("msg Recv Success\r\n");
		else
			printf("msg Recv Error\r\n");
		printf("%s %s\r\n",__func__,pmsg->msg_string);
		printf("%s %d\r\n",__func__,pmsg->value);
		
	}
	
}

在这里插入图片描述

更多推荐

Python项目Flask ipv6双栈支持改造

一、背景Flask是一个微型的(轻量)使用Python语言开发的WSGIWeb框架(一组库和模块),基于WerkzeugWSGI工具箱/库和Jinja2模板引擎,当然,Python的WEB框架还有:Django、Tornado、Webpy,这暂且不提。Flask使用BSD授权。Flask也被称为microframewo

excel中的引用与查找函数篇2

如下所有案例中表头均不参与范围查找内:1、LOOKUP(lookup_value,lookup_vector,[result_vector]):在一行或者一列中查找某个值并从另一行或者列中找到同位置的值记住:中括号内的参数可以不赋值,若在中间用逗号隔开这个参数,若在末尾则不予理会lookup(查找对象,查找对象所在的行

AI+低代码:开启普惠人工智能时代的新篇章

🌷🍁博主猫头虎带您GotoNewWorld.✨🍁🦄博客首页——猫头虎的博客🎐🐳《面试题大全专栏》文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~🌺🌊《IDEA开发秘籍专栏》学会IDEA常用操作,工作效率翻倍~💐🌊《100天精通Golang(基础入门篇)》学会Golang语言,畅玩云原生,走遍大

深入学习 Redis Cluster - 基于 Docker、DockerCompose 搭建 Redis 集群,处理故障、扩容方案

目录一、基于Docker、DockerCompose搭建Redis集群1.1、前言1.2、编写shell脚本1.3、执行shell脚本,创建集群配置文件1.4、编写docker-compose.yml文件1.5、启动容器1.6、构建集群1.7、使用集群1.8、如果集群中,有节点挂了,怎么办?二、集群故障、扩容处理2.1

Selenium常见问题解析

1、元素定位失败:在使用Selenium自动化测试时,最常见的问题之一是无法正确地定位元素,这可能导致后续操作失败。解决方法包括使用不同的定位方式(如xpath、CSSselector、id等),等待页面加载完全后再进行操作,或者增加元素定位的鲁棒性。举个例子:假设我们要定位一个登录页面的“用户名”输入框,但是该输入框

docker四种网络模式

文章目录一.为什么要了解docker网络二.docker网络理论三.docker的四类网络模式3.1bridge模式3.2host模式3.3container模式3.4none模式四.bridge模式下容器的通信4.1防火墙开启状态4.2防火墙关闭状态一.为什么要了解docker网络当你开始大规模使用Docker时,你

Docker基础-namespace

Docker-namespacenamespace基础命令dd命令mkfsdfmountunsharepid隔离试验mount隔离namespacenamespace是Linux内核用来隔离内核资源的方式。通过namespace可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,

Spark 框架概述

目录一、Spark是什么1.1统一分析引擎?二、Spark风雨十年​三、SparkVSHadoop(MapReduce)3.1面试题:Hadoop的基于进程的计算和Spark基于线程方式优缺点?四、Spark四大特点​4.1速度快4.2易于使用4.3通用性强​4.4运行方式五、Spark框架模块5.1介绍5.2Spar

Python+Selenium定位不到元素常见原因及解决办法(报:NoSuchElementException)

这篇文章主要介绍了Python+Selenium定位不到元素常见原因及解决办法(报:NoSuchElementException),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧在做web应用的自动化测试时,定位元素是必不可少的,这个过程经常会碰到定

虹科分享 | 软件供应链攻击如何工作?如何评估软件供应链安全?

说到应用程序和软件,关键词是“更多”。在数字经济需求的推动下,从简化业务运营到创造创新的新收入机会,企业越来越依赖应用程序。云本地应用程序开发更是火上浇油。然而,情况是双向的:这些应用程序通常更复杂,使用的开放源代码比以往任何时候都包含更多的漏洞。此外,威胁行为者正在创造和使用更多的攻击方法和技术,通常是组合在一起的。

华为云云耀云服务器L实例评测|部署功能强大的监控和可视化工具Grafana

应用场景Grafana介绍Grafana是一个功能强大的监控和可视化工具,适用于各种行业和应用场景,如IT运维监控、网络监控、能源管理、金融市场分析等。它提供了灵活的数据源支持、强大的可视化功能和告警机制,以及注释和过滤功能,使得用户能够更好地理解和分析实时数据。下面的监控查询面板都是使用Grafana制作的。一个用于

热文推荐