文章目录

  • 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原理和驱动程序相关推荐

  1. STM32 RTC LSE 初始化失败 卡在 RTC_ICSR_INITF 或者 LSERDY

    问题描述 在使用STM32 RTC时钟的时候,想使用外部的32.768K Hz的高精度带温度补偿的 LSE 时钟源. 但是调用MX_RTC_Init()初始化的时候都会卡住.debug进去,可以看到卡 ...

  2. 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配置 ...

  3. STM32 中断原理及外部中断的实现

    STM32 中断原理及外部中断的实现 NVIC 中断优先级管理 中断寄存器 库函数配置 小结 STM32 外部中断 基础知识 库函数配置 外部中断配置示例 小结 内容较充实,作为个人的学习记录 NVI ...

  4. 纠结的STM32 RTC时钟源LSE

    一开始,所有实验都是在神舟板上去完成,根本就没有发现RTC的问题.直到我们自己画板来后调试时,才发现STM32 RTC的外部时钟源存在问题. 这也算是STM32的一个鸡肋,对于LSE外部晶振太过于苛刻 ...

  5. STM32 RTC应用 内部唤醒中断 (Internal Wakeup)

    STM32 RTC应用 周期性中断及内部唤醒(Internal Wakeup) 1. 介绍 STM32的RTC(实时时钟)模块,提供了多种功能,当前以STM32L4系列的RTC功能最为丰富,此处基于S ...

  6. STM32 RTC时钟源LSE

    一开始,所有实验都是在神舟板上去完成,根本就没有发现RTC的问题.直到我们自己画板来后调试时,才发现STM32 RTC的外部时钟源存在问题. 这也算是STM32的一个鸡肋,对于LSE外部晶振太过于苛刻 ...

  7. STM32 RTC时钟掉电日期不更新 STM32 HAL库RTC时钟配置

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 STM32 RTC时钟掉电日期不更新 & STM32 HAL库RTC时钟配置 一.STM32CubeMX RTC配置 二.RT ...

  8. stm32 RTC时钟配置

    stm32--RTC实时时钟 一.关于时间 2038年问题 在计算机应用上,2038年问题可能会导致某些软件在2038年无法正常工作.所有使用UNIX时间表示时间的程序都将将受其影响,因为它们以自19 ...

  9. STM32之RTC原理

    一.RTC时钟框图分析(重要) 先熟悉一下几个知识点:       1.STM32的实时时钟(RTC)是一个独立的定时器!       2.RTC模块和时钟配置系统(RCC_BDCR寄存器)是在后备区 ...

  10. STM32——RTC实时时钟原理+BKP寄存器原理

    一.RTC实时时钟特征与原理 1.RTC(Real Time Clock):实时时钟 2.RTC是个独立的BCD定时器/计数器.RTC提供一个日历时钟,两个可编程闹钟中断,以及一个具有中断功能的周期性 ...

最新文章

  1. Android的API与差异化之路
  2. 四种struts2访问web元素的方式
  3. 实验7-3-6 字符串转换成十进制整数 (15分)
  4. css 深度选择器 ,CSS的coped私有作用域和深度选择器
  5. matlab短均线滞后项,均线理论的滞后性问题
  6. rust怎么关阳光指令_我家也有庭院多好,伸缩阳光房装上,能休闲能当车库,还不算违建...
  7. 已解决:手动打包war包结果无法在Tomcat中部署
  8. python和java哪个好找工作-想转行,Java与python该选择哪个?
  9. NOIP2017后记
  10. 安装VMware时,出现 安装程序无法继续 Microsoft Runtime DLL 安装程序未能完成安装 您无权输入许可证密钥,请使用系统管理员账户重试 VMware15.5.x 安装问题处理
  11. 数字图像处理第四版更新内容
  12. 电脑一拖二的学习方法
  13. MangaEditor(漫画编辑器)v1.10b官方版
  14. 51单片机语音跳绳计播报跳绳数目
  15. 联想android手机驱动,Lenovo联想手机驱动
  16. 企业网站排名,站内布局,不只有关键词密度
  17. 深入理解 OC/C++ 闭包
  18. Autodesk AutoCAD 2015 英文版+简体中文版,附有效注册机
  19. 调用方法求出数组两个元素的和
  20. 分享一款完全免费、功能强大、可商用、可扩展的PHP文章管理系统

热门文章

  1. React history.push 传递参数
  2. matlab读入从文件中读取大量的数据
  3. 进程上下文和中断上下文
  4. html语言文字闪烁,html+CSS3实现的文字闪烁特效
  5. python编程顺序_Python编程中归并排序算法的实现步骤详解
  6. 基于 Dash Bio 的生物信息学数据可视化
  7. Coronascape – 为COVID-19研究特制的基因列表比较工具
  8. 宏基因组合种树第292期—侧柏、樟子松,为祖国绿化做贡献
  9. R语言plotly可视化:plotly可视化分组归一化直方图(historgram)并在直方图中添加密度曲线kde、并在直方图的底部部边缘使用geom_rug函数添加边缘轴须图
  10. python使用openCV图像加载(转化为灰度图像)、使用filter2D函数对图像进行锐化(Sharpen Images)