03 Die map() Funktion

 

Wir haben bisher das Konzept von analogInput (Poti) und analogOutput (LED dimmen) kennengelernt. Lass uns nun beide Konzepte in einem Sketch verbinden. Im Folgenden werden wir durch das Drehen des Potentiometers die Helligkeit der LED verändern.

Schaltung und Aufbau

Der Sketch

int potiPin = A0;  //Analog input pin that the potentiometer is attached to
int potiValue = 0; //value read from the pot

int ledPin = 6; //Analog output pin that the LED is attached to


void setup() 
{
  //initialize serial communications at 9600 bps:
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
}


void loop() 
{
  //read the analog in value:
  potiValue = analogRead(potiPin);
    
  //change the analog out value:
  analogWrite(ledPin, potiValue);

  //print the results to the Serial Monitor:
  Serial.print("Poti Value = ");
  Serial.print(potiValue);


  //wait 2 milliseconds before the next loop for the analog-to-digital
  //converter to settle after the last reading:
  delay(2);
}

Die Werteübertragung zwischen Potentiometer und LED spielt sich in nur zwei Zeilen Code ab. In der einen wird der Sensorwert abgefragt und das Ergebnis in die zweite Zeile transferiert. Da die Variable potiValue in beiden Funktionen vorkommt, verbindet sie beide Funktionen miteinander. Diese Kombination bewirkt die proportionale Übertragung des Potentiometerwertes direkt an die LED.

void loop()
{
  ...
  potiValue = analogRead(potiPin); 
  analogWrite(ledPin, potiValue);
  ...
}

Fällt dir etwas auf, wenn du am Potentiometer drehst? Was passiert genau mit der LED? Mache an dieser Stelle eine Lesepause und versuche heraus zu finden, was nicht stimmt.

Hier das Problem: Hast du gemerkt, dass die LED in seiner maximalen Intensität leuchtet, wenn das Poti bereits bei 25% der Drehung angekommen ist? Kannst du dir vorstellen, voran das liegt? Ein Tipp: Rufe den seriellen Monitor auf, drehe den Poti auf sein Maximum und sieh dir an welcher Wert angezeigt wird.

Die Auflösung: Die zwei Funktionen haben unterschiedliche Wertebereiche! Erinnern wir uns, dass analogRead() 1024 und analogWrite() 256 Werte hat. Schon bei der ersten Viertelumdrehung des Potis ist bereits das Maximum von analogWrite() erreicht: 256 ist ein Viertel von 1024. Unterschiedliche Wertebereiche miteinander zu kombinieren, wird uns noch häufig begegnen. Es gibt eine Funktion namens map(), die uns hilft einen Wertebereich auf einen anderen zu skalieren.

Die map()-Funktion nimmt 5 Argumente auf. In das erste Argument wird der Wert oder die Variable eingetragen, deren Wertebereich verändert werden soll. Low1 definiert die untere Grenze und High1 die obere Grenze des zu verändernden Bereiches an. Im Poti-Beispiel ist das die 0 und die 1023.

Low2 und High2 definieren die untere und obere Grenze des neuen Bereiches. Da die LED mit analogWrite() insgesamt 256 Zustände einnehmen kann, wird der neue Bereich von 0 bis 255 definiert. Map arbeitet mit ganzen Zahlen. Alle Nachkommastellen werden abgeschnitten und nicht gerundet. Jedes vom Poti einkommende Signal wird auf den entsprechenden Wert übertragen. Beispielsweise entspricht der Wert 256 im neuen Bereich dem Wert 64.

Durch folgende Zeile werden beide Bereiche ineinander überführt.

ledMap =map(sensorWert,0,1023,0,255);

Hier noch mal der obere Sketch mit der map-Funktion:

const int potiPin = A0;  // Analog input pin that the potentiometer is attached to
const int ledPin = 9; // Analog output pin that the LED is attached to

int sensorWert = 0;        // value read from the pot
int ledMap = 0;        // value output to the PWM (analog out)

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
}

void loop() {
  // read the analog in value:
  sensorWert = analogRead(potiPin);
  
  // map it to the range of the analog out:
  ledMap = map(sensorWert, 0, 1023, 0, 255);
  
  // change the analog out value:
  analogWrite(ledPin, ledMap);

  // print the results to the Serial Monitor:
  Serial.print("sensor = ");
  Serial.print(sensorWert);
  Serial.print("\t output = ");
  Serial.println(ledMap);

  // wait 2 milliseconds before the next loop for the analog-to-digital
  // converter to settle after the last reading:
  delay(2);
}

Weiteres zur map() Funktion

Die map-Funktion ist sehr flexibel und kann unseren Bedürfnissen angepast werden. Bleiben wir bei unserem Beispiel mit analogRead(). Dieser liefert Werte zwischen 0 und 1023. Wir könnten den Zielbereich anders gestalten. Angenommen du willst den Bereich 0 bis 1023 in Prozent darstellen. Dann kann dies mit folgender Zeile bewerkstelligt werden.

prozent =map(value,0,1023,0,100);

Du könntest aber auch den Nullpunkt auf die Mitte des Potentiometers verschieben und so einen positiven und negativen Bereich definieren. Unser Poti hat einen Drehwinkel von 270°. Teilt man diesen in zwei Bereiche, liegt der Nullpunkt bei 135° – genau in der Mitte. Dann könnte die Zeile so aussehen.

winkel =map(value,0,1023,-135,135);

Bei der Verwendung der map()-Funktion müssen wir die Minimal- und Maximalwerte der jeweiligen Anwendung kennen. Kennen wir diese nicht, können wir sie per seriellem Monitor herausfinden. Aus diesem entnehmen wir dann die Unter- und Obergrenze der Sensorwerte.

Aufgabe

In diesem speziellen Beispiel (Potentiometer <> LED) hätten wir die map()-Funktion eigentlich nicht gebraucht. Es ist möglich das Problem auch durch eine kleine mathematische Rechnung zu lösen. Mach eine Pause und versuche selber auf die Lösung zu kommen.

 

Die Auflösung:

Die Lösung liegt in der Relation der Wertebereiche. Der Wertebereich von analogRead ist ein Vielfaches von analogWrite: 1024/256= 0,25 oder 1/4. Mit anderen Worten, wäre es ausreichend gewesen den Sensorwert aus analogRead() durch 4 zu teilen.

void loop()
{
...
potiValue = analogRead(potiPin/4); 
analogWrite(ledPin, potiValue);
...
}