AVR ATMega16 Timer Interrupt funktioniert, scheint aber den uC zu reseten

#1017492
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
}
#1017550
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
#1017563
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
Persönliche Seite #1018984
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?
#1019598
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 ?
Persönliche Seite #1019643
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
}
#1019883
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.
Persönliche Seite #1019987
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren