MicroPython-On-ESP8266——时钟模块DS3231的使用方法

1. 模块DS3231介绍

1.1. 模块基本参数

DS3231是一块低成本高精度的时钟RTC芯片(模块),采集IIC总线方式通讯(从机地址为0x68),包含了电池输入端能支持断开主电源也可保持的计时功能。
芯片的实时时钟提供了秒、分、时、星期、日、月、年信息,带闰年补偿。还可以设定两个闹钟,可输出方波来驱动蜂鸣器等。
另外芯片还内置了湿度传感器,温度分辨率为0.25度。

没找到模块对应的官方网站,只从百度文库中找到了一份模块的介绍,见此地址

1.2. 芯片各寄存器地址及参数含义

从文档资料里面截取了下面这个寄存器说明表:

需要注意:

  1. 日期和时间寄存器里面将8个字节拆分开存储,低4字节存个位,高4字节存十位
  2. year那里存储的范围是0~99,所以在设置年份的时候就不能设置为2021这样的长时间格式,用21就可以了
  3. 温度用了两个字节来存,有效数据共10位,11H存储了高8位、12H在大端存储了低两位。因为温度存储要兼顾负数,所以存储值用了2的补码形式。
  4. 温度分辨率为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, I2CDS3231_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), sda=Pin(gpio_sda), freq=freq)def Date(self, dat=[]):'''读取或设置当前日期'''if dat == []:t = []t.append(str(self.year()))t.append(str(self.month()))t.append(str(self.day()))return telse:self.year(dat[0])self.month(dat[1])self.day(dat[2])def Time(self, dat=[]):'''读取或设置当前时间'''if not dat:t = []t.append(str(self.hour()))t.append(str(self.min()))t.append(str(self.sec()))return telse:self.hour(dat[0])self.min(dat[1])self.sec(dat[2])def DateTime(self, dat=[]):'''读取或设置当前日期与时间'''if dat == []:return self.Date() + self.Time()else:self.year(dat[0])self.month(dat[1])self.day(dat[2])self.hour(dat[3])self.min(dat[4])self.sec(dat[5])def _set_reg(self, reg, dat, trans_dec=True):'''写寄存器'''# 转换成寄存器需要的大小端分离格式dat = (int(dat / 10) << 4) + (dat % 10) if trans_dec else dat# 待发送数据:寄存器地址 + 设定值buf = bytearray(2)buf[0] = reg[0]buf[1] = datself.i2c.writeto(DS3231_ADDR, buf)def _get_reg(self, reg, trans_dec=True):'''读寄存器'''# 指定待读取寄存器地址self.i2c.writeto(DS3231_ADDR, reg)# 读取1位数据t = self.i2c.readfrom(DS3231_ADDR, 1)[0]if trans_dec:  # 将大小端分离的格式数据转换为正常十进制return (t >> 4) * 10 + (t % 16)else:return tdef sec(self, sec=''):if sec == '':return self._get_reg(DS3231_REG_SEC)else:self._set_reg(DS3231_REG_SEC, sec)def min(self, min=''):if min == '':return self._get_reg(DS3231_REG_MIN)else:self._set_reg(DS3231_REG_MIN, min)def hour(self, hour=''):if hour == '':return self._get_reg(DS3231_REG_HOUR)else:self._set_reg(DS3231_REG_HOUR, hour)def day(self, day=''):if day == '':return self._get_reg(DS3231_REG_DAY)else:self._set_reg(DS3231_REG_DAY, day)def month(self, month=''):if month == '':return self._get_reg(DS3231_REG_MONTH)else:self._set_reg(DS3231_REG_MONTH, month)def year(self, year=''):if year == '':return self._get_reg(DS3231_REG_YEAR)else:self._set_reg(DS3231_REG_YEAR, year)def Temperature(self):'''获取温度# t1是高8位,本来要左移两位的,因为温度分辨率还得除4,相当于不用移位了。# t2是低2位,但放置在了12H的最高位置上,所以需要右移6位(除以64),再加上分辨率因素(除4),所以t2/256就是实际值了。'''t1 = self._get_reg(DS3231_REG_TEMPM, trans_dec=False)t2 = self._get_reg(DS3231_REG_TEMPL, trans_dec=False)if t1 > 0x7F:  # 11H最高位为1代表负数return t1 - t2 / 256 - 256   # 补码简化算法,得数-256else:return t1 + t2 / 256

