RTC

[新人试水] LPC1768 Nano3_9 添加RTC

发布于 2018-03-28 23:16:43
    本帖最后由 wlof 于 2018-3-28 23:16 编辑


第九章 添加RTC
Wlof摘要:本文首先介绍如何将RTC组件添加到RTT_Nano3上使用,针对在MDK下无法正常使用mktime的问题,重写了mktime函数,也是抄过来的。
9.1 起源
之前SD卡上我们为了写入时间,将gettime这个函数进行了替换,主要还是那个time函数没有去弄它,为了尽可能少地修改提供的代码,这里使用了RTC组件进行操作,实现time函数。在调试过程中发现,mktime这个函数不对,不知道怎么回事,为此在网上找了一些文章,正在好发现有个linux下的源码,直接改写过来。至于那个自带的函数为什么会有问题,俺也不清楚,网上很多人说可以用,但我实际测试就是不能用呢。
9.2 复制文件
位于rt-thread-master\components\drivers\rtc,全部搞过来也行,这里只用以了rtc.c,对应的头文件也复制过来,在rt-thread-master\components\drivers\include\drivers里面。然后找个参考复制文件,我这里参考了STM32F429的,把文件drv_rtc.c 和.h复制过来。这4个文件,统一放到一个目录下,添加到工程,添加include到包含目录。
9.3 修改drv_rtc.c
9.3.1 头文件
去除drv_rtc.c #include "board.h",添加#include "LPC17xx.h"。
9.3.2 删除函数
保留rt开头的函数,保留RTC_Init,SetRTCTimeStamp,GetRTCTimeStamp函数,其的函数全部干掉。然后清空RTC_Init,SetRTCTimeStamp,GetRTCTimeStamp这3个函数的内容,因为我们要添加到LPC1768上来。所有的驱动代码要用LPC1768上的代码,周立功网上可以下载到参考代码。
9.3.3 添加函数
然后把周立功里面的代码复制过来,先不管它用不用,先搞去再说,那个初始化,放到RTC_Init里去,时间读取和设置函数先不要。
void RTC_IRQHandler (void)
{
LPC_RTC->ILR |= ILR_RTCCIF; /* clear interrupt flag */
return;
}

void RTC_Init(void)
{
uint32_t calibration_register = 0;

/* Disable RTC Clock, Reset Clock, Disable Calibration */
LPC_RTC->CCR = ( !CLKEN | CTCRST );

calibration_register = 32768000 / (32768000 - 327630000); //4min + 1s

/* CALDIR */
calibration_register &= ~CALDIR(0);
/* Enable calibration */
LPC_RTC->CCR &= ~CCALEN;
/* Save new calibration register value */
LPC_RTC->CALIBRATION = calibration_register;

/* Disable Clock Reset */
LPC_RTC->CCR &= ~CTCRST;
//==================================//

/* Enable CLOCK into RTC */
LPC_SC->PCONP |= (1 << 9);

/* If RTC is stopped, clear STOP bit. */
if ( LPC_RTC->RTC_AUX & (0x1 << 4) )
{
LPC_RTC->RTC_AUX |= (0x1 << 4);
}

/*--- Initialize registers ---*/
LPC_RTC->AMR = 0; //Alarm Mask Register
LPC_RTC->CIIR = 0; //Counter Increment Interrupt Register
LPC_RTC->CCR = 0; //Clock Control Register
}

void RTCStart( void )
{
/*--- Start RTC counters ---*/
LPC_RTC->CCR |= CCR_CLKEN;
LPC_RTC->ILR = ILR_RTCCIF;
return;
}

void RTCStop( void )
{
/*--- Stop RTC counters ---*/
LPC_RTC->CCR &= ~CCR_CLKEN;
return;
}

void RTC_CTCReset( void )
{
/*--- Reset CTC ---*/
LPC_RTC->CCR |= CCR_CTCRST;
return;
}

void RTCSetAlarmMask( uint32_t AlarmMask )
{
/*--- Set alarm mask ---*/
LPC_RTC->AMR = AlarmMask;
return;
}


9.3.4 修改读写时间函数

time_tGetRTCTimeStamp(void)
{
struct tm tm_new = {0};
time_t cur_time = 0;
tm_new.tm_sec = LPC_RTC->SEC;
tm_new.tm_min = LPC_RTC->MIN;
tm_new.tm_hour = LPC_RTC->HOUR;
tm_new.tm_mday = LPC_RTC->DOM;
tm_new.tm_mon = LPC_RTC->MONTH;
tm_new.tm_year = LPC_RTC->YEAR;
cur_time = mktime(&tm_new);
return cur_time;//mktime(&tm_new);
}
rt_err_t SetRTCTimeStamp(time_t time_stamp)
{
struct tm *p_tm;
p_tm = localtime(&time_stamp);
if(p_tm->tm_year < 100)
{
return RT_ERROR;
}
LPC_RTC->SEC = p_tm->tm_sec;
LPC_RTC->MIN = p_tm->tm_min;
LPC_RTC->HOUR = p_tm->tm_hour;
LPC_RTC->DOW = p_tm->tm_wday+1;
LPC_RTC->DOM = p_tm->tm_mday;
LPC_RTC->MONTH = p_tm->tm_mon+1;
LPC_RTC->YEAR = p_tm->tm_year-100;
return RT_EOK;
}


这里都是按原来的那个文件进行改写的,应改不会出太大的问题。
9.3.5 修改初始化函数
int  rt_hw_rtc_init(void)
{
RTC_Init();
NVIC_EnableIRQ(RTC_IRQn);
RTCSetAlarmMask(AMRSEC | AMRMIN | AMRHOUR | AMRDOM | AMRDOW | AMRDOY | AMRMON | AMRYEAR);
LPC_RTC->CIIR = IMMIN | IMYEAR;
RTCStart();
/* register rtc device */
rt_hw_rtc_register(&rtc, RT_RTC_NAME, 0);
return RT_EOK;
}
INIT_BOARD_EXPORT(rt_hw_rtc_init);


这里发现一个好东东,以前没有注意,这个
INIT_BOARD_EXPORT
可以让系统自动执行初始化函数



9.4 dfs_elm.c的函数还原

这里主要是因为在上一节中我们自己写了一个函数进行了替换,现在将它还原回去。如果没有看上节也没有关系,这里提到这个函数的主要目的就是对这个函数地进行测试,看一下最后结是不是我们想要的。
DWORD get_fattime(void)
{
time_t now;
struct tm *p_tm;
struct tm tm_now;
DWORD fat_time;

/* get current time */
now = time(RT_NULL);
/* lock scheduler. */
rt_enter_critical();
/* converts calendar time time intolocal time. */
p_tm = localtime(&now);
/* copy the statically locatedvariable */
memcpy(&tm_now, p_tm, sizeof(struct tm));
/* unlock scheduler. */
rt_exit_critical();
fat_time = (DWORD)(tm_now.tm_year - 80) << 25 |
(DWORD)(tm_now.tm_mon + 1) << 21 |
(DWORD)tm_now.tm_mday << 16 |
(DWORD)tm_now.tm_hour << 11 |
(DWORD)tm_now.tm_min << 5 |
(DWORD)tm_now.tm_sec / 2 ;
return fat_time;
}


9.5 编译测试
编译有错的话,记得把头文件的宏定义复制来过。编译没有错了,发现转换的时间死活就是不对。我不知道别人有没有这事,反正我里那mktime这个函数就是不对,不仅不对还将传入的参数都改了!!!


9.6 mktime抄过来

按理说,它应改可以正常工作的,但是这是为什么呢?不知道,我用的是MDK5.23。这个代码的原版本是从Linux中搞出来的,我按头文件的写法重新搞一下,其实就是得到utc时间。
time_t mktime(struct tm * timeptr)
{
uint32_t y,m,d,h,n,s;
y = timeptr->tm_year;
m = timeptr->tm_mon;
d = timeptr->tm_mday;
h = timeptr->tm_hour;
n = timeptr->tm_min;
s = timeptr->tm_sec;
if(0 >= (int) (m -= 2)){//1...12 --> 11,12,1...10
m += 12;
y -= 1;
}
return (((
(time_t)(y/4 - y/100 + y/400 + 367*m/12 +d) +
y*365 - 719499
)*24 + h
)*60 + n
)*60 + s;
}



9.7 测试
 {
time_t x = 0; //2017-10-16 14:21:4
x = time(RT_NULL);//x=1508163664
x = x;
get_fattime(); //里面的tm_now 117-9-1614:22:52(加了断点抄数造成的延时)
rt_thread_delay(1);
SetRTCTimeStamp(1508163664);//2017-10-16 14:21:4
}


值得一提的是,那个localtime这个函数,使用时要注意,它返回的是一个指针,应该是一个静态变量,只是值不一样而已,调用一次用一次,不然会悲剧,好像是传说中的不可重入函数。

文档下载:下载附件[RT_Nano_V3初级教程_9 添加RTC.pdf]


查看更多

关注者
0
被浏览
2k
5 个回答
armink
armink 2018-03-29
造了 mktime ,可是测试里面好像没看到使用?
wlof
wlof 2018-03-30
armink 发表于 2018-3-29 17:04
造了 mktime ,可是测试里面好像没看到使用?


那个函数被测代码中的函数调用,洲试代码中的函数在前面。
wlof
wlof 2018-03-30
9.3.4中调用了它,那个time也调用了它
haold123
haold123 2020-03-11
文档怎么下载不来了:o
wlof
wlof 2020-03-11
haold123 发表于 2020-3-11 08:55
文档怎么下载不来了


不知道怎么回事,可能是时间太久了

撰写答案

请登录后再发布答案,点击登录

发布
问题

分享
好友