正点原子 发表于 2020-6-6 15:54:01

【正点原子Linux连载】第二十五章RTC实时时钟实验--摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南

本帖最后由 正点原子 于 2020-10-24 16:06 编辑

1)实验平台:正点原子阿尔法Linux开发板
2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html
4)本章实例源码下载:   
5)对正点原子Linux感兴趣的同学可以加群讨论:876919289
6)关注正点原子公众号,获取最新资料





第二十五章RTC实时时钟实验
      
      实时时钟是很常用的一个外设,通过实时时钟我们就可以知道年、月、日和时间等信息。因此在需要记录时间的场合就需要实时时钟,可以使用专用的实时时钟芯片来完成此功能,但是现在大多数的MCU或者MPU内部就已经自带了实时时钟外设模块。比如I.MX6U内部的SNVS就提供了RTC功能,本章我们就学习如何使用I.MX6U内部的RTC来完成实时时钟功能。

25.1 I.MX6U RTC简介
      如果学习过STM32的话应该知道,STM32内部有一个RTC外设模块,这个模块需要一个32.768KHz的晶振,对这个RTC模块进行初始化就可以得到一个实时时钟。I.MX6U内部也有个RTC模块,但是不叫作“RTC”,而是叫做“SNVS”,这一点要注意!本章我们参考《I.MX6UL参考手册》,而不是《I.MX6ULL参考手册》,因为《I.MX6ULL参考手册》很多SNVS相关的寄存器并没有给出来,不知道是为何?但是《I.MX6UL参考手册》里面是完整的。所以本章我们使用《I.MX6UL参考手册》,如果直接在《I.MX6UL参考手册》的书签里面找“RTC”相关的字眼是找不到的。I.MX6U系列的RTC是在SNVS里面,也就是《I.MX6UL参考手册》的第46章“Chapter46 Secure Non-Volatile Storage(SNVS)”。
      SNVS直译过来就是安全的非易性存储,SNVS里面主要是一些低功耗的外设,包括一个安全的实时计数器(RTC)、一个单调计数器(monotonic counter)和一些通用的寄存器,本章我们肯定只使用实时计数器(RTC)。SNVS里面的外设在芯片掉电以后由电池供电继续运行,I.MX6U-ALPHA开发板上有一个纽扣电池,这个纽扣电池就是在主电源关闭以后为SNVS供电的,如图25.1.1所示:

图25.1.1 I.MX6U-ALPHA开发板纽扣电池
      因为纽扣电池在掉电以后会继续给SNVS供电,因此实时计数器就会一直运行,这样的话时间信息就不会丢失,除非纽扣电池没电了。在有纽扣电池作为后备电源的情况下,不管系统主电源是否断电,SNVS都正常运行。SNVS有两部分:SNVS_HP和SNVS_LP,系统主电源断电以后SNVS_HP也会断电,但是在后备电源支持下,SNVS_LP是不会断电的,而且SNVS_LP是和芯片复位隔离开的,因此SNVS_LP相关的寄存器的值会一直保存着。
      SNVS分为两个子模块:SNVS_HP和SNVS_LP,也就是高功耗域(SNVS_HP)和低功耗域(SNVS_LP),这两个域的电源来源如下:
      SNVS_LP:专用的always-powered-on电源域,系统主电源和备用电源都可以为其供电。
      SNVS_HP:系统(芯片)电源。
      SNVS的这两个子模块的电源如图25.1.2所示:

