RailFX: Arduino Bahnhof

Dieses Modul des RailFX-Systems steuert einen Arduino Bahnhof für die Modellbahn. Zu den Funktionen zählten: OLED-Abfahrtsanzeiger mit wechselnden Inhalten Zufalls- oder sensorgesteuerte Umschaltung des Displays Sound-Modul mit Ansagen der »Blechelse« Bahnhofsbeleuchtung mit Leuchtstoffröhren-Einschalteffekt Schaltplan D2, D3: DFPlayer MP3 Modul D4 – D12: LEDs als Leuchtstoffröhren A0 (D14) und A1 (D15) Lichtschranken für Zugdetektion A3: Anschluss des Zeitsignals des Conrol-Moduls A4, A5: I2C Verbindung zum OLED-Display Achtung: Am Pin A3 (normalerweise A4, aber hier A3) wird das Control-Signal des RailFX Control-Moduls angelegt. Es steuert die Tageszeit und ist zwingend erforderlich. Bauteile Arduino Bahnhof 1x LED-Set 1x OLED-Display 1x Elektrolytkondensator (100 – 470µF) DFPlayer Mini MP3 Player Modul (Bitte nicht das ähnlich aussehende MP3-TP-16P Modul kaufen) MicroSD-Karte Lautsprecher 2x TCRT5000 Lichtschranken 1x 1kOhm Widerstand Einstellungen im Code Auch dieses Modul bietet eine Reihe von Einstellmöglichkeiten. Die Beleuchtung des Bahnhofes kann beim Einschalten wie Leuchtstoffröhren flackern. Die Zeit, die alle Lampen zum Einschalten kann man mit der Variable flackerzeitLeuchten einstellen. Je höher der Wert ist, desto länger flackern die Leuchten. Wie heftig sie flackern lässt sich mit der Variable flackerGeschwindigkeit einstellen. Die Anzeigen auf dem OLED-Display wechseln sich entweder per Zufall oder per Lichtschranken, je nachdem, ob man die Methode anzeigeTafelAutomatisch() oder anzeigeTafelSensor() im Loop anspricht. Im Lichtschranken-Modus wechselt sich die Anzeigt, sobald beide Sensoren freigegeben werden, also, wenn sich kein Zug mehr auf dem Gleis befindet. Im automatischen Modus kann man die folgenden Einstellungen vornehmen: Die minimale Dauer pro Anzeige lässt sich mit der Variable anzeigenWechselMin einstellen. Zu ihr wird per Zufall eine Zeit zwischen 0 und dem in der Variable anzeigenwechselVariableZeit festgelegten Wert addiert. Die Texte auf dem Display werden im Array textSegments festgelegt. Es lässt sich durch weitere Texte erweitern. Dafür müssen die Dimensionen im Array und die Variable anzeigeAnzahl angepasst werden. Das Display zeigt automatisch beim Umschalten die aktuelle Modellbahnzeit an. Die Folgezüge werden im 30-Minuten-Takt angezeigt. Ist die aktuelle Zeit also 17:21, werden die Abfahrtszeiten der Folgezüge 17:51 und 18:21 angezeigt. Per Zufall zeigt das Display auch einen Hinweis an. Den Text kann man in der Variable hinweis anpassen. Für die Tonausgabe wird der DFPlayer Mini verwendet. Er spielt MP3- und WAV-Dateien von einer SD-Karte ab. Für die Nutzung muss die DFPlayer Mini Bibliothek eingebunden werden. Klicke dafür im Arduino-Menü auf Sketch>Bibliotheken einbinden>Bibliotheken verwalten und gib im Suchfeld »dfplayer mini« ein. Installiere die Bibliothek DFPlayer Mini MP3 by Makuna in der aktuellen Version. Die SD-Karte muss im FAT16 oder FAT32-Dateisystem formatiert sein. Darüber hinaus müssen sich die Dateien im Ordner »01« befinden und die Dateinamen müssen aufeinander folgend 001.mp3, 002.mp3, 003.mp3 usw. benannt sein. Wie erwähnt, dürfen auch WAV-Dateien verwendet werden: 001.mp3, 002.wav, 003.mp3 Beispiel-Dateien können hier heruntergeladen werden: MP3 Daten herunterladen /* ***** ***** Einstellungen ***** ***** */ int flackerzeitLeuchten = 1000; // Je höher der Wert, desto mehr flackern die Leuchtstoffröhren beim Einschalten int flackerGeschwindigkeit = 100; // Flackergeschwindigkeit der Leuchtstoffröhren int anzeigenWechselMin = 2000; // Anzeigewechsel alle x Millisekunden int anzeigenwechselVariabeleZeit = 3000; // Um diesen Wert (Millisekunden) variiert der Anzeigewechsel int mp3Anzahl = 10; // Menge der MP3 Dateien auf der SD-Karte int mp3Dauer[] = {16,16,15,17,17,18,19,18,19,9}; // Dauer der MP3 Dateien in Sekunden int mp3Wahrscheinlichkeit = 20; // Wahrscheinlichkeit, mit der MP3s abgespielt werden, 10 oft, 100 selten int lautstaerke = 10; // Lautstärke des DFPlayers (0 – 30); /* Anzeigen */ int anzeigeAnzahl = 6; // Muss so groß sein, wie die Anzahl der angezeigten Texte aus dem Array textSegments const char* textSegments[6][9] = { {"12", "", "Zugdurchfahrt", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Hannover Hbf", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Berlin Hbf", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Dresden Hbf", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Leipzig Hbf", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Hamburg Hbf", "17:08", "17:44", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"} }; const char* hinweis[] = { "Aufgrund einer Signalstorung ", "hat der ICE100 heute leider ca. 25 Minuten Verspatung. ", "Wir bitten um Ihr Verstandnis." }; Code für das Modul: RailFX-Bahnhof Libraries Für dieses Projekt wird dieSSD1306Ascii Bibliothek von Bill Greiman benötigt. Man kann sie hinzufügen, indem man im Arduino Menü > Sketch > Bilbiothek hinzufügen > Bibliotheken verwalten nach »SSD1306Ascii« sucht und die aktuelle Version installiert. Darüber hinaus wird die Bibliothek DFRobotDFPlayerMini von DFRobot verwendet. Auch diese installiert man über Bibliotheken verwalten. Hier kann man einfach nach dfplayer suchen. Beim Upload muss man darauf achten, dass das richtige Board im Arduino-Menü ausgewählt ist. Dazu muss ebenfalls im Werkzeuge-Menü im Unterpunkt Prozessor »ATmega328P (Old Bootlaoder)« ausgewählt sein. Ansonsten kann man den folgenden Programmcode mit den oben erwähnten Änderungen einfach kopiert und auf das Arduino-Nano laden. #include <Wire.h> #include "SSD1306Ascii.h" #include "SSD1306AsciiWire.h" #include "SoftwareSerial.h" // Wird für den DFPlayer benötigt #include "DFRobotDFPlayerMini.h" // Wird für den DFPlayer benötigt /* Rail-FX Bahnhof StartHardware.org */ /* ***** ***** Einstellungen ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** ***** */ int flackerzeitLeuchten = 1000; // Je höher der Wert, desto mehr flackern die Leuchtstoffröhren beim Einschalten int flackerGeschwindigkeit = 100; // Flackergeschwindigkeit der Leuchtstoffröhren int anzeigenWechselMin = 2000; // Anzeigewechsel alle x Millisekunden int anzeigenwechselVariabeleZeit = 3000; // Um diesen Wert (Millisekunden) variiert der Anzeigewechsel int mp3Anzahl = 6; // Menge der MP3 Dateien auf der SD-Karte int mp3Dauer[] = {13, 16, 16, 10, 9, 9}; // Dauer der MP3 Dateien in Sekunden int mp3Wahrscheinlichkeit = 10; // Wahrscheinlichkeit, mit der MP3s abgespielt werden, 10 oft, 100 selten int lautstaerke = 10; // Lautstärke des DFPlayers (0 – 30); int empfangsPuffer = 55; // Ändern der Anzeige kann das Empfangen des Zeitsignals verhindern. Deshalb werden ab dieser Modellbahn-Minute keine Displayänderungen ausgeführt (muss kleiner als 59 sein) /* Anzeigen */ int anzeigeAnzahl = 6; // Muss so groß sein, wie die Anzahl der angezeigten Texte aus dem Array textSegments const char* textSegments[6][7] = { {"12", "", "Zugdurchfahrt", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Hannover Hbf", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Berlin Hbf", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Dresden Hbf", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Leipzig Hbf", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"}, {"12", "Leipzig Hbf - Halle (Saale)", "Hamburg Hbf", "RB31", "RB31", "Elsterw-Biehal", "von Coswig (b. Dresde"} }; const char* hinweis[] = { "Auf Grund einer Signalstorung ", "hat der ICE100 heute leider ca. 25 Minuten Verspatung. ", "Wir bitten um Ihr Verstandnis." }; /* ***** ***** Ab hier beginnt der Programmcode, der nicht angepasst werden muss ***** ***** ***** ***** */ // 0X3C+SA0 - 0x3C or 0x3D #define I2C_ADDRESS 0x3C uint32_t tickTime = 0; int tickerPosition = 0; #define RTN_CHECK 1 int leuchtstoffroehrenPins[9] = {4, 5, 6, 7, 8, 9, 10, 11, 12}; int sensorPin1 = 15; // an diesem Pin ist ein Abstandssensor angeschlossen (15 = A1) int sensorPin2 = 16; // an diesem Pin ist ein Abstandssensor angeschlossen (16 = A2) int sensor1Zustand = 0; // speichert den aktuellen Zustand des Sensors int sensor1ZustandAlt = 0; // macht den Zustand des Sensors nach dem Neueinlesen verfügbar int sensor2Zustand = 0; // speichert den aktuellen Zustand des Sensors int sensor2ZustandAlt = 0; // macht den Zustand des Sensors nach dem Neueinlesen verfügbar /* Speicher Variablen */ int leuchtstoffroehrenZustand[9] = {1, 1, 1, 1, 1, 1, 1, 1, 1}; TickerState state; // Speichert den aktuellen Text-Pointer des OLED-Tickers int verspaetung = 0; // wird per Zufall ermittelt; 1=Verspätung, 0=keine Verspätung int anzeigenwechselVariabeleZeitHilfsvariable = 0; /* Timer Variablen */ long leuchtstoffroehrenTimer[9]; long anzeigeTimer; /* Variablen für das OLED */ SSD1306AsciiWire oled; /* Variablen für den MP3 Player*/ long soundTimer = 0; // Timer des DFPlayers long soundTimeout = 0; // Speichert die Abspieldauer des aktuellen MP3 int soundState = 0; // Status des DFPlayers int soundRandom; int theSound; int soundPlaying = false; SoftwareSerial mySoftwareSerial(3, 2); // RX, TX für den DFPlayer DFRobotDFPlayerMini myDFPlayer; // DFPlayer Objekt /* Variablen vom Controlmodul um die Uhrzeit festzustellen*/ boolean receive = false; boolean receiveStarted = false; int receiveTimeout = 10; long receiveTimer = 0; int receivedTime = 0; int receivePulse = 0; int lastReceivePulse = 0; int receivePin = 17; int myTime = 8; int myMinutes = 0; long lastTimeSignal; int timeToHour; #define PAYLOAD_SIZE 2 // nötig für die Kommunikation zum Master int uhrzeit = 0; // speichert die uhrzeit vom Master-Modul (0 und 255) byte nodePayload[PAYLOAD_SIZE]; // speichert die Daten vom Master-Modul zwischen void setup() { Serial.begin(115200); // started die serielle Kommunikation pinMode(receivePin, INPUT); // Empfangspin vom Control-Modul Wire.begin(); // I2C Verbindung zum OLED Wire.setClock(400000L); // I2C Verbindung zum OLED mySoftwareSerial.begin(9600); // started die serielle Kommunikation für den DFPlayer oled.begin(&Adafruit128x64, I2C_ADDRESS); // Start des OLEDs for (int i = 0; i < 9; i++) { pinMode(leuchtstoffroehrenPins[i], OUTPUT); digitalWrite(leuchtstoffroehrenPins[i], HIGH); } randomSeed(A2); oled.tickerInit(&state, Adafruit5x7, 0, false, 27, 100); // Ticker für die Anzeigetafel drawInfo(1); /* DFPlayer Setup */ Serial.println(F("Initializing DFPlayer ... ")); if (!myDFPlayer.begin(mySoftwareSerial, false)) { // nutze softwareSerial um mit dem DFPlayer zu sprechen Serial.println(F("Fehler: Prüfe Verbindung zum DFPlayer und SD-Karte")); /*while (true) { delay(0); // Code to compatible with ESP8266 watch dog. }*/ } Serial.println(F("DFPlayer Mini online.")); myDFPlayer.volume(lautstaerke); // Lautstärke wird zugewiesen delay(1000); pinMode(sensorPin1, INPUT_PULLUP); pinMode(sensorPin2, INPUT_PULLUP); } void loop() { receiveFunction(); // Führe Anweisungen für Empfang aus if (receiveStarted == false) { // Falls gerade keine Daten empfangen werden: if (myTime > 22) { // ***** Später Abend ***** leuchtstoffroehrenEin(); // Leuchtstoffröhren einschalten soundAn(); // Sound An } else if (myTime > 18) { // ***** Abend ***** leuchtstoffroehrenEin(); // Leuchtstoffröhren einschalten soundAn(); // Sound An } else if (myTime > 12) { // ***** Nachmittag ***** leuchtstoffroehrenAus(); // Leuchtstoffröhren ausschalten soundAn(); // Sound An } else if (myTime > 9) { // ***** Vormittag ***** leuchtstoffroehrenAus(); // Leuchtstoffröhren ausschalten soundAn(); // Sound An } else if (myTime > 7) { // ***** Morgen ***** leuchtstoffroehrenAus(); // Leuchtstoffröhren einschalten soundAn(); // Sound An } else if (myTime > 0) { // ***** Nacht ***** leuchtstoffroehrenEin(); // Leuchtstoffröhren einschalten soundAus(); // Sound Aus } if (myMinutes < empfangsPuffer) { anzeigeTafelSensor(); // Anzeigetafel schaltet per Sensor um // anzeigeTafelAutomatisch(); // Anzeigetafel schaltet per Zufall um } } } void anzeigeTafelSensor() { sensor1Zustand = digitalRead(sensorPin1); sensor2Zustand = digitalRead(sensorPin2); //Serial.print("Sensor 1: ");Serial.print(sensor1Zustand);Serial.print("\t Sensor 2: ");Serial.println(sensor2Zustand); int i; if ((sensor1Zustand == 1) && (sensor2Zustand == 1)) { // Gleis leer if ((sensor1ZustandAlt == 0) || (sensor2ZustandAlt == 0)) { // Vorher Gleis besetzt i = random(anzeigeAnzahl); drawInfo(i); verspaetung = random(2); } } if ((verspaetung > 0) && (i != 0)) { if (tickTime <= millis()) { tickTime = millis() + 30; oled.setInvertMode(1); int8_t rtn = oled.tickerTick(&state); if (rtn <= RTN_CHECK) { oled.tickerText(&state, hinweis[(tickerPosition++) % 3]); } } } sensor1ZustandAlt = sensor1Zustand; sensor2ZustandAlt = sensor2Zustand; } void anzeigeTafelAutomatisch() { int i; if (anzeigeTimer + anzeigenWechselMin + anzeigenwechselVariabeleZeitHilfsvariable < millis()) { // der zweite Teil verhindert, dass ein Anzeigewechsel dem Empfang des Zeitsignals blockiert anzeigeTimer = millis(); i = random(anzeigeAnzahl); drawInfo(i); verspaetung = random(2); anzeigenwechselVariabeleZeitHilfsvariable = random(anzeigenwechselVariabeleZeit); } if ((verspaetung > 0) && (i != 0)) { if (tickTime <= millis()) { tickTime = millis() + 30; oled.setInvertMode(1); int8_t rtn = oled.tickerTick(&state); if (rtn <= RTN_CHECK) { oled.tickerText(&state, hinweis[(tickerPosition++) % 3]); } } } } void drawInfo(int i) { // OLED Ausgabe oled.clear(); oled.setInvertMode(0); oled.setCursor(0 , 0); oled.setFont(Callibri15); oled.println(textSegments[i][0]); oled.clearToEOL(); oled.setCursor(104 , 0); oled.setFont(Callibri10); oled.println(makeTime()); oled.clearToEOL(); oled.setFont(Callibri10); oled.setCursor(27 , 1); oled.println(textSegments[i][1]); oled.setFont(Callibri14); oled.setCursor(27 , 2); oled.println(textSegments[i][2]); oled.setFont(Callibri10); oled.setCursor(0 , 5); oled.println(makeTime1()); oled.setCursor(0 , 6); oled.println(makeTime2()); oled.setCursor(27 , 5); oled.println(textSegments[i][3]); oled.setCursor(27 , 6); oled.println(textSegments[i][4]); oled.setCursor(54 , 5); oled.println(textSegments[i][5]); oled.setCursor(54 , 6); oled.println(textSegments[i][6]); } String makeTime() { String myTimeString = ""; int myHoursSub = myTime; int myMinutesSub = myMinutes; if (myHoursSub < 10) myTimeString = " " + String(myHoursSub); else myTimeString = String(myHoursSub); if (myMinutesSub < 10) myTimeString += ":0" + String(myMinutesSub); else myTimeString += ":" + String(myMinutesSub); return myTimeString; } String makeTime1() { // Nächster Zug String myTimeString = ""; int myHoursSub = myTime; int myMinutesSub = myMinutes; //int myMinutesSub1=random(30); if (myMinutesSub > 29) { if (myHoursSub > 22) myHoursSub = 0; else myHoursSub++; } else { myMinutesSub += 30; } if (myHoursSub < 10) myTimeString = " " + String(myHoursSub); else myTimeString = String(myHoursSub); if (myMinutesSub < 10) myTimeString += ":0" + String(myMinutesSub); else myTimeString += ":" + String(myMinutesSub); return myTimeString; } String makeTime2() { // Übernächster Zug String myTimeString = ""; int myHoursSub = myTime; int myMinutesSub = myMinutes; if (myHoursSub >= 23) myHoursSub = 0; else myHoursSub++; if (myHoursSub < 10) myTimeString = " " + String(myHoursSub); else myTimeString = String(myHoursSub); if (myMinutesSub < 10) myTimeString += ":0" + String(myMinutesSub); else myTimeString += ":" + String(myMinutesSub); return myTimeString; } void leuchtstoffroehrenEin() { for (int i = 0; i < 9; i++) { if (random(flackerzeitLeuchten) == 0) leuchtstoffroehrenZustand[i] = 0; if (leuchtstoffroehrenZustand[i] != 0) { // wenn die Röhre nicht eingeschaltet ist if (leuchtstoffroehrenZustand[i] + leuchtstoffroehrenTimer[i] < millis()) { leuchtstoffroehrenZustand[i] = random(flackerGeschwindigkeit) + 20; // erzeugt eine Timeout-Variable leuchtstoffroehrenTimer[i] = millis(); int myOutput = random(2); digitalWrite(leuchtstoffroehrenPins[i], myOutput); } } else { digitalWrite(leuchtstoffroehrenPins[i], 0); } } } void leuchtstoffroehrenAus() { for (int i = 0; i < 9; i++) { leuchtstoffroehrenZustand[i] = 1; digitalWrite(leuchtstoffroehrenPins[i], HIGH); } /*if (random(ausschaltWahrscheinlichkeit) == 1) { // Einschalten der Leuchtstoffröhren per Zufall int thePin = random(10); digitalWrite(leuchtstoffroehrenPins[thePin], HIGH); leuchtstoffroehrenZustand[thePin] = 0; }*/ } void soundAn() { switch (soundState) { case 0: Serial.println("soundTimer 0"); soundRandom = random(mp3Wahrscheinlichkeit); if (soundRandom < 1) { soundState = 1; theSound = random(mp3Anzahl) + 1; soundTimer = millis(); soundTimeout = mp3Dauer[theSound - 1] * 1000; Serial.print("Playsound: \t\t\t"); Serial.print(theSound); Serial.print("\t\t\t"); Serial.println(soundTimeout); myDFPlayer.playFolder(1, theSound); //play specific mp3 in SD:/15/004.mp3; Folder Name(1~99); File Name(1~255) soundPlaying = true; } else { soundTimer = millis(); soundTimeout = 500; soundState = 1; } break; case 1: if (soundTimer + soundTimeout < millis()) { soundPlaying = false; soundState = 0; } break; } } void soundAus() { if (soundPlaying == true) { Serial.println(soundPlaying); myDFPlayer.pause(); soundPlaying = false; } } void receiveFunction() { // Empfängt die Uhrzeit vom Control-Modul receivePulse = digitalRead(receivePin); // Lies den Empfangspin aus if ((receiveTimer + receiveTimeout < millis()) && (receiveStarted == true)) { // Bei Timeout und aktivem Empfang receiveStarted = false; // beende aktiven Empfang myTime = receivedTime - 1; // speichere die empfangene Zeit receivedTime = 0; // setze die Hilfsvariable zum Zeitempfang zurück timeToHour = millis() - lastTimeSignal; lastTimeSignal = millis(); } // falls ein Puls am Empfangspin erfasst wird, der vorher nicht da war if ((receivePulse == 0) && (lastReceivePulse == 1)) { receiveTimer = millis(); // starte Timer neu if (receiveStarted == false) receiveStarted = true; // starte aktiven Empfang, wenn noch nicht geschehen receivedTime++; // es gab einen Puls, also erhöhe die Hilfsvariable zum Zeitempfang } lastReceivePulse = receivePulse; // aktuellen Zustand am Pin für nächsten Durchlauf merken if (receiveStarted == false) { if (millis() % 100 < 2) { int myNewMinutes = map(millis() - lastTimeSignal, 0, timeToHour, 0, 59); myNewMinutes = constrain(myNewMinutes, 0, 59); if (myNewMinutes != myMinutes) { Serial.print(myTime); Serial.print(":"); Serial.print(myMinutes); Serial.print("\t"); Serial.println(myTime); } myMinutes = myNewMinutes; } } } Alle RailFX-Module Ansehen » Der Beitrag RailFX: Arduino Bahnhof erschien zuerst auf Arduino Tutorial.

zum Artikel gehen

Sende a message from arduino nano to raspberry pi via 433 mhz rf module

I want to make a data transfer circuit using Arduino nano and Raspberry Pi. It will be done using 433 mhz rf module. If the password sent by Arduino is correct, Raspberry Pi will respond with a message stating the correct password... (Budget: $10 - $11 US

zum Artikel gehen

Mit Arduino Bewegungs- und Orientierungssensoren in Systeme integrieren

Entwickler müssen ihre Systeme zunehmend mit Orientierungs- und Bewegungsfunktionen ausstatten, sind aber unsicher, wo sie anfangen sollen. Ein Arduino könnte dabei helfen.

zum Artikel gehen

heise+ | Spracherkennung mit Arduino nano connect realisieren

Spracherkennung mit einem Arduino, das war bislang mangels Rechenpower unvereinbar. Doch der Nano RP2040 connect soll das packen. Wir zeigen, wie es geht.

zum Artikel gehen

Wokwi: Web-Simulator, etwa für Raspberry Pi Pico, Arduino und ESP32

Mit dem Online-Simulator Wokwi lassen sich Mikrocontroller-Projekte mit Raspberry Pi Pico, Arduino, ESP32 und weiteren Boards sowie Sensoren im Web-Browser simulieren.

zum Artikel gehen

Bauteile für Arduino – Hier bekommst du Nachschub

Bauteile für Arduino zu beschaffen kann eine Herausforderung darstellen. Besonders, wenn man gerade damit anfängt, scheitert man oft an Kleinigkeiten, wie dem speziellen Widerstandswert, den man noch nicht vorrätig hat. Doch woher bekommt man Teile und wa

zum Artikel gehen