下面的程序根据固件库进行修改,变成自己想要的程序,包含RTC秒中断以及闹钟中断,由于嵌入式竞赛板没有外加晶振,所以使用内部低速时钟LSI
下面的程序不能进行年月计时,只能在一天之内进行计时,如果要进行长时间计时,那么就得考虑闰年,还要考虑一月是31,30还是29或28天。应对比赛来说就够了
(2018/1/22加)今天添加一点小窍门,利用数组对时间的时、分、秒进行
存储,这样就不用定义三个变量了,闹钟时间使用相同的方式比较好,这样写程序会更快;
配置步骤(原子教程)
1) 使能电源时钟和备份区域时钟。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//PWR是电池时钟
2) 取消备份区写保护。//原子点的视频有断电恢复断电时间的功能
PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后备寄存器访问
3) 复位备份区域,开启外部低速振荡器。
BKP_DeInit();//复位备份区域
RCC_LSEConfig(RCC_LSE_ON);// 开启外部低速振荡器
4) 选择 RTC 时钟,并使能。
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //选择 LSE 作为 RTC 时钟,
RCC_RTCCLKSource_LSI//选择的是低速时钟
RCC_RTCCLKSource_HSE_Div128// HSE 的 128 分频
5) 设置 RTC 的分频,以及配置 RTC 时钟。
在进行 RTC 配置之前首先要打开允许配置位(CNF),库函数是:
RTC_EnterConfigMode();/// 允许配置
在配置完成之后,千万别忘记更新配置同时退出配置模式,函数是:
RTC_ExitConfigMode();//退出配置模式, 更新配置
设置 RTC 时钟分频数, 库函数是:
void RTC_SetPrescaler(uint32_t PrescalerValue);
这个函数只有一个入口参数,就是 RTC 时钟的分频数,很好理解。
然后是设置秒中断允许, RTC 使能中断的函数是:
void RTC_ITConfig(uint16_t RTC_IT, FunctionalState NewState);
这个函数的第一个参数是设置秒中断类型,这些通过宏定义定义的。 对于使能秒中断方法是:
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC 秒中断
6) 更新配置,设置 RTC 中断分组。
在设置完时钟之后,我们将配置更新同时退出配置模式,这里还是通过 RTC_CRH 的 CNF
来实现。 库函数的方法是:
RTC_ExitConfigMode();//退出配置模式,更新配置
void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);//写入后备寄存器
7) 编写中断服务函数
void RTC_IRQHandler(void)
{
if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒中断
{
RTC_ClearITPendingBit(RTC_IT_SEC);//清除中断标志位
}
if(RTC_GetITStatus(RTC_IT_ALR)!=RESET)//闹钟中断
{
RTC_ClearITPendingBit(RTC_IT_ALR);
AlarmFlag = 1;
}
}
第六届省赛代码“电压测量监控设备”
#include "include.h"
#include "rtc.h"
#include "lcd.h"
#define HH 23 //时
#define MM 59 //分
#define SS 55 //秒
u32 THH = 0, TMM = 0, TSS = 0;
_Bool TimeDisplay = 0;
_Bool AlarmFlag = 0;//闹钟中断
/**
* @说明 配置RTC
* @参数 None
* @返回值 None
*/
void RTC_Configuration(void)
{
/* Enable PWR and BKP clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
RCC_LSICmd(ENABLE);
/* Wait till LSE is ready */
while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
/* Enable the RTC Second */
RTC_ITConfig(RTC_IT_SEC, ENABLE); //秒中断
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_ALR, ENABLE); //闹钟中断
RTC_WaitForLastTask();
/* Set RTC prescaler: set RTC period to 1sec */
RTC_SetPrescaler(39999); /* RTC period = RTCCLK/RTC_PR = (40 KHz)/(39999+1) */
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
RTC_SetCounter(HH*3600+MM*60+SS);//设置初始时间
RTC_WaitForLastTask();
RTC_SetAlarm(0); //设置闹钟时间
RTC_WaitForLastTask();
NVIC_Configuration();//中断优先级
}
/**
* @说明 显示当前时间
* @参数 TimeVar:RTC Counter值
* @返回值 None
*/
uint8_t text[20];
void Time_Display(u32 TimeVar)
{
/* 23:59:59 */
if (RTC_GetCounter() == 23*3600+59*60+59)
{
RTC_SetCounter(0x0);
RTC_WaitForLastTask();
}
/* Compute hours */
THH = TimeVar / 3600;
/* Compute minutes */
TMM = (TimeVar % 3600) / 60;
/* Compute seconds */
TSS = (TimeVar % 3600) % 60;
sprintf(text," T: %0.2d:%0.2d:%0.2d",THH, TMM, TSS);
LCD_DisplayStringLine(Line5,text);
}
/**
* @说明 配置中断向量控制器
* @参数 None
* @返回值 None
*/
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* Enable the RTC Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void RTC_IRQHandler(void)
{
if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒中断
{
RTC_ClearITPendingBit(RTC_IT_SEC);
TimeDisplay = 1; //时间更新标志置位
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
}
if(RTC_GetITStatus(RTC_IT_ALR)!=RESET)//闹钟中断发生
{
RTC_ClearITPendingBit(RTC_IT_ALR);
AlarmFlag = 1;//送出标志位
}
}
网友评论