Forum: Mikrocontroller und Digitale Elektronik if Abfrage in main() ignoriert?


von Nn N. (jaytharevo)


Angehängte Dateien:

Lesenswert?

Hallo alle zusammen :)!

Also ich steh hier einfach total am Schlauch.
Bin gerade dabei ein Programm häppchenweiße zu debuggen.
Aus reinen Testzwecken schaltet man mal da mal da ein LED ein oder aus.
Funktioniert auch alles so weit.

Es geht um die Anweisung. Ich weiß ein wenig aus dem Zusammenhang 
gerissen, der restl. Code befindet sich im Anhang.

Es handelt sich um die Zeile.
1
if(Second==5) PORTC ^= (1<<PC1);

Das komische ist wenn ich es in der ISR ausführe alles funktioniert.
1
ISR (TIMER1_OVF_vect)
2
{static uint8_t _20_ms=0;
3
 _20_ms++;
4
5
if (_20_ms == 50)
6
  {
7
   Second++;
8
   _20_ms = 0;
9
   if(Second==5) PORTC ^= (1<<PC1);
10
  }
11
}

Also so funktioniert es.
Jemand eine Idee?

Mfg JTR

von ozo (Gast)


Lesenswert?

Volatile?

von Nn N. (jaytharevo)


Lesenswert?

LOL?! Warum hab ich das gelöscht? ...
1
volatile uint8_t Second=0;

Ist nun so global definiert, leider keine Veränderung.

MfG

von Nn N. (jaytharevo)


Lesenswert?

Hab wohl mal wieder ein C- Mysterium programmiert^^.

von Henry (Gast)


Lesenswert?

if(Second==5) PORTC ^= (1<<PC1);

Weil du diese Abfrage in deine Main machst.... und wenn deine ISR 
schneller ist und die Sekunden schon auf 6 hat bevor die bedinung 
getestet wird , kanns halt nicht funktionieren....also mach lieber

if(Second>4) PORTC ^= (1<<PC1);

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Wenn du den Portzustand sowohl in der ISR als auch in der Main toggelst 
soltest du dich auch nicht wundern ;)

von Bernhard S. (b_spitzer)


Lesenswert?

Wenn die Abfrage in main() steht, wird eine ganze Sekunde lang 
getoggelt. Erst ab der Sekunde 6 wird nicht mehr getoggelt. Wenn nur 1x 
getoggelt werden soll (das macht ja die ISR), dass musst Du in der ISR 
ein globales Flag setzen und dieses in main() nach Bearbeitung wieder 
löschen.

in der ISR:
if(Sekunde==5) tuwas=1;

in main():
if(tuwas){
  tuwas=0;
  PORTC ^= (1<<PC1);
}

tschuessle
Bernhard

von timer (Gast)


Lesenswert?

Sehe ich das richtig, dass _20_ms in der ISR jedes mal wieder neu 
angelegt wird und somit immer 1 ist. D.h. die IF-Abfrage wäre sinnlos

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

timer schrieb:
> Sehe ich das richtig, dass ...
nein. Es handelt sich um eine static lokale Variable die behält ihren 
Wert das ist schon richtig so.

von Nn N. (jaytharevo)


Lesenswert?

Danke für eure Antworten!

Ich denke, dass da irgendwo das richtige dabei sein wird :)!
Leider komm ich erst wieder am Montag zum testen, werde berichten.

@Läubi:
Hab wohl den upload der .c Datei vermasselt. Beim testen wurde natürlich 
nur an einer Stelle getoggelt.

@Henry:
Der Controller läuft mit 8Mhz. Ich glaub nicht, dass er bei so einem 
popeligen Programm nicht ein mal die main() durchrattern kann.

@Bernhard:
Das hört sich schon sehr vielversprechend an. Aber, dass jedes Mal eine 
gerade Zahl getoggelt wird?

Danke! Allen ein schönes WE :)!

MfG

von Peter (Gast)


Lesenswert?

Was denkst Du wie oft dass
1
if(Second==5) PORTC ^= (1<<PC1);
 im main ausgeführt wird, bis Second endlich gleich 6 ist? Vielleicht 
1000 mal?

von Nn N. (jaytharevo)


Lesenswert?

