串口卡死在USART1_IRQHandler原因分析

文章描述了一块电机控制板在供电和下载程序时遇到卡死现象,原因在于串口中断时同时触发了LIN中断。通过修改USART1_IRQHandler函数清除LIN中断标志位后解决了问题,提醒注意外部干扰和功能复用可能导致的此类问题。

问题描述:使用的是一块220V供电的电机控制板。当用JLINK下载程序、供电时,可以点亮LED正常运行。此时供上220V电,程序表现出卡死现象。

打断点调试程序发现上电瞬间接收到一个串口数据,继续全速运行,发现虽然进入USART1_IRQHandler,但并没有触发RXNE,程序以很快的速度执行USART1_IRQHandler,导致出现卡死现象。

void USART1_IRQHandler(void)
{
	if(LL_USART_IsActiveFlag_RXNE_RXFNE(USART1) && LL_USART_IsEnabledIT_RXNE_RXFNE(USART1))
   {
		  mrx_data = LL_USART_ReceiveData8(USART1); //只有上电瞬间才执行到这里
	}
}

 查看串口ISR寄存器,最终发现LBDF: LIN break detection flag,触发了LIN检测中断。

 

因为使用的这块板子串口复用了很多功能,包括:串口、LIN、PWM调速、0--10V调速,虽然用宏定义来选择了功能,但把串口和LIN的初始化放在一起了,导致串口中断里面触发了LIN中断但没有清除标志位。

void MX_USART1_UART_Init(void)
{
  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  LL_USART_InitTypeDef USART_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

  /** Initializes the peripherals clocks
  */
  PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
  PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }

  /* Peripheral clock enable */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);

  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
  /**USART1 GPIO Configuration
  PB6   ------> USART1_TX
  PB7   ------> USART1_RX
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_6;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_7;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_0;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN USART1_Init 1 */

  /* USER CODE END USART1_Init 1 */
  USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
  USART_InitStruct.BaudRate = 4800;
  USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B;
  USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
  USART_InitStruct.Parity = LL_USART_PARITY_NONE;
  USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
  USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
  USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
  LL_USART_Init(USART1, &USART_InitStruct);
  LL_USART_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
  LL_USART_SetRXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
  LL_USART_DisableFIFO(USART1);
  LL_USART_DisableOverrunDetect(USART1);
  LL_USART_DisableDMADeactOnRxErr(USART1);
  LL_USART_ConfigAsyncMode(USART1);

  /* USER CODE BEGIN WKUPType USART1 */

  /* USER CODE END WKUPType USART1 */
  LL_USART_SetLINBrkDetectionLen(USART1,LL_USART_LINBREAK_DETECT_11B);
	LL_USART_EnableLIN(USART1);
  LL_USART_Enable(USART1);

  /* Polling USART1 initialisation */
  while((!(LL_USART_IsActiveFlag_TEACK(USART1))) || (!(LL_USART_IsActiveFlag_REACK(USART1))))
  {
  }
  /* USER CODE BEGIN USART1_Init 2 */
  LL_USART_EnableIT_RXNE_RXFNE(USART1);
	LL_USART_EnableIT_LBD(USART1);  //使能了LIN中断
  /* USER CODE END USART1_Init 2 */

}

做如下修改,清除中断标志位即可。

void USART1_IRQHandler(void)
{
	if(LL_USART_IsActiveFlag_RXNE_RXFNE(USART1) && LL_USART_IsEnabledIT_RXNE_RXFNE(USART1))
     {
		mrx_data = LL_USART_ReceiveData8(USART1);
	 }
	if(LL_USART_IsActiveFlag_LBD(USART1)!=RESET)//LIN中断检测标志
	{
       LL_USART_ClearFlag_LBD(USART1);
	}
}

很多时候因为干扰,一直触发外部中断、串口一直有干扰数据;或者一个口复用多个功能时,同一时刻使用了两个功能,等等,都会出现类似现象,注意排查。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值