历史上的今天
今天是:2024年10月05日(星期六)
2018年10月05日 | stm32学习笔记(1):实时时钟RTC
2018-10-05 来源:eefocus
太久没写过像样的文,先从学习笔记开始,之后逐渐补充这个月以来的单片机学习笔记。
-------------------------------------我是分界线你看不见-------------------------------------------
1.RTC简介
(关于stm32的实时时钟RTC的介绍,参考手册甚是详细,自可参考,编程时不懂查阅即可,不必死背硬记。)
STM32的实时时钟(RTC)是一个独立的定时器,RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能,修改计数器的值可以重新设置系统当前的时间和日期。
RTC模块和时钟配置系统(RCC_BDCR寄存器)是在备份区域,即在系统复位或从待机模式唤醒后RTC的设置和时间维持不变。但是在系统复位后,会自动禁止访问后备寄存器和RTC,以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前, 先要取消备份区域(BKP)写保护。
使用库函数RCC_APB1PeriphClockCmd()设置寄存器 RCC->APB1ENR位使能PWR时钟
使用库函数PWR_BackupAccessCmd()设置寄存器PWR->CR的PWR_CR_DBP位使能对后备寄存器和RTC的访问
-------------------------------------我是分界线你看不见------------------------------------------
2.RTC编程
(关于stm32的实时时钟RTC的编程,在ST提供的库函数驱动中也十分详细,亦自可查阅使用。)
下面以经过小修改的例程来调戏一下RTC:让单片机每天于早上8点开始正常工作,18点进入待机模式。因此该程序主要的设置在于两方面:
(1)关机:设置好闹钟alarm A的时间,以及对应的RTC中断驱动,由闹钟中断重设闹钟时间,并且进入Standby Mode,由备用电源VBAT对RTC和备份寄存器进行供电;
(2)开机:通过闹钟唤醒单片机,此过程相当于power on reset, and restart the program。因此在主函数中重设闹钟。RTC和5个备份寄存器在电源复位或器件从待机模式唤醒时不会丢失。
大致过程如上,RTC正常工作的一般配置步骤如下:
(1)RTC_Config(void):设置RTC控制寄存器
1)使能电源时钟和备份区域时钟。
前面已经介绍了,我们要访问RTC和备份区域就必须先使能电源时钟和备份区域时钟。这个通过RCC_APB1ENR寄存器来设置。
2)取消备份区域写保护。
要向备份区域写入数据,就要先取消备份区域写保护(写保护在每次硬复位之后被使能),否则是无法向备份区域写入数据的。我们需要用到向备份区域写入一个字节,来标记时钟已经配置过了,这样避免每次复位之后重新配置时钟。
3)复位备份区域,开启外部低速振荡器。
在取消备份区域写保护之后,我们可以先对这个区域复位,以清除前面的设置,当然这个操作不要每次都执行,因为备份区域的复位将导致之前存在的数据丢失,所以要不要复位,要看情况而定。然后我们使能外部低速振荡器,注意这里一般要先判断RCC_BDCR的LSERDY位来确定低速振荡器已经就绪了才开始下面的操作。
4)选择RTC时钟,并使能。
这里我们将通过RCC_BDCR的RTCSEL来选择LSE作为RTC的时钟。然后通过RTCEN位使能RTC时钟。
(2)RTC_Init(&RTC_InitStructure):初始化RTC时间和闹钟寄存器
1)设置RTC的分频。
在开启了RTC时钟之后,我们要做的就是设置RTC时钟的分频值,通过库函数RTC_Init()来设置RTC_SynchPrediv和RTC_AsynchPrediv,然后等待RTC寄存器操作完成,并同步。
2)配置RTC时钟。
通过库函数RTC_TimeRegulate()和RTC_ALARMARegulate()设置时间和闹钟。
3)更新配置。
在设置完时钟之后,我们将配置更新,这里还是通过RTC_CRH的CNF来实现。在这之后我们在备份区域RTC_BKP_DR0中写入0x32F0代表我们已经初始化过时钟了,下次开机(或复位)的时候,先读取RTC_BKP_DR0的值,然后判断是否是0x32F0来决定是不是要配置。
(3)实现programming alarm A中断服务程序
1)Configure and enable the EXTI line corresponding to the RTC Alarm event in interrupt mode and select the rising edge sensitivity.
EXTI_ClearITPendingBit(EXTI_Line17);
EXTI_InitStructure.EXTI_Line = EXTI_Line17;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
2)Configure and enable the RTC_ALARM IRQ channel in the NVIC.
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
3)最后,我们要编写中断服务函数,在秒钟中断产生的时候,重设闹钟时间,并且进入Standby Mode。
void RTC_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_ALRA) != RESET)
{
RTC_ALARMARegulate(8,0,0);//--------重设ALARM A-------
RTC_TimeShow();//-------清除中断标记-------
RTC_ClearITPendingBit(RTC_IT_ALRA);
EXTI_ClearITPendingBit(EXTI_Line17);
PWR_EnterSTANDBYMode();//----Enter Standby mode----
}
}
(4)调试时其余硬件设置:初始化USART和LED,便于观察程序效果。
void USART_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_AHBPeriphClockCmd( RCC_AHBPeriph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE );
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_1);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_1);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200;//设置串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//设置数据位
USART_InitStructure.USART_StopBits = USART_StopBits_1;//设置停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//设置效验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//设置流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//设置工作模式
USART_Init(USART1, &USART_InitStructure); //配置入结构体
USART_Cmd(USART1, ENABLE);//使能串口1
}
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_12 ;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed =GPIO_Speed_Level_3;
GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_SetBits(GPIOA, GPIO_Pin_11 | GPIO_Pin_12 );
}
void LED_Open(void)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_11);
}
-------------------------------------我是分界线你看不见------------------------------------------
3.实时时钟RTC注解和说明
(1)RTC时钟源可以是以下三种之一:
——HSE时钟除以128
——LSE晶体振荡器时钟
——LSI晶体振荡器时钟
其中LSE为内部低频RC晶体振荡器,关于上述三个时钟特点详解下图。
![[转载]stm32学习笔记(1):实时时钟RTC [转载]stm32学习笔记(1):实时时钟RTC](https://8.eewimg.cn/news/uploadfile/2018/1005/20181005085702347.jpg?imageView2/2/w/550)
(2)RTC完全独立于RTC APB1接口:
软件通过APB1接口访问RTC的分频值、计数器值和闹钟值等。但是,相关的可读寄存器只在与RTC APB1时钟进行重新同步的RTC时钟的上升沿被更新,RTC标志亦是如此。
因此,若发生以下三种情况:
——发生系统复位或电源复位;
——系统刚从Standby Mode唤醒;
——系统刚从Stop Mode唤醒;
若要读取RTC寄存器的值,则软件首先须使用库函数 RCC_APB1PeriphClockCmd()重新使能APB1时钟,并使用RTC_WaitForSynchro()等待时钟同步完成。
-------------------------------------我是分界线你看不见------------------------------------------
4.RTC晶振问题
STM32的RTC对晶振的高度挑剔估计让很多人头疼。某师兄曾经在某宝上入手了一块STM32的板子,结果LSE不起振。怒摔再购之,这块板子的LSE起振了。然后就传入我手中,苦恼发现晶振不准……我忍了,于是对分频值细细调整,但是……时钟走得时快时慢这是闹哪样……问苍天捶大地仰天长啸吐血三升。
以下为个人关于RTC晶振问题的避免以及解决方法的见解(有些未尝试过,但据论坛讨论可用于借鉴参考)
(1)LSE不起振:
1)最好选用说6pF的晶振以及6pF的负载电容,并且选用精度高一点的晶振;
2)注意晶振周围的环境,有人指出应该仔细清洗RTC晶振周围的电路,甚至是使用环氧树脂胶将晶振密封起来;
(2)Standby Mode下时钟不稳定:提高Vbat引脚的电源质量;
(3)时钟过快或者过慢:
如果晶振通过分频后的实际时钟效果与公式计算的频率不同,一可以通过调整分频值来调整时钟频率,二是可以通过RTC校准功能来调整时钟频率。其中第二种方法适用于温度差异补偿以及细微时钟偏差补偿。
【若差别过大只可通过调整分频值,时钟校准功能仅可进行细微的时钟补偿。若LSE分频值为默认值32768HZ时,时钟校准功能可以作用的范围为:32768HZ-32772HZ(当仅可减慢时)(具体补偿操作和效果可查看ST官方参考手册)】
综上:最好的其实是选购一个合适的并且质量相对较好的晶振。
下一篇:stm32串口加dma接收问题
史海拾趣
|
摘 要: 随着VLSI的集成度越来越高,设计也越趋复杂。传统的设计方法如原理图输入、HDL语言描述在进行复杂系统设计时,设计效率往往比较低。特别是在算法由软件转化为硬件的环节上,传统的设计方法的效率不是很高,设计者往往要耗费大量的时间和精 ...… 查看全部问答> |
|
现在要为已经有的驱动程序(以前通过手工的方式拷贝文件和执行注册表文件)编制INF文件,但是不知道其GUID,导致Windows通过编制的INF文件,仍然无法识别驱动程序。 请问有没有什么办法获取原有驱动文件的GUID(源代码已经丢失)?… 查看全部问答> |
|
请教各位大侠,设置ARM Linker的Output时,RO Base 如何设置,我在编译时,老是说“Entry point lies outside the image.”还有一个Warning: Ignoring -first command.Cannot find section 2410 init.s(Init). 谢谢! … 查看全部问答> |
|
请问当arm通过网口下载了映像后,为什么tshell执行i没有问题,串口一执行i就死掉? 请问当arm通过网口下载了映像后,为什么tshell执行i没有问题,串口一执行i就死掉? 为了验证串口是否好用,在映像起来后,做了个周期打印的程序,可以在串口打印,没有问题,但是只要一执行i,马上打出部分东东,串口就死掉了,同时通过tshell可以 ...… 查看全部问答> |
|
新手求教“JTAGCommunicationfailured” 这一阵开始学习STM32,从网上下了一例子,是按钮控制小灯的,但后来就一直不能下程序,总出现“JTAG Communication failured”,先前一直不知道什么原因,在论坛里找帖子才知道是自己在程序里把JTAG口禁用了,这样导致再也下载不下去程序了, ...… 查看全部问答> |
|
请教一下,这个程序是DSP中的自适应滤波例子程序, 其中一行我感觉有问题,我已经用红色标示,不知大家怎么看了??? #include\"math.h\" #define PI 3.1415926 #define Coeff 16 //定义阶数16阶 #define num 1024 // ...… 查看全部问答> |
|
TI Code Composer Studio (CCS) v4.x中文应用指南-软件、安装、注册、教程、示例全集 TI开发软件Code Composer Studio IDE v3.3 全新 Code Composer Studio 3.3 (CCStudio v3.3) 白金版支持多处理器运行将分析特性提高到新的水平,可不断满足高级嵌入式系统开发发展的需求。统一的新型断点管理器、缓存状态可视化工具,完全集成的分 ...… 查看全部问答> |
|
我们都知道CM3内核支持中断嵌套,即当一个中断正在进行处理时来了一个抢占优先级高于当前正在被处理的中断的新的中断,则内核会将当前中断挂起,转而执行抢占优先级更高的新来中断,这种中断嵌套属于被动式抢占;还有一种情况,就是,当前正在处理 ...… 查看全部问答> |




