我一开始以为树莓派Pico没有时钟模块,但查了相关资料,Pico仍有基本的RTC支持,只不过它在掉电的时候,无法再维护精确的时间。

这里的RTC,是实时时钟(Real Time Clock)的缩写,MicroPython里也提供了RTC标准类的支持,用datetime()函数可以获取8元组的时间数据。

import machine
rtc_pico = machine.RTC()
print(rtc_pico.datetime())

8元组是指(year, month, day, weekday, hours, minutes, seconds, subseconds),其中weekday表示星期几,从0到6,值得注意的是0表示星期一,6表示星期日,符合ISO8601国际标准定义。

subseconds与硬件相关,Pico不支持这个数据。

给datetime()函数传递8元组的参数,可以设置Pico的时间。下面的代码把时间设置为双十一的零点(周四),注意必须是两层括号。

rtc_pico.datetime((2021, 11, 11, 3, 0, 0, 0, 0))

我的Pico连接Windows的USB,用Thonny调试程序,datetime会自动与电脑的时间同步,我现在还不清楚这是Thonny的功能,还是MicroPython的功能。

Pico如果不连网,得到的时间不是很准确,只能用于相对时间参考。如果想获得更加准确的时间,则要外购实时时钟模块,我在网上搜索时钟模块,常见的有三种型号:DS1302、DS1307和DS3231。

DS3231好像更加精确,但价格贵不少,我就锁定在前2种型号了。

DS1302和DS1307的精度差不多,区别主要在于通讯接口上,DS1302总共要5根线,而DS1307可以用标准的I2C协议,只需要连4根线,为了编程方便还省一根线,还可以离线保存56个字节的信息(你没看错,只有56个字节),我就下单买了DS1307,某多平台到手价3.8元,还包邮。DS1307模块到货后,它的模样是这样的。

商家一般不焊接排针,需要自己动手,这个模块在一侧有5根针,另一侧有7根针,我只用I2C编程,就只焊了5根针,足够用了。第一次用烙铁,焊锡非常不均匀,但也成功了。

5根针只用到4根,分别是VCC、GND、SDA和SCL。
1)GND不用多说了,接地
2)VCC,模块的用户手册说要接5V电压,我接3.3V也能正常工作
3)SDA/SCL接GP16/GP17

在接5V还是3.3V的时候,还纠结了好一阵子。网上有人说接5V电压后,SDA/SCL出来的信号也是5V,而Pico工作电压为3.3V,可能会损坏Pico板子。但也有人说,DS1307这个模块上已经接好了上拉电阻,放心接SDA/SCL就行。

我就先接3.3V试试,数据获取稳定,后来改接5V电压也正常,实际连接图。

DS1307的通讯协议,可以暂时不用了解,别人已经写好类库了,只有70行,直接拿来用即可,请把文件名保存为 ds1307.py 。

