打印
[uCOS/RTOS]

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

[复制链接]
638|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
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更新到当前时间点


852705ed4c06c41675.png (406.63 KB )

852705ed4c06c41675.png

使用特权

评论回复

相关帖子

沙发
21ic小喇叭| | 2020-6-5 12:43 | 只看该作者
大大,我看您写的非常专业,您如果完成了作品,千万别忘记按比赛要求,做成文档,上传到论坛

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

提交作品以后,大掌柜给您寄礼品

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

8

主题

9

帖子

0

粉丝