【RTC PCF8563 micrpython 程序与调试经验】

PCF8563 是低功耗的 CMOS 实时时钟/日历芯片

本文用到ESP32 WROOM模块,文中假定你熟悉用 Micropython开发该模块的方式。

应用中需要知道当前的年份是哪一年,想了多种方案。最后,还是决定用一款低功耗的实时时钟/日历芯片来实现。选型过程中,看到有人说,达拉斯DS1302等产品,对电源电压有特别的要求,要十分注意,否则可能读不到数据。故而,本人避开达拉斯产品,选用了PCF8653这款芯片(模块)。

在这里插入图片描述

程序设计和应用过程

我的主控芯片是EPS32 WROOM,用Micropython当作开发平台。 EPS32 WROOM是一个紧凑的电子电路板,在裸机上运行MicroPython,就有了一个低级Python操作系统, MicroPython旨在尽可能与普通Python兼容,所以编程很方便。

  1. 下载pcf8653.py源程序
    PCF8653这款芯片是IIC接口,虽然MicroPython有现成的IIC machine函数,但要编程序代码,还是要充分理解IIC的工作原理才行,不然,会出现意想不到的情况来。偷懒的我就在网上搜,看有没有现成的程序代码。还果真有,感谢这位老兄的奉献。链接如下:
    https://www.micropython.org.cn/wiki/doku.php?id=micropython:mpy-lib:misc:pcf8563%E5%AE%9E%E6%97%B6%E6%97%B6%E9%92%9F
    在这里插入图片描述
    输入以上网址,点击在上图红箭头处,就可下载源程序了。紧接着应是测试代码能不能用了。

  2. 把该程序传ESP32模块中

  3. 编制测试程序
    主程序main.py 代码如下

from machine import UART,Pin,Timer,WDT,I2C,SoftI2C
import time
BoardLed=Pin(2,Pin.OUT)           #create LED object
#---------------------------------------------------------
#定时器中断服务函数
def tim0_handle_callback(tim0): 
    BoardLed.value(not BoardLed.value())  
    
#开启定时器0中断,每隔on_ms触发一次
def SetLedStatus(on_ms):
    tim0 = Timer(0)         #创建定时器对象 tim0~3 共四个类
    #周期性模式 最小单位为ms
    tim0.init(period=on_ms, mode=Timer.PERIODIC, callback = tim0_handle_callback)   
    
try:
    #i2c0 = SoftI2C(sda=Pin(5),scl=Pin(4),freq=400000)
    i2c0 = I2C(0)               # 默认的i2c0:scl:18 sda:19  默认的i2c1:scl:25 sda:26
    addr0 = i2c0.scan()         #扫描I2C地址,以列表的形式返回设备地址
    print("address:", addr0)    #打印I2C设备地址
    SetLedStatus(1000)         #调用,指示程序在运行
    Rtc8563 = PCF8563(i2c = i2c0)     #实例化
  #设定PCF8653的日期、时间
    Rtc8563.year(year = 2023)
    Rtc8563.month(month = 12)
    Rtc8563.day(day = 9)
    Rtc8563.weekday(weekday=6)
    Rtc8563.hour(hour = 19)
    Rtc8563.minute(minute = 11)
     #看读取情况 
    while True:
        print("time: ",Rtc8563.datetime())
        time.sleep(1)    #延时1秒后,再读RTC
  
except:
    print("mainprog err,exit")

  1. 当然还有一个boot.py程序如下:
# This file is executed on every boot (including wake-boot from deepsleep)
#import esp
#esp.osdebug(None)
#import webrepl
#webrepl.start()
exec(open('pcf8563.py').read(),globals())
exec(open('main.py').read(),globals())
  1. 运行情况
    在这里插入图片描述
    每延时1秒,读到的内容

硬件连接
在这里插入图片描述

调试经验:遇到的问题

本示例基于Thonny平台开发。
本想用软件I2C总线,自定义相关引脚,这样的话,设计电路图方便一些。有资料也介绍说:软件 I2C(使用 bit-banging)适用于所有具有输出输入功能的引脚,并通过machine.SoftI2C类访问:
例如,引用方式如下:
from machine import SoftI2C
i2c = SoftI2C(scl=Pin(22),sda=Pin(23),freq=100000)
但这样不行,不能读到RTC数据
我改用默认I2C0的引脚来调试,ESP32有两个标识符为0和1的默认I2C硬件外设。下面给出了默认值。

           I2C(0)        I2C(1)
    SCL   	IO18	       IO25
    SDA	    IO19	       IO26

默认的I2C引脚引用方法:
from machine import Pin, I2C
i2c = I2C(0) # 默认的i2c0:scl:18 sda:19
i2c = I2C(1) # 默认的i2c1:scl:25 sda:26
等价于:
from machine import Pin, I2C
i2c = I2C(scl=Pin(18), sda=Pin(19),freq=400000)
i2c = I2C(scl=Pin(25), sda=Pin(26),freq=400000)

