一、目的

        这一节我们学习如何使用合宙的ESP32 C3开发板开发DS1302T时钟模块(模块带电池),然后通过1.3寸彩色TFT显示屏模块(分辨率240*240,SPI接口,ST7789驱动芯片)来显示。

二、环境

        ESP32 C3(MicroPython v1.19.1 on 2022-06-18) + Thonny(V4.0.1) + 1.3寸 ST7789 显示屏模块 +DS1302时钟模块 + 几根杜邦线 + Win10 商业版

st7789屏幕接线方法,st7789屏幕驱动和字体请参考下文:

esp32设置时间 esp32显示时间_嵌入式硬件

DS1302T时钟模块接线方法:

esp32设置时间 esp32显示时间_嵌入式硬件_02

三、DS1302T时钟模块驱动

from machine import Pin

DS1302_REG_SECOND = (0x80)
DS1302_REG_MINUTE = (0x82)
DS1302_REG_HOUR   = (0x84)
DS1302_REG_DAY    = (0x86)
DS1302_REG_MONTH  = (0x88)
DS1302_REG_WEEKDAY= (0x8A)
DS1302_REG_YEAR   = (0x8C)
DS1302_REG_WP     = (0x8E)
DS1302_REG_CTRL   = (0x90)
DS1302_REG_RAM    = (0xC0)

