STM32L051 HAL库非DMA模式使用空闲中断接收不定长数据

STM32L051 HAL库非DMA模式使用空闲中断接收不定长数据

因项目中的上位机与单片机之间的通信协议采用非标准协议,上位机发送的数据长度不定,因此在网上查询相关的解决方法,但查询的结果,网上讨论的利用空闲模式接收不定长数据的方法,都是基于DMA接收的,个人项目因为有低功耗需要,平时是在停机模式,在唤醒后才能接收数据,所以考虑非DMA接收方式,经过调试,试验成功,将代码记录下来。

  • 实现的功能
    实验完成的代码功能包括STM32L051的低功耗串口LPUART1初始化、中断接收,Printf打印函数,利用空闲中断实现不定长数据接收;RTC时钟配置、闹钟配置等功能

  • 开发环境
    利用STSTM32CubeMX向导,生成初始化函数,使用KEIL编绎:

  1. 系统时钟配置:RTC使用外部LSE晶振,主时钟使用内部HSI,开启PLL,SYSCLK配置为32MHz,LPUART时钟源使用LSE。STM32L051 HAL库非DMA模式使用空闲中断接收不定长数据_第1张图片
  2. RTC配置:开启RTC,开启闹钟A,外部校准关闭,RTC唤醒关闭。 STM32L051 HAL库非DMA模式使用空闲中断接收不定长数据_第2张图片
  3. LPUART配置: STM32L051 HAL库非DMA模式使用空闲中断接收不定长数据_第3张图片
  4. 代码向导输出配置,使用HAL库:
    STM32L051 HAL库非DMA模式使用空闲中断接收不定长数据_第4张图片
  • 部分函数修改
    因为STM32CubeMX向导生成的初始化函数默认是没开启空闲中断功能的,所以需要修改部分初始化函数。
    1.LPUART初始化函数中,增加开启接收中断和空闲中断
/**
* @brief UART MSP Initialization
* This function configures the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(huart->Instance==LPUART1)
  {
  /* USER CODE BEGIN LPUART1_MspInit 0 */

  /* USER CODE END LPUART1_MspInit 0 */
    /* Peripheral clock enable */
    __HAL_RCC_LPUART1_CLK_ENABLE();
    __HAL_RCC_GPIOC_CLK_ENABLE();
    /**LPUART1 GPIO Configuration    
    PC4     ------> LPUART1_TX
    PC5     ------> LPUART1_RX 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF2_LPUART1;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

    /* LPUART1 interrupt Init */
    HAL_NVIC_SetPriority(LPUART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(LPUART1_IRQn);
  /* USER CODE BEGIN LPUART1_MspInit 1 */
	 __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
  __HAL_UART_ENABLE_IT(huart, UART_IT_IDLE);
  /* USER CODE END LPUART1_MspInit 1 */
  }
}

2.修改LPUART中断接收函数,屏蔽原向导生成的中断处理函数 HAL_UART_IRQHandler(&hlpuart1)

/**
  * @brief This function handles LPUART1 global interrupt / LPUART1 wake-up interrupt through EXTI line 28.
  */
void LPUART1_IRQHandler(void)
{
  /* USER CODE BEGIN LPUART1_IRQn 0 */
  /* USER CODE END LPUART1_IRQn 0 */
//  HAL_UART_IRQHandler(&hlpuart1);
  /* USER CODE BEGIN LPUART1_IRQn 1 */
if(__HAL_UART_GET_FLAG(&hlpuart1, UART_FLAG_RXNE) != RESET)  
    { 
        __HAL_UART_CLEAR_FLAG(&hlpuart1, UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_PEF | UART_CLEAR_FEF);
			if(LPUart1_End_flage == 0)
			{
			  LPUart1_RX_BUF[LPUart1_REC_Cnt] = LPUART1->ISR;    
        LPUart1_RX_BUF[LPUart1_REC_Cnt] = LPUART1->RDR;    
        LPUart1_REC_Cnt++;
				if(LPUart1_REC_Cnt > LPUart1_BUF_SIZE) 
					LPUart1_REC_Cnt =0;	
			}
  }
  else if(__HAL_UART_GET_FLAG(&hlpuart1,UART_FLAG_IDLE) == SET)
    {
			 __HAL_UART_CLEAR_IDLEFLAG(&hlpuart1);
//       	printf("UART IT For IDEL \r\n");
        LPUart1_End_flage = 1;
        LPUart1_REC_SIZE = LPUart1_REC_Cnt;
        LPUart1_REC_Cnt = 0;
   }        
  /* USER CODE END LPUART1_IRQn 1 */
}

3.修改闹钟配置函数,这里我设置为闹钟每小时激活一次。
**注意**这个闹钟设置:AlarmMask的意思是屏蔽相应的参数为无效,代码里闹钟时间设置成了1:30:20,如果要在每天的1:30:20闹钟动作,则sAlarm.AlarmMask = RTC_ALARMMASK_NONE,表示闹钟时间严格匹配设置的时间,因为我这里设置每小时的30分20秒闹钟动作,所以需要屏蔽RTC_ALARMMASK_DATEWEEKDAYRTC_ALARMMASK_HOURS,代码修改为sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS

/** Enable the Alarm A 
  */
  sAlarm.AlarmTime.Hours = 1;
  sAlarm.AlarmTime.Minutes = 30;
  sAlarm.AlarmTime.Seconds = 20;
  sAlarm.AlarmTime.SubSeconds = 0;
  sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY|RTC_ALARMMASK_HOURS;//|RTC_ALARMMASK_MINUTES|RTC_ALARMMASK_SECONDS;
  sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_NONE;
  sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  sAlarm.AlarmDateWeekDay = 1;
  sAlarm.Alarm = RTC_ALARM_A;
  if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
  {
    Error_Handler();
  }

4.测试代码

while (1)
  {
		if(LPUart1_End_flage == 1)
		{
			HAL_RTC_GetTime(&hrtc, &stimestructure, RTC_FORMAT_BIN);
            HAL_RTC_GetDate(&hrtc, &sdatestructure, RTC_FORMAT_BIN);
//			printf("\r\n%02d/%02d/%02d\r\n",2000 + sdatestructure.Year, sdatestructure.Month, sdatestructure.Date);
//      printf("%02d:%02d:%02d\r\n",stimestructure.Hours, stimestructure.Minutes, stimestructure.Seconds);
			for(i=0;i< LPUart1_REC_SIZE;i++)
			printf("%.2x",LPUart1_RX_BUF[i]);
//			printf("\r\n");
			LPUart1_End_flage = 0;
		}
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

5.测试结果
STM32L051 HAL库非DMA模式使用空闲中断接收不定长数据_第5张图片

完整工程下载

链接: 完整工程下载.

你可能感兴趣的:(STM32)