2.1  Digitale Eingänge

Wenn wir einen Digitalport als Eingang verwenden wollen, müssen wir zunächst die Sonderfunktion wie ADC oder USART abschalten. Dazu muss das Function-Select-Register mit 0 initialisiert werden. Außerdem muss im Direction-Register festgelegt werden, dass der Digitalport als Eingang genutzt werden soll. Jeder Byteport verfügt über (bis zu) acht unabhängig voneinander ansprechbare Digitalpins. Die acht Bitstellen in den jeweiligen Registern (z.B. P1DIR oder P1SEL) sind dabei für den jeweiligen Pin 0 bis 7 vorgesehen. Beispiel 2.1 zeigt, wie wir den Byteport P1 als Eingang definieren können.

int main(void) 
{ 
  P1DIR = 0x00;                 // alle Pins von P1 als Eingang 
  P1SEL = 0x00;                 // normale I/O-Funktion für alle 
}
Listing 2.1: Initialisierung von P1 als digitalen Eingang

Häufig verwendet man in der Mikrocontrollertechnik die hexadezimale Schreibweise zur Darstellung von Werten. Bei dieser Schreibweise stellt jede Ziffer ein so genanntes 4 Bit breites Nibble dar. Mit zwei Nibble können alle acht Pins adressiert werden. Sehr günstig ist dafür auch die Verwendung symbolischer Konstanten1 . Durch deren konsequente Nutzung wird der Code wesentlich besser lesbar und Fehler werden vermieden. Die Konstanten können dann mit einfacher boolscher Logik verknüpft werden. Mit der ”ODER”-Verknüpfung kann man ein Bit setzen, mit der ”UND-NICHT”-Verknüpfung ein Bit löschen.

#define BIT0 0x01 
#define BIT1 0x02 
#define BIT2 0x04 
#define BIT3 0x08 
#define BIT4 0x10 
#define BIT5 0x20 
#define BIT6 0x40 
#define BIT7 0x80 
 
i = i | BIT1 & ~BIT6;           // Setze Bit 1 und Lösche Bit 6
Listing 2.2: Definition von Konstanten um selektiv Bits in Registern zu beeinflussen

Um nun den Status eines Pins (in unserem Beispiel den Pin P1.2) auszulesen, müssen wir nach der Initialisierung auf das Input-Register zugreifen. Die Eingänge basieren auf Schmitt-Trigger-Bausteinen. Damit ist sichergestellt, dass selbst bei langsam wechselnden Eingangssignalen sauber zwischen dem eingeschalteten (1) und dem ausgeschalteten (0) Pegel unterschieden werden kann. Die Hysterese der Schmitt-Trigger-Bausteine sorgt schaltungstechnisch dafür, dass es zu keinen Schwingungen am Umschaltpunkt kommt. Eine Eingangsspannung oberhalb von 2V wird sicher als eine logische 1 erkannt, eine Spannung unterhalb von 0,9V sicher als eine logische 0. Diese Werte können sich für kleinere Betriebsspannungen noch verändern. Hier gibt das Datenblatt des jeweiligen Controllers genauen Aufschluss.

Man kann nur den kompletten Zustand eines Byteports einlesen und nicht jeden einzelnen Pin selbst. Um dennoch den Status eines einzelnen Pins auslesen zu können, kann man das Input-Register des Byteports entsprechend bitweise verknüpfen.

#include <msp430x16x.h>     // Headerdatei für Definitionen 
int main(void) { 
  int byteport;             // Variable für Port-Status 
  P1DIR = 0x00;             // alle Ports von P1 als Eingang 
  P1SEL = 0x00;             // normale I/O-Funktion 
  while(1) { 
    byteport = P1IN;        // Einlesen des Ports 
    if(byteport == BIT2) {  // teste, ob nur P1.2 gesetzt ist 
       // P1.2 ist gesetzt ... tue irgendwas... 
    } 
  } 
}
Listing 2.3: Auslesen des Status von Digitalport P1.2

Im Beispiel 2.3 wird geprüft, ob nur P1.2 logisch 1 ist. Alle anderen Pins müssen logisch 0 sein. Will man testen, ob P1.2 logisch 1 ist, unabhängig von den anderen Pins, müsste man auf P1.2 anstatt des ”==” -Operators eine AND-Verknüpfung (Achtung: &-Operator, nicht &&-Operator) anwenden. In jedem Fall ist zu beachten, dass die Zählung der Pins bei 0 beginnt. Für den Pin P1.0 muss man somit mit der hexadezimalen Zahl 0x01 verknüpfen. Für den Pin P3.6 dagegen würde man das Register P3IN mit der hexadezimalen Zahl 0x40 (dezimal = 64) verknüpfen. Wie gesagt, wäre das Verwenden der logischen Konstante BIT6 allemal einfacher zu verstehen.

2.1.1  Anschluss von Tastern

Beim Anschluss von Tastern sollte man bestimmte Eigenschaften der digitalen I/O-Ports beachten. Wenn man mit digitalen Eingängen arbeitet, ist die Eingangsimpedanz der jeweiligen Pins sehr hochohmig. Ein strombegrenzender Vorwiderstand zum Sensor oder Taster ist daher nicht zwingend erforderlich, für die Entwicklungsphase aber dringend anzuraten. Schnell hat man aus Versehen den Pin als Ausgang statt als Eingang definiert. Der Widerstand vermeidet dann den elektrischen Kurzschluss und sichert das Überleben des Mikrocontrollers. Die digitalen Eingänge haben charakteristische Eingangspegel, die in Tabelle 2.2 zusammengefasst sind.


