Forum: Mikrocontroller und Digitale Elektronik AVR ATMega16 Timer Interrupt funktioniert, scheint aber den uC zu reseten


von Sebastian N. (exl)


Lesenswert?

Hi, wollte mir vl mal ne uhr oder so bauen,
aber der code soll bisjetzt blos einen ausgang dauerhaft blinkenlassen,
und mit interrupt nach 1s einen anderen ausgang dauerhaft einschalten.

Jetzt hab ich das Problem, das der eine zwar dauerhaft blinkt,
aber der andere der nach einer sekunde dauerhaft an sein soll
erst nach ca 8s. mal kurz blinkt, und dann wieder nach ca.8s ....
1
#include <inttypes.h>                    
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/delay.h>
5
#include <stdlib.h>
6
7
// Initialisierung vom Timer1
8
void init_timer_1(){
9
TCCR1A = 0x00; // PWM ausgeschaltet, Es gibt kein signal nach ausen
10
TCCR1B = (1<<3)|(1<<2)|(0<<1)|(0<<0); //3 = bei erreichen des vergleichwertes auf 0 setzen 2-1-0 = 100= teiler auf 256 010=8
11
OCR1AH=0x7A; //höherwertiges bit des vergleichwertes //es wird bis 31250 gezählt, (8Mhz/256)=1s
12
OCR1AL=0x12; //niederwertiges bit der vergleichwertes
13
TIMSK = 0xff;//(1<<6)|(1<<7);//Interupt bei compare enable
14
}// init_timer_1
15
16
17
ISR(TIMER1_COMPA_vect) {//Timerinterupt 
18
    PORTD|=(0 << 0) | (0 << 1) | (0 << 2) | (0 << 3) | (0 << 4) | (0 << 5) | (1 << 6) | (0 << 7);
19
    //sollte ausgang PD6 dauerhaft ein schalten
20
}//Timerinterupt TIMER1_COMPA_vect
21
22
23
int main (void)
24
{
25
DDRD = (0 << 0) | (0 << 1) | (0 << 2) | (0 << 3) | (0 << 4) | (1 << 5) | (1 << 6) | (0 << 7); //festlegen der ein0/ausgänge1
26
PORTD = 0; //alle ausgänge des PortD sind auf 0
27
28
init_timer_1();//Timer 1 Initialisieren
29
sei(); //interupts aktivieren
30
31
     while(1)
32
     {
33
             //einen ausgang immer abwechselnd ein/aus schalten
34
             if(bit_is_set (PORTD,5)){
35
                PORTD&=(1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (0 << 5) | (1 << 6) | (1 << 7); 
36
           }else{
37
                 PORTD|=(0 << 0) | (0 << 1) | (0 << 2) | (0 << 3) | (0 << 4) | (1 << 5) | (0 << 6) | (0 << 7);
38
          }    
39
     }           
40
      return 0;             
41
}

von Sebastian N. (exl)


Lesenswert?

ich betreibe den ATMega16 auf dem Pollin Ev.Board
Quarz=8Mhz;
Compiliere mit WinAVR
Übertrage mit Ponyprog
Fusebits: BOTSZ1, BOTSZ0, SUT0, CKSEL3, CKSEL2, CKSEL1 (haben alle 
hacken)

von Michael U. (amiga)


Lesenswert?

Hallo,

1. Deine Fusebits dürften der Auslieferungszustand sein, also läuft der 
Mega16 mit 1MHz intern.

8MHz externer Quarz wäre CKSEL3...0 auf 1, also bei Pony Haken raus.

2. Sind Deine LED zwischen Ausgang und GND oder zwischen Ausgang und + 
angeschlossen?

Die &-Verknüpfung in der While-Schleife macht vermutlich nicht, was Du 
erwartest.

Gruß aus Berlin
Michael

von Sebastian N. (exl)


Lesenswert?

Ja, sie waren noch im Auslieferungszustand, hab jetzt die hacken raus,
es sind jetz nur noch die hacken bei
Fusebits: BOTSZ1, BOTSZ0, SUT0
drin.

Meine LED sind zwischen Ausgang und GND => müssten bei ausgang HI 
leuchten

Die & verknüpfung in der whileschleife...
soll rücksetzen wenn ausgang aktiv, und setzen wenn inaktiv,
(das scheint sie auch zu machen, nur halt so schnell das man es nicht 
sieht)


Jetzt ist nur noch das Problem das der Ausgang den der Timerinterupt
setzen soll nur ganz kurz aufblinkt

von Sebastian N. (exl)


Lesenswert?

Ich habe mal wie in einem anderen Thema empfohlen einen Kondensator 
zusätzlich nahe am uC angeschlossen (+->GND) hilft aber auch nichts

von Sebastian N. (exl)


Lesenswert?

Hilfe !!!
Weis denn keiner eine Antwort ?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich verstehe deine Fragestellung nicht ganz und müsste mich erst 
durchkämpfen.

EDIT: Hier wurde ein Teil gelöscht. Der falsche Takt wurde bereits 
festgestellt. Anpassung der folgenden Vermutungen dazu spare ich mir ;-)

