Forum: Mikrocontroller und Digitale Elektronik Timer mit 1 ms und ISR ?


von Achim S. (achims)


Lesenswert?

Hallo Gemeinde
möchte an einem AT 1284p / 16 M einen Timer0 (8 bit) mit 1 ms 
programmieren
Komme aber nicht ganz klar. Habe den folgenden Code dazu:
1
TCCR0A = (1<<WGM01);    // CTC Modus
2
TCCR0B |= (1<<CS01)|(1<<CS00);  // Prescaler 64
3
OCR0A = 249;
4
TIMSK0 |= (1<<OCIE0A);

Nach dem Datenblatt müsste das 1 ms ergeben.

Problem ist aber die ISR:
1
ISR (TIMER0_COMPB_vect)
2
{
3
  if(wait<=9)
4
  {
5
    wait++;
6
  }
7
  else
8
  {
9
    wait=0;
10
    wait10=0xff;
11
  }
12
}

In einem Stück Code möchte ich _delay_ms(1) durch den Timer ersetzen. 
Der Timer soll genau so 1 ms warten (ohne delay)

Irgendwie habe ich ein Brett vor dem Kopf.
achim

von Bitflüsterer (Gast)


Lesenswert?

Schön. Was aber ist nun genau Deine Frage?

von San L. (zwillingsfreunde)


Lesenswert?

Bitflüsterer schrieb:
> Schön. Was aber ist nun genau Deine Frage?

Vermutlich, wie er den Timer zu einem bestimmten Zeitpunkt anwerfen 
kann. Er will ja wohl kaum alle ms wieder einen Programmunterbruch, 
sondern vermutlich nur an einer Stelle.

von Achim S. (achims)


Lesenswert?

Frage genauer:
- Ist der Timer 1 ms?
- Wie muss die ISR aussehen um 1 ms verzögerung zu bekommen?
- Wie kann ich das statt delay 1 ms nehmen?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Achim Seeger schrieb:
>
1
> ISR (TIMER0_COMPB_vect)
2
> {
3
>   if(wait<=9)
4
>   {
5
>     wait++;
6
>   }
7
>   else
8
>   {
9
>     wait=0;
10
>     wait10=0xff;
11
>   }
12
> }
13
>

Wird die Variable wait lediglich innerhalb der ISR benötigt? Wenn ja, 
dann definiere sie innerhalb der ISR (und nicht global) mit:

   static uint8_t wait;

und nicht außerhalb.

Wenn nein, definiere sie global mit

   volatile uint8_t wait;

Oder wenn nur innerhalb einer C-Datei benötigt:

   static volatile uint8_t wait;

Dasselbe gilt für wait10.

von Achim S. (achims)


Lesenswert?

sorry, übersehen.
- möchte permanent einen unterbruch von jeweils 1 ms.
Soll in einer Blinkschleife verwendet werden. Diese hat 2 x 500 ms mit 
delay, also 500 x 1 ms an und 500 x 1 ms aus

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Achim Seeger schrieb:
> Soll in einer Blinkschleife verwendet werden. Diese hat 2 x 500 ms mit
> delay, also 500 x 1 ms an und 500 x 1 ms aus

Dann schreib den An- und Aus-Befehl noch mit in die ISR. Ob Du gerade 
an- oder ausschalten musst, kannst Du mittels flag, welches Du toggelst, 
testen.

Oder Du togglest direkt den Port-Pin. Das wäre das sparsamste Vorgehen.

von Delay (Gast)


Lesenswert?

Warum willst du delayms ersetzen?
Wenn es daruf hinaus läuft, dass du an einer Stelle im Programm so lange 
wartest, bis ein Timer-Interrupt eine Variable gesetzt hat, kannst du 
auch genausogut delayms weiterbenutzen.
Wenn du mehrere Dinge parallel (ereignisgesteuert) abarbeiten willst, 
sind schon größere Änderungen am Programmablauf nötig als nur delayms 
durch etwas selbstgebautes zu ersetzten.

