首页 > 其他分享 >关于关于STM32F103芯片RTC模块的一些注意事项

关于关于STM32F103芯片RTC模块的一些注意事项

时间:2024-08-29 19:48:11浏览次数:10  
标签:STM32F103 02d RTC rtc 31 param NVIC 关于

1、首先是晶振的问题,只有外部低速晶振LSE支持VBAT供电时持续运行,LSI或者HSE均不行,所以若要求设备断电后,RTC时钟可以继续运行,一定要使用LSE晶振

2、关于LSE晶振的干扰问题,本次调试设备的过程中发现,LSE虽然正常起振,RTC也正常走时,但刚开机的时候会走的比较慢,之后逐渐稳定,通过抓取LSE波形,发现存在一个周期性的干扰,如下图

 通过对波形放大发现,该干扰并不会导致LSE停振,只是会抬高正常的震荡电平,如下图

起初同事推测是由于PC13引脚可作为RTC的入侵检测引脚导致, 经测试关闭TAMPER引脚的侵入检测功能后,并未解决该问题,

后经百度发现,之前也有人遇到过,而且官方的勘误手册上也提到过,是由于使用PC13引脚做LED指示灯导致,关闭该引脚后LSE震荡正常

 3、关于玩不低速32.768KHz晶振的匹配电容问题,官方手册上给出的是6pF,实际贴片时为节省一种物料,使用了跟8M晶振一样的18pF,

导致主电源关闭时LSE停振,但RTC始终与后备寄存器依然保持,数据并未丢失,主电源上电之后RTC又继续走时,并未发现异常,

后经测试发现使用官方推荐的6pF电容,或者直接去掉电容,断电后LSE均正常震荡,且震荡频率并不收影响,如下图。

 这是主电源断电之后,电池供电的LSE震荡波形,如下图

 

