Forum: Mikrocontroller und Digitale Elektronik Atmega8L: Warum geht Timer0 Interrupt nicht?


von Daniel -. (root)


Lesenswert?

Hallo zusammen,

ich habe 2 Testprogramme für euch.
Das erste läuft wie erwartet. Hier wird TIMER0_OVF über TIFR abgefragt.
Beim zweiten wird in der ISR toggle=1 gesetzt, als Indikator für
eine ausgeführte ISR. Makefile ist in beiden Fällen gleich und setzt
atmega8 als uC.

Hardware Plattform STK500.
Meine Rechereche hat einen sehr ähnlichen Fall herausgebracht.
Beitrag "atmega8515 auf STK 500: Timer funtkionieren nicht"
Leider wurde dem Fragesteller dort nicht geholfen.

Alle Quellen nachfolgend gelistet.


Zuerst Makefile (Cygwin Umgebung)
1
gcc = avr-gcc
2
objcopy = avr-objcopy
3
inc = -I /cygdrive/c/WinAVR-20100110/avr/include
4
cflags = -Wall -O2 -Os
5
controller = atmega8
6
7
main: main.c
8
  $(gcc) -c main.c -mmcu=$(controller) $(inc) $(cflags)
9
  $(gcc) -o main.elf main.o
10
  $(objcopy) -j .text -j .data -I binary -O ihex main.elf main.hex
11
  
12
flash:
13
  avrdude -p atmega8 -P COM5 -c stk500v2 -e -U flash:w:main.hex:i
14
15
read:
16
  avrdude -p atmega8 -P COM5 -c stk500v2 -U flash:r:main_.hex:i
17
18
clean:
19
  rm -f main.o main.elf main.hex



Program ohne ISR
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
 
5
#define F_CPU 8000000UL
6
#include <util/delay.h>
7
8
void init_timer0(void) {
9
  TCNT0 = 0;
10
  TCCR0 = 0x05;    // 1024 prescaler of 8MHz
11
  TIFR = 1<<TOV0;    // clear pending interrupt
12
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
13
}
14
15
void init(void) {
16
  DDRB = 0x03;
17
  init_timer0();
18
}
19
20
int main(void) {
21
  uint8_t cnt=0;
22
  init();
23
  while(1) {
24
    PORTB = 0x03;
25
    while(1)
26
      if(TIFR & (1<<TOV0)) {
27
        TIFR = 1<<TOV0;
28
        TCNT0 = 0;
29
        break;
30
      }
31
    PORTB = 0x00;
32
    for(cnt=0; cnt<20; cnt++)
33
      while(1)
34
        if(TIFR & (1<<TOV0)) {
35
          TIFR = 1<<TOV0;
36
          TCNT0 = 0;
37
          break;
38
        }
39
  }
40
  return 0;
41
}


Mit ISR (nicht funktionierend = ISR nicht ausgeführt)
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
 
5
#define F_CPU 8000000UL
6
#include <util/delay.h>
7
8
volatile uint8_t toggle = 0;
9
10
ISR(TIMER0_OVF_vect) {
11
  TCNT0 = 0;
12
  toggle = 1;
13
}
14
15
void init_timer0(void) {
16
  cli();
17
  TCNT0 = 0;
18
  TCCR0 |= 0x05;    // 1024 prescaler of 8MHz
19
  TIFR = 1<<TOV0;    // clear pending interrupt
20
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
21
  sei();
22
}
23
24
void init(void) {
25
  DDRB = 0x03;
26
  init_timer0();
27
}
28
29
int main(void) {
30
  init();
31
  PORTB = 0x03;  // switch on
32
  while(1) {
33
    if(toggle)      // if interrupt occured
34
      PORTB = 0x00;  // switch off
35
  }
36
  return 0;
37
}

von Daniel -. (root)


Lesenswert?

Nachtrag:

$(objcopy) -j .text -j .data -I binary -O ihex main.elf main.hex

ist das so korrekt?


Was mich nocht etwas verwundert ist ...
1
$ avr-objdump.exe -j .data -d main.elf
2
3
main.elf:     file format elf32-avr

müsste nicht die volatile Variable toggle in der Sektion .data
abgelegt sein? Oder "löst" Compiler die volatile Anforderung damit,
dass er ihnen ein Register zuweist.

