Forum: Mikrocontroller und Digitale Elektronik Interupt Routine leicht gemacht?


von Ganui K. (Firma: BOSCH) (zmx2000)


Lesenswert?

Hallo

ich benutze zurzeit zwei Timer Interrupts (beim atmega8). leider 
verstehe ich nicht 100% die funktion von Interrupts. Wenn ich zum 
beispiel zwei timer laufen lasse und einer liest den adc wert aus und 
der andere führt einen bestimmte logik aus, wie sieht es mit dem timing 
aus? kann es sein, dass Werte verloren gehen? siehe erstmal programm 
(ohne jetzt auf die syntax zu achten):

isr( timer0_Overflow)
{

// ADC Wert wird z.B. alle 10 ms eingelesen //

}

isr( timer1_Overflow)
{

// LED toggeln lassen //

// ADC Werte auf 0 bis 255 begrenzen, wegen Timer //

//   TCNT1 = ADC_WERT //

}


Meine Frage ist nun, werden alle eingelesenen ADC Werte im Timer1 
verwendet oder kann es sein, dass bei erhöhung der ADC Werte die zeit zu 
lange dauert (Toggeln) dass der timer1 noch rechtzeitig auf ein neues 
ereignis des timer0 reagiert? oder hab ich bzgl. Interrupt ein 
denkfehler?

ich möchte gern impulse mit variabler frequenz aber gleichbleibendem 
duty cycle erzeugen, mein wunsch wäre bei einem wert von 0 = 10 ms und 
bei einem ADC wert von 255 = 500 us Impulse erzeugen. Ich benutze 
zurzeit einen internen RC mit 1 MHz. Muss cih vlt. einen höhren externen 
Oscillator nehmen, z.B.  4 MHz um diese Zeiten zu schaffen?

Zurzeit schaffe ich es zwar diese impulse mit den interrupts zu erzeugen 
aber leider nicht mit diesen zeiten und zudem schwanken die impulse bei 
höheren werten wie z.B. 255.

P.S. der prescaler sind bei beiden timern gleich --> auf 64 eingestellt

von oha (Gast)


Lesenswert?

Das macht man anders. Man laesst einen Timer laufen und wenn der kommt 
setzt man einen Boolean. Im Main startet man den ADC wenn der Timer 
gekommen ist, indem dort der Timer boolean abgefragt wird. Das Lesen des 
ADC macht man im ADC interrupt.

von janjan (Gast)


Lesenswert?

Aus dem bisschen Pseudocode wird noch nicht viel klar. Häng doch mal den 
echten Code als Attachment an. Die restliche Fragestellung ist auch 
nicht sonderlich verständlich.

Nur mal zur Klarstellung: Ein ADC Wert von 0 soll einer Impulslänge von 
10ms (milli) entsprechen, und ein Wert von 255 soll 500us (mikro) 
entsprechen?
Sind das die richtigen Größenordnungen?

Timer1 ist ein 16bit Timer, kann also bis 65535 zählen, nutze das doch 
aus. Eventuell kannst du dadurch den Prescaler weglassen, oder auf 8 
verringern, momentan ist deine Auflösung ja auf 64us begrenzt.

ADC Messungen brauchen Zeit. Das Datenblatt empfiehlt eine ADC clock 
zwischen  50 und 200kHz, das heisst der ADC braucht einen Prescaler von 
8 bei 1 MHz um 125kHz zu erreichen. Eine (Einzel-)Messung dauert dann 
200us. Da bringt auch ein höherer Takt nichts. Im Regelfall lässt man 
die Interrupts aus, während einer Interrupt-routine, das hieße, während 
der ADC messung kann der Timer1 interrupt nicht aktiv werden.

Wenn die Timer1 routine nichts anderes macht, als einen Pin zu toggeln, 
kannst du das ganz ohne Interrupt routine machen, und zwar an Pins OC1A, 
bzw. OC1B. Die Funktionalität kannst du in TCCR1A einstellen.
Das funktioniert aber auch nur, während die Interrupts aktiv sind. Daher 
den Rat von oha befolgen. Wenn du sonst keine weiteren Interrupts 
verwendest, kannst du evtl. auch die die Interrupts in der Timer0 
routine wieder aktivieren, aber damit kenne ich mich nicht aus.

