问题描述:使用的是一块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);
}
}
很多时候因为干扰,一直触发外部中断、串口一直有干扰数据;或者一个口复用多个功能时,同一时刻使用了两个功能,等等,都会出现类似现象,注意排查。