Forum: Compiler & IDEs Interruptssteuerung Atmel


von A. R. (redegle)


Lesenswert?

Hallo,

kann mir vielleicht jemand sagen, wo ich im Internet eine gute Erklärung 
zur Interruptsteuerung bei einem Atmel finde?

Ich hab mich an einem Programm für einem Atmega2560 probiert jedoch ohne 
Erfolg.

Ziel:
- Ich gebe eine PWM aus (Zähler 5). Dies funktioniert.
- Ich lasse den Counter 1 bis 15625 hochzählen.
- Bei einem Overflow soll per Interrupt der Duty-Cyle erhöht werden.
1
 #include <avr/io.h>
2
 #include <avr/interrupt.h>
3
4
int main(void)
5
{
6
7
/*
8
Hinweis:
9
16Bit-Register immer direkt hintereinander auslesen
10
*/
11
12
13
// Alle Ports als Ausgänge
14
  DDRA = 0b11111111;
15
  DDRB = 0b11111111;
16
  DDRC = 0b11111111;
17
  DDRD = 0b11111111;
18
  DDRE = 0b11111111;
19
  DDRF = 0b11111111;
20
  DDRG = 0b11111111;
21
  DDRH = 0b11111111;
22
  DDRJ = 0b11111111;
23
  DDRK = 0b11111111;
24
  DDRL = 0b11111111;
25
26
  //Timer_Counter 5
27
  TCCR5A = 0b10100010;    //PWM Konfirguration
28
  TCCR5B = 0b00011001;  //PWM Konfirguration
29
  TCCR5C = 0b00000000;  //PWM Konfirguration
30
  ICR5   = 1024;          // Zähler auf den Endwert 1024
31
  // 3 PWMs verügbar
32
  OCR5A = 0;      // PINL3 
33
  OCR5B = 0;      // 
34
  OCR5C = 0;      // 
35
36
  // Timer 1 Initialisieren
37
  // Als Timer verwenden. // Vorteiler 1
38
  // 16Mhz Takt, zählen bis 15625 --> 1024 Overflows pro Sekunde 
39
  TCCR1A = (0<<WGM10) | (0<<WGM11);
40
  TCCR1B = (1<<WGM12) | (1<<WGM13)|(0<<CS12) |(0<<CS11)| (1<<CS10);
41
  ICR1 = 15625;  
42
43
44
  // Interrupts aktivieren
45
  sei();
46
  TIMSK5 = (1<<TOIE5);
47
  //Dauerschleife
48
  while(1)
49
  {
50
  }
51
52
return 0;
53
}
54
55
ISR(TIMER1_OVF_vect)
56
{
57
    //Duty-Cyle erhöhen
58
    if(OCR5A<1024)
59
    {
60
      ++OCR5A;
61
    }
62
    else
63
    {
64
      OCR5A=0;
65
    }
66
    // Interruptbit zurücksetzten
67
    TIFR5=0;
68
}

von Karl H. (kbuchegg)


Lesenswert?

A. R. schrieb:
> Hallo,
>
> kann mir vielleicht jemand sagen, wo ich im Internet eine gute Erklärung
> zur Interruptsteuerung bei einem Atmel finde?

Im Datenblatt steht alles was du wissen musst.

>   //Timer_Counter 5
>   TCCR5A = 0b10100010;    //PWM Konfirguration
>   TCCR5B = 0b00011001;  //PWM Konfirguration
>   TCCR5C = 0b00000000;  //PWM Konfirguration
>   ICR5   = 1024;          // Zähler auf den Endwert 1024

Super!
Das macht es so wahnsinnig einfach da nachzuvollziehen, was du da 
eigentlich alles eingestellt hast.

Nur weiter so!
Schiess dir weiter selber ins Knie und freu dich daran.


>   TCCR1A = (0<<WGM10) | (0<<WGM11);
>   TCCR1B = (1<<WGM12) | (1<<WGM13)|(0<<CS12) |(0<<CS11)| (1<<CS10);

Na also: Geht doch auch anders!
Warum hier und beim Timer 5 nicht?


> // Interrupts aktivieren
>  sei();
>  TIMSK5 = (1<<TOIE5);

