PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : TIMER1 CAPTURE INPUT



Koertis
13.08.2010, 15:15
Hallo,
ich habe jetzt schon X mal das Datenblatt vom Atmega644 durchgeblättert, und habe auch mein Programm im AVR studio Simuliert.

Ich versuche den Caputre In Interrupt anszusprechen, ohne Erfolg.
Wenn ich im AVR Modus PD6 (ICP) auf High setze passiert nichts, wenn ich aber PD4 auf High setze springt er zum Interrupt TIMER1_CAPT_vect.
Wenn ich im Register per Mausklick das Flag ICF1 setze, springt er auch??
Sollte ICF1 nicht mit dem PD6 verbunden sein??? Habe ich ein Register übersehen?

Bitte helft mir





#include <avr/io.h>
#define F_CPU 20000000
#include <util/delay.h>
#include <avr/interrupt.h>
#define TICIE 4

// Umdrehung durch Hallsensor messen

uint8_t softtimer = 0, LB =0, HB = 0,Spalte=0;
double TIME=0, OLDTIME = 0, Overflow = 0;

ISR(TIMER1_OVF_vect) // Timer1 Überlauf
{
softtimer++; // zählen der Überläufe
}

ISR(TIMER1_CAPT_vect) // Flanke an ICP pin
{
// Variablendeklaration

LB = ICR1L; // low Byte zuerst, high Byte wird gepuffert
HB = ICR1H;

TIME = (HB<<8)| LB;

OCR2A = TIME/5;
//TCNT1 =0;
TCNT2 =0;
if(Overflow)
Spalte--;

}



SIGNAL (TIMER2_COMPA_vect)
{Overflow = 0xFF;
sei();
if(Overflow)
Spalte++;


cli();
Overflow = 0;
}

int main(void) {
TCCR1A = 0; // kein PWM, kein INPUT bei OC1...
TCCR1B |= (1<<ICES1); // reagiert bei steigender Flanke
TCCR1B |= (1<<CS11) | (1<<CS10); // TAKT /64
TIMSK1 |= (1<<ICIE1)| (1<<TOIE1); // ICP steigende Flanke und overflow
TIFR1 |= (1<<TOV1) | (1<<ICF1);

TCCR2A |= (1<<WGM21);// CTC Modus: Wenn der Timer OCR2B erreicht löst er ein Interrupt aus und beginnt von 0
//OCR2B = 0x02; // Gibt vergleichswert des TIMER 2 an
TCCR2B |= (1<<CS11) | (1<<CS10);
// Compare Interrupt erlauben
TIMSK2 |= (1<<OCIE2A);
TIFR2 |= (1<<OCIE2A); // Interrupt freischalten

DDRC = 0xff;
PORTC =0;

long int Zahl =0;

while(1){
sei();
Zahl = TIME;

cli();
PORTC = Zahl;
sei();
}
return 0;
}

Jaecko
13.08.2010, 17:18
In einer ISR haben sei() und cli() nichts zu suchen. Das macht der Compiler selbst. (Ausser die damit verbundenen Auswirkungen sind beabsichtigt, was ich hier aber nicht glaub)

Die Interrupts 1x in der main VOR der while(1) freigeben und gut is.
Nicht ständig an und abschalten.

Koertis
14.08.2010, 10:04
Ich habe das gemacht, dass der Timer 1 immer die höhere priorität hat, also auch wenn der Interrupt von Timer 2 ausgelöst hat soll immer noch Timer1 die höhere Priorität haben und eventuell einspringen.
Komischerweise, wenn ich sei() und cli() in der while(1) lösche und ein sei() vor die while(1) setze, dann geht der Simulator einmal die while schleife durch und hängt von da an im Timer2 interrupt.

Besserwessi
14.08.2010, 10:55
Das Sei / CLI in der einen ISR kann man tatsächlich so machen. Es dauert hier doch relativ lange bis der Interupt ein zweites mal auftritt. Generell sollte man damit aber vorsichtig sein, denn verschachtelte Interrupts sind Fehleranfällig, und man sollte es nur tun, wenn man genau weiss was man tut und es auch nötig ist. Lohnen tut es sich hier eigentlich nicht, die ISR ist auch so sehr schnell fertig.

