Samstag, 11. Juli 2015

Port Manipulation am Arduino

In diesem Artikel geht es darum, wie man die Pins des Arduino schneller und effizienter verwenden kann. Dazu benutzt man Port Manipulation, was die langsamen Fuktionen digitalRead() und digitalWrite() ersetzt. Zusätzlich benötigt Port Manipulation weniger Speicherplatz, wodurch sich größere Sketche programmieren lassen, und  durch Port Manipulation kann man mehrere Pins gleichzeitig schalten.

Die Theorie

Ein Arduino enthält einen Mikrocontroller, der Uno beispielsweise den ATmega328P-PU. Diese Mikrocontroller besitzen die Pins, welche man über den Arduino, neu nummeriert, schalten kann. Dafür benutzt man dann die Funktionen digitalRead() und digitalWrite(). Die Pins des Mikrocontroller sind jedoch eigentlich anders, als beim Arduino, sortiert, nämlich in Ports. Ein Port ist nicht gleich mit einem Pin sondern ein Port ist eine "Pingruppe". Die Pins des Arduino Uno sind, am Mikrocontroller, eigentlich in 3 Ports gegliedert. Das sind Port B, C und D.
Über die Port Manipulation schaltet man also die Pins eines Ports beziehungsweise einen ganzen Port auf einmal. Dazu gibt es drei Register: DDRx, PORTx und PINx. Das klingt jetzt komplizierter als es ist. 

Die Umsetzung

Über DDRx legt man fest, ob die einzelnen Pins eines Port OUTPUTs oder INPUTs sein sollen. Beispielsweise würde die Zeile DDRC = B000111 die analog Eingänge A0 bis A2 als Input definieren und A3 bis A5 als Output definieren. 0 steht für Input und 1 für Output. Das "B" vor den Zahlen gibt nur das Format an. Die Definition beginnt immer mit dem Pin mit der kleinsten Nummer am Arduino, also von A0 bis A5, da  0 < 5. 

Über das PORTx Register legt man fest, ob die Pins auf LOW oder HIGH geschaltet werden sollen. Dabei steht das x wieder für den jeweiligen Port. Wenn wir also Pin 8, 10 und 12 auf HIGH und Pin 9, 11 und 13 auf LOW setzen wollen, schreiben wir PORTB = B101010.

Das PINx Register ist dazu da, um den aktuellen Status der Input Pins, also LOW oder HIGH, festzustellen. Dazu wählt man für x wieder den aktuellen Port und vergleicht dann das Register mit einer Abfolge. Beispielsweise überprüft if(PINB == 0b000000), ob alle Pins, des Ports B, auf LOW geschaltet sind. 

Nun weißt du also, wie du schnell und effizient einen ganzen Port schalten kannst. Doch was ist, wenn du nur mal schnell den Status eines Pins ändern willst?

Um nur einen einzelnen Pin zu definieren, beziehungsweise zu schalten oder auszulesen gibt es verschiedene Schreibweisen, die jedoch immer das selbe bewirken.

Wenn ich beispielsweise Pin 10 als OUTPUT festlegen möchte, so brauche ich das DDR Register vom Port B. Dort ist der Pin 10 der Pin 2 und OUTPUT ist als 1 definiert. Deshalb schreibt man die Zeile DDRB = (1<<PB2). Dadurch wird eine 1, also Output, zu Pin 2 des Ports B geschrieben. Wenn wir diesen Pins nun auf HIGH schalten wollen, so schreibt man PORTB = (1<<PB2). Um einen Eingang auszulesen schreibt man PINB & (1<<PB2). (Das & ist kein Tippfehler!) Das gibt den aktuellen Status des Eingangs zurück. Nicht wundern: Falls der Pin auf HIGH ist, gibt die "Abfrage" den Wert 4 zurück.

Dank der Port Manipulation könnt ihr jetzt Pins gleichzeitig schalten, beziehungsweise auslesen. Außerdem sind eure Sketche kleiner, wie ihr hier sehen könnt:
(zum Vergrößern klicken)

Kommentare:

  1. How do i enter PWM write with this methode?

    AntwortenLöschen
  2. This article on the arduino website is about how to use pwm with port manipulation:
    https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM

    AntwortenLöschen