[STM32] Ejemplo de programa RTC

00. Tabla de contenido

01. Introducción al reloj RTC

Comparado con STM32F1, el reloj en tiempo real (RTC) de STM32F4 ha mejorado mucho, con una función de calendario El RTC de STM32F4 es un temporizador / contador BCD independiente. El RTC proporciona un reloj calendario (que incluye información sobre el año, mes, día, hora, minuto y segundo), dos alarmas programables (ALARMA A y ALARMA B) interrupciones y una
bandera de activación periódica programable con función de interrupción . El RTC también contiene una unidad de activación automática para administrar los modos de bajo consumo.

Dos registros de 32 bits (TR y DR) contienen el segundo, minuto, hora (formato de 12 o 24 horas), día de la semana, fecha, mes y año en formato decimal binario (BCD). Además, también se pueden proporcionar valores inferiores a un segundo en formato binario.

El RTC del STM32F4 puede compensar automáticamente el número de días del mes a 28, 29 (año bisiesto), 30 y 31 días. Y también puede compensar el horario de verano.

El módulo RTC y la configuración del reloj se encuentran en el área de respaldo, es decir, la configuración y el tiempo del RTC permanecen sin cambios después de que el sistema se reinicia o se activa desde el modo de espera. Mientras el área de respaldo esté alimentada normalmente, el RTC continuará funcionando. Sin embargo, después de reiniciar el sistema, el acceso al registro de respaldo y RTC se prohíbe automáticamente para evitar operaciones de escritura accidentales en el área de respaldo (BKP). Por lo tanto, antes de configurar la hora, cancele la protección contra escritura del área de respaldo (BKP).

02. Diseño de hardware

Los recursos de hardware utilizados son:
1) Luz indicadora DS0
2) Puerto serie
3) Módulo TFTLCD
4) RTC

03. Pasos de configuración del calendario de RTC

①Habilitar el reloj PWR: RCC_APB1PeriphClockCmd ();

② Habilite el acceso al registro de respaldo: PWR_BackupAccessCmd ()

③ Configure la fuente de reloj RTC y habilite el reloj RTC:

RCC_RTCCLKConfig ();

RCC_RTCCLKCmd ();

Si usa LSE, abra LSE: RCC_LSEConfig (RCC_LSE_ON);

④ Inicializar RTC (coeficiente de división de frecuencia sincrónica / asincrónica y formato de reloj): RTC_Init ();

⑤ Establecer hora: RTC_SetTime ();

⑥ Establecer fecha: RTC_SetDate ();

04. Ejemplo de configuración y obtención de fecha

rtc.h

#ifndef __RTC_H__
#define __RTC_H__

#include "sys.h"

//RTC初始化
u8 MY_RTC_Init(void);

//RTC时间设置
ErrorStatus RTC_Set_Time(u8 hour, u8 min, u8 sec, u8 ampm);

//RTC日期设置
ErrorStatus RTC_Set_Date(u8 year, u8 mon, u8 day, u8 week);

#endif /*__RTC_H__*/

rtc.c

#include "rtc.h"
#include "delay.h"


//RTC时间设置
ErrorStatus RTC_Set_Time(u8 hour, u8 min, u8 sec, u8 ampm)
{
    
    
	RTC_TimeTypeDef RTC_TimeStruct;
	RTC_TimeStruct.RTC_H12 = ampm;
	RTC_TimeStruct.RTC_Hours = hour;
	RTC_TimeStruct.RTC_Minutes = min;
	RTC_TimeStruct.RTC_Seconds = sec;

	return RTC_SetTime(RTC_Format_BIN,&RTC_TimeStruct);
}

//RTC日期设置
ErrorStatus RTC_Set_Date(u8 year, u8 mon, u8 day, u8 week)
{
    
    
	RTC_DateTypeDef RTC_DateStruct;
	
	RTC_DateStruct.RTC_Year = year;
	RTC_DateStruct.RTC_Month = mon;
	RTC_DateStruct.RTC_Date = day;
	RTC_DateStruct.RTC_WeekDay = week;

	return RTC_SetDate(RTC_Format_BIN, &RTC_DateStruct);
}

