cubemx配置stm32f429IGTb, 实现阿波罗RTC实时时钟实验

一如既往的,将阿波罗的实验用cubemx配置实现。

实验一:利用前面RGB屏幕测试的实验,将RTC实时时间显示在屏幕上,每按下一次key0,刷新一次屏幕并显示最新时间。

1.使能RCC的LSE和RTC

2.配置时钟树

这里我之前就没有选上LSE,cubemx默认LSI,所以效果上会比正常时间慢一些。

3.配置RTC

这里需要注意的是,Data Format选择上,binary和BCD的区别,比如12点,binary的形式就是hours=12,而BCD则是hours=0x12.

此外,初始时间虽然设置上了,但不知道是哪里的问题,cubemx生成代码后并未帮我初始化上我设置的时间。明白的同学麻烦评论一下

4.生成代码,cubemx会帮你初始化好RTC,但是时间并未设置,还需要调用两个函数自行配置时间。

HAL_StatusTypeDef HAL_RTC_SetTime(RTC_HandleTypeDef *hrtc, RTC_TimeTypeDef *sTime, uint32_t Format);

HAL_StatusTypeDef HAL_RTC_SetDate(RTC_HandleTypeDef *hrtc, RTC_DateTypeDef *sDate, uint32_t Format);

值得注意的是,原子建议先设置时间再设置日期。这样时间上更贴近你的预期。

//RTC时间设置
//hour,min,sec:小时,分钟,秒钟
//ampm:@RTC_AM_PM_Definitions:RTC_HOURFORMAT12_AM/RTC_HOURFORMAT12_PM
//返回值:HAL_OK(0),成功
//       HAL_ERROR(1)
HAL_StatusTypeDef RTC_Set_Time(uint8_t hour, uint8_t min, uint8_t sec, uint8_t ampm)
{
	RTC_TimeTypeDef RTC_TimeStructure;
	
	RTC_TimeStructure.Hours=hour;
	RTC_TimeStructure.Minutes=min;
	RTC_TimeStructure.Seconds=sec;
	RTC_TimeStructure.TimeFormat=ampm;
	RTC_TimeStructure.DayLightSaving=RTC_DAYLIGHTSAVING_NONE;
        RTC_TimeStructure.StoreOperation=RTC_STOREOPERATION_RESET;
	return HAL_RTC_SetTime(&hrtc,&RTC_TimeStructure,RTC_FORMAT_BIN);	
}

//RTC日期设置
//year,month,date:年(0~99),月(1~12),日(0~31)
//week:星期(1~7,0,非法!)
//返回值:HAL_OK(0),成功
//       HAL_ERROR(1)
HAL_StatusTypeDef RTC_Set_Date(uint8_t year, uint8_t month, uint8_t date, uint8_t week)
{
	RTC_DateTypeDef RTC_DateStructure;
    
	RTC_DateStructure.Date=date;
	RTC_DateStructure.Month=month;
	RTC_DateStructure.WeekDay=week;
	RTC_DateStructure.Year=year;
	return HAL_RTC_SetDate(&hrtc,&RTC_DateStructure,RTC_FORMAT_BIN);
}

调用完时间和日期的设置后记得去掉,不然每次重新上电都会执行一遍。对此,cubemx的方法是利用备份域,备份域可在VDD电源关闭时通过VBAT保持上电状态,备份寄存器不会再系统复位或电源复位时复位,也不会再MCU从待机模式唤醒时复位。所以第一次设置好时间后就向备份区固定位置写上一个值,这样每次上电都判断一下,如果已经有这个值了就表明我设置过时间无需再次设置了。

 /**Initialize RTC and set the Time and Date */
  if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0) != 0x32F2)
  {
      if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
      {
        _Error_Handler(__FILE__, __LINE__);
      }

      if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
      {
        _Error_Handler(__FILE__, __LINE__);
      }

      HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0x32F2);
  }

5.RTC的时间和日期是分开的,在实际应用中我们如果合二为一使用起来更加方便

//rtc.h 定义结构体作为系统实时时间
typedef struct
{
	uint8_t Year;     /*!< Specifies the RTC Date Year.
                         This parameter must be a number between Min_Data = 0 and Max_Data = 99 */
	uint8_t Month;    /*!< Specifies the RTC Date Month (in BCD format).
                         This parameter can be a value of @ref RTC_Month_Date_Definitions */
	uint8_t Date;     /*!< Specifies the RTC Date.
                         This parameter must be a number between Min_Data = 1 and Max_Data = 31 */
	uint8_t WeekDay;  /*!< Specifies the RTC Date WeekDay.
                         This parameter can be a value of @ref RTC_WeekDay_Definitions */
	uint8_t Hours;    /*!< Specifies the RTC Time Hour.
						 This parameter must be a number between Min_Data = 0 and Max_Data = 12 if the RTC_HourFormat_12 is selected.
						 This parameter must be a number between Min_Data = 0 and Max_Data = 23 if the RTC_HourFormat_24 is selected  */
	uint8_t Minutes;  /*!< Specifies the RTC Time Minutes.
                         This parameter must be a number between Min_Data = 0 and Max_Data = 59 */
	uint8_t Seconds;  /*!< Specifies the RTC Time Seconds.
                         This parameter must be a number between Min_Data = 0 and Max_Data = 59 */

}RTC_RealTimeTypeDef;
extern RTC_RealTimeTypeDef gRealTime;

