Experimente mit dem Super Starterkit Teil 4 - Taster, Folientastatur und Joystick - AZ-Delivery
In diesem Beitrag geht es um die im Set enthaltenen Eingabeelemente. Entprellen von Tastern, Ermittlung der gedrückten Taste bei einer Tastenmatrix und zweidimensionale Analogeingabe mit dem Joystick.

Benötigte Hardware

Anzahl

Bauteil

Anmerkung

1

Super Starter Kit

 

1

9V-Blockbatterie oder 9V-Netzteil

optional

 

Einfacher Taster

Im Starterkit sind fünf dieser Taster enthalten. Drückt man auf den Knopf, werden die Anschlüsse 1 und 2 miteinander verbunden. Konstruktionsbedingt existiert jeder Anschluss zweimal.
Beim Schließen eines mechanischen Kontaktes kann es vorkommen, dass die Verbindung nicht gleich dauerhaft hergestellt, sondern wieder kurz unterbrochen wird. Man nennt das: Prellen. Bei der Verwendung eines Tasters mit einem Mikrocontroller muss das Prellen berücksichtigt werden.

LED mit Taster ein- und ausschalten

Im ersten Beispiel soll eine LED immer dann leuchten, wenn der Taster gedrückt wird. Diese Aufgabe kann auch ohne Mikrocontroller gelöst werden. Das Beispiel soll nur die Funktion digitalRead(Pinnummer); erklären.

 

Die Kathode der LED wird mit GND und die Anode über einen 1kOhm Widerstand mit dem Pin 3 verbunden. Der Taster wird ebenfalls mit GND und auf der anderen Seite mit Pin 2 verbunden.
Das Programm ist sehr einfach.

#define LED 3
#define  TASTER 2

Zuerst werden die verwendeten Pins definiert.

void setup() {
    pinMode(LED, OUTPUT);
    pinMode(TASTER, INPUT_PULLUP);
}

In der Setup-Funktion werden die Aufgaben der Pins festgelegt. Der Pin für den Taster wird als Input mit Pullup-Widerstand definiert. Das heißt der Eingang wird im Mikrocontroller über einen Widerstand mit +5V verbunden. Dadurch wird sichergestellt, dass der Pin auf +5V liegt, wenn der Taster nicht gedrückt ist. Wird der Taster gedrückt, wird der Pin mit GND verbunden.

void loop() {
    boolean on = ! digitalRead(TASTER);
    digitalWrite(LED, on);
}

In der Hauptschleife wird mit boolean on =  !digitalRead(TASTER); der invertierte Zustand des Pins eingelesen. Ist der Taster gedrückt liegt der Pin auf 0. Es wird also 0 oder false eingelesen. Durch den Negationsoperator „!“ wird der Wert umgekehrt und on wird true. Wenn jetzt on ausgegeben wird geht der Pin auf +5V und die LED leuchtet.

Etwas mehr Programmieraufwand erfordert es, wenn mit einem Taster die LED dauerhaft eingeschaltet und dauerhaft wieder ausgeschaltet werden soll. Dazu ist es notwendig, das Drücken des Tasters zu erkennen. Wird der Taster gedrückt, wechselt die Spannung am Pin von +5V auf 0V. Beim Loslassen wechselt die Spannung von 0V auf +5V.

#define TASTER 2
#define LED 3

Nachdem die verwendeten Pins definiert wurden, werden zwei globale Variablen definiert.

boolean led = false;
int cnt = 0;


Die Variable led speichert den aktuellen Zustand der LED. Die Variable cnt ist ein Zähler, der die Anzahl der Taster Betätigungen zählt.

void setup() {
  Serial.begin(9600);
  pinMode(TASTER, INPUT_PULLUP);
  pinMode(LED, OUTPUT);
}

In der setup Funktion wird die serielle Schnittstelle initialisiert und der Pin-Modus definiert

void loop() {
  if (digitalRead(TASTER) == 0) {
    delay(10);
    if (digitalRead(TASTER)==1) {
      led = !led;
      cnt++;
      Serial.println(cnt);
    }
    digitalWrite(LED,led);
  }
}