von Krapao (Gast)


Lesenswert?

Wie erkennst du, ob was passiert? Zwischen PORTB=0x03 und PORTB=0x00 
vergehen nur 32.8ms. Und dann passiert laut Programmcode im 2. Beispiel 
nix mehr.

Wenn du zwei LEDs hast, schalte nur eine regelmä0ig und lass die andere 
immer an. Wenn die eine LED sehr schnell geschaltet wird (alle 32ms ist 
schnell!), sollte man wenigstens einen Helligkeitsunterschied sehen.

von Tobi (Gast)


Lesenswert?

Nach deinem ersten Interrupt passiert nichts mehr. Du setzt toggle nie 
wieder auf 0. Mach lieber sowas
1
if(toggle) {
2
  toggle = 0;
3
  PORTB ^= 0x01; // B0 togglen, B1 so lassen (zum Test)
4
}

von Karl H. (kbuchegg)


Lesenswert?

IN deiner 'nicht funktionierenden Version':

Wo wird toggle wieder auf 0 zurück gesetzt?
Du setzt toggle mit dem ersten AUfruf der ISR auf 1, setzt es aber nie 
weider zurück.

von Thomas E. (thomase)


Lesenswert?

Daniel -------- schrieb:
> ISR(TIMER0_OVF_vect) {
>   TCNT0 = 0;
>   toggle = 1;
> }

Und dann brems' das Ding mal aus:

volatile unsigned char nT = 0;

SR(TIMER0_OVF_vect)
{
  nT++;
  if (!nT)
  {
   TCNT0 = 0;
   toggle = 1;
  }
}

Und siehe Toby.

Dann blinkt das auch für dich sichtbar.

mfg.

von Daniel -. (root)


Lesenswert?

Krapao schrieb:
> Wie erkennst du, ob was passiert?

vielleicht hätte ich das, was ich beobachte deutlicher zum Ausdruck 
bringen sollen

Vorbereitung => setze die 2 externen leds mit PORTB = 0x03; (sie 
leuchten)

Erwartung => ich erwarte, dass ISR toggle=1 setzt, sodass dann in main
if(toggle){PORTB=0x00;} die leds abschaltet.

Beobachtung => die externen leds werden nicht abgeschaltet. (sie 
leuchten)

Schlussfolgerung => ISR wird nicht ausgeführt.


---

toggle ist irreführend bezeichnet, ihr habt da recht.

von spess53 (Gast)


Lesenswert?

Hi

>Beobachtung => die externen leds werden nicht abgeschaltet.

Kommt darauf an, wie die LEDs angeschlossen sind.

MfG Spess

von Daniel -. (root)


Angehängte Dateien:

Lesenswert?

vielleicht kann jemand mal bei sich ausprobieren

von Jonas Biensack (Gast)


Lesenswert?

led gegen ground oder gegen vcc?

von Krapao (Gast)


Lesenswert?

Beim STK500 sind die LEDs active-low geschaltet. NAch dem Reset sind die 
LEDs aus, da der Pourt Eingang ist. Beim Datenrichtungssetzen sind die 
LEDs ein. Dein erstes Kommando schaltet die LEDs aus. Dann beim Timer 
IRQ schaltest du die LEDs ein. Weil zwischen den ersten Kommandos der 
AVR affenartig schnell ist, siehst du die einzelnen LED-Zustände nicht.

von Daniel -. (root)


Lesenswert?

spess53 schrieb:
> Kommt darauf an, wie die LEDs angeschlossen sind.
>
> MfG Spess

logo :)

masse --|<|-- PORTB1
masse --|<|-- PORTB2

kein Vorwiderstand, lasse den AVR die leds mit 20mA speisen :)

BTW: wieviel mA kann ein Port (in dem Fall zufälligerweise PORTB)
insgesamt treiben? Das ein Pin 20mA heisst, bedeutet ja noch
lange nicht, dass ein Port mit 8 Pins 160mA treiben kann.
Oder im Fall von AVR schon? Hab leider dazu vergeblich im Netz gesucht.

von Stefan E. (sternst)


Lesenswert?

1
  $(gcc) -o main.elf main.o
Dein Code wird für den falschen Controller gelinkt (-mmcu fehlt).

von Jonas Biensack (Gast)


