OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 19648|回复: 8

分享一个rt-thread 串口接收不定长度数据的历程,亲测可用

[复制链接]

22

主题

49

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
214
金钱
214
注册时间
2014-4-30
在线时间
26 小时
发表于 2019-9-28 12:27:42 | 显示全部楼层 |阅读模式


使用了串口的中断轮询方式,
接收线程负责接收数据,接收完之后使用消息队列发送给数据处理线程。

注意,使用队列的接收函数时 ,这里可能是个rtthread的bug:

rt_mq_recv(&mq, &tmp, sizeof(tmp), RT_WAITING_FOREVER) == RT_EOK
当rt_mq_recv接收不定长数据时会出现,rt_mq_recv每次从mq队列里取数据后没有清除原来的数据,这样会导致下一次接收到的实际消息长度小于本次长度时,下次消息队列接收到的数据是夹杂着上一次数据的尾巴。
譬如,接收buffer大小大于7,小于消息队列单个消息长度,第一次发送消息"123456",第一次调用rt_mq_recv没有问题,第二次发送消息"111"时,第二次调用rt_mq_recv接收到的数据会变成"111456"。
解决方案:
在ipc.c中的rt_mq_recv函数
    rt_memcpy(buffer, msg + 1, size > mq->msg_size ? mq->msg_size : size);
后面加一句:
    rt_memset(msg + 1, 0, size > mq->msg_size ? mq->msg_size : size);   

360截图17001022439085.jpg




源代码如下:(由于是基于自己设计的开发板板,很多底层接口和驱动没办法直接用,这里就不上次整个工程了)

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <drv_log.h>
#include <stdio.h>
#include <string.h>

#define PORT "uart4"

typedef struct {
    char buf[128];
    unsigned short sta;
}uart_rcv_typedef;

uart_rcv_typedef ur;

static rt_thread_t rcv_thread = RT_NULL, parse_thread = RT_NULL;
static rt_device_t dev_uart;           

char gnss_cmd[] = "version\r\n";
static struct rt_messagequeue mq;
/* 消息队列中用到的放置消息的内存池*/
static rt_uint8_t msg_pool[1024];

static struct rt_semaphore rx_sem1;

static void rcv_thread_entry(void* parameter);
static void parse_thread_entry(void* parameter);

static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    rt_sem_release(&rx_sem1);

    return RT_EOK;
}
//主函数

int app01_gnss_thread_start(void)
{  

    rt_sem_init(&rx_sem1, "rx_sem1", 0, RT_IPC_FLAG_FIFO);
    rt_mq_init(&mq,"mqt",&msg_pool[0], 128,sizeof(msg_pool),RT_IPC_FLAG_FIFO);/* 内存池指向msg_pool */

    dev_uart = rt_device_find(PORT);

    rt_kprintf("%s listen on\n",PORT);

//    rt_device_open(dev_uart , RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX );
    rt_device_open(dev_uart , RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX );

    rt_device_set_rx_indicate(dev_uart , uart_input);

    rcv_thread =                        
    rt_thread_create( "listen_uart4",            
                      rcv_thread_entry,   
                      RT_NULL,            
                      512,                 
                      10,                  
                      20);                 

   if (rcv_thread != RT_NULL)
        rt_thread_startup(rcv_thread);
    else
        return -1;

    parse_thread =                        
    rt_thread_create( "parse_data",            
                      parse_thread_entry,   
                      RT_NULL,            
                      2048,                 
                      10,                  
                      20);                 

   if (parse_thread != RT_NULL)
        rt_thread_startup(parse_thread);
    else
        return -1;
    return RT_EOK;
}

//线程函数

static void rcv_thread_entry(void* parameter)
{
    char te[128];


   char ch;

    while (1)
    {
        while (rt_device_read(dev_uart , -1, &ch, 1) != 1)
        {
            rt_sem_take(&rx_sem1, RT_WAITING_FOREVER);
        }
            ur.buf[ur.sta++] = ch;
            if(ch == '\n')
            {
                ur.buf[ur.sta] = '\0';
                rt_mq_send(&mq, &ur.buf, ur.sta&0x7fff);
                memset(&ur,0,sizeof(uart_rcv_typedef));
            }

    }

}


static void parse_thread_entry(void* parameter)
{
    char tmp[128];
    while(1)
    {

        if (rt_mq_recv(&mq, &tmp, sizeof(tmp), RT_WAITING_FOREVER) == RT_EOK)
        {
            rt_kprintf("get:%s",tmp);
        }
          rt_thread_mdelay(50);
    }
}



INIT_APP_EXPORT(app01_gnss_thread_start);




正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

31

主题

2176

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
14096
金钱
14096
注册时间
2018-8-3
在线时间
1143 小时
发表于 2019-9-28 12:37:05 | 显示全部楼层
回复 支持 反对

使用道具 举报

5

主题

63

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2018-6-15
在线时间
28 小时
发表于 2019-9-29 13:42:07 | 显示全部楼层
厉害了
回复 支持 反对

使用道具 举报

2

主题

17

帖子

0

精华

初级会员

Rank: 2

积分
74
金钱
74
注册时间
2018-3-17
在线时间
9 小时
发表于 2019-9-29 14:30:31 | 显示全部楼层
楼主的动手能力很强啊
回复 支持 反对

使用道具 举报

10

主题

59

帖子

0

精华

初级会员

Rank: 2

积分
191
金钱
191
注册时间
2018-7-23
在线时间
23 小时
发表于 2019-9-29 17:04:55 | 显示全部楼层
楼主具有探索性
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
34
金钱
34
注册时间
2018-8-28
在线时间
9 小时
发表于 2020-12-10 17:29:18 | 显示全部楼层
这段代码在Finsh组件中好像就有吧
回复 支持 反对

使用道具 举报

2

主题

26

帖子

0

精华

初级会员

Rank: 2

积分
86
金钱
86
注册时间
2018-12-26
在线时间
24 小时
发表于 2020-12-14 16:25:14 | 显示全部楼层
谢谢分享
回复 支持 反对

使用道具 举报

8

主题

51

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
389
金钱
389
注册时间
2019-4-25
在线时间
99 小时
发表于 2021-12-17 20:25:56 | 显示全部楼层
本帖最后由 a314825348 于 2021-12-17 20:27 编辑

你好,这是不定长数据吗?这里使用了 '\n' 作为结束符?如果我的数据结尾不是 '\n' 这个就不能用了吧。
  1. ur.buf[ur.sta++] = ch;
  2. if(ch == '\n')
  3. {
  4.     ur.buf[ur.sta] = '\0';
  5.     rt_mq_send(&mq, &ur.buf, ur.sta&0x7fff);
  6.     memset(&ur,0,sizeof(uart_rcv_typedef));
复制代码
回复 支持 反对

使用道具 举报

22

主题

49

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
214
金钱
214
注册时间
2014-4-30
在线时间
26 小时
 楼主| 发表于 2023-12-6 14:07:04 | 显示全部楼层
加定时器,超时
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-5-16 07:00

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表