打印
[应用相关]

STM32:UART-接收不定长数据

[复制链接]
1561|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-4-30 16:50 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
正文
空闲帧


一空闲帧所需要的时间:1位起始位+8位数据位+1位校验位+1位停止位。

编程要点
串口硬件相关宏定义,bsp_uart.h

#ifndef __BSP_UART_H
#define __BSP_UART_H

#include "stm32f10x.h"
#include <stdio.h>


#define RCC_UART_GPIO_Clk_Cmd           RCC_APB2PeriphClockCmd
#define RCC_UART_GPIO_Clk               RCC_APB2Periph_GPIOA

#define UART_GPIO_Tx_Pin                GPIO_Pin_9
#define UART_GPIO_Tx_Port               GPIOA

#define UART_GPIO_Rx_Pin                GPIO_Pin_10
#define UART_GPIO_Rx_Port               GPIOA

#define BSP_USARTx                      USART1
#define RCC_UART_Clk_Cmd                RCC_APB2PeriphClockCmd
#define RCC_UART_Clk                    RCC_APB2Periph_USART1
#define UART_BaudRate                   115200

#define BSP_USARTx_IRQHandler           USART1_IRQHandler

void BSP_UART_Init(void);

#endif /* __BSP_UART_H */




串口模块配置,bsp_uart.c

#include "bsp_uart.h"

static void BSP_UART_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_UART_GPIO_Clk_Cmd(RCC_UART_GPIO_Clk,ENABLE);
    GPIO_InitStructure.GPIO_Pin = UART_GPIO_Tx_Pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(UART_GPIO_Tx_Port,&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = UART_GPIO_Rx_Pin;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(UART_GPIO_Rx_Port,&GPIO_InitStructure);
}


static void BSP_UART_Config(void)
{
    USART_InitTypeDef USART_InitStructure;
    RCC_UART_Clk_Cmd(RCC_UART_Clk,ENABLE);
    USART_InitStructure.USART_BaudRate = UART_BaudRate;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_StopBits =USART_StopBits_1;
    USART_InitStructure.USART_WordLength =USART_WordLength_8b;
    USART_Init(BSP_USARTx,&USART_InitStructure);
    USART_ITConfig(BSP_USARTx,USART_IT_RXNE,ENABLE);
    USART_ITConfig(BSP_USARTx,USART_IT_IDLE,ENABLE);

    USART_Cmd(BSP_USARTx,ENABLE);
}


void BSP_UART_Init(void)
{
    BSP_UART_Config();
    BSP_UART_GPIO_Config();
}



串口不定长数据接收
主函数,main.c

#define data_size   100

typedef struct{
    uint16_t flag;
    uint16_t len;
    char data[data_size];
}Data_TypeDef;


void Data_Process(Data_TypeDef* Data_Struct)
{
    Usart_SendString(BSP_USARTx,Data_Struct->data);

    Data_Struct->flag = 0;
    Data_Struct->len = 0;
}



void BSP_NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}



Data_TypeDef Data_Structure;

int main(void)
{
    BSP_UART_Init();
    BSP_NVIC_Config();
    while(1)
    {
        if(Data_Structure.flag == 1)
        {
            Data_Process(&Data_Structure);
        }
    }
}


中断服务,stm32f10x_it.c

extern Data_TypeDef Data_Structure;

void BSP_USARTx_IRQHandler(void)
{
  if(USART_GetITStatus(BSP_USARTx, USART_IT_RXNE) != RESET)
  {   
    /* Read one byte from the receive data register */
    Data_Struct.data[Data_Structure.len] = USART_ReceiveData(BSP_USARTx);
    if(++Data_Structure.len > data_size - 2)
    {
        Data_Struct.len = 0;
    }

  }
  if(USART_GetITStatus(BSP_USARTx,USART_IT_IDLE) != RESET)
  {
        BSP_USARTx->SR;
        BSP_USARTx->DR;
        Data_Structure.data[Data_Structure.len] = '\0';
        Data_Structure.flag = 1;
  }

}