von San L. (zwillingsfreunde)


Lesenswert?

Delay schrieb:
> Wenn du mehrere Dinge parallel (ereignisgesteuert) abarbeiten willst,
> sind schon größere Änderungen am Programmablauf nötig als nur delayms
> durch etwas selbstgebautes zu ersetzten.

Naja... Mit einem Timer wäre es immerhin schon mal möglich das Blinken 
Parallel zum Rest laufen zu lassen. Pin Toggle in die ISR und das 
wars... sehe da nicht, was für andere Änderungen noch nötig wären in 
diesem Fall.

Kommen da andere Interrupts usw hinzu, dann stimme ich dir zu. Dann 
wirds irgendwann etwas komplizierter.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

So ähnlich könnte das aussehen:

ISR (TIMER0_COMPB_vect)
{
    static uint16_t cnt;

    cnt++;

    if (cnt == 500)
    {
         cnt = 0;
         PORTX ^= (1<<PINXY);
    }
}

Wenn der TO es schafft, dass die ISR nur alle 2ms aufgerufen wird, 
könnte er auch bis 250 zählen und cnt käme mit einem uint8_t aus.

von Achim S. (achims)


Lesenswert?

Hallo Frank
das Problem ist es etwas grösser und länger. Versuche es mal zu erklären
Im grund sieht es so aus

Timer
ISR

int main
.....

while

Unterprogramm 1
Unterprogramm 1
...
Unterprogramm 5
delay 1ms

Jedes Unterprogramm verwendet kein delay und keiner Verzögerung. Dadurch 
wird die gesamtlaufzeit des Programmes nur durch die 1 ms bestimmt. Die 
1 ms muss aber relativ konstant sein, da in den Unterprogrammen Zähler 
sind, die bei jedem Durchlauf um eins erhöht werden. Bei der LED 500 x 
1ms, dann LED an, nochmal 500 x 1 ms dann LED aus.
Brauche also einen Timer mit 1 ms. Die ISR dazu muss mein Programm bei 
jedem Durchlauf 1 ms stoppen.
Kommt alles aus dem Bereich Multitasking
achim

von Delay (Gast)


Lesenswert?

Okay, die letzten Antworten hatte ich vor dem Absenden nicht gesehen.
Wenn ein Ausgang alle 500ms getogglet werden soll, ist es natürlich 
sinnvoll, einen ms-Counter zu bauen, der bei jedem Durchlaf der 
main-Schleife geprüft wird (und bei jedem Aufruf der Timer-ISR erhöht 
wird mit Überlauf bei 1000).

Je nachdem, was der Timer sonst noch so steuern soll, kann es natürlich 
auch sinvoll sein (oder gerade nicht) den Ausgang direkt in der 
Timer-ISR zu togglen.

von Achim S. (achims)


Lesenswert?

Es geht eigentlich nicht darum eine LED unabhängig blinken zu lassen, 
sondern 5 Stück und dazu noch 3 Taster abzufragen und dazu noch 4 
Bodensensoren und die Tasterabfrage nach Peter und Karl Heinz.
Nur eine Timer mit fester zeit. alles andere wird da von abgeleitet.
Das wichtigste daran sind die Unterprogramme. Es darf keinerlei 
Verzögerung eintreten.
Habe das alles auf einem AT 128 zu laufen. Leider mit anderen Libs und 
einem anderen Timer. Möchte es jetz einfach auf dem 1284p anpassen.

von Falk B. (falk)


Lesenswert?

@ Achim Seeger (achims)

>Brauche also einen Timer mit 1 ms.

Wo liegt das Problem? Stell ihn richtig ein und los!

> Die ISR dazu muss mein Programm bei
>jedem Durchlauf 1 ms stoppen.

Nö, dein Programm, genauer die FUNKTIONEN, müssen darauf passen 
reagieren, dass sie im 1ms Raster aufgerufen werden! Siehe 
Statemachine.

>Kommt alles aus dem Bereich Multitasking

