Skip to content

Commit 3383c41

Browse files
committed
add RTC PCF8563
1 parent 45448f4 commit 3383c41

1 file changed

Lines changed: 132 additions & 0 deletions

File tree

04.i2c/RTC-PCF8563.py

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
# https://github.com/gwvsol/ESP8266-RTC-PCF8563
2+
3+
from micropython import const
4+
from time import localtime, mktime
5+
from gc import collect
6+
7+
#Registers overview
8+
_SECONDS = const(0x02)
9+
_MINUTES = const(0x03)
10+
_HOURS = const(0x04)
11+
_DATE = const(0x05)
12+
_WDAY = const(0x06)
13+
_MONTH = const(0x07)
14+
_YEAR = const(0x08)
15+
16+
class PCF8563(object):
17+
def __init__(self, i2c, i2c_addr, zone=0, dht=True):
18+
self.i2c = i2c
19+
self.i2c_addr = i2c_addr
20+
self.timebuf = None
21+
self.zone = zone
22+
self.block = False
23+
self.dht = dht
24+
if self.i2c_addr in self.i2c.scan():
25+
print('RTC: PCF8563 find at address: 0x%x ' %(self.i2c_addr))
26+
else:
27+
print('RTC: PCF8563 not found at address: 0x%x ' %(self.i2c_addr))
28+
collect() #Очищаем RAM
29+
30+
#Преобразование двоично-десятичного формата
31+
def _bcd2dec(self, bcd):
32+
"""Convert binary coded decimal (BCD) format to decimal"""
33+
return (((bcd & 0xf0) >> 4) * 10 + (bcd & 0x0f))
34+
35+
#Преобразование в двоично-десятичный формат
36+
def _dec2bcd(self, dec):
37+
"""Convert decimal to binary coded decimal (BCD) format"""
38+
tens, units = divmod(dec, 10)
39+
return (tens << 4) + units
40+
41+
def _tobytes(self, num):
42+
return num.to_bytes(1, 'little')
43+
44+
#Чтение времени или запись нового знвчения и преобразование в формат ESP8266
45+
#Возвращает кортеж в формате localtime() (в ESP8266 0 - понедельник, а 6 - воскресенье)
46+
def datetime(self, datetime=None):
47+
"""Reading RTC time and convert to ESP8266 and Direct write un-none value.
48+
Range: seconds [0,59], minutes [0,59], hours [0,23],
49+
day [0,7], date [1-31], month [1-12], year [0-99]."""
50+
if datetime == None:
51+
"""Reading RTC time and convert to ESP8266"""
52+
data = self.i2c.readfrom_mem(self.i2c_addr, _SECONDS, 7)
53+
ss = self._bcd2dec(data[0] & 0x7F)
54+
mm = self._bcd2dec(data[1] & 0x7F)
55+
hh = self._bcd2dec(data[2] & 0x3F)
56+
dd = self._bcd2dec(data[3] & 0x3F)
57+
wday = data[4] & 0x07
58+
MM = self._bcd2dec(data[5] & 0x1F)
59+
yy = self._bcd2dec(data[6]) + 2000
60+
return yy, MM, dd, hh, mm, ss, wday, 0 # wday in esp8266 0 == Monday, 6 == Sunday
61+
elif datetime != None:
62+
"""Direct write un-none value"""
63+
if datetime == 'reset': #Если datetime = 'reset', сброс времени на 2000-01-01 00:00:00
64+
(yy, MM, mday, hh, mm, ss, wday, yday) = (0, 1, 1, 0, 0, 0, 0, 0)
65+
else:
66+
(yy, MM, mday, hh, mm, ss, wday, yday) = datetime
67+
if ss < 0 or ss > 59: #Записывем новое значение секунд
68+
raise ValueError('RTC: Seconds is out of range [0,59].')
69+
self.i2c.writeto_mem(self.i2c_addr, _SECONDS, self._tobytes(self._dec2bcd(ss)))
70+
if mm < 0 or mm > 59: #Записываем новое значение минут
71+
raise ValueError('RTC: Minutes is out of range [0,59].')
72+
self.i2c.writeto_mem(self.i2c_addr, _MINUTES, self._tobytes(self._dec2bcd(mm)))
73+
if hh < 0 or hh > 23: #Записываем новое значение часов
74+
raise ValueError('RTC: Hours is out of range [0,23].')
75+
self.i2c.writeto_mem(self.i2c_addr, _HOURS, self._tobytes(self._dec2bcd(hh))) #Sets to 24hr mode
76+
if mday < 1 or mday > 31: #Записываем новое значение дней
77+
raise ValueError('RTC: Date is out of range [1,31].')
78+
self.i2c.writeto_mem(self.i2c_addr, _DATE, self._tobytes(self._dec2bcd(mday))) #Day of month
79+
if wday < 0 or wday > 6: #Записываем новое значение дней недели
80+
raise ValueError('RTC: Day is out of range [0,6].')
81+
self.i2c.writeto_mem(self.i2c_addr, _WDAY, self._tobytes(self._dec2bcd(wday)))
82+
if MM < 1 or MM > 12: #Записываем новое значение месяцев
83+
raise ValueError('RTC: Month is out of range [1,12].')
84+
self.i2c.writeto_mem(self.i2c_addr, _MONTH, self._tobytes(self._dec2bcd(MM)))
85+
if yy < 0 or yy > 99: #Записываем новое значение лет
86+
raise ValueError('RTC: Years is out of range [0,99].')
87+
self.i2c.writeto_mem(self.i2c_addr, _YEAR, self._tobytes(self._dec2bcd(yy)))
88+
(yy, MM, mday, hh, mm, ss, wday, yday) = self.datetime() #Cчитываем записанное новое значение времени с PCF8563
89+
print('RTC: New Time: {:0>2d}-{:0>2d}-{:0>2d} {:0>2d}:{:0>2d}:{:0>2d}'.format(yy, MM, mday, hh, mm, ss)) #Выводим новое время PCF8563
90+
91+
def settime(self, source='esp'):
92+
utc = self.datetime()
93+
if source == 'esp': #Устанавливаем время с часов ESP8266
94+
utc = localtime()
95+
rtc = self.datetime() #Cчитываем значение времени с PCF8563
96+
#Блокировка перевода времени. Если октябрь, блокировка на 1час 3минуты
97+
if self.block and rtc[1] == 10:
98+
if rtc[3] == 2: #Если 2 часа, блокировка не снимается
99+
pass
100+
elif rtc[3] == 3 and rtc[4] <= 2: #Если 3 часа и меньше 2 минут, бликировка не снимается
101+
pass
102+
else: #Во всех остальных случаях блокировка снимается
103+
self.block = False
104+
#Если март, бликировка включена для следующего вызова метода
105+
elif self.block and rtc[1] == 3:
106+
if rtc[3] == 3: #Блокировка действует пока не измениться rtc[3] = 3
107+
pass
108+
else: #Во всех остальных случаях блокировка снимается
109+
self.block = False
110+
else: #Во всех остальных случаях блокировка снимается
111+
self.block = False
112+
(yy, MM, mday, hh, mm, ss, wday, yday) = utc
113+
#Если существует разница во времени, применяем изменения
114+
if source == 'dht' and rtc[3] != hh:
115+
print('RTC: Old Time: {:0>2d}-{:0>2d}-{:0>2d} {:0>2d}:{:0>2d}:{:0>2d}'\
116+
.format(rtc[0], rtc[1], rtc[2], rtc[3], rtc[4], rtc[5]))
117+
self.datetime((yy - 2000, MM, mday, hh, mm, ss, wday, yday))
118+
elif source == 'esp' or source == 'ntp' or rtc[3] != hh or rtc[4] != mm or rtc[5] != ss:
119+
print('RTC: Old Time: {:0>2d}-{:0>2d}-{:0>2d} {:0>2d}:{:0>2d}:{:0>2d}'\
120+
.format(rtc[0], rtc[1], rtc[2], rtc[3], rtc[4], rtc[5]))
121+
self.datetime((yy - 2000, MM, mday, hh, mm, ss, wday, yday))
122+
#else: #Если разница во времени не обнаружена, выводим время с PCF8563
123+
# print('RTC: No time change: {:0>2d}-{:0>2d}-{:0>2d} {:0>2d}:{:0>2d}:{:0>2d}'\
124+
# .format(yy, MM, mday, hh, mm, ss))
125+
126+
if __name__ == "__main__":
127+
128+
from machine import I2C, Pin
129+
i2c = I2C(scl=Pin(22), sda=Pin(21), freq=400000)
130+
rtc = PCF8563(i2c, 0x51, zone=3)
131+
print(rtc.datetime())
132+

0 commit comments

Comments
 (0)