Forum: Compiler & IDEs Timer ungleichmässig


von Achim S. (achims)


Lesenswert?

Hallo
verwende einen Atmega 128 mit 16Mhz. Bei dem Stück Prg kommt es zu einem 
ungleichmässigen Zeit bei an und aus. Teilweise wird sogar eine längere 
Pause (1s) eingelegt. Verstehe leider nicht warum.
1
void nibo_timer2()  // Timer 1ms  - 1000ms=1Sekunde
2
  {          
3
  TCNT2 = 0;
4
  OCR2=249;
5
  TCCR2=(1<<WGM21)|(1<<CS21)|(1<<CS20);  
6
  TIMSK |= (1<<OCIE2);          
7
  }
8
9
ISR (TIMER2_COMP_vect)    // wait1=1ms,
10
{
11
  if(wait1<500)      // Takt 1ms auf 10ms
12
  {
13
  wait1++;      // erhöht um je 1ms
14
  }
15
  else        // wenn dann ...
16
  {
17
  wait1=0;      // setzt wait1 auf 0
18
  signal_wait1=0xFF;    // Signal alle 10ms
19
  }
20
}
21
22
habe schon einiges probiert
23
24
while(1){
25
    
26
  if (signal_wait1==0xFF)
27
  {
28
//cli();***
29
signal_wait1=0;
30
//sei();***
31
leds_set_status(1,5);     /* Led5 soll 5sek lang rot sein */
32
}
33
34
35
if (signal_wait1==0xFF)
36
{
37
//cli();***
38
signal_wait1=0;
39
//sei();***
40
  
41
leds_set_status(0,5);     /* Led5 soll 5sek lang rot aus sein */
42
}
43
}
44
return 0;      
45
}
Das Ziel ist es eigentlich ein Stück Prg zu haben, wie es als Beispiel 
bei Johann steht. möchte mit signal_wait eine Pause machen ohne das Prg 
zu stoppen ode in delay zu verzweigen. Vielleicht seht ihr mein Fehler.
danke

von Karl H. (kbuchegg)


Lesenswert?

Hier (mit einer vernünftigen Formatierung sieht man es besser) ...
1
  while(1) {
2
    
3
    if (signal_wait1 == 0xFF)
4
    {
5
      led einschalten
6
    }
7
8
    if (signal_wait1 == 0xFF)
9
    {
10
      led ausschalten
11
    }
12
  }
13
14
  return 0;      
15
}

... hast du etwas, was man eine 'race condition' nennt. Schau dir die 
beiden if an. Sie haben beide dieselbe Bedingung. D.h. abhängig davon, 
wo deine Hauptschleife ganz genau steht, wenn der entscheidende 
Interrupt kommt, wird einmal das obere if ausgeführt und einmal das 
untere. Welches der beiden aber genommen wird, hängt von den exakten 
Umständen innerhalb der Schleife ab. Mit einer kleinen Programmänderung, 
und damit einem klitzeklein anderem Timing, kann sich das alles 
umdrehen.

Das ist so, wie wenn du zu deinem Kumpel sagst:
2 Regeln:
* wenn die Sonne scheint, mach das Fenster auf
* wenn die Sonne scheint, mach das Fenster zu

Dann wird dir der sagen: "Ja was denn nu? auf oder zu? Du widersprichst 
dir doch selber!"
Deinem µC hingegen ist das wurscht. Der hackelt stur seine beiden Regeln 
ab, wieder und immer wieder, viele tausend mal in der Sekunde. Und je 
nachdem wann genau die Sonne hinter einer Wolke hervorkommt prüft er 
gerade die eine oder die andere Regel und führt dann auch 
dementsprechend die Konsequenz (auf oder zu) aus.



Wenn dein signal_wait1 auf 0xFF geht, weißt du erst mal nur, dass 1 
halbe Sekunde rum ist. Mehr nicht. Davon losgelöst ist dann die Aktion, 
die passieren soll: Wenn die LED brannte, dann schaltest du sie aus. 
Wenn sie ausgeschaltet ist, dann schaltest du sie ein.
1
  while(1) {
2
    
3
    if (signal_wait1 == 0xFF)
4
    {
5
      signal_wait1 = 0;
6
7
      if( led ist ausgeschaltet )
8
        led einschalten
9
      else
10
        led ausschalten
11
    }
12
  }