//rtc.c 由main.c不断调用,不断读取RTC更新这个结构体,在其他模块可直接使用
RTC_RealTimeTypeDef gRealTime;
void RTC_GetRealTime(void)
{
	RTC_TimeTypeDef RTC_TimeStruct;
        RTC_DateTypeDef RTC_DateStruct;
	HAL_RTC_GetTime(&hrtc,&RTC_TimeStruct,RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc,&RTC_DateStruct,RTC_FORMAT_BIN);
	gRealTime.Year 		= RTC_DateStruct.Year;
	gRealTime.Month		= RTC_DateStruct.Month;
	gRealTime.Date		= RTC_DateStruct.Date;
	gRealTime.WeekDay	= RTC_DateStruct.WeekDay;
	gRealTime.Hours		= RTC_TimeStruct.Hours;
	gRealTime.Minutes	= RTC_TimeStruct.Minutes;
	gRealTime.Seconds	= RTC_TimeStruct.Seconds;
	
}

6.最后,借用RGB屏的实验,将时间gRealTime显示在屏幕上

    POINT_COLOR=RED;	  
    LTDC_ShowString(10,40,260,32,32,	(uint8_t*)"Apollo STM32F4/F7"); 	
    LTDC_ShowString(10,80,240,24,24,	(uint8_t*)"LTDC TEST");
    LTDC_ShowString(10,110,240,16,16,	(uint8_t*)"ATOM@ALIENTEK");
    sprintf((char*)tbuf,"Date:20%02d-%02d-%02d",gRealTime.Year,gRealTime.Month,gRealTime.Date); 
    LTDC_ShowString(10,130,240,16,16,	(uint8_t*)tbuf);
    sprintf((char*)tbuf,"Time:%02d:%02d:%02d",gRealTime.Hours,gRealTime.Minutes,gRealTime.Seconds); 			                                                         
    LTDC_ShowString(10,150,240,12,12,	(uint8_t*)tbuf);

效果:

实验二:RTC的闹钟功能,原子实验的是AlarmA的星期闹钟,我觉得时间的闹钟更常用,每天的某时间进入一次AlarmA中断让LED1翻转电平。

1.使能AlarmA

2.配置AlarmA,分为五种掩码,掩码的意思是掩盖或忽略哪项,比如我要哪一小时、分钟、秒的闹钟,那么Alarm Mask Date Week day设置为使能,hours、minutes、seconds设置为失能,sub seconds设置为使能,效果就是忽略日期、亚秒,关注时分秒。也就是当11时1分0秒时闹钟中断。而如下图所示,当时间为0秒时闹钟中断,也就是每分钟触发一次中断。

week day sel的意思是闹钟选择的是日期还是星期(当然如果掩码设置为使能也就没用了),如果选择为星期,那么Alarm Date就是选择星期几,反之选择日期,那么Alarm Date选择的就是几号(并不能选择年月,我选择的是此项)。

3.开启中断,并配置优先级为1,子优先级为2.

4.然后生成代码,并重新定义闹钟中断的回调函数,执行LED1的翻转

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
	LED_Twinkle(1);
}

效果就是每分钟的0秒,LED1更换状态。非常简单和实用,比如每分钟发送一次分钟数据。

实验三:RTC的唤醒功能

1.使能唤醒功能

2.配置唤醒为1hz计数器值为0(一秒一次唤醒),若为1HZ计数器为1,那就是两秒一唤醒,count就是计数器的值,每一个周期减一,若为0则唤醒且重填计数器值。

3.使能中断,优先级为1,子优先级为3

4.之后生成代码,cubemx会将唤醒的初始化好,但是回调函数得自己写

我让他翻转一下LED1的状态

//RTC WAKE UP中断处理
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{
    LED_Twinkle(1);
}

效果:LED1一秒翻转一次


总结:最关键的是第一个实验,也就是初始化RTC和设置时间和读取时间。闹钟和唤醒有用但是不是必须。

之前都是用别人的底层,也没好好看RTC怎么来的,这次自己实现了心里就有底了。

发布了26 篇原创文章 · 获赞 0 · 访问量 2994

猜你喜欢

转载自blog.csdn.net/nianzhu2937/article/details/103627300