├── software
├── config.py
├── font5x8.bin
├── boot.py
├── week7x7.py
├── font3x8.py
├── bitmapfont.py
├── rx8111.py
└── main.py
├── documents
└── images
│ ├── 1.png
│ ├── 2.jpg
│ ├── 3.jpg
│ ├── 4.jpg
│ ├── 5.png
│ ├── 6.jpg
│ └── 7.jpg
├── hardware
├── SCH_1.3a.pdf
└── gerber_bom_pick
│ ├── Gerber_PCB1_2_2023-08-18.zip
│ └── BOM_1.3a_PCB1_2_2023-08-18.xlsx
├── mechanical
├── stl
│ ├── 压板.stl
│ ├── 外壳.stl
│ └── 按键.stl
└── Panel
│ └── Panel_2023-08-08.epanm
├── firmware
└── esp32c3-usb-20230426-v1.20.0.bin
└── README.md
/software/config.py:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #wifi
5 | ssid = " "
6 | password = " "
7 |
--------------------------------------------------------------------------------
/software/font5x8.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/software/font5x8.bin
--------------------------------------------------------------------------------
/documents/images/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/documents/images/1.png
--------------------------------------------------------------------------------
/documents/images/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/documents/images/2.jpg
--------------------------------------------------------------------------------
/documents/images/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/documents/images/3.jpg
--------------------------------------------------------------------------------
/documents/images/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/documents/images/4.jpg
--------------------------------------------------------------------------------
/documents/images/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/documents/images/5.png
--------------------------------------------------------------------------------
/documents/images/6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/documents/images/6.jpg
--------------------------------------------------------------------------------
/documents/images/7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/documents/images/7.jpg
--------------------------------------------------------------------------------
/hardware/SCH_1.3a.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/hardware/SCH_1.3a.pdf
--------------------------------------------------------------------------------
/mechanical/stl/压板.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/mechanical/stl/压板.stl
--------------------------------------------------------------------------------
/mechanical/stl/外壳.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/mechanical/stl/外壳.stl
--------------------------------------------------------------------------------
/mechanical/stl/按键.stl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/mechanical/stl/按键.stl
--------------------------------------------------------------------------------
/mechanical/Panel/Panel_2023-08-08.epanm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/mechanical/Panel/Panel_2023-08-08.epanm
--------------------------------------------------------------------------------
/firmware/esp32c3-usb-20230426-v1.20.0.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/firmware/esp32c3-usb-20230426-v1.20.0.bin
--------------------------------------------------------------------------------
/hardware/gerber_bom_pick/Gerber_PCB1_2_2023-08-18.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/hardware/gerber_bom_pick/Gerber_PCB1_2_2023-08-18.zip
--------------------------------------------------------------------------------
/hardware/gerber_bom_pick/BOM_1.3a_PCB1_2_2023-08-18.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MakerM0/PixelTime/HEAD/hardware/gerber_bom_pick/BOM_1.3a_PCB1_2_2023-08-18.xlsx
--------------------------------------------------------------------------------
/software/boot.py:
--------------------------------------------------------------------------------
1 | # This file is executed on every boot (including wake-boot from deepsleep)
2 | #import esp
3 | #esp.osdebug(None)
4 | #import webrepl
5 | #webrepl.start()
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | # [PixelTime](https://oshwhub.com/kakaka/PixelTime)
14 | a low power led watch based on ESP32-C3 & MicroPython
15 |
16 | [afdian.net](https://afdian.net/a/modular) [bilibili](https://www.bilibili.com/video/BV1Bj411i7ZR/) [OSHWHUB](https://oshwhub.com/kakaka/PixelTime)
17 |
18 | 
19 |
20 | 
21 |
22 | 
23 |
24 | 
25 |
26 | 
27 |
28 | 
29 |
30 | 
31 |
32 | ## Software
33 |
34 | based on MicroPython
35 |
36 |
37 |
38 |
39 |
40 | ## Mechanical
41 |
42 |
43 |
44 | ## License
45 |
46 | (hardware/mechanical)[Creative Commons — Attribution-NonCommercial-ShareAlike 4.0 International — CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/)
47 |
48 |
49 |
50 | ## Extra
51 |
52 |
53 |
--------------------------------------------------------------------------------
/software/week7x7.py:
--------------------------------------------------------------------------------
1 | WEEK7X8=(
2 | (0,1,1,1,1,1,0,
3 | 0,1,0,0,0,1,0,
4 | 0,1,0,0,0,1,0,
5 | 0,1,1,1,1,1,0,
6 | 0,1,0,0,0,1,0,
7 | 0,1,0,0,0,1,0,
8 | 0,1,1,1,1,1,0,
9 | 0,0,0,0,0,0,0,
10 |
11 | ),#日
12 | (0,0,0,0,0,0,0,
13 | 0,0,0,0,0,0,0,
14 | 0,0,0,0,0,1,0,
15 | 1,1,1,1,1,1,1,
16 | 0,0,0,0,0,0,0,
17 | 0,0,0,0,0,0,0,
18 | 0,0,0,0,0,0,0,
19 | 0,0,0,0,0,0,0,
20 |
21 | ),#一
22 | (
23 | 0,0,0,0,0,0,0,
24 | 0,1,1,1,1,1,0,
25 | 0,0,0,0,0,0,0,
26 | 0,0,0,0,0,0,0,
27 | 0,0,0,0,0,0,0,
28 | 0,0,0,0,0,1,0,
29 | 1,1,1,1,1,1,1,
30 | 0,0,0,0,0,0,0,
31 |
32 | ),#二
33 | (0,0,0,0,0,0,0,
34 | 0,1,1,1,1,1,0,
35 | 0,0,0,0,0,0,0,
36 | 0,0,1,1,1,0,0,
37 | 0,0,0,0,0,0,0,
38 | 0,0,0,0,0,0,0,
39 | 1,1,1,1,1,1,1,
40 | 0,0,0,0,0,0,0,
41 |
42 | ),#三
43 | (
44 | 1,1,1,1,1,1,1,
45 | 1,0,1,0,1,0,1,
46 | 1,0,1,0,1,0,1,
47 | 1,0,1,0,1,1,1,
48 | 1,1,0,0,0,0,1,
49 | 1,0,0,0,0,0,1,
50 | 1,1,1,1,1,1,1,
51 | 0,0,0,0,0,0,0,
52 | ),#四
53 | (
54 | 0,1,1,1,1,1,0,
55 | 0,0,0,1,0,0,0,
56 | 0,0,0,1,0,0,0,
57 | 0,1,1,1,1,1,0,
58 | 0,0,1,0,0,1,0,
59 | 0,0,1,0,0,1,0,
60 | 1,1,1,1,1,1,1,
61 | 0,0,0,0,0,0,0,
62 |
63 | ),#五
64 | (
65 | 0,0,0,1,0,0,0,
66 | 1,1,1,1,1,1,1,
67 | 0,0,0,0,0,0,0,
68 | 0,0,1,0,1,0,0,
69 | 0,0,1,0,1,0,0,
70 | 0,1,0,0,0,1,0,
71 | 1,0,0,0,0,0,1,
72 | 0,0,0,0,0,0,0,
73 | ),#六
74 | (
75 | 0,1,1,1,1,1,1,
76 | 0,1,0,1,0,0,1,
77 | 0,1,1,1,1,0,1,
78 | 0,1,0,1,0,0,1,
79 | 0,1,1,1,1,1,1,
80 | 0,1,1,0,1,0,1,
81 | 1,0,1,1,1,0,1,
82 | 0,0,0,0,0,0,0,
83 | ),#周
84 |
85 |
86 | )
--------------------------------------------------------------------------------
/software/font3x8.py:
--------------------------------------------------------------------------------
1 | FONT3X8 = (
2 | #
3 | # NUM0 =
4 | (
5 | 1, 1, 1,
6 | 1, 0, 1,
7 | 1, 0, 1,
8 | 1, 0, 1,
9 | 1, 0, 1,
10 | 1, 0, 1,
11 | 1, 0, 1,
12 | 1, 1, 1,
13 | ),
14 | #
15 | # NUM1 =
16 | (
17 | 0, 1, 0,
18 | 1, 1, 0,
19 | 0, 1, 0,
20 | 0, 1, 0,
21 | 0, 1, 0,
22 | 0, 1, 0,
23 | 0, 1, 0,
24 | 1, 1, 1,
25 | ),
26 | #
27 | # NUM2 =
28 | (
29 | 1, 1, 1,
30 | 0, 0, 1,
31 | 0, 0, 1,
32 | 1, 1, 1,
33 | 1, 0, 0,
34 | 1, 0, 0,
35 | 1, 0, 0,
36 | 1, 1, 1,
37 | ),
38 | #
39 | # NUM3 =
40 | (
41 | 1, 1, 1,
42 | 0, 0, 1,
43 | 0, 0, 1,
44 | 1, 1, 1,
45 | 0, 0, 1,
46 | 0, 0, 1,
47 | 0, 0, 1,
48 | 1, 1, 1,
49 | ),
50 | #
51 | # NUM4 =
52 | (
53 | 1, 0, 1,
54 | 1, 0, 1,
55 | 1, 0, 1,
56 | 1, 1, 1,
57 | 0, 0, 1,
58 | 0, 0, 1,
59 | 0, 0, 1,
60 | 0, 0, 1,
61 | ),
62 | #
63 | # NUM5 =
64 | (
65 | 1, 1, 1,
66 | 1, 0, 0,
67 | 1, 0, 0,
68 | 1, 1, 1,
69 | 0, 0, 1,
70 | 0, 0, 1,
71 | 0, 0, 1,
72 | 1, 1, 1,
73 | ),
74 | #
75 | # NUM6 =
76 | (
77 | 1, 1, 1,
78 | 1, 0, 0,
79 | 1, 0, 0,
80 | 1, 1, 1,
81 | 1, 0, 1,
82 | 1, 0, 1,
83 | 1, 0, 1,
84 | 1, 1, 1,
85 | ),
86 | #
87 | # NUM7 =
88 | (
89 | 1, 1, 1,
90 | 0, 0, 1,
91 | 0, 0, 1,
92 | 0, 0, 1,
93 | 0, 0, 1,
94 | 0, 0, 1,
95 | 0, 0, 1,
96 | 0, 0, 1,
97 | ),
98 | #
99 | # NUM8 =
100 | (
101 | 1, 1, 1,
102 | 1, 0, 1,
103 | 1, 0, 1,
104 | 1, 1, 1,
105 | 1, 0, 1,
106 | 1, 0, 1,
107 | 1, 0, 1,
108 | 1, 1, 1,
109 | ),
110 | #
111 | # NUM9 =
112 | (
113 | 1, 1, 1,
114 | 1, 0, 1,
115 | 1, 0, 1,
116 | 1, 1, 1,
117 | 0, 0, 1,
118 | 0, 0, 1,
119 | 0, 0, 1,
120 | 1, 1, 1,
121 | )
122 | )
--------------------------------------------------------------------------------
/software/bitmapfont.py:
--------------------------------------------------------------------------------
1 | # MicroPython basic bitmap font renderer.
2 | # Author: Tony DiCola
3 | # License: MIT License (https://opensource.org/licenses/MIT)
4 | try:
5 | import ustruct
6 | except ImportError:
7 | import struct as ustruct
8 |
9 |
10 | class BitmapFont:
11 |
12 | def __init__(self, width, height, pixel, font_name='font5x8.bin'):
13 | # Specify the drawing area width and height, and the pixel function to
14 | # call when drawing pixels (should take an x and y param at least).
15 | # Optionally specify font_name to override the font file to use (default
16 | # is font5x8.bin). The font format is a binary file with the following
17 | # format:
18 | # - 1 unsigned byte: font character width in pixels
19 | # - 1 unsigned byte: font character height in pixels
20 | # - x bytes: font data, in ASCII order covering all 255 characters.
21 | # Each character should have a byte for each pixel column of
22 | # data (i.e. a 5x8 font has 5 bytes per character).
23 | self._width = width
24 | self._height = height
25 | self._pixel = pixel
26 | self._font_name = font_name
27 |
28 | def init(self):
29 | # Open the font file and grab the character width and height values.
30 | # Note that only fonts up to 8 pixels tall are currently supported.
31 | self._font = open(self._font_name, 'rb')
32 | self._font_width, self._font_height = ustruct.unpack('BB', self._font.read(2))
33 |
34 | def deinit(self):
35 | # Close the font file as cleanup.
36 | self._font.close()
37 |
38 | def __enter__(self):
39 | self.init()
40 | return self
41 |
42 | def __exit__(self, exception_type, exception_value, traceback):
43 | self.deinit()
44 |
45 | def draw_char(self, ch, x, y, *args, **kwargs):
46 | # Don't draw the character if it will be clipped off the visible area.
47 | if x < -self._font_width or x >= self._width or \
48 | y < -self._font_height or y >= self._height:
49 | return
50 | # Go through each column of the character.
51 | for char_x in range(self._font_width):
52 | # Grab the byte for the current column of font data.
53 | self._font.seek(2 + (ord(ch) * self._font_width) + char_x)
54 | line = ustruct.unpack('B', self._font.read(1))[0]
55 | # Go through each row in the column byte.
56 | for char_y in range(self._font_height):
57 | # Draw a pixel for each bit that's flipped on.
58 | if (line >> char_y) & 0x1:
59 | self._pixel(x + char_x, y + char_y, *args, **kwargs)
60 |
61 | def text(self, text, x, y, *args, **kwargs):
62 | # Draw the specified text at the specified location.
63 | for i in range(len(text)):
64 | self.draw_char(text[i], x + (i * (self._font_width + 1)), y,
65 | *args, **kwargs)
66 |
67 | def width(self, text):
68 | # Return the pixel width of the specified text message.
69 | return len(text) * (self._font_width + 1)
70 |
--------------------------------------------------------------------------------
/software/rx8111.py:
--------------------------------------------------------------------------------
1 | '''
2 | RX8111 RTC drive
3 |
4 | Author: M0dular
5 | Date: 2023-8-5
6 | Ver: 0.1.0
7 |
8 | https://oshwhub.com/kakaka
9 | '''
10 |
11 |
12 |
13 | from micropython import const
14 | from math import log2
15 | from gc import collect
16 | # bus address
17 | RX8111_ADDR = const(0x32)
18 |
19 | # Basic time and calendar register
20 | RX8111_SEC = const(0x10)
21 | RX8111_MIN = const(0x11)
22 | RX8111_HOUR = const(0x12)
23 | RX8111_WEEK = const(0x13)
24 | RX8111_DAY = const(0x14)
25 | RX8111_MONTH = const(0x15)
26 | RX8111_YEAR = const(0x16)
27 | RX8111_MIN_ALARM = const(0x17)
28 | RX8111_HOUR_ALARM = const(0x18)
29 | RX8111_WEEK_DAY_ALARM = const(0x19)
30 | RX8111_TIMER_COUNTER0 = const(0x1A)
31 | RX8111_TIMER_COUNTER1 = const(0x1B)
32 | RX8111_TIMER_COUNTER2 = const(0x1C)
33 | RX8111_EXTENREG = const(0x1D)
34 | RX8111_FLAGREG = const(0x1E)
35 | RX8111_CTRLREG = const(0x1F)
36 |
37 | RX8111_TIMESTAMP_1_1000S = const(0x20)
38 | RX8111_TIMESTAMP_1_100S = const(0x21)
39 | RX8111_TIMESTAMP_SEC = const(0x22)
40 | RX8111_TIMESTAMP_MIN = const(0x23)
41 | RX8111_TIMESTAMP_HOUR = const(0x24)
42 | RX8111_TIMESTAMP_WEEK = const(0x25)
43 | RX8111_TIMESTAMP_DAY = const(0x26)
44 | RX8111_TIMESTAMP_MONTHS = const(0x27)
45 | RX8111_TIMESTAMP_YEAR = const(0x28)
46 | RX8111_STATUS_STAMP = const(0x29)
47 |
48 | RX8111_EVIN_SETTING = const(0x2B)
49 | RX8111_SEC_ALARM = const(0x2C)
50 | RX8111_TIMER_CONTROL = const(0x2D)
51 | RX8111_CMD_TRIG_CTRL = const(0x2E)
52 | RX8111_COMMAND_TRIGGER = const(0x2F)
53 |
54 | RX8111_PWR_SWITCH_CTRL = const(0x32)
55 | RX8111_STATUS_MONITOR = const(0x33)
56 | RX8111_TIME_STAMP_BUF_CTRL = const(0x34)
57 | RX8111_TIME_STAMP_TRIG_CTRL = const(0x35)
58 | RX8111_TIME_STAMP_DATA_STATUS = const(0x36)
59 |
60 | '''
61 | RX8111_EXT_TSEL0 BIT(0)
62 | RX8111_EXT_TSEL1 BIT(1)
63 | RX8111_EXT_ECP BIT(2)
64 | RX8111_EXT_WADA BIT(3)
65 | RX8111_EXT_TE BIT(4)
66 | RX8111_EXT_USEL BIT(5)
67 | RX8111_EXT_FSEL0 BIT(6)
68 | RX8111_EXT_FSEL1 BIT(7)
69 |
70 | RX8111_FLAG_FSTOPF BIT(0)
71 | RX8111_FLAG_VLF BIT(1)
72 | RX8111_FLAG_EVF BIT(2)
73 | RX8111_FLAG_AF BIT(3)
74 | RX8111_FLAG_TF BIT(4)
75 | RX8111_FLAG_UF BIT(5)
76 | RX8111_FLAG_PORF BIT(7)
77 | '''
78 | RX8111_CTRL_STOP =const(0)
79 | '''
80 | RX8111_CTRL_EIE BIT(2)
81 | RX8111_CTRL_AIE BIT(3)
82 | RX8111_CTRL_TIE BIT(4)
83 | RX8111_CTRL_UIE BIT(5)
84 |
85 | RX8111_EVIN_EOVEN BIT(1)
86 | RX8111_EVIN_EPRUP_SEL0 BIT(2)
87 | RX8111_EVIN_EPRUP_SEL1 BIT(3)
88 | RX8111_EVIN_EPRDW_SEL BIT(4)
89 | RX8111_EVIN_ET0 BIT(5)
90 | RX8111_EVIN_ET1 BIT(6)
91 | RX8111_EVIN_EHL BIT(7)
92 |
93 | RX8111_TIMER_CTRL_TSTP BIT(0)
94 | RX8111_TIMER_CTRL_TMPIN BIT(1)
95 | RX8111_TIMER_CTRL_TBKE BIT(2)
96 | RX8111_TIMER_CTRL_TBKON BIT(3)
97 |
98 | RX8111_CMD_TRIG_DUMMY0 BIT(0)
99 | RX8111_CMD_TRIG_DUMMY1 BIT(1)
100 | RX8111_CMD_TRIG_DUMMY2 BIT(2)
101 | RX8111_CMD_TRIG_DUMMY3 BIT(3)
102 | RX8111_CMD_TRIG_DUMMY4 BIT(4)
103 | RX8111_CMD_TRIG_DUMMY5 BIT(5)
104 | RX8111_CMD_TRIG_DUMMY6 BIT(6)
105 | RX8111_CMD_TRIG_DUMMY7 BIT(7)
106 |
107 | RX8111_PSC_SMP_TSEL0 BIT(0)
108 | RX8111_PSC_SMP_TSEL1 BIT(1)
109 | RX8111_PSC_SMP_SWSEL0 BIT(2)
110 | RX8111_PSC_SMP_SWSEL1 BIT(3)
111 | RX8111_PSC_SMP_INIEN BIT(6)
112 | RX8111_PSC_SMP_CHGEN BIT(7)
113 |
114 | RX8111_PSC_SMP_CHGEN BIT(7)
115 |
116 | RX8111_STAT_M_FVLOW BIT(1)
117 | RX8111_STAT_M_FVCMP BIT(3)
118 | RX8111_STAT_M_EVINMON BIT(6)
119 | # Insert and Defined ALARM_AE
120 | RX8111_ALARM_AE BIT(7)
121 |
122 | '''
123 |
124 | class RX8111(object):
125 | def __init__(self,i2c):
126 | self.i2c = i2c
127 | self.tb = bytearray(1)
128 | self.rb = bytearray(1)
129 | self.buf = bytearray(7)
130 | self.DT = [0] * 7
131 | # if RX8111_ADDR in self.i2c.scan():
132 | # print('RTC: rx8111 find at address: 0x%x ' %(RX8111_ADDR))
133 | # else:
134 | # print('RTC: rx8111 not found at address: 0x%x ' %(RX8111_ADDR))
135 | # collect() #
136 |
137 | # set reg
138 | def setReg(self, reg, dat):
139 | self.tb[0] = dat
140 | self.i2c.writeto_mem(RX8111_ADDR, reg, self.tb)
141 |
142 | # get reg
143 | def getReg(self, reg):
144 | self.i2c.readfrom_mem_into(RX8111_ADDR, reg, self.rb)
145 | return self.rb[0]
146 |
147 |
148 | # 将二进制编码的十进制数转换为普通十进制数
149 | def _bcd2dec(self, bcd) :
150 | """Convert binary coded decimal (BCD) format to decimal"""
151 | return (((bcd & 0xf0) >> 4) * 10 + (bcd & 0x0f))
152 |
153 | # 将十进制编码的二进制数转换为普通十进制数
154 | def _dec2bcd(self, dec):
155 | """Convert decimal to binary coded decimal (BCD) format"""
156 | tens, units = divmod(dec, 10)
157 | return (tens << 4) + units
158 |
159 | def WeekToBdc(self, val) :
160 | return 0x01 << val
161 |
162 |
163 | def WeekToNum(self, val) :
164 | return int(log2(val))
165 |
166 |
167 |
168 | def setBit(self, reg, bit_addr):
169 |
170 | data = self.getReg(reg)
171 | data |= (0x01 << bit_addr)
172 |
173 | self.setReg(reg, data)
174 |
175 |
176 | def clearBit(self, reg, bit_addr):
177 |
178 | data = self.getReg(reg)
179 | data &= ~(0x01 << bit_addr)
180 |
181 | self.setReg(reg, data)
182 |
183 | def datetime(self,DT=None):
184 | '''
185 | DT: year,month,day,hour,minute,second,weekday
186 | 在Python的time.localtime()函数中,stars from Monday (0) and ends on Sunday (6)。所以星期从0开始计数,0代表星期一。
187 | 而rx8111是从星期日开始计数,0代表星期日
188 | Sunday 0 0 0 0 0 0 0 1 01 h
189 | Monday 0 0 0 0 0 0 1 0 02 h
190 | Tuesday 0 0 0 0 0 1 0 0 04 h
191 | Wednesday 0 0 0 0 1 0 0 0 08 h
192 | Thursday 0 0 0 1 0 0 0 0 10 h
193 | Friday 0 0 1 0 0 0 0 0 20 h
194 | Saturday 0 1 0 0 0 0 0 0 40 h
195 | '''
196 | if DT==None:
197 | self.i2c.readfrom_mem_into(RX8111_ADDR, RX8111_SEC, self.buf)
198 |
199 | self.DT[0] = self._bcd2dec(self.buf[6]) + 2000 # year
200 | self.DT[1] = self._bcd2dec(self.buf[5]& 0x1F)# month
201 | self.DT[2] = self._bcd2dec(self.buf[4] & 0x3F)# day
202 |
203 | self.DT[3] = self._bcd2dec(self.buf[2] & 0x3F)# hour
204 | self.DT[4] = self._bcd2dec(self.buf[1]& 0x7F)# minute
205 | self.DT[5] = self._bcd2dec(self.buf[0]& 0x7F)# second
206 |
207 | self.DT[6] = self.WeekToNum(self.buf[3]) # week day
208 |
209 | return tuple(self.DT)
210 | else:
211 | self.setBit(RX8111_CTRLREG, RX8111_CTRL_STOP)
212 | self.setReg(RX8111_FLAGREG, 0x00)
213 |
214 | self.buf[6] = self._dec2bcd(DT[0]%100) # year
215 | self.buf[5] = self._dec2bcd(DT[1]%13) # month
216 | self.buf[4] = self._dec2bcd(DT[2]%32) # day
217 |
218 | self.buf[2] = self._dec2bcd(DT[3]%24) # hour
219 | self.buf[1] = self._dec2bcd(DT[4]%60) # minute
220 | self.buf[0] = self._dec2bcd(DT[5]%60) # second
221 |
222 | self.buf[3] = self.WeekToBdc((DT[6]+1)%7) # week day
223 |
224 | self.i2c.writeto_mem(RX8111_ADDR, RX8111_SEC, self.buf)
225 |
226 | self.clearBit(RX8111_CTRLREG, RX8111_CTRL_STOP)
227 |
228 |
229 |
230 |
231 |
232 | if __name__ == "__main__":
233 | from machine import I2C, Pin
234 | import time
235 | print('rx8111 test')
236 | i2c = I2C(0, scl=Pin(7), sda=Pin(8), freq=400000)
237 | rtc = RX8111(i2c)
238 | rtc.datetime((2023,8,5,16,25,59,6))
239 | while True:
240 | print(rtc.datetime())
241 | time.sleep(1.0)
242 |
243 |
244 |
--------------------------------------------------------------------------------
/software/main.py:
--------------------------------------------------------------------------------
1 |
2 | from machine import I2C, Pin
3 | import time
4 | import network
5 | import neopixel
6 | import gc
7 | import bitmapfont
8 | from font3x8 import *
9 | from week7x7 import *
10 | import rx8111
11 |
12 | import config
13 |
14 | ssid = config.ssid
15 | password =config.password
16 |
17 | zonetime = 8*3600
18 |
19 | NEOPIXEL_PIN = 5
20 | ROWS = 8
21 | COLS = 15
22 | NUMBER_PIXELS = ROWS * COLS
23 |
24 | C_BLACK=(0,0,0)
25 | C_GREEN=(0,35,0)
26 | C_BLUE=(0,0,35)
27 | C_RED=(35,0,0)
28 | C_YELLOW=(35,35,0)
29 | C_MONTH=(31,5,12)
30 | C_DAY=(35,31,31)
31 |
32 | np = neopixel.NeoPixel(Pin(NEOPIXEL_PIN), NUMBER_PIXELS)
33 |
34 |
35 |
36 |
37 | #15x8
38 | ICON_WIFI=(
39 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
40 | 1,0,1,0,0,1,0,0,1,1,1,0,0,1,0,
41 | 1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,
42 | 1,0,1,0,0,1,0,0,1,1,0,0,0,1,0,
43 | 1,0,1,0,0,1,0,0,1,0,0,0,0,1,0,
44 | 1,1,1,0,0,1,0,0,1,0,0,0,0,1,0,
45 | 1,1,1,0,0,1,0,0,1,0,0,0,0,1,0,
46 | 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
47 |
48 | )
49 |
50 | class Display(object):
51 | def __init__(self,np):
52 | self.np=np
53 |
54 |
55 | def write_pixel(self,x,y,value):
56 | if y >= 0 and y < ROWS and x >=0 and x < COLS:
57 | self.np[x*ROWS + y] = value
58 |
59 | def drawPixel(self,x,y,value):
60 | self.write_pixel(x,y,value)
61 |
62 |
63 |
64 | def clear(self):
65 | for i in range(NUMBER_PIXELS):
66 | np[i]=(0,0,0)
67 | self.np.write()
68 |
69 | def show(self):
70 | self.np.write()
71 |
72 | def draw1Num(self,x,y,num,color,bg=None):
73 | num=num%10
74 | for j in range(8):
75 | for i in range(3):
76 | if FONT3X8[num][i+j*3]==1:
77 | self.write_pixel(x+i,y+j,color)
78 | else :
79 | if bg != None:
80 | self.write_pixel(x+i,y+j,bg)
81 |
82 | def drawNum(self,x,y,num,color,bg=None) :
83 | self.draw1Num(x,y,num//1000%10,color,bg)
84 | self.draw1Num(x+4,y,num%1000//100,color,bg)
85 | self.draw1Num(x+4*2,y,num%100//10,color,bg)
86 | self.draw1Num(x+4*3,y,num%10,color,bg)
87 |
88 | def change1Num(self,x,y,num_src,num_dest,color,bg=None):
89 | num_src=num_src%10
90 | num_dest=num_dest%10
91 |
92 | for i in range(1,9):
93 | self.draw1Num(x,y-i,num_src,color,bg)
94 | self.draw1Num(x,y+8-i,num_dest,color,bg)
95 | time.sleep(0.01)
96 | self.show()
97 |
98 | def draw1Week(self,x,y,num,color,bg=None):
99 | for j in range(8):
100 | for i in range(7):
101 | if WEEK7X8[num][i+j*7]==1:
102 | self.write_pixel(x+i,y+j,color)
103 | else :
104 | if bg != None:
105 | self.write_pixel(x+i,y+j,bg)
106 |
107 | def drawWeek(self,x,y,watch,color,bg=None) :
108 | # num=num%7
109 | # print(num)
110 | self.draw1Week(x,y,7,color,bg)
111 | self.draw1Week(x+8,y,watch.time_now[6],color,bg)
112 |
113 | def drawTime(self,x,y,watch,color1,color2,bg=None):
114 | self.draw1Num(x+0,y,watch.time_now[3]//10,color1,bg)
115 | self.draw1Num(x+4,y,watch.time_now[3]%10,color1,bg)
116 | self.draw1Num(x+8,y,watch.time_now[4]//10,color2,bg)
117 | self.draw1Num(x+12,y,watch.time_now[4]%10,color2,bg)
118 | self.show()
119 |
120 | def drawDate(self,x,y,watch,color1,color2,bg=None):
121 | if watch.time_now[1]//10:
122 | self.draw1Num(x+0,y,watch.time_now[1]//10,color1,bg)
123 | else:
124 | self.draw1Num(x+0,y,watch.time_now[1]//10,bg,bg)
125 |
126 | self.draw1Num(x+4,y,watch.time_now[1]%10,color1,bg)
127 | if watch.time_now[2]//10:
128 | self.draw1Num(x+8,y,watch.time_now[2]//10,color2,bg)
129 | else:
130 | self.draw1Num(x+8,y,watch.time_now[2]//10,bg,bg)
131 | self.draw1Num(x+12,y,watch.time_now[2]%10,color2,bg)
132 | self.show()
133 |
134 | def drawIcon(self,x,y,width,height,icon,color,bg=None):
135 | for j in range(height):
136 | for i in range(width):
137 | if icon[i+j*width]==1:
138 | self.write_pixel(x+i,y+j,color)
139 | else :
140 | if bg != None:
141 | self.write_pixel(x+i,y+j,bg)
142 |
143 |
144 |
145 |
146 | disp = Display(np)
147 |
148 | import machine
149 | class Watch(object):
150 | def __init__(self,time_now):
151 | self.time_now=time_now
152 | self.time_old=time_now
153 | self.timeout=0 #关机超时时间,ms单位
154 | self.timeout_stamp=time.ticks_ms()
155 |
156 |
157 | def resetTimeout(self,timeout=5000):
158 | self.timeout= timeout
159 | self.timeout_stamp=time.ticks_ms()
160 |
161 | def checkTimeout(self):
162 | deadline = time.ticks_add(self.timeout_stamp, self.timeout)
163 | if time.ticks_diff(deadline, time.ticks_ms()) > 0:
164 | return False
165 | else:
166 | return True
167 |
168 |
169 |
170 |
171 |
172 |
173 | def poweroff(self):
174 | machine.deepsleep()
175 |
176 |
177 |
178 |
179 |
180 | INDEX_HOUR = 3
181 | INDEX_MINUTE = 4
182 | INDEX_SECOND = 5
183 |
184 |
185 |
186 | def updateTime(watch):
187 | watch.time_now = rtc.datetime()
188 | if watch.time_now != watch.time_old:
189 | if watch.time_now[INDEX_MINUTE]%10 != watch.time_old[INDEX_MINUTE]%10:
190 | disp.change1Num(12,0,watch.time_old[INDEX_MINUTE]%10,watch.time_now[INDEX_MINUTE]%10,C_YELLOW,C_BLACK)
191 |
192 | if watch.time_now[INDEX_MINUTE]//10 != watch.time_old[INDEX_MINUTE]//10:
193 | disp.change1Num(8,0,watch.time_old[INDEX_MINUTE]//10,watch.time_now[INDEX_MINUTE]//10,C_YELLOW,C_BLACK)
194 |
195 | if watch.time_now[INDEX_HOUR]%10 != watch.time_old[INDEX_HOUR]%10:
196 | disp.change1Num(4,0,watch.time_old[INDEX_HOUR]%10,watch.time_now[INDEX_HOUR]%10,C_GREEN,C_BLACK)
197 |
198 | if watch.time_now[INDEX_HOUR]//10 != watch.time_old[INDEX_HOUR]//10:
199 | disp.change1Num(0,0,watch.time_old[INDEX_HOUR]//10,watch.time_now[INDEX_HOUR]//10,C_GREEN,C_BLACK)
200 |
201 | watch.time_old = watch.time_now
202 |
203 |
204 | print('rx8111 test')
205 | i2c = I2C(0, scl=Pin(7), sda=Pin(8), freq=400000)
206 | rtc = rx8111.RX8111(i2c)
207 |
208 | week=('SUN','MON','TUE','WED','THU','FRI','SAT')
209 |
210 |
211 |
212 | def syncTimeByWifi(ssid,password,trycnt=20):
213 | if ssid == None :
214 | return
215 | import ntptime
216 | wlan = network.WLAN(network.STA_IF)
217 | wlan.active(True)
218 | wlan.connect(ssid,password)
219 |
220 | if not wlan.isconnected():
221 | while not wlan.isconnected():
222 | print("Waiting to connect:")
223 | time.sleep(1.0)
224 | trycnt = trycnt-1
225 | if trycnt%2 :
226 | disp.drawPixel(5,1,C_GREEN)
227 | else:
228 | disp.drawPixel(5,1,C_RED)
229 |
230 | disp.show()
231 | if trycnt<0:
232 | print("\nFail !!!\n")
233 | break
234 | if wlan.isconnected():
235 | print(wlan.ifconfig())
236 | while True:
237 | try:
238 | print('获取时间中')
239 | ntptime.host = 'ntp1.aliyun.com'
240 | ntptime.settime()
241 | print('成功获取')
242 | break
243 | except:
244 | print('获取失败')
245 | time.sleep(1)
246 | wlan.disconnect()
247 | wlan.active(False)
248 | watch.resetTimeout()
249 |
250 |
251 |
252 | charge = Pin(20, Pin.IN, Pin.PULL_UP)
253 |
254 | k1 = Pin(4, Pin.IN)
255 | k2 = Pin(0, Pin.IN)
256 | k3 = Pin(9, Pin.IN)
257 |
258 |
259 | class Event():
260 | K1_PRESSED=1
261 | K1_RELEASED=2
262 | K2_PRESSED=3
263 | K2_RELEASED=4
264 | K3_PRESSED=5
265 | K3_RELEASED=6
266 | K1_LONG=7
267 | K2_LONG=8
268 | K3_LONG=9
269 |
270 | def __init__(self):
271 | self.event=[]
272 |
273 | def addEvent(self,evt):
274 | self.event.append(evt)
275 |
276 | def getEvent(self):
277 | if len(self.event)==0:
278 | return -1
279 | return self.event.pop(0)
280 |
281 | LongPressed = 1000
282 | key_time=0
283 | def fun(key):
284 | global key_time
285 | watch.resetTimeout()
286 | if key==k1:
287 | if key.value() == 0:
288 | key_time=time.ticks_ms()
289 | # print('k1 pressed')
290 | evt.addEvent(Event.K1_PRESSED)
291 | else:
292 | # print('k1 released')
293 | if time.ticks_diff(time.ticks_ms(),key_time)>LongPressed:
294 | evt.addEvent(Event.K1_LONG)
295 | else:
296 | evt.addEvent(Event.K1_RELEASED)
297 | if key==k2:
298 | if key.value() == 1:
299 | # print('k2 pressed')
300 | evt.addEvent(Event.K2_PRESSED)
301 | else:
302 | # print('k2 released')
303 | evt.addEvent(Event.K2_RELEASED)
304 | if key==k3:
305 | if key.value() == 0:
306 | # print('k3 pressed')
307 | evt.addEvent(Event.K3_PRESSED)
308 | else:
309 | # print('k3 released')
310 | evt.addEvent(Event.K3_RELEASED)
311 |
312 |
313 |
314 |
315 |
316 | k1.irq(fun,Pin.IRQ_FALLING | Pin.IRQ_RISING)
317 | k2.irq(fun,Pin.IRQ_FALLING | Pin.IRQ_RISING)
318 | k3.irq(fun,Pin.IRQ_FALLING | Pin.IRQ_RISING)
319 |
320 | currentPage=0
321 |
322 |
323 |
324 |
325 | # syncTimeByWifi(ssid,password)
326 | # sec=time.mktime(time.localtime())#获取时间戳
327 | # now = time.localtime(sec+zonetime)#获取新时区的时间
328 |
329 | # rtc.datetime(now)
330 |
331 | evt = Event()
332 | disp.clear()
333 |
334 | watch = Watch(rtc.datetime())
335 |
336 | disp.drawTime( 0,0,watch,C_GREEN,C_YELLOW,C_BLACK)
337 |
338 | watch.resetTimeout()
339 |
340 | def switchPage():
341 | global currentPage
342 | if currentPage==0:
343 |
344 | for j in range(8):
345 | disp.drawTime(0,-1-j,watch,C_GREEN,C_YELLOW,C_BLACK)
346 | disp.drawWeek(0,7-j,watch,C_GREEN,C_BLACK)
347 | disp.show()
348 | time.sleep(0.01)
349 | currentPage=1
350 | print(currentPage)
351 | return
352 |
353 | if currentPage==1:
354 | for j in range(8):
355 | disp.drawWeek(0,-1-j,watch,C_GREEN,C_BLACK)
356 | disp.drawDate(0,7-j,watch,C_MONTH,C_DAY,C_BLACK)
357 | disp.show()
358 | time.sleep(0.01)
359 | currentPage=2
360 | print(currentPage)
361 | return
362 |
363 | if currentPage==2:
364 | for j in range(8):
365 | disp.drawDate(0,-1-j,watch,C_MONTH,C_DAY,C_BLACK)
366 | disp.drawTime(0,7-j,watch,C_GREEN,C_YELLOW,C_BLACK)
367 | disp.show()
368 | time.sleep(0.01)
369 | currentPage=0
370 | print(currentPage)
371 | return
372 |
373 | def handleEvent(evt):
374 | global currentPage
375 | if evt<=0:
376 | return
377 |
378 | if evt==Event.K2_PRESSED:
379 | switchPage()
380 | pass
381 | if evt==Event.K3_PRESSED:
382 | watch.poweroff()
383 |
384 | if evt==Event.K1_LONG:
385 | print('syncTimeByWifi')
386 |
387 | disp.drawIcon(0,0,15,8,ICON_WIFI,C_BLUE,C_BLACK)
388 | disp.show()
389 | syncTimeByWifi(ssid,password)
390 | sec=time.mktime(time.localtime())#获取时间戳
391 | now = time.localtime(sec+zonetime)#获取新时区的时间
392 |
393 | rtc.datetime(now)
394 | if currentPage ==0:
395 | disp.drawTime(0,0,watch,C_GREEN,C_YELLOW,C_BLACK)
396 | updateTime(watch)
397 | elif currentPage ==1:
398 | disp.drawWeek(0,0,watch,C_GREEN,C_BLACK)
399 | elif currentPage ==2:
400 | disp.drawDate(0,0,watch,C_MONTH,C_DAY,C_BLACK)
401 |
402 | disp.show()
403 |
404 | print(now)
405 | pass
406 |
407 |
408 |
409 | timeout_en = False
410 |
411 | if charge.value()==0 :
412 | timeout_en = False
413 | else:
414 | timeout_en = True
415 |
416 |
417 | print(timeout_en)
418 |
419 |
420 |
421 |
422 | while True:
423 | if charge.value()==0 :
424 | time.sleep(1.0)
425 | disp.clear()
426 |
427 | if watch.checkTimeout() and timeout_en:
428 | print("timeout")
429 | watch.poweroff()
430 | watch.resetTimeout()
431 |
432 |
433 | handleEvent(evt.getEvent())
434 | # Calculate deadline for operation and test for it
435 | deadline = time.ticks_add(time.ticks_ms(), 5000)
436 | if time.ticks_diff(deadline, time.ticks_ms()) > 0:
437 | deadline = time.ticks_add(time.ticks_ms(), 5000)
438 | if currentPage ==0:
439 | updateTime(watch)
440 |
441 |
442 |
443 | # print(watch.time_now)
444 | time.sleep(0.2)
445 | gc.collect()
446 | # print(f'mem: {gc.mem_free()}')
447 |
--------------------------------------------------------------------------------