RTC实时时钟重用外设驱动代码

电子说

1.3w人已加入

描述

周立功教授新书《面向AMetal框架与接口的编程(上)》,对AMetal框架进行了详细介绍,通过阅读这本书,你可以学到高度复用的软件设计原则和面向接口编程的开发思想,聚焦自己的“核心域”,改变自己的编程思维,实现企业和个人的共同进步。

第六章为重用外设驱动代码,本文内容包含6.3 RTC 实时时钟前四个小节:

6.3.1 PCF85063

6.3.2 RTC 通用接口

6.3.3 闹钟通用接口

6.3.4 系统时间

6.3.5 特殊功能控制接口

6.3 RTC 实时时钟

本节将以PCF85063 为例,详细介绍RTC 通用接口,闹钟通用接口等。在本节的最后两小节,将介绍另外两款RTC 芯片:RX8025T 和DS1302,虽然它们与PCF85063 存在差异,但却可以使用同样的通用接口对其进行操作,实现了RTC 应用的跨平台复用。

>>>6.3.1 PCF85063

1. 器件简介

PCF85063 是一款低功耗实时时钟/日历芯片,它提供了实时时间的设置与获取、闹钟、可编程时钟输出、定时器/报警/半分钟/分钟中断输出等功能。

NXP 半导体公司的PCF85063 引脚封装详见图6.4,其中的SCL 和SDA 为I2C接口引脚,VDD 和VSS 分别为电源和地;OSCI 和OSCO 为32.768KHz 的晶振连接引脚,作为PCF85063 的时钟源;CLKOUT 为时钟信号输出,供其它外部电路使用;INT 为中断引脚,主要用于闹钟等功能。

RTC

图6.4 PCF85063 引脚定义

PCF85063 的7 位I2C从机地址为0x51,MicroPort-RTC 模块通过MicroPort 接口与AM824-Core 相连,SCL 和SDA 分别与PIO0_16 和PIO0_18 连接,详见图6.5。若焊接R1,则INT 与PIO0_1 相连;若焊接R3,则INT 与PIO0_8 相连;若焊接R2,则CLKOUT 与PIO0_24 相连。

RTC

图6.5 PCF85063 电路原理图

2. 器件初始化

在使用PCF85063 前,必须完成PCF85063 的初始化操作,以获取对应的操作句柄,进而才能使用PCF85063 的各种功能,初始化函数原型(am_pcf85063.h)为:

RTC

该函数意在获取PCF85063 器件的实例句柄,其中,p_dev 为指向am_pcf85063_dev_t类型实例的指针,int_pin 作为实例信息,指定PCF85063 的INT 与MCU 的连接引脚号。

(1)实例

定义am_pcf85063_dev_t 类型(am_pcf85063.h)实例如下:

RTC

其中,g_pcf85063_dev 为用户自定义的实例,其地址作为p_dev 的实参传递。

(2)实例信息

实例信息仅一个中断引脚信息,用于指定PCF85063 的INT 与MCU 的引脚号相连,便于使用闹钟等功能。假设使用PIO0_1,则PIO0_1 作为int_pin 的实参传递。

(3)I2C句柄i2c_handle

以I2C1 为例,其实例初始化函数am_lpc82x_i2c1_inst_init ()的返回值将作为实参传递给i2c_handle。即:

RTC

(4)实例句柄

PCF85063 初始化函数am_pcf85063_init ()的返回值,作为实参传递给其它功能接口函数的第一个参数(handle)。am_pcf85063_handle_t 类型的定义(am_pcf85063.h)如下:

RTC

若返回值为NULL,说明初始化失败;若返回值不为NULL,说明返回值handle 有效。

基于模块化编程思想,将初始化相关的实例、实例信息等的定义存放到对应的配置文件中,通过头文件引出实例初始化函数接口,源文件和头文件的程序范例分别详见程序清单6.39 和程序清单6.40。

程序清单6.39 实例初始化函数实现(am_hwconf_pcf85063.c)

RTC

程序清单6.40 实例初始化函数声明(am_hwconf_pcf85063.h)

RTC

后续只需要使用无参数的实例初始化函数,即可获取到PCF85063 的实例句柄。即:

RTC

>>>6.3.2 RTC 通用接口