In der Hauptschleife wird eine Änderung am Taster-Pin ermittelt. Immer wenn der Taster gedrückt also 0 ist, wird nach einer Verzögerung von 10 ms der Zustand erneut gelesen. Ist er jetzt auf 1, so wurde der Taster losgelassen. Damit wurde die Flanke von 0 nach 1 erkannt. Der Zähler wird um eins erhöht und der Status der LED invertiert. Der neue Status wird an den Pin für die LED ausgegeben. Die Verzögerung um 10 ms verhindert Mehrfachzählungen durch Kontaktprellen.


Folientastatur

 

Die im Set enthaltene Folientatstatur besteht aus einem Gitter mit vier Zeilen und vier Spalten. Durch Drücken auf die Kreuzungspunkte wird eine leitende Verbindung zwischen der jeweiligen Zeile und Spalte hergestellt.
Zum Auslesen werden die Spalten an Eingänge des Mikrocontrollers mit Pullup Widerständen angeschlossen. Die Zeilen werden mit Ausgängen verbunden. Nacheinander wird eine der Zeilen auf 0 gelegt. Während eine Zeile auf 0 ist, kann durch Lesen der Spalten-Eingänge eine gedrückte Taste erkannt werden, da der gelesene Wert in diesem Falle ebenfalls 0 ist.

Einfacher Rechner

Kombiniert man die vierstellige Siebensegmentanzeige (siehe Teil 3) mit der Folientastatur, kann man einen einfachen Rechner realisieren, der addieren und subtrahieren kann. Das Layout der Tastatur soll so aussehen.

Für die Ansteuerung der vier Zeilen kann die Stellenauswahl der Siebensegment-Anzeige mit genutzt werden, sodass nur noch vier Eingänge zum Lesen der Spalten benötigt werden.

 

Für das Programm wird die vierstellige Siebensegmentanzeige aus dem Teil 3 erweitert.

Zuerst werden wieder alle benutzten Pins definiert. Für die Spalten und Zeilen wird jeweils nur eine Pin-Nummer definiert, da die weiteren Spalten und Zeilen aufeinanderfolgende Pins nutzen.

#define SER 2
#define RCLK 3
#define SRCLK 4


#define DIG1 5
#define COL1 9

Es folgt die Tabelle mit den Bitmustern für die Siebensegment-Anzeige und eine zweidimensionale Tabelle, die den Spalten und Zeilen die Tastennummer zuordnet.

byte segmente[18] = {
//  hgfedcba 
  0B00111111, //0
  0B00000110, //1
  0B01011011, //2
  0B01001111, //3
  0B01100110, //4
  0B01101101, //5
  0B01111101, //6
  0B00000111, //7
  0B01111111, //8
  0B01101111, //9
  0B01110111, //A
  0B01111100, //b
  0B00111001, //C
  0B01011110, //d
  0B01111001, //E
  0B01110001, //F
  0B01000000, //-
  0B00000000, //leer
};

int tasten[4][4] = {
  {1,2,3,10},
  {4,5,6,11},
  {7,8,9,12},
  {14,0,15,13}
};

Es folgen globale Variablen.

int zahl, summe;
int taste;
boolean add;

die Variable zahl enthält die Zahl, die gerade eingegeben wird und summe die aktuelle Summe. Die Variable taste enthält die zuletzt gedrückte Taste. Das ist notwendig, damit ein Tastendruck nur einmal ausgewertet wird. Die Variable add ist auf true, wenn addiert werden soll oder auf false für eine Subtraktion.

Die Funktion print7() ist identisch mit dem Beispiel in Teil 3.

void print7(byte zahl, boolean punkt) {
  byte bits;
  if (zahl < 18) {
    bits =  segmente[zahl];
    if (punkt) bits = bits | 0B10000000;
    for (byte i = 0; i < 8; i++) {
      digitalWrite(SER, bits & 128);
      digitalWrite(SRCLK, 1);
      digitalWrite(SRCLK, 0);
      bits = bits << 1;
    }
    digitalWrite(RCLK, 1);
    digitalWrite(RCLK, 0);
  }
}

