MicroPython-On-ESP8266——时钟模块DS3231的使用方法
1. 模块DS3231介绍
1.1. 模块基本参数
DS3231是一块低成本高精度的时钟RTC芯片(模块),采集IIC总线方式通讯(从机地址为0x68),包含了电池输入端能支持断开主电源也可保持的计时功能。
芯片的实时时钟提供了秒、分、时、星期、日、月、年信息,带闰年补偿。还可以设定两个闹钟,可输出方波来驱动蜂鸣器等。
另外芯片还内置了湿度传感器,温度分辨率为0.25度。
没找到模块对应的官方网站,只从百度文库中找到了一份模块的介绍,见此地址
1.2. 芯片各寄存器地址及参数含义
从文档资料里面截取了下面这个寄存器说明表:
需要注意:
- 日期和时间寄存器里面将8个字节拆分开存储,低4字节存个位,高4字节存十位
- year那里存储的范围是0~99,所以在设置年份的时候就不能设置为2021这样的长时间格式,用21就可以了
- 温度用了两个字节来存,有效数据共10位,11H存储了高8位、12H在大端存储了低两位。因为温度存储要兼顾负数,所以存储值用了2的补码形式。
- 温度分辨率为0.25度,也就是得出的10位有效数值再乘0.25(或者除4),就是最终温度
1.3. DS3231寄存器读写方式
1.3.1. 从设备接收模式(DS3231写模式)
官方文档对写寄存器方式的描述为:
通过SDA和SCL接收串行数据和时钟。收到每个字节后,发送应答位。START和STOP条件作为串行传输的开始和结束。
在收到从设备地址和传输方向位之后,由硬件实现地址识别。
(1). 主设备产生START条件后,从设备地址字节是收到的第一个字节。从设备地址字节包括7位DS3231地址,即1101000,接着是传输方向位(R/W)。该位为0,表示写操作。在收到并译码从设备地址字节后,DS3231向SDA发出应答信号。
(2). 在DS3231应答从设备地址+写位之后,主设备发送一个字节地址至DS3231。这用于设定DS3231的寄存器指针,DS3231对该传输做出应答。
(3). 主设备随后可以发送0或者更多字节的数据,DS3231应答每个收到的字节。每个数据字节传输完后,寄存器指针自动递增。主设备产生STOP条件以终止数据写人。
抛开I2C总线传输方向和应答不讲(因为micropython已经封装好了),单纯看数据流的话,写寄存器就很简单了。从主机(咱们的esp8266模块)向从机(ds3231模块)依次向送的数据流为:“从机I2C地址0x68
+ 寄存器地址
+ 设定值
”。
1.3.2. 从设备发送模式(DS3231读模式)
官方文档对读取寄存器数据方式的描述为:
接收和处理首字节的方式与从设备接收模式相同。但是,在这种模式下,方向位指示的传输方向是相反的。DS3231向SDA发送串行数据,并由SCL输入串行时钟。START和STOP条件作为串行传输的开始和结束。在收到从设备地址和方向位后,由硬件进行地址识别。
(1). 主设备产生START条件后,从设备地址字节是收到的首字节。从设备地址字节包括7位DS3231地址,即1101000,接下来是方向位(R/W)。该位为1,表示读操作。在接收和译码从设备地址字节后,DS3231向SDA发出应答信号。
(2). 然后DS3231开始发送数据,并从寄存器指针所指向的寄存器地址开始。如果在启动读模式之前未写寄存器指针,所读取的首地址是最后存储的寄存器指针值。DS3231必须收到非应答信号以结束读操作。
读寄存器的话,重点在描述里面的第(2)点。原本主机(esp8266)向从机发送地址后,从机就会应答数据了,但是我们要读取的是指定寄存器的值呀,不能乱给数据。按后面“所读取的首地址是最后存储的寄存器指针值”,这就意味着,咱们要给从机指定寄存器发送个寂寞,然后再从从机那里读取指定长度的值,从机这时会在前面刚被写了个寂寞的地方开始回数据给主机。
1)主机向从机指定地址存数据,只指定地址不用发数据。主机发送 从机I2C地址0x68
+ 寄存器地址
2)主机读取从机指定长度的缓存值
(这里咱们只读取一位,因为底层要单独封装年、月、日、时、分、秒等)
2. DS3231驱动库封装
2.1. ds3231寄存器的读写
按照1.3.节文档对寄存器读取的描述和个人的理解,咱们使用micropython对ds3231的寄存器进行读写可以总结为下述方法。
写寄存器
buf = bytearray(2)
buf[0] = reg_addr # eg. 0x00
buf[1] = 'int-data-to-set' # eg. 59
i2c.writeto(ds3231_addr, buf)
读寄存器
i2c.writeto(ds3231_addr, reg_addr)
buf = i2c.readfrom(ds3231_addr, 1)
2.2. ds3231封装库
按照上面文档中对寄存器读取方式的说明,我们使用micropython的I2C总线方式对模块进行封装。
目前我们只测试时钟的设置与获取、温度获取,其他闹钟设置、方波输出和复位设置等先不做研究。
ds3231库,主要参考了别人家使用pyboard时封装的库,初始化方法和函数名等少部分地方做了修改。
from micropython import const
from machine import Pin, I2C
DS3231_ADDR = const(0x68)
DS3231_REG_SEC = b'\x00'
DS3231_REG_MIN = b'\x01'
DS3231_REG_HOUR = b'\x02'
DS3231_REG_WEEKDAY = b'\x03'
DS3231_REG_DAY = b'\x04'
DS3231_REG_MONTH = b'\x05'
DS3231_REG_YEAR = b'\x06'
DS3231_REG_A1SEC = b'\x07'
DS3231_REG_A1MIN = b'\x08'
DS3231_REG_A1HOUR = b'\x09'
DS3231_REG_A1DAY = b'\x0A'
DS3231_REG_A2MIN = b'\x0B'
DS3231_REG_A2HOUR = b'\x0C'
DS3231_REG_A2DAY = b'\x0D'
DS3231_REG_CTRL = b'\x0E'
DS3231_REG_STA = b'\x0F'
DS3231_REG_OFF = b'\x10'
DS3231_REG_TEMPM = b'\x11'
DS3231_REG_TEMPL = b'\x12'
class DS3231(object):
def __init__(self, gpio_scl=5, gpio_sda=4, freq=100000, i2c=None):
# 初始化i2c总线,可以外部传入也可以指定管脚在内部创建
self.i2c = i2c or I2C(scl=Pin(gpio_scl