RTC时钟
- 一、RTC时钟的简介
- 二、RTC的具体配置
-
- 1.对应的时钟图
- 2.RTC配置一般步骤
- 3.RTC特征
-
- ①闹钟中断
- ②秒中断(常用)
- ③溢出中断(应该不常用)
- 3.主函数中的使用
- 未解决的问题
- 其他学习总结
-
- 1.将OLED从mini板移到C8T6上
- 2.AD20复制问题
- 总结
- 写在最后
一、RTC时钟的简介
RTC时钟不同于STM32单片机上其他的时钟,RTC时钟在STM32mini板子上经一个纽扣电池供电,所以它不需要我们再供给电源就可以进行计数,这样的特殊性使得它可以让我们利用它制作一个类似万年历的小钟表。
二、RTC的具体配置
1.对应的时钟图
这里的TR_CLK是由RTCCLK分频后进行装载,实际我们将它装载的周期控制到一秒,再用一个终端服务函数使得我们每一秒都将时间更新。而RTC_DIV是经没有分频的RTCCLK进行装载的 ,所以它的装载周期就会小很多,并且TR_CLK和RTC_DIV的数量关系恰好是分频系数,这就使得我们可以精确到秒后面更小的单位,但是对于万年历这样的功能,对于时间的精准性不需要太高所以就不需要对RTC_DIV这个参数进行操作。
2.RTC配置一般步骤
①使能PWR和BKP时钟
②使能后备寄存器访问
③配置RTC时钟源,使能RTC时钟
④设置RTC预分频系数
⑤设置时间
⑥开启相关中断(在需要的时候)
⑦编写终端服务函数
⑧一些操作要等待写操作完成和同步
代码如下:
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
RCC_LSEConfig(RCC_LSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)//通过判断寄存器标志位判断低速晶振是否准备就绪
{
temp++;
delay_ms(10);
}
if(temp>=250)return 1;
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //选择外部低速晶振作为时钟来源
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForLastTask(); //等待写操作完成
RTC_WaitForSynchro(); //等待同步完成
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
RTC_WaitForLastTask();
RTC_EnterConfigMode(); //允许配置
RTC_SetPrescaler(32767); //设置预分频系数
RTC_WaitForLastTask();
RTC_Set(2020,10,18,9,40,20); //设置初始时间
RTC_ExitConfigMode(); //退出配置模式
3.RTC特征
RTC时钟可以有三种中断函数,分别是闹钟中断,秒中断和溢出中断。
①闹钟中断
用来产生一个软件可编程的闹钟中断
②秒中断(常用)
用来产生一个可编程的周期性中断信号(最长为1秒)
③溢出中断(应该不常用)
指示内部可编程计数器溢出并回转为0的状态
3.主函数中的使用
u8 RTC_Get(void)
{
static u16 daycnt=0;
u32 timecount=0;
u32 temp=0;
u16 temp1=0;
timecount=RTC_GetCounter();
temp=timecount/86400; //得到天数
if(daycnt!=temp)//超过一天了
{
daycnt=temp;
temp1=1970; //从1970年开始算起
while(temp>=365)
{
if(Is_Leap_Year(temp1))//是闰年
{
if(temp>=366)temp-=366;//闰年的秒数
else { temp1++;break;}
}
else temp-=365; //平年
temp1++;
}
calendar.w_year=temp1;//得到年份
temp1=0;
while(temp>=28)//超过了一个月
{
if(Is_Leap_Year(calendar.w_year)&&temp1==1)//今年是不是闰年
{
if(temp>=29)temp-=29;//闰年的秒针数
else break;
}
else
{
if(temp>=mon_table[temp1])temp-=mon_table[temp1];
else break;
}
temp1++;
}
calendar.w_month=temp1+1; //月
calendar.w_date=temp+1; //日
}
temp=timecount%86400; //得到今天总共过了多少秒
calendar.hour=temp/3600; //小时
calendar.min=(temp%3600)/60; //分钟
calendar.sec=(temp%3600)%60; //秒
calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);//得到第几周
return 0;
}
这个函数是在RTC函数中,是一个显示当前时间的函数,之所以很复杂是因为在RTC的寄存器中只记录秒数,也就是我们需要根据现在的秒数进行计算当前的日期和时间,我们可以直接进行利用。
在主函数中我们可以配合显示模块,将时间进行显示,上面展示的函数将年月日时分秒星期写如一个结构体,在引用时我们需要用一个结构体指针进行使用。
未解决的问题
商家给的例程是用LCD屏幕对时间进行的显示,烧录后效果达到。
我想要将时间显示在OLED屏幕上时,打算像往常一样 直接复制一个RTC工程文件然后在HARDWARE文件里新建一个OLED的文件夹,之后将对应的OLED文件复制过来,再在MDK5中添加.c文件然后添加路径,但是编译后一直会显示OLED的某一个头文件找不到或者已损坏,排查后确定不是损坏问题,而是文件路径问题,但是路径已经添加过了还是不知道为何报错。下面是问题截图
问题还未解决,如果以后解决会在这里进行修改。
尽管这样,使用正点原子的OLED程序就不会产生这样的报错。
其他学习总结
1.将OLED从mini板移到C8T6上
具体操作就是将程序在C8T6上没有的引脚转换为C8T6上的引脚
#define LED_ON GPIO_ResetBits(GPIOD,GPIO_Pin_2)
#define LED_OFF GPIO_SetBits(GPIOD,GPIO_Pin_2)
在C8T6上没有D引脚,所以我们进行转换,这两行代码在OLED.h中找到
我选择换到了PA1和PA2,不仅是这里需要修改还有就是对IO 口的使能需要进行修改。
最后还需要将工程文件中的芯片选择为C8T6。由于OLED没有使用定时器,所以我们更换IO只需要选择两个无特殊作用的就可以。
2.AD20复制问题
在画板子过程中,经常会出现铺铜后导线也被铺铜,所以常常直接复制所有的元件到新PCB中就可以解决,但是这里有个细节没有发现,就是如果我们直接使用Ctrl+c,Ctrl+v就会让我们复制后的 PCB没有网络,解决方法就是我们需要进行特殊粘贴,具体操作如下
复制整个原理图时,我们能可以全部框选后Ctrl+c进行复制,之后
选择特殊粘贴
之后我们一定不要勾选粘贴到当前层,否则他会强制将两层板压缩到一层板,产生很多报错。还有就是保持网络名称需要勾选上,这样我们复制后的PCB就有网络了。
总结
这周的学习比较仓促,所以还有一些问题没有解决,希望可以快点解决OLED添加工程的问题。
RTC的使用情况比较特殊,必须使用一块电池进行供电,所以C8T6不能使用,但是以后可以自己画板在其上添加,就可以拥有一个独立的时钟模块,可能会为以后的低功耗有帮助。
AD20还是有一些不太熟练,有时候对板子进行修改还是会有一些问题,还需要多总结。
写在最后
本人小白一枚,这些仅仅是我个人的经验与认知,也许含有多处错误,希望读者给我指正。