wangji12 发表于 2020-6-1 16:53

【RTOS】+ RT-Thread + 雅特力AT_START_F403A_V1开发板-wifi-ntp_rtc移植

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={0,3,3,6,1,4,6,2,5,0,3,5};                                                 //Monthly correction data sheet.const uint8_t mon_table={31,28,31,30,31,30,31,31,30,31,30,31};        //Month data table of Pingnian_calendar_obj calendar;

/*** @briefGet current week by Input Leap year\mouth\day.* @paramsyear : 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;        if (yearL%4==0&&month<3)                temp2--;        return(temp2%7);}/*** @briefGet current time.* @paramNone.* @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)temp-=mon_table;                                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));}

/*** @briefJudeg the Leap year or Pingnian.*         Month      12345678910 11 12*         Leap year31 29 31 30 31 30 31 31 30 31 30 31*         Pingnian   31 28 31 30 31 30 31 31 30 31 30 31* @paramyear* @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;        }       
/*** @briefSet time. Convert the input clock to a second.*         The time basic : 1970.1.1*         legitimate year: 1970 ~ 2099* @paramsyear: 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*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_OPSconst 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更新到当前时间点

21ic小喇叭 发表于 2020-6-5 12:43

大大,我看您写的非常专业,您如果完成了作品,千万别忘记按比赛要求,做成文档,上传到论坛

文档模板在咱们参赛群里有,如果没找到,联系大掌柜单独发给您

提交作品以后,大掌柜给您寄礼品
页: [1]
查看完整版本: 【RTOS】+ RT-Thread + 雅特力AT_START_F403A_V1开发板-wifi-ntp_rtc移植