串口卡死在USART1_IRQHandler原因分析

问题描述:使用的是一块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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1. 在stm32cubemx中配置串口参数 首先,打开stm32cubemx软件,新建一个工程,选择需要使用的芯片型号,并进行初始化配置。 在Pinout & Configuration选项卡中,选择USART1,然后在右侧的Configuration栏中配置串口参数,如下图所示: ![image](https://user-images.githubusercontent.com/57706581/129364710-0b0ec9cd-7e6c-4e05-8d0c-6b7ee6e5c8b7.png) 其中,Baud Rate设置为115200,Data Bits为8,Stop Bits为1,Parity为None,Flow Control为None。 在Project Manager选项卡中,点击GENERATE CODE按钮生成代码。 2. 使用USART1串口,采用中断接收数据 在生成的代码中,找到main.c文件,在main函数中添加以下代码: ``` /* USER CODE BEGIN 2 */ HAL_UART_Receive_IT(&huart1, RxData, 1); /* USER CODE END 2 */ ``` 这段代码的作用是启动USART1串口的中断接收功能,当接收到数据时,会触发中断,并执行中断处理函数。 在stm32cubeIDE中,中断处理函数的名称为USART1_IRQHandler,在stm32cubemx生成的代码中已经定义了该函数,我们只需要在该函数中添加处理接收数据的代码即可。 在USART1_IRQHandler函数中添加以下代码: ``` void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ if (__HAL_UART_GET_IT(&huart1, UART_IT_RXNE) != RESET) { uint8_t data; HAL_UART_Receive(&huart1, &data, 1, 0xFFFF); // 处理接收到的数据 } /* USER CODE END USART1_IRQn 1 */ } ``` 其中,__HAL_UART_GET_IT函数用于判断是否接收到了数据,如果接收到了数据,则调用HAL_UART_Receive函数接收数据,并进行处理。 3. 使用DMA方式发送数据 在stm32cubemx生成的代码中,已经默认启用了DMA方式发送数据,我们只需要在main函数中添加以下代码即可: ``` /* USER CODE BEGIN 4 */ uint8_t TxData[] = "Hello World!\r\n"; HAL_UART_Transmit_DMA(&huart1, TxData, sizeof(TxData)); /* USER CODE END 4 */ ``` 这段代码的作用是启动USART1串口的DMA发送功能,将TxData数组中的数据发送出去。 至此,我们已经完成了使用USART1串口,采用中断接收数据,使用DMA方式发送数据的配置代码。完整代码如下: ``` #include "main.h" #include "stm32f1xx_hal.h" #include "usart.h" #include "gpio.h" uint8_t RxData[1]; void SystemClock_Config(void); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ HAL_UART_Receive_IT(&huart1, RxData, 1); uint8_t TxData[] = "Hello World!\r\n"; HAL_UART_Transmit_DMA(&huart1, TxData, sizeof(TxData)); /* USER CODE END 2 */ while (1) { } } void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ /* USER CODE END USART1_IRQn 0 */ HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ if (__HAL_UART_GET_IT(&huart1, UART_IT_RXNE) != RESET) { uint8_t data; HAL_UART_Receive(&huart1, &data, 1, 0xFFFF); // 处理接收到的数据 } /* USER CODE END USART1_IRQn 1 */ } void Error_Handler(void) { } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值