Forum: Compiler & IDEs ATMega16: Interrupt mit Timer1


von Elroy (Gast)


Lesenswert?

Hallo!
Ich versuche mit einem STK500 und ATMega16 mit Hilfe des Timer1 nach 
einer bestimmten Zeit eine ISR aufzurufen.
Einstellungen sind wie folgt:
- Der uC taktet mit 1Mhz in dem Auslieferungszustand
- CTC Modus
- Prescaler ist auf 64 eingestellt
  --> wenn der Timer1 also 1 Sekunde warten soll, bis ISR ausgelöst 
wird, muss bis 15625 gezählt werden

Was soll passieren:
1. LED an PD5 und PD6 anschalten
2. LED an PD5 soll dauerhaft leuchten
3. Nach 1 Sekunde soll in die ISR gesprungen werden, wo LED an PD6 
ausgeschaltet wird


Mein Code:

#define F_CPU 1000000L  //Standardeinstellung 1MHz
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>

// Initialisierung vom Timer1
// als Clear Timer on Compare Match (CTC) Mode
// (Mode 4 Tabelle 47 Atmega16 Datenblatt)
void init_timer_1()
{
  // Non-PWM, Tabelle 44
  TCCR1A = 0x00;

  // Non-PWM Mode 4 (CTC), Tabelle 47
  // Teiler 64, Tabelle 48
  TCCR1B = (1<<WGM12) | (1<<CS11)  | (1<<CS10);

  TCNT1H = 0;
  TCNT1L = 0;

  // Vergleichswert setzen. 1Mhz/64 => 1s //entspricht 15625
  OCR1AH = ((15625 & 0xFF00) >> 8);
  OCR1AL =  (15625 & 0x00FF);

  TIMSK = (1<<OCIE1A);
}



//Timerinterupt
ISR(TIMER1_COMPA_vect)
{
  // Ausgang PD6 ausschalten
  PORTD |= (1 << PD6);
  _delay_ms(1000);
}


int main (void)
{
  // Pin 5 und 6 Ausgänge, Rest Eingänge (unbenutzt)
  DDRD = (1 << DDD5) | (1 << DDD6);

  // LED an PIN5 und PIN6 AN
  PORTD = (0<<PD5) | (0<<PD6);

  init_timer_1(); // Timer 1 initialisieren
  sei();          // Interupts global aktivieren

  while(1) {
  }

  return 0;
}


Was passiert ist folgendes: LED an PD5 und PD6 leuchten dauerhaft! Es 
wird kein Interrupt ausgelöst! Woran liegt das?
Ich wäre echt dankbar, wenn sich jemand erbarmt und mir auf die Sprünge 
helfen könnte.

von PORTD (Gast)


Lesenswert?

schreib das ma in deine ISR:
PORTD &= ~(1<<PD6);

von Elroy (Gast)


Lesenswert?

Das hats nicht gebracht, denn komischerweise sind bei mir, wenn ich in 
der main schreibe:

  DDRD |= (1 << DDD5) | (1 << DDD6);  // PD5 und 6 als Ausgang
  PORTD |= (1<<PD5) | (1<<PD6);       // PD5 und PD6 HIGH

die LEDs auf LOW, also AUS! Warum leuchten die nur, wenn ich sie auf 
null setze?? also: PORTD |= (0<<PD5) | (0<<PD6); //LEDs leuchten!! (??)

Ich bin schon den ganzen tag dabei, sehe ich den Wald vor lauter Bäumen 
nicht?

von Michal Z. (z_lahcim)


Lesenswert?

Hallo Elroy,

willst Du nur eine LED zum leuchten bringen musst Du sie auf Null und 
die anderen auf Eins setzen, hört sich komisch an ist aber so.
z.Bsp.
PORTD = 0xEF; // binär 11101111
jetzt leuchtet nur die 4-te von links.

viel spass noch
Michal

von Elroy (Gast)


Lesenswert?

Okay, danke für den Hinweis, Michal. Aber das erklärt mir immer noch 
nicht, warum mein Programm nicht nach einer Sekunde in meine ISR 
reinspringt?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

>> muss bis 15625 gezählt werden

Nö. Bis 15625-1 siehe 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Die_Timer_und_Z%C3%A4hler_des_AVR#CTC-Betriebsart_.28Clear_Timer_on_Compare_Match.29

>> STK500
Das Stk500 hat active low geschaltete LEDs.
           R     LED
Pin -----####----|<------ Vcc

>> // LED an PIN5 und PIN6 AN
>> PORTD = (0<<PD5) | (0<<PD6);

Richtig.
Bits LOW setzen = LEDs an

>> PORTD |= (1<<PD5) | (1<<PD6); // PD5 und PD6 HIGH
>> die LEDs auf LOW, also AUS!