13
14
  return 0;      
15
}



Und rück deinen Code ordentlich ein. Sonst wirst du immer Hilfe bei 
seltsamen Logikfehlern brauchen, die du selber nicht siehst, weil dein 
Code  einfach nur unübersichtlich ist.

von Krapao (Gast)


Lesenswert?

> ISR (TIMER2_COMP_vect)    // wait1=1ms,
> {
>   if(wait1<500)           // Takt 1ms auf 10ms
>   ...
>     signal_wait1=0xFF;    // Signal alle 10ms

Die Zahl 500 verstehe ich nicht, wenn ich die Kommentare betrachte.

von Achim S. (achims)


Lesenswert?

Erst mal vielen Dank für Eure Hilfe, besonders Karl Heinz. Werde deine 
Worte befolgen und es so machen, wie du es sagst.
Sorry wegen den Kommentaren. Habe einfach was rauskopiert und die 
Kommentare drin gelassen. Eigentlich ist das meine Arbeitsroutine zum 
testen der Programme oder Teile. Im Original steht 10 ms. Der Timer und 
die ISR dienen zum Erzeugen von 10 ms Impulsen. Diese möchte ich nutzen 
um entsprechende

ISR (TIMER2_COMP_vect)    // wait1=1ms,
{
  if(wait1<9)      // Takt 10ms
  {
  wait1++;      // erhöht um je 1ms
  }
  else        // wenn dann ...
  {
  wait1=0;      // setzt wait1 auf 0
  signal_wait1=0xFF;    // Signal alle 10ms

Verzögerungen zu schalten. Dies sollen im Prg genutzt werden um z.B. die 
Entprellung zu machen. Besonders aber in einer Funktion von Johann um 
delay zu ersetzen und damit Zeitverzögerungen zu umgehen. Es könne 
dadurch auch verschiedene Zeiten gleichzeizig ablaufen. Es gibt ja schon 
einiges in den einzelnen Artikeln. Bei Ihm sieht es so aus:

if(0==count.ms10.led1)
{
PIN_LED|=)(1<<PAD_LED1)
count.ms10.LED1=100
}
Habe den Artikel gerade nicht zur Hand. Das ist nur ein Teil da von.
Im Kommentar heisst es dazu:
Falls Countdown für LED1 abgelaufen ist, neu aufziehen auf 1 Sekunde und 
toggle LED1
Was mir nicht gefällt, ist die Grösse der Datein und Anweisungen die 
dazu nötig sind. Wenn ich den Timer für 10ms einmal aufrufe und die ISR 
dazu nehm geht es doch auch kleiner und Einfacher (?). Das oberste Ziel 
dabei ist eigentlich auch die Entprellung für verschiedene Zeiten zu 
machen, so das ich mit einem Taster ein Menue bedienen kann. Aber alles 
der Reihe nach.
achim

von Achim S. (achims)


Lesenswert?

Hallo
Muss noch mal nachfragen. Habe das Prg so geändert, doch leider ohne 
Funktion jetzt. Der Timer und ISR sind gleich beblieben,

while(1){

  if (signal_wait1==0xFF)
    {
      signal_wait1=0;
    }

  if(PINC & (0<<PC5))     // Abfrage Eingang zu LED 5 Grün
    {
       leds_set_status(1,5);  // setzt LED 5 Grün auf ein
    }

  else
    {
        leds_set_status(0,5);  // schaltet LED 5 Grün auf aus
    }
}
return 0;
}
Die LED 5 Grün liegt bei mir auf dem PC5
Irgend was mache ich wieder falsch. Habe mich an dein Vorbild gehalten.
Schau es dir noch mal an Karl Heinz. Hast du für die andere Sache auch 
eine Idee.

von kommentar (Gast)


Lesenswert?

Da ist doch was falsch, der Ausdruck ist immer FALSE bzgl. PC5, das 
(0<<PC5) == 0 ist.

Achim Seeger schrieb:
> if (PINC & (0<<PC5))

von Karl H. (kbuchegg)


Lesenswert?

Achim Seeger schrieb:
> Hallo
> Muss noch mal nachfragen. Habe das Prg so geändert


Du hast aber etwas ganz anderes programmiert, als das was ich dir da 
oben gezeigt habe. Die {}-Klammern sind da nicht zum Spaß vorhanden, 
sondern haben eine Bedeutung.

von Achim S. (achims)


Lesenswert?

Hallo Karl Heinz
habe die Klammern weggenommen. Geht immer noch nicht

while(1)
   {
  if (signal_wait1 == 0xFF)
  {
        signal_wait1 = 0;
  if(PINC&(0<<PC5))     // Abfrage PortC PC5 LED 5 Grün

    leds_set_status(1,5);  // schaltet LED 5 Grün auf ein
   else
    leds_set_status(0,5);  // schaltet LED 5 Grün auf aus
  }
    }
return 0;
}
PINC & .. ist die Abfrage des Ports C PC5 auf 0. Was habe ich wieder 
falsch gemacht?
achim