von Ganui K. (Firma: BOSCH) (zmx2000)


Angehängte Dateien:

Lesenswert?

Hallo

danke für die hinweise, aber es geht nicht wirklich nur ums toggeln. 
dies diente nur zu testzwecken...

es geht darum Hall Impulse NACHZUSIMULIEREN, indem abhängig vom ADC die 
Impulsbreite immer kürzer wird (Motorgeschwindigkeit steigt) oder immer 
breiter, wodurch simuliert wird, dass der Motor immer langsamer wird. 
Dabei möchte ich Impulse in der Grössenordnung zwischen 500 us und 10 ms 
erreichen. Geplant waren bisher dass alle 1 ms ein ADC Wert eingeselen 
wird. Können auch 2 ms oder etwas mehr sein...die auflösung ist nicht 
problematisch.

im grunde ganz einfach, wenn man sich mit Timern und Interrupts speziell 
Timing auskennt. Leider hab ich noch nie damit gearbeitet und es trten 
halt die oben aufgelisteten Probleme auf: Schwanken im obenren Bereich, 
nicht erreichen von diesen gewünschten Zeiten (500 us und 10 ms)...

Anbei der Code:

Hoffe ihr habt eine idee warum das nicht so optimal klappt. Bislang 
schaffe ich es, dass die Impulse ihre Frequenz durch änderng der ADC 
Were ereichen, nur nicht wie gewünscht, aus welchen gründen auch immer?

Würde es denn mit einem Timer1 besser klappen? Oder besser einen 
externen Quarz, der diese Zeiten problemlos schafft?

Gruss und danke im voraus.

von Analog (Gast)


Lesenswert?

interrupt (englisch) = unterbrechen.

Ein Interrupt unterbricht das laufende (Haupt-)Programm bei eintreffen 
einer bestimmten Bedingung. Nach der Abarbeitung des Interrupts fährt 
das (Haupt-)Programm genau an der Stelle fort, wo es zuvor unterbrochen 
worden ist.

von Ganui K. (Firma: BOSCH) (zmx2000)


Lesenswert?

Wäre super, wenn du auch für meine anderen Fragen eine Antwort hättest 
;)

von ... (Gast)


Lesenswert?

Sollte pulselength nicht volatile sein ?
1
#include <util/delay.h>
2
#include <avr/interrupt.h>
3
#include <avr/io.h>
4
5
volatile char pulselength; // somit wird die Variable vor jeder Benutztung neu geladen, sonnst könnte die Änderung durch die ISR "verloren" gehen.
6
char S1 = 0;
7
char S2 = 0;
8
char Direction = 1;
9
10
volatile uint16_t AdcValue = 0; // hier auch ein Volatile ?

von Thomas W. (wagneth)


Lesenswert?

Es gibt eine extra ISR um den ADC auszulesen...

Vielleicht interessiert Dich auch der FreeRunningMode des AVR ?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ganui Kliuz wrote:

> ich benutze zurzeit zwei Timer Interrupts (beim atmega8). leider
> verstehe ich nicht 100% die funktion von Interrupts. Wenn ich zum
> beispiel zwei timer laufen lasse und einer liest den adc wert aus und
> der andere führt einen bestimmte logik aus, wie sieht es mit dem timing
> aus? kann es sein, dass Werte verloren gehen?

Ja, kann sein. Es kommt auf die µC Architektur an und auf den konkreten 
Fall.

Bei AVRs wird pro Interruptquelle ein weiterer Interrupt in der 
Warteschlange gehalten. Ist die ISR von Timer0 aktiv, müssen andere 
Irterrupts in der Warteschlange warten. Kommt zu einem wartenden 
Interrupt von Timer1 ein zweiter, geht einer verloren.

Ob in deinem Fall mehrere Interrupts von Timer1 in der ISR von Timer0 
kommen, bzw. auch umgekehrt, hängt von der Frequenz von Timer0 und 
Timer1 ab und wie lange die ISRs dauern. Daher das Ziel die ISRs zu kurz 
wie möglich zu halten. Eine ADC Messung ist da vergleichsweise eher 
"lang".

