www.mikrocontroller.net

Forum: Compiler & IDEs ATMega16: Interrupt mit Timer1


Autor: Elroy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: PORTD (Gast)
Datum:

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

Autor: Elroy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Michal Zoltowski (z_lahcim)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Elroy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> muss bis 15625 gezählt werden

Nö. Bis 15625-1 siehe 
http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

>> 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.

Autor: Elroy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

// Rest...
#include <avr/wdt.h>

// Rest...

int main(void)
{
  wdt_disable(); // Option 1

  // Rest...

  while (1)
  {
    wdt_reset(); // Option 2
  }
}


Autor: Elroy (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.