von Peter II (Gast)


Lesenswert?

schon mal übelegt was das eigentlich bedeutet:

(0<<PC5)

ist das gleiche wie

(0<<100)

oder noch kürzer

(0)

jetzt klar, das das keinen sinn macht?

von Achim S. (achims)


Lesenswert?

Hallo
in der Antwort von KH steht, "led ausgeschaltet". Diese LED 5 Grün liegt 
bei mir am PC5. Welche Möglichkeit zur abfrage des Ports habe ich sonst 
noch?
Es wird abgefragt ob der PC5 ausgeschaltet ist

if(PINC&(0<<PC5))      // Abfrage PortC PC5 LED 5 Grün

ist PC5 aus, wenn dann einschalten

leds_set_status(1,5);  // schaltet LED 5 Grün auf ein

sost einschalten

else
leds_set_status(0,5);  // schaltet LED 5 Grün auf aus
 sorry, unklar

von Peter II (Gast)


Lesenswert?

Achim Seeger schrieb:
> Welche Möglichkeit zur abfrage des Ports habe ich sonst
> noch?

> if(PINC&(0<<PC5))

eine & (und) bedingung mit 0 ist immer 0. So kann die bedingung nie wahr 
werden.

Überlegt doch mal wie man es abfragen würde?

Tip: normale auf "1" abfragen und das ergebnis negieren

von Achim S. (achims)


Lesenswert?

Hallo
habe es jetzt so gemacht:

while(1)
   {
  if (signal_wait1 == 0xFF)
  {
        signal_wait1 = 0;

  if(!PINC&(1<<PC5))     // Abfrage PortC PC5 LED 5 Grün

    leds_set_status(1,5);  // schaltet LED 5 Grün auf ein
   else
    leds_set_status(0,5);  // schaltet LED 5 Grün auf aus
        }
   }
return 0;
}
Die Abfrage ist jetzt auf 1 und wird negiert. Geht aber trotzdem nicht. 
Wie ist es mit den Klammern. In meinem C-Buch stehen für jede if und 
else abfrage ein paar Klammern {} drin. Wieso werden diese hierbei nicht 
gebraucht.

von Karl H. (kbuchegg)


Lesenswert?

Achim Seeger schrieb:
> Hallo
> in der Antwort von KH steht, "led ausgeschaltet".

Und womit? Mit Absicht.
Ich wollte nämlich wissen, wie gut du deine Basics gelernt hast.
Ehe man irgendetwas anderes macht, wie zb Timer, ist es unabdingbar, 
dass man die Grundlagen beherrscht. Diese Grundlagen sind:
* Wie setze ich einen Portpin auf 1?
* Wie setzt ich einen Portpin auf 0?
* Wie frage ich einen Portpin ab (sowohl auf 1 als auch auf 0)?


Bitmanipulation

von uff (Gast)


Lesenswert?

Was solln das sein?

>if(!PINC&(1<<PC5))

von Karl H. (kbuchegg)


Lesenswert?

Achim Seeger schrieb:

>   if(!PINC&(1<<PC5))     // Abfrage PortC PC5 LED 5 Grün

Operatoren Reihung!


Das hier wird als

   ( !PINC ) & ( 1 << PC5 )