Oft.

Aber immer eine gerade Anzahl? Unwahrscheinlich....

von Nn N. (jaytharevo)


Angehängte Dateien:

Lesenswert?

Leider gab es keinen Unterschied.

Was zur Hölle kann, dass sein?
Hab auch die LED einzeln probiert, sie kann also blinken^^.

MfG

von Karl H. (kbuchegg)


Lesenswert?

Diese Berechnung

        OCR1A_tmp = Tick_P_el_tmp / Divisor_P_el + P_Offset;

ergibt 1000

d.h. diese while Schleife hier

        while(!(OCR1A==OCR1A_tmp))
        {
          if(OCR1A < OCR1A_tmp) OCR1A++;
          if(OCR1A > OCR1A_tmp) OCR1A--;
          set_sleep_mode(SLEEP_MODE_IDLE);
                sleep_mode();
        } // While end

(wenn überhaupt der Timer interrupt den µC aus dem Sleep Mode rausholt 
was ich nicht kontrolliert habe), dauert bei 20 ms INterrup Frequenz wie 
lange, damit sie den Wert von OCR1A von Initial 1999 auf 1000 reduziert 
hat?

Dann kommen hinten nach noch mal 20 ms Wartezeit

->
Es ist ziemlich unwahrscheinlich, dass du hier

  if(Second==5)

die Variable Second genau mit dem Wert 5 erwischt. Die wird da schon 
wesentlich weiter sein. (DIe müsste da schon so im Bereich um die 20 
haben)


Was soll das ganze eigentlich sein? Was hat es da mit dem Sleep Mode auf 
sich, wozu die ganzen Wartereien?

Ich kann mir nicht helfen. Das ganze sieht für mich nach "von hinten 
durch die Brust ins Auge" Programmierung aus.

von Karl H. (kbuchegg)


Lesenswert?

und second ist immer noch nicht volatile.

von Hans W. (hans_w30)


Lesenswert?

1
ISR (TIMER1_OVF_vect)  // ISR for counting the time with 16-Bit Timer1; Overflow every 20ms
2
{static uint8_t _20_ms=0;
3
4
 _20_ms++;
5
6
if (_20_ms == 50)
7
  {
8
   Second++;
9
   _20_ms = 0;
10
   PORTC ^= (1<<PC0);
11
  }
12
}

Du setzt jedes mal wenn du in die ISR kommst deinen Wert von _20_ms auf 
Null. Dann geht er ja schon nie in die if Abfrage in deiner ISR.
Wie sollte dann Second jemals 5 werden?

von Guru (Gast)


Lesenswert?

@ Hans W.

Lieber Hans,

Static Variablen werden nur einmal initialisiert. Das steht in einem 
C-Buch.

von Hans W. (hans_w30)


Lesenswert?

ups stimmt sorry 1tes Semester....
Nehm alles zurück und behaupte das gegenteil

Kann das aber sein das du 2 mal deinen Timer initialisierst? Bzw. dir 
deine Funktion implizit deklarierst?
Ein Prototyp gehört nicht unbedingt in die main
1
.....
2
// Prototypen
3
4
// Timer1 Initialization (ICP & PWM)
5
void Timer1_init(void);
6
7
// Timer1 Initialization
8
Timer1_init();

von Guru (Gast)


Lesenswert?

@ Hans W.

Lieber Hans,

das soll jetzt so ein kleiner Scherz unter Informatikern sein.

Du schriebst:

>Nehm alles zurück und behaupte das gegenteil

Das stimmt leider auch nicht so ganz.
Denn das Gegenteil von "jedesmal" ist eines von "niemals", "einmal" und 
"einige Male".
Eine static Variable wird aber genau "einmal" initialisiert.

Ich hoffe, Du findest das so lustig wie ich.

von Nn N. (jaytharevo)


Lesenswert?

Karl Heinz Buchegger schrieb:
> (wenn überhaupt der Timer interrupt den µC aus dem Sleep Mode rausholt
> was ich nicht kontrolliert habe)

kommt raus :)