Mensch Meier, und warum nimmst du nicht einfach das gottverdammte 
Beispiel? Hast du das Thema nicht schon vor vielen Monaten bearbeitet? 
Mir scheint, dein Langzeit- und Lerngedächtnis ist nicht das Beste.

http://www.mikrocontroller.net/articles/Multitasking#Ein_einfaches_Beispiel_f.C3.BCr_den_AVR

von Falk B. (falk)


Lesenswert?

@ Achim Seeger (achims)

>Es geht eigentlich nicht darum eine LED unabhängig blinken zu lassen,
>sondern 5 Stück und dazu noch 3 Taster abzufragen und dazu noch 4
>Bodensensoren und die Tasterabfrage nach Peter und Karl Heinz.

Einfachster Krümelkram.

>Nur eine Timer mit fester zeit. alles andere wird da von abgeleitet.

Richtig!

>Das wichtigste daran sind die Unterprogramme. Es darf keinerlei
>Verzögerung eintreten.

Genau!

>Habe das alles auf einem AT 128 zu laufen. Leider mit anderen Libs und
>einem anderen Timer. Möchte es jetz einfach auf dem 1284p anpassen.

Muss ich das verstehen? Wo ist denn da das Problem?

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Siehe Anhang.

von Holger L. (max5v)


Lesenswert?

Erstmal sollte die ISR geändert werden, eingestellt ist OCRA, die ISR 
bezieht sich allerdings auf OCRB.

ISR (TIMER0_COMPB_vect)

von Achim S. (achims)


Lesenswert?

Hallo Falk
stimmt genau
Habe es schon vor einiger Zeit gemacht. Damals war ich so blöd, die 
Pause richtig kompliziert zu machen. Habe neulich was kurzes gesehen, 
weiss leider nicht mehr wo.
Genau, zur Statemaschine will ich kommen, aber nicht sofort. Da muss ich 
erst noch einiges lernen.
Hatte es damals für den nib.. programmiert. Leider verwendet der 
Hersteller viel eigene Sachen. Da Nib.. nur noch als Ausstellungsstück 
dient, mache ich einiges neu.
Hast du schon mal versucht I2C Bus und Multitasking zu kreuzen?
Wenn der Timer so stimmt, eine kurzes Stück Code zur Verzögerung.
Habe die Datenblätter vom 128 und 1284 gelesen. Sind doch ein paar 
Unterschiede drin

von Bitflüsterer (Gast)


Lesenswert?

Solche Problembeschreibungen solltest Du wirklich von Anfang an posten. 
Man weiss sonst einfach nicht, worum es geht.

1. Du hast also innerhalb einer while-Schleife mehrere Unterprogramme.
2. Die while-Schleife soll alle 1ms einmal durchlaufen werden.
2.a. Dazu gehört die Bedingung, dass die Laufzeit aller Unterprogramme 
zusammen weniger als 1ms beträgt (mit ein wenig Reserve). Ist das 
gegeben?
3.  Zusätzlich soll eine LED alle 500ms getoggelt werden.

Das wäre jetzt mal so ein Ansatz, den ich mir von Dir gewünscht hätte. 
Darauf kann man Fragen beziehen.

Du solltest Dir angewöhnen Dir mal so ein grundsätzliche 
Ablaufbeschreibung zu entwerfen. Und wenn sie noch so falsch ist.
Wenn Du immer nur irgendwelche Schnippsel hinlegst und darauf starrst 
und das als Ausgangspunkt einer Frage nimmst, dann müssen wir immer die 
Entwürfe für Dich machen. Davon lernst Du nichts und wirst immer von uns 
abhängig sein.

- Init

1. Timer initialisieren
2. Flag initialisieren


- main
1. Timer starten
2. while(1)
3.   up1();
4.   up2();
5.   Warten bis Zähler 1ms abgelaufen - Flag variable zurücksetzen
6.   500ms Zähler inkrementieren
7.   500ms Zähler abgelaufen?
8.     Wenn ja, LED toggeln - Zähler zurücksetzen
9. } /* while */