附优化之后的RTC初始化及时钟配置获取代码(以正点原子例程为父本修改),仅供参考

  1 #include "RTC.h"
  2 #include "sys.h"
  3 #include "delay.h"
  4 #include "usart.h"
  5 
  6 rtc_param_def rtc_param;//时钟结构体 
  7 
  8 //月份数据表                                             
  9 u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表      
 10 //平年的月份日期表
 11 const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
 12 
 13 /*
 14 void set_clock(u16 divx)
 15 {
 16      RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);    //使能PWR和BKP外设时钟  
 17     PWR_BackupAccessCmd(ENABLE);    //使能RTC和后备寄存器访问 
 18 
 19     RTC_EnterConfigMode();/// 允许配置    
 20  
 21     RTC_SetPrescaler(divx); //设置RTC预分频的值                                               
 22     RTC_ExitConfigMode();//退出配置模式                                                                    
 23     RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成                                               
 24 }       
 25 */
 26 static void RTC_NVIC_Config(void){    
 27     NVIC_InitTypeDef NVIC_InitStructure;
 28     NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;                //RTC全局中断
 29     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;        //先占优先级3位,最低
 30     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;            //先占优先级3位,最低
 31     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;            //使能该通道中断
 32     NVIC_Init(&NVIC_InitStructure);                                //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 33 }
 34 
 35 //实时时钟配置
 36 //初始化RTC时钟,同时检测时钟是否工作正常
 37 //BKP->DR1用于保存是否第一次配置的设置
 38 //返回0:正常
 39 //其他:错误代码
 40 u8 RTC_Init(void){
 41 //检查是不是第一次配置时钟
 42     u16 temp=0;
 43     if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050) {            //从指定的后备寄存器中读出数据:读出了与写入的指定数据不相等
 44         
 45         RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);    //使能PWR和BKP外设时钟   
 46         BKP_TamperPinCmd(DISABLE);                            //关闭TAMPER引脚的侵入检测功能
 47         PWR_BackupAccessCmd(ENABLE);                        //使能后备寄存器访问 
 48         BKP_DeInit();                                        //复位备份区域     
 49         
 50         RCC_LSEConfig(RCC_LSE_ON);                            //设置外部低速晶振(LSE),使用外设低速晶振
 51         while((RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) && (temp<250)) {//检查指定的RCC标志位设置与否,等待低速晶振就绪    
 52             temp++;
 53             delay_ms(10);
 54         }
 55         if(temp>=250) {printf("RTC Init faild!\r\n"); return 1;}    //初始化时钟失败,晶振有问题 
 56             
 57         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);                //设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
 58         RCC_RTCCLKCmd(ENABLE);                                //使能RTC时钟  
 59         
 60         RTC_WaitForLastTask();                                //等待最近一次对RTC寄存器的写操作完成
 61         RTC_WaitForSynchro();                                //等待RTC寄存器同步  
 62         RTC_ITConfig(RTC_IT_SEC, ENABLE);                    //使能RTC秒中断
 63         RTC_WaitForLastTask();                                //等待最近一次对RTC寄存器的写操作完成
 64         RTC_EnterConfigMode();                                //允许配置    
 65         RTC_SetPrescaler(32767);                             //设置RTC预分频的值
 66         RTC_WaitForLastTask();                                //等待最近一次对RTC寄存器的写操作完成
 67         RTC_Set(2024,1,1,0,0,0);                              //设置时间    
 68         RTC_ExitConfigMode();                                 //退出配置模式   
 69         BKP_WriteBackupRegister(BKP_DR1, 0X5050);            //向指定的后备寄存器中写入用户程序数据
 70     }
 71     else{//系统继续计时
 72         RTC_WaitForSynchro();                                //等待最近一次对RTC寄存器的写操作完成
 73         RTC_ITConfig(RTC_IT_SEC, ENABLE);                    //使能RTC秒中断
 74         RTC_WaitForLastTask();                                //等待最近一次对RTC寄存器的写操作完成
 75     }
 76     RTC_NVIC_Config();                                        //RCT中断分组设置                    
 77     RTC_Get();                                                //更新时间 
 78     printf("RTC Init:%04d-%02d-%02d %02d:%02d:%02d\r\n", rtc_param.year, rtc_param.mon, rtc_param.day, rtc_param.hour, rtc_param.min, rtc_param.sec);
 79     return 0; 
 80 }                             
 81 //RTC时钟中断
 82 //每秒触发一次  
 83 //extern u16 tcnt; 
 84 void RTC_IRQHandler(void)
 85 {         
 86     if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断
 87     {                            
 88         RTC_Get();//更新时间 
 89 //        printf("RTC Time:%04d-%02d-%02d %02d:%02d:%02d\r\n", rtc_param.year, rtc_param.mon, rtc_param.day, rtc_param.hour, rtc_param.min, rtc_param.sec);//输出RTC时间
 90      }
 91 //    if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断
 92 //    {
 93 //        RTC_ClearITPendingBit(RTC_IT_ALR);        //清闹钟中断          
 94 //        RTC_Get();                //更新时间   
 95 //        printf("Alarm Time:%04d-%02d-%02d %02d:%02d:%02d\r\n", rtc_param.year, rtc_param.mon, rtc_param.day, rtc_param.hour, rtc_param.min, rtc_param.sec);//输出闹铃时间    
 96 //        
 97 //      }                                                    
 98     RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);        //清闹钟中断
 99     RTC_WaitForLastTask();                                                   