PCF85063 作为一种典型的RTC 器件,可以使用RTC(Real-Time Clock)通用接口设置和获取时间,其函数原型详见表6.10。

表6.10 RTC 通用接口函数(am_rtc.h)

RTC

可见,这些接口函数的第一个参数均为am_rtc_handle_t 类型的RTC 句柄,显然,其并非前文通过PCF85063 实例初始化函数获取的am_pcf85063_handle_t 类型的句柄。

RTC 时间设置和获取只是PCF85063 提供的一个主要功能,PCF85063 还能提供闹钟等功能。PCF85063 的驱动提供了相应的接口用于获取PCF85063 的RTC 句柄,以便用户通过RTC 通用接口操作PCF85063,其函数原型为:

RTC

该函数意在获取RTC 句柄,其中,PCF85063 实例的句柄(pcf85063_handle)作为实参传递给handle,p_rtc 为指向am_rtc_serv_t 类型实例的指针,无实例信息。定义am_rtc_serv_t类型(am_rtc.h)实例如下:

RTC

其中,g_pcf85063_rtc 为用户自定义的实例,其地址作为p_rtc 的实参传递。

基于模块化编程思想,将初始化相关的实例定义存放到对应的配置文件中,通过头文件引出实例初始化函数接口,源文件和头文件分别详见程序清单6.41 和程序清单6.42。

程序清单6.41 新增PCF85063 的RTC 实例初始化函数(am_hwconf_pcf85063.c)

RTC

程序清单6.42 am_hwconf_pcf85063.h 文件内容更新(1)

RTC

后续只需要使用无参数的RTC 实例初始化函数,即可获取RTC 实例句柄。即:

RTC

1. 设置时间

该函数用于设置RTC 器件的当前时间值,其函数原型为:

RTC

其中,handle 为RTC 实例句柄,p_tm 为指向细分时间(待设置的时间值)的指针。返回AM_OK,表示设置成功,反之失败。其类型am_tm_t 是在am_time.h 中定义的细分时间结构体类型,用于表示年/月/日/时/分/秒等信息。即:

RTC

其中,tm_mon 表示月份,分别对应1~12 月。tm_year 表示年,1900 年至今的年数,其实际年为该值加上1900。tm_wday;表示星期,0~6 分别对应星期日~星期六。tm_yday 表示1 月1 日以来的的天数(0~365),0 对应1 月1 日。tm_isdst 表示夏令时,夏季将调快1 小时。如果不用,则设置为-1。设置年/月/日/时/分/秒的值详见程序清单6.43,星期等附加的一些信息无需用户设置,主要便于在获取时间时得到更多的信息。

程序清单6.43 设置时间范例程序

RTC

2. 获取时间

该函数用于获取当前时间值,其函数原型为:

RTC

其中,handle 为RTC 实例句柄,p_tm 为指向细分时间的指针,用于获取细分时间。返回AM_OK,表示获取成功,反之失败,范例程序详见程序清单6.44。

程序清单6.44 获取细分时间范例程序

RTC

基于RTC 通用接口,可以编写一个通用的时间显示应用程序:每隔1s 通过调试串口打印当前的时间值。应用程序的实现和接口声明分别详见程序清单6.45 和程序清单6.46。

程序清单6.45 RTC 时间显示应用程序(app_rtc_time_show.c)

RTC

程序清单6.46 RTC 时间显示接口声明(app_rtc_time_show.h)

RTC

为了启动该应用程序,必须提供一个RTC 实例句柄以指定设置时间和获取时间的RTC对象,若使用PCF85063,则RTC 实例句柄可通过实例初始化函数am_pcf85063_rtc_inst_init()获得,范例程序详见程序清单6.47。

程序清单6.47 启动RTC 应用程序(基于PCF85063)

RTC

>>>6.3.3 闹钟通用接口

PCF85063 除提供基本的RTC 功能外,还可以提供闹钟功能,可以使用闹钟通用接口设置使用闹钟,其函数原型详见表6.11。

表6.11 闹钟通用接口函数(am_alarm_clk.h)

RTC

由此可见,这些接口函数的第一个参数均为am_alarm_clk_handle_t 类型的闹钟句柄,PCF85063 的驱动提供了相应的接口用于获取PCF85063 的闹钟句柄,以便用户通过闹钟通用接口操作PCF85063,其函数原型为:

RTC

该函数意在获取闹钟句柄,其中,PCF85063 实例的句柄(pcf85063_handle)作为实参传递给handle,p_alarm_clk 为指向am_alarm_clk_serv_t 类型实例的指针,无实例信息。定义am_alarm_clk_serv_t 类型(am_alarm_clk.h)实例如下:

RTC

其中,g_pcf85063_alarm_clk 为用户自定义的实例,其地址作为p_alarm_clk 的实参传递。

基于模块化编程思想,将初始化相关的实例定义存放到对应的配置文件中,通过头文件引出实例初始化函数接口,源文件和头文件分别详见程序清单6.48 和程序清单6.49。

程序清单6.48 新增PCF85063 的闹钟实例初始化函数(am_hwconf_pcf85063.c)

RTC

程序清单6.49 am_hwconf_pcf85063.h 文件内容更新(2)

RTC

后续只需要使用无参数的闹钟实例初始化函数,即可获取闹钟实例句柄。即:

RTC

1. 设置闹钟时间

该函数用于设置闹钟时间,其函数原型为:

RTC

其中,handle 为闹钟实例句柄,p_tm 为指向闹钟时间(待设置的时间值)的指针。返回AM_OK,表示设置成功,反之失败。类型am_alarm_clk_tm_t 是在am_alarm_clk.h 中定义的闹钟时间结构体类型,用于表示闹钟时间信息。即:

RTC

其中,min 表示闹钟时间的分,hour 闹钟时间的小时,wdays 用于指定闹钟在周几有效,可以是周一至周日的任意一天或几天。其可用的值已经使用宏进行了定义,比如,AM_ALARM_CLK_SUNDAY 位星期日有效,AM_ALARM_CLK_MONDAY 为星期一有效,AM_ALARM_CLK_TUESDAY 为星期二有效,AM_ALARM_CLK_WEDNESDAY 为星期三有效,AM_ALARM_CLK_THURSDAY 为星期四有效,M_ALARM_CLK_FRIDAY 为星期五有效,AM_ALARM_CLK_SATURDAY 为星期六有效,AM_ALARM_CLK_WORKDAY为工作日有效,AM_ALARM_CLK_EVERYDAY 为每天均有效。

若需闹钟在多天同时有效,则可以将多个宏值使用“|”连接起来,比如,要使闹钟在星期一和星期二有效,则其值为:

AM_ALARM_CLK_MONDAY | AM_ALARM_CLK_TUESDAY。

若需闹钟在星期一至星期五有效(工作日有效),则其值为:

AM_ALARM_CLK_WORKDAY。

若需闹钟在每一天均有效,这其值为AM_ALARM_CLK_EVERYDAY,设置闹钟的范例程序详见程序清单6.50。

程序清单6.50 设置闹钟时间的范例程序

RTC

2. 设置闹钟回调函数

PCF85063 可以在指定的时间产生闹钟事件,当事件发生时,由于需要通知应用程序,因此需要由应用程序设置一个回调函数,在闹钟事件发生时自动调用应用程序设置的回调函数。设置闹钟回调函数原型为:

RTC

其中,handle 为闹钟实例句柄,pfn_callback 为指向实际回调函数的指针,p_arg 为回调函数的参数。若返回AM_OK,表示设置成功,反之失败。

函数指针的类型am_pfnvoid_t 在am_types.h 中定义,即:

RTC

当闹钟事件发生时,将自动调用pfn_callback 指向的回调函数,传递给该回调函数的void*类型的参数就是p_arg 设定值,范例程序详见程序清单6.51。

程序清单6.51 设置闹钟回调函数范例程序

RTC

3. 打开闹钟

该函数用于打开闹钟,以便当闹钟时间到时,自动调用用户设定的回调函数,其函数原型为:

RTC

其中,handle 为闹钟实例句柄。返回AM_OK,表示打开成功,反之失败,范例程序详见程序清单6.52。

程序清单6.52 打开闹钟范例程序

RTC

4. 关闭闹钟

该函数用于关闭闹钟,其函数原型为:

RTC

其中,handle 为闹钟实例句柄。返回AM_OK,表示关闭成功,反之失败,范例程序详见程序清单6.53。

程序清单6.53 关闭闹钟范例程序

RTC

