Schönen Abend,
ich beschäftige mich eher seit kurzer Zeit mit der Kunst des
uC-Programmierens und habe eine für viele von euch wahrscheinlich eher
dumm gestrickte Frage.
Hier mein Problem:
Ich würde gerne innerhalb des Hauptprogramms durch eine while-Schleife
das Programm zum Warten veranlassen. Dieses Warten soll unterbrochen
werden, wenn eine der beiden Bedingungen erfüllt ist:
1.) die Variable "start" ihren Wert auf 1 verändert
(dies kann nur innerhalb der Interrupt-Routine geschehen)
2.) der Zustand eines als Eingang definierten Pins auf logisch "high"
wechselt.
Der Code gestaltet sich folgendermaßen (so wie ich's mir ersponnen
habe):
SIGNAL(SIG_INTERRUPT0)
{
if (start == 0)
{
start = 1;
...
}
else
{
start = 0;
...
}
}
// im Main:
volatile uint8_t start;
while( !(PINC & (1<<PC1)) || (start) ); <- hier das Problem
Die Einzelanweisung funktionieren einwandfrei, sprich die Abfrage des
Pins PC1 oder die Abfrage nach dem Variablenwert start. Lediglich die
mit Oder (||) verknüpfte Symbiose möchte irgendwie nicht funken??
Nun habe ich das Tutorial durchforstet (wirklich gut gemacht!) aber in
meinem Fall glaube ich liegt das Problem eher bei meinem C-Code. ich
habe auch schon diverse andere Codes versucht wie z.B.:
while( !(PINC & (1<<PC1)) || (start==1) );
Langsam weiß ich nicht recht weiter. Ich hoffe irgend jemand kann mir
hierbei helfen.
Gruß,
Pawel
Hallo Rufus,
danke für die schnelle Antwort. Ist die Deklaration denn falsch ?
volatile uint8_t start;
Oder ist es die Position der Deklaration im allgemeinen Teil des
Programms (also unmittelbar vor dem Main-Hauptprogramm, aber in der
gleichen C-Datei)
Hi Pawel
Nee, die Deklaration mit volatile ist prima!
Das Problem liegt woanders, Du hast einen Logik-Fehler: In Deinem Fall
brauchst Du eine AND-Verknüpfung nicht OR.
while( !(PINC & (1<<PC1)) && (start==1));
Du wirst bestimmt selbst draufkommen, wieso... ;o))
Gruss Peter
Zu der Logik:
Als Eingang stehen der Pin und der Inhalt von start zur verfügung.
Der Pin sei durch P repräsentiert und start durch C (start=0 sei
logisch 0, alles andere logisch 1). Soll der Abbruch erfolgen, wenn
mindestens eine der beiden Bedingungen erfüllt ist, so muss gelten:
Abbruch A = P + C. Die Schleifenbedingung S der while-Schleife ist der
Abbruchbedingung entgegengesetzt, also S = /A.
Somit wird S = /(P + C). Nun kann man noch mit DeMorgan rumröteln und S
= /P * /C abfragen. Belassen wir es mal beim ersteren.
while(S)
while(/A)
while(/(P + C))
while(!(P + C))
while(!((P) + start))
while(!((PINC & (1 << PC1)) + start))
Eingesetzt in dem Sourcecode
int main (void) {
while(!((PINC & (1 << PC1)) || start)) ;
while(!(PINC & (1 << PC1)) && (start == 1));
}
führt es zu folgendem Assembler-Code:
...
while(!((PINC & (1 << PC1)) || start)) ;
7c: 99 99 sbic 0x13, 1 ; 19
7e: 04 c0 rjmp .+8 ; 0x88
80: 80 91 60 00 lds r24, 0x0060
84: 88 23 and r24, r24
86: d1 f3 breq .-12 ; 0x7c
while(!(PINC & (1 << PC1)) && (start == 1));
88: 99 99 sbic 0x13, 1 ; 19
8a: 04 c0 rjmp .+8 ; 0x94
8c: 80 91 60 00 lds r24, 0x0060
90: 81 30 cpi r24, 0x01 ; 1
92: d1 f3 breq .-12 ; 0x88
...
start steht im RAM bei 0x0060. Der Vergleich mit der zuvor genannten
Lösung zeigt einen Unterschied auf. Im ersten Fall wird in der Schleife
verblieben, wenn start==0 ist. Dagegen im zweiten Fall, wenn start==1
ist.
Gruß
Marco
-
@Pawel:
Bitte, gern geschen. Aber Pawel hat eigentlich mit seinem Hinweis
ebenfalls recht: "volatile uint8_t start;" müsste ausserhalb vom main
als globale Variable definiert sein. Reklamiert denn der Compiler nicht,
weil "start" in der ISR undefiniert ist?
@Marco:
Nette Abhandlung, Du magste es offenbar sehr ausführlich! ;o))
Trotzdem hast Du nicht ganz recht:
Im ersten Fall wird in der Schleife verblieben, solange mindestens eine
der zwei Bedingungen True ist: (PINC.1=High) und/oder (Start!=0)
Im zwitenFall wird in der Schleife verblieben, solange beide
Bedingungen True sind: (PINC.1=High) und (Start==1)
Gruss Peter
Erst mal frohe Weihnachten!
@Peter
In der Tat weicht meine Lösung von der Aufgabenstellung ab. Dort steht:
...Warten soll unterbrochen werden, wenn eine der beiden Bedingungen
erfüllt ist: ... Wenn wirklich nur eine der beiden Bedingungen zum
Ausbruch aus der Schleife führen sollte, so müsste wohl irgendwie eine
XOR-Verknüfung eingebaut sein. Zweitens sollte das Warten unterbrochen
werden, wenn start auf 1 geht. Hier sehe ich den Fehler, denn es müsste
(Start == 0) im zweiten Fall heißen.
Und wenn man sich den Assembler-Code ansieht, sieht man, dass beide
Routinen fast gleich sind. Im ersten Fall wird in der Warteroutine
verblieben bei Start==0 (and r24, r24) im zweiten Fall bei Start==1
(cpi r24,0x01). Bei Beiden Routinen kann ein gesetzter Portpin zum rjmp
+8 Befehl führen, wo dann die zweite Bedingung übergangen wird.
Gruß
Marco
-
Eine eigene Frage?
Dieser Thread ist über 20 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.