Ähm. Wolltest du dich nicht an den Overflow vom Timer 1 klemmen?
Zumindest hast du eine ISR für den geschrieben. Hier gibst du aber den 
Interrupt für den Overflow vom Timer 5 frei!


> ISR(TIMER1_OVF_vect)
> {
>     //Duty-Cyle erhöhen
>     if(OCR5A<1024)
>     {
>       ++OCR5A;
>     }
>     else
>     {
>       OCR5A=0;
>     }
>     // Interruptbit zurücksetzten
>     TIFR5=0;

Was immer du hier zurücksetzen willst: lass es
Das Flag, welches zum Aufruf der ISR geführt hat, wird automatisch durch 
den Aufruf zurückgesetzt.

von A. R. (redegle)


Lesenswert?

>Im Datenblatt steht alles was du wissen musst.

Wo finde ich z.B. den unteren Befehl oder was er genau macht außer das 
Interrupt aufrufen?
Sicherung der Register, löschen des Interruptbit etc.
1
ISR(TIMER1_OVF_vect)
2
{
3
}

Im Datenblatt finde ich den Interruptvektor aber nicht die notwendigen 
Befehle zum aufrufen.

>Na also: Geht doch auch anders!
>Warum hier und beim Timer 5 nicht?

Weil der Timer 5 vor längerer Zeit programmiert wurde.
Ich habe das Programm lediglich erweitert.
Der Programmierstil verändert sich mit der Zeit.

>Ähm. Wolltest du dich nicht an den Overflow vom Timer 1 klemmen?
>Zumindest hast du eine ISR für den geschrieben. Hier gibst du aber den
>Interrupt für den Overflow vom Timer 5 frei!

Das könnte der Fehler sein danke für den Hinweis.
Ist es normal, dass das Overflowflag in der Simulation nicht gesetzt 
wird?

>Was immer du hier zurücksetzen willst: lass es
>Das Flag, welches zum Aufruf der ISR geführt hat, wird automatisch durch
>den Aufruf zurückgesetzt.

Mit Aufruf meinst du diese Funktion?
1
ISR(TIMER1_OVF_vect)
2
{
3
}

Habe Interrupts bis jetzt nur bei nem PIC in Assembler programmiert.

von A. R. (redegle)


Lesenswert?

Aktuelle Version des Programms.
1
 #include <avr/io.h>
2
 #include <avr/interrupt.h>
3
4
int main(void)
5
{
6
7
/*
8
Hinweis:
9
16Bit-Register immer direkt hintereinander auslesen
10
*/
11
12
// Alle Ports als Ausgänge
13
  DDRA = 0b11111111;
14
  DDRB = 0b11111111;
15
  DDRC = 0b11111111;
16
  DDRD = 0b11111111;
17
  DDRE = 0b11111111;
18
  DDRF = 0b11111111;
19
  DDRG = 0b11111111;
20
  DDRH = 0b11111111;
21
  DDRJ = 0b11111111;
22
  DDRK = 0b11111111;
23
  DDRL = 0b11111111;
24
25
  //Timer_Counter 5
26
  TCCR5A = (1<<COM5A1 | 0<<COM5A0 | 1<<WGM51); // Port PINL3 als Fast PWM max. 16Bit (clear on compare),   
27
  TCCR5B = (1<<WGM53  | 1<<WGM52  | 0<< CS52 | 0<<CS51 | 1<<CS50); // Fast PWM, Prescaller = 1
28
  ICR5   = 1024;          // Zähler auf den Endwert 1024
29
  // 3 PWMs verügbar
30
  OCR5A = 0;      // PINL3 
31
  OCR5B = 0;      // PWMB nicht in gebrauch
32
  OCR5C = 0;      // PWMC nicht in gebrauch
33
34
  // Timer 1 Initialisieren
35
  // Als Timer verwenden. // Vorteiler 1
36
  // 16Mhz Takt, zählen bis 15625 --> 1024 Overflows pro Sekunde 
37
  TCCR1A = (0<<WGM10) | (0<<WGM11);
38
  TCCR1B = (1<<WGM12) | (1<<WGM13)|(0<<CS12) |(0<<CS11)| (1<<CS10);
39
  ICR1 = 15625;  
40
41
42
  // Interrupts aktivieren
43
  sei();          // Setzt Globales Interrupt Enable
44
  TIMSK1 = (1<<TOIE1);  // Overflowflag des Timers 1 setzten
45
46
  //Dauerschleife
47
  while(1)
48
  {
49
  }
50
51
return 0;
52
}
53
54
ISR(TIMER1_OVF_vect)
55
{
56
    //Duty-Cyle erhöhen
57
    if(OCR5A<1024)
58
    {
59
      ++OCR5A;
60
    }
61
    else
62
    {
63
      OCR5A=0;
64
    }
65
}

von Karl H. (kbuchegg)


Lesenswert?

A. R. schrieb:
>>Im Datenblatt steht alles was du wissen musst.
>
> Wo finde ich z.B. den unteren Befehl oder was er genau macht außer das
> Interrupt aufrufen?

Den 'Befehl' findest du dort gar nicht.
Aber das das eine Interrupt Funktion einleitet kann man wissen.
Und alles dazu nötige findet sich im Kapitel über Interrupts.

> Sicherung der Register, löschen des Interruptbit etc.

Wozu brauchst du das?
Als C-Programmierer interessiert dich das alles nicht.
Alles was du wissen musst ist: Wenn eine ISR betreten wird, wird das 
entsprechende Flag, welches die Abarbeitung ausgelöst hat wieder 
gelöscht. Das steht bei jedem Interrupt-Flag bei allen Registern im 
Datenblatt immer dabei. Einzige Ausnahme: Der RxD Interrupt der UART. 
Dieses Interrupt Anforderung wird erst dann zurückgenommen, wenn das UDR 
Register ausgelesen wird. Aber auch das steht im Datenblatt. Wo? Na bei 
der Beschreibung des Interrupt Request Bits im entsprechenden Register 
der UART.

> Im Datenblatt finde ich den Interruptvektor aber nicht die notwendigen
> Befehle zum aufrufen.

Du rufst auch einen Interrupt nicht auf.
Eine Interrupt Funktion wird von der Hardware aufgerufen. Ein bestimmtes 
Ereignis tritt ein und als Folge davon kommt eine Handlungskette ins 
laufen, die darin mündet, dass deine ISR-Funktion aufgerufen wird.

> Ist es normal, dass das Overflowflag in der Simulation nicht gesetzt
> wird?

Der Simulator hat zwar so seine Bugs, aber das Overflwo Flag wird recht 
zuverlässig gesetzt. Leg einen Breakpoint in die ISR und sieh nach ob 
sie aufgerufen wird.


> Mit Aufruf meinst du diese Funktion?

Ja.
Sobald ein Ereignis eintritt (wie zb ein Overflow) merkt sich die CPU 
das mit einem Bit in einem Register. Bei nächster Gelegenheit und 
freigegebenen Interrupts wird dann die ISR aufgerufen und das 
entsprechende Anforderungsbit wieder gelöscht.

von Karl H. (kbuchegg)


Lesenswert?


von Falk B. (falk)


Lesenswert?

Siehe Interrupt

von A. R. (redegle)


Lesenswert?

Danke für die Hilfe!
Ich habe das Problem gefunden.
Ich darf den Timer nicht im "Clear Timer on Compare Match (CTC) Mode" 
verwenden.

von A. R. (redegle)


Lesenswert?

Das Programm:
Erzeugung eines Dreicks von 0 bis 5V mittels einer 10Bit PWM mit einer 
Periodendauer von 2Sekunden.
Vielleicht hat jemand ein paar Verbesserungsvorschläge.
1
 #include <avr/io.h>
2
 #include <avr/interrupt.h>
3
4
5
volatile int Temp=0;
6
// Jeder Zugriff auf die Variable Temp erfolgt als Zugriff auf den Speicher, es werden keine Register verwendet.
7
8
int main(void)
9
{
10
  
11
/*
12
Hinweis:
13
16Bit-Register immer direkt hintereinander auslesen
14
*/
15
16
// Alle Ports als Ausgänge
17
  DDRA = 0b11111111;
18
  DDRB = 0b11111111;
19
  DDRC = 0b11111111;
20
  DDRD = 0b11111111;
21
  DDRE = 0b11111111;
22
  DDRF = 0b11111111;
23
  DDRG = 0b11111111;
24
  DDRH = 0b11111111;
25
  DDRJ = 0b11111111;
26
  DDRK = 0b11111111;
27
  DDRL = 0b11111111;
28
29
  //Timer_Counter 5
30
  TCCR5A = (1<<COM5A1 | 0<<COM5A0 | 1<<WGM51); // Port PINL3 als Fast PWM max. 16Bit (clear on compare),   
31
  TCCR5B = (1<<WGM53  | 1<<WGM52  | 0<< CS52 | 0<<CS51 | 1<<CS50); // Fast PWM, Prescaller = 1
32
  ICR5   = 1024;          // Zähler auf den Endwert 1024
33
  // 3 PWMs verügbar
34
  OCR5A = 0;      // PINL3 
35
  OCR5B = 0;      // PWMB nicht in gebrauch
36
  OCR5C = 0;      // PWMC nicht in gebrauch
37
38
  // Timer 1 Initialisieren
39
  // Als Timer verwenden. // Vorteiler 1 // Modus normel zählt bis 65536
40
  // 16Mhz Takt
41
  TCCR1A = (0<<WGM10) | (0<<WGM11);
42
  TCCR1B = (0<<WGM12) | (0<<WGM13)|(0<<CS12) |(0<<CS11)| (1<<CS10);
43
44
45
  // Interrupts aktivieren
46
  sei();          // Setzt Globales Interrupt Enable
47
  TIMSK1 = (1<<TOIE1);  // Overflowenable des Timers 1 setzten
48
  TCNT1 = 49911;  
49
  //Dauerschleife
50
  while(1)
51
  {
52
  }
53
54
return 0;
55
}
56
57
ISR(TIMER1_OVF_vect)
58
{
59
  //int Temp=0; Wird ggf. in ein Register geschrieben und nach der ISR überschrieben
60
  TCNT1 = 49911;  // Startwert des Timers, damit 1024 Interrupts pro Sekunde ausgeführt werden
61
  //Duty-Cyle erhöhen
62
63
  if(Temp==0)// Temp 0 --> aufzählen
64
  {
65
    if(OCR5A==1023)
66
    {
67
      OCR5A=1024;
68
      Temp=1;
69
    }
70
    else
71
    {
72
      ++OCR5A;
73
    }
74
  }
75
76
  if(Temp==1)// Temp 1--> abzählen
77
  {
78
    if(OCR5A==1)
79
    {
80
      OCR5A=0;
81
      Temp=0;
82
    }
83
    else
84
    {
85
      --OCR5A;
86
    }
87
  }
88
}

von Falk B. (falk)


Lesenswert?

@  A. R. (redegle)

>Erzeugung eines Dreicks von 0 bis 5V mittels einer 10Bit PWM mit einer
>Periodendauer von 2Sekunden.

Easy.

>Vielleicht hat jemand ein paar Verbesserungsvorschläge.

Dein "manuelles Vorlanden" des Timers ist eine Steinzeitmethode und 
somit Schrott.

>Ich darf den Timer nicht im "Clear Timer on Compare Match (CTC) Mode"
>verwenden.

Das Gegenteil ist der Fall. Nutze den CTC Modus und du wirst einen 
superschicken PMW- und Funktionsgenerator haben. Der Rest ist eine 
triviale Fleißaufgabe för den Schöler!

MFG
Falk

von A. R. (redegle)


Lesenswert?

>Das Gegenteil ist der Fall. Nutze den CTC Modus und du wirst einen
>superschicken PMW- und Funktionsgenerator haben. Der Rest ist eine
>triviale Fleißaufgabe för den Schöler!

Könntest du das bitte etwas genauer erläutern?
Im CTC Modus wird ein Interrupt erst beim overflow ausgelöst oder kann 
ich da das "Output Compare Flag" verwenden?

von Falk B. (falk)


Lesenswert?

@  A. R. (redegle)

>Im CTC Modus wird ein Interrupt erst beim overflow ausgelöst oder kann

Nö, beim CTC gibt es keinen Overflow, "nur" einen Compare Match 
Interupt, das reicht aber. Dait hat man eine feste, zuverlässige 
Zeitbasis, in der man eine Tabelle oder Berechung für die Kurvenform 
durchgehen kann. Etwa so, wenn gleich das ein anderes Problem ist.

Beitrag "Re: 16 unabhängig arbeitende Oszillatoren ?"

MFG
Falk

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.