STM32+RTThread串口不定长接收

/**
 * @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;
}


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
STM32 上实现串口不定接收,可以使用中断方式来处理。以下是一个基本的流程: 1. 初始化串口: - 配置串口波特率、数据位、停止位、校验位等参数; - 使能串口中断。 2. 实现串口中断处理函数,用于接收数据: - 在中断处理函数中,如果接收数据,则将数据存储到缓冲区中; - 如果接收到的数据长度超过缓冲区长度,则需要处理溢出情况。 3. 判断缓冲区中是否有完整的数据包: - 可以根据数据包的头部和尾部进行判断; - 如果有完整的数据包,则可以将数据包取出进行处理。 以下是一个简单的代码示例: ```c #define BUFFER_SIZE 256 // 缓冲区大小 uint8_t buffer[BUFFER_SIZE]; // 缓冲区 uint8_t index = 0; // 当前缓冲区中已经接收到的数据长度 // 串口中断处理函数 void USART2_IRQHandler(void) { if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) // 接收数据 { uint8_t data = USART_ReceiveData(USART2); // 读取接收到的数据 if (index < BUFFER_SIZE) // 缓冲区未满 { buffer[index++] = data; // 将数据存储到缓冲区中 } else // 缓冲区已满,需要处理溢出情况 { index = 0; // 重置缓冲区指针,覆盖之前的数据 } } } // 判断缓冲区中是否有完整的数据包 bool isPacketComplete(void) { if (index < 2) // 数据包头部长度为2字节 { return false; } uint16_t length = buffer[0] << 8 | buffer[1]; // 数据长度为头部中的2字节 if (index < length + 2) // 数据长度数据长度加上头部长度 { return false; } return true; } int main(void) { // 初始化串口 USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART2, &USART_InitStructure); USART_Cmd(USART2, ENABLE); // 使能串口中断 NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPriority = 0; NVIC_Init(&NVIC_InitStructure); while (1) { if (isPacketComplete()) // 如果有完整的数据包 { // 处理数据包,例如解析数据包中的命令和参数 // ... index = 0; // 清空缓冲区 } } } ``` 在上面的代码中,我们使用一个缓冲区来存储接收到的数据,使用一个指针 `index` 来记录当前缓冲区中已经接收到的数据长度。当缓冲区已满时,我们重新从缓冲区开头开始存储数据,覆盖之前的数据。在 `isPacketComplete()` 函数中,我们根据数据包的头部和尾部来判断是否有完整的数据包,如果有,则将数据包取出进行处理。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值