> dauert bei 20 ms INterrup Frequenz wie
> lange, damit sie den Wert von OCR1A von Initial 1999 auf 1000 reduziert
> hat? DIe müsste da schon so im Bereich um die 20 haben)
>
Jo, 20s dürfte es dauern. Also alle 20ms ein Schritt weiter. 20ms*1000 = 
20 000ms = 20s. Daran hab ich wie immer nicht gedacht und wird auch des 
Rätslslösung sein. Ich verneige mich :)!


> Was soll das ganze eigentlich sein? Was hat es da mit dem Sleep Mode auf
> sich, wozu die ganzen Wartereien?
> Ich kann mir nicht helfen. Das ganze sieht für mich nach "von hinten
> durch die Brust ins Auge" Programmierung aus.

Ja, mag wohl so ausschauen. Wie bereits erwähnt handelt es sich um einen 
kleinen Ausschnit eines Programms. Quasi um gewisse Funktionen zu 
testen. Wenn man sein ganzes Prog. testen will und iwas nicht 
funktioniert wird, das eine endlose Sucherei.

Es geht darum die Position eines Servos langsam zu verändern.

Kennst du eine besser Methode (garantiert sogar) :D ;)!

Danke soweit!

MfG


ps: @guru: Ich habe gelacht :D! freaky

von Karl H. (kbuchegg)


Lesenswert?

Julian Schild schrieb:

> Es geht darum die Position eines Servos langsam zu verändern.
>
> Kennst du eine besser Methode (garantiert sogar) :D ;)!

1 Timer macht die Servoansteuerung. Ich hab jetzt nicht auf deine 
Taktfrequenz geachtet, aber der Timer 1 müsste normalerweise hinkommen.

Ein 2.ter Timer gibt einen Basistakt vor. In dessen ISR wird der OCR 
Wert für den Servo-Timer verändert, so dass er sich seiner Zielvorgabe 
annähert.
Sleep Mode braucht da kein Mensch dazu.

Hauptschleife
1
   while( 1 )
2
   {
3
     ServoSoll = 0;               // Zielvorgabe: Servo ganz nach links
4
5
     _delay_ms( 10000 );          // etwas warten (währenddessen verfährt
6
                                  // die Timer ISR das Servo
7
8
     ServoSoll = ServoMaximum;    // Zielvorgabe: Servo ganz nach rechts
9
10
     _delay_ms( 10000 );          // und wieder: das Servo fahren lassen
11
   }

Die Verfahr-ISR
Aufgabe: Wenn die Servo Istposition nicht mit der ServoSollposition 
übereinstimmt, dann für den Servo-Timer den OCR Wert nachstellen
1
ISR( .... )    // zb Overflow vom Timer 2
2
{
3
  if( OCR1A < ServoSoll )
4
    OCR1A++;
5
6
  else if( OCR1A > ServoSoll )
7
    OCR1A--;
8
}

Und dann natürlich noch den Timer 1, der so konfiguriert wird, dass er 
ganz alleine das Servosignal erzeugt, welches mit OCR1A beeinflusst 
werden kann.


Voila: Die komplette Servoansteuerung und Nachführung erledigen die 
Timer ganz von alleine bzw. mit einer ISR. In der Hauptschleife muss man 
nur noch die ServoSoll-Position zuweisen und das Servo fährt dann diese 
Position langsam an.

Hmm. Gerade noch mal drüber nachgedacht. Man könnte wahrscheinlich das 
ganze auch so regeln, dass der Timer 1 beides übernimmt. Er generiert 
sowohl die Servosignale (per Hardware) als er sich auch darum kümmert, 
dass die Servo Istposition an die Soll Position herangeführt wird (in 
einer ISR)

von Nn N. (jaytharevo)


Lesenswert?

Das ist, wie immer, eine gute Idee.

Dafür muss ich aber sogar den 3. Timer verwenden :D!

Denn der 1. 8 Bit Timer (Timer 0) zählt Pulse (fmax = 4kHz).
Das Ergebnis nach 50s ist dann ausschalggebend für die Servoposition.

Das der Timer1 (16Bit) bereits die Servoansteuerung übernimmt sieht man 
eh, außerdem übernimmt er auch noch die Funktion einer "Uhr".

Gefällt mir sehr gut, den Code schlanker zu machen und dafür auf die 
Hardware auslagern :)!

Danke Karl!! :)

MfG

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.