RTC时钟
配置的RTC时钟需要添加bkp.c备份寄存器库函数、pwr.c电源管理库函数和rtc.c实时时钟函数,要用到RTC中断还要添加mis.c函数。
RTC除了可用作时钟日历功能,主要的功能是定时唤醒和休眠计时。
一、RTC时钟的配置:
1.由图一、RTC简介中画红框的文字可知:
(1)使能BKP和PWR时钟;
(2)BKP备份区域使能;
(3)复位BKP寄存器;
void RTC_Configuration() //配置RTC
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP|RCC_APB1Periph_PWR, ENABLE); //使能BKP和PWR时钟
PWR_BackupAccessCmd(ENABLE); //BKP备份区域使能
BKP_DeInit(); //复位BKP寄存器
2.在STM32中文参考手册中,查找到RTC的时钟源
蓝桥杯嵌入式的开发板只能使用LSI时钟源。
(1)使能内部低速时钟 ;
(2)等待内部低速时钟就绪;
(3)设置RTC时钟为内部低速时钟;
(4)使能RTC时钟;
RCC_LSICmd(ENABLE); //使能内部低速时钟
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)== RESET); //等待内部低速时钟就绪
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI); //设置RTC时钟为内部低速时钟
RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
3.LSI时钟
(1) 等待APB1时钟与RTC时钟同步;
(2) RTC时钟秒中断使能
(3) 设置RTC预分频系数为40000-1;
LSI时钟频率大约40KHZ,RTC需要1HZ的时钟,因此需要40000-1分频。
(4) 设置时间初始值;
u8 HH = 23; //时
u8 MM = 59; //分
u8 SS = 57; //秒
RTC_WaitForSynchro(); //等待APB1时钟和RTC时钟同步
RTC_WaitForLastTask(); //等待寄存器操作完成
RTC_ITConfig(RTC_IT_SEC, ENABLE); //RTC时钟秒中断使能
RTC_WaitForLastTask(); //等待寄存器操作完成
RTC_SetPrescaler(40000-1); //RTC period = RTCCLK/RTC_PR = (40 KHz)/(39999+1) 40M时钟分频产生秒时基
RTC_WaitForLastTask(); //等待寄存器操作完成
RTC_SetCounter(HH*3600+MM*60+SS); //设置秒计数寄存器值
RTC_WaitForLastTask(); //等待寄存器操作完成
}
(5)使能RTC中断
void NVIC_Configuration()
{
NVIC_InitTypeDef NVIC_InitStructure; //中断初始化结构体
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //设置中断优先级级分组,不设置默认组0
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn; //RTC中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //RTC通道被使能
NVIC_Init(&NVIC_InitStructure);
}
中断优先级分组讲解:
STM32的中断分组:STM32 将中断分为5个组,组0到4。该分组的设置是由SCB->AIRCR寄存器的bit10~8来定义的。
组 | [AIRCR[10:8] | bit[7:4] | 分配情况 | 分配情况 |
---|---|---|---|---|
0 | 111 | 0:4 | 0位抢占优先级 | 4位响应优先级 |
1 | 110 | 1:3 | 1位抢占优先级 | 3位响应优先级 |
2 | 101 | 2:2 | 2位抢占优先级 | 2位响应优先级 |
3 | 100 | 3:1 | 3位抢占优先级 | 1位响应优先级 |
4 | 011 | 4:0 | 4位抢占优先级 | 0位响应优先级 |
组 0~4 对应的配置关系:
例如:组设置为3,那么此时所有的60个中断,每个中断的中断优先寄存器的高四位中的最高3位是抢占优先级,低1位是响应优先级。
每个中断,你可以设置抢占优先级为 0~7,响应优先级为1或0。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。
注意:
第一,如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
第二,高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。而抢占优先级相同的中断,高优先级的响应优先级不可以打断低响应优先级的中断。
例如:假定设置中断优先级组为2,设置中断3(RTC中断)的抢占优先级为2,响应优先级为1。中断6(外部中断0)的抢占优先级为3,响应优先级为0。中断7(外部中断1)的抢占优先级为2,响应优先级为0。那么这3个中断的优先级顺序为:中断7>中断3>中断6。
中断 3 和中断 7 都可以打断中断 6 的中断。而中断 7 和中断 3 却不可以相互打断。
二、RTC中断函数配置
在while(1)内不能进行计算时间的步骤,如果循环内有延时会影响计时的准确性。
中断里不要有大量的计算和延时,最好只有判断。
因为时钟的计算量较小可以放在中断中:
extern u8 HH; //时
extern u8 MM; //分
extern u8 SS; //秒
void RTC_IRQHandler()
{
if(RTC_GetITStatus(RTC_IT_SEC) != RESET)
{
RTC_ClearITPendingBit(RTC_IT_SEC);
if(SS == 59)
{
SS = 0;
if(MM == 59)
{
MM = 0;
if(HH == 23)
{
HH = 0;
}
else
{
HH ++;
}
}
else
{
MM ++;
}
}
else
{
SS ++;
}
}
}
用extern引入全局变量在外部使用,调用RTC.c中的全局变量HH、MM、SS,三个变量的作用是初始化秒计数寄存器内的值。
extern外部引用的全局变量不能与系统内的变量名相同。
因为先显示在判断,所以HH = 23时归零,MM和SS = 59时归零并向前进一位。实际操作时各时段计时均为1s。
采用设置一个u32的变量,通过RTC_GetCounter();函数使u32的变量存储秒计数寄存器内的值,判断该变量的值是否等于24*3600,等于后秒计数寄存器内的值置零,即RTC_GetCounter(0);该方法实际操作时由23:59:59变为00:00:00后,再变到00:00:01中时间为2秒。
void RTC_IRQHandler(void)
{
u32 Times;
if(RTC_GetITStatus(RTC_IT_SEC) == 1)
{
RTC_ClearITPendingBit(RTC_IT_SEC);
RTC_Flag = 1;
Times = RTC_GetCounter();
RTC_WaitForLastTask();
if(Times == (24 * 3600))
{
RTC_SetCounter(0);
RTC_WaitForLastTask();
}
}
三、main函数中LCD配置和sprintf函数
1. LCD配置
蓝桥杯嵌入式的开发板的LCD可以显示10行,每行显示20个字符。
只调用工程内的函数时,先建立一个长度为20的字符串。
(1) 调用LCD初始化函数;
(2) 调用清屏函数,函数内配置清屏后屏幕显示的颜色;
(3) 调用设置文字颜色和文字背景颜色的函数,再调用清除行函数清除的行会显示刚才设置的文本背景颜色。
extern u8 HH;//时
extern u8 MM; //分
extern u8 SS; //秒
u8 text[20];
//Main Body
int main(void)
{
SysTick_Config(SystemCoreClock/1000);
STM3210B_LCD_Init();
Delay_Ms(100);
LCD_Clear(White);
LCD_SetTextColor(White);
LCD_SetBackColor(Blue);
LCD_ClearLine(Line0); //让123456行背景均为Blue
LCD_ClearLine(Line1);
LCD_ClearLine(Line2);
LCD_ClearLine(Line3);
LCD_ClearLine(Line4);
LCD_ClearLine(Line5);
LCD_DisplayStringLine(Line1," RTC DEMO ");
LCD_DisplayStringLine(Line3," RTC_Calendar_Test ");
LCD_SetTextColor(Blue);
LCD_SetBackColor(Cyan);
LCD_ClearLine(Line6); //让78910行背景均为Cyan
LCD_ClearLine(Line7);
LCD_ClearLine(Line8);
LCD_ClearLine(Line9);
RTC_Configuration();
NVIC_Configuration();
2. sprintf函数
while(1)
{
sprintf(text," Time: %02d:%02d:%02d",HH, MM, SS);
LCD_DisplayStringLine(Line7,text);
}
}
显示字符串函数的参数为显示在第几行和字符串名。
%02d:输出两位十进制整数,左边补零;
%2d:输出两位十进制整数,右边补空格;
%+02d:输出带整号的两位十进制整数,左边补零
(以上仅个人观点)