gewertet. Das ist aber nicht das was du willst.
Du willst nicht, dass der Inhalt vom Pin Register logisch negiert wird 
und dann mit einem & ein Bit herausgeholt wird. Du willst
 * das Pin Register holen                         PINC
 * mit einem & und einer Maske ein                PINC & ( 1 << PC5 )
   Bit ausmaskieren
 * und dann das Ergebnis davon
   (welches nur noch von diesem Bit abhängt)
   logisch umdrehen                              !(PINC & ( 1 << PC5 ))


> Wie ist es mit den Klammern. In meinem C-Buch stehen für jede if und
> else abfrage ein paar Klammern {} drin. Wieso werden diese hierbei nicht
> gebraucht.

Weil dein Buch mies ist.
Das heißt, dein Buch ist nicht unbedingt mies. Grundsätzlich ist es 
guter Stil diese Klammern auch dann zu machen, wenn sie eigentlich nicht 
benötigt werden. Aber dein Buch sollte dir erklären, wie die Sache 
wirklich ist (wenn es sich dabei um ein C-Lehrbuch handelt, was du nicht 
ausdrücklich erwähnt hast)

Ausserdem war das nicht dein Problem.
Wenn du endlich mal deinen Code richtig einrücken würdest, würdest du 
erkennen, dass zwischen ....
1
    if( Bedingung_A )
2
    {
3
       mach_was;
4
    }
5
6
    if( Bedingung_B )
7
    {
8
      mach_was_anderes;
9
    }

... und ....
1
    if( Bedingung_A )
2
    {
3
      mach_was;
4
5
      if( Bedingung_B )
6
      {
7
        mach_was_anderes;
8
      }
9
    }
ein Unterschied besteht, der sich auch durch die Einrückung optisch 
zeigt. Im ersten Beispiel muss NUR Bedingung_B erfüllt sein, damit 
mach_was_anderes ausgeführt wird. Das muss auch im zweiten Beispiel so 
sein, aber zusätzlich muss im zweiten Beispiel auch noch Bedingung_A 
erfüllt sein, weil die Abfrage nach Bedingung_B  überhaupt nicht gemacht 
wird, wenn Bedingung_A schon nicht erfüllt ist. Das zweite if ist ins 
erste hineingeschachtelt! Die Einrückung zeigt das auch. Die { } 
klammern Code! Der Codeteil innerhalb dieser Klammern
1
   if( Bedingung_A )
2
   {
3
     ....
4
     ....
5
     ....
6
   }