ParameterMinimalMaximal
   
Obere Umschaltschwelle V IT+ 1.5V 1.9V
Untere Umschaltschwelle V IT- 0.9V 1.3V
Eingangsspannungshysterese V hys 0.5V 1V
   

Tabelle 2.2.: Eingangspegel der digitalen Eingänge

Um saubere und definierte Schaltzustände zu erhalten, verschaltet man die Eingänge meist mit so genannten Pull-Up- oder Pull-Down-Widerständen. Ein Pull-Up-Widerstand zieht den Pegel des Digitalports hoch (HIGH). Ein Pull-Down-Widerstand wird den Pegel des Digitalports dagegen runterziehen (LOW). Der Pegel ist dabei die am Port anliegende Spannung, die einem bestimmten logischen Zustand (gesetzt oder nicht gesetzt) des Digitalports entspricht.


PIC

Bild 2.2.: Anschluss von Tastern mit Pull-Up- und Pull-Down-Widerständen sowie einem ”Sicherheits-” Vorwiderstand


Will man, dass der Eingang logisch HIGH ist, wenn man einen Taster drückt, würde man den Port entsprechend Abbildung 2.2 (links) verschalten. Für einen Eingang, der beim Betätigen eines angeschlossenen Tasters logisch LOW sein soll, bietet sich die Schaltung in Abbildung 2.2 (rechts) an. Die Größe des ”Pull”-Widerstandes ist dabei nicht so entscheidend. Werte im Bereich von 10 bis 1 sind dafür üblich.

Die Dimensionierung des ”Sicherheitswiderstands” bemisst sich am Fehlerfall. Im schlimmsten Fehlerszenario schaltet der Port aktiv gegen Masse (Pull-Up-Konfiguration) oder Betriebsspannung (Pull-Down-Konfiguration), wenn der Schalter geschlossen ist. Das klingt auf den ersten Blick vielleicht relativ unwahrscheinlich, ist es aber nicht. Gerade bei der Entwicklung der Mikrocontroller-Software hat man schnell mal den falschen Port als Ausgang definiert und schon ist es passiert. Damit der Mikrocontroller überlebt, darf der Strom nicht größer als maximal erlaubt werden (z.B. IMax < 2mA). Damit erhalten wir bei 3.3V Versorgungsspannung einen minimalen ”Sicherheits-” Vorwiderstand von etwa 1.8.

2.1.2  Entprellen von Eingängen

Ein Problem von Schaltern und Tastern ist, dass sie als mechanische Bauteile die Eigenschaft haben zu prellen. Das bedeutet, dass sie bei Betätigung - also zum Beispiel beim Schließen eines Schalters - nicht unmittelbar Kontakt zum Eingangsport herstellen, sondern mehrfach schnell ein- und ausschalten. Dies wird zum Problem, wenn man in der Software nicht auf den Zustand eines Schaltelementes sondern auf den Zustandswechsel reagiert. Bei einer Taktung von 8MHz würde die While-Schleife aus Listing 2.3 in etwa einer Mikrosekunde durchlaufen. Wenn man an den Digitalport P1.2 einen Taster anschließt und die Tastendrücke nun in dieser Schleife zählt, so würde der Controller während eines Tastendrucks viele Male die Schleife durchlaufen und fälschlicherweise jedes Mal die Anzahl der Tastendrücke inkrementieren. Eine Lösungmöglichkeit ist das Entprellen von Eingängen. Prinzipiell kann man dies sowohl in Hardware als auch in Software erreichen.

Entprellen per Software

Eine einfache Möglichkeit einen Eingang zu entprellen ist eine FOR-Schleife, die einige tausend Zyklen durchläuft und so eine künstliche Programmpause erzeugt. Beispiel 2.4 zeigt eine Software-Entprellung mit einer FOR-Schleife, die 1000-mal durchlaufen wird.

  int i, byteport, oldbyteport; 
  while(1) { 
    byteport = P1IN;                // lese Port ein 
    if(byteport != oldbyteport) {   // hat sich etwas verändert? 
      if(byteport & BIT2) {         // teste ob P1.2 Verursacher 
       for(i = 0; i < 1000; i++) {} // kurze Pause 
      // P1.2 ist gesetzt ... tue irgendwas... 
      } 
    } 
    oldbyteport = byteport;         // merke den neuen Wert 
  }
Listing 2.4: Programmausschnitt mit Software-Entprellung

Ein Nachteil der Software-Entprellung ist, dass das Programm für eine kurze Zeit unterbrochen wird. Zeitkritische Anwendungen können dadurch beeinträchtigt werden. Im Gegensatz zur Entprellung per äußerer Beschaltung lässt sie sich jedoch auch noch nachträglich implementieren.

Entprellen per äußerer Beschaltung

Wenn man den Programmfluss durch das Entprellen der Eingänge nicht unterbrechen will, bietet sich das Entprellen per äußerer Beschaltung an. Dazu kann man an den Eingang ein RC-Glied mit Tiefpassverhalten schalten, wie dies in Bild 2.3 zu sehen ist. Die RC-Zeitkonstante τ = R C sollte so gewählt werden, dass sie deutlich größer als die Prellzeit ist. Für die meisten handelsüblichen Schalter ist bei einem Vorwiderstand von 47 eine Kapazität von 100nF ausreichend. Dies ergibt dann eine Zeitkonstante von etwa 5ms.


PIC

Bild 2.3.: Entprellung eines Tasters mit paralleler Kapazität