Die Analyse eines Timer-Codes ist IMHO ja müssig, wenn der µC mit einem 
anderen als dem erwarteten Takt rennt.

OK, soweit bin ich
1
#include <inttypes.h>                    
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
#include <util/delay.h>
5
#include <stdlib.h>
6
7
// Initialisierung vom Timer1 
8
// als Clear Timer on Compare Match (CTC) Mode 
9
// (Mode 4 Tabelle 47 Atmega16 Datenblatt)
10
void init_timer_1()
11
{
12
  // PWM ausgeschaltet, Es gibt kein Signal nach aussen
13
  TCCR1A = 0x00; 
14
15
  // Bit
16
  // 3     : bei Erreichen des Vergleichwertes auf 0 setzen 
17
  // 2-1-0 : 100 : Teiler auf 256 
18
  //         010 :              8
19
  TCCR1B = (1<<3) | (1<<2); // Teiler 256
20
21
  /*  
22
    To do a 16-bit write, the High byte must be written 
23
    before the Low byte. 
24
25
    For a 16-bit read, the Low byte must be read before 
26
    the High byte.
27
  */
28
29
  // Höherwertiges Bit des Vergleichwertes 
30
  // es wird bis 31250 gezählt, (8 Mhz / 256) = 1 s
31
  OCR1AH = (31250 & 0xFF00) >> 8; 
32
33
  // Niederwertiges Bit des Vergleichwertes
34
  OCR1AL = 31250 & 0x00FF; 
35
36
  //Interupt bei Compare enable
37
  TIMSK = 0xff; //(1<<6)|(1<<7);
38
}
39
40
41
//Timerinterupt TIMER1_COMPA_vect
42
ISR(TIMER1_COMPA_vect) 
43
{
44
  // Ausgang PD6 dauerhaft einschalten
45
  PORTD |= (1 << 6); // PD6 HIGH
46
} 
47
48
49
int main (void)
50
{
51
  // Pin 5 und 6 Ausgänge, Rest Eingänge (unbenutzt)
52
  DDRD = (1 << 5) | (1 << 6); 
53
54
  // alle Ausgänge des PortD sind auf 0 (LOW)
55
  PORTD = 0; 
56
57
  init_timer_1(); // Timer 1 initialisieren
58
  sei();          // Interupts global aktivieren
59
60
  while(1)
61
  {
62
    // Ausgang an Pin 5 abwechselnd ein/aus schalten
63
    PORTD ^= (1 << 5); // PD5 toggeln mit XOR
64
    
65
    // 1s = 1000 ms warten 
66
    // 1000 setzt aktuelle avr-libc voraus s. Doku
67
    _delay_ms(1000);
68
  }           
69
70
  return 0;             
71
}

Du siehst, ich habe die Bitfummeleien (für mich) lesbarer geschrieben. 
Aus deiner Beschreibung und dem Originalcode ist mir nicht klar, was du 
bei welcher LED bzw. Pin du beobachtest.

Deine while(1) Hauptschleife wechselt quasi ohne Wartezeiten PD5. Noch 
extremer in meinem Umschrieb mit dem Toggeln ohne Abfrage. Ich würde 
erwarten, dass man mit dem Auge kein Blinken beobachten kann.

Deshalb habe ich in der umgeschriebenen Source ein 1s Warten 
hinzugefügt. Eine LED PD5 sollte mit 1s hell/1s dunkel blinken, wenn 
F_CPU + Fuses + Taktquelle stimmen und mit Optimierung übersetzt wurde.

Ein langsameres Blinken wäre ein Zeichen für falschen Takt. Kein Blinken 
ein zeichen für Fehler in der Schaltung und/oder beim Programmieren.

Die ISR(TIMER1_COMPA_vect) sieht OK aus.

Bei der init_timer_1() war ich gerade dran, deine Bitnummern und 
Hexwerte mit dem Datenblatt zu vergleichen und Kommentare zu dem 
einzufügen, was ich meine, was du machen willst.

Für mich lesbarer habe ich das Setzen des Compare-Wertes geschrieben und 
ich habe die Reihenfolge des 16-Bit Register-Schreiben gecheckt.

Bin aber noch nicht fertig. Verdächtig ist mir die Zeile

> TIMSK = 0xff; //(1<<6)|(1<<7);

denn das würde bedeuten

 TICIE1    Timer 1 Input Capture Interrupt Enable
 OCIE1A    Timer 1 Output Compare A Match Interrupt Enable
 OCIE1B    Timer 1 Output Compare B Match Interrupt Enable
 TOIE1     Timer 1 Overflow Interrupt Enable

Und da 3 von 4 Interruptroutinen fehlen... rattert der µC wohl in den 
Reset. Nach dem Reset wird der Anfang von main() wieder durchlaufen, 
d.h. PD5 und PD6 in "Grundstellung".

Wenn die LED an PD6 diese ist:

> der andere der nach einer sekunde dauerhaft an sein soll erst nach
> ca 8s. mal kurz blinkt, und dann wieder nach ca.8s beschrieben wird