100 }
101 //判断是否是闰年函数
102 //月份   1  2  3  4  5  6  7  8  9  10 11 12
103 //闰年   31 29 31 30 31 30 31 31 30 31 30 31
104 //非闰年 31 28 31 30 31 30 31 31 30 31 30 31
105 //输入:年份
106 //输出:该年份是不是闰年.1,是.0,不是
107 u8 Is_Leap_Year(u16 year)
108 {              
109     if(year%4==0) //必须能被4整除
110     { 
111         if(year%100==0) 
112         { 
113             if(year%400==0)return 1;//如果以00结尾,还要能被400整除        
114             else return 0;   
115         }else return 1;   
116     }else return 0;    
117 }                    
118 //设置时钟
119 //把输入的时钟转换为秒钟
120 //以1970年1月1日为基准
121 //1970~2099年为合法年份
122 //返回值:0,成功;其他:错误代码.
123 //月份数据表                                             
124 u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
125 {
126     u16 t;
127     u32 seccount=0;
128     if(syear<1970||syear>2099)return 1;       
129     for(t=1970;t<syear;t++)    //把所有年份的秒钟相加
130     {
131         if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
132         else seccount+=31536000;              //平年的秒钟数
133     }
134     smon-=1;
135     for(t=0;t<smon;t++)       //把前面月份的秒钟数相加
136     {
137         seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
138         if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数       
139     }
140     seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 
141     seccount+=(u32)hour*3600;//小时秒钟数
142     seccount+=(u32)min*60;     //分钟秒钟数
143     seccount+=sec;//最后的秒钟加上去
144 
145     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);    //使能PWR和BKP外设时钟  
146     PWR_BackupAccessCmd(ENABLE);    //使能RTC和后备寄存器访问 
147     RTC_SetCounter(seccount);    //设置RTC计数器的值
148 
149     RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成      
150     return 0;        
151 }
152 
153 //初始化闹钟          
154 //以1970年1月1日为基准
155 //1970~2099年为合法年份
156 //syear,smon,sday,hour,min,sec:闹钟的年月日时分秒   
157 //返回值:0,成功;其他:错误代码.
158 u8 RTC_Alarm_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
159 {
160     u16 t;
161     u32 seccount=0;
162     if(syear<1970||syear>2099)return 1;       
163     for(t=1970;t<syear;t++)    //把所有年份的秒钟相加
164     {
165         if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
166         else seccount+=31536000;              //平年的秒钟数
167     }
168     smon-=1;
169     for(t=0;t<smon;t++)       //把前面月份的秒钟数相加
170     {
171         seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
172         if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数       
173     }
174     seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加 
175     seccount+=(u32)hour*3600;//小时秒钟数
176     seccount+=(u32)min*60;     //分钟秒钟数
177     seccount+=sec;//最后的秒钟加上去                 
178     //设置时钟
179     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);    //使能PWR和BKP外设时钟   
180     PWR_BackupAccessCmd(ENABLE);    //使能后备寄存器访问  
181     //上面三步是必须的!
182     
183     RTC_SetAlarm(seccount);
184  
185     RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成      
186     
187     return 0;        
188 }
189 
190 //得到当前的时间
191 //返回值:0,成功;其他:错误代码.
192 u8 RTC_Get(void)
193 {
194     static u16 daycnt=0;
195     u32 timecount=0; 
196     u32 temp=0;
197     u16 temp1=0;      
198     timecount=RTC_GetCounter();     
199      temp=timecount/86400;   //得到天数(秒钟数对应的)
200     if(daycnt!=temp)//超过一天了
201     {      
202         daycnt=temp;
203         temp1=1970;    //从1970年开始
204         while(temp>=365)
205         {                 
206             if(Is_Leap_Year(temp1))//是闰年
207             {
208                 if(temp>=366)temp-=366;//闰年的秒钟数
209                 else {temp1++;break;}  
210             }
211             else temp-=365;      //平年 
212             temp1++;  
213         }   
214         rtc_param.year=temp1;//得到年份
215         temp1=0;
216         while(temp>=28)//超过了一个月
217         {
218             if(Is_Leap_Year(rtc_param.year)&&temp1==1)//当年是不是闰年/2月份
219             {
220                 if(temp>=29)temp-=29;//闰年的秒钟数
221                 else break; 
222             }
223             else 
224             {
225                 if(temp>=mon_table[temp1])temp-=mon_table[temp1];//平年
226                 else break;
227             }
228             temp1++;  
229         }
230         rtc_param.mon=temp1+1;    //得到月份
231         rtc_param.day=temp+1;      //得到日期 
232     }
233     temp=timecount%86400;             //得到秒钟数          
234     rtc_param.hour=temp/3600;         //小时
235     rtc_param.min=(temp%3600)/60;     //分钟    
236     rtc_param.sec=(temp%3600)%60;     //秒钟
237     rtc_param.week=RTC_Get_Week(rtc_param.year,rtc_param.mon,rtc_param.day);//获取星期   
238     return 0;
239 }     
240 //获得现在是星期几
241 //功能描述:输入公历日期得到星期(只允许1901-2099年)
242 //输入参数:公历年月日 
243 //返回值:星期号                                                                                         
244 u8 RTC_Get_Week(u16 year,u8 month,u8 day)
245 {    
246     u16 temp2;
247     u8 yearH,yearL;
248     
249     yearH=year/100;    yearL=year%100; 
250     // 如果为21世纪,年份数加100  
251     if (yearH>19)yearL+=100;
252     // 所过闰年数只算1900年之后的  
253     temp2=yearL+yearL/4;
254     temp2=temp2%7; 
255     temp2=temp2+day+table_week[month-1];
256     if (yearL%4==0&&month<3)temp2--;
257     return(temp2%7);
258 }              

 

标签:STM32F103,02d,RTC,rtc,31,param,NVIC,关于
From: https://www.cnblogs.com/txqdm/p/18387469

