PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer0 + Timer1 Input Capture



Kesandal
01.07.2011, 20:19
An T1=PB1 wird ein Rechtecksignal mit variabler Frequenz angelegt.
Diese kann man mit Timer1 zählen.

Erzeugen Sie dann eine Torzeit mit Timer0 im CTC-Modus welche kleiner als 1 Sekunde sein soll.
Dann verbinden Sie OC0=PB3 mit ICP1=PD6, um am Ende der Torzeit automatisch einen Input Capture den momentanen Stand von Timer1 auszulesen [...]


Leider habe ich ein wenig Probleme mit der Aufgabenstellung.

So wie ich das verstanden habe muss ich folgendes tun:

1. Irgendwie PB1 verarbeiten. Ich denke hiermit ist nicht soetwas gemeint?!


while(PINB&_BV(1));
freq++;
while(!(PINB&_BV(1)));


2. Mit Timer0 in bestimmten Zeitabständen (kleiner als 1 Sekunde) OC0 toggeln.


OCR0=180; // 1/20
TCNT0=0;
TCCR0=(1<<WGM01)|(1<<CS12)|(1<<CS00)|(1<<COM00); // CTC, pr=1024, bei Match OC0 toggle

Warum 180?
Nun.. Da es ja ein 8bit-Register ist kann ich nicht höher als 256 gehen.
Und in der Aufgabenstelung ist von kleiner als 1 Sekunde die Rede :D
Also habe ich hier 20hz.



3. Da OC0 mit ICP1 verbunden ist kann ich den "Input Capture" Modus vom Timer1 verwenden.



// Timer 1
TCNT1=0;
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS12)|(1<<CS10)|(1<<ICNC1)|(1<<ICES1);


CTC wenn externes Signal, steigende Flanke und Noice-Canceler einschalten.



Sooooo.

das ganze sieht dann folgendermaßen aus (Punkt2 und 3. Punkt1 weiß ich noch nicht wie ich es implementieren soll :( )




#define SYSTEMCLOCK 3686400
#define F_CPU 3686400UL
#define LCD_PORT PORTC

#include <avr/io.h>
#include <avr/interrupt.h>
#include "display.inc"

volatile unsigned long freq = 0;
volatile unsigned int tim0_cnt = 0;

int main(void){
DDRC=0xff;
DDRB=0xff;

lcd_init();

PORTB=0xff;

lcd_setcursor(0,0);
lcd_putstring("Freq: ");

OCR0=180; // 1/20
TCNT0=0;
TCCR0=(1<<WGM01)|(1<<CS12)|(1<<CS00)|(1<<COM00); // CTC, pr=1024, bei Match OC0 toggle


// Timer 1
TCNT1=0;
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS12)|(1<<CS10)|(1<<ICNC1)|(1<<ICES1);


TIMSK=(1<<OCIE0);

TIFR=(1<<ICF1);


while(1){


if((TIFR&_BV(ICF1))!=0){

TIFR=(1<<ICF1);

lcd_setcursor(6,0);
lcd_putdez_uint(ICR1);

}
}

return 0;
}






Problem
Ich glaube er kommt nichtmal in die If-Schleife (innerhalb der While) rein :(

Besten Dank
Kesandal

sternst
01.07.2011, 22:14
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS12)|(1<<CS10)|(1<<ICNC1)|(1<<ICES1);Wie soll denn bitte das Input-Capturing funktionieren, wenn du einen Timer-Mode auswählst, bei dem ICR1 anderweitig verwendet wird? Wieso überhaupt einen CTC-Mode?

Und wieso wählst du als Clock-Source clkIO/1024? Das passt doch überhaupt nicht hierzu:

An T1=PB1 wird ein Rechtecksignal mit variabler Frequenz angelegt.
Diese kann man mit Timer1 zählen.


Und so nebenbei:

Ich glaube er kommt nichtmal in die If-Schleife (innerhalb der While) reinhttp://www.if-schleife.de/

Kesandal
01.07.2011, 22:35
Hallo sternst,

danke für Deine Antwort.


Wie soll denn bitte das Input-Capturing funktionieren, wenn du einen Timer-Mode auswählst, bei dem ICR1 anderweitig verwendet wird? Wieso überhaupt einen CTC-Mode?


