新随笔  :: 联系 :: 订阅 订阅  :: 管理

MDK:Keil v5.38/STM32CubeMX

MCU:STM32G431CBUx

外设:串口USART1

初始化部分

static 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_PCLK2;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
  {
    Error_Handler();
  }

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

  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOA);
  /**USART1 GPIO Configuration
  PA9   ------> USART1_TX
  PA10   ------> USART1_RX
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
  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_7;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
  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_7;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN USART1_Init 1 */
  
    /* USART1 interrupt Init */
  NVIC_SetPriority(USART1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),2, 1));
  NVIC_EnableIRQ(USART1_IRQn);
  
    /* USER CODE END USART1_Init 1 */
  USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
  USART_InitStruct.BaudRate = 115200;
  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_ConfigAsyncMode(USART1);

  /* USER CODE BEGIN WKUPType USART1 */

  /* USER CODE END WKUPType 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 */

  /* USER CODE END USART1_Init 2 */

}

串口接收数据结构体,设置标志位,表示空闲中断工作状态

 struct RxData_Via_UART{
    unsigned char RxBuffer[200];
    uint8_t RxPointer;  //接收数据指针
    uint8_t RxIDLECounter;  //当长时间(空闲一个字节)没有从串口接收到数据时,认为一帧接收结束
    uint32_t RxLength;   //接收数据帧长度
    volatile uint8_t RxFrameEnd;  //帧结束标注
    uint32_t RxCmd;//四字节接收到的命令字段
};

 extern struct RxData_Via_UART CMD_RxDataViaUSART1;

 

中断服务函数

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
        USART1_RXIdleCallback();
  /* USER CODE END USART1_IRQn 0 */
  /* USER CODE BEGIN USART1_IRQn 1 */
    
  /* USER CODE END USART3_IRQn 1 */
}

接收不定长数据函数;

调试过程中发现系统上电后会自动进入一次IDLE中断,所以将使能IDLE中断写入服务函数中,保证初始化时不进入一次IDLE中断

void USART1_RXIdleCallback(void)
{
   uint8_t res_usart1;
     //接收中断
     if(LL_USART_IsActiveFlag_RXNE(USART1))
        {
        res_usart1=LL_USART_ReceiveData8(USART1);
        CMD_RxDataViaUSART1.RxBuffer[CMD_RxDataViaUSART1.RxLength++]=res_usart1;
        CMD_RxDataViaUSART1.RxIDLECounter=0;    
        LL_USART_EnableIT_IDLE(USART1);
        LL_USART_ClearFlag_IDLE(USART1);//发现上电会进一次IDLE中断,所以将使能中断写在这里
            
        }
        //空闲中断
    if(LL_USART_IsActiveFlag_IDLE(USART1))
        {
        LL_USART_ClearFlag_IDLE(USART1);
        
        CMD_RxDataViaUSART1.RxIDLECounter=1;    
        LL_USART_DisableIT_IDLE(USART1);
        }
}

通过在主程序while(1)循环中检测标志位是否改变来判断是否介绍不定长数据帧,进入命令帧解析程序

 while (1)
  {
        while(Timer2ReadyFlag==0);
        Timer2ReadyFlag = 0;//定时器中断,用于定期执行功能
        /*other code*/

                /* USART1 get Data CODE */
        if((CMD_RxDataViaUSART1.RxIDLECounter==1))
        {
            USART1_CmdJudge();
        }
        
  }