待调试出RTC数据后,再来尝试一下其他的引脚,即也可以自定义切换指定引脚
from machine import I2C,
i2c = I2C(1, scl=Pin(5), sda=Pin(4), freq=400000)

再次感谢提供pcf8653.py源程序的网友,这个程序完全可用

pcf8653.py代码我复制如下,以便引用

"""
    PCF8563 RTC drive
    Author: shaoziyang
    Date:   2021.1
    http://www.micropython.org.cn
"""
from micropython import const
PCF8563_I2C_ADDRESS  = const(81)
PCF8563_REG_CTRL1    = const(0)
PCF8563_REG_CTRL2    = const(1)
PCF8563_REG_SECOND   = const(2)
PCF8563_REG_MINUTE   = const(3)
PCF8563_REG_HOUR     = const(4)
PCF8563_REG_WEEKDAY  = const(6)
PCF8563_REG_DAY      = const(5)
PCF8563_REG_MONTH    = const(7)
PCF8563_REG_YEAR     = const(8)

class PCF8563():
    def __init__(self, i2c):
        self.i2c = i2c
        self.tb = bytearray(1)
        self.rb = bytearray(1)
        self.buf = bytearray(7)
        self.DT = [0] * 8
    # set reg
    
    def	setReg(self, reg, dat):
        self.tb[0] = dat
        self.i2c.writeto_mem(PCF8563_I2C_ADDRESS, reg, self.tb)

    # get reg
    def	getReg(self, reg):
        self.i2c.readfrom_mem_into(PCF8563_I2C_ADDRESS, reg, self.rb)
        return self.rb[0]


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

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

    def year(self, year = None):
        if year == None:
            return self.HexToDec(self.getReg(PCF8563_REG_YEAR)) + 2000
        else:
            self.setReg(PCF8563_REG_YEAR, self.DecToHex(year%100))

    def month(self, month = None):
        if month == None:
            return self.HexToDec(self.getReg(PCF8563_REG_MONTH)%32)
        else:
            self.setReg(PCF8563_REG_MONTH, self.DecToHex(month%13))

    def day(self, day = None):
        if day == None:
            return self.HexToDec(self.getReg(PCF8563_REG_DAY)%64)
        else:
            self.setReg(PCF8563_REG_DAY, self.DecToHex(day%32))

    def weekday(self, weekday = None):
        if weekday == None:
            return self.HexToDec(self.getReg(PCF8563_REG_WEEKDAY)%8)
        else:
            self.setReg(PCF8563_REG_WEEKDAY, self.DecToHex(weekday%8))

    def hour(self, hour = None):
        if hour == None:
            return self.HexToDec(self.getReg(PCF8563_REG_HOUR)%64)
        else:
            self.setReg(PCF8563_REG_HOUR, self.DecToHex(hour%24))

    def minute(self, minute = None):
        if minute == None:
            return self.HexToDec(self.getReg(PCF8563_REG_MINUTE)%128)
        else:
            self.setReg(PCF8563_REG_MINUTE, self.DecToHex(minute%60))

    def second(self, second = None):
        if second == None:
            return self.HexToDec(self.getReg(PCF8563_REG_SECOND)%128)
        else:
            self.setReg(PCF8563_REG_SECOND, self.DecToHex(second%60))


    def datetime(self, DT=None):
        if DT == None:
            self.i2c.readfrom_mem_into(PCF8563_I2C_ADDRESS, PCF8563_REG_SECOND, self.buf)
            self.DT[0] = self.HexToDec(self.buf[6]) + 2000
            self.DT[1] = self.HexToDec(self.buf[5]%32)
            self.DT[2] = self.HexToDec(self.buf[3]%64)
            self.DT[3] = self.HexToDec(self.buf[4]%8)
            self.DT[4] = self.HexToDec(self.buf[2]%64)
            self.DT[5] = self.HexToDec(self.buf[1]%128)
            self.DT[6] = self.HexToDec(self.buf[0]%128)
            self.DT[7] = 0
            return self.DT
            
        else:
            self.buf[0] = self.DecToHex(DT[6]%60)    # second
            self.buf[1] = self.DecToHex(DT[5]%60)    # minute
            self.buf[2] = self.DecToHex(DT[4]%24)    # hour
            self.buf[3] = self.DecToHex(DT[2]%32)    # date
            self.buf[4] = self.DecToHex(DT[3]%8)     # week da
            self.buf[5] = self.DecToHex(DT[1]%13)    # month
            self.buf[6] = self.DecToHex(DT[0]%100)   # year
            self.i2c.writeto_mem(PCF8563_I2C_ADDRESS, PCF8563_REG_SECOND, self.buf)    


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值