Forum: Mikrocontroller und Digitale Elektronik Attiny24 Timer1, Frequenzmessen


von Mr.T (Gast)


Lesenswert?

Hallo in die Runde,
ich hab da ein kleines Problem mit dem Timer am tiny24.

Erstmal möchte ich den Timer einfach laufen lassen, den Wert auslesen 
und vergleichen. Der Tiny läuft auf 8Mhz.
1
TIMSK1 = (1<<ICIE1 )|(1<<TOIE1);
2
3
TCCR1B = (1<<CS11)|(1<<CS10)|(1<<ICES1); //vorteiler 64, Positive Flanke


1
while(1)
2
{
3
   if (TCNT1 <= 360)
4
   {  
5
    PORTA &= ~(1<<PA3);             
6
   }
7
   else
8
   {
9
    PORTA |= (1<<PA3);
10
   }
11
}

OK jetzt rechne mal nach und möchte mit dem wert "360", die Länge der 
negativen "Pulsbreite" einstellen.  8Mhz/64 = 125000 Timerticks/s = 125 
Timerticks/ms. In einer [ms] zählt der Timer1 also 125 mal hoch, wenn 
ich jetzt 25ms eine negative breite haben will, 25ms*(125 Timerticks/ms) 
= 3125. OK jetzt arbeite ich gerade aber mit dem Wert "360" und mein 
Oszi zeigt -Breite = 22,72ms an.

Lasse ich den 64er Vorteiler weg, und lasse ihn auf 8Mhz laufen, so habe 
ich eine -Breite von 63µs, rechnerisch sind es 45µs die Stop Uhr im AVR 
Studio zeigt 16,25µs für einen Programmdurchlauf an und somit sind wir 
doch bei den ~63µs.

Das verstehe ich ja noch, aber warum ist mit 64er Vorteile der Wert so 
weit weg? Ich möchte eigentlich nur ein 0-100Hz Signal auswerten, sehr 
unelegant aber so habe ich das schon mal erfolgreich gemacht...
1
ISR(TIMER1_CAPT_vect)
2
{   
3
  if (TCNT1 <= 360)
4
   {  
5
    PORTA &= ~(1<<PA3);             
6
   }
7
   else
8
   {
9
    PORTA |= (1<<PA3);
10
   }
11
12
  TCNT1= 0;
13
14
15
}

Das Funktioniert auch soweit... schreibe ich aber
1
unsigned short tticks;
2
3
ISR(TIMER1_CAPT_vect)
4
{ tticks = TCNT1;
5
  TCNT1=0;
6
}

und vergleiche den werte in tticks in meiner main, wie oben. 
Funktioniert es nicht...
Ich versuche das noch eleganter zu lösen in dem ich mir die Werte aus 
ICR1 hole, aber was rechne ich mit 64 Vorteiler falsch?

lg Malte
von m.n. (Gast)


Lesenswert?

Was Du eigentlich genau machen willst, ist mir ein unklar. Geht es nur 
darum die ICP1-Frequenz zu messen?
Wie man mit T1 und ICP1 bei tiefen Frequenzen umgehen kann, kannst Du 
hier entnehmen. Beitrag "einfache Drehzahlmessung mit ATmega88"

Wichtig ist zunächst nur die Zeitmessung und Verwertung der 
T1-Überläufe.
Aber sage doch am besten, welches Problem gelöst werden soll.
von Mr.T (Gast)


Lesenswert?

Hallo,
danke, da sind zwei Dinge durcheinander geraten... ich will am ICP1 eine 
Frequenz messen, das Problem ist aber das meine Werte nicht mit den 
eingestellten übereinstimmen. Also habe ich es umgedreht und Werte vom 
Timer1 ausgegeben, dabei habe ich dann herausgefunden das die Timerticks 
nicht mit meinen berechneten übereinstimmten... wenn der Vorteiler auf 
64 eingestellt ist!


