【雅特力开发板 AT32F421 测评】2 . 外设ERTC的使用
[复制链接]
首先来介绍一下这个外设:
实时时钟 (ERTC) 是一个独立的 BCD 定时器/计数器。 ERTC 提供一个日历时钟、一个可编程闹钟中断。
两个 32 位寄存器包含二进码十进数格式 (BCD) 的秒、分钟、小时(12 或 24 小时制)、星期几、日期、
月份和年份。此外,还可提供二进制格式的亚秒值。
系统可以自动将月份的天数补偿为 28、 29(闰年)、 30 和 31 天。并且还可以进行夏令时补偿。
其它 32 位寄存器还包含可编程的闹钟亚秒、秒、分钟、小时、星期几和日期。
此外,还可以使用数字校准功能对晶振精度的偏差进行补偿。
上电复位后,所有 ERTC 寄存器都会受到保护,以防止可能的非正常写访问。
无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内, ERTC
便不会停止工作。
2. 它的特性如下:
ERTC的主要特性
● 包含亚秒、秒、分钟、小时( 12/24 小时制)、星期几、日期、月份和年份的日历。
● 软件可编程的夏令时补偿。
● 一个具有中断功能的可编程闹钟。可通过任意日历字段的组合驱动闹钟。
● 参考时钟检测:可使用更加精确的第二时钟源( 50 Hz 或 60 Hz)来提高日历的精确
度。
● 利用亚秒级移位特性与外部时钟实现精确同步。
● 可屏蔽中断/事件:
闹钟 A
时间戳
入侵检测
● 数字校准电路(周期性计数器调整 )
精度为 0.95 ppm,在数秒钟的校准窗口中获得
● 用于事件保存的时间戳功能( 1 个事件)
● 入侵检测:
1个带可配置过滤器和内部上拉的入侵事件
● 5 个备份寄存器( 20 字节 )。发生入侵检测事件时,将复位备份寄存器。
● 复用功能输出 (ERTC_OUT),可选择以下两个输出之一:
ERTC_CAL: 512 Hz 或 1 Hz 时钟输出( LSE 频率为 32.768 kHz)。可通过将
ERTC_CTRL 寄存器中的 CALOE[23] 位置 1 来使能此输出。该输出可连接到器
件 ERTC_AF1 功能。
ERTC_ALARM(闹钟 A)。 可通过配置 ERTC_CTRL 寄存器的 OSEL[1:0] 位
选择此输出。该输出可连接到器件 ERTC_AF1 功能。
● ERTC 复用功能输入:
ERTC_TS:时间戳事件检测。该输入可连接到器件 ERTC_AF1。
ERTC_TAMP: TAMPER 事件检测。该输入可连接到器件 ERTC_AF1。
ERTC_REFIN:参考时钟输入(通常为市电, 50 Hz 或 60 Hz)。
3.
官方给说明如下:
As an application example, it demonstrates how to setup the ERTC peripheral, in
terms of prescaler and interrupts, to be used to keep time and to generate
alarm interrupt.
One from the following clock can be used as ERTC clock source (uncomment the
corresponding define in main.c):
- LSE oscillator clock usually delivered by a 32.768 kHz quartz.
- LSI oscillator clock
The ERTC is in the backup (BKP) domain, still powered by VBAT when VDD is switched off,
so the ERTC configuration is not lost if a battery is connected to the VBAT pin.
A key value is written in backup data register 0 to indicate if the ERTC is already
configured.
首先,我们要初始化这个外设:
/**
* [url=home.php?mod=space&uid=159083]@brief[/url] Configure the ERTC peripheral by selecting the clock source.
* @param None
* @retval None
*/
static void ERTC_Config(void)
{
ERTC_DateType ERTC_DateStructure;
/* Enable the PWR clock */
RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_PWR, ENABLE);
/* Allow access to ERTC */
PWR_BackupAccessCtrl(ENABLE);
/* Reset ERTC Domain */
RCC_BackupResetCmd(ENABLE);
RCC_BackupResetCmd(DISABLE);
#if defined (ERTC_CLOCK_SOURCE_LSI) /* LSI used as ERTC source clock*/
/* The ERTC Clock may varies due to LSI frequency dispersion */
/* Enable the LSI OSC */
RCC_LSICmd(ENABLE);
/* Wait till LSI is ready */
while(RCC_GetFlagStatus(RCC_FLAG_LSISTBL) == RESET)
{
}
/* Select the ERTC Clock Source */
RCC_ERTCCLKConfig(RCC_ERTCCLKSelection_LSI);
/* ck_spre(1Hz) = ERTCCLK(LSI) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1)*/
uwSynchPrediv = 0xFF;
uwAsynchPrediv = 0x7F;
#elif defined (ERTC_CLOCK_SOURCE_LSE) /* LSE used as ERTC source clock */
/* Enable the LSE OSC */
RCC_LSEConfig(RCC_LSE_ENABLE);
/* Wait till LSE is ready */
while(RCC_GetFlagStatus(RCC_FLAG_LSESTBL) == RESET)
{
}
/* Select the ERTC Clock Source */
RCC_ERTCCLKConfig(RCC_ERTCCLKSelection_LSE);
/* ck_spre(1Hz) = ERTCCLK(LSE) /(uwAsynchPrediv + 1)*(uwSynchPrediv + 1)*/
uwSynchPrediv = 0xFF;
uwAsynchPrediv = 0x7F;
#endif /* ERTC_CLOCK_SOURCE_LSI */
/* Enable the ERTC Clock */
RCC_ERTCCLKCmd(ENABLE);
/* Wait for ERTC APB registers synchronisation */
ERTC_WaitForSynchro();
/* Configure the ERTC data register and ERTC prescaler */
ERTC_InitStructure.ERTC_AsynchPrediv = uwAsynchPrediv;
ERTC_InitStructure.ERTC_SynchPrediv = uwSynchPrediv;
ERTC_InitStructure.ERTC_HourFormat = ERTC_HourFormat_24;
ERTC_Init(&ERTC_InitStructure);
/* Set the alarm 05h:20min:10s */
ERTC_AlarmStructure.ERTC_AlarmTime.ERTC_AMPM = ERTC_H12_AM;
ERTC_AlarmStructure.ERTC_AlarmTime.ERTC_Hours = 5;
ERTC_AlarmStructure.ERTC_AlarmTime.ERTC_Minutes = 20;
ERTC_AlarmStructure.ERTC_AlarmTime.ERTC_Seconds = 10;
ERTC_AlarmStructure.ERTC_AlarmDateWeek = 11;
ERTC_AlarmStructure.ERTC_AlarmDateWeekSel = ERTC_AlarmDateWeekSel_Date;
ERTC_AlarmStructure.ERTC_AlarmMask = ERTC_AlarmMask_DateWeek;
/* Configure the ERTC Alarm A register */
ERTC_SetAlarmValue(ERTC_Format_BIN, ERTC_AlA, &ERTC_AlarmStructure);
/* Enable ERTC Alarm A Interrupt */
ERTC_INTConfig(ERTC_INT_ALA, ENABLE);
/* Enable the alarm */
ERTC_AlarmCmd(ERTC_AlA, ENABLE);
ERTC_ClearFlag(ERTC_FLAG_ALAF);
/* Set the date: Friday January 11th 2013 */
ERTC_DateStructure.ERTC_Year = 21;
ERTC_DateStructure.ERTC_Month = 4;
ERTC_DateStructure.ERTC_Date = 9;
ERTC_DateStructure.ERTC_WeekDay = 5;
ERTC_SetDateValue(ERTC_Format_BIN, &ERTC_DateStructure);
/* Set the time to 05h 20mn 00s AM */
ERTC_TimeStructure.ERTC_AMPM = ERTC_H12_AM;
ERTC_TimeStructure.ERTC_Hours = 5;
ERTC_TimeStructure.ERTC_Minutes = 20;
ERTC_TimeStructure.ERTC_Seconds = 0;
ERTC_SetTimeValue(ERTC_Format_BIN, &ERTC_TimeStructure);
/* Indicator for the ERTC configuration */
ERTC_WriteBackupRegister(ERTC_BKP_DT0, 0x32F1);
}
然后,每次上电后,就会判断备份寄存器中是否已经配置好时间,不需要每次上电后都进行配置:
我们的主函数如下:
int main(void)
{
NVIC_InitType NVIC_InitStructure;
EXTI_InitType EXTI_InitStructure;
int temp=0;
/* AT Board Initial */
AT32_Board_Init();
/* initialize UART1 */
UART_Print_Init(115200);
if (ERTC_ReadBackupRegister(ERTC_BKP_DT0) != 0x32F1)
{
/* ERTC configuration */
ERTC_Config();
}
else
{
/* Check if the Power On Reset flag is set */
if (RCC_GetFlagStatus(RCC_FLAG_PORST) != RESET)
{
/* Power On Reset occurred */
AT32_LEDn_ON(LED3);
}
/* Check if the Pin Reset flag is set */
else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
{
/* External Reset occurred */
AT32_LEDn_ON(LED4);
}
/* Enable the PWR clock */
RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_PWR, ENABLE);
/* Allow access to ERTC */
PWR_BackupAccessCtrl(ENABLE);
/* Wait for ERTC APB registers synchronisation */
ERTC_WaitForSynchro();
/* Clear the ERTC Alarm Flag */
ERTC_ClearFlag(ERTC_FLAG_ALAF);
/* Clear the EXTI Line 17 Pending bit (Connected internally to ERTC Alarm) */
EXTI_ClearIntPendingBit(EXTI_Line17);
}
/* ERTC Alarm A Interrupt Configuration */
/* EXTI configuration *******************************************************/
EXTI_ClearIntPendingBit(EXTI_Line17);
EXTI_InitStructure.EXTI_Line = EXTI_Line17;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineEnable = ENABLE;
EXTI_Init(&EXTI_InitStructure);
/* Enable the ERTC Alarm Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = ERTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
while (1)
{
ERTC_GetTimeValue(ERTC_Format_BIN, &ERTC_TimeStructure);
ERTC_GetDateValue(ERTC_Format_BIN, &ERTC_DateStructure);
if(temp != ERTC_TimeStructure.ERTC_Seconds)
{
temp = ERTC_TimeStructure.ERTC_Seconds;
/* Display time Format : hh:mm:ss */
printf("20%02d-%02d-%02d ", ERTC_DateStructure.ERTC_Year, ERTC_DateStructure.ERTC_Month, ERTC_DateStructure.ERTC_Date);
printf("%0.2d:%0.2d:%0.2d ", ERTC_TimeStructure.ERTC_Hours, ERTC_TimeStructure.ERTC_Minutes, ERTC_TimeStructure.ERTC_Seconds);
printf("week %d\r\n", ERTC_DateStructure.ERTC_WeekDay);
}
}
}
到此,我们的代码就写好了:
来,看看效果吧~
这个增强型RTC带有硬件日历的哦,比如,2月运行到了28号,会直接跳到3月1号,自动判断闰年。所以使用起来会方便很多呢。
最后附上工程源码。欢迎下载点评~
ERTC_Calendar_V1.0.0.zip
(981.22 KB, 下载次数: 23)
|