//RTC初始化
u8 MY_RTC_Init(void)
{
    
    
	u16 retry = 0x1fff;
	
	RTC_InitTypeDef RTC_InitStruct;

	//使能PWR时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
	
	//使能后备寄存器访问
	PWR_BackupAccessCmd(ENABLE);
	
	//判断是否第一次初始化
	if (RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x8080)
	{
    
    
	
		//开启LSE
		RCC_LSEConfig(RCC_LSE_ON);
		//等待LSE准备就绪
		while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
		{
    
    
			retry++;
			delay_ms(10);
		}
		
		//开始LSE失败
		if (0 ==  retry)
		{
    
    
			return 1;
		}
		
		//设置RTC时钟为LSE
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
		
		//使能RTC时钟
		RCC_RTCCLKCmd(ENABLE);
		
		//初始化RTC
		RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24;
		RTC_InitStruct.RTC_AsynchPrediv = 0x7F;
		RTC_InitStruct.RTC_SynchPrediv = 0xFF;
		
		RTC_Init(&RTC_InitStruct);
		
		//设置时间
		RTC_Set_Time(16, 06, 50, RTC_H12_AM);
		
		//设置日期
		RTC_Set_Date(20, 9, 9, RTC_Weekday_Wednesday);
		
		//标记已经初始化
		RTC_WriteBackupRegister(RTC_BKP_DR0, 0x8080);
		
	}

	return 0;
}

C Principal

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "beep.h"
#include "key.h"
#include "usmart.h"
#include "lcd.h"
#include "rtc.h"

//LED状态设置函数
void led_set(u8 sta)
{
    
    
	LED1 = sta;
}

//函数参数调用测试函数
void test_fun(void(*ledset)(u8), u8 sta)
{
    
    
	ledset(sta);
}

int main(void)
{
    
     
	u8 buf[40];
	u8 t = 0;
	
	RTC_TimeTypeDef RTC_TimeStruct;
	RTC_DateTypeDef RTC_DateStruct;
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	
	delay_init(168);
	
	uart_init(115200);
	
	usmart_dev.init(84);
	
	LED_Init();
	LCD_Init();
	
	//RTC初始化
	MY_RTC_Init();
	
	
	POINT_COLOR = RED;
	
	LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");	
	LCD_ShowString(30,70,200,16,16,"USMART TEST");	
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2020/09/09");	 
	
	while(1)
	{
    
    
		t++;
		
		//每隔100ms更新显示
		if (0 == t % 10)
		{
    
    
			RTC_GetTime(RTC_Format_BIN, &RTC_TimeStruct);
			sprintf((char*)buf, "Time: %02d:%02d:%02d", RTC_TimeStruct.RTC_Hours, RTC_TimeStruct.RTC_Minutes, RTC_TimeStruct.RTC_Seconds);
			LCD_ShowString(30, 140, 210, 16, 16, buf);
			
			
			RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct);
			sprintf((char*)buf, "Date: 20%02d-%02d-%02d", RTC_DateStruct.RTC_Year, RTC_DateStruct.RTC_Month, RTC_DateStruct.RTC_Date);
			LCD_ShowString(30, 160, 210, 16, 16, buf);
			
			sprintf((char*)buf, "Week: %d", RTC_DateStruct.RTC_WeekDay);
			LCD_ShowString(30, 180, 210, 16, 16, buf);		
			
		}
		
		
		if (0 == t % 20)
		{
    
    
			LED1 = !LED1;
		}
		
		//睡眠10毫秒
		delay_ms(10);
	}
}

05. Ejemplo de configuración de interrupción de alarma

