NTP是网络时间协议(Network Time Protocol),它是用来同步网络中各个计算机的时间的协议。在上一节wifi联网成功,这一节使能ntp来更新rtc时间。 1、由于在雅特力AT_START_F403A_V1开发板上默认rtthread模板工程中没有移植rtc驱动。故这里首先进行rtc移植。 在工程中新建一个drv_rtc.c文件,在文件里完成rtc设备的初始化、注册。参考其他板子的rtc设备移植,确定了rtc设备注册主要提供一个rt_rtc_control函数来设置时间戳和读取时间戳。 作为rtc设备只需要提供device->control = rt_rtc_control;可以获取时间戳和设置时间戳。 #include <rtthread.h> #include "board.h" #include "time.h" #include "drv_rtc.h"
//#ifdef BSP_USING_ONCHIP_RTC //#define DRV_DEBUG #define LOG_TAG "drv.rtc" #include <drv_log.h>
#define BKUP_REG_DATA 0xA5A5
static struct rt_device rtc;
const uint8_t table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //Monthly correction data sheet. const uint8_t mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31}; //Month data table of Pingnian _calendar_obj calendar;
/** * @brief Get current week by Input Leap year\mouth\day. * @param syear : Year * smon : Month * sday : Day * @retval week number. */ uint8_t RTC_Get_Week(uint16_t year, uint8_t month, uint8_t day) { uint16_t temp2; uint8_t yearH,yearL; yearH=year/100; yearL=year%100; if (yearH>19)yearL+=100; temp2=yearL+yearL/4; temp2=temp2%7; temp2=temp2+day+table_week[month-1]; if (yearL%4==0&&month<3) temp2--; return(temp2%7); } /** * @brief Get current time. * @param None. * @retval None. */ void RTC_Get(void) { static uint16_t daycnt=0; uint32_t timecount=0; uint32_t temp=0; uint32_t temp1=0; timecount=RTC_GetCounter(); temp=timecount/86400; if(daycnt!=temp) { daycnt=temp; temp1=1970; while(temp>=365) { if(Is_Leap_Year(temp1)) { if(temp>=366)temp-=366; else {temp1++;break;} } else temp-=365; temp1++; } calendar.w_year=temp1; temp1=0; while(temp>=28) { if(Is_Leap_Year(calendar.w_year)&&temp1==1) { if(temp>=29)temp-=29; else break; } else { if(temp>=mon_table[temp1])temp-=mon_table[temp1]; else break; } temp1++; } calendar.w_month=temp1+1; calendar.w_date=temp+1; } temp=timecount%86400; calendar.hour=temp/3600; calendar.min=(temp%3600)/60; calendar.sec=(temp%3600)%60; calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date); }
static time_t get_rtc_timestamp(void) { struct tm tm_new; RTC_Get(); tm_new.tm_sec = calendar.sec; tm_new.tm_min = calendar.min; tm_new.tm_hour = calendar.hour; tm_new.tm_mday = calendar.w_date; tm_new.tm_mon = calendar.w_month-1; tm_new.tm_year = calendar.w_year-1900;
LOG_D("get rtc time."); return (mktime(&tm_new)); }
/** * @brief Judeg the Leap year or Pingnian. * Month 1 2 3 4 5 6 7 8 9 10 11 12 * Leap year 31 29 31 30 31 30 31 31 30 31 30 31 * Pingnian 31 28 31 30 31 30 31 31 30 31 30 31 * @param year * @retval 1: Leap year 2: Pingnian */ uint8_t Is_Leap_Year(uint16_t year) { if(year%4==0) { if(year%100==0) { if(year%400==0) return 1; else return 0; }else return 1; }else return 0; }
/** * @brief Set time. Convert the input clock to a second. * The time basic : 1970.1.1 * legitimate year: 1970 ~ 2099 * @param syear: Year * smon : Month * sday : Day * hour * min * sec * @retval 0: Set time right. * 1: Set time failed. */ uint8_t RTC_Set(uint16_t syear, uint8_t smon, uint8_t sday, uint8_t hour, uint8_t min, uint8_t sec) { uint32_t t; uint32_t seccount=0;
if(syear<1970||syear>2099) return 1;
for(t=1970;t<syear;t++) { if(Is_Leap_Year(t))seccount+=31622400; else seccount+=31536000; } smon-=1; for(t=0;t<smon;t++) { seccount+=(uint8_t)mon_table[t]*86400; if(Is_Leap_Year(syear)&&t==1)seccount+=86400; } seccount+=(uint8_t)(sday-1)*86400; seccount+=(uint8_t)hour*3600; seccount+=(uint8_t)min*60; seccount+=sec;
/* Enable PWR and BKP clock */ RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_PWR | RCC_APB1PERIPH_BKP, ENABLE);
/* Enable write access to Backup domain */ PWR_BackupAccessCtrl(ENABLE);
/* Set the RTC counter value */ RTC_SetCounter(seccount); /* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask();
return 0; }
static rt_err_t set_rtc_time_stamp(time_t time_stamp) { struct tm *p_tm;
p_tm = localtime(&time_stamp); if (p_tm->tm_year < 100) { return -RT_ERROR; } //p_tm->tm_wday + 1; RTC_Set(p_tm->tm_year+1900,p_tm->tm_mon+1,p_tm->tm_mday, p_tm->tm_hour, p_tm->tm_min, p_tm->tm_sec); LOG_D("set rtc time."); return RT_EOK; }
static void rt_rtc_init(void) {
}
static rt_err_t rt_rtc_config(struct rt_device *dev) { /* Enable PWR and BKP clocks */ RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_PWR | RCC_APB1PERIPH_BKP, ENABLE);
/* Allow access to BKP Domain */ PWR_BackupAccessCtrl(ENABLE);
/* Check Backup data registers is correct*/ if (BKP_ReadBackupReg(BKP_DT1) != 0x5051) { /* Reset Backup Domain */ BKP_Reset(); /* Enable the LSI OSC */ RCC_LSEConfig(RCC_LSE_ENABLE); /* Wait till LSI is ready */ while(RCC_GetFlagStatus(RCC_FLAG_LSESTBL) == RESET); /* Select the RTC Clock Source */ RCC_RTCCLKConfig(RCC_RTCCLKSelection_LSE); /* Enable RTC Clock */ RCC_RTCCLKCmd(ENABLE); /* Wait for RTC registers synchronization */ RTC_WaitForSynchro(); /* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask(); /* Set RTC prescaler: set RTC period to 1sec */ RTC_SetDIV(32767); /* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask(); /* Set the RTC time */ RTC_Set(2018, 8, 8, 8, 8, 0); /* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask(); /* Writes data to Backup Register */ BKP_WriteBackupReg(BKP_DT1, 0x5051); } else { /* Wait for RTC registers synchronization */ RTC_WaitForSynchro(); /* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask(); /* Clear RTC pending flag */ RTC_ClearFlag(RTC_FLAG_PACE); /* Wait until last write operation on RTC registers has finished */ RTC_WaitForLastTask(); } return RT_EOK; }
static rt_err_t rt_rtc_control(rt_device_t dev, int cmd, void *args) { rt_err_t result = RT_EOK; RT_ASSERT(dev != RT_NULL); switch (cmd) { case RT_DEVICE_CTRL_RTC_GET_TIME: *(rt_uint32_t *)args = get_rtc_timestamp(); LOG_D("RTC: get rtc_time %x\n", *(rt_uint32_t *)args); break;
case RT_DEVICE_CTRL_RTC_SET_TIME: if (set_rtc_time_stamp(*(rt_uint32_t *)args)) { result = -RT_ERROR; } LOG_D("RTC: set rtc_time %x\n", *(rt_uint32_t *)args); break; }
return result; }
#ifdef RT_USING_DEVICE_OPS const static struct rt_device_ops rtc_ops = { RT_NULL, RT_NULL, RT_NULL, RT_NULL, RT_NULL, rt_rtc_control }; #endif
static rt_err_t rt_hw_rtc_register(rt_device_t device, const char *name, rt_uint32_t flag) { RT_ASSERT(device != RT_NULL);
rt_rtc_init(); if (rt_rtc_config(device) != RT_EOK) { return -RT_ERROR; } #ifdef RT_USING_DEVICE_OPS device->ops = &rtc_ops; #else device->init = RT_NULL; device->open = RT_NULL; device->close = RT_NULL; device->read = RT_NULL; device->write = RT_NULL; device->control = rt_rtc_control; #endif device->type = RT_Device_Class_RTC; device->rx_indicate = RT_NULL; device->tx_complete = RT_NULL; device->user_data = RT_NULL;
/* register a character device */ return rt_device_register(device, name, flag); } //将函数rt_hw_rtc_init作为设备供系统自动调用,此时rtc设备移植成功。 int rt_hw_rtc_init(void) { rt_err_t result; result = rt_hw_rtc_register(&rtc, "rtc", RT_DEVICE_FLAG_RDWR); if (result != RT_EOK) { LOG_E("rtc register err code: %d", result); return result; } LOG_D("rtc init success"); return RT_EOK; } INIT_DEVICE_EXPORT(rt_hw_rtc_init);
//#endif /* BSP_USING_ONCHIP_RTC */ 2、测试rtc功能 通过测试date查看rtc时钟,但是此时由于雅特力默认工程并没有注册rtc设备到工程里,故如下图date获取到的时间是错误的。 3、通过menuconfig使能ntp,使能ntp更新rtc时间 4、编译工程,测试从网络获取当前时间 ntp需要联网,网络连接参考上篇帖子介绍 工程运行后在控制台输入ntp_sync获取当前时间,获取情况如下图: 输入”date”命令获取时间此时rtc时间已成功被ntp更新到当前时间点
|