wird nur dann, und zwar der komplette Codeteil, ausgeführt, wenn 
Bedinung_A zutrifft. Und wenn dieser abhängige Codeteil 25 
Bildschirmseiten lang ist, dann ist eben dieser 25-seitige Codeteil 
davon abhängig und wird nur dann ausgeführt, wenn Bedingung_A wahr ist. 
Und wenn da weitere if sich innerhalb dieses Blocks befinden, Schleifen, 
Funktionsaufrufe, Datenbankabfragen, weitere Blöcke, 
Feuerwerkszündungen, .... spielt alles keine Rolle. Der Block (so nennt 
man das, wenn mehrere Codezeilen mittels einer umschliessenden { } 
Klammerung zusammengebunden werden, wird nur dann ausgeführt, wenn 
Bedingung_A zutrifft. Ist Bedingung_A nicht zutreffend, wird der 
komplette Block überhaupt nicht in Angriff genommen sondern es wird zum 
else, wenn es eines gibt, gegangen und dort die Ausführung fortgesetzt. 
Gibt es kein else, dann geht die Codeausführung dann eben direkt nach 
dem if weiter.

Und spätestens jetzt sollte klar sein, dass es natürlich auch zwischen 
...
1
    if( Bedingung_A )
2
    {
3
      mach_was;
4
5
      if( Bedingung_B )
6
      {
7
        mach_was_anderes;
8
      }
9
      else
10
      {
11
        jag_den_Panzer_in_die_Luft;
12
      }
13
    }
... und ...
1
    if( Bedingung_A )
2
    {
3
      mach_was;
4
5
      if( Bedingung_B )
6
      {
7
        mach_was_anderes;
8
      }
9
    }
10
    else
11
    {
12
      jag_den_Panzer_in_die_Luft;
13
    }
... einen Unterschied gibt. Das eine mal gehört das else zur 
Bedingung_B, das andere mal zur Bedingung_A. Der Panzer wird also unter 
unterschiedlichen Voraussetzungen in die Luft gejagt.

Und weil das alles Unterschiede sind, die eine andere Programmlogik 
bewirken, ist es überaus wichtig, dass man schnell und eindeutig 
erkennen kann,
* wo ein Block anfängt
* wo ein Block aufhört
* und was sich alles innerhalb des Blocks befindet.
Und damit sind wir bei der Begründung, warum korrektes Code-Einrücken 
nicht eine Frage der Code-Schönheit sondern eine Frage der 
Fehlervermeidung ist. Wie du schon gesehen hast, gibt es 2 Arten von 
Fehlern. Die einen sind Syntaxfehler, grob gesagt, wenn du dich nicht an 
die Sprachregeln hältst. Dann klopft dir der Compiler auf die Finger. 
Die anderen Fehler sind aber unangenehmer. Das sind die logischen 
Fehler, wenn deine Programmlogik nicht stimmt. Da diese Logik aber 
einzig und alleine dein Bier ist, bist du dafür verantwortlich, alles zu 
tun, damit die Logik auch stimmt.
"Das U-Boot frühstückte durch den Bürosessel." ist ein völlig korrekter 
deutscher Satz, der allen Grammatikregeln genügt. Trotzdem ist er 
logisch gesehen unsinnig - unlogisch.

von Achim S. (achims)


Lesenswert?

Ich verwende das Buch "C von A bis Z" von Jürgen Wolf. Hoffe das es das 
richtige ist.
Noch was zu dem Artikel Bitmanipulatin. Habe den Artikel hier und vorher 
durchgearbeitet. Steht viel drin, so mit Verschiebung und so, aber was 
gerade such und brauche, Port Abfrage und setzen steht so nicht. In 
einem anderen Prg von mir, geht das wunderbar mit der Abfrage eines 
Einganges und weiteren Verarbeitung. Unterschied ist nur, das dort ein 
Taster dran hängt und eine vereinfachte Abfrage Taster ist. Ich kann 
auch mit den Port Befehlen Ausgänge setzen.
Muss halt weieter lesen. Werde erst das mal KH durcharbeiten.
Danke

von Achim S. (achims)


Lesenswert?

Hallo
nach eueren letzten Hilfen habe ich das Prg in Funktion bekommen. Werde 
weiterhin alles lesen was so da steht. Möchte es aber euch noch mal 
zeigen. Man kann es sehr gut nutzen z.B. um einen Timer zu testen oder 
für Einstellungen. Habe es auf 1Hz (2x0,5) gestellt im Timer.

while(1)      // Beginn Hauptschleife
  {
     if (signal_wait == 0xFF)  // Frage signal wait
  {
        signal_wait = 0;  // signal wait = 0
  if(!(PINC&(1<<PC5)))   // Abfrage PortC PC5 LED 5 Grün
  leds_set_status(1,5);  // schaltet LED 5 Grün auf ein

    else
  leds_set_status(0,5);  // schaltet LED 5 Grün auf aus
  }
  }
return 0;
}

Als Timer könnt ihr das obere Teil nehmen.

von Karl H. (kbuchegg)


Lesenswert?

Zeig mal alles. Da gibt es sicherlich noch einiges zu verbessern.

Der erste Punkt, den ich anmäkeln möchte
1
  if(!(PINC&(1<<PC5)))   // Abfrage PortC PC5 LED 5 Grün
2
  leds_set_status(1,5);  // schaltet LED 5 Grün auf ein

Bei beiden Dingen handelt es sich konzeptionell um die gleiche Sache: 
Den µC Pin an dem eine LED angeschlossen ist.
Das eine mal wird die Pin Abfrage direkt durch Zugriff auf das PINC 
Register gemacht, das andere mal wird eine Hilfsfunktion benutzt, so 
dass nicht mehr ersichtlich ist, welcher Pin da eigentlich manipuliert 
wird.
Nicht besonders schön, zumal es zur Verwirrung beiträgt. Wenn man einen 
Mechanismus benutzt (entweder direkte PIN/PORT Zugriffe oder 
Hilfsfunktionen), dann sollte man das dann auch konsequent durchziehen.

