(16)给树莓派B+ 安装一个实时时钟芯片DS1302


在这里首先感谢glgoo在google被墙的情况下提供搜索功能,还要感谢
http://wiringpi.com/ 以及github,尽管自己眼瞎,几经波折还是发现了尘封已久的少林“七十二绝技”,没错,每种绝技都能克制一个树莓派GPIO控制外设的问题,七十二绝技的核心就是wiringpi这个为Pi GPIO写的C语言库了,而每种绝技则暗藏在wiringPi/examples/目录下,这里就不一一罗列了,大家想学什么招式,就去看每个example,都非常简短。
其实早在第9篇文章“安装GPIO库”,就已经下载并安装了wiringPi,然而后来一直没用C,而用的是python,python的便捷性、交互式开发使得调试非常方便,直到这一次准备安装一个DS1302时钟芯片时,苦于搜不到相关的解决方案,才最终转回C库。然而可能会陷入rtc-pi这个C程序来驱动DS1302,这里面并没有用wiringPi的封装,二是直接和交互了,像我这种菜鸟,暂时不会改里面的地址,外文网站上又写的不清楚。好在最终还是搜到了github里面的ds1302.c,定睛一看原来是在wiringPi项目的examples里,顿时心中千万头草泥马呼啸而过。
暂时不必着急看ds1302.c源码,因为,它相当简单,把自己的线路连接好,引脚编号对应修改就大功告成,然后再仔细品读源码不迟。
DS1302时钟模块的5个引脚分别是VCC、GND、CLK、DAT、RST,都是有意义的,可以在树莓派B+上面找到类似的引脚如SCLK、SDA、CE,我们就用这几个类似的GPIO引脚来和DS1302连接,如下图:

这里我们要注意这几个引脚对应的wPi的编号,而不是BOARD编号,对应关系如下:
BOARD – NAME – DS1302 – wPi
1         – 3.3V   – VCC      – 无

23       – SCLK   – CLK      – 14

25       – 0V      – GND      – 无 

27       – SDA.0 – DAT      – 30

24       – CE0    – RST      – 10
所以,我们只需要用14、30、10这几个GPIO引脚来编程就可以了。
现在,可以打开wiringPi/examples/ds1302.c文件,它里面包含了wiring/devLib/下的ds1302.h,隐藏了具体的实现细节,可以先不关注。直接看main函数:

需要用到的函数就是画红线的几个,首先调用ds1302setup(int clockPin, int dataPin, int csPin)来设置树莓派GPIO引脚,参数修改成14、30、10即可。setLinuxClock()设置系统的时间,setDSclock()则是根据系统时间设置DS模块的时间,ramTest对DS模块的RAM进行测试,ds1302clockRead()从DS模块读出时间,细节处理函数这里略过。现在在examples目录下make ds1302,成功后即可使用ds1302了。
使用方法:
1)./ds1302 -rtest,测试DS1032的RAM,如果引脚连接错误GPIO设置错误则会报错:

成功则会显示OK:

2)./ds1302 -sdsc,会调用setDSclock(),将DS模块设置成系统的时间,在这之前需要把自己的时区设置成本地时区cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime,并且同步网络时间ntpdate cn.pool.ntp.org

3)现在可以从DS模块读取时间

一段时间后再读一次:

看样子DS模块已经保存了系统时间。
4)./ds1302 -slc,从DS模块读取时间来设置系统的时间

结果设置成了比本地时间慢8个小时,正好是UTC时间。
修改ds1302.c源文件,找到setDSclocl()函数,其中调用了time()来获取系统时间,而time()函数返回的是从UTC(Coordinated Universal Time)时间1970年1月1日00:00:00(称为UNIX系统的Epoch时间)到当前时刻的秒数,要想从该秒数转换成本地时间需要用localtime()函数struct tm *localtime(const time_t *clock),最后修改成如下:

删除原来的ds1302.o和ds1302,重新make ds1302。
重新执行ntpdate cn.pool.ntp.org同步网络时间,然后./ds1302 -sdsc设置DS模块的时间为本地时间,再执行./ds1302查看时钟模块的时间,这时应该就显示正确了。
5)cp ./ds1302 /usr/bin/下,并添加开机启动项
Arch下面用的是systemctl,所以需要将/usr/bin/ds1302 -slc命令加到一个service中,我是添加在了网卡启动服务中。
重启后,时间正确,则说明我们的时钟模块安装成功了。
注:本文中的代码可以通过下载wiring库然后自行修改examples/ds1302.c,也可以从我的github下载:https://github.com/hustlbj/raspberry