Fitness-uhr



- auf dem runden 1.28-Zoll-IPS-LCD-Display 240 x 240 Pixel
- nutzt den ACC Beschleunigungssensor in Micropython




Hardware

- Rundes 1,28-Zoll-IPS-LCD-Display
- RP Pico 2040 (inclusive)
- USB-A zu USB-C Kabel
- 3.7V 100mAh Lithium Polymer Akku (z.B. von hier)


Es wird wieder der 3-Achsen ACC Sensor genutzt, wie schon in der 1. Anleitung, um die Schritte zu zählen. Zuätzlich wird in dieser Anleitung die exakte Uhrzeit, auch wenn das Gerät nicht am PC angeschlossen ist, angezeigt. Dazu wird diese auf dem Pico-Laufwerk gespeichert und zur Stromversorgung wird ein kleiner Akku ins Gehäuse integriert. Es geht also
- um die Stromversorgung beim runden Pico-LCD-Display mit einem kleinen 3.7V 100mAh Lithium Polymer Akku
- um die exakte Erfassung der Zeit auf Basis des Prozessortaktes (unabhängig von time.sleep()) und,
- um Schreib- und Lesevorgänge unter Micropython beim Pico.


Los gehts

1.

Ich gehe als erstes auf die Stromversorgung ein. Der vorgeschlagene 3,7 V Litium-Polymer Akku mit 100 mAh ist größenmäßig gut in ein Uhrengehäuse integrierbar. Im Betrieb fließen beim runden Pico-LCD-Display etwa 60 mA Strom, so dass die Akkukapazität ohne nachladen für ca. 1,5 Stunden reicht. Zum Aufladen kann die Fitnessuhr ohne Funktionsunterbrechung an den USB-C Anschluss angeschlossen werden. So gesehen besser als beim E-Auto. Die Fitnessuhr muss zwar auch häufig an die "Ladesäule" aber braucht dabei nicht mal anzuhalten.

Ganz wichtig: Ein Anbieter der Displays hat darauf hingewiesen, dass der Batterieanschluss ein wenig gebräuchlicher MX1.25-Stecker mit 1.25 mm Rastermaß ist. Den passenden Stecker habe ich (z.B. hier bestellt). Zu beachten ist, dass bei der Richtung, wie der Stecker in die Inline-Buchse am Display kommt, die Farbkennzeichnung der Polung verkehrt ist. Dass bedeuted, dass Sie beim Anlöten der Kabel an den Akku bewußt schwarz auf rot und rot auf schwarz löten müssen. Bei meinen gelieferten Kabeln war es auf jeden Fall so!


Bildbox (klick hier)

2.

Weiter geht es mit dem Einrichten der Uhrfunktion. Der Programmanfang stimmt mit dem in der vorherigen Anleitung überein ( wird am Ende noch einmal komplett zum Kopieren eingefügt). Ab Zeile 93 werden zwei Funktionen definiert, die den Bildschirm aufbauen.

  
  

93  def refresh():
94     # Hintergrundbildschirm
95     LCD.fill(LCD.black)
96     circle(120,120,114,LCD.beige)
97     circle(120,120,86,LCD.black)
98     circle(120,120,75,LCD.darkgray)
99     ring(step,ziel)
100     printstring("Schritte",90,90,1,LCD.white)
101     triangle2(x3,y3,x4,y4)
102     LCD.fill_rect(30,210,160,50,LCD.black)
103     triangle1(x1,y1,x2,y2)
104     # Spannung in % anzeigen anzeigen
105     LCD.rect(90,220,30,10,LCD.white)
106     LCD.rect(120,222,2,5,LCD.white)
107     LCD.fill_rect(92,222,24,6,LCD.glade)
108     reading = Vbat.read_u16()*3.3/65535*2
109     printstring(str(int(reading/4.5*100)) + " %",130,220,1,LCD.white)
110     LCD.show()
111
112 def ring(step,ziel):
113     for i in range (step*120/ziel):
114         xpos_neu = int(width/2 + 100*math.cos((i/2+15)*math.pi/30))
115         ypos_neu = int(height/2 + 100*math.sin((i/2+15)*math.pi/30))
116         circle(xpos_neu,ypos_neu,17,LCD.red)
117         time.sleep(0.01)
118         LCD.show()
  

Danach werden Werte aus der Datei 'last_time.txt' vom Pico-Laufwerk gelesen. Darin ist die Stunde und Minute der letzten bekannten Uhrzeit und die Anzahl der Schritte abgelegt. In diesem Teil des Programms wird auch ermittelt, ob der Pico am PC angeschlossen ist. Wenn ja, liefert 'time.localtime()' die aktuelle Uhrzeit an das Tupel 'current_time'. Diese wird in den Zeilen 141 bis 150 sofort neu in die Datei gespeichert. Ist hingegen 'current_time[0]=2021', dann bedeuted das, dass der Pico ohne Rechneranschluss gestartet wurde. 'time.localtime()' beginnt in diesem Fall am 1.1.2021 die Sekunden zu zählen. Für die Stunde und die Minuten wird dann die letzte bekannte Zeit verwendet. Wenn man also den USB Anschluss des Pico vom Rechner abzieht und innerhalb einer Minute an eine andere Spannungsversorgung anklemmt, verliert man max. eine Minute, die man ja im Bereich der Zeilen 151 bis 157 hinzuaddieren könnte. Ist hingegen der Akku angeschlossen, kommt es zu keiner Unterbrechung, also auch zu keinem Zeitverlust, da der Timer nicht neu startet.

  
  