基于闹钟通用接口,可以编写一个通用的闹钟测试应用程序:设定当前时间为09:32:30,闹钟时间为09:34,一分半后,达到闹钟时间,蜂鸣器鸣叫1 分钟。闹钟测试应用程序的实现和接口声明分别详见程序清单6.54 和程序清单6.55。

程序清单6.54 闹钟测试应用程序(app_alarm_clk_test.c)

RTC

程序清单6.55 闹钟测试应用程序接口声明(app_alarm_clk_test.h)

RTC

为了启动该应用程序,必须提供一个RTC 实例句柄以设置当前时间与一个闹钟实例句柄用于设置闹钟,若使用PCF85063,则RTC 实例句柄可通过am_pcf85063_rtc_inst_init()获得,闹钟实例句柄可通过am_pcf85063_alarm_clk_inst_init()获得,范例程序详见程序清单6.56。

程序清单6.56 启动闹钟测试应用程序(基于PCF85063)

RTC

>>>6.3.4 系统时间

AMetal 平台提供了一个系统时间,进行设置和获取系统时间的函数原型详见表6.12。

表6.12 系统时间接口函数(am_time.h)

RTC

1. 系统时间

系统时间的3 种表示形式分别为日历时间、精确日历时间、细分时间,细分时间前文已有介绍,这里仅介绍日历时间和精确日历时间。

  • 日历时间

与标准C 的定义相同,日历时间表示从1970 年1 月1 日1 时0 分0 秒开始的秒数。其类型am_time_t 定义如下:

RTC

  • 精确日历时间

日历时间精度为秒,精确日历时间的精度可以达到纳秒,精确日历时间只是在日历时间的基础上,增加了一个纳秒计数器,其类型am_timespec_t(am_time.h)定义如下:

RTC

当纳秒值达到1000000000 时,则秒值加1;当该值复位为0 时,则重新计数。

2. 初始化

使用系统时间前,必须初始化系统时间,其函数原型为:

RTC

其中,rtc_handle 用于指定系统时间使用的RTC,系统时间将使用该RTC 保存时间和获取时间。update_sysclk_ns 和 update_rtc_s 用以指定更新系统时间相关的参数。

  • RTC 句柄rtc_handle

获取RTC 句柄可通过RTC 实例初始化函数获取,以作为rtc_handle 的实参传递。即:

RTC

  • 与系统时间更新相关的参数(update_sysclk_ns 和 update_rtc_s)

每个MCU 都有一个系统时钟,比如,LPC824,其系统时钟的频率为30MHz,常常称之为主频,在短时间内,该时钟的误差是很小的。由于直接读取MCU 中的数据要比通过I2C读取RTC 器件上的数据快得多,因此根据系统时钟获取时间值比直接从RTC 器件中获取时间值要快得多,完全可以在短时间内使用该时钟更新系统时间,比如,每隔1ms 将精确日历时间的纳秒值增加1000000。但长时间使用该时钟来更新系统时间,势必产生较大的误差,这就需要每隔一定的时间重新从RTC 器件中,读取精确的时间值来更新系统时间,以确保系统时间的精度。

update_sysclk_ns 为指定使用系统时钟更新系统时间的时间间隔,其单位为ns,通常设置为1~100ms,即1000000~100000000。update_rtc_s 为指定使用RTC 器件更新系统时间的时间间隔,若对精度要求特别高,将该值设置为1,即每秒都使用RTC 更新一次系统时间,通常设置为10~ 60 较为合理。

基于此,将初始化函数调用在添加到配置文件中,通过头文件引出系统时间的实例初始化函数接口,详见程序清单6.57 和程序清单6.58。

程序清单6.57 PCF85063 用作系统时间的实例初始化(am_hwconf_pcf85063.c)

RTC

程序清单6.58 am_hwconf_pcf85063.h 文件内容更新(2)

RTC

后续只需要简单的调用该无参函数,即可完成系统时间的初始化。即:

RTC

3. 设置系统时间

根据不同的时间表示形式,有2 种设置系统时间方式。

  • 精确日历时间设置的函数原型为:

RTC

其中,p_tv 为指向精确日历时间(待设置的时间值)的指针。若返回AM_OK,表示设置成功,反之失败,范例程序详见程序清单6.59。