Die Funktion int displayDigit(int pos, int wert, boolean show) zeigt eine Ziffer mit dem Wert wert an der angegebenen Position pos an. Mit dem Parameter show kann verhindert werden, dass die Ziffer überhaupt angezeigt wird. Außerdem wird die Tastatur für die durch pos ausgewählte Zeile eingelesen und als Ergebnis der Funktion zurückgegeben.

int displayDigit(int pos, int wert, boolean show) {
  int res = -1;
  boolean k;
  if (show) {
    print7(wert, false);
  } else {
    print7(17 , false);
  }
  digitalWrite(DIG1+pos,0);
  delay(2);
  for (int c = 0; c<4; c++) {
    k = digitalRead(COL1+r);
    if (!k) res = tasten[pos][c];
  }
  digitalWrite(DIG1+pos,1);
  return res;
}

Der Rückgabewert wird mit -1 (bedeutet keine Taste gedrückt) vorbesetzt.  Ist der Parameter show auf true, wird die Ziffer ausgegeben, sonst bleibt die Anzeige leer (Code 17);
Mit  digitalWrite(DIG1+pos,0); wird die Kathode der Siebensegmentanzeige und die entsprechende Zeilenleitung der Tastaturmatrix auf 0 gelegt. Dadurch wird die Siebensegmentanzeige aktiviert. In einer Schleife werden nun hintereinander alle Spaltenleitungen geprüft. Ist eine Spaltenleitung auf 0, so wurde die zugehörige Taste in dieser Spalte gedrückt. Die Nummer der Taste wird in res gespeichert. Werden mehrere Tasten in einer Zeile gleichzeitig gedrückt, so wird die am weitesten rechtsliegende Taste als Ergebnis geliefert. Nachdem alle vier Spalten gelesen wurden, wird mit digitalWrite(DIG1+pos,1); der Ausgang zur Kathode der Siebensegmentanzeige und zur Zeilenleitung der Tastaturmatrix wieder auf 5V gelegt. Der ermittelte Tastenwert oder -1, wenn keine Taste gedrückt wurde, wird als Ergebnis zurückgegeben.

Die Funktion int displayNum(int Nummer) gibt eine maximal dreistellige Zahl mit Vorzeichen auf der Siebensegmentanzeige aus und prüft, ob eine Taste gedrückt wurde.

int displayNum(int Nummer) {
  int z;
  int k;
  int res = -1;
  boolean show = true;
  boolean err = false;
  err = ((Nummer < -1000) || (Nummer > 999));
  if (!err && (Nummer < 0)) {
    k = displayDigit(0,16,true);
    Nummer = Nummer * -1;
  } else {
    if (err) {
      k = displayDigit(0,14,true);
    } else {
      k = displayDigit(0,0,false);
    }
  }
  if (k >= 0) res = k;
  for (int i = 3; i>0; i--) {
    z = Nummer % 10;
    if (err) {
      k = displayDigit(i,0,false);
    } else {
      k = displayDigit(i,z,show);
    }
    if (k >= 0) res = k;
    Nummer = Nummer / 10;
    show = Nummer > 0;
  }
  return res;
}