相关文章

  • 关于垂直领域大模型的探索和尝试
    最近这一两周看到不少互联网公司都已经开始秋招提前批面试了。不同以往的是,当前职场环境已不再是那个双向奔赴时代了。求职者在变多,HC在变少,岗位要求还更高了。最近,我们又陆续整理了很多大厂的面试题,帮助一些球友解惑答疑,分享技术面试中的那些弯弯绕绕。总结链接如下:《......
  • 关于linux系统镜像下载 ubuntu centos
    1.直接上观点:目前主流的linux:乌班图(Ubuntu):主要是个人使用,值得一提的是,目前ai服务器很多都选择乌班图,主要还是centos7官网停更了;centos7:这个可是主流,尽管官网停更,但是这些年积累的用户量是最多的,如果不知道自己服务器用什么,那选centos7肯定没错,各类技术文档,各种问题解决,c......
  • 关于linux 中断的嵌套
    在Linux系统中,关于中断嵌套的问题,我们可以从以下几个方面进行说明:###一、Linux中断处理的基本机制Linux系统中的中断是一种异步事件处理机制,用于处理硬件设备或其他系统事件引起的中断请求。中断处理程序(InterruptServiceRoutine,ISR)是操作系统内核中用于响应和处理这些中断......
  • 关于安科瑞蓄电池在线监测系统的设计与应用-安科瑞 蒋静
    蓄电池在线监测系统是一种用于实时监测蓄电池状态并分析其性能的重要设备。该系统通过监测蓄电池的关键参数,如电压、电流、温度、内阻等,对电池的性能和健康状况进行评估,从而及时发现潜在问题并采取相应的维护措施。以下是对蓄电池在线监测系统的详细介绍:一、系统概述蓄电池在......
  • MySQL - [19] 关于个人负债为主题的数据库设计
    天生我材必有用,千金散尽还复来。 一、开发环境序号名称版本描述1JDK1.8.0_4012数据库MySQLCommunityServer8.0.373数据库客户端DBeaver21.0.2.2021040420404开发工具IntelliJIDEACommunityEdition2023.3.4  二、数据库设计2.1、......
  • 重塑视频监控体验:WebRTC技术如何赋能智慧工厂视频高效管理场景
    视频汇聚EasyCVR视频监控平台,作为一款智能视频监控综合管理平台,凭借其强大的视频融合汇聚能力和灵活的视频能力,在各行各业的应用中发挥着越来越重要的作用。EasyCVR平台不仅兼容多种主流标准协议及私有协议/SDK的接入(如:GB28181、RTSP/Onvif、RTMP、JT808、GA/T1400协议,海康Ehome......
  • 浅析WebRTC技术在智慧园区视频管理场景中的应用
    随着科技的飞速发展,智慧园区作为城市智慧化的重要组成部分,正逐步成为现代化管理的重要方向。智慧园区的建设不仅涉及硬件设施的智能化升级,还离不开高效的视频管理和实时通信技术。在这一背景下,WebRTC(WebReal-TimeCommunication)技术以其低延迟、高互动性的优势,在智慧园区的视频管......
  • 关于HTML的表单标签
    html表单标签from表单标签里面就是所有用户填写的表单数据;action:"xxx.py"把表单数据提交给了哪一个后台程序去处理method="post"传递数据时用的是什么方法,post表示隐式提交数据,get表示明文传输数据 用户名:中文的冒号为了防止代码错误 input+tab键来生成代码 ......
  • 关于我的摆烂大二生活
    关于我的摆烂大二生活如今大二生活已经结束,这一年学到了很多知识,无论是在计算机方面还是生活方面都让我收获颇丰。这一年还是承蒙各位学长,朋友以及老师的关照了。这一年我对自己的认识是有些停滞不前的,似乎对很多事情已经丧失了大一的热情,所以这一年我对我自己的评价是摆烂的,但......
  • 【图像去噪(Image Denoising)】关于【图像去噪】专栏的相关说明,包含适配人群、专栏简介
    文章目录前言适配人群专栏简介专栏亮点阅读方法定价理由品质承诺关于更新环境配置去噪概述文章目录资料汇总(持续更新中。。。)问题汇总(持续更新中。。。)前言先思考几个问题:你是否在全网苦寻【图像去噪(ImageDenoising)】的相关资料?你的目标是否是看懂【图像去噪(Image......