OpenEdv-开源电子网

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

串口+DMA接收有问题怎么办

[复制链接]

4

主题

7

帖子

0

精华

新手上路

积分
35
金钱
35
注册时间
2023-10-18
在线时间
8 小时
发表于 2024-10-4 16:16:52 | 显示全部楼层 |阅读模式
5金钱

串口+DMA数据传输。经过排查,发送没有问题,接收数据出现问题?各位大佬这种情况是怎么回事
这是主函数接收代码

这是串口+DMA代码
/*-------------------------------------------------*/
/*            超子说物联网STM32系列开发板          */
/*-------------------------------------------------*/
/*                                                 */
/*            实现各个串口功能的源文件             */
/*                                                 */
/*-------------------------------------------------*/


#include "stm32f4xx_hal.h"    //包含需要的头文件
#include "usart.h"            //包含需要的头文件
#include "sys.h"




USART_ControlCB UART1_ControlCB;            //串口1控制结构体
uint8_t  U1_TxBuff[U1_TXBUFF_SIZE];         //定义一个数组缓冲区,串口1发送缓冲区


USART_ControlCB UART2_ControlCB;            //串口2控制结构体
uint8_t  U2_TxBuff[U2_TXBUFF_SIZE];         //定义一个数组缓冲区,串口2发送缓冲区
uint8_t  U2_RxBuff[U2_RXBUFF_SIZE];         //定义一个数组缓冲区,串口2发接收冲区