Zuerst werden lokale Variablen angelegt. In z wird die Jeweils anzuzeigende Ziffer gespeichert. Die Variable k wird als Hilfsspeicher für die Tastenermittlung benutzt und in res wird die ermittelte Taste gespeichert. Als Vorgabewert wird hier -1, also keine Taste gedrückt, gespeichert. Die boolesche Variable show dient zum Steuern, ab welcher Position keine Null ausgegeben werden soll. Die boolesche Variable err wird auf true gesetzt, wenn ein Fehler vorliegt. Nun erfolgt die Prüfung, ob die Zahl zwischen 999 und -999 liegt. Ist das nicht der Fall wird err auf true gesetzt.
Nun wird die ganz linke Stelle ausgegeben. Wenn kein Fehler vorliegt und die Zahl kleiner als 0 ist, wird ein „-“ ausgegeben und die Zahl mit -1 multipliziert, damit sie positiv wird.
Liegt ein Fehler vor, wird ein „E“ ausgegeben, sonst bleibt die Stelle leer. Der Rückgabewert der Anzeigefunktion wird jeweils in der Variablen k gespeichert. Ist der Wert von k nicht negativ, so wurde eine Taste in der obersten Zeile gedrückt. Der Wert wird für die Rückgabe in res gespeichert.
Jetzt folgt noch die Anzeige der weiteren Stellen. Man beginnt mit der äußerst rechten Stelle, die die Einer enthält. Das Schleifenkommando for (int i = 3; i>0; i--) beginnt mit dem Wert 3 für i. Dann wird i bei jedem Durchlauf um eins verringert, solange i größer 0 ist. Mit dem „%“ Operator, der den Rest einer Division, in diesem Fall durch 10, liefert, erhält man die Ziffer der niederwertigsten Stelle. Wenn ein Fehler vorliegt, wird „0“ ausgegeben, sonst die Ziffer. Ist der Rückgabewert nicht negativ, wird er in res für die Rückgabe gespeichert.
Nun wird die Zahl durch 10 dividiert, damit man beim nächsten Durchlauf die nächste Stelle erhält. Da die Division eine Ganzzahlendivision ist, erhält man bei einem Ergebnis, das kleiner als 1 ist, als Ergebnis 0. In diesem Fall, wird show auf false gesetzt, damit keine Vornullen angezeigt werden.  Nachdem die Schleife abgelaufen ist, wird die in res gespeicherte Tastennummer zurückgeliefert

In der setup() Funktion wird für die verwendeten Pins der Modus festgelegt. Da für die Zeilenausgänge und für die Spalteneingänge aufeinanderfolgende Pins verwendet werden, können diese in einer Schleife festgelegt werden. Dabei werden auch die Zeilenausgänge auf 1 gesetzt. Die beiden Taktausgänge werden auf 0 gesetzt. Die globalen Variablen erhalten ihre Anfangswerte.

void setup() {
  Serial.begin(9600);
  pinMode(SER, OUTPUT);
  pinMode(RCLK, OUTPUT);
  pinMode(SRCLK, OUTPUT);
  for (int i = 0; i<4;i++) {
    pinMode(DIG1+i, OUTPUT);
    digitalWrite(DIG1+i,1);
    pinMode(COL1+i, INPUT_PULLUP);
  }
  digitalWrite(RCLK, 0);
  digitalWrite(SRCLK, 0);
  zahl = 0;
  summe = 0;
  taste = -1;
  add = true;
}

In der Hauptschleife wird der Wert der globalen Variablen zahl angezeigt. Ist die von der Funktion zurückgegebene Tastennummer anders als die zuletzt erkannte Taste, so ist eine entsprechende Aktion erforderlich.

void loop() {
  int k = displayNum(zahl);
  if (k != taste) {
    taste = k;
    if (taste >= 0) {
      Serial.print(taste);Serial.print(" -> ");Serial.println(zahl);
      if (taste < 10) zahl = zahl*10+taste;
      if (taste == 15) zahl = zahl/10;
      if (taste == 14) { zahl = 0; summe = 0;}
      if (taste == 10) {add = true; summe = zahl; zahl = 0;}
      if (taste == 11) {add = false; summe = zahl; zahl = 0;}
      if (taste == 13) {
        if (add) {
          zahl = summe + zahl;
        } else {
          zahl = summe - zahl;
        }
      summe = zahl;
      }
    }
  }
}

Nachdem festgestellt wurde, dass sich die Tastennummer geändert hat, wird die neue Tastennummer für den Vergleich in der Variablen taste gespeichert. Ist die Tastennummer negativ, bedeutet das, dass die Taste wieder losgelassen wurde. Es erfolgt keine Aktion. Bei einer positiven Tastennummer muss nun die Verarbeitung erfolgen. Die Tasten mit den Nummern 0 bis 9 sind die Zifferntasten. Die neue Ziffer = Tastennummer wird an die bestehende Zahl angehängt. Dazu wird die Zahl mit 10 multipliziert und die Tastennummer addiert. Tastennummern größer als 9 sind Sondertasten. Ist die Tastennummer gleich 15, sollte die letzte Ziffer der Zahl gelöscht werden. Das erreicht man, indem man die Zahl durch 10 dividiert. Ist die Tastennummer gleich 14, so soll alles gelöscht werden. Zahl und Summe werden auf 0 gesetzt. Ist die Tastennummer gleich 10, so sollte eine Addition vorbereitet werden. Die Zahl wird als erster Summand in Summe gespeichert. Dann wird die Zahl zur Eingabe des zweiten Summanden auf 0 gesetzt. Das add-Flag wird auf true gesetzt. Ist die Tastennummer gleich 11, so sollte eine Subtraktion vorbereitet werden. Die Zahl wird als Minuend in Summe gespeichert. Dann wird die Zahl zur Eingabe des Subtrahenden auf 0 gesetzt. Das add-Flag wird auf false gesetzt. Ist die Tastennummer 13, sollte die Operation abgeschlossen werden. Je nach add-Flag wird die Zahl zur Summe addiert oder von der Summe abgezogen.


