公司负责硬件的同事测试发现,RTC使用外部晶振时,由于一些干扰(高频信号之类的),外部晶振会出现不起振的情况,于是就决定把外部晶振取消了,又因为设备要低功耗的,就没用有源的晶振,于是乎就用了STM32内部的RC时钟
RC时钟的两个分频值都可以设置,校准的原理很简单,固定一个分频值,然后动态调整另一个分频值ji就OK了。
校准步骤:
1、首先随便设置两个个分频值,比如127,255,其中固定的值为127,另一个分频值为Y1(此处的Y1就是255)
2、然后利用秒中断(或者与秒中断等效的代码),获取RTC发生一次秒中断所需要的实际时间T1,单位是ms
3、利用公式 Y2=Y1*1000/T1,得到新的分频值Y2。
4、然后用127(固定值),和新的分频值Y2,重新配置RTC,至此,一次校准就完成了,然后可以利用RTC做计时
5、把Y2写入RTC的备份寄存器或者Flash或者EEPROM,以备下次使用
6、把Y2当作Y1,重复1到5的步骤
具体代码实现:
void vRtcCalibrate(void)
{
uint32_t ulStartTime;
uint32_t ulEndTime;
uint32_t ulSynchPrediv = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);
DEBUG0("ulSynchPrediv:%u\r\n",ulSynchPrediv);
/* 备份寄存器上电值为0 */
if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) == 0){
hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
hrtc.Init.AsynchPrediv = 36;
hrtc.Init.SynchPrediv = 999;
hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
DEBUG0("RTC校准失败1\r\n");
return ;
}
/* 等待RTC时钟运行稳定 */
HAL_Delay(500);
}else{
hrtc.Init.AsynchPrediv = 36;
hrtc.Init.SynchPrediv = ulSynchPrediv;
}
DEBUG0("hrtc.Init.AsynchPrediv: %u\r\n",hrtc.Init.AsynchPrediv);
DEBUG0("hrtc.Init.SynchPrediv: %u\r\n",hrtc.Init.SynchPrediv);
ulStartTime = HAL_GetTick();
uint32_t temp = hrtc.Instance->SSR;
HAL_Delay(2);
while(temp!=hrtc.Instance->SSR && HAL_GetTick()-ulStartTime< 3000);
ulEndTime = HAL_GetTick();
if( ulEndTime >= ulStartTime + 3000)
{
DEBUG0("RTC校准失败2\r\n");
return ;
}
DEBUG0("%u\r\n",ulEndTime - ulStartTime);
uint32_t ulCalibrateTime = (hrtc.Init.SynchPrediv) * 1000/(ulEndTime-ulStartTime);
DEBUG0("ulCalibrateTime:%u\r\n",ulCalibrateTime);
if( ulCalibrateTime > INT_LEAST16_MAX )
{
DEBUG0("RTC校准失败3\r\n");
return ;
}
hrtc.Init.AsynchPrediv = 36;
hrtc.Init.SynchPrediv = ulCalibrateTime;
if (HAL_RTC_Init(&hrtc) != HAL_OK)
{
DEBUG0("RTC校准失败4\r\n");
}
/* 等待RTC时钟运行稳定 */
HAL_Delay(500);
DEBUG0("实测RTC频率:%uHz\r\n",(hrtc.Init.AsynchPrediv+1)*(hrtc.Init.SynchPrediv+1));
HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR1,ulCalibrateTime);
}
其中:
ulStartTime = HAL_GetTick();
uint32_t temp = hrtc.Instance->SSR;
HAL_Delay(2);
while(temp!=hrtc.Instance->SSR && HAL_GetTick()-ulStartTime< 3000);
相当于一次秒中断
此代码可以解决不同STM32内部RC时钟的误差,不管是什么频率,都可以得到一个比较准确的秒中断,实测误差不超过5ms,每隔一段时间,校准一次RTC时钟,还可以解决RC时钟温漂的问题。
此代码是基于STM32的滴答时钟做的校准,若滴答时钟不准,那就没办法了
未经允许,不得转载