STM32+RTThread串口不定长接收

本文介绍了一个基于RT-Thread系统的UART2模块实现细节,包括串口接收、数据处理和分帧定时等功能。通过使用消息队列、FIFO缓冲区和定时器等机制实现了可靠的数据收发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/**
 * @file usart2.c
 * @author zhaoguangxin (zhaoguangxin@qq.com)
 * @brief 
 * @version 0.1
 * @date 2022-08-25
 * 
 * @copyright Copyright (c) 2022
 * 
 */

#include <rtthread.h>
#include <string.h>
#include <serial.h>

/* 设备句柄 */
#define UART_NAME       "uart2"
static rt_device_t serial;

/* 消息传递队列 */
#define USART2_QUE_NUM           (10)
static struct rt_messagequeue  rx_que;
typedef struct{
    rt_uint32_t p_read;         //开始读取地址
    rt_uint32_t p_end;          //读取的结束地址
}Rx_Index_t;
static rt_uint8_t msg_pool[sizeof(Rx_Index_t) * USART2_QUE_NUM];

/* FIFO */
#define USART2_RX_MAX            (1024UL)
typedef struct{
    rt_uint32_t wIndex;
    rt_uint32_t rIndex;
    rt_uint8_t overFlag;
    rt_uint8_t *fifo;
}Rx_FIFO_t;
static Rx_FIFO_t usart2FIFO;

/* 分帧定时器 */
static struct rt_timer firTimer;
static rt_uint8_t timerStatus = 0;  //0未启动 1:启动

/**
 * @name: firTimer_timeout
 * @func: 分帧定时器回调函数
 * @input: 
 * parameter:参数
 * @output: none
 * @return: none
 */
static void firTimer_timeout(void* parameter)
{
    Rx_Index_t rIndex;
    rIndex.p_read = usart2FIFO.rIndex;
    rIndex.p_end = (usart2FIFO.wIndex == 0) ? (USART2_RX_MAX - 1) : (usart2FIFO.wIndex  - 1);
    usart2FIFO.rIndex = usart2FIFO.wIndex;
    if( rt_mq_send( &rx_que, &rIndex, sizeof(rIndex) ) == -RT_EFULL )
        rt_kprintf("message queue full!\n");
}

/**
 * @name: uart_input
 * @func: 串口2接收回调函数
 * @input: 
 * dev:设备
 * size:接收的数据量
 * @output: none
 * @return: none
 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
    while( 1 ){
        if( rt_device_read(serial, -1, &usart2FIFO.fifo[usart2FIFO.wIndex], 1) == 1 ){
            usart2FIFO.wIndex += 1;
            if( usart2FIFO.wIndex >= USART2_RX_MAX )
                usart2FIFO.wIndex = 0;
    
            if( usart2FIFO.wIndex == usart2FIFO.rIndex )
                usart2FIFO.overFlag = 1;
        }else{
            break;
        }
    }
    
    if( timerStatus == 0 )
        rt_timer_start(&firTimer);
    else{
        int arg = 10;
        rt_timer_control(&firTimer, RT_TIMER_CTRL_SET_TIME, &arg);
    }
	return RT_EOK;
}

/**
 * @name: USART2_GetData
 * @func: 串口2获取数据
 * @input: 
 * timeout:超时
 * @output:
 * getBuff:输出获取的数据 需要外部释放
 * len:获取的数据长度
 * @return: 
 * 0:成功  其他失败
 */
int USART2_GetData(rt_uint8_t **getBuff, rt_uint32_t *len, rt_uint32_t timeout)
{
    rt_uint32_t tempLen = 0;
    Rx_Index_t recIndex;
    rt_uint8_t *p = RT_NULL;

    if( getBuff == RT_NULL || len == RT_NULL){
        return -1;
    }

    memset(&recIndex, 0, sizeof(recIndex));
    if(rt_mq_recv(&rx_que, &recIndex, sizeof(recIndex), timeout) != RT_EOK){  //读取串口队列消息,没有数据就阻塞等待
        return -1;
    }


    if( usart2FIFO.overFlag != 0 ){
        usart2FIFO.overFlag = 0;
    }
  
  if( recIndex.p_end >= recIndex.p_read ){
    *len = recIndex.p_end - recIndex.p_read + 1;
    p = rt_malloc(*len + 1);
    if( p != RT_NULL ){
      memset(p, 0, *len + 1);
      memcpy(p, &usart2FIFO.fifo[recIndex.p_read], *len);
    }
  }else{
    tempLen = USART2_RX_MAX - recIndex.p_read;
    *len = tempLen + recIndex.p_end +1;

    p = rt_malloc(*len + 1);
    if( p != RT_NULL ){
      memset(p, 0, *len + 1);
      memcpy(p, &usart2FIFO.fifo[recIndex.p_read], tempLen);
      memcpy(p + tempLen, usart2FIFO.fifo,recIndex.p_end + 1);
    }
  }
  *getBuff = p;

  return 0;
}

/**
 * @name: serial_thread_entry
 * @func: 串口2线程
 * @input: 
 * parameter:线程参数
 * @output: none
 * @return: 
 * 初始化结果
 */
static void serial_thread_entry(void *parameter)
{
    rt_uint8_t *buf;
    rt_uint32_t len;

    while(1){
        if( 0 == USART2_GetData(&buf, &len, (rt_uint32_t)RT_WAITING_FOREVER)){
            rt_device_write(serial, 0, buf, len);
            rt_free(buf);
        }
    }
}

/**
 * @name: uart2_init
 * @func: 串口2初始化
 * @input: 
 * bound:波特率
 * @output: none
 * @return: 
 * 初始化结果
 */
int uart2_init(int bound)
{
    serial = rt_device_find(UART_NAME);
    if( !serial ){
        rt_kprintf("find %s failed!\n", UART_NAME);
        return RT_ERROR;
    }

    rt_device_open(serial, RT_DEVICE_FLAG_INT_RX);
    struct serial_configure serialConfig = RT_SERIAL_CONFIG_DEFAULT;
    serialConfig.baud_rate = bound;
    rt_device_control(serial, RT_DEVICE_CTRL_CONFIG, &serialConfig);

    rt_device_set_rx_indicate(serial, uart_input);

    rt_mq_init(&rx_que, "rx_que",               //队列名称
                msg_pool,                       //存放队列的数据
                sizeof(Rx_Index_t),             //队列元素的大小
                sizeof(msg_pool),               //队列缓存的大小
                RT_IPC_FLAG_FIFO);              //有多个线程等待时,先到先得

    rt_timer_init(&firTimer, "firTimer",        //定时器名字是 firTimer
                    firTimer_timeout,           //超时时回调的处理函数
                      RT_NULL,                  //超时函数的入口参数
                      10,                       //定时长度为 30 个 OS Tick 
                    RT_TIMER_FLAG_ONE_SHOT);    //单次定时器 

    usart2FIFO.fifo = rt_malloc(USART2_RX_MAX);
    if( usart2FIFO.fifo == RT_NULL )
        return RT_ERROR;

    
#if 1
    rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
    if( thread != RT_NULL ){
        rt_thread_startup(thread);
    }else{
        return RT_ERROR;
    }
#endif
    return RT_EOK;
}


评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值