Bildbox 1 (klick hier)
Digitaluhr mit dem
Pico-RTC-DS3231 Modul
(Anzeige auf pico Display)
Bildbox 1 (klick hier)
Digitaluhr mit dem
Pico-RTC-DS3231 Modul
(Anzeige auf pico Display)
Hardware
- Raspberry Pi Pico
- Pico-RTC-DS3231 Modul
- Pico Display
- Micro USB Kabel
Die Ausgabe von weiteren 16 Euro für das präzise Pico-RTC Uhr Modul werden Sie ganz bestimmt nicht bereuen. Ich werde Ihnen in diesem
Projekt zeigen, wie damit eine kleine Digitaluhr realisiert werden kann. Das Pico-RTC-DS3231 ist ein RTC-Erweiterungsmodul, das speziell
für den Raspberry Pi Pico entwickelt wurde. Es enthält den hochpräzisen RTC-Chip DS3231, einen Pufferbatteriehalter und nutzt
den I2C-Bus zur Kommunikation. Dank des stapelbaren Designs können mehrere externe Sensoren angeschlossen werden. Oder wie in unserem
Fall dass Pico Display zur Anzeige.
Bevor der Quelltext für die Ausgabe der Zeit eingegeben werden kann, muss der RTC-Chip einmalig (oder nach Batterietausch) programmiert werden.
Dafür bietet der chinesische Hersteller Waveshare ein Script in C oder Python an, mit dem Datum, Uhrzeit und Wochentag gesetzt werden.
Dieses Script, angepasst von mir auf deutsche Wochentage, können Sie
hier downloaden.
ds3231 in betrieb nehmen
Wie oben bereits erwähnt, können der Pico, das RTC Modul und das Pico Display direkt übereinander 'gestapelt' werden (natürlich im
ausgeschalteten Zustand). Auf dem Pico wird wieder die Firmware (siehe die vorigen Projekte) benötigt. Falls die schon vorhanden ist, können Sie
den Pico jetzt mit dem Micro-USB Kabel verbinden und Thonny öffnen. Das herunter geladenene und entpackte Script 'ds3231.py' wird geöffnet. Bevor (!)
Sie es ausführen, ändern Sie die Zeilen 27, 78 und 80, wie in den beiden unteren Bildern gezeigt. Geben Sie bei der Uhrzeit z.B. einen Wert in den nächsten
5 Minuten ein (damit Sie nicht unter Zeitdruck geraten). Dann den Wochentag und das aktuelle Datum. Speichern Sie das Script ohne es auszuführen. Schauen Sie nun auf dem Rechner oder
dem Smartphone auf die Zeitanzeige mit den genauen Sekunden und starten das Script sekundengenau.
Bei der Ausführung wird in der unteren Kommandozeile von Thonny die gesetzte Zeit, Tag und Datum ausgegeben. Der RTC Chip ist damit fertig programmiert. Starten Sie das Script nicht
erneut ohne die Zeit neu anzugeben, denn sonst würden Sie ja in der 'Vergangenheit landen'. Die vorhandenen Werte bleiben aufgrund der Pufferbatterie
auch beim Ausschalten des Pico erhalten und werden auch 'sekundengenau weitergezählt'. Das ist ja gerade der Sinn und Zweck des RTC Moduls.
script zur zeitanzeige
Zunächst werden das Display initialisiert (Zeilen 1 bis 6), das Display gelöscht (Zeilen 8 bis 13) und die I2C-Ports zugewiesen (Zeilen 15 bis 17).
Achten Sie darauf, dass bei Paste&Copy in Zeile 1 und auch später bei den Funktionsdefinitionen keine 'unerlaubten' Einrückungen entstehen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from machine import Pin, I2C
import picodisplay as display
width = display.get_width()
height = display.get_height()
display_buffer = bytearray(width * height * 2)
display.init(display_buffer)
display.set_backlight(1.0)
display.set_led(0,0,0)
display.set_pen(0,0,0)
display.clear()
display.set_pen(255,255,255)
display.update()
I2C_PORT = 0
I2C_SDA = 20
I2C_SCL = 21
Die Zeilen 18 bis 21 lassen wir frei und fügen anschließend wie im vorhergehenden Projekt die Zeilen 22 bis 118 mit
der angepassten Zeichensatz-Map ein. Wenn Sie die noch nicht aus dem vorigen Projekt haben, laden Sie sie
hier jetzt herunter, entpacken diese und fügen die
Zeilen im Script ein. Der Grund für die geänderte Zeichensatz-Map ist: Der originale Zeichensatz gefällt mir einfach nicht!
Weiter geht es mit der Eingabe der Funktion 'printchar' in Zeile 120 bis 143.
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
def printchar(letter,xpos,ypos,size):
origin = xpos
charval = ord(letter)
index = charval-32
character = cmap[index]
rows = [character[i:i+5] for i in range(0,len(character),5)]
for row in rows:
for bit in row:
if bit == '1':
display.pixel(xpos,ypos)
if size==2:
display.pixel(xpos,ypos+1)
display.pixel(xpos+1,ypos)
display.pixel(xpos+1,ypos+1)
if size==3:
display.pixel(xpos,ypos+1)
display.pixel(xpos,ypos+2)
display.pixel(xpos+1,ypos)
display.pixel(xpos+2,ypos)
display.pixel(xpos+1,ypos+1)
display.pixel(xpos+2,ypos+2)
xpos+=size
xpos=origin
ypos+=size
Achten Sie bei der Eingabe wieder auf die 'notwendigen' Einrückungen um jeweils 4 Leerzeichen, wie sie die Python Syntax verlangt.
Es folgt jetzt noch die Funktion 'printstring' in den Zeilen 145 bis 154.
145
146
147
148
149
150
151
152
153
154
155
def printstring(string,xpos,ypos,size):
if size == 1:
spacing = 8
if size == 2:
spacing = 14
if size == 3:
spacing = 22
for i in string:
printchar(i,xpos,ypos,size)
xpos+=spacing
In den Zeilen 156 bis 176 wird die 'class ds3231()' definiert.
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# ===Set up RTC ===============
class ds3231(object):
w = ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"];
address = 0x68
start_reg = 0x00
alarm1_reg = 0x07
control_reg = 0x0e
status_reg = 0x0f
def __init__(self,i2c_port,i2c_scl,i2c_sda):
self.bus = I2C(i2c_port,scl=Pin(i2c_scl),sda=Pin(i2c_sda))
def read_time(self):
t = self.bus.readfrom_mem(int(self.address),int(self.start_reg),7)
sc = t[0]&0x7F #second
mn = t[1]&0x7F #minute
hr = t[2]&0x3F #hour
wk = t[3]&0x07 #week
dy = t[4]&0x3F #day
mth = t[5]&0x1F #month
return ("20%x/%02x/%02x %02x:%02x:%02x %s" %(t[6],t[5],t[4],t[2],t[1],t[0],self.w[t[3]-1]))
Im sich jetzt anschließenden Haupteil werden noch die Monatsnamen auf deutsch gesetzt und die Variable 'rts' sowie 's_old' definiert.
Die Variable 's_old' sorgt nachher in der 'while'-Schleife dafür, dass eine neue Zeitanzeige nur erfolgt, wenn beim Aufruf
's = rtc.read_time()' diese nicht mehr mit 's_old' übereinstimmt. Denn so langsam ist unser Controler ja nun auch nicht.
179
180
181
182
183
184
185
# ======== Main ==========
months = ["Januar","Februar","Maerz","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"]
rtc = ds3231(I2C_PORT,I2C_SCL,I2C_SDA)
rtc.read_time()
s_old=rtc.read_time()
So nun noch die 'while'-Schleife in den Zeilen 186 bis 203 und dann ist es geschafft. In diesem Teil wird festgelegt, was auf dem Display
ausgegeben werden soll. Zu Erklärung habe ich deshalb Kommentarzeilen eingefügt. So ist es leicht möglich andere Anzeigen
nach eigenen Vorstellungen zu wählen.
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
while True:
s = rtc.read_time()
if (s != s_old):
s_old = s
display.set_pen(255,255,255)
# Wochentag
day_str = str((s[20:30]))
printstring(day_str,70,20,2)
# aktuelle Uhrzeit hour:minute:second
crt_time = s[11:19]
printstring(crt_time,35,55,3)
# aktuelles Datum
date_str = str(int(s[8:10])) + "."+ str(int(s[5:7])) +"." + s[0:4]
printstring(date_str,60,100,2)
display.update()
# schwarz ueberschreiben
display.set_pen(0,0,0)
printstring(crt_time,35,55,3)
Fertig.
Jetzt läuft unser Programm. Hier finden Sie wieder den Link zum
Download des kompletten Quelltextes
entsprechend der Beschreibung.
Viel Spass und Erfolg beim Ausprobieren.
Zurück
Bei der Ausführung wird in der unteren Kommandozeile von Thonny die gesetzte Zeit, Tag und Datum ausgegeben. Der RTC Chip ist damit fertig programmiert. Starten Sie das Script nicht erneut ohne die Zeit neu anzugeben, denn sonst würden Sie ja in der 'Vergangenheit landen'. Die vorhandenen Werte bleiben aufgrund der Pufferbatterie auch beim Ausschalten des Pico erhalten und werden auch 'sekundengenau weitergezählt'. Das ist ja gerade der Sinn und Zweck des RTC Moduls.
script zur zeitanzeige
Zunächst werden das Display initialisiert (Zeilen 1 bis 6), das Display gelöscht (Zeilen 8 bis 13) und die I2C-Ports zugewiesen (Zeilen 15 bis 17).
Achten Sie darauf, dass bei Paste&Copy in Zeile 1 und auch später bei den Funktionsdefinitionen keine 'unerlaubten' Einrückungen entstehen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
from machine import Pin, I2C
import picodisplay as display
width = display.get_width()
height = display.get_height()
display_buffer = bytearray(width * height * 2)
display.init(display_buffer)
display.set_backlight(1.0)
display.set_led(0,0,0)
display.set_pen(0,0,0)
display.clear()
display.set_pen(255,255,255)
display.update()
I2C_PORT = 0
I2C_SDA = 20
I2C_SCL = 21
Die Zeilen 18 bis 21 lassen wir frei und fügen anschließend wie im vorhergehenden Projekt die Zeilen 22 bis 118 mit
der angepassten Zeichensatz-Map ein. Wenn Sie die noch nicht aus dem vorigen Projekt haben, laden Sie sie
hier jetzt herunter, entpacken diese und fügen die
Zeilen im Script ein. Der Grund für die geänderte Zeichensatz-Map ist: Der originale Zeichensatz gefällt mir einfach nicht!
Weiter geht es mit der Eingabe der Funktion 'printchar' in Zeile 120 bis 143.
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
def printchar(letter,xpos,ypos,size):
origin = xpos
charval = ord(letter)
index = charval-32
character = cmap[index]
rows = [character[i:i+5] for i in range(0,len(character),5)]
for row in rows:
for bit in row:
if bit == '1':
display.pixel(xpos,ypos)
if size==2:
display.pixel(xpos,ypos+1)
display.pixel(xpos+1,ypos)
display.pixel(xpos+1,ypos+1)
if size==3:
display.pixel(xpos,ypos+1)
display.pixel(xpos,ypos+2)
display.pixel(xpos+1,ypos)
display.pixel(xpos+2,ypos)
display.pixel(xpos+1,ypos+1)
display.pixel(xpos+2,ypos+2)
xpos+=size
xpos=origin
ypos+=size
Achten Sie bei der Eingabe wieder auf die 'notwendigen' Einrückungen um jeweils 4 Leerzeichen, wie sie die Python Syntax verlangt.
Es folgt jetzt noch die Funktion 'printstring' in den Zeilen 145 bis 154.
145
146
147
148
149
150
151
152
153
154
155
def printstring(string,xpos,ypos,size):
if size == 1:
spacing = 8
if size == 2:
spacing = 14
if size == 3:
spacing = 22
for i in string:
printchar(i,xpos,ypos,size)
xpos+=spacing
In den Zeilen 156 bis 176 wird die 'class ds3231()' definiert.
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# ===Set up RTC ===============
class ds3231(object):
w = ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"];
address = 0x68
start_reg = 0x00
alarm1_reg = 0x07
control_reg = 0x0e
status_reg = 0x0f
def __init__(self,i2c_port,i2c_scl,i2c_sda):
self.bus = I2C(i2c_port,scl=Pin(i2c_scl),sda=Pin(i2c_sda))
def read_time(self):
t = self.bus.readfrom_mem(int(self.address),int(self.start_reg),7)
sc = t[0]&0x7F #second
mn = t[1]&0x7F #minute
hr = t[2]&0x3F #hour
wk = t[3]&0x07 #week
dy = t[4]&0x3F #day
mth = t[5]&0x1F #month
return ("20%x/%02x/%02x %02x:%02x:%02x %s" %(t[6],t[5],t[4],t[2],t[1],t[0],self.w[t[3]-1]))
Im sich jetzt anschließenden Haupteil werden noch die Monatsnamen auf deutsch gesetzt und die Variable 'rts' sowie 's_old' definiert.
Die Variable 's_old' sorgt nachher in der 'while'-Schleife dafür, dass eine neue Zeitanzeige nur erfolgt, wenn beim Aufruf
's = rtc.read_time()' diese nicht mehr mit 's_old' übereinstimmt. Denn so langsam ist unser Controler ja nun auch nicht.
179
180
181
182
183
184
185
# ======== Main ==========
months = ["Januar","Februar","Maerz","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"]
rtc = ds3231(I2C_PORT,I2C_SCL,I2C_SDA)
rtc.read_time()
s_old=rtc.read_time()
So nun noch die 'while'-Schleife in den Zeilen 186 bis 203 und dann ist es geschafft. In diesem Teil wird festgelegt, was auf dem Display
ausgegeben werden soll. Zu Erklärung habe ich deshalb Kommentarzeilen eingefügt. So ist es leicht möglich andere Anzeigen
nach eigenen Vorstellungen zu wählen.
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
while True:
s = rtc.read_time()
if (s != s_old):
s_old = s
display.set_pen(255,255,255)
# Wochentag
day_str = str((s[20:30]))
printstring(day_str,70,20,2)
# aktuelle Uhrzeit hour:minute:second
crt_time = s[11:19]
printstring(crt_time,35,55,3)
# aktuelles Datum
date_str = str(int(s[8:10])) + "."+ str(int(s[5:7])) +"." + s[0:4]
printstring(date_str,60,100,2)
display.update()
# schwarz ueberschreiben
display.set_pen(0,0,0)
printstring(crt_time,35,55,3)
Fertig.
Jetzt läuft unser Programm. Hier finden Sie wieder den Link zum
Download des kompletten Quelltextes
entsprechend der Beschreibung.
Viel Spass und Erfolg beim Ausprobieren.
Zurück
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
from machine import Pin, I2C
import picodisplay as display
width = display.get_width()
height = display.get_height()
display_buffer = bytearray(width * height * 2)
display.init(display_buffer)
display.set_backlight(1.0)
display.set_led(0,0,0)
display.set_pen(0,0,0)
display.clear()
display.set_pen(255,255,255)
display.update()
I2C_PORT = 0
I2C_SDA = 20
I2C_SCL = 21
|
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
def printchar(letter,xpos,ypos,size):
origin = xpos
charval = ord(letter)
index = charval-32
character = cmap[index]
rows = [character[i:i+5] for i in range(0,len(character),5)]
for row in rows:
for bit in row:
if bit == '1':
display.pixel(xpos,ypos)
if size==2:
display.pixel(xpos,ypos+1)
display.pixel(xpos+1,ypos)
display.pixel(xpos+1,ypos+1)
if size==3:
display.pixel(xpos,ypos+1)
display.pixel(xpos,ypos+2)
display.pixel(xpos+1,ypos)
display.pixel(xpos+2,ypos)
display.pixel(xpos+1,ypos+1)
display.pixel(xpos+2,ypos+2)
xpos+=size
xpos=origin
ypos+=size
|
145
146
147
148
149
150
151
152
153
154
155
|
def printstring(string,xpos,ypos,size):
if size == 1:
spacing = 8
if size == 2:
spacing = 14
if size == 3:
spacing = 22
for i in string:
printchar(i,xpos,ypos,size)
xpos+=spacing
|
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
|
# ===Set up RTC ===============
class ds3231(object):
w = ["Sonntag","Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag"];
address = 0x68
start_reg = 0x00
alarm1_reg = 0x07
control_reg = 0x0e
status_reg = 0x0f
def __init__(self,i2c_port,i2c_scl,i2c_sda):
self.bus = I2C(i2c_port,scl=Pin(i2c_scl),sda=Pin(i2c_sda))
def read_time(self):
t = self.bus.readfrom_mem(int(self.address),int(self.start_reg),7)
sc = t[0]&0x7F #second
mn = t[1]&0x7F #minute
hr = t[2]&0x3F #hour
wk = t[3]&0x07 #week
dy = t[4]&0x3F #day
mth = t[5]&0x1F #month
return ("20%x/%02x/%02x %02x:%02x:%02x %s" %(t[6],t[5],t[4],t[2],t[1],t[0],self.w[t[3]-1]))
|
179
180
181
182
183
184
185
|
# ======== Main ==========
months = ["Januar","Februar","Maerz","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"]
rtc = ds3231(I2C_PORT,I2C_SCL,I2C_SDA)
rtc.read_time()
s_old=rtc.read_time()
|
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
while True:
s = rtc.read_time()
if (s != s_old):
s_old = s
display.set_pen(255,255,255)
# Wochentag
day_str = str((s[20:30]))
printstring(day_str,70,20,2)
# aktuelle Uhrzeit hour:minute:second
crt_time = s[11:19]
printstring(crt_time,35,55,3)
# aktuelles Datum
date_str = str(int(s[8:10])) + "."+ str(int(s[5:7])) +"." + s[0:4]
printstring(date_str,60,100,2)
display.update()
# schwarz ueberschreiben
display.set_pen(0,0,0)
printstring(crt_time,35,55,3)
|
Viel Spass und Erfolg beim Ausprobieren.
Zurück