ich bin noch sehr neu auf dem Gebiet und habe nur "Basic"-Programmierkenntnisse.
Ich arbeite mit einem Arduino Uno R3
Zur Übung und für den Einstieg wollte ich den Beispielsketch "Blink" etwas erweitern.
Die Idee war an Pin13 und GND eine LED anzuschliessen und an Pin 10 einen Taster, der nicht im losgelassenem Zustand die LED aus und im gedrückten Zustand die LED einschalten sollte, sondern pro Druckaktion den Zustand der LED ändern soll.
Bisher habe ich das mit einer verschachtelten If-Schleife gelöst, aber ich glaube es müsste doch hierfür auch eine kürzer Methode geben um den Zustand von Pin13 bei einem Knopfdruck ändern zu können? (Das ist meine Frage )
Hier der Code mit dem es bereits funktioniert:
void setup() {
DDRB = 0b00100000; // Pin13 Output, Rest Input
PORTB = 0b00000100; // Pin13 auf LOW - Pin10 Pull-up aktiviert
}
void loop() {
if ( !(PINB & (1<<PINB2)) ){ // wenn Bit Nr. 2 gesetzt
if(PINB & (1<<PINB5)){
PORTB &= ~(1<<PORTB5); // Pin13 auf HIGH
}
if (!(PINB & (1<<PINB5))){
PORTB |= (1<<PORTB5); // Pin13 LOW
}
delay(200); // Für die Verweilzeit beim drücken
}
}
Nun zu meinem Problem:
Möchte ich mir am PC-Bildschirm über den SerialMonitor den Zustand der LED ausgeben lassen (über Serial.print("LED an")) funktioniert leider garnichts mehr, allerdings ist mir aufgefallen, wenn der Compiler und der Upload abgeschlossen sind und ich im Anschluss den SerialMonitor starte, blinkt die LED ein paar Mal sehr schnell auf
Hier der Code mit der Textausgabe, der nicht funktioniert:
void setup() {
DDRB = 0b00100000; // Pin13 Output, Rest Input
PORTB = 0b00000100; // Pin13 auf LOW - Pin10 Pull-up aktiviert
}
void loop() {
Serial.begin(9600);
if ( !(PINB & (1<<PINB2)) ){ // wenn Bit Nr. 2 gesetzt
if(PINB & (1<<PINB5)){
PORTB &= ~(1<<PORTB5); // Pin13 auf HIGH
Serial.println("LED an");
}
if (!(PINB & (1<<PINB5))){
PORTB |= (1<<PORTB5); // Pin13 LOW
Serial.println("LED aus");
}
delay(200); // Für die Verweilzeit beim drücken
}
}
Vom Prinzip her ist das doch eigentlich man anfänglicher Code nur mit Serial erweitert?
Das Serial.begin() gehört in setup(). Das muss man nur einmal machen.
Du kannst ein Bit ganz einfach toggeln wenn du eine 1 auf das Eingangs-Register PINn schreibst. Das ist auch die schnellste Möglichkeit ein Bit zu toggeln, da keine Lese-Operation nötig ist. Siehe Datenblatt Seite 77:
Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn.
Ansonsten ein XOR mit 1 auf den Wert des Ausgangs-Register PORTn (also PORTB ^= (1<<PB5)). Das invertiert auch das entsprechende Bit, da die Wahrheits-Tabelle wie folgt ist:
0 0 -> 0
0 1 -> 1
1 0 -> 1
1 1 -> 0
Du hast übrigens bei den Pin Makros eine kleine Inkonsistenz. Du verwendest mal PINB5 und mal PORTB5. Das existiert beides und ist gleichwertig. Es ist einfach die Nummer des Pins - hier 5. Am eindeutigsten ist aber vielleicht wenn du statt dessen PB5 schreibst. Dadurch verwechselt man es nicht so einfach mit PINB und PORTB. Das ist auch die Variante die in Beispielen i.d.R. verwendet wird.
Wieso greifst Du direkt auf die Register zu und nimmst nicht pinModer() digitalRead() und digitalWrite()?
Damit die LED bei einem Tastendruck umschaltet mußt Du auf die Flanke triggern.
Du nimmst eine Statusveriable uns speicherst den letzten Zustand des Tasters ab. Wenn der Zustand verschieden ist und der Taster gedrückt dann Schaltest Du die LED um.
Siehe Button Toggle Beispiel.
Grüße Uwe
Hi,
Danke schonmal für die schnellen Antworten! =)
@uwefed:
Ich bin kein Informatiker, belege aber einen Kurs für Mikrocontroller. Der Prof möchte, dass wir nicht pinMode(), digitalWrite(), etc. verwenden, sondern alles über die Bitmanipulation laufen lassen.
@Serenifly:
Vielen Dank, dass XOR habe ich bist jetzt (noch nicht wirklich) gekannt..
Könnte ich dann nur schreiben dass bei einem Tastendruck dann gechecked wird:
PB5 = PB2 XOR PB5 ??
Wie gesagt ich bin noch sehr frisch im Bereich Programmierung und Mikrocontroller.
Ob ich nun "PORTB5" oder "PINB5" schreibe macht also keinen Unterschied? Aber sonst würde es doch nicht zwei verschiedene Bezeichnungen gebe?
Habe versucht einmal den funktionierenden Sketch (ohne die Serial-Zeilen) mit "PB5" statt "PINB5" zu schreiben, allerdings meckert da dann der Compiler:
" Taster_LED_Ein_Aus:13: error: 'PB2' was not declared in this scope"
Und weiterhin besteht mein Problem, wenn ich zwar das Seriel.begin(9600) in void.setup schreibe leuchtet die LED und bei jedem Tastendruck wird im SerialMonitor angezeigt
"LED an
LED aus"
der Zustand der LED ändert sich allerdings nicht, es werden nur beide Zeilen direkt pro Druck ausgegeben. Weiterhin flackert auch die LED wieder sobald ich den SerialMonitor am PC öffne.
Entferne ich die drei Zeilen mit "Serial. ..." per // dann funktioniert das ganze wieder einwandfrei....
Das kann doch nicht sein, nur weil in der jeweiligen If-Schleife ein Serial.print steht funktioniert das Programm nicht mehr?
Ok, mein Problem mit der Textausgabe habe ich nun gelöst.
Ich glaube, dass Problem war, dass wenn die erste If-Bedingung = True war hat er die LED an gemacht, im Anschluss kam die nächste If-Bedingung, die somit auch True war und hat durch diese die LED wieder ausgemacht.
Solange die Textausgabe nicht vorhanden war, müsste er so schnell gewesen sein, dass die zweite if-Bedingung noch false war, aber mit der Textausgabe blieb ein bisschen Zeit, bis die Ausgabe ausgegeben war und die LED den Status gewechselt hat, dass die nächste dann auch True war.
Habe nun das zweite If mit einem "else if" ersetzt und es funktioniert einwandfrei
void setup() {
Serial.begin(9600);
DDRB = 0b00100000; // Pin13 Output, Rest Input
PORTB = 0b00000100; // Pin13 auf LOW - Pin10 Pull-up aktiviert
}
void loop() {
// PORTB5 = PINB2 XOR PINB5;
if ( !(PINB & (1<<PINB2)) ){ // wenn Bit Nr. 2 gesetzt
if(PINB & (1<<PINB5)){
PORTB &= ~(1<<PORTB5); // Pin13 auf LOW
Serial.println("LED aus");
}
else if (!(PINB & (1<<PINB5))){
PORTB |= (1<<PORTB5); // Pin13 HIGH
Serial.println("LED an");
}
delay(200); // Für die Verweilzeit beim drücken
}
}
Randruin: @Serenifly:
Vielen Dank, dass XOR habe ich bist jetzt (noch nicht wirklich) gekannt..
Könnte ich dann nur schreiben dass bei einem Tastendruck dann gechecked wird:
PB5 = PB2 XOR PB5 ??
Nein. Du musst das Eingangs-Register PINB schon richtig auslesen und das entsprechende Bit ausmaskieren.
PB5 ist wie gesagt nur "#define PB5 5" und PB2 ist "#define PB2 2"
Und XOR ist ^:
Ob ich nun "PORTB5" oder "PINB5" schreibe macht also keinen Unterschied? Aber sonst würde es doch nicht zwei verschiedene Bezeichnungen gebe?
Von der Funktion her ist es egal. Ich weiß nicht wieso es da 3 verschiedene Makros gibt. Aber für persönlich sehen PINB5 und PORTB5 zu ähnlich aus wie die Port Register. Ist aber Geschmackssache.
Dein Code suggeriert auch irgendwie dass man fürs Einlesen PINB5 machen muss und fürs Ausgeben PORTB5. Das ist nicht der Fall.