图25.1.2 SNVS子模块电源结构图
      图25.1.2中各个部分功能如下:
      、VDD_HIGH_IN是系统(芯片)主电源,这个电源会同时供给给SNVS_HP和SNVS_LP。
      、VDD_SNVS_IN是纽扣电池供电的电源,这个电源只会供给给SNVS_LP,保证在系统主电源VDD_HIGH_IN掉电以后SNVS_LP会继续运行。
      、SNVS_HP部分。
      、SNVS_LP部分,此部分有个SRTC,这个就是我们本章要使用的RTC。
      其实不管是SNVS_HP还是SNVS_LP,其内部都有一个SRTC,但是因为SNVS_HP在系统电源掉电以后就会关闭,所以我们本章使用的是SNVS_LP内部的SRTC。毕竟我们肯定都不想开发板或者设备每次关闭以后时钟都被清零,然后开机以后先设置时钟。
      其实不管是SNVS_HP里面的RTC,还是SNVS_LP里面的SRTC,其本质就是一个定时器,和我们在第八章讲的EPIT定时器一样,只要给它提供时钟,它就会一直运行。SRTC需要外界提供一个32.768KHz的时钟,I.MX6U-ALPHA核心板上的32.768KHz的晶振就是提供这个时钟的。寄存器SNVS_LPSRTCMR和SNVS_LPSRTCLR保存着秒数,直接读取这两个寄存器的值就知道过了多长时间了。一般以1970年1月1日为起点,加上经过的秒数即可得到现在的时间和日期,原理还是很简单的。SRTC也是带有闹钟功能的,可以在寄存器SNVS_LPAR中写入闹钟时间值,当时钟值和闹钟值匹配的时候就会产生闹钟中断,要使用时钟功能的话还需要进行一些设置,本章我们就不使用闹钟了。
      接下来我们看一下本章要用到的与SRTC相关的部分寄存器,首先是SNVS_HPCOMR寄存器,这个寄存器我们只用到了位:NPSWA_EN(bit31),这个位是非特权软件访问控制位,如果非特权软件要访问SNVS的话此位必须为1。
      接下来看一下寄存器SNVS_LPCR寄存器,此寄存器也只用到了一个位:SRTC_ENV(bit0),此位为1的话就使能STC计数器。
      最后来看一下寄存器SNVS_SRTCMR和SNVS_SRTCLR,这两个寄存器保存着RTC的秒数,按照NXP官方的《6UL参考手册》中的说法,SNVS_SRTCMR保存着高15位,SNVS_SRTCLR保存着低32位,因此SRTC的计数器一共是47位。
      但是!我在编写驱动的时候发现按照手册上说的去读取计数器值是错误的!具体表现就是时间是混乱的,因此我在查找了NXP提供的SDK包中的fsl_snvs_hp.c以及Linux内核中的rtc-snvs.c这两个驱动文件以后发现《6UL参考手册》上对SNVS_SRTCMR和SNVS_SRTCLR的解释是错误的,经过查阅这两个文件,得到如下结论:
      ①、SRTC计数器是32位的,不是47位!
      ②、SNVS_SRTCMR的bit14:0这15位是SRTC计数器的高15位。
      ③、SNVS_SRTCLR的bit31:bit15这17位是SRTC计数器的低17位。
按照上面的解释去读取这两个寄存器就可以得到正确的时间,如果要调整时间的话也是向这两个寄存器写入要设置的时间值对应的秒数就可以了,但是要修改这两个寄存器的话要先关闭SRTC。
关于SNVS中和RTC有关的寄存器就介绍到这里,关于这些寄存器详细的描述,请参考《I.MX6UL参考手册》第2931页的46.7小节。本章我们使用I.MX6U的SNVS_LP的SRTC,配置步骤如下:
      1、初始化SNVS_SRTC
      初始化SNVS_LP中的SRTC。
      2、设置RTC时间
      第一次使用RTC肯定要先设置时间。
      3、使能RTC
      配置好RTC并设置好初始时间以后就可以开启RTC了。
25.2硬件原理分析
本试验用到的资源如下:
、指示灯LED0。
、RGB LCD接口。
③、SRTC。
      SRTC需要外接一个32.768KHz的晶振,在I.MX6U-ALPHA核心板上就有这个32.768KHz的晶振,原理图如图25.2.1所示:

图25.2.1外接32.768KHz晶振
25.3实验程序编写
本实验对应的例程路径为:开发板光盘-> 1、裸机例程->16_rtc。
25.3.1修改文件MCIMX6Y2.h
在第十三章移植的NXP官方SDK包是针对I.MX6ULL编写的,因此文件MCIMX6Y2.h中的结构体SNVS_Type里面的寄存器是不全的,我们需要在其中加入本章实验所需要的寄存器,修改SNVS_Type为如下所示:
示例代码25.3.1.1 SNVS_Type结构体
1typedefstruct{
2    __IO uint32_t HPLR;
3    __IO uint32_t HPCOMR;
4    __IO uint32_t HPCR;
5    __IO uint32_t HPSICR;
6    __IO uint32_t HPSVCR;
7    __IO uint32_t HPSR;
8    __IO uint32_t HPSVSR;
9    __IO uint32_t HPHACIVR;
10   __IO uint32_t HPHACR;
11   __IO uint32_t HPRTCMR;
12   __IO uint32_t HPRTCLR;
13   __IO uint32_t HPTAMR;
14   __IO uint32_t HPTALR;
15   __IO uint32_t LPLR;
16   __IO uint32_t LPCR;
17   __IO uint32_t LPMKCR;
18   __IO uint32_t LPSVCR;
19   __IO uint32_t LPTGFCR;
20   __IO uint32_t LPTDCR;
21   __IO uint32_t LPSR;
22   __IO uint32_t LPSRTCMR;
23   __IO uint32_t LPSRTCLR;
24   __IO uint32_t LPTAR;
25   __IO uint32_t LPSMCMR;
26   __IO uint32_t LPSMCLR;
27}SNVS_Type;
25.3.2编写实验程序
      本章实验在上一章例程的基础上完成,更改工程名字为“rtc”,然后在bsp文件夹下创建名为“rtc”的文件夹,然后在bsp/rtc中新建bsp_rtc.c和bsp_rtc.h这两个文件。在bsp_rtc.h中输入如下内容:
示例代码25.3.2.1 bsp_rtc.h文件代码
1#ifndef _BSP_RTC_H
2#define _BSP_RTC_H
3/***************************************************************
4Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
5文件名    : bsp_rtc.h
6作者      : 左忠凯
7版本      : V1.0
8描述      : RTC驱动头文件。
9其他      : 无
10论坛      : www.openedv.com
11日志      : 初版V1.0 2019/1/3 左忠凯创建
12 ***************************************************************/
13 #include "imx6ul.h"
14
15/* 相关宏定义 */
16 #define SECONDS_IN_A_DAY         (86400)      /* 一天86400秒                */
17 #define SECONDS_IN_A_HOUR          (3600)      /* 一个小时3600秒      */
18 #define SECONDS_IN_A_MINUTE(60)      /* 一分钟60秒      */
19 #define DAYS_IN_A_YEAR            (365)                /* 一年365天      */
20 #define YEAR_RANGE_START         (1970)                /* 开始年份1970年      */
21 #define YEAR_RANGE_END            (2099)      /* 结束年份2099年      */
22
23/* 时间日期结构体 */
24struct rtc_datetime
25{
26unsignedshort year;                /* 范围为:1970 ~ 2099               */
27unsignedchar month;                /* 范围为:1 ~ 12                */
28unsignedchar day;                /* 范围为:1 ~ 31 (不同的月,天数不同).*/
29unsignedchar hour;                /* 范围为:0 ~ 23                           */
30unsignedchar minute;      /* 范围为:0 ~ 59                     */
31unsignedchar second;      /* 范围为:0 ~ 59                     */
32};
33
34/* 函数声明 */
35void rtc_init(void);
36void rtc_enable(void);
37void rtc_disable(void);
38unsignedint rtc_coverdate_to_seconds(struct rtc_datetime
*datetime);
39unsignedint rtc_getseconds(void);
40void rtc_setdatetime(struct rtc_datetime *datetime);
41void rtc_getdatetime(struct rtc_datetime *datetime);
42
43 #endif
      第16到21行定义了一些宏,比如一天多少秒、一小时多少秒等等,这些宏将用于将秒转换为时间,或者将时间转换为秒。第24行定义了一个结构体rtc_datetime,此结构体用于描述日期和时间参数。剩下的就是一些函数声明了,很简单。
      在文件bsp_rtc.c中输入如下内容:
示例代码25.3.2.2 bsp_rtc.c文件代码
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名   : bsp_rtc.c
作者   : 左忠凯
版本   : V1.0
描述   : RTC驱动文件。
其他   : 无
论坛   : www.openedv.com
日志   : 初版V1.0 2019/1/3 左忠凯创建
***************************************************************/
1   #include "bsp_rtc.h"
2   #include "stdio.h"
3
4/*
5    * @description      :初始化RTC
6    */
7void rtc_init(void)
8{
9/*
10       * 设置HPCOMR寄存器
11       * bit 1 : 允许访问SNVS寄存器,一定要置1
12       */
13      SNVS->HPCOMR |=(1<<31);
14
15#if0
16struct rtc_datetime rtcdate;
17
18      rtcdate.year =2018U;
19      rtcdate.month =12U;
20      rtcdate.day =13U;
21      rtcdate.hour =14U;
22      rtcdate.minute =52;
23      rtcdate.second =0;
24      rtc_setDatetime(&rtcdate);      /* 初始化时间和日期      */
25#endif
26      rtc_enable();                              /* 使能RTC                         */
27}
28
29/*
30   * @description      : 开启RTC
31   */
32void rtc_enable(void)
33{
34/*
35       * LPCR寄存器bit0置1,使能RTC
36       */
37      SNVS->LPCR |=1<<0;
38while(!(SNVS->LPCR &0X01));      /* 等待使能完成 */
39
40}
41
42/*
43    * @description      : 关闭RTC
44   */
45void rtc_disable(void)
46{
47/*
48       * LPCR寄存器bit0置0,关闭RTC
49       */
50      SNVS->LPCR &=~(1<<0);
51while(SNVS->LPCR &0X01);      /* 等待关闭完成*/
52}
53
54/*
55   * @description         : 判断指定年份是否为闰年,闰年条件如下:
56   * @param – year      : 要判断的年份
57   * @return            : 1 是闰年,0 不是闰年
58   */
59unsignedchar rtc_isleapyear(unsignedshort year)
60{
61unsignedchar value=0;
62
63if(year %400==0)
64          value =1;
65else
66{
67if((year %4==0)&&(year %100!=0))
68            value =1;
69else
70            value =0;
71}
72return value;
73}
74
75/*
76   * @description             : 将时间转换为秒数
77   * @param – datetime      : 要转换日期和时间。
78   * @return                  : 转换后的秒数
79   */
80unsignedint rtc_coverdate_to_seconds(struct rtc_datetime *datetime)
81{
82unsignedshort i =0;
83unsignedint seconds =0;
84unsignedint days =0;
85unsignedshort monthdays[]={0U,0U,31U,59U,90U,120U,151U,
181U,212U,243U,273U,304U,334U};
86
87for(i =1970; i < datetime->year; i++)
88{
89          days += DAYS_IN_A_YEAR;                /* 平年,每年365天      */
90if(rtc_isleapyear(i)) days +=1;      /* 闰年多加一天      */
91}
92
93      days += monthdays;
94if(rtc_isleapyear(i)&&(datetime->month >=3)) days +=1;
95
96      days += datetime->day -1;
97
98      seconds = days * SECONDS_IN_A_DAY +
99                  datetime->hour * SECONDS_IN_A_HOUR +
100               datetime->minute * SECONDS_IN_A_MINUTE +
101               datetime->second;
102
103return seconds;
104}
105
106/*
107* @description             : 设置时间和日期
108* @param – datetime      : 要设置的日期和时间
109* @return                  : 无
110*/
111void rtc_setdatetime(struct rtc_datetime *datetime)
112{
113
114unsignedint seconds =0;
115unsignedint tmp = SNVS->LPCR;
116
117   rtc_disable();      /* 设置寄存器HPRTCMR和HPRTCLR前要先关闭RTC */
118/* 先将时间转换为秒         */
119   seconds = rtc_coverdate_to_seconds(datetime);
120   SNVS->LPSRTCMR =(unsignedint)(seconds >>17);/* 设置高16位 */
121   SNVS->LPSRTCLR =(unsignedint)(seconds <<15);/* 设置地16位 */
122
123/* 如果此前RTC是打开的在设置完RTC时间以后需要重新打开RTC */
124if(tmp &0x1)
125         rtc_enable();
126}
127
128/*
129* @description             : 将秒数转换为时间
130* @param - seconds         : 要转换的秒数
131* @param – datetime      : 转换后的日期和时间
132* @return                  : 无
133*/
134void rtc_convertseconds_to_datetime(unsignedint seconds,
struct rtc_datetime *datetime)
135{
136unsignedint x;
137unsignedintsecondsRemaining, days;
138unsignedshort daysInYear;
139
140/* 每个月的天数       */
141unsignedchar daysPerMonth[]={0U,31U,28U,31U,30U,31U,
30U,31U,31U,30U,31U,30U,31U};
142
143   secondsRemaining = seconds;/* 剩余秒数初始化 */
144   days = secondsRemaining / SECONDS_IN_A_DAY +1;
145   secondsRemaining = secondsRemaining % SECONDS_IN_A_DAY;
146
147/* 计算时、分、秒 */
148   datetime->hour = secondsRemaining / SECONDS_IN_A_HOUR;
149   secondsRemaining = secondsRemaining % SECONDS_IN_A_HOUR;
150   datetime->minute = secondsRemaining /60;
151   datetime->second = secondsRemaining % SECONDS_IN_A_MINUTE;
152
153/* 计算年 */
154   daysInYear = DAYS_IN_A_YEAR;
155   datetime->year = YEAR_RANGE_START;
156while(days > daysInYear)
157{
158/* 根据天数计算年 */
159         days -= daysInYear;
160         datetime->year++;
161
162/* 处理闰年 */
163if(!rtc_isleapyear(datetime->year))
164             daysInYear = DAYS_IN_A_YEAR;
165else/*闰年,天数加一 */
166             daysInYear = DAYS_IN_A_YEAR +1;
167}
168/*根据剩余的天数计算月份 */
169if(rtc_isleapyear(datetime->year))/* 如果是闰年的话2月加一天 */
170         daysPerMonth=29;
171for(x =1; x <=12; x++)
172{
173if(days <= daysPerMonth)
174{
175             datetime->month = x;
176break;
177}
178else
179{
180             days -= daysPerMonth;
181}
182}
183   datetime->day = days;
184}
185
186/*
187* @description         : 获取RTC当前秒数
188* @param               : 无
189* @return            : 当前秒数
190*/
191unsignedint rtc_getseconds(void)
192{
193unsignedint seconds =0;
194
195   seconds =(SNVS->LPSRTCMR <<17)|(SNVS->LPSRTCLR >>15);
196return seconds;
197}
198
199/*
200* @description             : 获取当前时间
201* @param – datetime      : 获取到的时间,日期等参数
202* @return                  : 无
203*/
204void rtc_getdatetime(struct rtc_datetime *datetime)
205{
206unsignedint seconds =0;
207   seconds = rtc_getseconds();
208   rtc_convertseconds_to_datetime(seconds, datetime);
209}
      文件bsp_rtc.c里面一共有9个函数,依次来看一下这些函数的意义。函数rtc_init明显是初始化rtc的,主要是使能RTC,也可以在rtc_init函数里面设置时间。函数rtc_enable和rtc_disable分别是RTC的使能和禁止函数。函数rtc_isleapyear用于判断某一年是否为闰年。函数rtc_coverdate_to_seconds负责将给定的日期和时间信息转换为对应的秒数。函数rtc_setdatetime用于设置时间,也就是设置寄存器SNVS_LPSRTCMR和SNVS_LPSRTCLR。函数rtc_convertseconds_to_datetime用于将给定的秒数转换为对应的时间值。函数rtc_getseconds获取SRTC当前秒数,其实就是读取寄存器SNVS_LPSRTCMR和SNVS_LPSRTCLR,然后将其结合成47位的值。最后一个函数rtc_getdatetime是获取时间值。