- Timer-Int

1. Flag setzen

von Achim S. (achims)


Lesenswert?

Hallo Falk
habe dein Stück gleich gezogen.
Vieles ist aus der anderen Version.
War der Timer schon immer dadrin? Wenn ja, habe ich noch was anderes, 
oder total verschlafen.
Danke dir
achim

P.S.
Paket ist angekommen. Noch mal meine Dummheit gesucht. Sorry hatte es 
ganz vergessen

von Achim S. (achims)


Lesenswert?

Hallo Gast
du hast vollkommen Recht. Deine Beschreibung stimmt genau.
Leider ist maches schwer auszudrücken. Wollte es eigentlich nicht zu 
kompliziert machen. Im Netz steht von Falk und anderen ein extra Artikel 
drin, der alles beschreibt, Multitasking. Ist ein sehr guter Artikel der 
alles sehr einfach beschreibt. Ansonsten stimmt dein Ansatz genau.
achim

von Achim S. (achims)


Lesenswert?

Sorry, habe es erst jetzt gesehen. Innerhalb der Unterprogramme laufen 
die Zähler. Können durchaus 5 bis 10 Stück sein. 6, 7, 8 nicht in der 
while Schleife

von Falk B. (falk)


Lesenswert?

@ Achim Seeger (achims)

>War der Timer schon immer dadrin?

Nein, der kam etwas später rein.

Ist am 11. NOvember 2012 reingekommen (doch schon ne Weile her)

>Sorry, habe es erst jetzt gesehen. Innerhalb der Unterprogramme laufen
>die Zähler. Können durchaus 5 bis 10 Stück sein.

10 kleine Unterprogramme und darin jeweils ein Zähler oder gar eine 
Statemachine bringen den AVR noch nicht ins Schwitzen]].

von Falk B. (falk)


Lesenswert?

@ Achim Seeger (achims)

>Hast du schon mal versucht I2C Bus und Multitasking zu kreuzen?

Jain, ich hab mal vor langer Zeit einen kleinen Zähler mit I2C gemacht. 
Wenn gleich sich dort das Multitasking in Grenzen hielt.

>Habe die Datenblätter vom 128 und 1284 gelesen. Sind doch ein paar
>Unterschiede drin

Ja, aber die sind eher klein. So ein Timer hat beim AVR bestenfalls drei 
Register, das sollte schon drin sein, die richtig einzustellen.

von Achim S. (achims)


Lesenswert?

Im Grunde wollen wir das gleiche. Habe jetzt so ziemlich alles 
exportiert auf das neue system. Hattest ja mitbekommen, das ich viel mit 
dem Bus mache. Dazu jetzt noch Multitasking und später Statemaschine. 
Das kann ganz neue Sachen bringen.
Du hast auch eine Sicherheitskontrolle drin. War mir ganz neu. Da habe 
ich doch wieder was zu lesen und kann getrost auf das blöde Fernsehen 
verzichten. Informiere dich über die Ergebnisse.
achim

von Achim S. (achims)


Lesenswert?

Muss noch nachfragen.
Habe ein Problem den AT1284p / 16MHz der Timer 0 in Betrieb zu nehmen. 
Habe nach Datenblatt die folgenden Einstellungen gemacht. Es soll 1 ms 
kommen
Es geht aber nicht. Was mach ich falsch?

// Timer 0 konfigurieren
TCCR0A = (1<<WGM01);        // CTC Modus
TCCR0B |= (1<<CS01)|(1<<CS00);    // Prescaler 64
OCR0A=249;

// Compare Interrupt erlauben
TIMSK0|= (1<<OCIE0A);

// Global Interrupts aktivieren

sei();

von Falk B. (falk)


Lesenswert?

@ Achim Seeger (achims)