> ich möchte gern impulse mit variabler frequenz aber gleichbleibendem
> duty cycle erzeugen, mein wunsch wäre bei einem wert von 0 = 10 ms und
> bei einem ADC wert von 255 = 500 us Impulse erzeugen. Ich benutze
> zurzeit einen internen RC mit 1 MHz. Muss cih vlt. einen höhren externen
> Oscillator nehmen, z.B.  4 MHz um diese Zeiten zu schaffen?

Du kannst einen 10ms Timer laufen lassen und wie von oha vorgeschlagen 
ein volatile Flag in der ISR setzen, dass 10ms vergangen sind. In dem 
Hauptprogramm prüfst du dieses Flag, setzt das Flag zurück und machst 
eine ADC Messung. Den Messwert kannst du dann benutzen, um einen zweiten 
Timer zu steuern z.B. um dessen Startwert im CTC Modus zu verändern 
(hochsetzen => höhere Frequenz, runtersetzen => niedrigere Frequenz).

1 MHz sollte ausreichen, um einen 10ms Timer laufen zu lassen. Eine 
Möglichkeit bei AVRs wäre der 8-Bit Timer0 mit Prescaler von 8 und einen 
Startwert des Timerzählers von 131 (=256-125) und alle 10 Overflows das 
Flag setzen. Der Startwert wird in der ISR von Hand nachgeladen oder 
automatisch nachgeladen (CTC Modus).

Bei dem 1 MHz internen RC-Oszillator bei den AVRs muss man beachten, 
dass der ggf. kalibriert werden muss, um genau zu laufen und dass eine 
rel. starke Abhängigkeit der Taktrate von der Umgebungstemperatur 
vorhanden ist. Wenn es genau sein soll, also eher auf externe Taktquelle 
wie Quarz oder Quarzoszillator gehen.

500µs Dauer für die Halbperiode... Bei einem 16-Bit Timer und Prescaler 
1 sollten die Overflows alle 500 Takte kommen. Das ist wie oben machbar. 
Schön ist daran, dass die Dauer in µs direkt der Zahl der Takte zwischen 
den Overflows entspricht. Unschön ist die niedrige Zahl der Takte 
zwischen den Overflows. Das Hauptprogramm und die ISR Timer0 haben ja 
nicht viele Takte (500 - Zahl der Takte in der Timer1 ISR) zum arbeiten 
und das wird schlimmer, wenn die Dauer verkürzt werden soll. Da wären 
mehr MHz eindeutig geschickter.

von Tester (Gast)


Angehängte Dateien:

Lesenswert?

Hallo

ich hab es jetzt doch mit dem ADC Interrupt gemacht und es funktioniert 
soweit ganz gut. Ich kann die variablen Impulse erzeugen. Allerdings 
möchte ich gerne bei einem ADC Wert von 0, dass keine Impulse (also 
S1=S2=0..siehe anhang code)) erzeugt werden, wodurch der stillstand 
simuliert wird. zurzeit werden auch bei einem wert von 0 Impulse erzeugt 
und das soll ja nicht sein . Wie kann man die Logik erweitern, dass eben 
bei einem wert von NULL die Impulse ebenso NULL sind? Hab es mit der if 
(AdcValue <=1 && Direction) versucht, aber irgendwie kommen noch ganz 
kurze unregelmässige Impulse?...

danke im vorraus und für die zahlreichen tipps

von Karl H. (kbuchegg)


Lesenswert?

Ich würds so machen, dass bei einer pulslength von 0
der 2.te Timer ganz einfach über seinen Vorteiler abgeschaltet wird.
Wird pulslength dann wieder ungleich 0, wird wieder ein Vorteiler 
gesetzt und der Timer tickt wieder.

Edit:
Ah, du erzeugst ja den Puls sowieso im Overflow Interrupt vom Timer 2. 
Also dort ganz einfach eine Abfrage rein, dass das Signal nur dann 
ausgegeben wird, wenn pulslength ungleich 0

