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. 串口初始化
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. 中断回调函数也要处理
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. 刚拿到硬件可以用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. 在使用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配置

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