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.
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?
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
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?
>> 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.
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?
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 | }
|
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.