CTC zu nehmen war meine Idee, weil ich ja später anhand vom Zählerstand die Frequenz ausgeben möchte.



When a capture is triggered, the 16-bit value of the counter (TCNT1) is written to the Input Capture Register (ICR1). The Input Capture Flag (ICF1) is set at
the same system clock as the TCNT1 value is copied into ICR1 Register

Wird nach dem kopieren TCNT1=0 gesetzt?
Das geht hierraus leider nicht hervor. Wenn dies der Fall ist, brauche ich natürlich keinen CTC.



Und wieso wählst du als Clock-Source clkIO/1024? Das passt doch überhaupt nicht hierzu:


weil:


das ganze sieht dann folgendermaßen aus (Punkt2 und 3. Punkt1 weiß ich noch nicht wie ich es implementieren soll :-( )


Ich verstehe immernoch Deine Idee nicht eine externe Clok-Source zu wählen.
Kannst Du mir vielleicht die Idee näher erleutern?

sternst
01.07.2011, 23:11
CTC zu nehmen war meine Idee, weil ich ja später anhand vom Zählerstand die Frequenz ausgeben möchte.Und wo ist da der Zusammenhang zwischen "später anhand vom Zählerstand die Frequenz ausgeben" und CTC-Mode?



Wird nach dem kopieren TCNT1=0 gesetzt?Nein.



Wenn dies der Fall ist, brauche ich natürlich keinen CTC.Auch so kannst du mit dem CTC-Mode nichts anfangen. Jetzt verstehe ich aber, was dein Gedanke hinter der Mode-Wahl war. Kurz gesagt: das klappt nicht.
Wenn es eine einmalige Messung ist, setzt du den Timer einfach "von Hand" auf Null. Und wenn es eine fortlaufende Messung sein soll, setzt du den Timer gar nicht auf Null, sondern ziehst die jeweiligen ge-capture-ten Timer-Werte voneinander ab.



Ich verstehe immernoch Deine Idee nicht eine externe Clok-Source zu wählen.Das ist nicht meine Idee, sondern die Vorgabe der Aufgabe:
An T1=PB1 wird ein Rechtecksignal mit variabler Frequenz angelegt.
Diese kann man mit Timer1 zählen.

Kesandal
02.07.2011, 00:03
Ich habe nun den Quelltext entsprechend angepasst:



#define SYSTEMCLOCK 3686400
#define F_CPU 3686400UL
#define LCD_PORT PORTC

#include <avr/io.h>
#include <avr/interrupt.h>
#include "display.inc"

volatile unsigned long freq = 0;
volatile unsigned int tim0_cnt = 0;

int main(void){
DDRC=0xff;
DDRB=0xff;

lcd_init();

PORTB=0xff;

lcd_setcursor(0,0);
lcd_putstring("Freq: ");

OCR0=180; // 1/20
TCNT0=0;
TCCR0=(1<<WGM01)|(1<<CS12)|(1<<CS00)|(1<<COM00); // CTC, pr=1024, bei Match OC0 toggle


// Timer 1
TCNT1=0;
TCCR1B=(1<<CS12)|(1<<CS11)|(1<<CS10)|(1<<ICNC1)|(1<<ICES1);


TIMSK=(1<<OCIE0);

TIFR=(1<<ICF1);


while(1){


if((TIFR&_BV(ICF1))!=0){

TIFR=(1<<ICF1);

lcd_setcursor(6,0);
lcd_putdez_uint(ICR1);
TCNT1=0;

}
}

return 0;
}


Irgnedwie scheint das mit Clock-Source = extern nicht zu klappen.
Im Display erhalte ich nämlich nur die ausgabe: Freq: 0000

Gibt es noch etwas bei der externen Clock-Source zu beachten?
Laut Manual müsste es ja reichen wenn ich die Bits im TCCR1B entsprechend setze.

sternst
02.07.2011, 00:50
Gibt es noch etwas bei der externen Clock-Source zu beachten?Dein Programm verursacht an dem Pin einen Kurzschluss. Das dürfte hinderlich sein.

Außerdem hast du die beiden oben erwähnten Möglichkeiten vermengt. Du hast eine fortlaufende Messung, setzt den Counter aber auf Null. Das ergibt ungenaue Ergebnisse, zumal du das Zurücksetzen auch noch an der ungünstigsten Stelle überhaupt platziert hast.