Lesenswert?

ein port 100 mA

von Daniel -. (root)


Angehängte Dateien:

Lesenswert?

Krapao schrieb:
> Beim STK500 sind die LEDs active-low geschaltet.

jepp, mein setup ist aber anders
ich hab's angehängt

von Daniel -. (root)


Lesenswert?

Jonas Biensack schrieb:
> ein port 100 mA

Danke. Ist das irgendwo im Datenblatt angegeben?

von Krapao (Gast)


Lesenswert?

>> masse --|<|-- PORTB2
>> kein Vorwiderstand, lasse den AVR die leds mit 20mA speisen :)
> jepp, mein setup ist aber anders

Freu dich dran so lange es hält. Nix ist ewig ;-(

von spess53 (Gast)


Lesenswert?

Hi

>kein Vorwiderstand, lasse den AVR die leds mit 20mA speisen :)

Ich dachte, das wäre ein Scherz. AVR-Quäler.

MfG Spess

von Daniel -. (root)


Lesenswert?

Stefan Ernst schrieb:
> $(gcc) -o main.elf main.o
> Dein Code wird für den falschen Controller gelinkt (-mmcu fehlt).

jetzt habe ich Makefile abgeändert, aber keine Wirkung.
Gehört -mmcu Option in jedem Fall dazu, wenn man aus .o die .elf Datei 
erzeugt?

von Jonas Biensack (Gast)


Lesenswert?

>Ist das irgendwo im Datenblatt angegeben?

Bestimmt. Aber ich such jetzt net die Stelle raus ;)

Gruß Jonas

von Daniel -. (root)


Lesenswert?

um ein Paar zusätzliche Einsichten zu bekommen, habe ich mein Code
leicht erweitert.

als feedback, dass main normal abgearbeitet wird, habe ich
STK500 eigene leds mit in spiel reingebracht.
Das interessante ist, wenn ich sei() herauskommentiere!, dann
wechseln die STK500 leds ihren Zustand (0xAA -> 0x55 -> 0xAA ..)
Wenn sei() nicht herauskommentiert ist, verharren die STK500 leds
im 0x55 Zustand.

hmm, irgendwas stinkt da. Das ist nämlich exakt das, was im Thread
Beitrag "atmega8515 auf STK 500: Timer funtkionieren nicht"
beschrieben wird.

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
 
5
#define F_CPU 8000000UL
6
#include <util/delay.h>
7
8
volatile uint8_t toggle = 0;
9
10
ISR(TIMER0_OVF_vect) {
11
  TCNT0 = 0;
12
  toggle = 1;
13
}
14
15
void init_timer0(void) {
16
  cli();
17
  TCNT0 = 0;
18
  TCCR0 |= 0x05;    // 1024 prescaler of 8MHz
19
  TIFR = 1<<TOV0;    // clear pending interrupt
20
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
21
  sei();   // main hängt, wenn nicht auskommentiert!!!
22
}
23
24
void init(void) {
25
  DDRC = 0xFF;
26
  DDRB = 0x03;
27
  init_timer0();
28
}
29
30
int main(void) {
31
  init();
32
  PORTB = 0x03;  // switch on
33
  while(1) {
34
    if(toggle)      // if interrupt occured
35
      PORTB = 0x00;  // switch off
36
    PORTC = 0xAA;
37
    _delay_ms(100);
38
    PORTC = 0x55;
39
    _delay_ms(100);
40
  }
41
  return 0;
42
}

von Stefan E. (sternst)


Lesenswert?

Daniel -------- schrieb:
> jetzt habe ich Makefile abgeändert, aber keine Wirkung.

Dann mache doch mal
1
avr-objdump -d -h main.elf
und poste den Output.

Daniel -------- schrieb:
> Gehört -mmcu Option in jedem Fall dazu, wenn man aus .o die .elf Datei
> erzeugt?

Ja, zwingend.

Übrigens:
1
cflags = -Wall -O2 -Os
Was denn nun, 2 oder s?
(dürfte aber nicht die Ursache deines Problems sein)

von Stefan E. (sternst)


Lesenswert?

Daniel -------- schrieb:
> hmm, irgendwas stinkt da. Das ist nämlich exakt das, was im Thread
> Beitrag "atmega8515 auf STK 500: Timer funtkionieren nicht"
> beschrieben wird.