这里使用软件清除RXNE标志,对USART_DR读操作可以将该位清零。



这里使用软件清除IDLE标志,对USART_SR,USART_DR读操作可以将该位清零。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/ZipingPan/article/details/137313795

使用特权

评论回复
沙发
xixi2017| | 2024-4-30 21:08 | 只看该作者
不定长一直是个协议的问题

使用特权

评论回复
板凳
i1mcu| | 2024-5-1 22:50 | 只看该作者
数据包的开始部分包含一个表示数据包长度的字段。接收方首先读取这个字段,然后知道需要读取多少字节来接收完整的数据包。

使用特权

评论回复
地板
deliahouse887| | 2024-5-2 16:55 | 只看该作者
环形缓冲区(也称为循环缓冲区或FIFO)是一种数据结构,它允许你在固定大小的内存中存储不定量的数据。当缓冲区满时,新数据将覆盖最旧的数据。

使用特权

评论回复
5
iyoum| | 2024-5-3 13:44 | 只看该作者
在接收不定长数据时,可以使用一个缓冲区来存储接收到的数据。当接收到一个数据包时,可以通过检测特定的结束符来判断数据包是否接收完毕。

使用特权

评论回复
6
biechedan| | 2024-5-4 12:56 | 只看该作者
使用特殊字符或序列作为数据包结束标记

使用特权

评论回复
7
beacherblack| | 2024-5-4 20:21 | 只看该作者
一个简单但常用的方法。发送方在数据包的末尾添加一个或多个特殊字符(如\r\n、0x0D 0x0A、0xFF等),接收方在检测到这些字符时知道数据包已经结束。

使用特权

评论回复
8
bestwell| | 2024-5-7 15:04 | 只看该作者
STM32的UART模块支持DMA传输,这允许CPU在数据接收过程中执行其他任务。

使用特权

评论回复
9
pmp| | 2024-5-7 20:23 | 只看该作者
在DMA传输完成后,通过中断或轮询的方式检查接收到的数据长度。

使用特权

评论回复
10
lihuami| | 2024-5-9 12:09 | 只看该作者
需要定义一个足够大的缓冲区来存储接收到的数据。

使用特权

评论回复
11
elsaflower| | 2024-5-10 13:29 | 只看该作者
如果数据包的长度未知且没有结束标记,你可以使用定时器来确定何时停止接收。例如,你可以设置一个超时时间,如果在该时间内没有接收到新的数据,则认为数据包已经结束。

使用特权

评论回复
12
eefas| | 2024-5-12 13:46 | 只看该作者
可以使用环形缓冲区来存储从UART接收到的数据。然后,你可以定期检查缓冲区中的数据量,并在数据量达到某个阈值时处理数据。

使用特权

评论回复
13
Bowclad| | 2024-5-12 20:24 | 只看该作者
这个用空闲中断就可以了。新版的hal库里提供了

使用特权

评论回复
14
hilahope| | 2024-5-13 20:45 | 只看该作者
以配置DMA以将接收到的数据直接传输到内存中的某个区域,并在数据传输完成后触发一个中断。

使用特权

评论回复
15
maudlu| | 2024-5-14 13:13 | 只看该作者
在中断服务例程(ISR)中检查接收到的字节是否为结束标记。如果是,就停止接收并将数据保存到缓冲区中。

使用特权

评论回复
16
updownq| | 2024-5-15 08:48 | 只看该作者
使用DMA可以显著提高数据接收的效率和速度,但也需要更多的设置和配置工作。

使用特权

评论回复
17
抹茶妹妹| | 2024-7-30 20:31 | 只看该作者
空闲帧(IDLE frame)通常指的是串口通信中的空闲状态,即在串口接收线上连续一段时间没有接收到数据时的状态。

使用特权

评论回复
18
我爱台妹mmd| | 2024-7-31 23:12 | 只看该作者
在处理串口通信时,特别是在接收端,通常需要检测空闲帧来判断一个完整的数据帧是否接收完毕。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2028

主题

15903

帖子

14

粉丝