本帖最后由 djz1992 于 2021-1-20 09:40 编辑
STM32F030,采用HSI内部始终,RTC采用LSI,40KHZ
分频设置40000/100/400=1HZ。
主要是不准,一小时能快1分钟。
采用HSI的话,是不是没法校准?
@dirtwillfly @xyz549040622 @m564522634 @ufbycd
修改了一下,加入了一点通过网络校准同步分频值的功能。从网上到处找帖子,找到一篇不错的帖子,精密校准HAL_RTCEx_SetSmoothCalib。附上链接:https://blog.csdn.net/u012183892/article/details/103405972
然后打算是分四步校准。
第一步同步网络时间;
第二步:粗调同步分频值;
第三步:精密调整;
第四步:补齐误差;
最后试了一下,精密校准HAL_RTCEx_SetSmoothCalib函数一直不起作用,所以还是只用了前两步。
附代码,请各位大佬指点。
为避免代码运行的时间,导致本地时间与网络时间的差异放大,所有此处用网络时间差与本地时间差进行比较。
uint16_t SynchPrediv = 0;
uint32_t time_ntp1=0,time_ntp2=0,time_rtc1=0,time_rtc2=0;
float time_ntp_sub=0,time_rtc_sub=0,time_ntp_rtc_sub=0;
float time_cal_num=0;
float time_cal_cnt=0;
int time_get(device_status_t *dev_stat)
{
char *p1,*p2;
char buffer[64]={0};
char val_buffer[15]={0};
uint32_t time_ntp=0;
static uint8_t time_get_num=0;
wifi_printf("AT+GETSNTP\r\n");
rt_thread_mdelay(50);
if(ring_length() > 0)
{
ring_buf_read(&g_uart_rx_buf,sizeof(buffer),(uint8_t *)buffer);
}
if(strstr(buffer,"{\"time\":"))
{
p1 = strstr(buffer,"\":\"");
p2 = strstr(p1+3,"\"}");
strncpy(val_buffer,p1+3,(p2-(p1+3)-3));//舍去最后三位的毫秒
time_ntp = atoi(val_buffer);
covUnixTimeStp2Beijing(time_ntp,&tempBeijing1);//网络时间
switch(time_get_num)
{
case 0:
/***
STEP0:首次获取网络时间
记录初次ntp时间、初次本地时间,用于差值计算
****/
time_ntp1 = time_ntp;
time_rtc1 = time_ntp;
set_rtc_time(&tempBeijing1); //保存到RTC
time_get_num = 1;
break;
case 1:
/***
STEP1:初略校准
利用两次时间同步的ntp时间差、本地时间差,计算本地时间的初略误差,调整同步分频数
****/
time_ntp2 = time_ntp;
time_ntp_sub = time_ntp2 -time_ntp1;
time_ntp1 = time_ntp2;
get_rtc_time(&tempBeijing2);//本地时间
time_rtc2 = covBeijing2UnixTimeStp(&tempBeijing2);
time_rtc_sub = time_rtc2 - time_rtc1;
time_rtc1 = time_rtc2;
if(time_ntp_sub >0 && time_rtc_sub >0)
{
if(time_ntp_sub > time_rtc_sub) //慢了
{
time_ntp_rtc_sub = time_ntp_sub-time_rtc_sub;
if(time_ntp_rtc_sub > 1)
{
SynchPrediv = (1 - (time_ntp_rtc_sub / time_ntp_sub) * 0.9) * (SynchPrediv+1) - 1;
HAL_RTC_DeInit(&hrtc);
MX_RTC_Init();
set_rtc_time(&tempBeijing1); //保存到RTC
time_rtc1 = time_ntp2;
}
else
{
// time_get_num = 2;
}
}
else if(time_ntp_sub < time_rtc_sub)//快了
{
time_ntp_rtc_sub = time_rtc_sub - time_ntp_sub;
if(time_ntp_rtc_sub > 1)
{
SynchPrediv = (1 + (time_ntp_rtc_sub / time_ntp_sub) * 0.9) * (SynchPrediv+1) - 1;
HAL_RTC_DeInit(&hrtc);
MX_RTC_Init();
set_rtc_time(&tempBeijing1); //保存到RTC
time_rtc1 = time_ntp2;
}
else
{
// time_get_num = 2;
}
}
else
{
}
}
break;
case 2:
/***
STEP2:精密数字校准计算方法:
24*3600/32s=2700;以32s修正间隔,每24小时有2700个周期
1s/2700 = 3.7*10-4;以24小时差1s为修正目标,计算每个周期需要减少的秒数
3.7*10-4/(1/32767) ≈ 12;以32767为同步分频数为例,计算每个周期减少的秒速等于多少个rtc周期
****/
time_ntp2 = time_ntp;
time_ntp_sub = time_ntp2 -time_ntp1;
time_ntp1 = time_ntp2;
get_rtc_time(&tempBeijing2);//本地时间
time_rtc2 = covBeijing2UnixTimeStp(&tempBeijing2);
time_rtc_sub = time_rtc2 - time_rtc1;
time_rtc1 = time_rtc2;
if(time_ntp_sub >0 && time_rtc_sub >0)
{
if(time_ntp_sub > time_rtc_sub)
{
time_ntp_rtc_sub = time_ntp_sub-time_rtc_sub;
time_cal_num = ((float)(time_ntp_rtc_sub * (60*24/2))) / 2700;
time_cal_cnt = time_cal_num/(1/(float)40000);
HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, RTC_SMOOTHCALIB_PLUSPULSES_SET, (uint32_t)time_cal_cnt);
set_rtc_time(&tempBeijing1); //保存到RTC
time_rtc1 = time_ntp2;
}
else if(time_ntp_sub < time_rtc_sub)
{
time_ntp_rtc_sub = time_rtc_sub - time_ntp_sub;
time_cal_num = ((float)(time_ntp_rtc_sub * (60*24/2))) / 2700;
time_cal_cnt = time_cal_num/(1/(float)40000);
HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, RTC_SMOOTHCALIB_PLUSPULSES_RESET, (uint32_t)time_cal_cnt);
set_rtc_time(&tempBeijing1); //保存到RTC
time_rtc1 = time_ntp2;
}
else
{
}
}
break;
case 3:
/***
STEP3:时刻同步计算方法
本地毫秒比远程快了590-200=390ms,390ms/(1s/256) ≈ 100
****/
HAL_RTCEx_SetSynchroShift(&hrtc, RTC_SHIFTADD1S_RESET, 100);
break;
default:
break;
}
return SUCCESS;
}
return ERROR;
}
|