本帖最后由 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;
- }
|