>Habe ein Problem den AT1284p / 16MHz der Timer 0 in Betrieb zu nehmen.
>Habe nach Datenblatt die folgenden Einstellungen gemacht. Es soll 1 ms
>kommen
>Es geht aber nicht. Was mach ich falsch?

Dass du konsequent nur sinnlose Quelltextfragmente postest!
Was soll das? Poste VOLLSTÄNDIGE Quelltexte als Anhang!

Es fehlt MINDESTENS die ISR!

>// Timer 0 konfigurieren
>TCCR0A = (1<<WGM01);        // CTC Modus
>TCCR0B |= (1<<CS01)|(1<<CS00);    // Prescaler 64
>OCR0A=249;

>// Compare Interrupt erlauben
>TIMSK0|= (1<<OCIE0A);

Die Registereinstellungen sehen OK aus.

von Achim S. (achims)


Lesenswert?

Da sind sie. Kennst du aber

ISR (TIMER0_COMPB_vect)
  {
    flag_1ms=1;
  }


Im Programmm steht das noch:

volatile uint8_t flag_1ms;

...
if(flag_1ms)
  {
    flag_1ms=0;
    Unter 1..
    Unter 2 ..
    Unter 3 ...
  }

Der ganze Code besteht im Moment nur aus diesen paar Zeilen. Die 
Unterprg habe ich vollständig rausgelassen.

von Stefan E. (sternst)


Lesenswert?

1
TIMSK0|= (1<<OCIE0A);
2
                  ^
3
ISR (TIMER0_COMPB_vect)
4
                ^

von Achim S. (achims)


Lesenswert?

Danke dir Steffan. Das war es. Keine Ahnung warum ich das nicht gesehen 
habe.
Da muss wohl doch eine Brille her.
Danke

von Falk B. (falk)


Lesenswert?

@ Achim Seeger (achims)

>Danke dir Steffan. Das war es. Keine Ahnung warum ich das nicht gesehen
>habe.
>Da muss wohl doch eine Brille her.

Erkennst du JETZT, warum man VOLLSTÄNDIGEN Quelltext posten MUSS?!

von Achim S. (achims)


Lesenswert?

Ja das erkenne ich. Stelle aber auch fest, das ich noch viel lernen 
muss. Aus Fehlern lernt man.
Egal, danke für deine Hilfe.
Dein Programm läuft sofort richtig.
Der Sinn deiner überwachung ist mir nicht ganz klar.
Wenn flag noch 1 ist > Anzeige - ok
und das andere??

von Falk B. (falk)


Lesenswert?

@Achim Seeger (achims)

>Der Sinn deiner überwachung ist mir nicht ganz klar.

Steht das nicht sonnenklar im Text? Damit kann man live im Programm 
prüfen, ob deine Tasks schnell genug abgearbeitet werden können oder 
nicht. Also eine Echtzeitfehlerüberwachung.

von Achim S. (achims)


Lesenswert?

Du fragst hier ab, ob flag_1ms auf 0 gesetzt ist, wenn nicht Anzeige mit 
LED
1
if (flag_1ms)   // ist flag_1ms auf 1 dann ...
2
  {
3
    flag_1ms=0;   // setze flag_1ms aif 0
4
    taste = taste_lesen();
5
    led_blinken(taste);
6
    uart_lesen();
7
    if (flag_1ms) // Ist doch nur Zustand flag_1ms 1 oder 0 ????? 
8
      {          // Laufzeit der Tasks >1ms, Fehlersignalisierung ???
9
        PORTB |= (1<<PB1); // PB1 (LED) auf HIGH, Programm stoppen
10
        while(1);
11
      }
12
  }

Beim Timer machst du es doch noch mal:
1
if (flag_1ms) 
2
  {  // Laufzeit der Tasks >2ms, Fehlersignalisierung
3
     PORTB |= (1<<PB1);   // PB1 (LED) auf HIGH, Programm stoppen
4
     while(1);
5
   }
6
 flag_1ms = 1;

Ist doch auch nur eine Abfrage nach 0 oder 1.
Sehe ich was falsch?
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.