找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1126|回复: 6
收起左侧

关于MCU USART-DMA数据传输的一个bug请教

[复制链接]
ID:644357 发表于 2023-4-28 15:59 | 显示全部楼层 |阅读模式
问题描述:奇怪的MCU bug
16进制给板子发送数据
比如:
串口助手:发-04 03 01 02 03 0A C5 98
板子          收-04 03 01 02 03 0A C5 98
就能完成的完成数据传输
但是发
发-04 03 00 00 00 0A C5 98时


收到的就是
收-04 03 00 00 00 00 00 00

数据流收发没问题,但是只要是00,就会把后面的数据给抹掉
串口中断:
  1. void USART1_IRQHandler(void)
  2. {
  3.     OSIntEnter();

  4.     HAL_UART_IRQHandler(&huart1);

  5.         user_uart1IT_ReceiveCallback();
  6.    
  7.     OSIntExit();
  8. }

  9. void user_uart1IT_ReceiveCallback(void)
  10. {
  11.         uint8_t temp;
  12.         if((__HAL_UART_GET_FLAG(UART_DEBUG, UART_FLAG_IDLE) != RESET))  //获取IDLE标志位,idle标志被置位
  13.         {
  14.                 __HAL_UART_CLEAR_IDLEFLAG(&huart1);                                                                                                                //清除空闲中断标志位
  15.                 HAL_UART_DMAStop(UART_DEBUG);                                                                                                                                        //停止串口DMA功能
  16.                
  17.                 temp = huart1.hdmarx->Instance->CNDTR;                                                                                                //得到当前还剩余多少个数据
  18.                 uartDMA_data.bits.recive_count = BUFFER_SIZE - temp;                                        //接收数据计数
  19.                
  20.                 uartDMA_data.bits.interrupt_idle = ON;                                                                                                // 接受完成标志位置1        
  21.                
  22.         }
  23. }
复制代码
数据接收服务,放在一个5ms定时一次的定时器中断里
  1. void USART1DMA_rx_service(void)
  2. {
  3.    
  4.     /*在72MHZ系统时钟工况下,此函数运行时间为无空闲中断0.78ms-0.81ms;
  5.                                              有空闲中断,需要处理 运行时间为72.114ms*/

  6.     /*将此接收服务判定函数置于中断中,有较小概率产生数据丢包BUG*/
  7.     /*此任务函数置于定时中断中,进行循环检测*/
  8.     if(uartDMA_data.bits.interrupt_idle == ON)                //有空闲中断
  9.     {
  10.         uartDMA_data.bits.interrupt_idle = OFF;

  11.         /*加入临界段保护-----------------------------------------------------------------------------------------------------------------*/
  12.         CPU_SR_ALLOC();
  13.         CPU_CRITICAL_ENTER();  
  14.         
  15.         memset(uartDMA_data.bits.uart_buffer, 0, sizeof(uartDMA_data.bits.uart_buffer));                                    //清除缓存数据数组
  16.         memcpy(uartDMA_data.bits.uart_buffer, uartDMA_data.bits.rx_buffer, strlen((char *)uartDMA_data.bits.rx_buffer));    //取出数据
  17.         memset(uartDMA_data.bits.rx_buffer, 0, sizeof(uartDMA_data.bits.rx_buffer));                                        //清空数组
  18.         HAL_UART_Receive_DMA(UART_DEBUG, uartDMA_data.bits.rx_buffer, sizeof(uartDMA_data.bits.rx_buffer));                 //重新启动串口DMA功能
  19.         
  20.         CPU_CRITICAL_EXIT();
  21.          /*加入临界段保护-----------------------------------------------------------------------------------------------------------------*/
  22.         
  23.         if((DEBUG_USART_ENABLE==1)&&(Modbus_ENABLE==0)){
  24.             /*测试模式,向PC发送接收到的数据*/
  25.             
  26.         }
  27.         if((Modbus_ENABLE==1)&&(DEBUG_USART_ENABLE==0)){     /*进入MODBUS通讯模式*/
  28.             
  29.             uint8_t icnt;
  30.             /*空闲中断发生,将DMA接收缓存数据转存至MODBUS数据缓存中*/
  31.             Modbus_data_len =  uartDMA_data.bits.recive_count;
  32.             //HAL_UART_Transmit_DMA(UART_DEBUG, (uint8_t *)uartDMA_data.bits.uart_buffer, strlen((char *)uartDMA_data.bits.uart_buffer));        //打印接收到的数据
  33.             ModbusbuffAllow = 0;    //modbus缓存写保护
  34.             for(icnt=0;icnt<Modbus_data_len;icnt++)
  35.             {
  36.                 modbus_Rx_buff[icnt] = uartDMA_data.bits.uart_buffer[icnt];
  37.             }
  38.             
  39.             ModbusbuffAllow = 1;    //modbus缓存解除写保护
  40.             /*数据已经写入modbus缓存*/
  41.             //HAL_UART_Transmit_DMA(UART_DEBUG,modbus_Rx_buff,Modbus_data_len);
  42.         }
  43.         
  44.         
  45. //                Debug_Printf(UART_DEBUG, "\r\n*******************************串口 DMA方式接收打印如下 *****************************\r\n ");         HAL_Delay(100);
  46. //                        
  47. //                        Debug_Printf(UART_DEBUG, "\r\n HAL_UART_Transmit_DMA 库函数打印\t:");         HAL_Delay(100);
  48. //                        HAL_UART_Transmit_DMA(UART_DEBUG, (uint8_t *)uartDMA_data.bits.uart_buffer, strlen((char *)uartDMA_data.bits.uart_buffer));        //打印接收到的数据
  49. //                        HAL_Delay(100);
  50. //                        Debug_Printf(UART_DEBUG, "\r\nDebug_Printf函数打印数组\t\t:");                                         HAL_Delay(100);
  51. //                        Debug_Printf(UART_DEBUG, (char *)uartDMA_data.bits.uart_buffer);        
  52. //                        HAL_Delay(100);
  53. //                        Debug_Printf(UART_DEBUG, "\r\nDebug_Printf函数打印字符\t\t:");                                         HAL_Delay(100);
  54. //                        Debug_Printf(UART_DEBUG, "uart MDA Debug printf function");
  55. //                        HAL_Delay(100);
  56. //                        Debug_Printf(UART_DEBUG, "\r\nDebug_Printf函数打印串口接收计数值\t:");                                         HAL_Delay(100);
  57. //                        Debug_Printf(UART_DEBUG, "recive_count: %d\r\n", uartDMA_data.bits.recive_count);
  58.     }
  59. }
复制代码

源码奉上: test.7z (818.38 KB, 下载次数: 4)
回复

使用道具 举报

ID:77589 发表于 2023-5-4 11:38 | 显示全部楼层
估计问题出在这里了:
memcpy(uartDMA_data.bits.uart_buffer, uartDMA_data.bits.rx_buffer, strlen((char *)uartDMA_data.bits.rx_buffer));    //取出数据
你是不熟悉strlen这个函数的用法,它是用于获取字符串长度的,再想想,字符串是以什么结尾的?是不是'\0',这个东西转成熟悉的十六进制是为是0x00?,所以遇到0x00就已经表示字符串结束了,后面的字节理所当然的就被抛弃了啊!
你不是在总线空闲中断处获取了接收数据长度么,直接用那个长度就好了。
回复

使用道具 举报

ID:644357 发表于 2023-4-28 17:30 | 显示全部楼层
初步查到问题是在HAL_UART_IRQHandler里,0x00会导致数据停止接收。
回复

使用道具 举报

ID:94031 发表于 2023-4-28 19:27 | 显示全部楼层
看来你是MODBUS协议没搞明白。
回复

使用道具 举报

ID:644357 发表于 2023-5-4 09:23 | 显示全部楼层
xuyaqi 发表于 2023-4-28 19:27
看来你是MODBUS协议没搞明白。

并不是,里面虽然有MODBUS的前置处理函数,问题并不在modbus里面,协议硬件部分是纯手撸的,HAL库的回调函数会把0x00判定为命令。停止接收。
回复

使用道具 举报

ID:644357 发表于 2023-5-4 11:27 | 显示全部楼层
  1.         memset(uartDMA_data.bits.uart_buffer, 0, sizeof(uartDMA_data.bits.uart_buffer));                                    //清除缓存数据数组
  2.         memcpy(uartDMA_data.bits.uart_buffer, uartDMA_data.bits.rx_buffer, strlen((char *)uartDMA_data.bits.rx_buffer));    //取出数据
  3.         memset(uartDMA_data.bits.rx_buffer, 0, sizeof(uartDMA_data.bits.rx_buffer));                                        //清空数组
  4.         HAL_UART_Receive_DMA(UART_DEBUG, uartDMA_data.bits.rx_buffer, sizeof(uartDMA_data.bits.rx_buffer));                 //重新启动串口DMA功能
  5.         
复制代码


问题已找到,strlen会把0x00识别为\0结束符,导致提前结束取出数据
回复

使用道具 举报

ID:644357 发表于 2023-5-5 09:15 | 显示全部楼层
Longan.Wang 发表于 2023-5-4 11:38
估计问题出在这里了:
memcpy(uartDMA_data.bits.uart_buffer, uartDMA_data.bits.rx_buffer, strlen((cha ...

大哥正解,通过这个BUG,感觉自己的C基础还有待提高
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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