Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
实现RTC驱动,将NTP服务器中获取的网络时间更新至RTC
发布于 2020-03-31 10:55:05 浏览:2567
订阅该版
**作业题目6:实现RTC驱动,将NTP服务器中获取的网络时间更新至RTC** 大家提交作业时,直接在本贴下方跟贴即可
查看更多
19
个回答
默认排序
按发布时间排序
风雨潇潇
2020-04-05
这家伙很懒,什么也没写!
在使用ESP8266成功联网后,先测试连接NTP服务器,获取时间。之前ESP8266成功的话,这个没什么问题的,使用固定的地址和端口号连接 ``` int GetNtp(void) { uint8_t PosInNtpPacket; uint8_t buf[48];//存储NTP服务器返回的数据 uint32_t local_timestamp; ntp_packet packet ; struct tm * Net_time; uint8_t NTP_Data[48]; //48字节的报文 RTC_DateTypeDef datestructure; RTC_TimeTypeDef timestructure; /*******************************/ //NTP查询报文赋初值 //NTP_Data[0]=0xa3; //10100011, 0xa3,100 版本4 //00011011, 0x1b,011 版本3 //00010011, 0x13,010 版本2 //00001011, 0x0b,001 版本1 //for(PosInNtpPacket=1;PosInNtpPacket<48;PosInNtpPacket++) NTP_Data[PosInNtpPacket]=0;//剩余的47字节为0 rt_memset(NTP_Data,0,48); NTP_Data[0]=0xa3; /*******************************/ ESP8266_Link_Server(enumUDP, (char*)TIME_SERVERIP, (char*)TIME_PORTNUM,Single_ID_0);//UDP连接 rt_thread_mdelay(300); ESP8266_UnvarnishSend ();//传输模式为:透传 // strEsp8266_Fram_Record .InfBit .FramLength = 0; //重新开始接收新的数据包 for(PosInNtpPacket=0;PosInNtpPacket<48;PosInNtpPacket++) //发送NTP查询包 HAL_UART_Transmit( &huart3,&NTP_Data[PosInNtpPacket], 1,0xFFFF ); // rt_thread_mdelay(20); strEsp8266_Fram_Record .InfBit .FramLength = 0; //重新开始接收新的数据包 rt_thread_mdelay(1000); ESP8266_ExitUnvarnishSend ( );//退出透传HZJ ESP8266_Close_Link ( );//关闭TCP或UDP连接HZJ rt_memcpy(buf,strEsp8266_Fram_Record.Data_RX_BUF,48); /*******************************/ //接收包原始数据打印 printf("/*******************************/\r\n"); printf("Receive NTP Packet (Hex):"); for(PosInNtpPacket=0;PosInNtpPacket<48;PosInNtpPacket++) if(PosInNtpPacket%16==0) { printf("\r\n"); printf("%02X ",buf[PosInNtpPacket]); } else printf("%02X ",buf[PosInNtpPacket]); printf("\r\n/*******************************/\r\n"); /*******************************/ packet.txTm_s = buf[40]<<24 | buf[40+1]<<16|buf[40+2]<<8 |buf[40+3];//由于本演示时间精度要求不高,故直接用服务器返回的时间作为对时的时间,并未用公式:时间差offset=((T2-T1)+(T3-T4))/2。而是用T3作为对时基准时间。 local_timestamp = packet.txTm_s - NTP_TIMESTAMP_DELTA;//减去1970和1900的差值 local_timestamp +=SEC_TIME_ZONE; //加上北京的时间差,GMT+8 Net_time = localtime(&local_timestamp); //秒数转换位标准时间 printf("NTP Time:%04d-%02d-%02d %02d:%02d:%02d\r\n",(Net_time->tm_year)+1900, (Net_time->tm_mon)+1, Net_time->tm_mday, Net_time->tm_hour,Net_time->tm_min,Net_time->tm_sec); //打印出时间 timestructure.Hours = Net_time->tm_hour; timestructure.Minutes = Net_time->tm_min; timestructure.Seconds = Net_time->tm_sec; datestructure.Year = Net_time->tm_year; datestructure.Month = Net_time->tm_mon + 1; datestructure.Date = Net_time->tm_mday; HAL_RTC_SetTime(&hrtc, ×tructure, RTC_FORMAT_BIN); HAL_RTC_SetDate(&hrtc, &datestructure, RTC_FORMAT_BIN); return 0; } MSH_CMD_EXPORT(GetNtp, Get BeiJing Time.); ``` 能够获取时间信息后,添加RTC驱动,在STM32CUBEMX中打开默认配置就好。注意的就是,把重新生成的系统时钟初始化函数重新拷贝到board中,时钟配置会有变化。 我实在main函数中周期打印RTC的时钟信息 ``` int main(void) { RTC_DateTypeDef sdatestructure; RTC_TimeTypeDef stimestructure; while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ HAL_RTC_GetTime(&hrtc, &stimestructure, RTC_FORMAT_BIN); HAL_RTC_GetDate(&hrtc, &sdatestructure, RTC_FORMAT_BIN); /* Display date Format : yy/mm/dd */ printf("%02d/%02d/%02d\r\n",1900 + sdatestructure.Year, sdatestructure.Month, sdatestructure.Date); /* Display time Format : hh:mm:ss */ printf("%02d:%02d:%02d\r\n",stimestructure.Hours, stimestructure.Minutes, stimestructure.Seconds); printf("\r\n"); rt_thread_mdelay(10000); } } ``` [attach]14629[/attach] 经过对比时间,稍微修改下赋值就好了 [attach]14631[/attach]
风雨潇潇
2020-04-05
这家伙很懒,什么也没写!
上面我忽略在main里面打印的年份不对,后面再试了几次也是NTP获取的值正确,但是从RTC读出来的值不对,后面找到网友说把weekday也填进去可以,确实成功了,没有做计算,weekday就写1了[attach]14643[/attach]
yichao
2020-04-06
这家伙很懒,什么也没写!
[md]1. rtc驱动实现 > 移植rthread完整版驱动到nano版 > 利用rthread设备管理驱动和框架api管理rtc驱动 > rt_device_register(&rtc, "rtc", RT_DEVICE_FLAG_RDWR); 注册 > 通过驱动调用api rt_device_find 、rt_device_init、rt_device_open、set_date、set_time来实现rtc时钟的更新。 2. ntp获取网络时间 > 主要是ntp协议的应用,通过udp协议请求ntp服务器,由于本演示时间精度要求不高,故直接用服务器返回的时间作为对时的时间,并未用公式:时间差offset=((T2-T1)+(T3-T4))/2。而是用T3作为对时基准时间。 3. 利用驱动更新本地rtc时间 ``` #define NTP_TIMESTAMP_DELTA 2208988800ull //number of seconds between 1900 and 1970,1900-1970的时间差 #define SEC_TIME_ZONE + (8*60*60) //Beijing,GMT+8, 时区差 /* 时间服务器--用于同步网络时间 */ #define TIME_SERVERIP "cn.ntp.org.cn"//NTP服务器 #define TIME_PORTNUM "123"//NTP服务器端口号,固定为123 static rt_device_t rtc_dev; /* RTC设备句柄 */ int GetNtp(void) { uint8_t PosInNtpPacket; uint8_t buf[48];//存储NTP服务器返回的数据 uint32_t local_timestamp; ntp_packet packet ; struct tm * Net_time; uint8_t NTP_Data[48]; //48字节的报文 /*******************************/ //NTP查询报文赋初值 NTP_Data[0]=0xa3; //10100011, 0xa3,100 版本4 //00011011, 0x1b,011 版本3 //00010011, 0x13,010 版本2 //00001011, 0x0b,001 版本1 for(PosInNtpPacket=1;PosInNtpPacket<48;PosInNtpPacket++) NTP_Data[PosInNtpPacket]=0;//剩余的47字节为0 /*******************************/ ESP8266_Link_Server(enumUDP, (char*)TIME_SERVERIP, (char*)TIME_PORTNUM,Single_ID_0);//UDP连接 rt_thread_mdelay(300); ESP8266_UnvarnishSend ();//传输模式为:透传 // strEsp8266_Fram_Record .InfBit .FramLength = 0; //重新开始接收新的数据包 for(PosInNtpPacket=0;PosInNtpPacket<48;PosInNtpPacket++) //发送NTP查询包 UsartSendByte(macESP8266_USARTx,NTP_Data[PosInNtpPacket]); // rt_thread_mdelay(20); strEsp8266_Fram_Record .InfBit .FramLength = 0; //重新开始接收新的数据包 rt_thread_mdelay(1000); ESP8266_ExitUnvarnishSend ( );//退出透传HZJ ESP8266_Close_Link ( );//关闭TCP或UDP连接HZJ rt_memcpy(buf,strEsp8266_Fram_Record.Data_RX_BUF,48); /*******************************/ //接收包原始数据打印 printf("/*******************************/\r\n"); printf("Receive NTP Packet (Hex):"); for(PosInNtpPacket=0;PosInNtpPacket<48;PosInNtpPacket++) if(PosInNtpPacket%16==0) { printf("\r\n"); printf("%02X ",buf[PosInNtpPacket]); } else printf("%02X ",buf[PosInNtpPacket]); printf("\r\n/*******************************/\r\n"); /*******************************/ packet.txTm_s = buf[40]<<24 | buf[40+1]<<16|buf[40+2]<<8 |buf[40+3];//由于本演示时间精度要求不高,故直接用服务器返回的时间作为对时的时间,并未用公式:时间差offset=((T2-T1)+(T3-T4))/2。而是用T3作为对时基准时间。 local_timestamp = packet.txTm_s - NTP_TIMESTAMP_DELTA;//减去1970和1900的差值 local_timestamp +=SEC_TIME_ZONE; //加上北京的时间差,GMT+8 Net_time = localtime(&local_timestamp); //秒数转换位标准时间 printf("NTP Time:%04d-%02d-%02d %02d:%02d:%02d\r\n",(Net_time->tm_year)+1900, (Net_time->tm_mon)+1, Net_time->tm_mday, Net_time->tm_hour,Net_time->tm_min,Net_time->tm_sec); //打印出时间 //更新本地时钟 rt_err_t ret = RT_EOK; time_t now; rtc_dev = rt_device_find("rtc"); if (!rtc_dev) { rt_kprintf("find rtc failed!\n"); return RT_ERROR; } /* 初始化设备 */ ret = rt_device_init(rtc_dev); if (ret != RT_EOK) { rt_kprintf("initialize rtc failed!\n"); return RT_ERROR; } ret = rt_device_open(rtc_dev,RT_DEVICE_OFLAG_OPEN ); if (ret != RT_EOK) { rt_kprintf("Open rtc failed!\n"); return RT_ERROR; } /* 设置日期 */ ret = set_date((Net_time->tm_year)+1900, (Net_time->tm_mon)+1, Net_time->tm_mday); if (ret != RT_EOK) { rt_kprintf("set RTC date failed\n"); return ret; } /* 设置时间 */ ret = set_time(Net_time->tm_hour, Net_time->tm_min, Net_time->tm_sec); if (ret != RT_EOK) { rt_kprintf("set RTC time failed\n"); return ret; } /* 延时3秒 */ rt_thread_mdelay(3000); /* 获取时间 */ now = time(RT_NULL); rt_kprintf("%s\n", ctime(&now)); return 0; } MSH_CMD_EXPORT(GetNtp, Get BeiJing Time.); ```[/md]
赵撵猪
2020-04-06
这家伙很懒,什么也没写!
总结,使用例子移植非常的简单。对于这些教程都非常有意思的地方是,大小端的问题(本来一句话就能说明白),解析例子都跳过,这可能就是唯一难的地方了吧,正如,ds18b20的数据传输疑问一样。 实现步骤 [list] [*]实现udp发送驱动 [/list]esp驱动是我自己写的,只需要将tcp改为udp,在调用函数时,只需要将网址和端口填入。 [list] [*]ntp协议实现 [/list]ntp采用现成的解析方式,其实就是一个结构体,表现出来,stm32发送0xA3 和47个字节的0x00,然后接收到48个字节的数据。数据按照协议,其实网上大部分例子可以直接使用,解析出日期等数据写入rtc。[attach]14737[/attach] ``` #include
#include "NtpExample.h" #include "time.h" #include "rtc.h" #include "usart.h" #define NTP_TIMESTAMP_DELTA 2208988800ull //number of seconds between 1900 and 1970,1900-1970的时间差 #define SEC_TIME_ZONE + (8*60*60) //Beijing,GMT+8, 时区差 /* 时间服务器--用于同步网络时间 */ #define TIME_SERVERIP "cn.ntp.org.cn"//NTP服务器 #define TIME_PORTNUM "123"//NTP服务器端口号,固定为123 int GetNtp(void) { uint8_t PosInNtpPacket; uint8_t buf[48];//存储NTP服务器返回的数据 uint32_t local_timestamp; ntp_packet packet_rev,packet_send = {0}; struct tm * Net_time; RTC_DateTypeDef sDate = {0}; RTC_TimeTypeDef sTime = {0}; /*******************************/ //NTP查询报文赋初值 packet_send.li_vn_mode = (0x03<<6)|(0x04<<3)|(0x03);//li = 0 vn = 4 版本号 mode = 3 客户端 //10100011, 0xa3,100 版本4 //00011011, 0x1b,011 版本3 //00010011, 0x13,010 版本2 //00001011, 0x0b,001 版本1 /*******************************/ extern int esp8266_connect(const char *ip, const char *port); extern int at_uart_read(uint8_t* buf,uint16_t size_max,uint32_t timeout); extern int esp8266_disconnect(void); esp8266_connect((char*)TIME_SERVERIP,(char*)TIME_PORTNUM); rt_thread_mdelay(1000); HAL_UART_Transmit(&huart2,(uint8_t*)&packet_send,sizeof(packet_send),3000);//发送NTP查询包 at_uart_read(buf,sizeof(buf),2000); esp8266_disconnect(); /*******************************/ //接收包原始数据打印 rt_kprintf("/*******************************/\r\n"); rt_kprintf("Receive NTP Packet (Hex):"); for(PosInNtpPacket = 0;PosInNtpPacket < 48;PosInNtpPacket++) if(PosInNtpPacket%16==0) { rt_kprintf("\r\n"); rt_kprintf("%02X ",buf[PosInNtpPacket]); } else rt_kprintf("%02X ",buf[PosInNtpPacket]); rt_kprintf("\r\n/*******************************/\r\n"); /*******************************/ packet_rev.txTm_s = buf[40]<<24 | buf[40+1]<<16|buf[40+2]<<8 |buf[40+3];//由于本演示时间精度要求不高,故直接用服务器返回的时间作为对时的时间,并未用公式:时间差offset=((T2-T1)+(T3-T4))/2。而是用T3作为对时基准时间。 local_timestamp = packet_rev.txTm_s - NTP_TIMESTAMP_DELTA;//减去1970和1900的差值 local_timestamp +=SEC_TIME_ZONE; //加上北京的时间差,GMT+8 Net_time = localtime(&local_timestamp); //秒数转换位标准时间 rt_kprintf("NTP Time:%04d-%02d-%02d %02d:%02d:%02d\r\n",(Net_time->tm_year)+1900, (Net_time->tm_mon)+1, Net_time->tm_mday, Net_time->tm_hour,Net_time->tm_min,Net_time->tm_sec); //打印出时间 sDate.WeekDay = Net_time->tm_wday; sDate.Year = (Net_time->tm_year)+1900 - 2000; sDate.Month = (Net_time->tm_mon)+1; sDate.Date = Net_time->tm_mday; sTime.Hours = Net_time->tm_hour; sTime.Minutes = Net_time->tm_min; sTime.Seconds = Net_time->tm_sec; HAL_RTC_SetTime(&hrtc,&sTime,RTC_FORMAT_BIN); HAL_RTC_SetDate(&hrtc,&sDate,RTC_FORMAT_BIN); for(int i = 0;i < 5;i++) { rt_thread_mdelay(1000); HAL_RTC_GetTime(&hrtc,&sTime,RTC_FORMAT_BIN); HAL_RTC_GetDate(&hrtc,&sDate,RTC_FORMAT_BIN); rt_kprintf("RTC Time:20%02d-%02d-%02d %02d:%02d:%02d\r\n",sDate.Year, sDate.Month, sDate.Date, sTime.Hours ,sTime.Minutes,sTime.Seconds); //打印出时间 } return 0; } MSH_CMD_EXPORT(GetNtp, Get BeiJing Time.); ``` [attach]14738[/attach][attach]14739[/attach]
瑞尧
2020-04-07
这家伙很懒,什么也没写!
需求:使用RTC,并用NTP服务器更新时间至RTC中需要用到的部分:RTC驱动(设备驱动框架),网络通信(网络数据包分析) RTC驱动:跟着视频教程,将设备框架需要用到的device.c文件从完整版中复制到内核代码文件中,以及RTC的驱动框架和底层驱动,(以及需要用到的libc库),这一步比较简单,但是也容易出错,需要在复制好后,在keil中包含所需要的头文件[attach]14750[/attach] NTP服务器通信:在上一节作业的基础上,使用ESP8266链接NTP服务器,接收服务器发送的网络时间数据包,经过解析后更新至RTC中,代码如下: ``` /* 时间服务器--用于同步网络时间 */ #define TIME_SERVERIP "cn.ntp.org.cn"//NTP服务器 #define TIME_PORTNUM "123"//NTP服务器端口号,固定为123 #define socket_num 0 int ntp_sync(void) { uint8_t PosInNtpPacket; rt_device_t device; uint8_t buf[48];//存储NTP服务器返回的数据 uint32_t local_timestamp; ntp_packet packet ; struct tm * Net_time; uint8_t NTP_Data[48]; //48字节的报文 /*******************************/ //NTP查询报文赋初值 NTP_Data[0]=0xa3; //10100011, 0xa3,100 版本4 //00011011, 0x1b,011 版本3 //00010011, 0x13,010 版本2 //00001011, 0x0b,001 版本1 for(PosInNtpPacket=1;PosInNtpPacket<48;PosInNtpPacket++) NTP_Data[PosInNtpPacket]=0;//剩余的47字节为0 /*******************************/ esp_start_socket("UDP",socket_num,TIME_SERVERIP,TIME_PORTNUM); rt_thread_mdelay(300); esp_send(socket_num,NTP_Data); UART4_RX_STA = 0; rt_thread_mdelay(1000); esp_close_socket(socket_num); rt_memcpy(buf,UART4_RX_BUF,48); packet.txTm_s = buf[40]<<24 | buf[40+1]<<16|buf[40+2]<<8 |buf[40+3];//由于本演示时间精度要求不高,故直接用服务器返回的时间作为对时的时间,并未用公式:时间差offset=((T2-T1)+(T3-T4))/2。而是用T3作为对时基准时间。 local_timestamp = packet.txTm_s - NTP_TIMESTAMP_DELTA;//减去1970和1900的差值 local_timestamp +=SEC_TIME_ZONE; //加上北京的时间差,GMT+8 Net_time = localtime(&local_timestamp); //秒数转换位标准时间 device = rt_device_find("rtc"); if(RT_NULL != device) { /* update to RTC device. */ ret = rt_device_control(device, RT_DEVICE_CTRL_RTC_SET_TIME, &now); rt_kprintf("get localtime by NTP server!\n"); } } ``` 使用以上代码即可完成NTP时间更新至RTC中,效果如下: [attach]14751[/attach]
yoowiwi
2020-04-07
这家伙很懒,什么也没写!
[md]## 小作业:实现RTC驱动,将NTP服务器中获取的网络时间更新至RTC * RTC实时时钟笔记 * 32位计数器,只能向上计数,一般使用低速外部时钟LSE,频率为32.768khz * RTC 区域的时钟比APB 时钟慢, 访问前需要进行时钟同步: `RTC_WaitForSynchro` * 若修改了RTC的寄存器,则需要调用`RTC_WaitForLastTask`确保数据写入 * 默认情况下,RTC 所属的备份域禁止访问,需调用库函数`PWR_BackupAccessCmd`使能访问 * 设置RTC时钟分频:`RTC_SetPrescaler` * 计数器:`RTC_SetCounter`、`RTC_GetCounter` * 闹钟寄存器:`RTC_SetAlarm` * RTC初始化代码示例: ```C // LSE有时候会不可靠,可更换为LSI内部时钟 void RTC_Configuration(void) { /* 使能 PWR 和 Backup 时钟 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); /* 允许访问 Backup 区域 */ PWR_BackupAccessCmd(ENABLE); /* 复位 Backup 区域 */ BKP_DeInit(); RCC_LSEConfig(RCC_LSE_ON); // 使用外部时钟 while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); RCC_RTCCLKCmd(ENABLE); // 使能 RTC 时钟 RTC_WaitForSynchro(); // 等待RTC寄存器同步 RTC_WaitForLastTask(); // 等待操作完成 //RTC_ITConfig(RTC_IT_SEC, ENABLE); // 使能秒中断 RTC_WaitForLastTask(); // 等待操作完成 /* 设置 RTC 分频: 使 RTC 周期为1s */ /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) = 1HZ */ RTC_SetPrescaler(32767); } ``` * C语言中时间格式的转换 ```C #include "time.h" typedef unsigned int time_t; struct tm { int tm_sec; int tm_min; /* minutes after the hour, 0 to 59 */ int tm_hour; /* hours since midnight, 0 to 23 */ int tm_mday; /* day of the month, 1 to 31 */ int tm_mon; /* months since January, 0 to 11 */ int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday, 0 to 6 */ int tm_yday; /* days since January 1, 0 to 365 */ int tm_isdst; /* Daylight Savings Time flag */ }; time_t mktime(struct tm *timeptr); // 年月日转换为时间戳 struct tm * localtime(const time_t * timer); // 时间戳转换为年月日 char *ctime(const time_t *timer); // 将时间戳转换为字符串形式 char *asctime(const struct tm *timeptr) // 将tm结构体转换为字符串形式 ``` * 完整代码示例 * ESP8266串口初始化,串口的初始化比较简单,这里就不贴出来了。 * 在与NTP服务通讯前需要先将ESP8266设置为STA模式并连接热点,相关命令在上次作业展开,这里不贴出;以下函数为ESP8266与NTP服务通讯,并将数据取回进行处理, ```C // 硬件RTC初始化 void RTC_Configuration(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | \ RCC_APB1Periph_BKP, ENABLE); PWR_BackupAccessCmd(ENABLE); BKP_DeInit(); RCC_LSEConfig(RCC_LSE_ON); while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET); RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); RCC_RTCCLKCmd(ENABLE); RTC_WaitForSynchro(); RTC_WaitForLastTask(); /* 设置 RTC 分频: 使 RTC 周期为1s */ /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) = 1HZ */ RTC_SetPrescaler(32767); } uint8_t NTP_Flag = 0; uint8_t NTP_Reci[48]; void get_ntp(void) { time_t NTP_Time; time_t Local_Time; struct tm * time_tf; uint8_t NTP_Data[48]; //发送48字节的报文 for(uint8_t i=0;i<48;i++) NTP_Data[i]=0;//先全部设置为0 NTP_Data[0]=0xA3; // li 10 vn 100 mode 011 // 连接服务器,UDP服务器 esp8266_atcmd_send("AT+CIPSTART=\"UDP\",\"114.118.7.161\",123"); rt_thread_mdelay(1000); esp8266_atcmd_send("AT+CIPMODE=0"); rt_thread_mdelay(200); // 延时等待连接完成 esp8266_atcmd_send("AT+CIPSEND=48"); // 发送48个数据 rt_thread_mdelay(200); NTP_Flag = 1; for(uint8_t i=0;i<48;i++) // 发送报文 { Usart_SendByte(USART3,NTP_Data[i]); } while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); rt_thread_mdelay(1000); rt_memcpy(NTP_Reci,buff3,48); // 将获取到的数据拷贝到NTP_Reci数组 NTP_Flag = 0; esp8266_atcmd_send("AT+CIPCLOSE"); // 关闭服务器 rt_thread_mdelay(50); NTP_Time = NTP_Reci[40]<<24 | NTP_Reci[40+1]<<16|NTP_Reci[40+2]<<8 |NTP_Reci[40+3]; NTP_Time = NTP_Time - NTP_TIMESTAMP_DELTA; time_tf = localtime(&NTP_Time); printf("格林威治时间:%04d-%02d-%02d %02d:%02d:%02d\r\n", \ (time_tf->tm_year)+1900, \ (time_tf->tm_mon)+1, \ time_tf->tm_mday, \ time_tf->tm_hour, \ time_tf->tm_min, \ time_tf->tm_sec); Local_Time = NTP_Time + SEC_TIME_ZONE; time_tf = localtime(&Local_Time); printf("北京时间:%04d-%02d-%02d %02d:%02d:%02d\r\n", \ (time_tf->tm_year)+1900, \ (time_tf->tm_mon)+1, \ time_tf->tm_mday, \ time_tf->tm_hour, \ time_tf->tm_min, \ time_tf->tm_sec); RTC_SetCounter(Local_Time); //将获取到的时间戳更新到板上RTC } MSH_CMD_EXPORT(get_ntp,update time from ntp); ``` * ESP8266中断处理函数 ```C uint8_t len = 0; extern uint8_t NTP_Flag; extern uint8_t NTP_Reci[48]; void DEBUG_USART3_IRQHandler() { if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) { buff3[len++] = USART_ReceiveData(USART3); if(NTP_Flag == 1 && buff3[0] != 0x24) // NTP返回的第一个字符为0x24 { len = 0; // 如果第一个不为0x24则重新接收 } USART_ClearITPendingBit(USART3, USART_IT_RXNE); }else if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET){ USART3->SR;USART3->DR; len = 0; } } ```[/md][/i][/i] [i][i]效果展示:[/i][/i] [attach]14752[/attach]
奔跑的蜗牛大大
2020-04-08
这家伙很懒,什么也没写!
获取时间 更新RTC
summer_me
2020-04-08
这家伙很懒,什么也没写!
在MSH命令行输入:GetNtp(获取网络事件,更新至RTC) 如果想单片机上点就自动获取网络事件更新至RTC,就改下代码,把GetNtp自动初始化下。
。。。
2020-04-10
这家伙很懒,什么也没写!
观看何老师的RT-Thread Nano-NTP-获取网络时间和RT-Thread Nano-RTC-设备驱动框架入门的视频之后,完成本次作业。 按照何老师视频中的讲解移植相关的代码文档。然后在这基础上进行一些代码编写,进而实现作业的功能。 我在WifiCmdTest.c的文档中编写了一个直接连接热点的函数,代码如下: ``` #define WIFI_IP "MERCURY_CC72" //热点名称 #define WIFI_password "fxmfy210." //热点密码 int ESP8266_Network_Connection(void) { ESP8266_Cmd ( "AT", "OK", NULL, 500 );//AT命令 ESP8266_Rst(); ESP8266_Net_Mode_Choose ( STA );//设置为工作站模式 while(!ESP8266_JoinAP ( WIFI_IP, WIFI_password));//加入热点 printf("ESP8266 Connect hotspot successfully.\r\n"); return 0; } INIT_APP_EXPORT(ESP8266_Network_Connection); ``` 我在config.h中增加了一些代码如下: ``` #include "NtpExample.h" #include "RTCExample.h" ``` 我又把何老师在NtpExample.c文档中的一些宏定义移到该文档的头文件中,移动的代码如下: ``` #define NTP_TIMESTAMP_DELTA 2208988800ull //number of seconds between 1900 and 1970,1900-1970的时间差 #define SEC_TIME_ZONE + (8*60*60) //Beijing,GMT+8, 时区差 /* 时间服务器--用于同步网络时间 */ #define TIME_SERVERIP "cn.ntp.org.cn"//NTP服务器 #define TIME_PORTNUM "123"//NTP服务器端口号,固定为123 ``` 接下来,我在RTCExample.c的文档中增加了如下的代码,实现该作业的要求: ``` #include "config.h" int RTCUpdate(void) { uint8_t PosInNtpPacket; uint8_t buf[48];//存储NTP服务器返回的数据 uint32_t local_timestamp; ntp_packet packet ; struct tm * Net_time; uint8_t NTP_Data[48]; //48字节的报文 rt_err_t ret = RT_EOK; time_t now; int year,mon,mday,hour,min,sec; /*******************************/ //NTP查询报文赋初值 NTP_Data[0]=0xa3; //10100011, 0xa3,100 版本4 //00011011, 0x1b,011 版本3 //00010011, 0x13,010 版本2 //00001011, 0x0b,001 版本1 for(PosInNtpPacket=1;PosInNtpPacket<48;PosInNtpPacket++) NTP_Data[PosInNtpPacket]=0;//剩余的47字节为0 /*******************************/ ESP8266_Link_Server(enumUDP, (char*)TIME_SERVERIP, (char*)TIME_PORTNUM,Single_ID_0);//UDP连接 rt_thread_mdelay(300); ESP8266_UnvarnishSend ();//传输模式为:透传 // strEsp8266_Fram_Record .InfBit .FramLength = 0; //重新开始接收新的数据包 for(PosInNtpPacket=0;PosInNtpPacket<48;PosInNtpPacket++) //发送NTP查询包 UsartSendByte(macESP8266_USARTx,NTP_Data[PosInNtpPacket]); // rt_thread_mdelay(20); strEsp8266_Fram_Record .InfBit .FramLength = 0; //重新开始接收新的数据包 rt_thread_mdelay(1000); ESP8266_ExitUnvarnishSend ( );//退出透传HZJ ESP8266_Close_Link ( );//关闭TCP或UDP连接HZJ rt_memcpy(buf,strEsp8266_Fram_Record.Data_RX_BUF,48); /* output current time */ now = time(RT_NULL); Net_time = localtime(&now); //秒数转换位标准时间 year = (Net_time->tm_year)+1900; mon = (Net_time->tm_mon)+1; mday = Net_time->tm_mday; hour = Net_time->tm_hour; min = Net_time->tm_min; sec = Net_time->tm_sec; printf("Time before RTC update:\r\n\t\t%04d-%02d-%02d %02d:%02d:%02d\r\n", year, mon, mday, hour, min, sec); //打印出时间 packet.txTm_s = buf[40]<<24 | buf[40+1]<<16|buf[40+2]<<8 |buf[40+3];//由于本演示时间精度要求不高,故直接用服务器返回的时间作为对时的时间,并未用公式:时间差offset=((T2-T1)+(T3-T4))/2。而是用T3作为对时基准时间。 local_timestamp = packet.txTm_s - NTP_TIMESTAMP_DELTA;//减去1970和1900的差值 local_timestamp +=SEC_TIME_ZONE; //加上北京的时间差,GMT+8 Net_time = localtime(&local_timestamp); //秒数转换位标准时间 year = (Net_time->tm_year)+1900; mon = (Net_time->tm_mon)+1; mday = Net_time->tm_mday; hour = Net_time->tm_hour; min = Net_time->tm_min; sec = Net_time->tm_sec; printf("NTP server time:\r\n\t\t%04d-%02d-%02d %02d:%02d:%02d\r\n", year, mon, mday, hour, min, sec); //打印出时间 rtc_dev = rt_device_find("rtc"); if (!rtc_dev) { rt_kprintf("find rtc failed!\n"); return RT_ERROR; } /* 初始化设备 */ ret = rt_device_init(rtc_dev); if (ret != RT_EOK) { rt_kprintf("initialize rtc failed!\n"); return RT_ERROR; } ret = rt_device_open(rtc_dev,RT_DEVICE_OFLAG_OPEN ); if (ret != RT_EOK) { rt_kprintf("Open rtc failed!\n"); return RT_ERROR; } /* 设置时间 */ ret = set_time( hour, min, sec); if (ret != RT_EOK) { rt_kprintf("set RTC time failed\n"); return ret; } /* 设置日期 */ ret = set_date( year, mon, mday); if (ret != RT_EOK) { rt_kprintf("set RTC date failed\n"); return ret; } /* 获取时间 */ now = time(RT_NULL); Net_time = localtime(&now); //秒数转换位标准时间 year = (Net_time->tm_year)+1900; mon = (Net_time->tm_mon)+1; mday = Net_time->tm_mday; hour = Net_time->tm_hour; min = Net_time->tm_min; sec = Net_time->tm_sec; printf("Time after update:\r\n\t\t%04d-%02d-%02d %02d:%02d:%02d\r\n", year, mon, mday, hour, min, sec); //打印出时间 return 0; } MSH_CMD_EXPORT(RTCUpdate,RTC Update BeiJing Time.); ``` 硬件调试的结果如下: 查看编写的MAH命令是否成功: [attach]14845[/attach] 测试作业的功能: [attach]14846[/attach]
guangying
2020-04-10
这家伙很懒,什么也没写!
[md]# 实现RTC驱动,将NTP服务器中获取的网络时间更新至RTC **标准库函数(STD)版** ## 硬件平台介绍 正点原子 NanoSTM32F103RBT6 ,本程序中 Finsh 组件使用 USART1 ;USART2 连接 ESP8266 的串口。 ## 设计思路 要达到题目要求,要实现一下几个方面 1. ESP8266 的应用 2. NTP 的查询 3. RTC 的应用 ## 实现过程 - ESP8266 的 AT 指令函数 - ESP8266 获取 NTP 时间 - 对接收到的数据处理 - 更新 RTC 的时间 ### ESP8266 的 AT 指令函数 ESP8266的AT指令都封装为函数了,使用的时野火电子的ESP8266的代码。 这里就不贴代码了,可以在文后的附件下载 ### ESP8266 获取 NTP 时间 这里简单介绍一下获取 NTP 时间的过程,可在文后附件下载。 1. 准备 NTP 查询报文, uint8_t 类型的数组,个数为 48 个,并将第 0 个数组的内容设置为 0xA3 ,其他都为 0 。 2. ESP8266 使用 UDP 连接 NTP 服务器 ,端口为 123。并开启透传模式。 3. 清空接收数组前 48 个字节,通过 ESP8266 发送 NTP 查询报文。 4. 延时一段时间,取出接收数组中的 48 个字节。 ### 对接收到的数据处理 这里简单介绍一下对接收数据处理的过程,可在文后附件下载。 1. 先打印出接收的原始数据 2. 因为要求精度不高,所以直接使用服务器返回数据时的时间。提取接收数组中的[40]、[41]、[42]、[43] ,将这 4 个字节组合成 32 位的二进制数(第[40]个为高位), 3. 将这 32 Bit 转换为十进制,然后减去 2208988800 得到 Unix 时间戳,以秒为单位。 4. 将得到的 Unix 时间戳加上北京的时间差(+60*60*8),得到北京时间。 5. 通过函数 localtime() 将秒数转换为标准时间。格式是 年-月-日 时:分:秒 ### 更新 RTC 的时间 这里简单介绍一下更新 RTC 的时间的过程,可在文后附件下载。 - 系统启动时,进行 RTC 的初始化,使用外部低速时钟。 - 获取 NTP 时间时进行 RTC 时间的更新。 ## 下载验证 ### 上电前我摘掉了RTC的备用电池,可以看到时间不对。 ![GTStT1.png](https://s1.ax1x.com/2020/04/10/GTStT1.png) ### 通过命令获得 NTP 时间 ![GTSaY6.png](https://s1.ax1x.com/2020/04/10/GTSaY6.png) ### 通过命令再次查看 RTC 的时间,可以看到时间已经更新 ![GTSUFx.png](https://s1.ax1x.com/2020/04/10/GTSUFx.png) ## 遇到过的问题 - 串口每次发送一个字节都要查询是否发送完。如下 ``` c for(PosInNtpPacket=0;PosInNtpPacket<48;PosInNtpPacket++) //发送NTP查询包 { //发送数据 USART_SendData(macESP8266_USARTx,NTP_Data[PosInNtpPacket]); //一定要等待发送完成***************************************************** while(USART_GetFlagStatus(macESP8266_USARTx,USART_FLAG_TXE) == RESET); //********************************************************************* } ```[/md] [attach]14848[/attach]
撰写答案
登录
注册新账号
关注者
1
被浏览
2.6k
关于作者
RT-Thread小喇叭
这家伙很懒,什么也没写!
提问
29
回答
54
被采纳
1
关注TA
发私信
相关问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
开源共生 商业共赢 | RT-Thread 2024开发者大会议程正式发布!
2
【24嵌入式设计大赛】基于RT-Thread星火一号的智慧家居系统
3
RT-Thread EtherKit开源以太网硬件正式发布
4
如何在master上的BSP中添加配置yml文件
5
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
MicroPython
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
19
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
6
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
5
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部