Hi!
Ich bins wiedermal.
Ich habe folgendes Problem:
Im angeführten Quellcode funktioniert die if-Anweisung für Pause und
pausiert wird ausgegeben, jedoch scheint es so, als würde der Rest nicht
passieren. Der Timer läuft nach wie vor weiter und auch, wenn ich Weiter
oder Stop eingebe scheint es so, als würde er, weil w=0 nicht in die
andere if-Anweisung hupfen.
Habt ihr vl eine Lösung?
1
SIGNAL(SIG_USART0_RECV)
2
{
3
charitr[10];
4
intw=0;
5
6
o=UDR0;
7
if((o!=0x0D)&&(o!=0x0A))
8
{
9
buffer[s++]=o;
10
}
11
elseif((o==0x0D))
12
{
13
buffer[s]=0;
14
if(strcmp(buffer,"Pause")==0)
15
{
16
TIFR=(0<<TOV0);// Timer Interrupt Flag Register --> disable
17
w=1;
18
s=0;
19
USART_Transmit_String("pausiert");
20
}
21
elseif(w==0)s=100;
22
if(w==1)
23
{
24
if(strcmp(buffer,"Stop")==0)//Stop
25
{
26
USART_Transmit_String("gestopt");
27
w=0;
28
flag=1;
29
s=0;
30
TIFR=(1<<TOV0);// Timer Interrupt Flag Register --> enable
31
}
32
elseif(strcmp(buffer,"Weiter")==0)//Weiter
33
{
34
USART_Transmit_String("fortf");
35
w=0;
36
s=0;
37
TIFR=(1<<TOV0);// Timer Interrupt Flag Register --> enable
Oliver Kra schrieb:> Im angeführten Quellcode funktioniert die if-Anweisung für Pause und> pausiert wird ausgegeben, jedoch scheint es so, als würde der Rest nicht> passieren.> Der Timer läuft nach wie vor weiter
Logisch. Niemand stoppt den Timer.
> und auch, wenn ich Weiter> oder Stop eingebe scheint es so, als würde er, weil w=0 nicht in die> andere if-Anweisung hupfen.
Klar ist w dann immer 0.
w ist eine lokale Variable und wird als solche beim Betreten der
FUnktion immer wieder neu erzeugt und mit 0 initialisiert.
> Der Timer läuft nach wie vor weiter
Klar, weder kannst du über TIFR den Timer anhalten, noch kannst du dort
den Interrupt disablen/enablen. Letzteres passiert in TIMSK.
Das mit der Variable w war eine Unaufmerksamkeit meinerseits.
Das heißt um den Timer abzuschalten müsste ich TIMSK = (0<<TOIE0);
setzen. Bleibt dann der Timer auch genau in dem Zustand in dem er war?
Wenn ich das richtig verstanden habe, wird der Interrupt dann gar nicht
mehr aufgerufen, bis ich es halt wieder 1 setze, oder?
lg
Oliver Kra schrieb:> Das heißt um den Timer abzuschalten müsste ich TIMSK = (0<<TOIE0);> setzen. Bleibt dann der Timer auch genau in dem Zustand in dem er war?
Nein.
Nein.
Hast du schon mal nachgesehen, was im Datenblatt zum Thema Timer so
alles steht? Das ist zwar auf englisch, aber da musst du durch.
Geheimtipp: AVR-Tutuorial.
Oliver
Also meiner Meinung nach passt das so, zur Sicherheit könnte ich TCNTO
noch sichern und danach wieder hineinschreiben, aber generell dürfte der
Interrupt dann nicht aufgerufen werden. Eine andere Möglichkeit hab ich
nicht gefunden.
Lothar Miller schrieb:> Dein Problem liegt aber grundlegend woanders. Denn sowas macht man nicht> in einem Interrupt:>
1
>if(strcmp(buffer,"Pause")==0)
2
>:
3
>USART_Transmit_String("pausiert");
4
>
> Solche Verwaltungsaufgaben macht man in der Main-Loop. Interruptroutinen> sind prinzipiell kurz und knackig zu halten.
Das weiß ich, dass ein Interrupt kurz zu halten ist, aber mir fällt
keine andere Möglichkeit ein, wo ich es hineingebe, sodass es trotzdem
sofort reagiert. Main ist keine Lösung, da andere Funktionen aufgerufen
werden.
> Main ist keine Lösung, da andere Funktionen aufgerufen werden.
Und trotzdem gehört es genau dort hinein.
Wenn in deiner Mainloop andere Funktionen dein Programm blockieren
können, dann ist dein Konzept falsch. Auch die Mainloop sollte in
absehbarer Zeit (mein Vorgabe ist da max. 5ms) einmal durchlaufen
werden.
> sodass es trotzdem sofort reagiert.
Definiere "sofort".
Welche Zeit ist das? 1ms, 10ms, 100ms?
Oliver Kra schrieb:> Also meiner Meinung nach passt das so, zur Sicherheit könnte ich TCNTO> noch sichern und danach wieder hineinschreiben, aber generell dürfte der> Interrupt dann nicht aufgerufen werden. Eine andere Möglichkeit hab ich> nicht gefunden.
Dann schau noch einmal im Dtaenblatt nach, was da zum Thema 'Prescaler'
steht. OK. Es steht dort nicht unbedingt explizit dort, wie man den
Timer anhält, aber mit ein bischen Querdenken kommt man drauf.
Und noch ein Nein.
So:
TIMSK = (0<<TOIE0);
löscht man grundsätzlich kein Bit in einem Register. Genauso wie man so
TIMSK = (1<<TOIE0);
kein Bit in einem Register setzt.
http://www.mikrocontroller.net/articles/Bitmanipulation
Dein 'w'-Problem existiert immer noch.
Welche Aufgabe hat denn diesess 'w' eigentlich? Alles wäre viel
einfacher, wenn du vernünftige Variablennamen benutzen würdest und nicht
w, o, s und was weiß ich noch alles.
Du hast 100-tausend Variablen, die nicht global sein müssen , aber
diejenige, die global sein muss (oder zumindest Funktions-static) ist es
nicht (nämlich w)
Karl heinz Buchegger schrieb:> Dann schau noch einmal im Dtaenblatt nach, was da zum Thema 'Prescaler'> steht. OK. Es steht dort nicht unbedingt explizit dort, wie man den> Timer anhält, aber mit ein bischen Querdenken kommt man drauf.
An das hab ich natürlich nicht gedacht. DAnke
> Und noch ein Nein.> So:> TIMSK = (0<<TOIE0);> löscht man grundsätzlich kein Bit in einem Register. Genauso wie man so> TIMSK = (1<<TOIE0);> kein Bit in einem Register setzt.
Nicht? Dachte, da hab ich endlich mal was richtig?
Ich hab leider noch sehr viel Nachholbedarf.
Oliver Kra schrieb:>> Und noch ein Nein.>> So:>> TIMSK = (0<<TOIE0);>> löscht man grundsätzlich kein Bit in einem Register. Genauso wie man so>> TIMSK = (1<<TOIE0);>> kein Bit in einem Register setzt.>> Nicht? Dachte, da hab ich endlich mal was richtig?
Dann frag ich mich, wer dir diesen Code geschrieben hat :-)
1
ISR(SIG_OVERFLOW0)//Timer fr die Motorsteuerung
2
{
3
if(richtungx==1){PORTB=PORTB|(1<<PB1);}//Richtungsabfrage x
4
else{PORTB=PORTB&~(1<<PB1);}
denn hier ist es richtig. So macht man das (abgesehen von der ausseren
Form dieses Codestückes. Die ist scheuslich und nicht wirklich so, dass
das ganze übersichtlich wird)
Karl heinz Buchegger schrieb:> Dein 'w'-Problem existiert immer noch.>> Welche Aufgabe hat denn diesess 'w' eigentlich? Alles wäre viel> einfacher, wenn du vernünftige Variablennamen benutzen würdest und nicht> w, o, s und was weiß ich noch alles.
Ich will nicht all zu lange Variablennamen verwenden, aber du hast
natürlich recht. Die Namen sollten auch auch Sinn machen.
Ja das mit dem W ist blöd, weiß schon, ich muss sie mal statisch machen.
Werd das gleich mal tun und dann probieren.
Oliver Kra schrieb:> Ich will nicht all zu lange Variablennamen verwenden, aber du hast> natürlich recht. Die Namen sollten auch auch Sinn machen.> Ja das mit dem W ist blöd, weiß schon, ich muss sie mal statisch machen.> Werd das gleich mal tun und dann probieren.
und wenn du schon dabei bist:
Formatier dir den Code um. Du stellst dir mit deiner Einrückstrategie
und deinem unübersichtlichen Code und den viel zu kurzen Variablennamen
nur selbst ein Bein.
Karl heinz Buchegger schrieb:> Du hast 100-tausend Variablen, die nicht global sein müssen , aber> diejenige, die global sein muss (oder zumindest Funktions-static) ist es> nicht (nämlich w)
Sind wirklich so viele Variablen unnötigerweise als statisch deklariert?
Karl heinz Buchegger schrieb:> Dann frag ich mich, wer dir diesen Code geschrieben hat :-)> ISR(SIG_OVERFLOW0) //Timer fr die Motorsteuerung> {> if(richtungx==1) {PORTB = PORTB |(1 << PB1);} //Richtungsabfrage x> else {PORTB = PORTB &~ (1 << PB1);}>> denn hier ist es richtig. So macht man das (abgesehen von der ausseren> Form dieses Codestückes. Die ist scheuslich und nicht wirklich so, dass> das ganze übersichtlich wird)
Den hab ich geschrieben. Dank eurer Hilfe.
Aber das brauch ich doch nur so, wenn ich den Rest im Register nicht
ändern will. In dem Fall vom Timer änder ich ja nur ein Bit und der Rest
ist doch egal, oder? In der Main hab ich es ja auch immer so gehalten
und es hat gefunkt.
Hab da etwas falsch verstanden?
Karl heinz Buchegger schrieb:> und wenn du schon dabei bist:> Formatier dir den Code um. Du stellst dir mit deiner Einrückstrategie> und deinem unübersichtlichen Code und den viel zu kurzen Variablennamen> nur selbst ein Bein.
Wie meinst, aber gerade durch das richtige Einrücken wird es ja
übersichtlicher. Oder hab ich das auch falsch gemacht? Ich weiß ein paar
sachen sind noch nicht wirklich formatiert.
Das mit den Variablennamen werd ich auch in Angriff nehmen und wenn es
geht heute noch alles ändern.
Oliver Kra schrieb:> Aber das brauch ich doch nur so, wenn ich den Rest im Register nicht> ändern will. In dem Fall vom Timer änder ich ja nur ein Bit und der Rest> ist doch egal, oder?
Solange bis du bei der nächsten Codeerweiterung auch noch ein anderes
Bit in diesem Register benötigst. Dann ist das Gejammere groß, dass sich
dieses Bit irgendwo 'magisch' selbst verstellt.
Man tatscht immer nur das eine Bit an, welches man ändern will und nicht
alles. Das ist 'defensives Programmieren' - vorausschauend arbeiten, so
dass man auch in der Zukunft nicht den halben Code wegen einer
Erweiterung ändern muss.
> Man tatscht immer nur das eine Bit an, welches man ändern will und nicht> alles. Das ist 'defensives Programmieren' - vorausschauend arbeiten, so> dass man auch in der Zukunft nicht den halben Code wegen einer> Erweiterung ändern muss.
Aber da mir ja hier die anderen Bits egal funkt es, oder? Ich werde das
aber auch noch ändern. Ich merke immer öfter, dass Programmieren nicht
zu meinen Spezialgebieten zählt, gg
Oliver Kra schrieb:> Karl heinz Buchegger schrieb:>> und wenn du schon dabei bist:>> Formatier dir den Code um. Du stellst dir mit deiner Einrückstrategie>> und deinem unübersichtlichen Code und den viel zu kurzen Variablennamen>> nur selbst ein Bein.>> Wie meinst, aber gerade durch das richtige Einrücken wird es ja> übersichtlicher. Oder hab ich das auch falsch gemacht? Ich weiß ein paar> sachen sind noch nicht wirklich formatiert.
Ich hab noch mal drübergescannt. Wenigstens hast du es einigermassen
konsequent gemacht.
Trotzdem: auch nach einem if kommt der abhängige Teil in die nächste
Zeile eingerückt.
1
SIGNAL(SIG_USART0_RECV)
2
{
3
charnextChar;
4
5
nextChar=UDR0;
6
7
if(nextChar=='\r')// Linefeed wird generell ignoriert
8
return;
9
10
if(nextChar!='\n'){// alles andere wird dranngehängt
11
buffer[s++]=nextChar;
12
return;
13
}
14
15
// bleibt nur noch '\n'
16
// Zeile ist vollständig, ein paar Schlüsselwörter gleich jetzt auswerten
17
buffer[s]='\0';
18
19
if(strcmp(buffer,"Pause")==0)
20
{
21
TIMSK&=~(1<<TOIE0);// Overflow für den Timer abschalten
22
buffer[0]='\0';// damit einlesen() nichts auswertet
23
s=0;
24
USART_Transmit_String("pausiert");
25
}
26
27
elseif(strcmp(buffer,"Stop")==0)
28
{
29
TIMSK|=(1<<TOIE0);// Overflow Interrupt wieder erlauben
30
buffer[0]='\0';// damit einlesen() nichts auswertet
31
s=0;
32
USART_Transmit_String("gestoppt");
33
}
34
35
elseif(strcmp(buffer,"Weiter")==0)
36
{
37
TIMSK|=(1<<TOIE0);
38
buffer[0]='\0';// damit einlesen() nichts auswertet
39
s=0;
40
USART_Transmit_String("fortf");
41
}
42
43
else
44
s=100;// wenn s gleich 100 ist, fängt einlesen() mit
Oliver Kra schrieb:> aber auch noch ändern. Ich merke immer öfter, dass Programmieren nicht> zu meinen Spezialgebieten zählt, *gg*
Gerade dann solltest du so defensiv wie nur möglich arbeiten.
Es sind die Nebeneffekte die einem bei der Programmierung das Leben
schwer machen und irgendwann nicht mehr beherrschbar sind. Dazu gehören
zu viele Flags mit immer kryptischeren Auswertungen, deren Geflecht
irgendwann nicht mehr durchschaubar ist und dazu gehören auch
Anweisungen, die ausser dem Gewollten noch andere Dinge machen, wie zb
Bits setzen/löschen die sie eigentlich in Ruhe lassen sollten.
Karl heinz Buchegger schrieb:> Ich hab noch mal drübergescannt. Wenigstens hast du es einigermassen> konsequent gemacht.> Trotzdem: auch nach einem if kommt der abhängige Teil in die nächste> Zeile eingerückt.>
1
>SIGNAL(SIG_USART0_RECV)
2
>{
3
>charnextChar;
4
>
5
>nextChar=UDR0;
6
>
7
>if(nextChar=='\r')// Linefeed wird generell ignoriert
8
>return;
9
>
10
>if(nextChar!='\n'){// alles andere wird dranngehängt
11
>buffer[s++]=nextChar;
12
>return;
13
>}
14
>
Die bieden Zeilen verstehe ich nicht ganz. Wozu sind die jetzt da? Der
Linefeed und der /n geben ja nur an, dass das Sende beenden ist bzw. das
wort zu ende ist. Für mich haben ja die Zeichen keine anderen Bedeutung,
oder?
Jetzt schließe ich den String ja in jeder if-Anweisung nochmal ab. Das
heißt es ist immer einmal zu viel, oder?
s setze ich 100, damit ich ansonsten warten kann bis eingelesen wurde.
Kann mir theoretisch auch einen andere Variable auf 1 oder was weis ich
setzen.
Danke schon mal an alle für die schnellen und hilfreichen Antworten.
Karl heinz Buchegger schrieb:> Gerade dann solltest du so defensiv wie nur möglich arbeiten.> Es sind die Nebeneffekte die einem bei der Programmierung das Leben> schwer machen und irgendwann nicht mehr beherrschbar sind. Dazu gehören> zu viele Flags mit immer kryptischeren Auswertungen, deren Geflecht> irgendwann nicht mehr durchschaubar ist und dazu gehören auch> Anweisungen, die ausser dem Gewollten noch andere Dinge machen, wie zb> Bits setzen/löschen die sie eigentlich in Ruhe lassen sollten.
Ich werde den ganzen Code mal in Ruhe überarbeiten und gegebenenfalls
verbessern. Kann ich ihn dann diese oder spätestens nächste Woche posten
und ihr sagt mir eure Meinung?
Will nämlich das Forum nicht unbedingt zumüllen.
Oliver Kra schrieb:> Karl heinz Buchegger schrieb:>> Ich hab noch mal drübergescannt. Wenigstens hast du es einigermassen>> konsequent gemacht.>> Trotzdem: auch nach einem if kommt der abhängige Teil in die nächste>> Zeile eingerückt.>>>
1
>>SIGNAL(SIG_USART0_RECV)
2
>>{
3
>>charnextChar;
4
>>
5
>>nextChar=UDR0;
6
>>
7
>>if(nextChar=='\r')// Linefeed wird generell ignoriert
8
>>return;
9
>>
10
>>if(nextChar!='\n'){// alles andere wird dranngehängt
11
>>buffer[s++]=nextChar;
12
>>return;
13
>>}
14
>>
> Die bieden Zeilen verstehe ich nicht ganz. Wozu sind die jetzt da?
Na ja.
Was macht denn ein 'return'?
return -> Ausstieg aus der Funktion. Funktion ist beendet.
Was passiert daher hier?
Wenn ein \r daher kommt dann passiert gar nichts, es wird schlicht und
ergreifend einfach ignoriert.
Alles andere: Solange es kein \n ist, wird einfach an den String
angehängt und das wars dann -> Funktion ist fertig, nichts wie raus
\r und \n sind die C-Schreibweisen für 0x0D und 0x0A
Ziel des ganzen ist es, da nicht 15 ineinander verschachtelte if zu
erhalten, die einem die Übersicht rauben.
Auch wenn die generelle Empfehlung ist, mitten in einer Funktion keine
returns zu machen, so gibt es doch eine Ausnahme:
Funktionen prüfen am Anfang gerne irgendwelche Dinge ab. zb Fehler oder
sonstige Nebenbedingungen. Und wenn die nicht erfüllt sind, gehts sofort
wieder raus. Dann ist ein return durchaus ok. Er verhindert, dass alles
zu einer
if
if
if
if
Orgie ausartet. Am Anfang der Funktion feststellen ob es was zu tun gibt
und wenn nicht, wird die Funktion sofort wieder verlassen.
Karl heinz Buchegger schrieb:> Na ja.> Was macht denn ein 'return'?>> return -> Ausstieg aus der Funktion. Funktion ist beendet.>> Was passiert daher hier?>> Wenn ein \r daher kommt dann passiert gar nichts, es wird schlicht und> ergreifend einfach ignoriert.>> Alles andere: Solange es kein \n ist, wird einfach an den String> angehängt und das wars dann -> Funktion ist fertig, nichts wie raus>> \r und \n sind die C-Schreibweisen für 0x0D und 0x0A
Ich weiß, hab mir das eh gerade nochmal durchgedacht. Aber mit return
beendet er doch den ganzen Interrupt und würde den String nicht
abschließen und auch nicht auf Pause etc, prüfen.
Wäre nicht break richtig?
Oliver Kra schrieb:> Ich weiß, hab mir das eh gerade nochmal durchgedacht. Aber mit return> beendet er doch den ganzen Interrupt und würde den String nicht> abschließen und auch nicht auf Pause etc, prüfen.
Solange kein \n daher kommt, kann deiner Vereinbarung nach der String
gar nicht fertig sein. Erst ein \n beendet den String! Und der Fall ist
ja ausgenommen :-)
if( nextChar != '\n' ) {
Wenn Du zufällig in der Menge am Strassenrand beim Fastnachtsumzug
stehst,
wo Erdbeere, Apfel und Haselnuss geschmissen wird...
Wenn Du zufällig gerade eine Erdbeerdiät machst...
Wenn Du etwas auffängst, es als Haselnuss erkennst und der braunäugigen
Schönheit neben Dir schenkst...
Reisst Du es ihr dann anschliessend noch zweimal aus der Hand um zu
prüfen ob es nicht eine Erdbeere oder ein Apfel ist?
Dann wird es aber nichts mit der Vermehrung!
Karl heinz Buchegger schrieb:> Solange kein \n daher kommt, kann deiner Vereinbarung nach der String> gar nicht fertig sein. Erst ein \n beendet den String! Und der Fall ist> ja ausgenommen :-)>> if( nextChar != '\n' ) {
Ah, jetzt versteh ich es!
So wird ja das ganze viel schneller, weil ich die ganzen if anweisungen
nur Prüfe wenn der String abgeschlossen ist. Vielen Dank!
Ich werd mir erlauben den Code zu kopieren, ich hoffe das ist ok gg
Wie gesagt ich werde mich gleich daran machen alles nochmal zu
überarbeiten und dann mal die neue Version posten, hoffe das ist ok.
Lg und vielen Dank mal jetzt schon an alle!