von Falk B. (falk)


Lesenswert?

@  Achim Seeger (achims)

>Noch was zu dem Artikel Bitmanipulatin. Habe den Artikel hier und vorher
>durchgearbeitet.

Aber nicht verstanden. -> Noch einmal.

> Steht viel drin, so mit Verschiebung und so, aber was
>gerade such und brauche, Port Abfrage und setzen steht so nicht.

Jaja, die gebratenen Tauben fliegen nicht in den Mund. Sowas auch. Und 
mit logischem Denken ist das auch so eine Sache . . .
Von Grundlagen der C-Programmierung mal ganz zu schweigen. Ja, die 
mussten wir uns alle erarbeiten.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Eing.C3.A4nge_.28Wie_kommen_Signale_in_den_.C2.B5C.29

von Achim S. (achims)


Angehängte Dateien:

Lesenswert?

Hallo KH
stelle dir das Prg rein. Denke bitte daran, es ist eigentlich für einen 
Nibo geschrieben, arbeitet mit dem 128 bei 16 Mhz. Falls es 
Verbesserungen gibt, sehe ich keinen Grund etwas nicht zu ändern. Es 
kann allerdings sein, das das Einrücken jetzt nicht so aussieht wie im 
ori.
Bleibt aber noch mein zweites Problem. Der Timer und das Prg ohne delay. 
Werde anschliessend dort weiter machen. Es lässt sich auch auf anderen 
Plattformen einiges damit machen. Besonders die Kürze der Anweisungen.
Werde bestimmt damit noch mal zu dir kommen.

Hallo Falk, danke für deinen Himweis. Werde es annehmen und es noch 
ausführlicher machen. Leider ist der Stoff teoretisch sehr trocken. 
Bevorzuge daher die Version mit Prg und Irrtum. Nach dem Motto, eine LED 
sagt mehr als tausend Worte.

Falls das Prg nicht richtig kommt, bringe ich es nochmal.
achim

von Falk B. (falk)


Lesenswert?

@  Achim Seeger (achims)

>ausführlicher machen. Leider ist der Stoff teoretisch sehr trocken.

jain.

>Bevorzuge daher die Version mit Prg und Irrtum.

Das ist nicht sehr clever.

"Der Mensch hat dreierlei Wege, klug zu Handeln;

erstens durch Nachdenken, das ist das Edelste,
zweitens durch Nachahmen, das ist das Leichteste,
und drittens durch Erfahrung, das ist das Bitterste.

Konfuzius

chinesischer Philosoph und Staatsmann (551 v. Chr. - 479 v. Chr.)"

>Falls das Prg nicht richtig kommt, bringe ich es nochmal.

Dein Formatierung ist schlecht. Nutze nur echte Leerzeichen, keine 
Tabulatoren. Schau es dir selber in der Codeansicht an.

MfG
Falk

von Achim S. (achims)


Lesenswert?

Hallo Falk
habe mit die Codeansicht angesehen. Es ist das erste mal das ich hier 
einen Code veröffentliche. Daher habe ich diese Erfahrungen noch nicht 
sammeln können. Ich arbeite aber dran.
Ich kenne diese Aussage von Konfuzius. Leider gibt es eine Frage dazu, 
die bis heute nicht beantwortet ist. Möchte auf keinen Fall etwas daran 
zweifeln. Doch woher weiss er es? Hat er auch die selben Erfahrungen 
gemacht wie andere oder ist er durch einfaches(?) Nachdenken zu dieser 
Aussage gekommen. Mein Weg liegt irgendwo dazwischen. Ich denke über ein 
Problem nach. Schaue wie es andere machen und sammle die Erfahrungen die 
ich zum Nachdenken über ein Problem zur Lösung brauche. Es ist nicht 
eleganteste, nicht der schnellste, nicht der leichteste, auch nicht der 
bitterste Weg zur Erkenntnis, es ist aber ein Weg zur Lösung.
achim

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.