Beruflich Dokumente
Kultur Dokumente
Auf der Platine ist ein Steckplatz für den ESP32 und ein 0,96“ OLED Grafik-Display (128x64 Pixel)
vorhanden. Ebenso sind vorhanden:
• Je eine rote LED (GPIO 32), grüne LED (GPIO 33), RGB-LED WS2812B an GPIO 26
• Zwei Taster (GPIO 2 und 4) und ein Touch-Feld (Touch T3, GPIO 15)
• Ein Drehencoder (GPIO 34 und 35) mit Taster (GPIO 0) und ein Poti (Analogeingang A0)
• Ein RS-485 Bustreiber an der 2. seriellen Schnittstelle (GPIO 16, 17) mit individuell
schaltbarem Sender (DE an GPIO13) und Empfänger (/RE an GPIO12) für Modbus RTU,
DMX512 etc. (Achtung: der Pin GPIO12 darf beim Booten nicht auf 1 gelegt werden!)
• Ein Steckplatz für I2C-Sensoren, ein Steckplatz für den RFID-Leser RC-522 (auch nutzbar für
SPI-Bus, One-Wire, 6 GPIO, DHT11/22),
• Ein analoger Eingang (Analogeingang A3) mit Anpassung für 0-5V Eingangsspannung.
Versorgung eines externen Sensors mit 3,3V oder 5V.
• Ein DCDC-Wandler (LM2596 Modul) ist optional bestückbar. Damit kann die Platine mit 7-
24V Gleichspannung versorgt werden. (Ausgangsspannung 5V unbedingt vor dem Auflöten
einstellen, sonst kann die RGB-LED beschädigt werden!)
Eine Anleitung zur Bestückung der Platine sowie Schaltplan und Layoutdaten sind unter der auf der
Platine aufgedruckten URL hinterlegt.
}
else {
digitalWrite(LED_rot, HIGH); // LED AUSschalten nicht
} // vergessen!
}
Linksdrehung Rechtsdrehung
Spur A
Spur B
Die Auswertung erfolgt hier mittels Flankenerkennung oder Interrupt bei der Spur A. Wenn eine
steigende Flanke erkannt wurde, wird auf die Spur B geschaut. Ein 0-Pegel bedeutet Rechtsdrehung,
ein 1-Pegel Linksdrehung (oder umgekehrt, bei Bedarf einfach anpassen!).
In dem Beispiel wird die Spur A mit Interrupt ausgewertet und eine Variable hoch oder runter gezählt.
Dabei wird für die Loop ein Signal gesetzt, wenn sich der Wert geändert hat. Die Ausgabe erfolgt über
die serielle Schnittstelle, öffnet unter Werkzeuge den Seriellen Monitor und stellt die Baudrate auf
115200 ein.
// ***** Portpins für Ein-/Ausgänge ***************************************
const int Enc_A=34, Enc_B=35, Enc_Taster=0;
// ***** Globale Variablen ************************************************
int Encoder, Status; // zur Kommunikation zw. ISR und loop
// ***** Initialisierung **************************************************
void setup() {
pinMode(Enc_A, INPUT); // externe Pullups auf der Platine
pinMode(Enc_B, INPUT); // Spur B des Encoders
pinMode(Enc_Taster, INPUT); // Taster des Encoders = Flash-Taster!
Serial.begin(115200); // Serielle Schnittstelle mit 115200Bit/s
attachInterrupt(digitalPinToInterrupt(Enc_A), Auswertung, RISING);
// ISR void Auswertung(void)
Encoder = 0;
Status = 0;
}
Das serielle Terminal in Arduino wird über Werkzeuge/Serieller Monitor oder das Lupen-Icon oben
rechts gestartet. Bei ersten mal muss im Terminal (nicht bei Werkzeuge/Upload-Speed!) die Baudrate
ebenfalls auf den programmierten Wert (hier 115200 Bit/s) eingestellt werden.
Im ersten Beispiel wird ein Wert einer Variablen gesendet
int Zahl=0;
void setup() {
Serial.begin(115200); // Serielle Schnittstelle initialisieren
delay(2000); // etwas Zeit zum Öffnen des seriellen Monitors
Serial.println("Serielle Datenübertragung");
}
void loop() {
Serial.print("Aktueller Wert: "); // keine Zeilenschaltung am Ende
Serial.println(Zahl); // Aktuellen Wert ausgeben, neue Zeile
Zahl ++; // hoch zählen
delay(1000); // 1 Sekunde warten
}
Zum Empfangen von Zeichen wird die Funktion Serial.available( ) aufgerufen, die prüft ob noch
Zeichen im Empfangspuffer vorhanden sind. Der Rückgabewert der Funktion ist die Anzahl an
vorhanden Zeichen.
char Zeichen;
void setup() {
Serial.begin(115200); // Serielle Schnittstelle initialisieren
Serial.println("Hallo Welt!");
}
void loop() {
if (Serial.available() > 0) { // Wurde etwas empfangen?
Zeichen = Serial.read(); // 1 Zeichen abholen
Serial.print(Zeichen); // Echo
}
}
Zum Steuern eines Mikrocontroller-Programms über das serielle Terminal denkt man sich einfache
Befehle aus, die über einen Buchstaben (ein ASCII-Zeichen) aufgerufen werden. Wenn Zahlenwerte
übergeben werden sollen, kann man die mit parseInt( ) aus den empfangenen Daten auslesen.
char Zeichen;
int Wert, Wert_neu;
void setup() {
Serial.begin(115200); // Serielle Schnittstelle initialisieren
Serial.println("Wert abfragen mit ?, neuer Wert z.B. mit w 1234");
}
void loop() {
if (Serial.available() > 0) { // Wurde etwas empfangen?
Zeichen = Serial.read(); // 1. Zeichen abholen
if (Zeichen == '?') { // Fragezeichen wurde empfangen
Serial.printf("Aktueller Wert %d \n", Wert); // hier mal mit printf
}
if (Zeichen == 'w') { // w empfangen, jetzt kommt eine Zahl
Wert_neu = Serial.parseInt(); // gibt 0 zurück, wenn keine Zahl ge-
if (Wert_neu != 0) Wert = Wert_neu; // funden wurde...
}
}
geschrieben werden. Für die Ausgabe auf dem Display ist danach immer die Funktion
display.display() aufzurufen.
#include <Wire.h>
#include "SSD1306Wire.h"
#define SCREEN_WIDTH 128 // OLED Display Breite, in Pixel
#define SCREEN_HEIGHT 64 // OLED Display Höhe, in Pixel
SSD1306Wire display(0x3c, 21, 22); // 21=SDA 22=SCL I2C-Bus Pins
void loop() {
static int gas, gas_new; // Messwerte des Gas-Sensors MQ-135 bzw. MQ-2
gas_new = map(analogRead(A3), 1900, 2100, 400, 800);// Sensor-Kennlinie
gas = ( gas_new * 40 + gas * 60 ) / 100; // Tiefpass-Filter
Serial.printf("Gas-Sensor MQ-135 CO2: %4d ppm\n", gas);
}
void loop() {
int Touchwert;
Touchwert = filter.in(touchRead(T3)); // Median Filter
if( Touchwert < 25 )
Serial.prinln("Touch erkannt");
delay(500);
}
0,0
2,61 Display
=
y
0,0 Messwert
127,63
Bild 3: Pixel-Koordinaten
In der Abbildung wird auch deutlich, dass Messwerte jetzt auf den Bereich von 0 (maximaler
Messwert) bis 61 (minimaler Messwert) abgebildet werden müssen. Dazu wird hier wieder die map-
Funktion genutzt. Zu Zeichnen des Koordinatensystems wird hier eine Funktion genutzt.
#include <Wire.h>
#include "SSD1306Wire.h"
#include <MedianFilter.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
SSD1306Wire display(0x3c, 21, 22); //21=SDA 22=SCL
MedianFilter filter(3, 100); // MedianFilter filterObject(size, seed);
//***** globale Variablen ***********************************************
long showtime, timeold, timenew, duration;
int x, y; // Pixel-coordinates for the display
Beachten Sie, dass die I2C-Bussignale des ESP32 nur 3,3V-Kompatibel sind. Sollte ein Sensor mit
5V Versorgungsspannung eingesetzt werden, muss ein Pegelwandler für die Busleitungen genutzt
werden, sonst kann der ESP32 beschädigt werden!
Schreibzyklus
Wire.beginTransmission ( I2C_Adresse );
Wire.write( Datenbyte ); // Datenbyte oder Registeradresse
Wire.endTransmission( );
Lesezyklus
byte Daten1, Daten2;
Wire.requestFrom ( I2C_Adresse, 2 ); // Baustein und Anzahl der Bytes
if( Wire.available( ) >= 2 ) {
Daten1 = Wire.read( );
Daten2 = Wire.read( );
}
Kombinierter Zyklus
byte Daten1, Daten2;
Wire.beginTransmission ( I2C_Adresse );
Wire.write( Registeradresse ); // Auswahl einer internen Registeradresse
Wire.endTransmission( false ); // true oder ( ) sendet ein Stop, false
// sendet kein Stop!
Wire.requestFrom ( I2C_Adresse, 2 );
if( Wire.available( ) >= 2 ) {
Daten1 = Wire.read( );
Daten2 = Wire.read( );
}
Bei der Arduino-Bibliothek wire.h muss die 7-Bit Bausteinadresse verwendet werden!
Beachten Sie, dass keine Adresskonflikte mit dem Display (Adresse 0x3C) oder extern
angeschlossenen I2C Sensoren bestehen. Es kommt dabei zu „Datensalat“ auf dem Bus.
Bei der ersten Platinenrevision ist die Buchse J4 um 180° gedreht und weiter unten platziert. Ein
RC522 mit abgewinkelten Kontakten kann aufgesteckt werden (am Poti wird es etwas eng), oder man
lötet die Pins am RC522 oben auf die Platine und steckt die Platine mit der Bauteilseite nach unten
auf. Ab der Platinenrevision 2 ist die Buchse gedreht, so dass die RC522-Platine mit der Bauteilseite
und Beschriftung nach oben aufgesteckt werden muss.
Für den RFID-Leser muss die Bibliothek MFRC522 installiert werden. Damit werden auch
verschiedene Beispielprogramme installiert. Diese erscheinen unter Datei/Beispiele/Beispiele aus
eigenen Bibliotheken/MFRC522. Hier wird nur auf die Pinbelegung des Reset und Slave-Select sowie
auf die Instanziierung des Leser-Objektes eingegangen. Die Pins für den SPI-Bus sind in der
Bibliothek festgelegt und müssen nicht deklariert werden.
Zur Erzeugung der PWM-Signale gibt es im ESP32 eine spezielle LED-Dimmerbaugruppe mit 16
Kanälen (0-15). Die Baugruppe kann PWM-Signale mit 8-16 Bit Auflösung erzeugen (entsprechend
256 bis 65536 Helligkeitsstufen bei der LED). Als Einschränkung muss beachtet werden, dass die
PWM-Frequenz * 2Auflösung <= 80MHz sein muss.
Für die Nutzung eines Dimmer-Kanals gibt es 3 Funktionen:
ledcSetup(Kanal, Frequenz, Auflösung); // Einstellung des Kanals
ledcAttachPin(Pin, Kanal); // stellt Verbindung in der Hardware her
ledcWrite(Kanal, Wert); // den Kanal, nicht den Pin schreiben!
// 0 <= Wert < 2^Auflösung
Beispiel: LED mit 100Hz, 12 Bit Auflösung, halben Maximalwert ausgeben
ledcSetup(0, 100, 12); // Einstellung des Kanals
ledcAttachPin(LED_rot, 0); // stellt Verbindung in der Hardware her
ledcWrite(0, 2048); // 12 Bit => 0-4095
Zur besseren Lesbarkeit sollte man für den Kanal (0-15) einen Namen definieren.
// ***** Portpins für Ein-/Ausgänge ***************************************
const int LED_rot=32, LED_gruen=33, Taster_L=2, Taster_R=4;
int Hell_1, Hell_2; // Variablen für den aktuellen Dimmer-Wert
#define LED0_Ch 0
#define LED1_Ch 1
void setup() {
pinMode(LED_rot, OUTPUT); // die LEDs beginnen danach
pinMode(LED_gruen, OUTPUT); // zu leuchten!
pinMode(Taster_L, INPUT_PULLUP); // Taster brauchen hier den
pinMode(Taster_R, INPUT_PULLUP); // Pullup-Widerstand
ledcSetup(LED0_Ch, 100, 12); // Einstellung von Kanal 0
ledcAttachPin(LED_rot, 0); // rote LED nutzt Kanal 0
ledcSetup(LED1_Ch, 100, 12); // Einstellung von Kanal 1
ledcAttachPin(LED_gruen, 1); // grüne LED nutzt Kanal 1
Hell_1 = 0;
Hell_2 = 0;
}
void loop() {
ledcWrite(LED0_Ch, 4095 - Hell_1); // LED ist LOW-Aktiv, daher umdrehen
ledcWrite(LED1_Ch, 4095 - Hell_2); // LED ist LOW-Aktiv, daher umdrehen
Hell_1 += 10; // Wert erhöhen
if( Hell_1 > 4095 ) Hell_1 = 0; // Maximalwert prüfen, 0 setzen
if ( digitalRead(Taster_R) == false ) { // low-aktiv, daher false
Hell_2 += 10; // LED heller
}
if ( digitalRead(Taster_L) == false ) { // low-aktiv, daher false
Hell_2 -= 10; // LED dunkler
}
Hell_2 = constrain( Hell_2, 0, 4095 ); // Wertebereich begrenzen
delay(50); // Wichtig, sonst läuft die Helligkeit bei langem
// Tastendruck zu schnell hoch!
}