von Google Master (Gast)


Lesenswert?

Hallo

das hab ich gerade versucht:

if ( (Direction) && (pulselegth != 0) )...

aber es tauchen immernoch irgendwelche kurzen impulse auf einem port 
pin..

liegt es am Timer2?

von Karl H. (kbuchegg)


Lesenswert?

Google Master wrote:
> Hallo
>
> das hab ich gerade versucht:
>
> if ( (Direction) && (pulselegth != 0) )...
>

dort wird aber der Puls am Pin nicht erzeugt :-)


Aber warum so kompliziert? Warum nicht einfach
1
ISR(TIMER2_OVF_vect ) 
2
{
3
  if( pulslength != 0 )
4
  {
5
    //Vorwärtsbetrieb
6
    if (Direction)       
7
    {
8
      if ((S1==1) && (S2==1)) { S1 = 0; S2 = 1; }  else 
9
      if ((S1==1) && (S2==0)) { S1 = 1; S2 = 1; }  else 
10
      if ((S1==0) && (S2==0)) { S1 = 1; S2 = 0; }  else 
11
      if ((S1==0) && (S2==1)) { S1 = 0; S2 = 0; } 
12
    }
13
14
    // Rückwärtsbetrieb    
15
    else if (!Direction)
16
    {
17
      if ((S2==1) && (S1==1)) { S2 = 0; S1 = 1; }  else 
18
      if ((S2==1) && (S1==0)) { S2 = 1; S1 = 1; }  else 
19
      if ((S2==0) && (S1==0)) { S2 = 1; S1 = 0; }  else 
20
      if ((S2==0) && (S1==1)) { S2 = 0; S1 = 0; }
21
    }
22
23
    if (S1) { PORTD |= (1<<PD1); } else { PORTD &= ~(1<<PD1); }
24
    if (S2) { PORTD |= (1<<PD2); } else { PORTD &= ~(1<<PD2); }
25
26
    TCNT2 = pulselength; //Zählregister
27
  }
28
}

Wenn pulslength 0 erreicht hat, passiert einfach gar nichts mehr im 
Overflow Interrupt und damit herrscht dann Ruhe an den Pins.

Wenn jetzt immer noch nicht Ruhe herrscht, dann liegt es daran, dass 
pulslength nie 0 wird.
1
ISR(ADC_vect)
2
{  
3
  AdcValue = ADCH;  // Nur die MSB werden übernommen ///
4
5
  //Sicherheitsüberprüfung ADC
6
  if ( AdcValue < 1 ) AdcValue = 0;

Das ist ja momentan ein wenig sinnfrei :-)

von Google Master (Gast)


Lesenswert?

haha sinnfrei ist gut :P stimmt, blöde abfrage...hab es eliminiert.

stimmt, bei 0 macht er immernoch nix...erst bei pulselegth > 2 herrscht 
ruhe. seltsam...

von Google Master (Gast)


Lesenswert?

...

nee doch nicht....war wohl nur zufall..ab und zu kommen dann doch welche 
impulse durch...hmmm

von Karl H. (kbuchegg)


Lesenswert?

Hast du dir schon mal die ADC Werte angesehen?

von Google Master (Gast)


Lesenswert?

Nein, noch nicht. Würde es gerne machen, aber müsste mich erst in UART 
reinlesen wie man das am schnellsten hinkriegt. Gibt es da vlt. schon 
was fertiges?
Ich benutze myAVR USB mit ISP und einen Atmega8L, falls das was 
ausmacht...

von Analog (Gast)


Lesenswert?

Achja ich arbeite bei der Firma Bosch und habe hier ein Problem mit 
Mikrokontrollern. Kann mir jemand das Programm schreiben ?

Danke

von Katapulski (Gast)


Lesenswert?

>Achja ich arbeite bei der Firma Bosch und habe hier ein Problem mit
>Mikrokontrollern. Kann mir jemand das Programm schreiben ?

Laß das dann am Besten sein und versuche in die Personalabteilung
zu wechseln. Dort kommt man auch ohne logisches Denken zum Erfolg.

gez. Katapulski

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.