RTC
实时时钟(RTC)是一个专用的计数器 / 定时器,可提供日历信息,包括小时、分钟、秒、日、月份、年份以及星期。RTC 具有两个独立闹钟,时间、日期可组合设定,可产生闹钟中断,并通过引脚输出;支持时间戳功能,可通过引脚触发,记录当前的日期和时间,同时产生时间戳中断;支持周期中断;支持自动唤醒功能,可产生中断并通过引脚输出;支持1Hz 方波和RTCOUT 输出功能;支持内部时钟校准补偿。
CW32L083 内置经独立校准的 32kHz 频率的 RC 时钟源,为 RTC 提供驱动时钟,RTC 可在深度休眠模式下运行, 适用于要求低功耗的应用场合。
RTC功能框图
RTC 时钟源RTCCLK 通过CR1寄存器进行选择,可选源为LSE、LSI和 HSE分频时钟。
主要功能
实时时钟 (RTC) 主要由专用的高精度 RTC 定时器组成,时钟源可选择外部低速时钟 LSE 或内部低速时钟 LSI,当选择外部高速时钟 HSE 时,因精度受限只能用作一般定时 / 计数器。
时间寄存器 RTC_TIME 和日期寄存器 RTC_DATE,以 BCD 码格式分别记录当前的时间和日期值,在对其写入时会自动进行合法性检查,任何非法的时间或日期值将不能被写入,如 32 日、2A 时、61 秒、13 月等。
日期寄存器 RTC_DATE 中,YEAR 位域表示年,有效值 0 ~ 99;MONTH 位域表示月,有效值 1 ~ 12;DAY 位域表 示日,有效值 1 ~ 31;WEEK 位域表示星期,有效值 0 ~ 6,其中 0 表示星期日,1 ~ 6 表示星期一至星期六。
时间寄存器 RTC_TIME 中,SECOND 位域表示秒,有效值 0 ~ 59;MINUTE 位域表示分,有效值 0 ~ 59;HOUR 位域代表小时,有效值为 1 ~ 12 或 0 ~ 23;HOUR 位域的最高位代表 AM/PM(上午 / 下午):- ‘0’表示 AM - ‘1’表示 PM HOUR。控制寄存器 RTC_CR0 的 H24 位域用于选择 12 或 24 小时制:• H24 为‘1’时,选择 24 时制 • H24 为‘0’时,选择 12 时制。HOUR位域值含义详细见下表:
其他功能
1.闹钟 A 和闹钟 B
RTC 支持 2 个独立闹钟(闹钟 A 和闹钟 B),可在一周内任意时刻产生闹钟事件,并产生闹钟中断,同时将闹钟匹配事件通过外部 RTC_OUT 引脚输出。设置控制寄存器 RTC_CR2 的 ALARMAEN 和 ALARMBEN 位域为 1,可分别单独使能闹钟 A 和闹钟 B。通过设置闹钟 A、B 控制寄存器(RTC_ALARMA 和 RTC_ALARMB)的时、分、秒匹配控制位 HOUREN、 MINUTEEN、SECONDEN 和时、分、秒计数值 HOUR、MINUTE、SECOND,可设定闹钟在‘xx 时 xx 分 xx 秒’, 或‘xx 分 xx 秒’或‘xx 时 xx 分’或‘xx 时’等多种组合产生闹钟事件;闹钟星期使能控制位 WEEKMASK,可选择一周中的任意一天产生闹钟事件,bit0 代表星期日,bit1 ~ 6 代表星期一至星期六。采用 12 或 24 小时制,闹钟控制寄存器 RTC_ALARMx(x = A, B) 的设置值可能不同,示例如下表:
2.周期中断功能:RTC 内置周期中断模块,可产生固定周期的中断信号。
3.自动唤醒功能
自动唤醒定时器是一个 16 位可编程自动重载减法计数器,计数时钟源为RTCCLK或者RTC1HZ时钟。定时范围为:61μs ~ 145h。当计数器溢出时,可产生自动唤醒中断,并将溢出标志通过 RTC_OUT 引脚输出。设置控制寄存器 RTC_CR2 的 AWTEN 位域为 1 使能自动唤醒功能,该功能专为低功耗应用场合而设计,可工作于 MCU 的全部工作模式。
自动唤醒定时器计数周期由计数时钟源和重载寄存器 RTC_AWTARR 决定,定时时长计算公式为:自动唤醒定时器定时周期 =(RTC_AWTARR+1)/ 唤醒定时器计数时钟频率 最短定时:( 0+1 ) / 16384Hz = 61μs 最长定时:(65535+1) / 0.125Hz = 524288s = 8738min ≈ 145.63h 通过 RTC 中断使能寄存器 RTC_IER 的 AWTIMER 位域,可选择自动唤醒定时器溢出时是否产生中断请求。
4.时间戳功能
RTC 支持时间戳功能,即通过 RTC_TAMP 引脚触发,将当前时间和日期分别保存到时间戳日期寄存器 RTC_TAMPDATE 和时间戳时间寄存器 RTC_TAMPTIM,同时可产生时间戳中断。控制寄存器 RTC_CR2 的 TAMPEDGE 位域用来选择触发时间戳的信号是上升沿还是下降沿有效,RTC_CR2 寄存 器的 TAMPEN 位域用于使能时间戳功能。用户可灵活选择触发引脚 RTC_TAMP,并需配置该引脚为数字输入和复用功能,具体 RTC_TAMP 引脚请参考数据手册引脚定义。当发生时间戳事件时,时间戳事件标志位 RTC_ISR.TAMP 会被置 1,如果设置了时间戳中断使能位 RTC_IER.TAMP 为 1,将产生中断请求。如果发生第一次时间戳事件后,未通过软件清除 RTC_ISR.TAMP 标志位,又产生了第二次时间戳事件,时间戳溢出标志位 RTC_ISR.TAMPOV 会被置 1,如果设置了时间戳溢出中断使能位 RTC_IER.TAMPOV 为 1,将产生中断请求。
实际例程操作——RTC初始化,日期时间读取,间隔中断,闹钟设置
1.系统时钟初始化设置
void RCC_Configuration(void) { RCC_HSI_Enable(RCC_HSIOSC_DIV6); //设置系统时钟为8M RCC_LSE_Enable(RCC_LSE_MODE_OSC, RCC_LSE_AMP_NORMAL, RCC_LSE_DRIVER_NORMAL); // 打开LSE时钟,作为RTC的计数时钟 RCC_APBPeriphClk_Enable1(RCC_APB1_PERIPH_RTC, ENABLE); //打开RTC模块工作时钟 }
2.配置输出时间所需GPIO口以及串口UART配置
void LogInit(void) { SerialInit(LOG_SERIAL_BPS); } static void SerialInit(uint32_t BaudRate) { uint32_t PCLK_Freq; GPIO_InitTypeDef GPIO_InitStructure = {0}; UART_InitTypeDef UART_InitStructure = {0}; PCLK_Freq = SystemCoreClock >> pow2_table[CW_SYSCTRL->CR0_f.HCLKPRS]; PCLK_Freq >>= pow2_table[CW_SYSCTRL->CR0_f.PCLKPRS]; // 调试串口使用UART5// PB8->TX// PB9<-RX// 时钟使能 __RCC_GPIOB_CLK_ENABLE(); __RCC_UART5_CLK_ENABLE(); // 先设置UART TX RX 复用,后设置GPIO的属性,避免口线上出现毛刺 PB08_AFx_UART5TXD(); PB09_AFx_UART5RXD(); PIO_InitStructure.Pins = GPIO_PIN_8; GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; GPIO_Init(CW_GPIOB, &GPIO_InitStructure); GPIO_InitStructure.Pins = GPIO_PIN_9; GPIO_InitStructure.Mode = GPIO_MODE_INPUT; GPIO_Init(CW_GPIOB, &GPIO_InitStructure); UART_InitStructure.UART_BaudRate = BaudRate;// 波特率 UART_InitStructure.UART_Over = UART_Over_16;// 采样方式 UART_InitStructure.UART_Source = UART_Source_PCLK;// 传输时钟源UCLK UART_InitStructure.UART_UclkFreq = PCLK_Freq;// 传输时钟UCLK频率 UART_InitStructure.UART_StartBit = UART_StartBit_FE;// 起始位判定方式 UART_InitStructure.UART_StopBits = UART_StopBits_1;// 停止位长度 UART_InitStructure.UART_Parity = UART_Parity_No;// 校验方式 UART_InitStructure.UART_HardwareFlowControl = UART_HardwareFlowControl_None; //硬件流控 UART_InitStructure.UART_Mode = UART_Mode_Rx | UART_Mode_Tx; // 发送/接收使能 UART_Init(CW_UART5, &UART_InitStructure); }
3.设置输出时间日期格式
void ShowTime(void) { RTC_TimeTypeDef RTC_TimeStruct = {0}; RTC_DateTypeDef RTC_DateStruct = {0}; static uint8_t *WeekdayStr[7]= {"SUN","MON","TUE","WED","THU","FRI","SAT"}; static uint8_t *H12AMPMStr[2][2]= {{"AM","PM"},{"",""}}; RTC_GetDate(&RTC_DateStruct);// 取用当前日期,BCD格式 RTC_GetTime(&RTC_TimeStruct);// 获取当前时间,BCD格式 printf(".Date is 20%02x/%02x/%02x(%s).Time is %02x%s:%02x:%02x\r\n", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Day, WeekdayStr[RTC_DateStruct.Week], RTC_TimeStruct.Hour, H12AMPMStr[RTC_TimeStruct.H24][RTC_TimeStruct.AMPM],RTC_TimeStruct.Minute, RTC_TimeStruct.Second);//串口打印数据 } Void RTC_GetDate(RTC_DateTypeDef* RTC_Date) { uint32_t RegTmp = 0; RegTmp = CW_RTC->DATE; while (RegTmp != CW_RTC->DATE) { RegTmp = CW_RTC->DATE; // 连续两次读取的内容一致,认为读取成功 } RTC_Date->Day = (uint8_t)(RegTmp & RTC_DATE_DAY_Msk); RTC_Date->Month = (uint8_t)((RegTmp & RTC_DATE_MONTH_Msk) >> 8); RTC_Date->Year = (uint8_t)((RegTmp & RTC_DATE_YEAR_Msk) >> 16); RTC_Date->Week = (uint8_t)((RegTmp & RTC_DATE_WEEK_Msk) >> 24); } Void RTC_GetTime(RTC_TimeTypeDef* RTC_TimeStruct) { uint32_t RegTmp = 0; RTC_TimeStruct->H24 = CW_RTC->CR0_f.H24; // 读CR0是否需要连读两次,待硬件检测 RegTmp = CW_RTC->TIME; while (RegTmp != CW_RTC->TIME) { RegTmp = CW_RTC->TIME; // 连续两次读取的内容一致,认为读取成功 } RTC_TimeStruct->Hour = (uint8_t)((RegTmp & RTC_TIME_HOUR_Msk) >> 16); RTC_TimeStruct->Minute = (uint8_t)((RegTmp & RTC_TIME_MINUTE_Msk) >> 8); RTC_TimeStruct->Second = (uint8_t)(RegTmp & RTC_TIME_SECOND_Msk); if (RTC_TimeStruct->H24 == RTC_HOUR12) { RTC_TimeStruct->AMPM = RTC_TimeStruct->Hour >> 5; RTC_TimeStruct->Hour &= 0x1f; } }
4.RTC模块初始化,ErrorStatus 返回值为SUCCESS或ERROR
ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct) { CW_SYSCTRL->APBEN1_f.RTC = 1; // 启动RTC外设时钟,使能RTC模块 if ((RCC_GetAllRstFlag() & SYSCTRL_RESETFLAG_POR_Msk) != RCC_FLAG_PORRST) //不是上电复位,直接退出 { RCC_ClearRstFlag(RCC_FLAG_ALLRST); return SUCCESS; } RTC_Cmd(DISABLE); // 停止RTC,保证正确访问RTC寄存器 RTC_SetClockSource(RTC_InitStruct->RTC_ClockSource); // 设置RTC时钟源, 用户需首先启动RTC时钟源!!! RTC_SetDate(&RTC_InitStruct->DateStruct);// 设置日期,DAY、MONTH、YEAR必须为BCD方,星期为0~6,代表星期日,星期一至星期六 RTC_SetTime(&RTC_InitStruct->TimeStruct); //时间,HOUR、MINIUTE、SECOND必须为BCD方式,用户须保证HOUR、AMPM、H24之间的关联正确性 RTC_Cmd(ENABLE); RCC_ClearRstFlag(RCC_FLAG_ALLRST); return SUCCESS; }
5.RTC周期中断时间设置
int RTC_SetInterval(uint8_t Period) { uint16_t timeout = 0xffff; RTC_UNLOCK(); if (IS_RTC_START()) // 如果RTC正在运行,则使用WINDOWS、ACCESS访问 { CW_RTC->CR1_f.ACCESS = 1; while ((!CW_RTC->CR1_f.WINDOW) && timeout--); if (timeout == 0) return 1; } CW_RTC->CR0_f.INTERVAL = Period; CW_RTC->CR1_f.ACCESS = 0; RTC_LOCK(); return 0; }
6.设置时钟中断使能
int RTC_ITConfig(uint32_t RTC_IT, FunctionalState NewState) { uint16_t timeout = 0xffff; RTC_UNLOCK(); CW_RTC->CR1_f.ACCESS = 1; while ((!CW_RTC->CR1_f.WINDOW) && timeout--); if (timeout == 0) return 1; if (!NewState) { CW_RTC->IER &= ~RTC_IT; } else { CW_RTC->IER |= RTC_IT; } CW_RTC->CR1_f.ACCESS = 0; RTC_LOCK(); return 0; } void RTC_IRQHandlerCallBack(void) { if (RTC_GetITState(RTC_IT_ALARMA)) { RTC_ClearITPendingBit(RTC_IT_ALARMA); printf("*********Alarm!!!!\r\n"); } if (RTC_GetITState(RTC_IT_INTERVAL)) { RTC_ClearITPendingBit(RTC_IT_INTERVAL); ShowTime(); } void NVIC_Configuration(void) { __disable_irq(); NVIC_EnableIRQ(RTC_IRQn); __enable_irq(); }
7.RTC时钟测试,初始化日历,使用间隔中断0.5秒通过Log输出日期时间
int32_t main(void) { RTC_InitTypeDef RTC_InitStruct = {0}; RTC_AlarmTypeDef RTC_AlarmStruct = {0}; /*系统时钟配置*/ RCC_Configuration(); /* GPIO 口配置*/ GPIO_Configuration(); LogInit();//配置输出时间所需GPIO口以及串口UART配置 printf("RTC Init...\r\n"); printf(" (RTC CR0:%04x,CR1:%04x,CR2:%04x,RESET FLAG:0x%08x)\r\n",CW_RTC- >CR0,CW_RTC->CR1,CW_RTC->CR2,CW_SYSCTRL->RESETFLAG); RCC_LSE_Enable(RCC_LSE_MODE_OSC, RCC_LSE_AMP_NORMAL, RCC_LSE_DRIVER_NORMAL); // 选择LSE为RTC时钟 RTC_InitStruct.DateStruct.Day = 0x21; //日 RTC_InitStruct.DateStruct.Month = RTC_Month_June;//月 RTC_InitStruct.DateStruct.Week = RTC_Weekday_Monday;//星期 RTC_InitStruct.DateStruct.Year = 0x21; //年 //设置日期,DAY、MONTH、YEAR必须为BCD方式,星期为0~6,代表星期日,星期一至星期六 printf("-------Set Date as 20%x/%x/%x\r\n", RTC_InitStruct.DateStruct.Year,RTC_InitStruct.DateStruct.Month,RTC_InitStruct.DateStruct.Day); //打印日期 RTC_InitStruct.TimeStruct.Hour = 0x11; //时 RTC_InitStruct.TimeStruct.Minute = 0x58;//分 RTC_InitStruct.TimeStruct.Second = 0x59;//秒 RTC_InitStruct.TimeStruct.AMPM = 0; RTC_InitStruct.TimeStruct.H24 = 0; //采用12小时设置 //设置时间,HOUR、MINIUTE、SECOND必须为BCD方式,用户须保证HOUR、AMPM、H24之间的关联正确性 printf("-------Set Time as %02x:%02x:%02x\r\n", RTC_InitStruct.TimeStruct.Hour,RTC_InitStruct.TimeStruct.Minute,RTC_InitStruct.TimeStruct.Second);//打印时间 RTC_InitStruct.RTC_ClockSource = RTC_RTCCLK_FROM_LSE; RTC_Init(&RTC_InitStruct); // RTC模块初始化, 用户需选定需要使用的时钟源 printf("=====Set interval period as 0.5s...\r\n"); RTC_SetInterval(RTC_INTERVAL_EVERY_0_5S); //闹钟为工作日上午的6:45 RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_WeekMON | RTC_AlarmMask_WeekTUE | RTC_AlarmMask_WeekWED | RTC_AlarmMask_WeekTHU |RTC_AlarmMask_WeekFRI; //设定时间为周一到周五 RTC_AlarmStruct.RTC_AlarmTime.Hour = 6; RTC_AlarmStruct.RTC_AlarmTime.Minute = 0x45; RTC_AlarmStruct.RTC_AlarmTime.Second = 0; RTC_SetAlarm(RTC_Alarm_A, &RTC_AlarmStruct); // 设置闹钟,BCD格式 RTC_AlarmCmd(RTC_Alarm_A, ENABLE);//使能闹钟 printf("=====Enable ALRAMA and INTERVAL IT...\r\n"); RTC_ITConfig(RTC_IT_ALARMA | RTC_IT_INTERVAL, ENABLE); //设置中断使能 While(1){} }
8.通过UART串口验证RTC工作正常
以上是CW32L083单片机的RTC设置时间及闹钟部分的介绍,CW32其他型号亦可参考此篇文档。有关芯片购买事宜,请咨询武汉芯源的销售和官方代理商。更多MCU详细信息,请访问武汉芯源官方网站:https://www.whxy.com。
来源:武汉芯源半导体
免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。
工程师笔记 | 解决RTC意外恢复到初始值问题
cathy 在 提交
STM32开发 -- RTC详解
cathy 在 提交
RTC为整个电子系统提供时间基准,主控设计均离不开RTC电路设计,在应用RTC时,会出现精度或功耗大的现象,如何解决RTC精度及功耗问题?本文将为您介绍时钟芯片应用问题及解决方法。
一、什么是RTC
实时时钟(Real_Time Clock)简称为RTC,主要为各种电子系统提供时间基准。通常把集成于芯片内部的RTC称为片内RTC,在芯片外扩展的RTC称为外部RTC,PCF8563是一款低功耗的CMOS实时时钟/日历外部芯片,支持可编程时钟输出、中断输出、低压检测等,与处理器通过I2C串行总线进行通信,最大总线速率可达400kHz。
二、RTC精度设计
RTC的主要职责就是提供准确的时间基准,计时不准的RTC毫无价值可言。目前部分MCU在片内已集成RTC,实际测试中在电池供电6小时环境下片内RTC的偏差在1-2分钟。因此,若对实时时钟有较高的要求则需优先考虑外扩RTC,同时要求时钟精度更高的RTC,比如PCF8563,表1所示是不同RTC的时钟精度对比。
1、电路设计
RTC设计电路简约而不简单,时钟芯片的选择、晶振的选择、电路设计、器件放置、阻抗控制、PCB走线规范均会影响RTC的时间基准的稳定性,图1为RTC芯片PCF8563电路设计。
2、晶体对地电容容值选择
负载电容:
Cload= [ (Ca*Cb)/(Ca+Cb) ]+Cstray
其中Ca、Cb为接在晶体两引脚到地的电容,Cstray为晶体引脚至处理器晶体管脚的走线电容(即杂散电容总和),一般Cstray的典型值取4~6pF之间;
如要满足晶体12.5pF负载电容的要求:
Cload= [ (15*15)/(15+15) ]+5=12.5pF
3、PCB布线
由于RTC的晶振输入电路具有很高的输入阻抗,因此它与晶振的连线犹如一个天线,很容易耦合系统其余电路的高频干扰。而干扰信号被耦合到晶振引脚导致时钟数的增加或者减少,考虑到线路板上大多数信号的频率高于32.768kHz,所以通常会发生额外的时钟脉冲计数,因此晶振应尽可能靠近OSC1和OSC2引脚放置,同时晶振、OSC1和OSC2的引脚最好布成地平面,具体PCB布线如图3所示。
4、电路相关说明
如图1所示,R56、R57为I2C总线上拉电阻,PCF8563中断输出及时钟输出均为开漏输出,所以也需要外接上拉电阻,如图1中的的R58、R59,若不使用这两个信号,对应的上拉电阻可以不用。
对于PCF8563芯片,需外接时钟晶振32.768kHz(如图1的X1),推荐使用±20ppm或更稳定的晶振。PCF8563典型应用电路推荐使用15pF的晶振匹配电容,实际应用时可以作相应的调整,以使RTC获得更高精度的时钟源。一般晶振匹配电容在15pF~21pF之间调整(相对于±20ppm精度的32.768kHz晶振),15pF电容时时钟频率略偏高,21pF电容时时钟频率略偏低。
5、精度调整方法
- 设置PCF8563时钟输出有效(CLKOUT),输出频率为32.768kHz;
- 使用高精度频率计测量CLKOUT输出的频率;
- 根据测出的频率,对CB1、CB2、CB3作短接或断开调整,频率比32.768kHz偏高时,加大电容值,频率比32.768kHz偏低时,减小电容值。
说明:图1中的C41、C42、C43的值在1pF~3pF之间,根据实际情况确定组合方式,以便于快速调整,推荐使用(3pF、3pF、3pF)、(1pF、2pF、3pF)、(2pF、3pF、4pF)。
三、RTC低功耗设计
很多RTC设计成可以只依靠一块电池供电就能工作,如果主电源关闭,仅依靠一小块锂电池就能够驱动振荡器和整个时钟电路,如何降低RTC电路工作时功率消耗?
通过应用几种不同的方法可以降低RTC功耗:
本文转自: ZLG立功科技,转载此文目的在于传递更多信息,版权归原作者所有。
在非常温的工作环境下,RTC时钟出现偶发性的延时或者超时现象。成熟的RTC电路设计看似简单,但如何保证RTC时钟的精确度?在出现偶发性异常现象时,如何快速定位和解决问题?本文将分享一个案例。
案例情况
工控板使用了NXP的PCF8563 RTC 芯片方案,在研发做环境温度摸底测试的时候, RTC时钟出现偶发性延时或者超前现象,于是研发展开一系列的问题定位。
排查分析
1、工控板使用了NXP的PCF8563 RTC 芯片方案,该方案是外置32.768kHz的石英晶体和电容,该RTC芯片的输出精度取决于其外接的石英晶体输出的时钟频率是否精准。
石英晶体本身输出频率带有一定的误差,常温25℃下,频率的误差为±20ppm,平均误差可达5分钟/年。且随着时间的增加,晶体电路元件的缓慢变化会造成长期性的频率漂移。同时,在外部温度较为极端的时候,时钟震荡回路可能出现异常,影响到RTC的正常计时。
2、工控板RTC芯片供电电池选用了型号为CR2032的锂二氧化锰电池,该电池理论工作温度范围是-30℃~60℃。
和其他锂电池类似,若外部温度较为极端的时候,会改变其内部的化学反应,导致电池寿命的降低或者电压异常的风险,从而影响RTC电路的正常工作。
解决方案
极限温度下长时间的高精度保证,有以下的解决方案:
1、选择带有温度补偿的RTC芯片如EPSON的RX-8025T。这款芯片是内置32.768kHz的晶体,具有高精度的温度补偿功能,输出的波形都是经过温度补偿校准过的,这样可以提高RTC的稳定性和精度。因为内嵌的晶体已经经过高温老化处理,比独立的晶体有更好的稳定性,精度误差在-40℃~85℃范围内小于±5ppm。
2、选择工业级电池(例如:FANSO ER14505)。理论上在工作温度-40~85°范围内能正常工作。参考电路图如图2所示:
由图2可知,RTC芯片工作电源由系统VCC_3.3电源和电池电源两部分组成。此电源电路的设计目的是当有外部电源供电时,RTC时钟工作时使用由外部电源经LDO转化而来的VCC_3.3电源,当外部电源停止供电时就自动切换到电池电源供电。这样可以保证RTC芯片一直能够正常地工作,同时可以延长电池的使用时间。
此电路的设计如以下所述:
1、电源切换电路设计
由RX-8025T芯片的数据手册上可知:
• 其工作电压范围是1.7V到5.5V;
• 系统电源为3.3V、工业级电池ER14505电压为3.6V;
• 可以通过二极管的正向导通特性来自动切换系统电源和电池电源的供电状态,使得RTC芯片能够保持正常工作状态。
由于系统电源电压为3.3V,电池电压为3.6V;如果要做到优先使用系统电源,那么就需要系统电源经过二极管后的电压比电池经过二极管后的电压要高,这样才能保证由系统电源优先工作。
可以通过选择两只不同管压降的二极管来实现,二极管SS14的正向导通电压为0.2V左右,1N4148的正向导通电压为0.7V左右。那么可以在系统电源线路上串接一只SS14二极管,而在电池供电线路上串接一只1N4148二极管;这样当外部供电时,系统电源经过SS14后得到的电压值大于电池经过1N4148后的电压值,此时由主电源供电;当外部电源停止供电后,电路自动切换成电池供电状态。
2、电压滞后处理
ER14505电池是一种供电电压为3.6V ,容量为2700mAh的锂亚硫酰氯电池;它的自身容量损耗极小,可以忽略不计。以待机电流为20uA计算,电池的供电可以达15年左右。
但是在实际应用中,发现在系统电源长期供电后,突然切换到电池供电时发生电压不足,导致RTC时钟出现异常,其根本原因是电池发生了钝化现象。
当RTC芯片由系统电源供电时,锂电池相当于闲置开路,如果电池闲置的时间过长,那么电池的内部会产生钝化膜,而切换到锂电池供电时,如果滞后的电压低于时钟芯片的工作电压,那么时钟芯片就会完全“失压”,系统时钟就会恢复到初始时间,导致时钟工作异常。为了消除这种现象的影响,我们可以通过在时钟芯片的电源上增加储能电容,以消除这种影响。
3、控制钝化膜生成
电池的钝化膜是由于电池长时间处于闲置开路状态而形成的,那么我们可以使电池一直维持在一个较小的电流放电工作状态,这样可以减缓电池的钝化膜生成的速度。通过选择合适的电阻值,使电池处于放电状态,比如放电电流控制在待机电流20uA左右,这样电池容量足够支撑15年左右,同时不会使钝化膜过厚而出现电压滞后导致RX-8025T完全掉电现象,从而影响RTC时钟的正常工作。
• 当系统电源供电时,Q1导通,由电池BT1、R1、Q1形成回路,实现电池的放电状态;
• 当系统电源停止供电时,Q1截至,电池经过D2给RTC芯片U1供电。
经实测时钟芯片及电池内阻自放电的电流为8uA左右,那么我们需要控制的电阻R1的阻值为3.6V/(20-8)uA=300k。
4、PCB设计
在PCB layout的时候需要注意RX-8052T与MCU的I2C走线应该越短越好,并且远离高频、高电流的信号线。同时旁路电容也应该靠近RX-8025T的电源端,并增加地线敷铜的面积,以防止干扰的产生。
来源: ZLG致远电子
一、什么是RTC
实时时钟(Real_Time Clock)简称为RTC,主要为各种电子系统提供时间基准。通常把集成于芯片内部的RTC称为片内RTC,在芯片外扩展的RTC称为外部RTC。
二、 RTC的发展
1、早期RTC
早期RTC常使用74/54系列、CC4000系列及555集成电路构建秒脉冲源,再利用分频器、计数器、缓存器等得到分、时、日、月、年的计时信号,最后通过通信口送到处理器处理。由于电路搭建复杂且受器件特性影响较大,这样的RTC往往精度差、功耗大且占用大面积PCB空间,且这类产品面临“2000年”的问题(千年虫问题详见百度)。
2、中期RTC
这一时期的RTC出现在20世纪90年代,由于采用特殊CMOS工艺,因此功耗大为降低,典型值约0.5μA以下,供电电压仅为1.4V以下。为节约宝贵的IO接口,通讯口也变为串行方式,出现了诸如三线SIO/四线SPI,部分产品采用2线I2C总线。封装上采用SOP/SSOP封装,体积大为缩小。得益于半导体技术的发展,这时的RTC精度、功耗等特性上得到实质性提高,已具备万年历功能甚至可以做到晶振停振自动检测功能。目前这类RTC正被广泛使用。
3、新一代RTC
最新一代RTC产品中,除了包含第二代产品所具有的全部功能,更加入了复合功能,如低电压检测,主备用电池切换功能,抗印制板漏电功能,且本身封装更小(高度0.85mm,面积仅为2mm*2mm)。
三、RTC使用
RTC设计推荐方案如图4所示,若采用I2C/SPI通信的RTC IC且已具备I2C/SPI驱动程序,RTC的使用就显得尤为简单,仅需要加上晶振电路就可以工作了。
RTC设计电路简约而不简单,时钟芯片的选择、电路设计、器件放置、阻抗控制、PCB走线规范均会影响RTC的时间基准的稳定性,如图5所示为致远电子基于Cortex-A7架构的800MHz主频的M6Y2C-256F256LI-T核心板以及配套硬件开发指南,致远电子每一款核心板均有提供标准的推荐电路,为设计者提供稳定可靠的设计参考。
软件方面,我们仅以linux为例了解下RTC的使用。在内核配置中选择与硬件匹配的RTC驱动,以生成正确的内核镜像。
然后结合硬件测试RTC功能,使用命令date –-help获取相关指令。hwclock –w命令将设置的时间同步到硬件,hwclock命令获取RTC时间,判断是否同步成功。
四、RTC问题
1、计时不准
RTC的主要职责就是提供准确的时间基准,计时不准的RTC毫无价值可言。目前部分MCU在片内已集成RTC,实际测试中在电池供电6小时环境下片内RTC的偏差在1-2分钟。因此,若对实时时钟有较高的要求则需优先考虑外扩RTC,若能支持温度自动补偿则精度更佳,如DS3231、PCF2129可以在后备电池供电时根据温度变化自动修改补偿量。
2、无法读写
RTC无法读写(通信)时可从软、硬件两方面考虑。软件方面重点考虑通信驱动的问题,在嵌入式linux系统中常表现出RTC驱动无法检测到RTC的存在。比如在启动信息中打印pcf8563_get_datetime: read error,或者无法对I2C/SPI操作。这类问题可以使用带协议解码的示波器排查、验证。
硬件方面,以常用的I2C为例,最不可忽视的则是上拉电阻的使用。I2C上拉电阻选择1K-10K为宜,可根据通信速率、长度、节点数而定。在节点数多、干扰大时还应在SDA、SCL线上串联100~200ohm左右的电阻,有效抑制干扰脉冲。另外,所有IC都有意外损坏的可能,必要时更换RTC芯片。
3、掉电不保存
这种情况最可能的原因是未使用备用电源或备用电源没电了,应检查硬件电源电路。软件方面可能在用户程序、自启动脚本中设置了RTC,每次重启则将RTC恢复为默认值,这时应从启动打印信息或系统日志中排查。
转自: ZLG致远电子
RTC-Real Time Clock是430单片机的实时时钟模块,可以配置成实时时钟模式(万年历)或者一般目的的32位计数器模式,其中实时时钟模式提供了年月日、时分秒,可以选择BCD码或者二进制格式,并且具有可编程的闹钟。RTC模块支持中断。相关寄存器请参阅430系列单片机user's guide(我用的是5438A)。
1.计数器模式
实时时钟控制器寄存器1 RTCMODE位被重置时,计数器模式被选择,通过软件设置可以得到一个32位的计数器。从时钟模式切换到计数器模式是通过重置计数值:RTCNT1、RTCNT2、RTCNT3、RTCNT4 和 预换算计数器:RT0PS、RT1PS。
计数器的增量计数器来自ACLK、SMCLK或者分频之后的ACLK、SMCLK。分频系数来自分频除法器RT0PS、RT1PS。RT0PS的输出可以和RT1PS的输出级联构成32位计数器的时钟源。4个独立的8位计数器级联成为32位的计数器。这能提供计数时钟的8位、16位、24位、32位溢出中断。RTCTEV位选择各自的触发,通过设置RTCTEVIE位,一个RTCTEV能够触发一个中断。计数器RTCNT1到RTCNT4都可以单独访问,并可能被写入数值。
2.日历模式
当RTCMODE被置位时,万年历模式被选中。值得一提的是,万年历模式有能够计算能否被4整除的闰年算法,这个算法范围是1901年到2099年。
2.1预分频
分频器自动将RT0PS和RT1PS配置成为实时时钟提供一秒间隔的时钟,RT0PS源于ACLK,一般来说ACLK为32768Hz,是为了实时时钟的运行。从日历模式切换到计数器模式时,会将年月日、时分秒全部被置位1,RT0PS和RT1PS也会被置位。当RTCBCD=1时,日历寄存器会被选为BCD码,必须在时间设置之前选择好格式,改变RTCBCD的状态和切换到计数器模式影响一样。
2.2闹钟功能
用户可编程闹钟只有在日历模式下有效。每一个闹钟寄存器都包括都包括一个闹钟使能位,AE用来修改每一个闹钟寄存器,通过设置闹钟寄存器的AE位,可以产生多种闹钟。无效的闹钟不会通过硬件的检测,所以用户有必要检查所设闹钟是否正确。
2.3读写实时时钟寄存器
系统时钟和实时时钟的时钟源异步,因而读写实时时钟寄存器的时候要注意。此时实时时钟寄存器每秒钟更新一次,为了防止在更新的时候读取实时时钟数据而造成错误数据的读取,应该设置一个禁止进入的窗口,在禁止进入窗口和窗口外期间,只有RTCRDY复位有效才可以读取。在RTCRDY复位的时候,读取操作是错误的并且读取的时间数据也无效被忽略。
2.4时钟中断
由于我做的部分只涉及实时时钟显示,中断部分没有过多涉及,就不在讨论了。
RTC实时时钟显示部分程序结构如下:
//只是部分代码,远未完整,只是说明一下框架 void Init_RTC(void)//初始化RTC { RTCCTL01 = RTCSSEL_0 + RTCMODE; // 时钟模式,每分钟中断, BCD格式 unsigned int hour,min,sec; hour=key[0]*10+key[1]; min =key[2]*10+key[3]; sec =key[4]*10+key[5]; SetRTCYEAR(2012); SetRTCMON(6); SetRTCDAY(1); SetRTCHOUR(hour); //按键设定时间 SetRTCMIN(min); SetRTCSEC(sec); } while(key_C) //扫描按键 { if(key_stime_ok) { char str[4]; key_stime_ok=0; key_temp=Read_Key();//读取按键数值 if(key_temp != No_key) { key[key_C-1]=key_temp; sprintf(str,"%d",key_temp); PutStringEN24(60,k,str); k-=16; key_C--; } } } void Show_Clock(void) { unsigned int Hour ,Minute,Second; char p1[10],p2[10],p3[10]; for(;RTCCTL01&RTCRDY;) _NOP(); // 等待RTC有效 for(;RTCCTL01&RTCRDY;) _NOP(); Hour = GetRTCHOUR(); Minute = GetRTCMIN(); Second = GetRTCSEC(); sprintf(p1,"%02d",Hour); sprintf(p2,"%02d",Minute); sprintf(p3,"%02d",Second); PutStringEN24(1,2,p1); //用的TFT屏显示时钟 PutStringEN24(1,34,":"); PutStringEN24(1,50,p2); PutStringEN24(1,82,":"); PutStringEN24(1,98,p3); }
转自:博临天下
前言
客户反馈在批量生产阶段,发现部分产品的MCU的RTC在低温(0℃)下工作不正常,但是在常温下又是正常的,且其他正常的MCU的RTC在常温与低温下都是正常的。
问题跟进
通过与客户邮件沟通,了解到客户使用的MCU型号是STM32F030C6T6TR。在产品的主从结构中主要用作电源管理和时钟管理。通过客户的描述,似乎相同型号不同片子都存在较大的差异。
由于时间紧急,在了解到初步信息后拜访客户,针对客户认为有问题的MCU芯片做针对性试验。通过STM32CubMx生成测试工程,分别使用LSI(40K),LSE(32.768K),RTC工作时每秒通过LED1(PB5)取反一次(通过LED1灯是否闪烁来指示RTC是否工作正常),然后分别测量OSC管脚与PA8脚(输出LSI或LSE),并对比ST官方的NUCLEO-F030板,最终测试结果如下:
1、当使用LSI时,无论常温还是低温下都能正常工作。
2、当使用LSE时,常温下能正常工作,但在低温(0℃)时,RTC不再工作(LED1停止闪烁),且PA8管脚无输出,但保持为高电平,且此时OSC管脚此时是存在32.768K的波形的。
3、通过修改负载电容C1&C2的电容值从5.1pF修改到6.8pF时,原本低温下不工作的RTC又能恢复正常工作。
4、对比ST官方的NUCLEO-F030板子,在常温与低温下均能正常工作。
从测试结果来看,通过修改负载电容的方式能让原本不能正常工作的RTC恢复正常工作,这个似乎为客户的负载电容不能精准的匹配系统的原因所致。
但客户对于这个做法不接受的,理由是现在设计的负载电容5.1pF是通过测试后的值,精度可以达到6.5ppm,但如果改为6.8pF,那么精度将会变到大约30ppm,这个会影响到MCU的RTC的时间精准度,系统在长时间运行后,时间必然会偏差很大,超出设计合理范围,这个是不允许的。
问题分析
既然客户不接受修改负载电容,那么首先我们重新梳理下客户的晶振设计各种参数是否准确,客户的LSE电路设计如下所示:
如上图,图中的MR10 10Mohm这个反馈电阻在实际电路中是没有加的,晶振使用的是TXC的,从晶振厂商提供的数据手册中得到相关参数如下:
再者,由于客户代码中使用的LSE drive配置的是最高等级,从下图芯片对应的数据手册中可以找到对应的gm值为25uA/V,此时的驱动电流为1.6uA:
前面提到过AN2867这个文档,我们打开这个文档,在3.4节,发现有这个要求:
也就是要求gain margin的值要求大于5,这样晶振才能正常起振,那么gain margin又是如何计算的呢?接下来找到gainmargin 的计算公式,如下:
其中gm就是图4中从数据手册中提到的跨导值,STM32F030 LSE的不同驱动等级对应着不同的gm值,由于我们的测试代码使用的是CubeMx自动生成的代码,其默认使用的是最高等级,且客户使用的也是最高等级,因此,这个得出的gm值为25 uA/V, gm有了,那么上面公式中的gmcrit又该如何计算,我们接下来找到它的计算公式,如:
通过晶振对应参数,我们可以得出:
ESR =70KΩ,C0 =1.0pF, CL =7.0pF, 而F就是LSE的频率,为32.768KHz.
于是:
g_mcrit =4 * 7E4 *POWER(2*PI()*32768,2) * POWER ((1.0E-12 + 7.0E-12),2) =7.6E-07
最终得到:
gain_magin =gm/g_mcrit=2.5E-05/7.6E-07 =32.89
这个值是远大于5,因此,理论上不会存在晶振不起振是的问题,实际上当在低温下,之前在测试中也有发现晶振也是有起振,有波形输出的,只不过PA8脚没有波形输出,那个又是什么问题呢?
最终定位到LSE的驱动等级过高,在AN2867这个文档中,有这样的描述:
也就是说,在STM32F0和STM32F3中,当使用最高驱动模式(gm_crit_max=5uA/V, 见Figure9gm_crit_max)时,对应地应该只使用在CL=12.5pF的晶振上,以此避免振荡回路饱和,从而导致启动失败。若此时使用了一个较小的CL(如CL=6pF),那么会导致振荡频率不稳定和工作周期可能被扭曲。
AN2867随后给出了一张表,列出了驱动等级与gm_min、gm_crit_max的关系,如下:
如上图,对于STM32F0,当使用最高驱动模式High时,此时的gm_min=25 uA/V,这个与数据手册中是一致的,另外gm_crit_max=5uA/V,正是上面所描述的。
也就是说,在使用最高驱动模式下,此时与之对应的CL应该使用12.5pF,而客户所使用的CL是7pF,这个与手册AN2867的建议内容是不相符的。从图4可以看出,在最高驱动等级模式下,此时驱动电流最大(1.6uA),但这里使用了一个比较小的负载电容(CL=7pF),按AN2867所述,此时有可能导致振荡回路饱和,振荡不稳定,工作周期扭曲。
此时,应该对应地下调这个LSE驱动等级,减小驱动电流,这里有4档(见Figure9):Low,Medium Low,Medium High,High. 目前使用的是High,正是它出了问题,为保守起见,使用Medium High相对合适。
如上图,将LSEDRV[1:0]这两个为修改为10即可,将原先低温下RTC有问题的MCU芯片修改后再次放到低温下进行验证,测试结果为正常。由于此问题是部分芯片有可能会出现的问题,客户需要对修改后的芯片进行持续跟踪,至今没有再反馈出现过此问题,由此,此问题基本解决。
总结
AN2867这个文档总结了关于STM32晶振匹配方面的信息。里边有提到,负载电容CL值越大,所需的驱动电流也就越大,但牵引度越小。这也就解释了表1中通过增大C1&C2的电容值,原本出现问题的RTC能恢复正常的现象,这是由于C1&C2的电容值变大将导致负载电容CL变大,进而对应所需的驱动电流也就跟着增加,这反而减少了在高驱动模式情况下振荡回路出现饱和的机会。
来源: STM32单片机