//设置闹钟时间(按星期闹铃,24小时制)
//week:星期几(1~7) @ref  RTC_Alarm_Definitions
//hour,min,sec:小时,分钟,秒钟
void RTC_Set_AlarmA(u8 week,u8 hour,u8 min,u8 sec)
{
    
    
	RTC_TimeTypeDef RTC_TimeStruct;
	
	RTC_AlarmTypeDef RTC_AlarmStruct;
	
	EXTI_InitTypeDef EXTI_InitStruct;
	
	NVIC_InitTypeDef NVIC_InitStruct;
	
	
	//关闭闹钟A
	RTC_AlarmCmd(RTC_Alarm_A, DISABLE);
	
	//设置闹钟参数
	RTC_TimeStruct.RTC_H12 = RTC_H12_AM;
	RTC_TimeStruct.RTC_Hours = hour;
	RTC_TimeStruct.RTC_Minutes = min;
	RTC_TimeStruct.RTC_Seconds = sec;
	
	
	RTC_AlarmStruct.RTC_AlarmTime = RTC_TimeStruct;
	RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_None;
	RTC_AlarmStruct.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_WeekDay;
	RTC_AlarmStruct.RTC_AlarmDateWeekDay = week;
	
	RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A, &RTC_AlarmStruct);

	//清除闹钟A的中断标志
	RTC_ClearITPendingBit(RTC_IT_ALRA);
	//清除中断线17上的中断标志
	EXTI_ClearITPendingBit(EXTI_Line17);
	
	//开启闹钟A中断
	RTC_ITConfig(RTC_IT_ALRA, ENABLE);
	
	//开启闹钟
	RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
	
	//初始化中断
	EXTI_InitStruct.EXTI_Line = EXTI_Line17;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_Init(&EXTI_InitStruct);
	
	//初始化中断优先级
	NVIC_InitStruct.NVIC_IRQChannel = RTC_Alarm_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =  0x2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x2;
	NVIC_Init(&NVIC_InitStruct);
}

//闹钟中断处理函数
void RTC_Alarm_IRQHandler(void)
{
    
    
	if (RTC_GetFlagStatus(RTC_FLAG_ALRAF) == SET)
	{
    
    
		RTC_ClearFlag(RTC_FLAG_ALRAF);
		printf("ALARM A!\r\n");
	}
	
	//清中断
	EXTI_ClearITPendingBit(EXTI_Line17);	
}

06. Ejemplo de configuración de la interrupción del despertador


//周期性唤醒定时器设置  
/*wksel:  @ref RTC_Wakeup_Timer_Definitions
#define RTC_WakeUpClock_RTCCLK_Div16        ((uint32_t)0x00000000)
#define RTC_WakeUpClock_RTCCLK_Div8         ((uint32_t)0x00000001)
#define RTC_WakeUpClok_RTCCLK_Div4         ((uint32_t)0x00000002)
#define RTC_WakeUpClock_RTCCLK_Div2         ((uint32_t)0x00000003)
#define RTC_WakeUpClock_CK_SPRE_16bits      ((uint32_t)0x00000004)
#define RTC_WakeUpClock_CK_SPRE_17bits      ((uint32_t)0x00000006)
*/
//cnt:自动重装载值.减到0,产生中断.
void RTC_Set_WakeUp(u32 wksel,u16 cnt)
{
    
    
		
	EXTI_InitTypeDef EXTI_InitStruct;
	
	NVIC_InitTypeDef NVIC_InitStruct;
	
	//关闭WakeUP
	RTC_WakeUpCmd(DISABLE);
	
	//配置WakeUP时钟分频系数或者来源
	RTC_WakeUpClockConfig(wksel);
	
	//设置WakeUP自动装载值
	RTC_SetWakeUpCounter(cnt);
	
	//清除中断标志
	RTC_ClearITPendingBit(RTC_IT_WUT);
	//清除中断线17上的中断标志
	EXTI_ClearITPendingBit(EXTI_Line22);
	
	//开启WakeUP中断
	RTC_ITConfig(RTC_IT_WUT, ENABLE);
	
	//使能WakeUp
	RTC_WakeUpCmd(ENABLE);
	
		//初始化中断
	EXTI_InitStruct.EXTI_Line = EXTI_Line22;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_Init(&EXTI_InitStruct);
	
	//初始化中断优先级
	NVIC_InitStruct.NVIC_IRQChannel = RTC_WKUP_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority =  0x2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0x2;
	NVIC_Init(&NVIC_InitStruct);


}


//唤醒中断处理函数
void RTC_WKUP_IRQHandler(void)
{
    
    
	if (RTC_GetFlagStatus(RTC_FLAG_WUTF) == SET)
	{
    
    
		RTC_ClearFlag(RTC_FLAG_WUTF);
		LED2 = !LED2;
	}
	
	//清中断
	EXTI_ClearITPendingBit(EXTI_Line22);	

}

07. Apéndice

7.1 [STM32] Resumen del tutorial de la serie STM32

Sitio web: [STM32] Resumen del tutorial de la serie STM32

08. Declaración

Este tutorial hace referencia a la "Guía de desarrollo STM32 F4" de Punctual Atom

Supongo que te gusta

Origin blog.csdn.net/dengjin20104042056/article/details/108493983
Recomendado
Clasificación