Grundfunktion eines Port-Pins
An den Port-Pins eines µC werden Taster und LED angeschlossen. Der µC soll die Funktion logischer Digital-Schaltungen simulieren. In der C-Umgebung kann nur auf die Gesammtheit aller Port-Bits zugegriffen werden, daher spielt das geschickte Bit-Maskieren hier eine grosse Rolle.
Vordefinierte Konstanten in den Include-Dateien
Da sich die Adressen der Port-Register der verwendeten µC unterscheiden können und zur besseren Lesbarkeit des Quellcodes sind in den Include-Dateien des jeweiligen Kontrollers für jedes Register und jedes Bit entsprechende Bezeichnungen vordefiniert. Beispiel:
- PINB ist die Adresse, mit denen die Tri-State-Bausteine der Pins des Port B auf den Datenbus geschaltet werden
- DDRB ist die Adresse des Data Direction Registers B, mit dem ein Port-Pin als Ausgang programiert wird
- PORTB ist die Adresse des Port Registers B
- PB0..PB7 sind die Bezeichnungen der Port-Pins des Port B. Bei Verwendung dieser Bezeichner im Programm werden die Bitnummern der Anschlüsse PB0..PB7 im Port B zurück gegeben, PB0 hat den Wert 0, PB7 den Wert 7
- 1<<PB2 statt 0b100 verwenden für eine bessere Dokumentation im Quelltext. PB2 hat den Wert 2. Der Shift-Operator << verschiebt dadurch die 1 um zwei Stellen nach links, der Wert des Ausdrucks ist 0b100.
Priorität der Operatoren beachten
Siehe Ausdrücke und Operatoren. Bindungsstärke der Operatoren nimmt ab: ==,!= > & > ^ > | > && > ||
Beispiel für typischen Fehler: (PINB&3==3) wird so berechnet: (PINB&(3==3)) ergibt PINB&1. Daher Klammern setzen ((PINB&3)==3).
Boolsche Interpretation von nicht boolschen Ausdrücken in C
In C werden die Werte 0, 0.0, null als false interpretiert, alle anderen Werte, auch negative, als true.
Beispiel: Bei if ((PINB&3)!=0) kann C der Vergleich !=0 weg gelassen werden, if (PINB&3) führt zum selben Ergebnis.
Grundprinzip
Im ersten Lösungsquelltext ist eine Initalisierung (enspricht bei Arduino dem setup) und die Endlos-whileschleife (loop) enthalten, die weiteren Quelltexte enthalten nur noch den Inhalt der While-Scheife. Auch wurden Alternativen in der Darstellung der Werte vorgeschlagen: 0b00001000 = 8 = 0x08 = 1<<3
Und Baustein
#include <avr/io.h> // Einbinden der Konstanten
int main(){ // Hauptprogramm
DDRB = 0b00001000; // PB3 auf Ausgang
//DDRB = 1<<PB3;
while (1){ // Endlosschleife
if((PINB&3)==3){ // PB0 & PB1
PORTB |= 8; // PB3 <- 1
//PORTB |= 0b00001000;
//PORTB |= 1<<PB3;
}
else{
PORTB &= ~8; // PB3 <- 0
//PORTB &= 0b11110111;
//PORTB &= ~(1<<PB3);
}
}
}
Lesen von PINB spricht alle Bits von PB an. Bei der Verarbeitung sind aber nur PB1 und PB0 relevant, die anderen Bits sollen ausgeblendet werden. Dies wird durch eine Und-Verknüpfung mit einer Maske erreicht, die alle unbeteiligten Bits ausblendet.
Maske: PINB & 0b11
Nach der Maskierung kann der Wert zwischen 0..3 liegen, der Und-Bausten soll beim Wert 3 eine 1 ausgeben, d.h. PB3 gesetzt werden sonst soll PB3 gelöscht werden.
Setzen von PB3: PORTB |= 1<<PB3; // 0b00001000
Löschen von PB3: PORTB &= ~(1<<PB3); // 0b11110111
SPS-Simulation mit Java
Für Schaltnetzsimulation zur Ausgabe von allen Kombinationen Vorher und Nachher:
Beachte: In Java werden Zahlenwerte nicht als boolsche Werte aktzeptiert, daher umschreiben, z.B. (PINB&1) zu ((PINB&1)!=0)
Oder Baustein
Zuerst die Maske bilden und dann mit dem Wert vergleichen,
bei dem das Oder nicht Eins sein soll.
SR-FlipFlop
Wegen der Rücksetzpriorität wird zuerst das R-Signal überprüft.
Taktflanken gesteuertes D-FF
Im der Variablen merker wird der letzte Zustand des PB1
gemerkt,
um die steigende Flanke erkennen zu können.