MezData-Logo

Zylonenlauflicht mit Arduino-Software

Programmierung beinahe wie mit Arduino

Zylonenlauflicht

Typischerweise werden 8 Ein-Ausgabe-Anschlüsse (Pins) bei Mikrocontrollern zu Ports gruppiert, z.B. PORTB. Die Anschlüsse werden durchnummeriert: PB0..PB7.

Bei Arduino wird die Zuordnung zu den Ports des Mikrocontrollers verborgen. Die Anschlüsse sind einfach durchgezählt und die Zuordnung zu der jeweiligen Hardware geschieht mit Funktionen wie pinMode, digitalWrite und digitalRead. Dies hat entscheidene Vorteile für Einsteiger und Leute, die sich nicht mit der konkreten Hardware detailiert auseinander setzen wollen.

Einlesen und Ausgeben

Quellcode [einfache_logik.c]
#include <avr/io.h> // Laden von Hardwaredefinitionen
 
int T0=4,T1=5,T2=6;      // Pinnummern festlegen
int L0=0,L1=1,L2=2,L3=3;
void setup(){        // Initialisieren der Ports
  DDRB = 0b00011111; // Ausgaenge einschalten
  PORTD= 0b01110000; // PullUps für Taster einschalten
}
int lese(int t){    // Hilfsfunktion zum Taster lesen
  if (PIND & (1<<t)) return 0; // Taste an Pin t 
  else return 1;
}
void ausgebenLed(int led,int wert){ // Led ausgeben
  if(wert) PORTB |= 1<<led;
  else PORTB &= ~(1<<led);
}
int main(){  // Hauptprogramm
  setup();   // Initialisierung aufrufen
  while (1){ // entspricht der loop-Funktion
    ausgebenLed(L0,lese(T0)); // L0 = T0
    ausgebenLed(L1,lese(T1)); // L1 = T1
  }
}

Der Sketch verwendet 236 Bytes (11%) des Programmspeichers.

Ziel: Taster T0 soll Led L0 und T1 Led L1 leuchten lassen.

Die Taster sind an PD6..PD4 angeschlossen, die Leds an PORTB. Nur die Led L3..L0 werden benötigt. Die Led sind als Matrix verschaltet, deshalb wird PB4 auf 0, GND geschaltet. Die Nummern der Taster- und Led-Pins werden in T2..T0 bzw. L3..L0 gespeichert.

Nach einem Reset sind alle Ports keine Ausgänge, im setup() werden die PB4..PB0 als Ausgang eingestellt. Die Taster verfügen über keine PullUp-Widerstände, daher werden die internen PullUp-Widerstände eingeschaltet.

Info: In C ist 0 = false, alle anderen Werte werden als true interpretiert

lese(t:GZ):GZ gibt 1 zurück, wenn Taster an PDt betätigt wurde, sonst 0.
Die Taster schalten den Pin bei Betätigung auf 0V, dann liegt eine 0 am Eingang vor. Ist der Taster offen liegt durch den PullUp-Widerstand am Eingang eine 1 vor. Negative Logik: Betätigung = 0, sonst 1. Es soll nur Pin t gelesen werden, PIND gibt den Byte-Wert des ganzen Ports, aller Pins wieder. Scheuklappe bzw. Maske soll nur einen Pin durchlassen:

  • 1<<t verschiebt 1 t Stellen nach links, Bsp: 1<<4 = 0b00010000
  • PIND & 0b00010000 lässt nur PD4 durch, der Rest ist 0

ausgebenLed(led:GZ,wert:GZ) setzt bzw. löscht die Led.

Logische Und-Verküpfung

Quellcode [und-verkuepfung_mit-watte.c]
#include <avr/io.h>
 
const unsigned char T0=4,T1=5,T2=6;
const unsigned char L0=0,L1=1,L2=2,L3=3;
void init(){         // Initialisierung
  DDRB = 0b00011111; // Ausgaenge einschalten
  PORTD= 0b01110000; // PullUps für Taster einschalten
}
unsigned char lese(unsigned char t){
  if (PIND & (1<<t)) return 0;
  else return 1;
}
void ausgebenLed(unsigned char led,unsigned char wert){
  if(wert) PORTB |= 1<<led;
  else PORTB &= ~(1<<led);
}
int main(){
  init();
  while (1){
    if(lese(T0) && lese(T1)) ausgebenLed(L0,1);
    else ausgebenLed(L0,0);
  }
}

Der Sketch verwendet 122 Bytes (5%) des Programmspeichers.

Ziel: Die logische Verknüpfung L0 = T1 & T0 soll realisiert werden.

Das obige Programm benötigte 236 Byte für die einfache Aufgabe, es geht sparsamer.

Statt int, das 2 Byte pro Variable benötigt wird jetzt unsigned char (1 Byte) verwendet, für die unveränderlichen Pinnummern noch const.

Der Speicherbedarf reduziert sich auf 122 Byte –knapp die Hälfte, das bedeutet auch, dass der zu bearbeitende Programmcode deutlich geringer wurde. Bei gleicher Agilität könnte eine geringere Taktfrequenz verwendet werden, damit ein geringerer Energiebedarf für die Aufgabe.

Weniger Maschinencode kann geringeren Energiebedarf bewirken.

Ohne die Lese- und Schreibunterprogramme lässt sich noch mehr sparen.

L0 = T1 & T0 = !PD5 & !PD4 wegen der negativen Logik. Mit De-Morgan lässt sich der Ausdruch umwandelt in L0 = !(PD5 # PD4) = !(PIND & 0b00110000)

Maske 0b0011000 lässt nur PD5 und PD4 durch, nur wenn beide Tasten gedrückt sind ist das Ergebnis 0.

 

 

Programmieren ohne Umverpackung

Quellcode [und-verkuepfung.c]
#include <avr/io.h>
 
void init(){         // Initialisierung
  DDRB = 0b00011111; // Ausgaenge einschalten
  PORTD= 0b01110000; // PullUps für Taster einschalten
}
int main(){
  init();
  while (1){
    if(PIND & 0b00110000){
      PORTB &= ~1; // setze PB0 auf 0
    }
    else{
      PORTB |=1; // setze PB0 auf 1
    }
  }
}

Der Sketch verwendet 82 Bytes (4%) des Programmspeichers.

Quellcode [und-verkuepfung_einfacher.c]
#include <avr/io.h>
 
void init(){
  DDRB = 0b00011111; // Ausgaenge einschalten
  PORTD= 0b01110000; // PullUps für Taster einschalten
}
int main(){
  init();
  while (1){ // mit ~PIND in positive Logik wandeln
    if((~PIND & 0b00110000)==0b00110000){ //T1 und T0
      PORTB |=1; // setze PB0 auf 1
    }
    else{
      PORTB &= ~1; // setze PB0 auf 0
    }
  }
}

Der Sketch verwendet 82 Bytes (4%) des Programmspeichers.