我们在main函数里面先初始化RTC,然后进入3S倒计时,如果这3S内按下了KEY0按键,那么就设置SRTC的日期。如果3S倒计时结束以后没有按下KEY0,也就是没有设置SRTC时间的话就进入while循环,然后读取RTC的时间值并且显示在LCD上,在文件main.c中输入如下所示内容:
示例代码25.3.2.3 main.c文件代码
/**************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名   : mian.c
作者   : 左忠凯
版本   : V1.0
描述   : I.MX6U开发板裸机实验17 RTC实时时钟实验
其他   : 本实验学习如何编写I.MX6U内部的RTC驱动,使用内部RTC可以实现
一个实时时钟。
论坛   : www.openedv.com
日志   : 初版V1.0 2019/1/15 左忠凯创建
**************************************************************/
1#include "bsp_clk.h"
2#include "bsp_delay.h"
3#include "bsp_led.h"
4#include "bsp_beep.h"
5#include "bsp_key.h"
6#include "bsp_int.h"
7#include "bsp_uart.h"
8#include "bsp_lcd.h"
9#include "bsp_lcdapi.h"
10 #include "bsp_rtc.h"
11 #include "stdio.h"
12
13/*
14* @description         : main函数
15* @param                : 无
16* @return               : 无
17*/
18int main(void)
19{
20      unsignedchar key =0;
21      int t =0;
22                int i =3;                /* 倒计时3S */
23      char buf;
24      struct rtc_datetime rtcdate;
25      unsignedchar state = OFF;
26
27      int_init();      /* 初始化中断(一定要最先调用!)         */
28      imx6u_clkinit();      /* 初始化系统时钟      */
29      delay_init();      /* 初始化延时                        */
30      clk_enable();      /* 使能所有的时钟      */
31      led_init();      /* 初始化led                           */
32      beep_init();      /* 初始化beep                            */
33      uart_init();      /* 初始化串口,波特率115200         */
34      lcd_init();      /* 初始化LCD                           */
35      rtc_init();      /* 初始化RTC                                 */
36      
37      tftlcd_dev.forecolor = LCD_RED;
38      lcd_show_string(50,10,400,24,24,      /* 显示字符串 */
(char*)"ALPHA-IMX6UL RTC TEST");
39      tftlcd_dev.forecolor = LCD_BLUE;
40      memset(buf,0,sizeof(buf));
41
42      while(1)
43      {
44      if(t==100)/* 1s时间到了 */
45                {
46                t=0;
47                printf("will be running %d s......\r", i);
48
49                lcd_fill(50,40,370,70, tftlcd_dev.backcolor);/* 清屏 */
50                sprintf(buf,"will be running %ds......", i);
51                lcd_show_string(50,40,300,24,24, buf);
52                i--;
53                if(i <0)
54                break;
55      }
56
57      key = key_getvalue();
58      if(key == KEY0_VALUE)
59      {
60                rtcdate.year =2018;
61      rtcdate.month =1;
62                rtcdate.day =15;
63                rtcdate.hour =16;
64                rtcdate.minute =23;
65                rtcdate.second =0;
66                rtc_setdatetime(&rtcdate);/* 初始化时间和日期 */
67                printf("\r\n RTC Init finish\r\n");
68                break;
69      }
70
71                delayms(10);
72      t++;
73      }
74      tftlcd_dev.forecolor = LCD_RED;
75      lcd_fill(50,40,370,70, tftlcd_dev.backcolor);/* 清屏 */
76      lcd_show_string(50,40,200,24,24,(char*)"Current Time:");
77      tftlcd_dev.forecolor = LCD_BLUE;
78
79      while(1)
80      {
81      rtc_getdatetime(&rtcdate);
82      sprintf(buf,"%d/%d/%d %d:%d:%d",rtcdate.year, rtcdate.month,
rtcdate.day, rtcdate.hour, rtcdate.minute, rtcdate.second);
83      lcd_fill(50,70,300,94, tftlcd_dev.backcolor);
84      lcd_show_string(50,70,250,24,24,(char*)buf);/* 显示字符串 */
85
86      state =!state;
87      led_switch(LED0,state);
88      delayms(1000);/* 延时一秒 */
89      }
90      return0;
91}
      第35行调用函数rtc_init初始化RTC。
      第42到73行是倒计时3S,如果在这3S 内按下了KEY0按键就会调用函数rtc_setdatetime设置当前的时间。如果3S到技术结束以后没有按下KEY0那就表示不需要设置时间,跳出循环,执行下面的代码。
      第79到89行就是主循环,此循环每隔1S调用函数rtc_getdatetime获取一次时间值,并且通过串口打印给SecureCRT或者在LCD上显示。
