RT-Thread消息邮箱和队列在STM32串口中的应用_冷月无声惜马蹄的博客-程序员秘密

技术标签: RT-Thread  

使用消息邮箱处理串口消息

邮箱用于线程间通信,特点是开销比较低,效率较高
邮箱中的每一封邮件只能容纳固定的 4 字节内容(针对 32 位处理系统,指针为 4 个字节大小,一封邮件恰好能够容纳一个指针

代码:

rt_thread_app.c:

#include "rtthread.h"
#include "rt_thread_app.h"
#include "bsp_usart.h"

static rt_thread_t usart1_thread = RT_NULL;
rt_mailbox_t usart1_mail = RT_NULL;

static void usart_receive_thread_entry(void* parameter);

int rt_thread_app_init(void)
{
    
  /* 创建一个邮箱 */
	usart1_mail = rt_mb_create("usart1_mail", /* 邮箱名字 */
                              10,         /* 邮箱大小 */
                             RT_IPC_FLAG_FIFO);/* 信号量模式 FIFO(0x00)*/
	if (usart1_mail != RT_NULL)
		rt_kprintf("邮箱创建成功!\n\n");
    
	usart1_thread =                          /* 线程控制块指针 */
		rt_thread_create( "receive",              /* 线程名字 */
                          usart_receive_thread_entry,   /* 线程入口函数 */
                          RT_NULL,             /* 线程入口函数参数 */
                          512,                 /* 线程栈大小 */
                          3,                   /* 线程的优先级 */
                          20);                 /* 线程时间片 */
                   
    /* 启动线程,开启调度 */
   if (usart1_thread != RT_NULL)
        rt_thread_startup(usart1_thread);
    else
       return -1;
}

//串口消息处理线程
static void usart_receive_thread_entry(void* parameter)
{
    		
	rt_err_t uwRet = RT_EOK;
	stUsartMsgBuffer *usart1Msg;
  /* 任务都是一个无限循环,不能返回 */
	while(1)
	{
    
		/* 等待接邮箱消息 */
		uwRet = rt_mb_recv(usart1_mail,              /* 串口消息的邮箱对象句柄 */
						  (rt_uint32_t*)&usart1Msg,  /* 接收串口的邮箱消息 */
						  RT_WAITING_FOREVER);       /* 指定超时事件,一直等 */
		
		if(RT_EOK == uwRet) /* 如果接收完成并且正确 */
		{
    
			rt_kprintf ( "邮箱的内容是:%s\r\n", usart1Msg->rxBuf);		
		}
		else
			rt_kprintf ( "邮箱接收错误!错误码是0x%x\n", uwRet);
		
		UsartBuffer_Reset(usart1Msg);		
  }
}

bsp_usart.c:

#define USART1_RX_BUFFER_SIZE    256
#define EN_USART1_RX  1

static u8 usart1RxBuffer[USART1_RX_BUFFER_SIZE];
stUsartMsgBuffer usart1MsgBuffer;

void UsartBuffer_Init(stUsartMsgBuffer *usartBuf, USART_TypeDef *USARTx, u8 *rxbuf, u32 rxbufSize)
{
    
	usartBuf->rxIndex   = 0;
	usartBuf->status    = 0;
	usartBuf->rxBuf     = rxbuf;
	usartBuf->txBufSize = 0;
	usartBuf->USARTx    = USARTx;
	memset(usartBuf->rxBuf, 0, rxbufSize);
}

void UsartBuffer_Reset(stUsartMsgBuffer *usartBuf)
{
    
	usartBuf->rxIndex = 0;
	memset(usartBuf->rxBuf, 0, usartBuf->rxBufSize);
}

void Usart_Send(stUsartMsgBuffer *usartBuf, u8 *txbuf, u32 txbufSize)
{
    
	u16 i, ucErrTime;

    for (i = 0; i < txbufSize; i++)
    {
    
        ucErrTime = 0;
        while (USART_GetFlagStatus(usartBuf->USARTx, USART_FLAG_TC) == RESET)
        {
    
            if (ucErrTime++ > 2000)    //这个值更具CPU的频率不同而有所改变
            {
    
                printf("USART_Write error: Write timeout\r\n");
                return;
            }
        }
        USART_SendData(usartBuf->USARTx, (uint8_t)txbuf[i]);
    }
}

void UsartIRQHandler(stUsartMsgBuffer *usartBuf)
{
    
    u8 retval;
	
	if (!usartBuf)
		return;
	
    if (USART_GetITStatus(usartBuf->USARTx, USART_IT_RXNE) == SET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
    {
    
        retval = USART_ReceiveData(usartBuf->USARTx);
        if (usartBuf->rxIndex > usartBuf->rxBufSize - 1) //长度超出,位找下面的头做准备
        {
    
            usartBuf->rxBuf[0] = usartBuf->rxBuf[usartBuf->rxIndex - 1]; //把最后一个搬到第一个
            usartBuf->rxIndex = 1;                                           //指向第二个
        }
        usartBuf->rxBuf[usartBuf->rxIndex++] = retval;         //(USART1->DR);	//读取接收到的数据
    }
    if (USART_GetITStatus(usartBuf->USARTx, USART_IT_IDLE) == SET)   //idle interrupt
    {
    
		extern rt_mailbox_t usart1_mail;
        USART_ReceiveData(usartBuf->USARTx);                         //clear idle interrupt
        usartBuf->status = 1;       
		rt_mb_send(usart1_mail, (rt_uint32_t)usartBuf);
//		USART_ITConfig(usartBuf->USARTx, USART_IT_RXNE, DISABLE); 
	}
}

void USART1_IRQHandler(void) //串口1中断服务程序
{
    
    UsartIRQHandler(&usart1MsgBuffer);
}

使用消息队列处理串口消息

消息队列是另一种常用的线程间通讯方式,是邮箱的扩展。可以应用在多种场合:线程间的消息交换、使用串口接收不定长数据等;
消息队列是一种异步的通信方式
消息队列是直接的数据内容复制,所以不需要动态分配内存作为缓存,只需用了局部变量作为缓存保存消息,这样也就免去动态内存分配的烦恼。

代码:

#include "rtthread.h"
#include "rt_thread_app.h"
#include "bsp_usart.h"

static rt_thread_t usart1_thread = RT_NULL;

rt_mq_t usart1_mq = RT_NULL;

static void usart_receive_thread_entry(void* parameter);

int rt_thread_app_init(void)
{
    
   /* 创建一个消息队列 */
	usart1_mq = rt_mq_create("usart1_mq",/* 消息队列名字 */
                     40,     /* 消息的最大长度 */
                     20,    /* 消息队列的最大容量 */
                     RT_IPC_FLAG_FIFO);/* 队列模式 FIFO(0x00)*/
  if (usart1_mq != RT_NULL)
    rt_kprintf("消息队列创建成功!\n\n");

	usart1_thread =                          /* 线程控制块指针 */
		rt_thread_create( "receive",              /* 线程名字 */
                          usart_receive_thread_entry,   /* 线程入口函数 */
                          RT_NULL,             /* 线程入口函数参数 */
                          512,                 /* 线程栈大小 */
                          3,                   /* 线程的优先级 */
                          20);                 /* 线程时间片 */
                   
    /* 启动线程,开启调度 */
   if (usart1_thread != RT_NULL)
        rt_thread_startup(usart1_thread);
    else
       return -1;
}

static void usart_receive_thread_entry(void* parameter)
{
    		
	rt_err_t uwRet = RT_EOK;
	stUsartMsgBuffer usart1Msg;
  /* 任务都是一个无限循环,不能返回 */
	while(1)
	{
    
		/* 等待接邮箱消息 */
		uwRet = rt_mq_recv(usart1_mq,	/* 读取(接收)队列的ID(句柄) */
							&usart1Msg,			/* 读取(接收)的数据保存位置 */
							sizeof(usart1Msg),		/* 读取(接收)的数据的长度 */
							RT_WAITING_FOREVER); 	/* 等待时间:一直等 */
		
		if(RT_EOK == uwRet) /* 如果接收完成并且正确 */
		{
    
			rt_kprintf ( "消息队列的内容是: %s\n\n", usart1Msg.rxBuf);		
		}
		else
			rt_kprintf ( "消息队列接收错误!错误码是0x%x\n", uwRet);
	}
}
void UsartIRQHandler(stUsartMsgBuffer *usartBuf)
{
    
    u8 retval;
	
	if (!usartBuf)
		return;
	
    if (USART_GetITStatus(usartBuf->USARTx, USART_IT_RXNE) == SET) //接收中断
    {
    
        retval = USART_ReceiveData(usartBuf->USARTx);
        if (usartBuf->rxIndex > usartBuf->rxBufSize - 1)
        {
    
            usartBuf->rxBuf[0] = usartBuf->rxBuf[usartBuf->rxIndex - 1]; 
            usartBuf->rxIndex = 1;                                          
        }
        usartBuf->rxBuf[usartBuf->rxIndex++] = retval;        
    }
    if (USART_GetITStatus(usartBuf->USARTx, USART_IT_IDLE) == SET)   //idle interrupt
    {
    
		extern rt_mq_t usart1_mq;
        USART_ReceiveData(usartBuf->USARTx);                         //clear idle interrupt
       // usartBuf->status = 1;       
		rt_mq_send(	usart1_mq,	/* 写入(发送)队列的ID(句柄) */
                    usartBuf,			/* 写入(发送)的数据 */
                    sizeof(stUsartMsgBuffer));			/* 数据的长度 */
                    
		UsartBuffer_Reset(usartBuf);
//		USART_ITConfig(usartBuf->USARTx, USART_IT_RXNE, DISABLE); 
	}
}

void USART1_IRQHandler(void) //串口1中断服务程序
{
    
    UsartIRQHandler(&usart1MsgBuffer);
}

后记:

两种方式都是在中断中接收数据,在线程中处理处理数据,处理数据是比较耗时的工作。这样的操作是将中断的处理分为上半部底半部。在Linux中对于中断的处理也是这类似这样处理的。
上半部——耗时短的工作放在中断中处理
底半部——耗时长的工作通过IPC通知线程处理

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_36413982/article/details/106855526

智能推荐

1.01的12次方怎么用计算机算,(1+0.5%)的12次方等于多少,CASIO计算器中怎样算_少女心杀手刘小姐的博客-程序员秘密

CASIO计算器中计算这个算式,与下面的方法基本相同;(1+0.5%)^12=1.0616778118644995687897076174316.......方法与步骤如下:步骤1、用计算器数字键输入并计算0.5÷100+1=1.005,如下图:步骤2、按下图红框这个键,如下图:步骤3、用计算器输入12,如下图:步骤4、按“=”这个键,如下图红框这个键,就计算出结果了:(1+0.5%)的12次方等...

【jetson-nano】 2.2、安装监测和控制软件jetson-stats_jn10010537的博客-程序员秘密

【jetson-nano】 2.1、安装监控软件jtop1、背景2、安装jtop3、jtop使用1、背景jtop是一款开源软件,可以查看Jetson Nano的运行状态。jtop的github官网:https://github.com/rbonghi/jetson_stats2、安装jtopsudo -H pip3 install -U jetson-stats查看版本[email protected]:~$ jtop -vjtop 3.1.13、jtop使用在终端直接输入jtop之

代码静态检测——QAC_注释远方的博客-程序员秘密

一、前言二、QAC构建三、QAC常见报警3.1 Msg(2:4700) metric value out of threshold range: STCYC=22:STLIN=307:STMCC = 48;函数内执行的代码行数少于5,比如一个函数中只有if-else if...或者switch-case3.2 Msg(2:4304) An expression of 'essentially Boolean type'is being cast to unsigne...

代码静态检测——QAC_注释远方的博客-程序员秘密

一、前言二、QAC构建三、QAC常见报警3.1 Msg(2:4700) metric value out of threshold range: STCYC=22:STLIN=307:STMCC = 48;函数内执行的代码行数少于5,比如一个函数中只有if-else if...或者switch-case3.2 Msg(2:4304) An expression of 'essentially Boolean type'is being cast to unsigne...

代码静态检测——QAC_注释远方的博客-程序员秘密

一、前言二、QAC构建三、QAC常见报警3.1 Msg(2:4700) metric value out of threshold range: STCYC=22:STLIN=307:STMCC = 48;函数内执行的代码行数少于5,比如一个函数中只有if-else if...或者switch-case3.2 Msg(2:4304) An expression of 'essentially Boolean type'is being cast to unsigne...

JETSON NANO与笔记本电脑连接_QSXXN的博客-程序员秘密

英伟达JETSON NANO利用网线与笔记本电脑连接前言环境及准备:开始咯前言在开发板下vncserver服务的时候做个笔记,博主刚刚拿到jetson nano开发板,准备用usb转ttl连接笔记本电脑的时候发现杜邦线不够,然后根据网上的教程用网线直接连接开发板和笔记本,但是!博主发现自己挂在了第二步,用arp -a根本扫不出开发板的ip地址,在查找了一番资料以后博主觉得可能是网线的原因,网络...

随便推点

C语言中的__FILE__、__LINE__和#line(用于打印当前函数及行数)_IT之路的博客-程序员秘密

C语言中的__FILE__用以指示本行语句所在源文件的文件名,举例如下(test.c):#include &amp;lt;stdio.h&amp;gt;int main(){printf(&quot;%s\n&quot;,__FILE__);}在gcc编译生成a.out,执行后输出结果为:test.c在windows的vc6.0下...

AngularJS 最常用的八种功能_chuofuji9725的博客-程序员秘密

现在部门的后台数据绑定框架是AngularJS,特整理一些常用方法,和大家分享 第一 迭代输出之ng-repeat标签 ng-repeat让table ul ol等标签和js里的数组完美结合 12345 &lt;ul&gt;&lt;li ng...

SpringCloud对应SpringBoot版本_Knight.Liam的博客-程序员秘密

大概率是版本问题,SpringCloud对应SpringBoot的版本是否对应,又或者SpringBoot与其他的jar不兼容。

C# windows服务启动winform应用程序_c# 守护winform 程序_静静的意思的博客-程序员秘密

最近在写一个守护进程的服务,遇到了一点儿问题,现在记录下来,也希望能帮到有需要的人。开发环境:win7,VS2015问题: 1、通过process启动App,不显示界面 2、有的电脑安装服务Service后,App启动正常,有的电脑仍然不显示界面原因: 问题1:与windows session有关,请参考文章“链接1”,里面写的很详细且易懂。 问

代码静态检测——QAC_注释远方的博客-程序员秘密

一、前言二、QAC构建三、QAC常见报警3.1 Msg(2:4700) metric value out of threshold range: STCYC=22:STLIN=307:STMCC = 48;函数内执行的代码行数少于5,比如一个函数中只有if-else if...或者switch-case3.2 Msg(2:4304) An expression of 'essentially Boolean type'is being cast to unsigne...

推荐文章

热门文章

相关标签