würde das zu falschem Takt (1 MHz statt 8 MHz) und Reset durch fehlende 
ISRs passen.

Das Blinken der LED an PD5 verstehe ich nicht, wenn in while(1) nichts 
wirklich wartendes ist.

Aber mich macht das in deiner Source ungenutzte #include <util/delay.h> 
stutzig.
Hast du vielleicht mal mit _delay_ms probiert (was das Blinken erklären 
könnte) und hier nur die falsche Source hochgeladen?

von Sebastian N. (exl)


Lesenswert?

Das in der While(1) schleife vergessen wir einfach mal
(war nur zum testen, es blinkt so schnell das man das blinken nur daran 
merkt das die led nicht ganz so hell ist)

Da anfangs garkein Interrupt ausgelöst worden ist hab ich halt mal das
ganze register auf 1 gesetzt (TIMSK = 0xff;)
mit
TIMSK =(1<<6);   //OCIE1A (Output Compare Match Interrupt Enable 
Timer/Counter 1)
oder
TIMSK =(1<<7);//TOIE1 (Timer/Counter Overflow Interrupt Enable 
Timer/Counter 1)
oder
TIMSK =(1<<6)|(1<<7);kommt leider gar kein interrupt

also resettet der uC jetzt weil ich interrupts auslöse sie aber nicht 
auswerte ?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

TCCR1B und TIMSK benutzt du falsch, jedenfalls wenn ich nach dem 
Datenblatt gehe und vermute, was du machen willst. Bei TIMSK haben die 
Bits 6 und 7 nichts mit dem CTC Modus zu tun.
1
// Initialisierung vom Timer1 
2
// als Clear Timer on Compare Match (CTC) Mode 
3
// (Mode 4 Tabelle 47 Atmega16 Datenblatt)
4
void init_timer_1()
5
{
6
  // Non-PWM, Tabelle 44
7
  TCCR1A = 0x00; 
8
9
  // Non-PWM Mode 4 (CTC), Tabelle 47
10
  // Teiler 256, Tabelle 48
11
  TCCR1B = (1<<WGM12) | (1<<CS12);
12
13
  /*  
14
    To do a 16-bit write, the High byte must be written 
15
    before the Low byte. 
16
17
    For a 16-bit read, the Low byte must be read before 
18
    the High byte.
19
  */
20
21
  TCNT1H = 0; 
22
  TCNT1L = 0; 
23
24
  // Vergleichswert setzen. 8 Mhz / 256 => 1 s
25
  OCR1AH = ((8000000L/256) & 0x0000FF00) >> 8; 
26
  OCR1AL = (8000000L/256) & 0x000000FF; 
27
28
  // Interupt bei Compare Enable A
29
  // s. 115
30
  TIMSK = (1<<OCIE1A); 
31
}

von Sebastian N. (exl)


Lesenswert?

Ok, Herzlichen dank!
mein Fehler lag an
1
TIMSK = 0xff;
bzw.
1
TIMSK = (1<<6);

mit
1
TIMSK = (1<<OCIE1A);
geht es

jetzt frag ich mich was daran der unterschied ist,
laut Tabelle im AVR-GCC Tutorial ist OCIE1A doch bit 6 ???

Bit      7        6    5    4    3      2     1    0
Name   TOIE1   OCIE1A   -   -   TICIE   -   TOIE0   -

von Stefan E. (sternst)


Lesenswert?

Sebastian N. wrote:

> jetzt frag ich mich was daran der unterschied ist,
> laut Tabelle im AVR-GCC Tutorial ist OCIE1A doch bit 6 ???

Im Tutorial steht aber auch:
1
Die folgenden Ausführungen beziehen sich auf den AT90S2313.
2
Für andere Modelltypen müsst ihr euch die allenfalls
3
notwendigen Anpassungen aus den Datenblättern der entsprechenden
4
Controller herauslesen.

Beim Atmega 16 ist OCIE1A Bit 4.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Sebastian N. wrote:

> laut Tabelle im AVR-GCC Tutorial ist OCIE1A doch bit 6 ???
>
> Bit      7        6    5    4    3      2     1    0
> Name   TOIE1   OCIE1A   -   -   TICIE   -   TOIE0   -

Diese Tabelle aus dem AVR-GCC-Tutorial stimmt für den Atmega16 
nicht. Leider steht im Tutorial rel. unauffällig:

> Einige Registerbeschreibungen dieses Tutorials beziehen
> sich auf den inzwischen veralteten AT90S2313.

Möglicherweise ist das hier der Fall.

Lerne:

1/ Man sollte immer das passende Datenblatt lesen und vergleichen.

2/ Symbolische Namen wie OCIE1A sind im Code sinnvoller als absolute 
Zahlen.

von Sebastian N. (exl)


Lesenswert?

...hätte ich dass nur früher gewusst, ...
danke für den hinweis
sollte vieleicht n bischen grösser geschrieben werden für welchen uC das 
Tutorial ist,
der Tip das man die Bits nicht direkt eingibt ist echt gut werd ich mir 
merken

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.