134 # Schritte auslesen
135 with open("last_time.txt", "r") as f:
136     hour = int(f.readline())
137     minute = int(f.readline())
138     step = int(f.readline())
139 f.close()
140
141 current_time = time.localtime()
142 hour = current_time[3]
143 minute = current_time[4]
144 second = current_time[5]
145 if current_time[0] > 2021:
146     with open("/last_time.txt", "w") as f:
147         f.write(str(hour)+"\n")
148         f.write(str(minute)+"\n")
149         f.write(str(step))
150     f.close()
151 if current_time[0] == 2021:
152     with open("last_time.txt", "r") as f:
153         hour = int(f.readline())
154         minute = int(f.readline())
155         step = int(f.readline())
156     f.close()
157     second = current_time[5]
158
159 refresh()
160 start = time.ticks_ms()
  

3.

In Zeile 160 wird die Variable Start mit time.ticks_ms() gesetzt. Damit wird später in der while Schleife nach 5 Minuten (300 s) der Bildschirm refreshed, wodurch wieder der aktuelle Batteriezustand angezeigt wird. In der 'while' Schleife erfolgt dann das Auslesen des Sensors und die Zeitanzeige. Wenn die Sekunde 59 erreicht ist, wird hochgezählt und die Stunde, Minute und Schritte in der Datei aktualisiert. Damit der Speichervorgang in der Sekunde 59 nicht mehrfach ausgeführt wird, ist in Zeile 194 eine Pause von 1s, die aber auf den Sekundentakt von 'time.localtime()' keinen Einfluss hat. Es kommt also nicht zu einer Zeitverspätung.

  
  

181     if second == 59:
182         printstring(zeit,50,120,3,LCD.darkgray)
183         minute += 1
184         if minute == 60:
185             minute = 0
186             hour += 1
187             if hour == 24:
188                 hour = 0
189         with open("/last_time.txt", "w") as f:
190             f.write(str(hour)+"\n")
191             f.write(str(minute)+"\n")
192             f.write(str(step))
193         f.close()
194         time.sleep(1)
195     zeit = str(hour) + ":" + str(minute)
196     if minute < 10:
197         zeit = str(hour) + ":0" + str(minute)
198     printstring(zeit,50,120,3,LCD.white)
199     meter = int(step * 0.762)
200     printstring(str(meter)+" m",105,175,1,LCD.white)
201     #cal = int(int(step * 0.38)*4.18)/1000
202     cal = int(int(step * 0.38)*4.18)
203     printstring(str(cal)+" J",105,190,1,LCD.white)
204     if second < 10:
205         printstring(":0" + str(second),157,123,2,LCD.white)
206     else:
207         printstring(":" + str(second),157,123,2,LCD.white)
208    LCD.show()
  

In den Zeilen 209 bis 236 wird die Bewegung des Sensors, wie bereits aus der 1. Anleitung bekannt, erfasst. Wie versprochen gebe ich jetzt noch einmal den kompletten Programmcode zu Kopieren an. Klicken Sie dazu auf die Schaltfläche 'Code kopieren' und setzen ihn im Thonny ein. Bevor Sie das Programm starten, stellen Sie sicher, dass sich die Dateien init_lcd_1_28.py, font.py und last_time.txt auf dem Picolaufwerk befinden. Die beiden ersten Dateien können Sie noch einmal hier herunterladen . Die Textdatei legen Sie einfach im Thonny an, indem Sie auf Datei hinzufügen klicken, dann eine Stunde[Enter]Minute [Enter]Schritte[Enter] eingeben und unter dem o.g. Namen speichern.


Updated : 15.08.2023
- Batterieanzeige in extra Funktion und Prozentanzeige bezogen auf die Abschaltspannung (< 3.3 V).

  
  

1   # SPDX-FileCopyrightText: 2023 Detlef Gebhardt, written for MicroPython
2   # SPDX-FileCopyrightText: Copyright (c) 2023 Detlef Gebhardt
3   #
4   # SPDX-License-Identifier: GEBMEDIA
5   from machine import Pin,I2C,SPI,PWM,ADC
6   import framebuf
7   import time
8   import init_lcd_1_28
9   import font
...
...
...
235         printstring(":" + str(second),157,123,2,LCD.white)
236     if step == ziel:
237         alpha = 1
238         refresh()
239     LCD.show()
240    time.sleep(0.2)
  




Viel Spass und Erfolg beim Ausprobieren.