Joystick

 

Der Joystick ist ein analoges Eingabegerät, das heißt die gelieferte Ausgangsspannung ist proportional zur Bewegung des Steuerknüppels. Es gibt für jede Achse ein Potentiometer, das als Spannungsteiler zwischen +5V und GND wirkt. Im Ruhezustand sind die Potentiometer in Mittelstellung, das bedeutet die Spannung für die X- und die Y-Achse beträgt jeweils ca. 2,5V. Wenn man auf den Steuerknüppel drückt, wird der Schalter geschlossen. Der Anschluss SW wird dann mit GND verbunden. Wird der Schalter als Eingang für den Mikrocontroller genutzt, ist ein Pullup-Widerstand notwendig, da sonst der Zustand bei offenem Schalter undefiniert ist.

Neben X und Y kann man auch den Winkel und Radius ermitteln. Das kann zum Beispiel zur Steuerung von Fahrzeugen genutzt werden. Der Winkel bestimmt die Richtung und die Neigung die Geschwindigkeit. In diesem Fall nimmt man die Ruhestellung als Mittelpunkt an.

Farbregler

Im folgenden Beispiel sollte mit dem Joystick die Farbe einer RGB-LED eingestellt werden. Der Winkel bestimmt die Farbe, die Neigung die Helligkeit. Im Ruhezustand soll die LED dunkel sein. Durch Drücken des Joysticks soll die aktuelle Farbe festgehalten werden. Ein erneutes Drücken sollte wieder ein Ändern der Farbe erlauben. Die RGB-LED wird, wie im Teil 2 beschrieben, über Widerstände mit den Pins 9, 10 und 11 verbunden. Diese Pins unterstützen PWM. Da der Joystick an VRx und VRy analoge Spannungen liefert, müssen diese Anschlüsse mit Analogeingängen verbunden werden. Es werden die Eingänge A0 und A1 verwendet. Für den Schalter wird der Eingang A2 verwendet. Für den Schalter wird zwar kein Analogeingang benötigt, aber die Analogeingänge können auch als Digitaleingänge genutzt werden.

Schaltung:

Im Mikrocontroller sind die Analogeingänge mit einem 10-Bit Analog-Digital-Wandler verbunden. Zum Lesen von Daten von Analogeingängen verwendet man das Kommando analogRead(pin). Dieses Kommando liefert einen 11-Bit Integer Wert. Die Referenzspannung beträgt 5V. Das heißt bei 0V erhält man 0 und bei 5V erhält man 1023. Mit dem Aufruf float x = analogRead(A0)  /  1024 * 5 erhält man die Spannung an A0 in Volt.

Farbkreis:

Das Farbspektrum kann man auf einem Kreis abbilden. Über den Winkel kann man dann eine bestimmte Farbe auswählen. Bei 0 Grad leuchtet nur die rote Leuchtdiode und bei 120 Grad nur die grüne Leuchtdiode. Dazwischen nimmt die Helligkeit der roten LED kontinuierlich ab und die Helligkeit der grünen LED im selben Maß zu. Bei 60 Grad sind beide gleich hell, was als Gelb wahrgenommen wird. Zwischen 120 und 240 Grad geschieht dasselbe mit der grünen und blauen LED, sowie zwischen 240 und 360 Grad mit der blauen und roten LED.

Winkel berechnen:

Die Ausgangsspannung des Joysticks ändert sich zwischen 0 und 5V und somit der gelesene Digitalwert zwischen 0 und 1023. Mit dem Kommando X = 2 * (analogRead(A0)  /  1024.0 - 0.5); erhält man dann Werte zwischen -1 und +1 und somit im Ruhezustand 0. Die Angabe der Konstanten 1024.0 mit Kommastelle ist notwendig, damit der Compiler keine Integer Division anwendet. Die folgende Abbildung zeigt die Werte, die man durch die Bewegung des Joysticks erhält.


Zur Berechnung des Winkels müssen Kreisgleichungen angewendet werden. Da die inversen Winkelfunktionen am besten nur zwischen 0 und 90 Grad eingesetzt werden sollen, wird jeder Quadrant getrennt betrachtet.


Für den ersten Quadranten gilt α = arcsin(b / r) bzw. α = arccos(a / r). Der Radius r = √(a2 + b2).
Für den zweiten Quadranten gilt β = arcsin(d/ r) + 90 bzw. β = arccos(c / r) + 90.
Der Radius r = √(c2 + d2). Man sieht, dass im ersten Quadranten der y-Wert mit arcsin und im zweiten Quadranten der x-Wert mit arcsin verknüft ist. Im dritten Quadranten gilt dasselbe wie im ersten mit dem Unterschied, dass 180 zu addieren ist. Im vierten Quadranten gilt dasselbe wie im zweiten mit dem Unterschied, dass 270 zu addieren ist. Aufbauend auf diesen Grundlagen ergibt sich der folgende Sketch.

#define UX A0
#define UY A1
#define TASTER A2
#define ROT 11
#define GRUEN 10
#define BLAU 9

Zuerst werden wieder die verwendeten Pins definiert. Es folgen die globalen Variablen.

uint32_t last = 0;
boolean t;
boolean auswahl = true;
int R,G,B;
float winkel,x,y;

Die 32-Bit Integer Variable last dient zum Speichern eines Zeitstempels. Die boolesche Variable t wird benötigt, um einen Tastendruck zu erkennen. Die boolesche Variable auswahl stellt den aktuellen Status dar. Sie unterscheidet, ob gerade die Farbe eingestellt werden kann. Ist sie auf false, wird der Farbwert festgehalten und ändert sich nicht, wenn der Joystick bewegt wird. R, G und B beinhalten die aktuellen Anteile für Rot, Grün und Blau. Die Fließkommavariablen winkel, x und y geben den aktuellen Winkel und die gemessenen Werte für x und y an.
Es folgt die setup() Funktion.

void setup() {
  Serial.begin(9600);
  pinMode(UX, INPUT);
  pinMode(UY, INPUT);
  pinMode(TASTER, INPUT_PULLUP);
  pinMode(ROT,OUTPUT);
  pinMode(GRUEN,OUTPUT);
  pinMode(BLAU,OUTPUT);
}

In der setup() Funktion wird die serielle Schnittstelle aktiviert und alle Pins werden in den entsprechenden Modus versetzt.
Die Reaktion auf die Joystick-Eingaben erfolgt in der loop() Funktion.

