主题:STM32通过GSM模块获取网络时间并设置到单片机内部RTC中实现上电自动校准时间(3种方法:服务器、GPRS基站定位、NTP)
先简单说一下实验目的吧。平时做项目或做一些小作品的时候需要用到时间,时间用的是STM32内部的RTC,在精度要求不是特别高时这样省去接外设时钟模块,省时省力。但我们都知道,RTC在断电后数据是不保存的,也就是说如果没有电源如电池之类一直给后备寄存器供电的话数据是会丢失的,下次开机时时间就会恢复初始化时设置的那个时间,想要时间正确就要重新设置时间,这就很不实用。所以就想通过网络获取时间的方式来自动校正时间。又恰好用到SIM900A这个模块,所以查了下资料,发现已经有前辈做过了。看了https://blog.csdn.net/ludaoyi88/article/details/51757664这位博主的文章,获取时间部分用了这位前辈提供的代码,在他提供的代码上进行测试和改进(直接用不修改的话是不行的。如果大家仔细对比的话会发现其实我改进后的代码跟原版的还是有蛮多小细节不同的),最终得以达到目的,即可以通过服务器获取到网络的时间并自动校正到STM32内部RTC中,这里再次感谢 ludaoyi123这位前辈。大家可以先去看看这位前辈的博客,也就是上面那个链接,获取时间和处理时间数据都是源于他的那篇文章。好了,接下来就说一下怎么获取时间的吧。
此次试验用的单片机是STM32F103C8T6核心板,串口2控制SIM900A模块数据的收发,串口1用于在串口调试助手打印相关信息。下图是我的硬件平台:STM32F103C8T6核心板和SIM900A模块。
获取网络时间的第一种方法是连接到国外的授时服务器,IP为:time.nist.gov,端口为:13,我用的连接方式是TCP连接。当客户端连接到此服务器后,服务器会立刻发送一串格式为“58646 19-06-12 16:05:36 50 0 0 668.3 UTC(NIST) * ”这样的字符串返回给客户端并主动断开连接。这一串字符串中就包含有日期和时间,我们所要做的,就是把相关的日期和时间提取出来转换成数字就好了,这也是最最重要的部分。这里贴出我修改后的代码:`
_nowtime_obj NowTime; //现在时间日期结构体
///*******************************************************************************
//* 函数名 : Get_Sever_Time
//* 描述 : 获取Time信息(连接服务器成功情况下)
//* 输入 :
//* 输出 :
//* 返回 :
//* 注意 :服务器返回的数据形式如下:58646 19-06-12 16:05:36 50 0 0 668.3 UTC(NIST) *
//*******************************************************************************/
void Get_Sever_Time(void)
{
u8 i =0;
char timestr1[200]={0};
char *timestr = timestr1;//指向timestr1地址
printf("\r\n获取时间日期中...\r\n");
while(1)
{
if(strstr((const char*)USART2_RX_BUF , "-") != NULL || strstr((const char*)USART2_RX_BUF , "5") != NULL )
{
timestr = strstr((const char*)USART2_RX_BUF,"5");//58646//USART2_RX_BUF 为接收缓存数组
break;
}
}
printf("\r\n时间数组timestr的数据为");
printf((char *)timestr);
printf("\r\n");
delay_ms(5);
//提取UTC世界时间
for(i = 0 ; i <50 ; i++)
{
if(timestr[i] == '-')
{
NowTime.year = (timestr[i-2]-'0')*10 + (timestr[i-1]-'0') + 2000;
NowTime.moon = (timestr[i+1]-'0')*10 + (timestr[i+2]-'0');
NowTime.day = (timestr[i+4]-'0')*10 + (timestr[i+5]-'0');
NowTime.hour = (timestr[i+7]-'0')*10 + (timestr[i+8]-'0');//时差相差8
if(NowTime.hour >= 16)//北京时间新的一天
{
NowTime.hour = (timestr[i+7]-'0')*10 + (timestr[i+8]-'0') + 8 - 24;
NowTime.day = NowTime.day + 1;
if(NowTime.hour == 24)
NowTime.hour = 0;
}
else
NowTime.hour = (timestr[i+7]-'0')*10 + (timestr[i+8]-'0') + 8 ;//时差相差8
NowTime.minu = (timestr[i+10]-'0')*10 + (timestr[i+11]-'0');
NowTime.sec = (timestr[i+13]-'0')*10 + (timestr[i+14]-'0') + 2;//2是返回数据到处理处结果的误差