Hallo zusammen!
ich hab schon einige Zeit hier im Forum mitgelesen. Ich versuche, mich in die Materie µC einzuarbeiten, programmieren tue ich in C mittels AVR Studio 5.1. Nun komme ich aber nicht mehr weiter und stelle deshalb meine erste Frage an Euch!
Ziel: Auf eine steigende und fallende Flanke am Pin Int0 nach einer einstellbaren Zeit reagieren (mittels externen Interrupt 0 und Timer0 Overflow Interrupt).
Vorgehen: Zunächst wird der Timer0 im "normal mode" gestartet, dessen Overflow Interrupt bleibt zunächst aber deaktiviert. Nun gebe ich ein Rechtecksignal auf den Int0-Pin meines Atmega32 (eingebaut im RN control @ 16MHz) und konfiguriere den µC so, dass ein Interrupt bei fallender und steigender Flanke auf Int0 ausgelöst wird (ISR(INT0_vect). Nun möchte ich eine gewisse Zeit nach Eingang dieses Interrupts etwas anderes machen/reagieren. Ich aktiviere also in der ISR(INT0_vect) den Timer0 Overflow Interrupt, initialisiere den Timer0 auf z.B. 1, schalte den Int0-Interrupt aus und schalte Pin PA1 auf high. Nun zählt Timer0 hoch und läuft über, wobei der Timer0 Overflow Interrupt ausgelöst wird (ISR(TIMER0_OVF_vect). In dieser ISR schalte ich zunächst den Overflow Interrupt aus, aktiviere wieder den externen Int0 Interrupt und ziehe PA1 auf low.
Die Zeit zwischen dem externen Interrupt 0 und dem folgendem Overflow Interrupt des Timer 0 (= Delay) wird festegelegt durch den verwendeten Prescaler des Timer 0 (in meinem Fall 64) und den Wert, den man TCNT0 in der Int0 ISR füttert. In meinem Codebeispiel wird TCNT0 1 gesetzt (8 bit Register), ich erwarte also ein Delay von 1/(16000000/64)*255 = ~1 ms. Dieses Delay versuche ich mittels dem Schalten des Pin PA1 sichtbar zu machen. Ich erwarte demnach einen Puls an PA1 für die Dauer von ~1ms nach einer eingehenden Flanke auf Int0.
Zum Testen verwende ich einen Funktionsgenerator (PCGU1000 von Velleman), der die Flanken generiert und ein DSO (Rigol DS1102E), welches Pin PA1 überwacht.
Es tritt dabei folgendes Problem auf: Je nach Frequenz des Funktionsgeneratorsignals (Rechteck), funktioniert das Ganze oder nicht. Bei 100 Hz auf Int0 ist der high-Puls auf PA1 immer (!) extrem kurz (µs). Bei 300 Hz ist der Puls immer ~1 ms lang, wie erwartet. Bei 250 Hz funktioniert es manchmal, manchmal nicht. Woran liegt das? Hat der µC Probleme, "langsam" steigende und fallende Flanken mittels Pin Change Interrupt auszuwerten? Vielleicht kennt ja jemand dieses Verhalten und kann mir das erklären. Wie kommen bei den "Fehl-Triggern" (100 Hz) die kurzen High-Pulse zustande (im Bereich von µs!)?
Hier der Code:
Code:
#define F_CPU 16000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>
void InitTimer0()
{
TCCR0 |= (1<<CS01) | (1<<CS00) | (1<<COM00) ; //Setup timer0 in normal mode with a prescaler of 64; enable OVF interrupt in ISR to start interrupt generation
DDRB |= (1<<PB3); //set OC0 as output
}
void StopTimer0()
{
TCCR0 &= ~(1<<COM00); //Set pin mode to normal operation; if this is not done, the pin will stay at the last logical level when stoppting timer
TCCR0 &= ~(1<<CS02); //Stops timer according to datasheet
TIMSK &= ~(1<<TOIE0); //disable timer0 OVF interrupt;
}
int main (void)
{
MCUCR |= (1<<ISC00); //interrupt on any logical change on Int0 "PD2"
GICR |= (1<<INT0); //enable INT0 interrupt
DDRA |= (1<<PA1); //Pin PA1 as output
InitTimer0(); //start timer 0
sei(); // Enable the Global Interrupt Enable flag so that interrupts can be processed
while(1)
{
//nothing here except interrupts
}
}
ISR(INT0_vect) //ISR when logical change on INT0 "PD2"
{
GICR &= ~(1<<INT0); //disable this IRF; enable again when the timer0 OVF ISR fires
TIMSK |= (1<<TOIE0); //enable timer0 OVF interrupt; will fire about 1ms after this ISR has completed
TCNT0 = 1; //Write 1 to timer 0 to restart counting at bottom+1; any 8 bits work to adjust delay
PORTA |= (1<<PA1); //Set PA1 high when INT0 fires
//SFIOR |= (1<<PSR10); //Reset prescaler
}
ISR(TIMER0_OVF_vect)
{
TIMSK &= ~(1<<TOIE0); //disable timer0 OVF interrupt -> enable again in next INTO ISR
//StopTimer0(); //Stop timer0; not needed as OVF interrupt is t
GICR |= (1<<INT0); //turn on INT0 ISR again
PORTA &= ~(1<<PA1); //Set PA1 low again when Timer0 OVF ISR fires -> High pulse (~1ms in duration) after logic level change on INT0 pin
}
Zudem hänge ich zwei Bilder an, die dieses Verhalten zeigen.
1. Bild - Timer0 Fehler: 100 Hz Rechteck auf Kanal 1 (gelb) verursacht zu kurzen High Puls auf PA1 (2. Kanal; blau). Anstiegszeiten des Rechtecksignals an Int0 ist ~30ns, Anstiegszeit von Pin PA1 ~24 ns. Zoom auf eine Flanke.
2. Bild - Timer0 läuft korrekt: 300 Hz Rechteck auf Kanal 1 (gelb) verursacht korrekten High Puls auf PA1 (2.Kanal; blau). Anstiegszeiten sind wie in Bild 1. Mehrere Flanken sichtbar.
Ich hoffe, ich habe nichts vergessen. Falls doch, gebt kurz Bescheid .
Vielen Dank für Eure Hilfe!
Christian
Lesezeichen