必须完成PCF85063 的初始化操作
发布时间:2019-03-20 22:25

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  其中,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,星期等附加的一些信息无需用户设置,主要便于在获取时间时得到更多的信息。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  每个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。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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