class DS1302:
    def __init__(self, clk, dio, cs):
        self.clk = clk
        self.dio = dio
        self.cs = cs
        self.clk.init(Pin.OUT)
        self.cs.init(Pin.OUT)

    def _dec2hex(self, dat):
        return (dat//10) * 16 + (dat % 10)

    def _hex2dec(self, dat):
        return (dat//16) * 10 + (dat % 16)

    def _write_byte(self, dat):
        self.dio.init(Pin.OUT)
        for i in range(8):
            self.dio.value((dat >> i) & 1)
            self.clk.value(1)
            self.clk.value(0)

    def _read_byte(self):
        d = 0
        self.dio.init(Pin.IN)
        for i in range(8):
            d = d | (self.dio.value() << i)
            self.clk.value(1)
            self.clk.value(0)
        return d

    def _get_reg(self, reg):
        self.cs.value(1)
        self._write_byte(reg)
        t = self._read_byte()
        self.cs.value(0)
        return t

    def _set_reg(self, reg, dat):
        self.cs.value(1)
        self._write_byte(reg)
        self._write_byte(dat)
        self.cs.value(0)

    def _wr(self, reg, dat):
        self._set_reg(DS1302_REG_WP, 0)
        self._set_reg(reg, dat)
        self._set_reg(DS1302_REG_WP, 0x80)
    #开启
    def start(self):
        t = self._get_reg(DS1302_REG_SECOND + 1)
        self._wr(DS1302_REG_SECOND, t & 0x7f)
    #关闭
    def stop(self):
        t = self._get_reg(DS1302_REG_SECOND + 1)
        self._wr(DS1302_REG_SECOND, t | 0x80)
    #秒
    def second(self, second=None):
        if second == None:
            return self._hex2dec(self._get_reg(DS1302_REG_SECOND+1)) % 60
        else:
            self._wr(DS1302_REG_SECOND, self._dec2hex(second % 60))
    #分
    def minute(self, minute=None):
        if minute == None:
            return self._hex2dec(self._get_reg(DS1302_REG_MINUTE+1))
        else:
            self._wr(DS1302_REG_MINUTE, self._dec2hex(minute % 60))
    #时
    def hour(self, hour=None):
        if hour == None:
            return self._hex2dec(self._get_reg(DS1302_REG_HOUR+1))
        else:
            self._wr(DS1302_REG_HOUR, self._dec2hex(hour % 24))
    #工作日
    def weekday(self, weekday=None):
        if weekday == None:
            return self._hex2dec(self._get_reg(DS1302_REG_WEEKDAY+1))
        else:
            self._wr(DS1302_REG_WEEKDAY, self._dec2hex(weekday % 8))
    #天
    def day(self, day=None):
        if day == None:
            return self._hex2dec(self._get_reg(DS1302_REG_DAY+1))
        else:
            self._wr(DS1302_REG_DAY, self._dec2hex(day % 32))
    #月
    def month(self, month=None):
        if month == None:
            return self._hex2dec(self._get_reg(DS1302_REG_MONTH+1))
        else:
            self._wr(DS1302_REG_MONTH, self._dec2hex(month % 13))
    #年
    def year(self, year=None):
        if year == None:
            return self._hex2dec(self._get_reg(DS1302_REG_YEAR+1)) + 2000
        else:
            self._wr(DS1302_REG_YEAR, self._dec2hex(year % 100))
            
    #获取或设置时间
    def date_time(self, dat=None):
        if dat == None:
            return [self.year(), self.month(), self.day(), self.weekday(), self.hour(), self.minute(), self.second()]
        else:
            self.year(dat[0])
            self.month(dat[1])
            self.day(dat[2])
            self.weekday(dat[3])
            self.hour(dat[4])
            self.minute(dat[5])
            self.second(dat[6])
            
    #返回设置结果
    def ram(self, reg, dat=None):
        if dat == None:
            return self._get_reg(DS1302_REG_RAM + 1 + (reg % 31)*2)
        else:
            self._wr(DS1302_REG_RAM + (reg % 31)*2, dat)

四、示例代码1

        DS1302_clock.py

from machine import Pin,SPI
from st7789py import ST7789,color565
from ds1302 import DS1302
import vga2_8x16 as font8x16
import vga2_bold_16x32 as font16x32
import time

# 创建SPI对象
spi = SPI(1,baudrate = 60_000_000,polarity = 1,sck = Pin(2),mosi = Pin(3),miso = None)
# 创建屏幕对象
tft = ST7789(spi,240,240,reset=Pin(10,Pin.OUT), dc=Pin(6,Pin.OUT),cs = None,backlight=Pin(8),rotation=180) 
# 创建DS1302时钟对象
ds  = DS1302(clk = Pin(12), dio = Pin(18), cs = Pin(19))

# 定义时钟函数
def Time():
    # 定义一个星期列表
    week = ['Mon','Tues','Wednes','Thurs','Fri','Satur','Sun']
    #年,月,日,星期,时,分,秒
    if ds.date_time()[0] != 2023:
        # 设置DS1302时间
        ds.date_time((2023,3,24,4,21,28,20))
        tft.text(font8x16,"Initialization time    ",20,0,color565(255,0,0),color565(0,0,0))
        time.sleep(1)
        
    tft.text(font8x16,"Initialization completed",20,0,color565(0,255,0),color565(0,0,0))
    
     # year, month, mday, weekday, hour, minute, second
    date = ds.date_time()
    
    year    = date[0]
    month   = date[1]
    mday    = date[2]
    weekday = date[3]
    hour    = date[4]
    minute  = date[5]
    second  = date[6]
    
    tft.text(font8x16,"%d-%.2d-%.2d %.2d:%.2d:%.2d [%s]" % (year,month,mday,hour,minute,second,week[weekday]),14,60,color565(0,255,0),color565(0,0,0))
    tft.text(font16x32,"%.2d:%.2d:%.2d"%(hour,minute,second),50,108,color565(255,255,0),color565(0,0,0))
    
def main():
    while True:
        Time()
    
    
if __name__ == "__main__":
    main()

显示效果:

esp32设置时间 esp32显示时间_2d_03

五、上电自动运行

        我们把代码写在main.py中,代码则可以上电后自动运行。

from DS1302_clock import Time

def main():
    while True:
        Time()
     
   
if __name__ == "__main__":
    main()

六、DS1302 实时时钟模块购买

https://item.taobao.com/item.htm?spm=a1z09.2.0.0.6ea92e8dsqtsNJ&id=609527215102&_u=op01rch5634

esp32设置时间 esp32显示时间_物联网_04

https://item.taobao.com/item.htm?spm=a1z09.2.0.0.6ea92e8dsqtsNJ&id=609527215102&_u=op01rch5634          

esp32设置时间 esp32显示时间_嵌入式硬件_05

DS1302实时时钟模块

DS1302 是DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和31 字节静态RAM ,通过简单的串行接口与单片机进行通信。实时时钟/日历电路提供秒、分、时、日、周、月、年的信息,每月的天数和闰年的天数可自动调整。时钟操作可通过AM/PM 指示决定采用24 或12 小时格式。DS1302 与单片机之间能简单地采用同步串行的方式进行通信,仅需用到三个口线:(1)RST 复位(2)I/O 数据线(3)SCLK串行时钟。时钟/RAM 的读/写数据以一个字节或多达31 个字节的字符组方式通信。DS1302 工作时功耗很低保持数据和时钟信息时功率小于1mW

DS1302主要性能指标:
★ 实时时钟具有能计算2100 年之前的秒、分、时、日、星期、月、年的能力,还有闰年调整的能力
★ 31 8 位暂存数据存储RAM
★ 串行 I/O 口方式使得管脚数量最少
★ 宽范围工作电压2.0 5.5V
★ 工作电流 2.0V 时,小于300nA
★ 读/写时钟或RAM 数据时有两种传送方式单字节传送和多字节传送字符组方式
★ 8 脚DIP 封装或可选的8 脚SOIC 封装根据表面装配
★ 简单 3 线接口
★ 与 TTL 兼容Vcc=5V
★ 可选工业级温度范围-40 +85
★ 双电源管用于主电源和备份电源供应
DS1302实时时钟模块参数如下:

1.PCB为单面板,尺寸:44mm*23mm*1.6mm

2.带4个定位孔,直径3.1mm

3.备用电池为正品天球CR2032,电压3V,电流260mAh,非可充电电池。理论数据保持时间大于10年!

4.晶振32.768KHz,日本原装进口晶振,匹配电容为6pF,尺寸2*6mm

5.DS1302为8脚直插国产大芯片,芯片下面有IC座,方便更换及插拔芯片

6.模块工作电压兼容3.3V/5V,可与5V及3.3V单片机连接

7.工作温度:0°---70°

接线方法(以提供的程序为例,可以接任意IO口,在程序中修改端口定义即可):

VCC→+5V/3.3V

GND→GND

CLK→P02

DAT→P01

RST→P00

注意事项:

1. VCC与GND千万不要接反,以免烧坏芯片

2. 51单片机P0口需要接上拉电阻,如果您的单片机没有接上拉电阻,可以将数据线接到其它端口