Die SEI / CLI Befehle in der While Schleife haben schon eine gewisse Berechtigung, wegen des Zugriffs auf die 16 Bit Variabel die in der ISR verändert wird. Das eine SEI sollte aber vor die Schleife, also nur das eine CLI-SEI paar in der Schleife. In diesem speziellen Fall ist es allerdings nicht nötig den Interrupt zu sperren - später werden (bis jetzt) ohnehin nur die unteren 8 Bits benutzt - das würde auch ohne das sperren des Interrupts gehen.

Es fehlt noch einige Male ein Volatile bei der Variablen deklaration - so wird der Compiler vermutlich etwas zu viel optimieren, weil er nicht weiss das da Werte in einer ISR verändert werden.




p.s.: Noch 2 Tipps:
1) ähnlich wie beim AD- kann man auch auf die ICP Register als 16 Bit Wert zugreifen. Man kann also gleich Time = ICP1 schreiben.

2) lokale Variabeln (hier HB und LB) für die ISR sollte man auch wirklich als soche deklarieren und keine globalen Variablen nutzen. Der Compiler kann dann besser optimieren, und außerhalb der ISR sind die Variabeln ohnehin nicht zu gebrauchen. Mit globalen Variabeln sollte man ohnehin sparsam sein.

Koertis
14.08.2010, 11:50
Es fehlt noch einige Male ein Volatile bei der Variablen deklaration - so wird der Compiler vermutlich etwas zu viel optimieren, weil er nicht weiss das da Werte in einer ISR verändert werden.

p.s.: Noch 2 Tipps:
1) ähnlich wie beim AD- kann man auch auf die ICP Register als 16 Bit Wert zugreifen. Man kann also gleich Time = ICP1 schreiben.


Danke das wusste ich nicht



2) lokale Variabeln (hier HB und LB) für die ISR sollte man auch wirklich als soche deklarieren und keine globalen Variablen nutzen. Der Compiler kann dann besser optimieren, und außerhalb der ISR sind die Variabeln ohnehin nicht zu gebrauchen. Mit globalen Variabeln sollte man ohnehin sparsam sein.

Wie deklariere ich Variablen für die ISR? Volatile benutzen?

und ich habe noch eine Frage:
Ich habe jetzt im Datenblatt nochmal alles durchgelesen bezüglich Timer2 CTC modus(der jetzt super funktioniert) und Timer1 Capture In modus. Aber einen Punkt finde ich nicht, wie verbinde ich den ICP Pin mit ICF flag? (Also wenn ICP(PD6) =high-> ICF = high-> Interrupt.



This flag is set when a capture event occurs on the ICP1 pin. When the Input Capture Register
(ICR1) is set by the WGMn3:0 to be used as the TOP value, the ICF1 Flag is set when the
counter reaches the TOP value.
ICF1 is automatically cleared when the Input Capture Interrupt Vector is executed. Alternatively,
ICF1 can be cleared by writing a logic one to its bit location.

Genau das muss ich machen, aber ich habe keinen Plan wie????

Besserwessi
14.08.2010, 13:22
Die lokalen Variablen in der ISR deklariert man gang normal (ohne Volatile), einfach innerhalt der ISR.

Die globalen Variablen die in der ISR verändert werden, und im Hauptprogramm (oder ggf. auch in einer anderen ISR) ausgelsen werden müssen als Volatile gekennzeichnet werden. Ähnliches gilt auch für Variablen die in der ISR gelesen werden und im Haptprogramm verändert werden. Die Deklaration also etwa so:

volatile unsigned int time ;


Die "Verbindug" vom ICP Eingang zum Inputcaptureflag (ICF1) ist immer da, außer bei einigen PWM modi die das ICP Register für was anderes nutzen. Man kann noch im Resgister TCCR1B einstellen, welche Flanke benutzt wird, hier soll das wohl die Steigende werden. Daszu muß man ggf. noch den Interrupt zum Input capture freigeben, üblicherweise in TIMSK1.

Koertis
14.08.2010, 13:39
Ich habe jetzt im AVR-Studio den Controll von Simulator-> Atmega644 auf Simulator2-> Atmega644 umgestellt. Und jetzt funktionierts.

2 Tage lang den Kopf zerprechen für so ein s*****....

Danke für eure Hilfe