dann habe ich noch das Problem das dies soweit funktioniert, nur die 
Werte eben nicht mit den berechnet Übereinstimmen.
1
#include <avr/io.h>          
2
#include <avr/interrupt.h>
3
4
unsigned int i;
5
6
7
8
ISR(TIMER1_CAPT_vect)
9
{   
10
  i = TCNT1;
11
   if (i <= 340)
12
   {  
13
    PORTA &= ~(1<<PA3);             
14
   }
15
   if (i>= 400)
16
   {
17
    PORTA |= (1<<PA3);
18
   }
19
20
  TCNT1= 0;
21
}
22
23
ISR(TIMER1_OVF_vect) 
24
{
25
26
int main (void) {     
27
28
      
29
30
DDRA = (1 << DDA3);
31
TIMSK1 = (1<<ICIE1 )|(1<<TOIE1);
32
TCCR1B =(1<<CS11)| (1<<CS10)|(1<<ICES1);
33
    
34
    
35
    sei();
36
37
  
38
  
39
   for(;;) 
40
   
41
   { 
42
   }                    
43
   
44
   
45
   return 0;                 
46
}

so funktioniert es, dies aber nicht.
1
#include <avr/io.h>          
2
#include <avr/interrupt.h>
3
4
unsigned int i;
5
6
7
8
ISR(TIMER1_CAPT_vect)
9
{   
10
  i = TCNT1;
11
  TCNT1= 0;
12
}
13
14
ISR(TIMER1_OVF_vect) 
15
{
16
17
int main (void) {     
18
19
      
20
21
DDRA = (1 << DDA3);
22
TIMSK1 = (1<<ICIE1 )|(1<<TOIE1);
23
TCCR1B =(1<<CS11)| (1<<CS10)|(1<<ICES1);
24
  
25
  
26
    sei();
27
28
  
29
  
30
   for(;;) 
31
   
32
   {   
33
   if (i <= 340)
34
   {  
35
    PORTA &= ~(1<<PA3);             
36
   }
37
   if (i>= 400)
38
   {
39
    PORTA |= (1<<PA3);
40
   }
41
   }                    
42
   
43
   
44
   return 0;                 
45
}

Das ganze soll einfach ab einer Frequenz X ein Relais ein, und ab einem 
Wert Y wieder aus schalten.

Problem 1. Warum stimmen die Timerticks mit meiner Berechnung nicht?
Problem 2. Warum funktioniert der zweite Code nicht?



lg Malte
von Krapao (Gast)


Lesenswert?

> Problem 2. Warum funktioniert der zweite Code nicht?

Der mit den tticks bzw. dem i?
Das fehlende volatile ist IMHO der offensichtliche Grund.
von Krapao (Gast)


Lesenswert?

volatile, atomar => Interrupt lesen
von Mr.T (Gast)


Lesenswert?

Problem 2. habe ich hinbekommen... ein Erklärung wäre da aber nett.
1
volatile unsigned int i;

habe ich geändert...
von Krapao (Gast)


Lesenswert?

von Mr.T (Gast)


Lesenswert?

aaa merci, ihr wart schneller...

Ok, bleibt noch das Problem mit dem Timer und den werten :(. aus dem 1. 
Beitrag.
1
   if (i <= 340)
2
   {  
3
    PORTA &= ~(1<<PA3);             
4
   }
5
   if (i>= 400)
6
   {
7
    PORTA |= (1<<PA3);
8
   }

mit den Werten schalte ich zur zeit bei ~25ms. Wenn ich das aber doch 
berechne, sollten die Werte doch um die 3125 liegen

8000000/64 = 125000 macht 125 Ticks/ms. Ich will bei ~20ms schalten also 
125 Ticks/ms * 25ms = 3125

oder was mache ich da schon wieder falsch...

danke euch :)
von m.n. (Gast)


Lesenswert?

Auf die Schnelle und nicht vollständig:
laß T1 einfach durchlaufen; bei jedem ICP1 Signal berechnest Du als 
uint_16.

{
static uint_16 alte_zeit;
neue_zeit = ICR1;
eff_zeit = neue_zeit - alte_zeit;
alte_zeit = neue_zeit;
}

Die Berechnung funktioniert, solange nicht mehrere Überläufe von T1 
auftreten. Andernfalls müssen sie mitgezählt werden.
Die 'eff_zeit' entspricht der Periodendauer und wird dann irgendwo 
ausgeweret.
von Krapao (Gast)


Lesenswert?

> Das ganze soll einfach ab einer Frequenz X ein Relais ein, und ab einem
> Wert Y wieder aus schalten.

Die Programmlogik dazu ist IMHO verkorkst. Nachdem das Relais aus 
geschaltet wurde, zählt i weiter hoch und läuft irgendwann über. 
Definierst du so den Abstand zum nächsten Einschalten?

Die Berechnung lade ich gerade in den Simulator.
von Mr.T (Gast)


Lesenswert?

Also ich meine, und habe es auch getestet das es funktioniert.

Damit mache ich eine Hysterese, i wird immer aktualisiert wenn an ICP1 
eine Steigende Flanke kommt (kann eigentlich ja nicht hochlaufen). Ich 
möchte einfach Drehzahl abhängig ein Relais schalten, damit das nicht 
"flackert" wenn man sich um den Schaltpunkt befindet gibt es eben diese 
Hysterese.

Das mit dem Timer ist nicht so elegant da ich dann Ticks verliere, das 
setze ich wie m.n. beschrieben hat aber noch um (danke dafür).

Änder aber irgend wie nichts daran, das ich noch Probleme mit dem 
Vorteiler habe :(.
von Krapao (Gast)


Lesenswert?

Der Vorteiler ist richtig eingestellt wenn du 64 haben willst.

Läuft dein Attiny24 sicher mit 9 MHz? Ich würde das mit einem 
timerkontrollierten Blinkprogramm mal überprüfen.

Wenn das erfolgreich ist, würde ich mir das zu messende Signal genauer 
ansehen - wie entsteht es, wie sieht es aus, wie kommt es in den AVR.
von Krapao (Gast)


Lesenswert?

s/9 MHz/8 MHz/
von Mr.T (Gast)


Lesenswert?

Krapao... herzlichsten Dank... verfuster mist :)

CKOUT gesetzt angeschaut 1MHz, was ist das? Int RC Osc. 8MHz... passt 
doch. nur warum ist bei CKDIV8 ein harken :D.

Herzlichen Dank euch beiden, hat meinen Morgen gerettet :D. Und wieder 
einiges schlauer geworden.

lg Malte
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
Noch kein Account? Hier anmelden.