/*-------------------------------------------------*/
/*函数名:初始化串口1                              */
/*参  数:bound:波特率                            */
/*返回值:无                                       */
/*-------------------------------------------------*/
void U1_Init(uint32_t bound)
{       
        UART1_ControlCB.USART_Handler.Instance=USART1;                                                //指定使用第几个串口
        UART1_ControlCB.USART_Handler.Init.BaudRate=bound;                                        //设置波特率
        UART1_ControlCB.USART_Handler.Init.WordLength=UART_WORDLENGTH_8B;       //设置字长为8位数据格式
        UART1_ControlCB.USART_Handler.Init.StopBits=UART_STOPBITS_1;                //设置一个停止位
        UART1_ControlCB.USART_Handler.Init.Parity=UART_PARITY_NONE;                        //设置无奇偶校验位
        UART1_ControlCB.USART_Handler.Init.Mode=UART_MODE_TX;                            //设置发模式
        UART1_ControlCB.USART_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;       //设置无硬件流控
        HAL_UART_Init(&UART1_ControlCB.USART_Handler);                                        //设置串口
}
/*-------------------------------------------------*/
/*函数名:初始化串口2                              */
/*参  数:bound:波特率                            */
/*返回值:无                                       */
/*-------------------------------------------------*/
void U2_Init(uint32_t bound)
{       
        UART2_ControlCB.USART_Handler.Instance=USART2;                                                //指定使用第几个串口
        UART2_ControlCB.USART_Handler.Init.BaudRate=bound;                                        //设置波特率
        UART2_ControlCB.USART_Handler.Init.WordLength=UART_WORDLENGTH_8B;       //设置字长为8位数据格式
        UART2_ControlCB.USART_Handler.Init.StopBits=UART_STOPBITS_1;                //设置一个停止位
        UART2_ControlCB.USART_Handler.Init.Parity=UART_PARITY_NONE;                        //设置无奇偶校验位
        UART2_ControlCB.USART_Handler.Init.Mode=UART_MODE_TX_RX;                        //设置收发模式
        UART2_ControlCB.USART_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;       //设置无硬件流控
        HAL_UART_Init(&UART2_ControlCB.USART_Handler);                                        //设置串口
        HAL_UART_Receive_IT(&UART2_ControlCB.USART_Handler,U2_RxBuff,U2_RXBUFF_SIZE);
        u2_BuffInit();                                                          //初始化串口2收发缓冲区以及各个指针
}
/*-------------------------------------------------*/
/*函数名:串口1的底层初始化                        */
/*参  数:huart:串口配置句柄                      */
/*返回值:无                                       */
/*说  明:此函数会被HAL_UART_Init()回调调用        */
/*-------------------------------------------------*/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{  
        GPIO_InitTypeDef GPIO_Initure;                 //GPIO端口设置变量
       
        if(huart->Instance==USART1){                   //如果配置的是串口1,则进入改if分支,进行串口1的底层初始化
                __HAL_RCC_GPIOA_CLK_ENABLE();                           //使能GPIOA时钟
                __HAL_RCC_USART1_CLK_ENABLE();                           //使能串口1时钟
               
                GPIO_Initure.Pin = GPIO_PIN_9|GPIO_PIN_10; //准备设置PA9 10
                GPIO_Initure.Mode = GPIO_MODE_AF_PP;       //复用功能
                GPIO_Initure.Pull = GPIO_PULLUP;           //上拉
                GPIO_Initure.Alternate = GPIO_AF7_USART1;  //PA9 10复用为串口1的TXD RXD功能
                HAL_GPIO_Init(GPIOA, &GPIO_Initure);       //设置PA9 10           
        }
       
        if(huart->Instance==USART2){                    //如果配置的是串口2,则进入改if分支,进行串口1的底层初始化
                __HAL_RCC_GPIOA_CLK_ENABLE();                            //使能GPIOA时钟
                __HAL_RCC_USART2_CLK_ENABLE();                            //使能串口2时钟
               
                GPIO_Initure.Pin = GPIO_PIN_2|GPIO_PIN_3;   //准备设置PA2 3
                GPIO_Initure.Mode = GPIO_MODE_AF_PP;        //复用功能
                GPIO_Initure.Pull = GPIO_PULLUP;            //上拉
                GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;


                GPIO_Initure.Alternate = GPIO_AF7_USART2;   //PA2 3复用为串口2的TXD RXD功能
                HAL_GPIO_Init(GPIOA, &GPIO_Initure);        //设置PA2 3
               
                HAL_NVIC_SetPriority(USART2_IRQn,0,2);      //设置串口2中断的抢占优先级为0,子优先级是2,但是要注意,G0系列中断子优先级不会生效
                HAL_NVIC_EnableIRQ(USART2_IRQn);            //使能串口2的中断
                __HAL_RCC_DMA1_CLK_ENABLE();                //使能DMA1时钟
               
                UART2_ControlCB.USART_TxDMA.Instance                 = DMA1_Stream6;               //DMA1通道1
                UART2_ControlCB.USART_TxDMA.Init.Channel                                                 = DMA_CHANNEL_4;
                UART2_ControlCB.USART_TxDMA.Init.Direction           = DMA_MEMORY_TO_PERIPH;        //存储区到外设
                UART2_ControlCB.USART_TxDMA.Init.PeriphInc           = DMA_PINC_DISABLE;            //外设不递增
                UART2_ControlCB.USART_TxDMA.Init.MemInc              = DMA_MINC_ENABLE;             //存储区递增
                UART2_ControlCB.USART_TxDMA.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;         //按字节存取
                UART2_ControlCB.USART_TxDMA.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;         //按字节存取
                UART2_ControlCB.USART_TxDMA.Init.Mode                = DMA_NORMAL;                  //正常模式
                UART2_ControlCB.USART_TxDMA.Init.Priority            = DMA_PRIORITY_HIGH;           //高优先级
                UART2_ControlCB.USART_TxDMA.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
                UART2_ControlCB.USART_TxDMA.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
                UART2_ControlCB.USART_TxDMA.Init.MemBurst            = DMA_MBURST_SINGLE;
                UART2_ControlCB.USART_TxDMA.Init.PeriphBurst         = DMA_PBURST_SINGLE;
                HAL_DMA_Init(&UART2_ControlCB.USART_TxDMA);                                         //配置
                __HAL_LINKDMA(huart, hdmatx, UART2_ControlCB.USART_TxDMA);                          //和串口2 DMA发送连接
               
                UART2_ControlCB.USART_RxDMA.Instance                 = DMA1_Stream5;               //DMA1通道2
                UART2_ControlCB.USART_RxDMA.Init.Channel                                                 = DMA_CHANNEL_4;
                UART2_ControlCB.USART_RxDMA.Init.Direction           = DMA_PERIPH_TO_MEMORY;        //外设到存储区
                UART2_ControlCB.USART_RxDMA.Init.PeriphInc           = DMA_PINC_DISABLE;            //外设不递增
                UART2_ControlCB.USART_RxDMA.Init.MemInc              = DMA_MINC_ENABLE;             //存储区递增
                UART2_ControlCB.USART_RxDMA.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;         //按字节存取
                UART2_ControlCB.USART_RxDMA.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;         //按字节存取
                UART2_ControlCB.USART_RxDMA.Init.Mode                = DMA_NORMAL;                  //正常模式
                UART2_ControlCB.USART_RxDMA.Init.Priority            = DMA_PRIORITY_HIGH;           //高优先级
                UART2_ControlCB.USART_RxDMA.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
                UART2_ControlCB.USART_RxDMA.Init.FIFOThreshold       = DMA_FIFO_THRESHOLD_FULL;
                UART2_ControlCB.USART_RxDMA.Init.MemBurst            = DMA_MBURST_SINGLE;
                UART2_ControlCB.USART_RxDMA.Init.PeriphBurst         = DMA_PBURST_SINGLE;
                HAL_DMA_Init(&UART2_ControlCB.USART_RxDMA);                                         //配置
                __HAL_LINKDMA(huart, hdmarx, UART2_ControlCB.USART_RxDMA);                          //和串口2 DMA接收连接


                HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 0, 0);                                     //配置DMA1 通道4的中断,优先级
                HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn);                                             //使能DMA1 通道4的中断


                HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 0, 0);                                   //配置DMA1 通道4的中断,优先级
                HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);                                           //使能DMA1 通道4的中断            
        }       
}
/*-------------------------------------------------*/
/*函数名:串口1 printf函数                         */
/*参  数:fmt,...  格式化输出字符串和参数          */
/*返回值:无                                       */
/*-------------------------------------------------*/
void u1_printf(char* fmt,...)
{  
        uint16_t i;           
        va_list ap;
        va_start(ap,fmt);
        vsprintf((char *)U1_TxBuff,fmt,ap);
        va_end(ap);
       
        while(__HAL_UART_GET_FLAG(&UART1_ControlCB.USART_Handler,UART_FLAG_TC)!=SET);           //等待串口1发送空闲,然后才能发送数据       
        for(i = 0;i < strlen((const char*)U1_TxBuff);i ++){                                                   //利用for循环,一个字节,一个字节的发送
                UART1_ControlCB.USART_Handler.Instance->DR = U1_TxBuff;                    //把需要发送的字节,填充到串口1,启动发送
                while(__HAL_UART_GET_FLAG(&UART1_ControlCB.USART_Handler,UART_FLAG_TC)!=SET);  //等待本次字节发送结束,才可以发送下一个字节       
        }       
}
void u2_printf(char* fmt,...)
{  
        uint16_t i;           
        va_list ap;
        va_start(ap,fmt);
        vsprintf((char *)U2_TxBuff,fmt,ap);
        va_end(ap);
       
        while(__HAL_UART_GET_FLAG(&UART2_ControlCB.USART_Handler,UART_FLAG_TC)!=SET);           //等待串口2发送空闲,然后才能发送数据       
        for(i = 0;i < strlen((const char*)U2_TxBuff);i ++){                                                   //利用for循环,一个字节,一个字节的发送
                UART2_ControlCB.USART_Handler.Instance->DR = U2_TxBuff;                    //把需要发送的字节,填充到串口2,启动发送
                while(__HAL_UART_GET_FLAG(&UART2_ControlCB.USART_Handler,UART_FLAG_TC)!=SET);  //等待本次字节发送结束,才可以发送下一个字节       
        }       
}
/*----------------------------------------------------------*/
/*函数名:初始化串口2收发缓冲区以及各个指针                 */
/*参  数:无                                                */
/*返回值:无                                                */
/*----------------------------------------------------------*/
void u2_BuffInit(void)
{       
        UART2_ControlCB.UsartTxDataInPtr  = &UART2_ControlCB.Usart_TxLocation[0];           //发送缓冲区 In插入指针归位到 位置结构体数组0号成员   
        UART2_ControlCB.UsartTxDataOutPtr =  UART2_ControlCB.UsartTxDataInPtr;              //发送缓冲区 Out提取指针归位到 In插入指针位置
    UART2_ControlCB.UsartTxDataEndPtr = &UART2_ControlCB.Usart_TxLocation[TX_NUM-1];    //发送缓冲区 End结尾标记指针归位到 位置结构体数组最后1个成员
        UART2_ControlCB.UsartTxDataInPtr->StartPtr = U2_TxBuff;                                    //In插入指向的数据成员 start指针指向发送缓冲区起始位置
        UART2_ControlCB.Usart_TxCounter = 0;                                                //累计发送缓冲区存放的数据量=0
        UART2_ControlCB.Usart_TxCpltflag = 0;                                               //发送空闲
       
        UART2_ControlCB.UsartRxDataInPtr  = &UART2_ControlCB.Usart_RxLocation[0];           //接收缓冲区 In插入指针归位到 位置结构体数组0号成员   
        UART2_ControlCB.UsartRxDataOutPtr =  UART2_ControlCB.UsartRxDataInPtr;              //接收缓冲区 Out提取指针归位到 In插入指针位置   
    UART2_ControlCB.UsartRxDataEndPtr = &UART2_ControlCB.Usart_RxLocation[RX_NUM-1];    //接收缓冲区 End结尾标记指针归位到 位置结构体数组最后1个成员
        UART2_ControlCB.UsartRxDataInPtr->StartPtr = U2_RxBuff;                             //In插入指向的数据成员 start指针指向接收缓冲区起始位置
        UART2_ControlCB.Usart_RxCounter = 0;                                                //累计接收缓冲区存放的数据量=0
       
        HAL_UART_Receive_DMA(&UART2_ControlCB.USART_Handler,UART2_ControlCB.UsartRxDataInPtr->StartPtr,U2_RXMAX_SIZE);    //设置DMA接收 指定接收位置  
        __HAL_UART_CLEAR_IDLEFLAG(&UART2_ControlCB.USART_Handler);                                                        //清除空闲中断标志                                                                                                                
        __HAL_UART_ENABLE_IT(&UART2_ControlCB.USART_Handler, UART_IT_IDLE);                                               //打开空闲中断
}
/*-------------------------------------------------*/
/*函数名:串口2发送数据                            */
/*参  数:data:数据                               */
/*参  数:len:数据量                              */
/*返回值:无                                       */
/*-------------------------------------------------*/
void u2_TxData(uint8_t *data, uint16_t len)
{  
        uint16_t i;                                                               
       
        while(__HAL_UART_GET_FLAG(&UART2_ControlCB.USART_Handler,UART_FLAG_TC)!=SET);      //等待串口2发送空闲,然后才能发送数据       
        for(i=0;i<len;i++){                                                                       //循环一个一个字节的发送       
                UART2_ControlCB.USART_Handler.Instance->DR = data;                         //把需要发送的字节,填充到串口2,启动发送
                while(__HAL_UART_GET_FLAG(&UART2_ControlCB.USART_Handler,UART_FLAG_TC)!=SET);  //等待串口2发送空闲,然后才能发送数据       
        }
       
}
/*----------------------------------------------------------*/
/*函数名:向发送缓冲区添加数据                              */
/*参  数:databuff:数据                                    */
/*参  数:datalen:数据长度                                 */
/*返回值:无                                                */
/*----------------------------------------------------------*/
void u2_TxDataBuf(uint8_t *databuff, uint32_t datalen)
{
        if(U2_TXBUFF_SIZE - UART2_ControlCB.Usart_TxCounter >= datalen){                                   //计算发送缓冲区内剩余的空间,还够不够存放本次的数据,够的话进入if
                UART2_ControlCB.UsartTxDataInPtr->StartPtr = &U2_TxBuff[UART2_ControlCB.Usart_TxCounter];           //标记本次存放数据的起始位置
        }else{                                                                                             //反之,不够存放本次的数据,进入else
                UART2_ControlCB.Usart_TxCounter = 0;                                                           //累计发送缓冲区存放的数据量清零
                UART2_ControlCB.UsartTxDataInPtr->StartPtr = U2_TxBuff;                                        //存放数据的起始位置重新设置到接收缓冲区的起始位置               
        }
        memcpy(UART2_ControlCB.UsartTxDataInPtr->StartPtr,databuff,datalen);                                   //拷贝数据            
    UART2_ControlCB.Usart_TxCounter += datalen;                                                               //计算累计发送缓冲区存放的数据量
        UART2_ControlCB.UsartTxDataInPtr->EndPtr = &U2_TxBuff[UART2_ControlCB.Usart_TxCounter];            //标记发送缓冲区本次存放的结束位置               
                               
        UART2_ControlCB.UsartTxDataInPtr++;                                                                //数据IN指针下移
        if(UART2_ControlCB.UsartTxDataInPtr==UART2_ControlCB.UsartTxDataEndPtr)                            //如果下移到End指针标记的结束位置,进入if
                UART2_ControlCB.UsartTxDataInPtr = &UART2_ControlCB.Usart_TxLocation[0];                       //发送缓冲区 In插入指针归位到 位置结构体数组0号成员   
}
/*----------------------------------------------------------*/
/*函数名:中止接收完成回调函数                              */
/*参  数:huart:串口配置句柄                               */
/*返回值:无                                                */
/*----------------------------------------------------------*/
void HAL_UART_AbortReceiveCpltCallback(UART_HandleTypeDef *huart)
{  
        if(huart->Instance==USART2){                                                                                          //判断是串口几的回调
                UART2_ControlCB.UsartRxDataInPtr->EndPtr = &U2_RxBuff[UART2_ControlCB.Usart_RxCounter];                                     //标记本次接收的结束位置               
                UART2_ControlCB.UsartRxDataInPtr++;                                                                               //接收缓冲区数据IN指针下移
                if(UART2_ControlCB.UsartRxDataInPtr==UART2_ControlCB.UsartRxDataEndPtr)                                           //如果指针下移到结尾标志指针的时候,进入if
                        UART2_ControlCB.UsartRxDataInPtr = &UART2_ControlCB.Usart_RxLocation[0];                                      //接收缓冲区 In插入指针归位到 位置结构体数组0号成员                  
                if(U2_RXBUFF_SIZE - UART2_ControlCB.Usart_RxCounter >= U2_RXMAX_SIZE){                                            //计算,如果剩余空间大于 单次接收的数据量 进入if
                        UART2_ControlCB.UsartRxDataInPtr->StartPtr = &U2_RxBuff[UART2_ControlCB.Usart_RxCounter];                     //记录下次接收的起始位置       
                }else{                                                                                                            //如果剩余空间不够单次接收量 进入else
                        UART2_ControlCB.Usart_RxCounter = 0;                                                                          //累计接收缓冲区存放的数据量清空
                        UART2_ControlCB.UsartRxDataInPtr->StartPtr = U2_RxBuff;                                                       //接收位置,重新回到缓冲区的起始位置               
                }
                HAL_UART_Receive_DMA(&UART2_ControlCB.USART_Handler,UART2_ControlCB.UsartRxDataInPtr->StartPtr,U2_RXMAX_SIZE);    //设置新一次的 DMA接收 指定接收位置                 
        }       
}
/*----------------------------------------------------------*/
/*函数名:数据接收完成回调函数                              */
/*参  数:huart:串口配置句柄                               */
/*返回值:无                                                */
/*----------------------------------------------------------*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance==USART2){                                                                                          //判断是串口几的回调
                UART2_ControlCB.Usart_RxCounter += U2_RXMAX_SIZE;                                                                 //累计当前缓冲区已经存放的数据量                               
                UART2_ControlCB.UsartRxDataInPtr->EndPtr = &U2_RxBuff[UART2_ControlCB.Usart_RxCounter];                                     //标记本次接收的结束位置               
                UART2_ControlCB.UsartRxDataInPtr++;                                                                               //接收缓冲区数据IN指针下移
                if(UART2_ControlCB.UsartRxDataInPtr==UART2_ControlCB.UsartRxDataEndPtr)                                           //如果指针下移到结尾标志指针的时候,进入if
                        UART2_ControlCB.UsartRxDataInPtr = &UART2_ControlCB.Usart_RxLocation[0];                                      //接收缓冲区 In插入指针归位到 位置结构体数组0号成员                  
                if(U2_RXBUFF_SIZE - UART2_ControlCB.Usart_RxCounter >= U2_RXMAX_SIZE){                                            //计算,如果剩余空间大于 单次接收的数据量 进入if
                        UART2_ControlCB.UsartRxDataInPtr->StartPtr = &U2_RxBuff[UART2_ControlCB.Usart_RxCounter];                     //记录下次接收的起始位置       
                }else{                                                                                                            //如果剩余空间不够单次接收量 进入else
                        UART2_ControlCB.Usart_RxCounter = 0;                                                                          //累计接收缓冲区存放的数据量清空
                        UART2_ControlCB.UsartRxDataInPtr->StartPtr = U2_RxBuff;                                                       //接收位置,重新回到缓冲区的起始位置               
                }
                HAL_UART_Receive_DMA(&UART2_ControlCB.USART_Handler,UART2_ControlCB.UsartRxDataInPtr->StartPtr,U2_RXMAX_SIZE);     //设置新一次的 DMA接收 指定接收位置                 


        }       
}
/*----------------------------------------------------------*/
/*函数名:数据发送完成回调函数                              */
/*参  数:huart:串口配置句柄                               */
/*返回值:无                                                */
/*----------------------------------------------------------*/
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
        if(huart->Instance==USART2){                         //判断是串口几的回调
                UART2_ControlCB.Usart_TxCpltflag = 0;            //发送空闲       
        }
}

1-正常传输模式 数据透传(节点板程序).zip

14.1 MB, 下载次数: 0

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

使用道具 举报

11

主题

2103

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
4588
金钱
4588
注册时间
2015-1-10
在线时间
574 小时
发表于 2024-10-8 16:26:25 | 显示全部楼层
描述一下问题啊,直接贴代码大家可没那么多时间给你一点点顺
回复

使用道具 举报

4

主题

7

帖子

0

精华

新手上路

积分
35
金钱
35
注册时间
2023-10-18
在线时间
8 小时
 楼主| 发表于 2024-10-9 09:37:43 | 显示全部楼层

stm32通过lora定点传输,左图发送端,右图接收端。实验现象:发送一次,数据分两次接收。然后就是我上面描述的问题,发送并没有问题,接收数据的时候分包,并且接收完补了三个0。
屏幕截图 2024-10-09 093017.png
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-25 06:15

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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