2.3. 封装库使用方法

from ds3231 import DS3231
ds = DS3231(gpio_scl=5, gpio_sda=4)  # 这里根据实际接线的GPIO管脚来修改
ds.DateTime()  # 获取日期、时间
ds.DateTime([21, 8, 18, 12, 0, 0])  # 设置日期时间(注意用短年份)
ds.Time([12, 1, 0])  # 仅设置时间
ds.Temperature()  # 获取当前温度

3. 实验:简易时钟与温湿度显示器

3.1. 需求

  • 将日期时间显示到oled屏幕上
  • 时钟每天联网校准一次
  • 同步显示当前环境温湿度

3.2. 多I2C从机的接线方式

我们这里ESP8266作为主机来使用,上面RTC时钟是个I2C从机,现在要将获取到的时间显示在oled屏幕上,我们之前用过的SSD1306驱动的0.96寸oled屏幕也是I2C总线协议。那这里就使用到了一主多从的模式,按下图所示的串接方式连接:

因为咱们使用的各个模块内部都已经封装好了时钟线和数据线连接上拉电阻到正极电源线,我们就不用管这里了,只需要按照VIN/GND/SCL/SDA标识,将各模块串接起来。

设备清单:

  • 主机:ESP8266
  • 从机1:DS3231时钟模块
  • 从机2:AHT10温湿度模块
  • 从机3:SSD1306显示屏

接线实物图:

3.3. 实验分析与代码

SSD1306驱动在micropython已经内置了,DS3231驱动见上,ATH10驱动咱们前面文章已经分析和做出来了,再加上前面也学习了在boot.py中配置wifi,这里实验其实就容易了,把各个驱动库引入进来,使用urequests.py定期获取网络时间来校准,然后定义一个Timer定时器来刷新oled屏幕就可以啦。

直接上完整代码,不拆解介绍了。

import urequests
import json
import time
from machine import Pin,I2C
from ds3231 import DS3231
from aht import AHT10
from ssd1306 import SSD1306_I2C
from machine import Timer# 初始化各个模块
i2c = I2C(scl=Pin(5), sda=Pin(4), freq=100000)
ds = DS3231(i2c=i2c)
aht = AHT10(i2c)
display = SSD1306_I2C(128,64,i2c,addr=60)NOW_DATE = ''# 网络校时
def reset_time():url = 'http://quan.suning.com/getSysTime.do'res=urequests.get(url).textprint(res)j=json.loads(res)t2_date = j['sysTime2'].split()[0] #日期t2_time = j['sysTime2'].split()[1] #时间global dsds.Date([int(x) for x in t2_date[2:].split('-')])   #设置初始日期年、月、日ds.Time([int(x) for x in t2_time.split(':')])   #设置初始时间时、分、秒# 获取待显示值
def get_content():global NOW_DATE# 读取时钟模块的日期和时间,拼接成正常的时间格式_date = '20'+'-'.join(ds.Date())_time = ':'.join(ds.Time())# 读取AHT10的温湿度_,_temperature,_humidity = aht.measure(),aht.temperature(),aht.humidity()# 判定是否需要校准时间,每天0时触发if NOW_DATE != _date:reset_time()NOW_DATE = _datereturn _date,_time,_temperature,_humidity# 刷新屏幕
def flash_display(t):global display_date,_time,_temperature,_humidity = get_content()display.fill(0)  # 清屏display.text(_date, 3, 5)display.text(_time, 3, 16)display.text(str(_temperature) + " 'c", 3, 27)display.text(str(_humidity) + " %", 3, 38)display.show()tim = Timer(-1)
tim.init(period=1000, mode=Timer.PERIODIC, callback=flash_display)

看看效果:

MicroPython-On-ESP8266——时钟模块DS3231的使用方法相关推荐

  1. 张高兴的 Windows 10 IoT 开发笔记:RTC 时钟模块 DS3231

    原文:张高兴的 Windows 10 IoT 开发笔记:RTC 时钟模块 DS3231 GitHub:https://github.com/ZhangGaoxing/windows-iot-demo/ ...

  2. 树莓派4b设置RTC时钟模块DS3231

    1 检查环境 由于在工程实现中,我发现树莓派的ip设置有问题,居然连不上外网.以及网络下载缓慢的问题,针对这两点,参考博客如下: IP设置检查:https://blog.csdn.net/taw199 ...

  3. ESP32连接DS3231实时时钟(RTC)的方法

    在本篇文章中,我们将学习如何将RTC实时时钟模块DS3231连接到ESP32开发板和0.96英寸I2C OLED显示屏.我们将使用DS3231实时时钟模块跟踪正确的时间和日期,在OLED显示屏上进行显 ...

  4. ESP8266 WiFi模块如何联网?

    一.ESP8266系列模块是什么? ESP8266系列无线模块是一个经济高效的WIFI SOC模块,支持标准IEEE802.11b/g/n协议,内置完整的TCP/IP协议栈. 用户可以使用此系列模块向 ...

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

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

  6. DIY一块DS3231的高精度时钟模块,让时钟DS3231/DS1302自动识别

    [DIY]DIY一块DS3231的高精度时钟模块,让时钟DS3231/DS1302自动识别 水晶城堡在设计之初,采用全直插设计理念,保证玩家在自行DIY的过程中,不会因为焊接贴片元器件而烦恼.所以水晶 ...

  7. 基于DS3231时钟模块的stm32 Hal库程序,源码

    关于DS3231模块介绍我在我的博客基于DS3231时钟模块的stm32 程序,源码中有介绍 ,大家可以自己看下.我这篇直接讲HAL的代码. 一.配置IO /**/****************** ...

  8. 【Arduino】ESP8266DS1302时钟模块

    前言 ​ ESP8266基于Arduino IDE的DS1302时钟模块使用,的过程记录.DS1302时钟模块就不详细介绍了,网上还是有很多资料的,这里只说如何快速上手. 下载文件 代码理解 实际测试 ...

  9. MicroPython实现ESP8266 控制电子墨水屏(SPI)

    最近15元淘了一块电子墨水屏,合宙家的产品.看评论是可以用微雪的代码驱动,于是找了微雪的代码,顺便翻了下读取BMP的代码,做了个小DEMO玩玩.手头几个ESP32都用了,只好翻了个旧的8266去写代码 ...

最新文章

  1. 【深度学习】基于Pytorch多层感知机的高级API实现和注意力机制(三)
  2. unity3d优化总结篇
  3. python心理学实验程序_psychopy coder模式编写心理试验程序 字符程序和记录反应时...
  4. wpf 可以取消的单选checkbox
  5. Java面向对象(18)--final关键字使用
  6. Randomize select algorithm 随机选择算法
  7. 3399 mysql_手动安装 mysql
  8. 12.C++ string 操作
  9. 【Jenkins】Jenkins : Mac中Jenkins的停止和启动
  10. 学了python做什么自由职业者_我又有一位程序员朋友成了自由职业者
  11. Linux 文件系统(三)---dup和fork函数执行后的文件情况
  12. Java使用JNA调用SWMM模型的DLL
  13. MTK6589百度云ROM移植教程
  14. 8086CPU标志位
  15. CodRED: A Cross-Document Relation Extraction Dataset for Acquiring Knowledge in the Wild
  16. OCR:ECCV 2020 论文了解
  17. 微信小程序:全局状态管理mobx-miniprogram、mobx-miniprogram-bindings
  18. Skip List(跳表)
  19. 【有奖征集】地球一小时:让万物感受你的爱,用H5表达你的心!
  20. LabVIEW编程LabVIEW开发WT210 WT230数字功率计例程与相关资料

热门文章

  1. python xlrd模块下载_python xlrd模块
  2. 0052-【科学可视】-纪录片-恐龙坑的秘密
  3. java 实现签到功能及数据库表设计
  4. 臀大肌(05):跪撑屈膝抬腿
  5. 又又又获得信通院产品认证
  6. 超顺磁氧化铁纳米颗粒/CoFe2O4@MnFe2O4/磁性材料CoFe2O4(443 W/g)/氧化铁纳米环
  7. 学习SCI论文绘制技巧(F)
  8. Linux 中的 usermod 命令
  9. 提高工作效率的8个小方法
  10. 通达信分时图数据结构