void loop() {
  boolean t1 = digitalRead(TASTER);
  if (t1 != t) {
    delay(10);
    boolean t2 = digitalRead(TASTER);
    if (t1 == t2) {
      t = t1;
      if (! t) auswahl = ! auswahl;
    }
  }

Am Anfang wird der Schalter des Joysticks ausgewertet. Mit den lokalen Variablen t1 und t2 wird das notwendige Entprellen vorgenommen. Wurde die Taste gedrückt, wird der Status umgeschaltet.
Falls die Farbwahl aktiv ist, werden die Spannungen vom Joystick gelesen und, wie weiter oben erklärt, in den Wertebereich -1 bis +1 umgerechnet. Der zugehörige Radius wird berechnet. Für diese Berechnung wird die Funktion sqrt() verwendet.
  if (auswahl) {
    winkel = 0;
    x = 2*(analogRead(UX)/1024.0-0.5);
    y = 2*(analogRead(UY)/1024.0-0.5);
   float r = sqrt(x * x + y * y);

Nun erfolgt die Berechnung des Winkels. Dazu ist es notwendig, die entsprechenden Quadranten zu kennen. Den ersten und dritten Quadranten erkennt man daran, dass x- und y-Werte das gleiche Vorzeichen haben, also wenn x * y positiv ist. Zum Berechnen des Winkels werden die Funktionen asin() und acos() benutzt. Da diese Funktionen den Winkel im Bogenmaß liefern, muss das Ergebnis mit 180 * π multipliziert werden, um den Winkel in Grad zu erhalten. Zur Berechnung des Winkels kann entweder asin() oder acos() verwendet werden. Da die Genauigkeit bei kleinen Werten schlechter ist, wird immer der größere Wert herangezogen. Schließlich muss noch im dritten Quadranten 180 Grad addiert werden. Der dritte Quadrant wird am negativen x-Wert erkannt.
Die Berechnung für den zweiten und vierten Quadranten erfolgt analog mit dem Unterschied, dass x und y vertauscht werden und zusätzlich 90 Grad addiert werden.

    if (x * y >= 0) { //1. oder 3. Quadrant
      if (x > y) winkel = acos(abs(x)/r)*180/PI; else winkel = asin(abs(y)/r)*180/PI;
      if (x < 0) winkel += 180;
    } else { //2. oder 4. Quadrant
      if (y > x) winkel = acos(abs(y)/r)*180/PI; else winkel = asin(abs(x)/r)*180/PI;
      winkel += 90;
      if (y < 0) winkel += 180;
    }

Mit dem so ermittelten Winkel kann der Farbwert berechnet werden. Zuerst wird sichergestellt, dass der Winkel maximal 359 Grad beträgt.  Ebenso wird der Radius, der für die Helligkeit herangezogen werden soll, auf 1 begrenzt. Ist der Winkel kleiner als 120 Grad, wird je nach Winkel eine Mischung zwischen Rot und Grün vorgenommen. Blau ist 0. Rot nimmt von 255 auf 0 ab, während Grün von 0 auf 255 zunimmt.

   if (winkel > 359) winkel -= 360;
    if (r > 1) r=1;
    float w = winkel;
    if (winkel < 120) {
      R = (120-w)*255/120;
      G = (w * 255/120);
      B = 0;

Ist der Winkel kleiner als 240 Grad, wird zuerst 120 Grad abgezogen und dann, je nach verbleibendem Winkel, eine Mischung zwischen Grün und Blau vorgenommen. Rot ist 0. Grün nimmt von 255 auf 0 ab, während Blau von 0 auf 255 zunimmt.

    } else if (winkel < 240) {
      w = winkel -120;
      G = (120-w)*255/120;
      B = (w * 255/120);
      R = 0;

Für Winkel größer als 240 Grad wird zuerst 240 Grad abgezogen und dann je nach verbleibendem Winkel eine Mischung zwischen Blau und Rot vorgenommen. Grün ist 0. Blau nimmt von 255 auf 0 ab, während Rot von 0 auf 255 zunimmt.

    } else {
      w = winkel -240;
      B = (120-w)*255/120;
      R = (w * 255/120);
      G = 0;
    }

Nun können die ermittelten Werte an die Leuchtdioden ausgegeben werden. Durch die Multiplikation mit dem Radius wird die Helligkeit beeinflusst.

  analogWrite(ROT,R * r);
  analogWrite(GRUEN,G * r);
  analogWrite(BLAU,B * r);
  }

Zur Kontrolle werden alle Sekunden die aktuellen Werte auf die serielle Schnittstelle ausgegeben.


  if ((millis() - l) > 1000) {
    l = millis();
    Serial.print("Winkel = ");
    Serial.println(winkel);
    Serial.print("Ux = "); Serial.print(x);
    Serial.print(" Uy = "); Serial.println(y);
    Serial.print("R = "); Serial.print(R);
    Serial.print(" G = "); Serial.print(G);
    Serial.print(" B = "); Serial.println(B);
  }
}

So, das war‘s für diesen Teil. Viel Spaß beim Experimentieren. Im nächsten Teil folgen analoge Sensoren.

 Beitrag als PDF

Für arduinoProjekte für anfänger

Kommentar hinterlassen

Alle Kommentare werden von einem Moderator vor der Veröffentlichung überprüft

Empfohlene Blogbeiträge

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery