• stm32 串口不通调试总结


    先贴上代码做参考

    1. 管脚初始化
    void HAL_UART_MspInit(UART_HandleTypeDef* huart)
    {
      GPIO_InitTypeDef GPIO_InitStruct = {0};
      if(huart->Instance==USART2)
      {
      /* USER CODE BEGIN USART2_MspInit 0 */
    
      /* USER CODE END USART2_MspInit 0 */
        /* Peripheral clock enable */
        __HAL_RCC_USART2_CLK_ENABLE();
    
        __HAL_RCC_GPIOA_CLK_ENABLE();
        /**USART2 GPIO Configuration
        PA2     ------> USART2_TX
        PA3     ------> USART2_RX
        */
        GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
        /* USART2 interrupt Init */
        HAL_NVIC_SetPriority(USART2_IRQn, 0, 0);
        HAL_NVIC_EnableIRQ(USART2_IRQn);
      /* USER CODE BEGIN USART2_MspInit 1 */
    
      /* USER CODE END USART2_MspInit 1 */
      }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    1. 串口初始化
    void MX_USART2_UART_Init(void)
    {
    
      /* USER CODE BEGIN USART2_Init 0 */
    
      /* USER CODE END USART2_Init 0 */
    
      /* USER CODE BEGIN USART2_Init 1 */
    
      /* USER CODE END USART2_Init 1 */
      huart2.Instance = USART2;
      huart2.Init.BaudRate = 9600;
      huart2.Init.WordLength = UART_WORDLENGTH_8B;
      huart2.Init.StopBits = UART_STOPBITS_1;
      huart2.Init.Parity = UART_PARITY_NONE;
      huart2.Init.Mode = UART_MODE_TX_RX;
      huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
      huart2.Init.OverSampling = UART_OVERSAMPLING_16;
      huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
      huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
      huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
      if (HAL_UART_Init(&huart2) != HAL_OK)
      {
        Error_Handler();
      }
      /* USER CODE BEGIN USART2_Init 2 */
    
      /* USER CODE END USART2_Init 2 */
      HAL_UART_Receive_IT(&huart2, (uint8_t *)&rx_buf, 1);        // 中断接收,要先调用下
      //HAL_UART_Receive_DMA(&huart2, (uint8_t *)&rx_buf, 10);    // dma接收,要先调用下
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    1. 中断回调函数也要处理
    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
      /* Prevent unused argument(s) compilation warning */
       UNUSED(huart);
      /* NOTE: This function Should not be modified, when the callback is needed,
               the HAL_UART_TxCpltCallback could be implemented in the user file
       */
    	if(huart == &huart2){
    		HAL_UART_Receive_IT(&huart2, (uint8_t *)&rx_buf, 1);   // 这个函数会开启中断,不调用下次中断就不会触发
    		ecbm_modbus_rtu_receive(rx_buf[0]);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    说明

    1. 刚拿到硬件可以用stm32mx生产串口测试程序,程序尽量的简单,排除软件问题干扰,看硬件是否有问题,先排除简单常见的软硬件问题
    2. 波特率是否匹配,这个问题基本上都能想到
    3. I/O配置是否正确,串口时钟和II/O口时钟是否打开
    4. 对于中断接收和dma接收,要先调用下接收函数,以开启中断,否则中断不会触发
    5. 485通讯,不通时检测使能脚位电压,发送为高电平,接收为低电平,看I/O是否配对,是否有效
    6. 收到数据第一个字节为0,可以考虑485通信近距离加了中断匹配电阻,或者发送端帧与帧之间间隔太短,导致接收溢出标志位置1
    7. dma发送时,在数据为发送完之前要保证内存有效,发送函数通常使用栈空间,或者堆管理,调用发送函数后,马上函数返回或者释放内存,这时dma还没发送完成,会导致错误,rtos中可以给点线程阻塞时间,或者使用非dma方式发送
    8. 使用jlink打印日志,使用过程中发现,栈太小导致串口无法接收数据,线程没有挂掉,这时线程栈为256个字节,改为512个字节正常,因此使用SEGGER_RTT_printf,注意栈要开大点,否则容易导致各种莫名其妙的问题
    /**
      * @brief 线程的入口函数
      * @param None
      * @retval None
    */
    static void sys_task_entry(void *parameter)
    {
    	void ecbm_modbus_rtu_set_data(uint8_t dat);
    	uint32_t val = 0;
    	while(1)
    	{
    		rt_thread_delay(1000);
    		val = _74hc_165_read();
    		SEGGER_RTT_printf(0, RTT_CTRL_BG_BLACK"%08x\n", val & 0xff);   // 栈要大点,改了配置文件后256也不行,原始文件栈可能需求更大
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1. 在使用stm32h7 过程中发现,出现波特率低为1200时,串口通信乱码,解决方案,串口时钟源频率太高,将其降低正常
      改在这里插入图片描述改上面箭头的地方,更换时钟源想办法降低频率
    2. 在使用dma时,注意单片机内部有的内存区是dma不能访问的,这些区域通常速度较快,只供内核访问
    3. 软件排查完后,硬件问题可能是管脚TX,RX反了,这个出现频率较高, 量下485芯片电压,信号线上电阻是否焊接对,如串联在信号线上的保护电阻用为10k的上拉电阻,单片接TX,RX管脚烧了,485芯片烧了
    4. 排查问题是可以用串口工具如ch340 rt232等接rx到板子上的信号测试点开是否有数据,以确定硬件是否有问题
    5. 电平不匹配,这种问题一般较少现在的芯片很多都是5v兼容3.3.v,但不排除个别特例
    6. 如果有隔离模块,串口较快,考虑隔离模块速度是否跟的上
    7. cortex-m 内核中开启数据缓存,使用dma要注意数据一致性问题,具体可参考我的另一篇文章rt-thread 中stm32h7 dma mpu配置
  • 相关阅读:
    go语言并发实战——日志收集系统(七) etcd的介绍与简单使用
    1.2继承性
    【每日一题】9.13 PING是怎么工作的?
    【mysql 统计表里面6个月的数据】
    大学生网页设计制作作业实例代码 (全网最全,建议收藏) HTML+CSS+JS
    油气大数据平台建设案例分享,让油田数据同步效率提升20%的解决方案
    【Unity编辑器扩展】| GameView面板扩展
    电商平台促销管理功能解析,数商云S2B2C商城系统开启日化行业数字零售新模式
    LeetCode经典面试150题-day3(删除有序数组的重复项)
    C 语言超全练习题(一): 初识C语言
  • 原文地址:https://blog.csdn.net/qq_34492122/article/details/126548271