from micropython import constDATETIME_REG = const(0) # 0x00-0x06
CHIP_HALT    = const(128)
CONTROL_REG  = const(7) # 0x07
RAM_REG      = const(8) # 0x08-0x3Fclass DS1307(object):"""Driver for the DS1307 RTC."""def __init__(self, i2c, addr=0x68):self.i2c = i2cself.addr = addrself.weekday_start = 1self._halt = Falsedef _dec2bcd(self, value):"""Convert decimal to binary coded decimal (BCD) format"""return (value // 10) << 4 | (value % 10)def _bcd2dec(self, value):"""Convert binary coded decimal (BCD) format to decimal"""return ((value >> 4) * 10) + (value & 0x0F)def datetime(self, datetime=None):"""Get or set datetime"""if datetime is None:buf = self.i2c.readfrom_mem(self.addr, DATETIME_REG, 7)return (self._bcd2dec(buf[6]) + 2000, # yearself._bcd2dec(buf[5]), # monthself._bcd2dec(buf[4]), # dayself._bcd2dec(buf[3] - self.weekday_start), # weekdayself._bcd2dec(buf[2]), # hourself._bcd2dec(buf[1]), # minuteself._bcd2dec(buf[0] & 0x7F), # second0 # subseconds)buf = bytearray(7)buf[0] = self._dec2bcd(datetime[6]) & 0x7F # second, msb = CH, 1=halt, 0=gobuf[1] = self._dec2bcd(datetime[5]) # minutebuf[2] = self._dec2bcd(datetime[4]) # hourbuf[3] = self._dec2bcd(datetime[3] + self.weekday_start) # weekdaybuf[4] = self._dec2bcd(datetime[2]) # daybuf[5] = self._dec2bcd(datetime[1]) # monthbuf[6] = self._dec2bcd(datetime[0] - 2000) # yearif (self._halt):buf[0] |= (1 << 7)self.i2c.writeto_mem(self.addr, DATETIME_REG, buf)def halt(self, val=None):"""Power up, power down or check status"""if val is None:return self._haltreg = self.i2c.readfrom_mem(self.addr, DATETIME_REG, 1)[0]if val:reg |= CHIP_HALTelse:reg &= ~CHIP_HALTself._halt = bool(val)self.i2c.writeto_mem(self.addr, DATETIME_REG, bytearray([reg]))def square_wave(self, sqw=0, out=0):"""Output square wave on pin SQ at 1Hz, 4.096kHz, 8.192kHz or 32.768kHz,or disable the oscillator and output logic level high/low."""rs0 = 1 if sqw == 4 or sqw == 32 else 0rs1 = 1 if sqw == 8 or sqw == 32 else 0out = 1 if out > 0 else 0sqw = 1 if sqw > 0 else 0reg = rs0 | rs1 << 1 | sqw << 4 | out << 7self.i2c.writeto_mem(self.addr, CONTROL_REG, bytearray([reg]))

开始写主程序了:

import machine
import ds1307rtc_pico = machine.RTC()
#rtc_pico.datetime((2021, 11, 11, 3, 0, 0, 0, 0))
print("系统时间:", rtc_pico.datetime())i2c = machine.I2C(0, sda = machine.Pin(16), scl = machine.Pin(17), freq = 100000)
print("ds1307 I2C 地址:", machine.I2C.scan(i2c))
rtc_ds1307 = ds1307.DS1307(i2c)
print("DS1307时间:", rtc_ds1307.datetime())

DS1307的I2C扫描地址有2个: [80, 104],一开始比较纳闷,一个芯片应该就只有一个地址的。后来才知道,DS1307模块上一般会集成AT24C32N EEPROM,它的地址是80,而DS1307芯片的地址是104。

刚拿到的DS1307可能时间不正确,需要自己设定一下,用下面的函数。

def update_time():str_time = input("请输入【年 月 日 星期 时 分 秒】:")if str_time == '': return givenTime = tuple(map(int, tuple(str_time.split(' '))))print(givenTime)rtc_ds1307.datetime(givenTime)

比如,你输入“2021 11 27 5 19 18 10”,一共7个数,中间用空格隔开,update_time()函数一般只调用一次,设置好时间后,一般就不用管了,它自身带的CR2032纽扣电池用于给它持续供电,声称10年不用换电池。

最后我们再来看看DS1307的关键特性:

DS1307 是美国DALLAS公司推出的I2C总线接口实时时钟芯片,它可独立于CPU工作,不受CPU主晶振及其电容的影响,且计时准确,月累积误差一般小于10秒。芯片还具有主电源掉电情况下的时钟保护电路,DS1307的时钟靠后备电池维持工作,拒绝CPU对其读出和写入访问。同时还具有备用电源自动切换控制电路,因而可在主电源掉电和其它一些恶劣环境场合中保证系统时钟的定时准确性。具有产生秒、分、时、日、月、年等功能,且具有闰年自动调整功能。同时,DS1307 芯片内部还集成有56字节掉电保存的静态RAM,可用于保存一些关键数据。

