IO-Register als Parameter und Variablen
Um Register als Parameter für eigene Funktionen übergeben zu können, muss man sie als einen volatile uint8_t Pointer übergeben. Zum Beispiel:
#include <avr/io.h>
#include <util/delay.h>
uint8_t key_pressed(const volatile uint8_t *inputreg, uint8_t inputbit)
{
static uint8_t last_state = 0;
if ( last_state == ( *inputreg & (1<<inputbit) ) ) {
return 0; /* keine Änderung */
}
/* Wenn doch, warten bis etwaiges Prellen vorbei ist: */
_delay_ms(20);
/* Zustand für nächsten Aufruf merken: */
last_state = ( *inputreg & (1<<inputbit) );
/* und den entprellten Tastendruck zurückgeben: */
return ( *inputreg & (1<<inputbit) );
}
/* Beispiel für einen Funktionsaufruf: */
//...
uint8_t i;
//...
i = key_pressed( &PINB, PB1 );
//...
|
Ein Aufruf der Funktion mit call by value würde Folgendes bewirken: Beim Funktionseintritt wird nur eine Kopie des momentanen Portzustandes angefertigt, die sich unabhängig vom tatsächlichen Zustand das Ports nicht mehr ändert, womit die Funktion wirkungslos wäre. Die Übergabe eines Zeigers wäre die Lösung, wenn der Compiler nicht optimieren würde. Denn dadurch wird im Programm nicht von der Hardware gelesen, sondern wieder nur von einem Abbild im Speicher. Das Ergebnis wäre das gleiche wie oben. Mit dem Schlüsselwort volatile sagt man nun dem Compiler, dass die entsprechende Variable entweder durch andere Softwareroutinen (Interrupts) oder durch die Hardware verändert werden kann.
Im Übrigen können mit volatile gekennzeichnete Variablen auch als const deklariert werden, um sicherzustellen, dass sie nur noch von der Hardware änderbar sind.
|