Das Waveshare RP2040-GEEK Entwicklungsboard basiert auf dem RP2040 Mikrocontroller, mit 1.14 Zoll 65K Farb-LCD, TF-Kartensteckplatz, USB-Debugging-Downloader,
im weißen Kunststoffgehäuse. Darüber hinaus ist es ausgestattet mit einem USB-A-Interface. Es bietet verschiedene Firmware für
SWD-Port, UART-Port und I2C-Port. An der vierpoligen I2C/ADC Buchse ist der GPIO 28 nach außen geführt. Was der Pico-Geek nicht besitzt,
sind Tasten für direkte Eingaben. Damit könnte man z.B. einen Pin eingeben, um etwas freizuschalten o.ä. In
diesem Beitrag habe ich gezeigt, dass man mit dem
analogen Keyboard Modul bei nur einem ADC-Port viele neue Möglichkeiten hat.
Hardware
- Pico-Geek (z.B. von Botland )
- Analoges Keyboard Modul mit fünf Tasten(z.B. von Funduino )
Software
- aktuelle Firmware Arduino IDE
Am Ende dieses Beitrags sollen Sie in der Lage sein, einen selbst gewählten sechsstelligen Pin in den EEPROM des Pico-Geek zu schreiben, der
bei jeder Inbetriebnahme ausgelesen wird. Sie merken sich den, nur Ihnen bekannten Pin, und geben ihn auf Anforderung ein. Stimmt er mit dem
abgespeicherten überein, dann wird eine 'Aktion' freigeschaltet.
Zuerst zeige ich, wie Sie den EEPROM beschreiben bzw. auslesen. Der Raspberry Pi Pico RP2040 hat keinen integrierten EEPROM-Speicher, sondern
nutzt dafür einen Teil des Flash-Speichers. Deshalb muss dieser Bereich zunächst festgelegt werden. Ausserdem ist es wichtig, dass man den
Schreibvorgang mit 'EEPROM.commit()' abschließt. Die meisten 'Hilferufe' im Netz, dass es nicht funktioniert, haben diesen Fehler. Hier ist der
Quellcode, um sechs Werte (unseren Pin) zu schreiben. Die Pause in Zeile 15 gibt Ihnen Zeit, nach dem Hochladen in den seriellen Monitor zu wechseln,
um die Ausgabe zu sehen. Die Loop-Schleife (30, 31) ist leer, muss aber vorhanden sein, damit fehlerfrei kompiliert wird.
1 #include <EEPROM.h>
2
3 // ================= EEPROM Layout =================
4 #define EEPROM_SIZE 512
5 #define EEPROM_PIN_START 0
6
7 int a = 0;
8 int valEE;
9
10 // Pin festlegen
11 int myPin[6] = {6,5,4,3,2,1};
12
13 void setup(){
14 Serial.begin(9600);
15 delay(5000);
16
17 EEPROM.begin(EEPROM_SIZE);
18
19 Serial.print("EEPROM schreiben\n");
20 for (a = 0; a < 6; a++){
21 // Adresse mit Adresswert beschreiben
22 EEPROM.write(EEPROM_PIN_START + a, myPin[a]);
23 Serial.print(a+1);
24 Serial.print(" . Wert: ");
25 Serial.println(myPin[a]);
26 delay(100);
27 }
28 EEPROM.commit();
29 }
30 void loop(){
31 }
Mit diesem Quellcode wird also einmalig ein Pin '654321' in den Speicher geschrieben,
den Sie später durch einen eigenen ersetzen. Immer wenn Sie den Pin ändern wollen, führen Sie diesen kurzen
Sketch aus (d.h. in der Arduino-IDE öffnen und hochladen).
Nun zum Auslesen. Wichtig ist, dass der gleiche EEPROM Bereich
(Zeilen 4 u. 5) wie beim Schreiben genutzt wird. Damit die Zuordnung der gelesenen Werte funktioniert, wird in Zeile 8 ein 'leerer' Pin
definiert. Der Lesevorgang wird später in einen Sketch integriert, der mit einem einzugebenden Pin verglichen wird und den Geek
freischaltet bzw. sperrt.
1 #include <EEPROM.h>
2
3 // ================= EEPROM Layout =================
4 #define EEPROM_SIZE 512
5 #define EEPROM_PIN_START 0
6
7 // leeren Pin definieren
8 int myPin[6] = {0,0,0,0,0,0};
9
10 void setup(){
11 Serial.begin(9600);
12 delay(5000);
13
14 EEPROM.begin(EEPROM_SIZE);
15
16 Serial.print("EEPROM lesen\n");
17 for (int i = 0; i < 6; i++) {
18 int val = EEPROM.read(EEPROM_PIN_START + i);
19 Serial.print(val);
20 }
21 }
22 void loop(){
23 }
Im anschließenden Sketch wollen wir auch das Display des Pico-Geek verwenden. Dort soll beim Einschalten zur Eingabe des Pins aufgefordert werden. Mit den Tasten (SW2) 'hoch' und (SW3) 'runter' werden die einzelnen 'Digits' gewählt. Mit den Tasten (SW4) 'rechts' bzw. (SW1) 'links' ändert man die Cursorposition. Sichtbar ist immer nur das gerade bearbeitete 'Digit'. Alle anderen werden als Sternchen dargestellt. Zum Abschluss der Eingabe wird die Taste (SW5) 'OK' gedrückt. Im unteren Kasten sehen Sie den kompletten Quellcode:
1 #include <Adafruit_GFX.h>
2 #include <Adafruit_ST7789.h>
3 #include <SPI.h>
4 #include <Fonts/FreeSansBold12pt7b.h>
5 #include <EEPROM.h>
6
7 // ======== Display (Pins für Pico-Geek angepasst) ======
8 #define TFT_CS 9
9 #define TFT_RST 12
10 #define TFT_DC 8
11 #define TFT_BLK 13
12
13 // ================= Display & PinManager =================
14 Adafruit_ST7789 tft = Adafruit_ST7789(&SPI1, TFT_CS, TFT_DC, TFT_RST);
15
16 // ======== ADC Pin des Pico========
17 const int analogPin = 28;
18
19 // ================= EEPROM Layout =================
20 #define EEPROM_SIZE 512
21 #define EEPROM_PIN_START 0
22
23 // ======== Button Definition ========
24 enum Button {
25 BTN_NONE,
26 BTN_LEFT,
27 BTN_UP,
28 BTN_DOWN,
29 BTN_RIGHT,
30 BTN_OK
31 };
32
33 struct ButtonRange {
34 int minVal;
35 int maxVal;
36 Button button;
37 };
38
39 ButtonRange buttons[] = {
40 {0, 500, BTN_LEFT},
41 {1500, 4500, BTN_UP},
42 {5000, 7000, BTN_DOWN},
43 {10000, 15000, BTN_RIGHT},
44 {20000, 30000, BTN_OK}
45 };
46
47 const int buttonCount = sizeof(buttons) / sizeof(buttons[0]);
48
49 // ======== PIN System ========
50 int pinDigits[6] = {0,0,0,0,0,0};
51 int correctPin[6] = {0,0,0,0,0,0}; // Beispiel-PIN
52 int cursorPos = 0;
53 bool pinActive = true; // true = Eingabe aktiv
54
55 // ======== Button State ========
56 Button lastButton = BTN_NONE;
57
58 // ======================================================
59 // Setup
60 // ======================================================
61 void setup() {
62 Serial.begin(115200);
63 delay(300);
64
65 EEPROM.begin(EEPROM_SIZE);
66 // ======== PIN einlesen ===========
67 for (int i = 0; i < 6; i++) {
68 int val = EEPROM.read(EEPROM_PIN_START + i);
69 correctPin[i] = val;
70 }
71
72 SPI1.setSCK(10);
73 SPI1.setTX(11);
74 SPI1.begin();
75 // Auflösung Analogbereich: 0-65535
76 analogReadResolution(16);
77 // Anzeige vorbereiten und starten
78 tft.init(135,240);
79 tft.setRotation(1);
80 tft.fillScreen(ST77XX_BLACK);
81 tft.setFont(&FreeSansBold12pt7b);
82 tft.setCursor(50,30);
83 tft.setTextColor(ST77XX_YELLOW);
84 tft.print("Enter PIN");
85 drawPin();
86 }
87
88 // ======================================================
89 // Loop
90 // ======================================================
91 void loop() {
92 Button current = getButton();
93 // Flankenerkennung (nur bei neu gedrückter Taste reagieren)
94 if (current != BTN_NONE && lastButton == BTN_NONE) {
95 handleButton(current);
96 }
97 lastButton = current;
98 delay(30);
99 }
100
101 // ======================================================
102 // ADC ? Button
103 // ======================================================
104 Button getButton() {
105 int value = analogRead(analogPin);
106 for (int i = 0; i < buttonCount; i++) {
107 if (value >= buttons[i].minVal &&
108 value <= buttons[i].maxVal) {
109 return buttons[i].button;
110 }
111 }
112 return BTN_NONE;
113 }
114
115 // ======================================================
116 // Button Handling
117 // ======================================================
118 void handleButton(Button btn) {
119 switch (btn) {
120 case BTN_UP:
121 pinDigits[cursorPos]++;
122 if (pinDigits[cursorPos] > 9)
123 pinDigits[cursorPos] = 0;
124 break;
125 case BTN_DOWN:
126 pinDigits[cursorPos]--;
127 if (pinDigits[cursorPos] < 0)
128 pinDigits[cursorPos] = 9;
129 break;
130 case BTN_LEFT:
131 if (cursorPos > 0)
132 cursorPos--;
133 break;
134 case BTN_RIGHT:
135 if (cursorPos < 5)
136 cursorPos++;
137 break;
138 case BTN_OK:
139 checkPin();
140 return;
141 default:
142 break;
143 }
144
145 drawPin();
146 }
147
148 // ======================================================
149 // PIN prüfen
150 // ======================================================
151 void checkPin() {
152 bool correct = true;
153 for (int i = 0; i < 6; i++) {
154 if (pinDigits[i] != correctPin[i]) {
155 correct = false;
156 break;
157 }
158 }
159 // keine Digits mehr anzeigen
160 pinActive = false;
161 tft.fillScreen(ST77XX_BLACK);
162 tft.setCursor(50, 90);
163 if (correct) {
164 tft.setTextColor(ST77XX_GREEN);
165 tft.print("PIN OK");
166 // Hier kann später Aktion ausgelöst werden, z.B. HID senden
167 } else {
168 tft.setTextColor(ST77XX_RED);
169 tft.print("FALSCH");
170 }
171 delay(1500);
172 // Reset für neue Eingabe
173 pinActive = true;
174 cursorPos = 0;
175 for (int i = 0; i < 6; i++) pinDigits[i] = 0;
176 tft.fillScreen(ST77XX_BLACK);
177 tft.setCursor(50,30);
178 tft.setTextColor(ST77XX_YELLOW);
179 tft.print("Enter PIN");
180 drawPin();
181 }
182
183 // ======================================================
184 // Anzeige
185 // ======================================================
186 void drawPin() {
187 if (!pinActive) return;
188 int y = 90;
189 int digitWidth = 16; // Breite eines Digits
190 int digitHeight = 20; // Höhe des Digit-Bereichs
191 int spacing = 20; // Abstand zwischen Digits
192 int xStart = 50;
193 for (int i = 0; i < 6; i++) {
194 int drawX = xStart + i * spacing;
195 if (i == cursorPos) {
196 // Aktives Digit: kompletten Bereich löschen
197 tft.fillRect(drawX, y - 18, digitWidth, digitHeight + 6, ST77XX_BLACK);
198 // Zahl zeichnen
199 tft.setTextColor(ST77XX_YELLOW);
200 tft.setCursor(drawX, y);
201 tft.print(pinDigits[i]);
202 } else {
203 // Abgeschlossenes Digit als Sternchen darstellen
204 tft.fillRect(drawX, y - 16, digitWidth, digitHeight, ST77XX_BLACK);
205 tft.setTextColor(ST77XX_WHITE);
206 tft.setCursor(drawX, y);
207 tft.print("*");
208 }
209 }
210 }