DS1307是一款低功耗,具有56字节非失性RAM的全BCD码时钟日历实时时钟芯片,地址和数据通过两线双向的串行总线的传输,芯片可以提供秒,分,小时等信息,每一个月的天数能自动调整。并且有闰年补偿功能。AM/PM 标志位决定时钟工作于24小时或12小时模式,芯片有一个内置的电源感应电路,具有掉电检测和电池切换功能。

官方Datasheet上的描述是:

  • Real time clock counts seconds, minutes, hours, date of the month, month, day of the week, and year with leap year compensation valid up to 2100
  • 56 byte nonvolatile RAM for data storage
  • 2-wire serial interface
  • Programmable squarewave output signal
  • Automatic power-fail detect and switch circuitry
  • Consumes less than 500 nA in battery backup mode with oscillator running
  • Optional industrial temperature range -40°C to +85°C
  • Available in 8-pin DIP or SOIC
  • Recognized by Underwriters Laboratory

现在拿出我的LCD1602,可以做一个实时时钟,SDA/SCL接GP2/GP3,实际连线图。


每秒在LCD上刷新日期、时间即可。

import pico_i2c_lcd
i2c_lcd = machine.I2C(1, sda=machine.Pin(2), scl=machine.Pin(3), freq=400000)
I2C_ADDR = i2c_lcd.scan()[0]
lcd = pico_i2c_lcd.I2cLcd(i2c_lcd, I2C_ADDR, 2, 16)while True:now = rtc_ds1307.datetime()lcd.move_to(0, 0)lcd.putstr("{:04d}-{:02d}-{:02d}\n".format(now[0], now[1], now[2]))lcd.putstr("{:02d}:{:02d}:{:02d}".format(now[4], now[5], now[6]))lcd.move_to(12, 1)lcd.putstr(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'][now[3]])utime.sleep(1)

另外,我在研究56个字节的信息时,发现DS1307模块里还带着AT24C32N EEPROM这个小芯片,可以离线保存32K(是32768个二进制位,4096字节)的数据,下一篇再研究它。

参考文章:

https://www.iotstarters.com/diy-digital-clock-with-rtc-ds1307-and-raspberry-pi-pico/

https://en.wikipedia.org/wiki/ISO_8601

https://docs.micropython.org/en/latest/library/machine.RTC.html#machine-rtc

https://github.com/mcauser/micropython-tinyrtc-i2c

推荐阅读:
树莓派Pico开发系列文章

树莓派54/100 - Pico连接DS1307时钟模块,做个实时数字钟相关推荐

  1. 树莓派32/100 - Pico连接温湿度传感器

    DHT11是一个廉价的温湿度传感器,它只有1平方厘米大小,加上一个小转接板,也没多大,接线也简单,除了正负极之外,只需再接一根信号线. 我一开始以为它要用到ADC,所以把信号线接到了Pico的GP26 ...

  2. ardino DS1307时钟模块

    ardino开发版 x1 DS1307时钟模块x1 接线: VCC-5V GND-GND(负极) CLK-SCL DAT-SDA 代码: #include <RtcDS1307.h> #i ...

  3. 用四位数码管和DS3231时钟模块做车载电子时钟

    用四位数码管和DS3231时钟模块做车载电子时钟 本来咱车上收音模块上是有一个时钟的,但换了导航以后,发现时钟不好用了:主界面上有时钟,但位置太靠左侧,俺的大手握方向盘刚好挡住视线,而且在播放音乐时, ...

  4. 树莓派22/100 - Pico入侵检测报警器

    入侵检测器 这一节需要一个HC-SR501的小元件,大概3~5元钱,某多非常给力,5元钱的东西也包邮. 中文说明书称之为人体感应模块,产品介绍是这样说的: HC-SR501是基于红外线技术的自动控制模 ...

  5. Tiny RTC DS1307 时钟模块 完整代码(Arduino)及一些要注意的地方

    这个东西其实是可以的,就是没什么技术支持,有很多细节会有坑,我搞了十几天(期间还花了一周来学习焊接)才完全成功的,期间我很恼火,觉得就是买了个垃圾,甚至想扔掉这个2块钱的东西.于是我又买了一个,结果两 ...

  6. 树莓派65/100 - Pico W初体验,点亮板载的LED灯

    有一段时间没有折腾树莓派Pico,最近发现它又出新品了,树莓派Pico W,可以通过WIFI连接互联网了. Pico W的产品小册子可以从这里下载. 这篇文章介绍了Pico 和 Pico W的区别. ...

  7. 树莓派53/100 - Pico小车v4版本,蓝牙、陀螺仪之后,再加上OLED显示屏

    我的树莓派Pico小车接上了蓝牙.陀螺仪之后,今天再把OLED显示屏接上,OLED的电源是3.3V,SDA/SCL分别接GP4/GP5,代码增加一些.对于OLED的SSD1306显示模块不熟悉的,可以 ...

  8. 树莓派24/100 - Pico与1602显示屏相连输出2行文本

    前面用8根引脚实现了七段数码管的显示,你没看错,不算正极的那根线,还用了8根连线,分别接到了Pico的8个GPIO接口上. 如果想显示更多的内容,这种办法肯定是不行了,Pico虽然有20多个GPIO接 ...

  9. 树莓派40/100 - Pico控制WS2812B,一根信号线实现多种LED灯光效果(1)

    从某多平台花了15元钱买了一米长的WS2812B彩灯,用于我的Pico编程试验,这种灯的神奇之处在于只需一根信号线,能够控制串联在一起的30颗LED灯珠(好像能长达1024颗灯),实现各种彩灯效果. ...

  10. 树莓派26/100 - Pico控制RGB三色灯

    RGB三色LED灯,相当于把三种颜色的LED灯组合在一起,它有4条腿,最长的那条腿是阴极或阳极,根据这个灯是共阴的,还是共阳的而定. 与以前接LED灯的情况类似,不过这次要接三个电阻,我把它们分别接到 ...

最新文章

  1. luogu P1345 [USACO5.4]奶牛的电信Telecowmunication(建图技巧 - “割点”模板 、最小割)
  2. 正式入住博客园----附07年写的短评,虽然稚嫩但已实现,那年我大三。
  3. 极简设计如何实现(一)
  4. springmvc静态资源;mvc:default-servlet-handler后Controller失效
  5. node-sass安装失败解决方法
  6. 如何在WCF中用TcpTrace工具查看发送和接收的SOAP消息
  7. asp.net(c#)两时间段每天是星期几,周几(时间段日历显示)的问题解
  8. 搭建SpringMVC+Hibernate4+Spring3+Ajax+Maven项目(二)
  9. 包的引入(base版本)
  10. windows虚拟机_Windows电脑体验macOS,装黑苹果?虚拟机也可以的——VMWare篇
  11. Django 学习第九天——请求与响应
  12. 改变form里面input,textarea.select等的默认样式
  13. 多策略调和的布谷鸟搜索算法
  14. 应用ruby打造个性化的有道单词本 (二)
  15. 五款服务器配置管理工具
  16. Log4j漏洞及解决方案,亲测
  17. 时间序列的特征工程——针对Hurst指数的Python计算
  18. 什么是rich text,富文本?富文本有什么优势?
  19. 乒乓球十一分制比赛规则_乒乓球11分制竞赛规则简单讲解
  20. 宝塔面板的数据库地址配置

热门文章

  1. [VB.NET]请教一个如何对姓名进行同音字查询?
  2. 认知无线电网络中的频谱切换理论
  3. 设计三极管放大电路有哪些技巧?尤其是假设
  4. java excel 单元格换行_单元格里的文字换行_ExcelHome - 全球极具影响力的Excel门户,Office视频教程培训中心...
  5. PDG转图像、PDF的若干方法
  6. esp32获取网络时间
  7. Javascript模块化编程 (附WebTrends的dcsMultiTrack方法浅述)
  8. 雷达的L、S、C、X波段是什么
  9. 【转载】C# ListView控件的一些用法
  10. 惠普HP Designjet 5100 打印机驱动