Richtig (Code) und Falsch (Beschreibung).
Bits HIGH setzen = LEDs aus

>> also: PORTD |= (0<<PD5) | (0<<PD6); //LEDs leuchten!! (??)

Diese Anweisung ändert überhaupt nichts an den Bits PD5 und PD6 in 
PORTD. Siehe Bitmanipulation oder 
Beitrag "Re: ATMega16: Interrupt mit Timer1"

>>//Timerinterupt
>>ISR(TIMER1_COMPA_vect)
>>{
>>  // Ausgang PD6 ausschalten
>>  PORTD |= (1 << PD6);
>>  _delay_ms(1000);
>>}

Entferne das _delay_ms(1000); aus der ISR. Das hat hier nichts zu 
suchen. ISRs so kurz wie möglich halten. Wenn du meinst das 
_delay_ms(1000); hier zu brauchen, stimmt deine restliche Codelogik 
nicht.

von Elroy (Gast)


Lesenswert?

Hallo Stefan,
schön, dass du dich meldest! Habe bereits einige aufschlussreiche 
Kommentare von dir gelesen!

Habe den geänderten Code vorhin auf einem Rechner getestet, schien auch 
im Simulator des AVRStudio4 in die ISR reinzuspringen, doch wenn ichs 
jetzt mit meinem STK500 versuche, leuchten die LEDS PD5 und PD6 einfach 
nur durchgängig:


#define F_CPU 1000000L  //Standardeinstellung 1MHz
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>

// Initialisierung vom Timer1
// als Clear Timer on Compare Match (CTC) Mode
// (Mode 4 Tabelle 47 Atmega16 Datenblatt)
void init_timer_1()
{
  // Non-PWM, Tabelle 44
  TCCR1A = 0x00;

  // Non-PWM Mode 4 (CTC), Tabelle 47
  // Teiler 64, Tabelle 48
  TCCR1B = (1<<WGM12) | (1<<CS11)  | (1<<CS10);

  TCNT1H = 0;
  TCNT1L = 0;

  // Vergleichswert setzen. 1Mhz/64 => 1s //entspricht 15625-1
  OCR1AH = ((15624 & 0xFF00) >> 8);
  OCR1AL =  (15624 & 0x00FF);

  TIMSK = (1<<OCIE1A);
}



//Timerinterupt
ISR(TIMER1_COMPA_vect)
{
  // PD6 und PD5 AUS
  PORTD = (1<<PD6) | (1<<PD5);
}


int main (void)
{
  // Pin 5 und 6 Ausgänge, Rest Eingänge (unbenutzt)
  DDRD = (1 << DDD6) | (1 << DDD5);

  // LED an PIN5 und PIN6 AN
  PORTD &= ~((1 << PD6) | (1<<PD5));

  init_timer_1(); // Timer 1 initialisieren
  sei();          // Interrupts global aktivieren

  while(1) {
  }

  return 0;
}

Also eigentlich sollten PD5 und PD6 nur für eine Sek an sein, danach 
durch die ISR ausgeschaltet werden.
Vielleicht werden sie nur einen Takt ausgeschaltet, sodass man es mit 
bloßem Auge nicht sieht?

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Leider bin ich jetzt auch überfragt. Dein Programm sieht richtig aus und 
wird auch richtig simuliert.

War bei deinem Atmega16 mal der Watchdog enabled? Wenn dein Programm 
in der Zeit bis zum Interrupt (1s sind Ewigkeiten!) einen Reset durch 
den Watchdog hat (nach paar 36µs Laufzeit in main() LEDs an, dann 
schlägt Watchdog in paar zig ms zu...), sieht das aus wie ein 
Dauerleuchten der LEDs. Du könntest wie in [[AVR-GCC-Tutorial/Der 
Watchdog]] beschrieben den Watchdog in der while-Schleife laufend 
zurücksetzen oder Zu Beginn von main disablen.
1
// Rest...
2
#include <avr/wdt.h>
3
4
// Rest...
5
6
int main(void)
7
{
8
  wdt_disable(); // Option 1
9
10
  // Rest...
11
12
  while (1)
13
  {
14
    wdt_reset(); // Option 2
15
  }
16
}

von Elroy (Gast)


Lesenswert?

Hey, super, mit
  wdt_disable(); // Option 1
funktionierts!

Über den Watchdog habe ich mir noch nichts durchgelesen, aber eigentlich 
habe ich weder am Board noch im AVRStudio irgendetwas verändert 
(zumindsest so weit ich weiß...)

Danke für deine Mühe!!
Werde morgen das Tutorial zum Watchdog durcharbeiten!
Nochmals danke!

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.