STM32-RTC原理和驱动程序
文章目录
- RTC电路原理图
- RTC实现原理
- 烧录示例文件的hex查看程序效果
- 添加相应的文件并添加进工程文件
- rtc.h/main.c解读
- rtc.c解读
杨桃32学习笔记,本文图片文字皆为转述
RTC电路原理图
RTC实现原理
STM32的RTC只用一个32位计数器来计时,而不是用年月日时分秒的分组寄存器。
通过设置可以让这个计数器1秒加1,从0-0XFFFFFFFF大约可计时136年。
时间起点一般设置为1970-01-01 00:00:00 (因现有函数如此定义)
如果要读当前的年月日时分秒,先读出32位RTC计数器值,
然后以1970-01-01 00:00:00为起点,加上计数器中的秒数,
再换算成年月日时分秒,即可得出当前时间。
烧录示例文件的hex查看程序效果
实现效果:led1按秒数的奇数偶数亮灭,奇数亮偶数灭,led2按分钟的奇数偶数亮灭。
时间通过RTC时钟产生,然后通过led状态表示出来。
添加相应的文件并添加进工程文件
由于我们添加了RTC的官方固件库,所以要在lib文件夹下rtc的相关文件。
rtc.h/main.c解读
#ifndef __RTC_H
#define __RTC_H
#include "sys.h"
//全局变量的声明,在rtc.c文件中定义
//以下2条是使用extern语句声明全局变量
//注意:这里不能给变量赋值
extern u16 ryear;
extern u8 rmon,rday,rhour,rmin,rsec,rweek;
u8 RTC_Get(void);//读出当前时间值
void RTC_First_Config(void);//首次启用RTC的设置
void RTC_Config(void);//实时时钟初始化
u8 Is_Leap_Year(u16 year);//判断是否是闰年函数
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec);//写入当前时间
u8 RTC_Get_Week(u16 year,u8 month,u8 day);//按年月日计算星期
#endif
#include "stm32f10x.h" //STM32头文件
#include "sys.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "buzzer.h"
#include "usart.h"
#include "rtc.h"
int main (void){//主程序RCC_Configuration(); //系统时钟初始化RTC_Config(); //实时时钟初始化LED_Init();//LED初始化KEY_Init();//按键初始化BUZZER_Init();//蜂鸣器初始化USART1_Init(115200); //串口初始化,参数中写波特率USART1_RX_STA=0xC000; //初始值设为有回车的状态,即显示一次欢迎词while(1){if(RTC_Get()==0){ //读出时间值,同时判断返回值是不是0,非0时读取的值是错误的。 GPIO_WriteBit(LEDPORT,LED1,(BitAction)(rsec%2)); //LED1接口GPIO_WriteBit(LEDPORT,LED2,(BitAction)(rmin%2)); //LED2接口}}
}
rtc.c解读
rtc.c文件中涉及到RTC固件库相关函数
#include "sys.h"
#include "rtc.h"//以下2条全局变量--用于RTC时间的读取
u16 ryear; //4位年
u8 rmon,rday,rhour,rmin,rsec,rweek;//2位月日时分秒周void RTC_First_Config(void){ //首次启用RTC的设置RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//启用PWR电源管理部分和BKP备用寄存器的时钟(from APB1)PWR_BackupAccessCmd(ENABLE);//后备域解锁BKP_DeInit();//备份寄存器模块复位RCC_LSEConfig(RCC_LSE_ON);//外部32.768KHZ晶振开启 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);//等待稳定 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//RTC时钟源配置成LSE(外部低速晶振32.768KHZ) RCC_RTCCLKCmd(ENABLE);//RTC开启 RTC_WaitForSynchro();//开启后需要等待APB1时钟与RTC时钟同步,才能读写寄存器 RTC_WaitForLastTask();//读写寄存器前,要确定上一个操作已经结束RTC_SetPrescaler(32767);//设置RTC分频器,使RTC时钟为1Hz,RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) RTC_WaitForLastTask();//等待寄存器写入完成 //当不使用RTC秒中断,可以屏蔽下面2条
// RTC_ITConfig(RTC_IT_SEC, ENABLE);//使能秒中断
// RTC_WaitForLastTask();//等待写入完成
}void RTC_Config(void){ //实时时钟初始化//在BKP的后备寄存器1中,存了一个特殊字符0xA5A5//第一次上电或后备电源掉电后,该寄存器数据丢失,表明RTC数据丢失,需要重新配置if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5){//判断寄存数据是否丢失 RTC_First_Config();//重新配置RTC BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);//配置完成后,向后备寄存器中写特殊字符0xA5A5}else{//若后备寄存器没有掉电,则无需重新配置RTC//这里我们可以利用RCC_GetFlagStatus()函数查看本次复位类型if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET){//这是上电复位}else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET){//这是外部RST管脚复位} RCC_ClearFlag();//清除RCC中复位标志//虽然RTC模块不需要重新配置,且掉电后依靠后备电池依然运行//但是每次上电后,还是要使能RTCCLKRCC_RTCCLKCmd(ENABLE);//使能RTCCLK RTC_WaitForSynchro();//等待RTC时钟与APB1时钟同步//当不使用RTC秒中断,可以屏蔽下面2条
// RTC_ITConfig(RTC_IT_SEC, ENABLE);//使能秒中断
// RTC_WaitForLastTask();//等待操作完成}#ifdef RTCClockOutput_Enable RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);PWR_BackupAccessCmd(ENABLE); BKP_TamperPinCmd(DISABLE); BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);#endif
}void RTC_IRQHandler(void){ //RTC时钟1秒触发中断函数(名称固定不可修改)if (RTC_GetITStatus(RTC_IT_SEC) != RESET){}RTC_ClearITPendingBit(RTC_IT_SEC); RTC_WaitForLastTask();
}void RTCAlarm_IRQHandler(void){ //闹钟中断处理(启用时必须调高其优先级)if(RTC_GetITStatus(RTC_IT_ALR) != RESET){}RTC_ClearITPendingBit(RTC_IT_ALR);RTC_WaitForLastTask();
}//判断是否是闰年函数
//月份 1 2 3 4 5 6 7 8 9 10 11 12
//闰年 31 29 31 30 31 30 31 31 30 31 30 31
//非闰年 31 28 31 30 31 30 31 31 30 31 30 31
//输入:年份
//输出:该年份是不是闰年.1,是.0,不是
u8 Is_Leap_Year(u16 year){ if(year%4==0){ //必须能被4整除if(year%100==0){ if(year%400==0)return 1;//如果以00结尾,还要能被400整除 else return 0; }else return 1; }else return 0;
}
//设置时钟
//把输入的时钟转换为秒钟
//以1970年1月1日为基准
//1970~2099年为合法年份//月份数据表
u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};//平年的月份日期表//写入时间
u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec){ //写入当前时间(1970~2099年有效),u16 t;u32 seccount=0;if(syear<2000||syear>2099)return 1;//syear范围1970-2099,此处设置范围为2000-2099 for(t=1970;t<syear;t++){ //把所有年份的秒钟相加if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数else seccount+=31536000; //平年的秒钟数}smon-=1;for(t=0;t<smon;t++){ //把前面月份的秒钟数相加seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数 }seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加seccount+=(u32)hour*3600;//小时秒钟数seccount+=(u32)min*60; //分钟秒钟数seccount+=sec;//最后的秒钟加上去RTC_First_Config(); //重新初始化时钟BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);//配置完成后,向后备寄存器中写特殊字符0xA5A5RTC_SetCounter(seccount);//把换算好的计数器值写入RTC_WaitForLastTask(); //等待写入完成return 0; //返回值:0,成功;其他:错误代码.
}//读出时间
u8 RTC_Get(void){//读出当前时间值 //返回值:0,成功;其他:错误代码.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++; } ryear=temp1;//得到年份temp1=0;while(temp>=28){//超过了一个月if(Is_Leap_Year(ryear)&&temp1==1){//当年是不是闰年/2月份if(temp>=29)temp-=29;//闰年的秒钟数else break;}else{if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年else break;}temp1++; }rmon=temp1+1;//得到月份rday=temp+1; //得到日期}temp=timecount%86400; //得到秒钟数 rhour=temp/3600; //小时rmin=(temp%3600)/60; //分钟 rsec=(temp%3600)%60; //秒钟rweek=RTC_Get_Week(ryear,rmon,rday);//获取星期 return 0;
} u8 RTC_Get_Week(u16 year,u8 month,u8 day){ //按年月日计算星期(只允许1901-2099年)//已由RTC_Get调用 u16 temp2;u8 yearH,yearL;yearH=year/100; yearL=year%100;// 如果为21世纪,年份数加100 if (yearH>19)yearL+=100;// 所过闰年数只算1900年之后的 temp2=yearL+yearL/4;temp2=temp2%7;temp2=temp2+day+table_week[month-1];if (yearL%4==0&&month<3)temp2--;return(temp2%7); //返回星期值
}
STM32-RTC原理和驱动程序相关推荐
- STM32 RTC LSE 初始化失败 卡在 RTC_ICSR_INITF 或者 LSERDY
问题描述 在使用STM32 RTC时钟的时候,想使用外部的32.768K Hz的高精度带温度补偿的 LSE 时钟源. 但是调用MX_RTC_Init()初始化的时候都会卡住.debug进去,可以看到卡 ...
- STM32 RTC时钟读取时间
文章目录 一.RTC简介 1.1 RTC 1.2 RTC特征 1.3 RTC原理框图 1.4 RTC工作流程 1.5 RTC时钟选择 1.6 RTC复位过程 1.7 RTC中断 二.CubeMX配置 ...
- STM32 中断原理及外部中断的实现
STM32 中断原理及外部中断的实现 NVIC 中断优先级管理 中断寄存器 库函数配置 小结 STM32 外部中断 基础知识 库函数配置 外部中断配置示例 小结 内容较充实,作为个人的学习记录 NVI ...
- 纠结的STM32 RTC时钟源LSE
一开始,所有实验都是在神舟板上去完成,根本就没有发现RTC的问题.直到我们自己画板来后调试时,才发现STM32 RTC的外部时钟源存在问题. 这也算是STM32的一个鸡肋,对于LSE外部晶振太过于苛刻 ...
- STM32 RTC应用 内部唤醒中断 (Internal Wakeup)
STM32 RTC应用 周期性中断及内部唤醒(Internal Wakeup) 1. 介绍 STM32的RTC(实时时钟)模块,提供了多种功能,当前以STM32L4系列的RTC功能最为丰富,此处基于S ...
- STM32 RTC时钟源LSE
一开始,所有实验都是在神舟板上去完成,根本就没有发现RTC的问题.直到我们自己画板来后调试时,才发现STM32 RTC的外部时钟源存在问题. 这也算是STM32的一个鸡肋,对于LSE外部晶振太过于苛刻 ...
- STM32 RTC时钟掉电日期不更新 STM32 HAL库RTC时钟配置
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 STM32 RTC时钟掉电日期不更新 & STM32 HAL库RTC时钟配置 一.STM32CubeMX RTC配置 二.RT ...
- stm32 RTC时钟配置
stm32--RTC实时时钟 一.关于时间 2038年问题 在计算机应用上,2038年问题可能会导致某些软件在2038年无法正常工作.所有使用UNIX时间表示时间的程序都将将受其影响,因为它们以自19 ...
- STM32之RTC原理
一.RTC时钟框图分析(重要) 先熟悉一下几个知识点: 1.STM32的实时时钟(RTC)是一个独立的定时器! 2.RTC模块和时钟配置系统(RCC_BDCR寄存器)是在后备区 ...
- STM32——RTC实时时钟原理+BKP寄存器原理
一.RTC实时时钟特征与原理 1.RTC(Real Time Clock):实时时钟 2.RTC是个独立的BCD定时器/计数器.RTC提供一个日历时钟,两个可编程闹钟中断,以及一个具有中断功能的周期性 ...
最新文章
- Android的API与差异化之路
- 四种struts2访问web元素的方式
- 实验7-3-6 字符串转换成十进制整数 (15分)
- css 深度选择器 ,CSS的coped私有作用域和深度选择器
- matlab短均线滞后项,均线理论的滞后性问题
- rust怎么关阳光指令_我家也有庭院多好,伸缩阳光房装上,能休闲能当车库,还不算违建...
- 已解决:手动打包war包结果无法在Tomcat中部署
- python和java哪个好找工作-想转行,Java与python该选择哪个?
- NOIP2017后记
- 安装VMware时,出现 安装程序无法继续 Microsoft Runtime DLL 安装程序未能完成安装 您无权输入许可证密钥,请使用系统管理员账户重试 VMware15.5.x 安装问题处理
- 数字图像处理第四版更新内容
- 电脑一拖二的学习方法
- MangaEditor(漫画编辑器)v1.10b官方版
- 51单片机语音跳绳计播报跳绳数目
- 联想android手机驱动,Lenovo联想手机驱动
- 企业网站排名,站内布局,不只有关键词密度
- 深入理解 OC/C++ 闭包
- Autodesk AutoCAD 2015 英文版+简体中文版,附有效注册机
- 调用方法求出数组两个元素的和
- 分享一款完全免费、功能强大、可商用、可扩展的PHP文章管理系统
热门文章
- React history.push 传递参数
- matlab读入从文件中读取大量的数据
- 进程上下文和中断上下文
- html语言文字闪烁,html+CSS3实现的文字闪烁特效
- python编程顺序_Python编程中归并排序算法的实现步骤详解
- 基于 Dash Bio 的生物信息学数据可视化
- Coronascape – 为COVID-19研究特制的基因列表比较工具
- 宏基因组合种树第292期—侧柏、樟子松,为祖国绿化做贡献
- R语言plotly可视化:plotly可视化分组归一化直方图(historgram)并在直方图中添加密度曲线kde、并在直方图的底部部边缘使用geom_rug函数添加边缘轴须图
- python使用openCV图像加载(转化为灰度图像)、使用filter2D函数对图像进行锐化(Sharpen Images)