Und dort fehlt übrigens auch ein -mmcu.

von Daniel -. (root)


Lesenswert?

als Zusammenfassung meiner Erkenntnise


schleife in main läuft ab
1
void init_timer0(void) {
2
  cli();
3
  TCNT0 = 0;
4
  TCCR0 |= 0x00;    // timer0 stopped
5
  TIFR = 1<<TOV0;    // clear pending interrupt
6
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
7
  sei();
8
}


schleife in main hängt
1
void init_timer0(void) {
2
  cli();
3
  TCNT0 = 0;
4
  TCCR0 |= 0x05;    // 1024 prescaler of 8MHz
5
  TIFR = 1<<TOV0;    // clear pending interrupt
6
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
7
  sei();
8
}

schleife in main läuft, aber ISR wird nicht ausgeführt
1
void init_timer0(void) {
2
  cli();
3
  TCNT0 = 0;
4
  TCCR0 |= 0x05;    // 1024 prescaler of 8MHz
5
  TIFR = 1<<TOV0;    // clear pending interrupt
6
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
7
  //sei();
8
}

von Daniel -. (root)


Lesenswert?

Stefan Ernst schrieb:
>> hmm, irgendwas stinkt da. Das ist nämlich exakt das, was im Thread
>> Beitrag "atmega8515 auf STK 500: Timer funtkionieren nicht"
>> beschrieben wird.
>
> Und dort fehlt übrigens auch ein -mmcu.

Makefile ist nachgezogen, sieht jetzt so aus
1
gcc = avr-gcc
2
objcopy = avr-objcopy
3
inc = -I /cygdrive/c/WinAVR-20100110/avr/include
4
cflags = -Wall -O2
5
controller = atmega8
6
7
main: main.c
8
  $(gcc) -c main.c -mmcu=$(controller) $(inc) $(cflags)
9
  $(gcc) -o main.elf -mmcu=$(controller) main.o
10
  $(objcopy) -j .text -j .data -I binary -O ihex main.elf main.hex
11
  
12
flash:
13
  avrdude -p atmega8 -P COM5 -c stk500v2 -e -U flash:w:main.hex:i
14
15
read:
16
  avrdude -p atmega8 -P COM5 -c stk500v2 -U flash:r:main_.hex:i
17
18
clean:
19
  rm -f main.o main.elf main.hex

von Daniel -. (root)


Angehängte Dateien:

Lesenswert?

Stefan Ernst schrieb:
> Dann mache doch mal
> avr-objdump -d -h main.elf

ich bin kein tiefer Kenner des Assemblers
mir scheinen alle Sektions vertreten zu sein.
Interrupt 0x09 steht auch in der Tabelle.

von Andi K. (aykay90)


Lesenswert?

Hallo zusammen!

Wie Daniel habe ich das Selbe Problem, allerdings mit Bascom (ich hoffe 
jemand kann nebst C auch Bascom lesen)

Bei mir will der Timer2 (übrigens das gleiche Problem auch mit Timer0) 
nicht hochzählen.
Am Besten ist es wenn ich den Code poste:

$regfile "m48def.dat"
$crystal = 10000000
$baud = 9600


Config Portb = Output
Dim A As Integer                                            'Winkel 
Alpha
Dim B As Integer                                            'Sin- Wert 
von Alpha
Dim C As Integer                                            'Ein- Zeit 
der PWM (indirekte Spannung)
Dim D As Integer                                            'Winkel
Dim E As Integer
Dim W As Byte

'PWM- Timer 
====================================================================
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Down , Compare B 
Pwm = Clear Up , Prescale = 256
Enable Timer1

'Interrupttimer 
================================================================
Config Timer2 = Timer , Prescale = 1

On Timer2 Tim2isr
Enable Interrupts
Enable Timer2

'======================================================================= 
========
Start Timer2

A = 0
B = 0
C = 1
D = 235 / 100

sbi portb,3
cbi portb,4
Pwm1a = C
Start Timer2

Do
W = Timer2
   If W > 2 Then
   sbi portb,5
   End If
Loop




Tim2isr: 
'interruptroutine f¸r timer0