25.4编译下载验证
25.4.1 编写Makefile和链接脚本
修改Makefile中的TARGET为rtc,然后在在INCDIRS和SRCDIRS中加入“bsp/rtc”,修改后的Makefile如下:
示例代码25.4.1 Makefile代码
1CROSS_COMPILE      ?= arm-linux-gnueabihf-
2TARGET                  ?=rtc
3
4/* 省略掉其它代码...... */
5
6INCDIRS      :=      imx6ul \
7                stdio/include \
8                bsp/clk \
9                bsp/led \
10                bsp/delay\
11                bsp/beep \
12               bsp/gpio \
13               bsp/key \
14                bsp/exit \
15                bsp/int \
16                bsp/epittimer \
17                bsp/keyfilter \
18                bsp/uart \
19               bsp/lcd \
20                bsp/rtc
21
22 SRCDIRS      :=      project \
23                stdio/lib \
24                bsp/clk \
25                bsp/led \
26                bsp/delay \
27                bsp/beep \
28               bsp/gpio \
29                bsp/key \
30                bsp/exit \
31                bsp/int \
32                bsp/epittimer \
33                bsp/keyfilter \
34               bsp/uart \
35                bsp/lcd \
36                bsp/rtc
37
38/* 省略掉其它代码...... */
39
40 clean:
41rm -rf $(TARGET).elf $(TARGET).dis $(TARGET).bin $(COBJS)$(SOBJS)
第2行修改变量TARGET为“rtc”,也就是目标名称为“rtc”。
      第20行在变量INCDIRS中添加RTC驱动头文件(.h)路径。
      第36行在变量SRCDIRS中添加RTC驱动驱动文件(.c)路径。
      链接脚本保持不变。
25.4.2编译下载
      使用Make命令编译代码,编译成功以后使用软件imxdownload将编译完成的rtc.bin文件下载到SD卡中,命令如下:
chmod 777 imxdownload                        //给予imxdownload可执行权限,一次即可
./imxdownload rtc.bin /dev/sdd                //烧写到SD卡中
      烧写成功以后将SD卡插到开发板的SD卡槽中,然后复位开发板。程序一开始进入3S倒计时,如图25.4.2.1所示:

图24.4.2.13秒钟倒计时
      如果在倒计数结束之前按下KEY0,那么RTC就会被设置为我们代码中设置的时间和日期值,RTC运行如图24.4.2.2所示:

图24.4.2.2设置有的时间
      我们在main函数中设置的时间是2018年1月15日,16点23分0秒,在倒计数结束之前按下KEY0按键设置RTC,图24.4.2.2中的时间就是我们设置以后的时间。
页: [1]
查看完整版本: 【正点原子Linux连载】第二十五章RTC实时时钟实验--摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南