程序清单6.59 使用精确日历时间设置系统时间范例程序

RTC

将精确日历时间的秒值设置为了1472175150,该值是从1970 年1 月1 日0 时0 分0 秒至2016 年8 月26 日09 时32 分30 秒的秒数。即将时间设置为2016 年8 月26 日09 时32分30 秒。通常不会这样设置时间值,均是采用细分时间方式设置时间值。

  • 细分时间设置的函数原型为:

RTC

其中,p_tm 为指向细分时间(待设置的时间值)的指针。若返回AM_OK,表示设置成功,反之失败,范例程序详见程序清单6.60。

程序清单6.60 使用细分时间设置系统时间范例程序

RTC

将时间设置为2016 年8 月26 日09:32:30,当使用细分时间设置时间值时,则细分时间的成员tm_wday, tm_yday 在调用后被更新。如果不使用夏令时,则设置为-1。

4. 获取系统时间

根据不同的时间表示形式,有3 种获取系统时间的方式。

  • 获取日历时间的函数原型为:

RTC

其中,p_time 为指向日历时间的指针,用于获取日历时间。返回值同样为日历时间,若返回值为-1,表明获取失败,通过返回值获取日历时间的范例程序详见程序清单6.61。

程序清单6.61 通过返回值获取日历时间范例程序

RTC

也可以通过参数获得日历时间,范例程序详见程序清单6.62。

程序清单6.62 通过参数获取日历时间范例程序

RTC

  • 获取精确日历时间的函数原型为:

RTC

其中,p_tv 为指向精确日历时间的指针,用于获取精确日历时间。若返回AM_OK,获取成功,反之失败,范例程序详见程序清单6.63。

程序清单6.63 读取精确日历时间范例程序

RTC

  • 获取细分时间的函数原型为:

RTC

其中,p_tm 为指向细分时间的指针,用于获取细分时间。若返回AM_OK,表示获取成功,反之失败,范例程序详见程序清单6.64。

程序清单6.64 获取细分时间范例程序

RTC

基于系统时间相关接口,可以编写一个通用的系统时间测试应用程序:每隔1s 通过调试串口打印当前的系统时间值。应用程序的实现和接口声明分别详见程序清单6.65 和程序清单6.66。

程序清单6.65 系统时间测试应用程序(app_sys_time_show.c)

RTC

程序清单6.66 系统时间测试应用程序接口声明(app_sys_time_show.h)

RTC

由此可见,在应用程序中,不再使用到任何实例句柄,使得应用程序不与任何具体器件直接关联,系统时间的定义使得应用程序在使用时间时更加便捷。在启动应用程序前,必须完成系统时间的初始化,若使用PCF85063 为系统时间提供RTC 服务,则系统时间的初始化可以通过am_pcf85063_time_inst_init ()完成,范例程序详见程序清单6.67。

程序清单6.67 启动系统时间测试应用程序(基于PCF85063)

RTC

>>>6.3.5 特殊功能控制接口

对于PCF85063,除典型的时钟和闹钟功能外,还具有一些特殊功能,如定时器、时钟输出、1 字节RAM 等。这些功能由于不是通用功能,只能使用PCF85063 相应的接口进行操作。以读写1 字节RAM 为例,其相应的接口函数详见表6.13。

表6.13 读写RAM 接口函数(am_pcf85063.h)

RTC

1. 写入RAM

该函数用于写入1 字节数据到PCF85063 的RAM 中,其函数原型为:

RTC

其中,handle 为PCF85063 实例句柄,data 为写入的单字节数据。若返回AM_OK,表示数据写入成功,反之失败,写入0x55 至RAM 中的范例程序详见程序清单6.68。

程序清单6.68 写入RAM 范例程序

RTC

2. 读取RAM

该函数读取存于PCF85063 的单字节RAM 中的数据,其函数原型为:

RTC

其中,handle 为PCF85063 实例句柄,p_data 为输出参数,用于返回读取到的单字节数据。返回AM_OK,表示读取成功,反之失败,范例程序详见程序清单6.69。

程序清单6.69 读取范例程序

RTC

可以使用读写RAM 接口简单验证PCF85063 是否正常,详见程序清单6.70。

程序清单6.70 读写RAM 数据范例程序

RTC


打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 相关推荐
  • RTC

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分