A = A + D
'B = Sin(a)                                                  'B = 
Round(b)
'B = Rad2deg(b)

   If A => 179 Then
   A = 0
   Toggle Pinb.3
   Toggle Pinb.4
   Else
   End If

C = B * 254                                                 'Ein-Zeit = 
sinAlpha * Radius
Pwm1a = C

Return


End                                        'end program





Kann mir ja vielleicht jemand helfen, bzw, sagen was nicht richtig ist?

Danke und Gruss Andi

von MWS (Gast)


Lesenswert?

Andi K. schrieb:
> Wie Daniel habe ich das Selbe Problem, allerdings mit Bascom (ich hoffe
> jemand kann nebst C auch Bascom lesen)

Mach' Dir 'nen eigenen Thraed auf, statt einen zu kapern.

von Stefan E. (sternst)


Lesenswert?

Daniel -------- schrieb:
> ich bin kein tiefer Kenner des Assemblers
> mir scheinen alle Sektions vertreten zu sein.
> Interrupt 0x09 steht auch in der Tabelle.

Ich kann kein Problem entdecken.

Zum Flashen benutzt du auch das Makefile?

von Andi K. (aykay90)


Lesenswert?

Andi K. schrieb:
>> Wie Daniel habe ich das Selbe Problem, allerdings mit Bascom (ich hoffe
>> jemand kann nebst C auch Bascom lesen)

>Mach' Dir 'nen eigenen Thraed auf, statt einen zu kapern.

Naja ich habe gedacht es wäre leichter zwei Leuten in einem Thraed zu 
helfen, als in zwei Thraed's... Aber gut, mache ich hald einen neuen 
auf.

von MWS (Gast)


Lesenswert?

Daniel -------- schrieb:
> vielleicht kann jemand mal bei sich ausprobieren

Mit AVR-Studio4 und dem angehängten Makefile lässt sich das erst gar 
nicht compilieren.
> make: *** No rule to make target `main.c', needed by `main'.  Stop.

mit ordentlichem makefile compiliert der Code. Wobei der aber sinnlos 
ist, da "toggle" nicht zurückgesetzt wird.

von MWS (Gast)


Angehängte Dateien:

Lesenswert?

Versuch's mal so, läuft im Simulator:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h>
4
 
5
#define F_CPU 8000000UL
6
#include <util/delay.h>
7
8
volatile uint8_t toggle = 0;
9
10
ISR(TIMER0_OVF_vect) {
11
  TCNT0 = 0;
12
  toggle = 1;
13
}
14
15
void init_timer0(void) {
16
  cli();
17
  TCNT0 = 0;
18
  TCCR0 |= 0x01;    // 1024 prescaler of 8MHz
19
  TIFR = 1<<TOV0;    // clear pending interrupt
20
  TIMSK |= 1<<TOIE0;  // timer overflow interrupt enable 0
21
  sei();
22
}
23
24
void init(void) {
25
  DDRB = 0x03;
26
  init_timer0();
27
}
28
29
int main(void) {
30
  init();
31
  while(1) {
32
    if(toggle)      // if interrupt occured
33
      PORTB ^= 0x03;  // switch off
34
      toggle = 0;
35
  }
36
  return 0;
37
}
Und benutze anhängendes makefile.

von Daniel -. (root)


Lesenswert?

Danke an alle. Ich glaube ich hab das Problem lokalisiert.

vorher
1
$(objcopy) -j .text -j .data -I binary -O ihex main.elf main.hex

nacher
1
$(objcopy) -j .text -j .data -O ihex main.elf main.hex

löst das Rätsel. Das Eingabeformat ist wohl nicht "binary".

@MWS
ich bevorzuge selbstgeschriebene makefiles
die sind schmächtig und ich verstehe was sie tun.
Bis solche harten Nüsse hochkommen :)
Andererseits lernt man es an denen mit der Zeit.

peace

von MWS (Gast)


Lesenswert?

Daniel -------- schrieb:
> ich bevorzuge selbstgeschriebene makefiles
> die sind schmächtig und ich verstehe was sie tun.

Ob die nun schmächtig sind, wird wohl eher wurscht sein. Wichtig ist, 
dass es läuft und wenn ein automatisch generiertes makefile dafür sorgt, 
dass das selbst zusammengeschraubte schließlich funktioniert, umso 
besser.

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.