ATmega168A Counter streikt bei Frequenz > 41kHz

Gast #3301353
Lesenswert?

Hallo,

ich hab ein kleines Problem mit dem Conuter eines ATmega 168A-PU.

Die Clocksource des Timer0 wurde auf Extern und fallende Flanke 
eingestellt. Damit sollen die von einem Encoder produzierten Flanken 
detektiert werden.
Timer2 stellt den Zeitbezug her um auf eine Drehzahl schließen zu 
können.

Prinziepiell funktioniert das auch. Allerdings nur solange der Motor 
nicht mit "Vollgas" fährt.

Sobal die Encoderpulsfrequenz einen Grenzwert (ca 41kHz) überschreitet 
verweigert der Counter vollständig seinen Dienst. Die über die 
Serielleschnittstelle eingelesenen Variablen bleiben 0.
Unterhalb der genannten Frequenz liefert der Counter zwar Werte, 
allerdings sehen diese eher nach einer Alias-Frequenz aus. Das heisst 
bei geringerer Geschwindigkeit zählt der Counter mehr Pulse als bei 
höheren.

Soweit ich das im Datenblatt nachlesen konnte sollte die Grenzfrequenz 
bei dem 1/2,5 fachen des CPU-Taktes liegen. Da die CPU über einen 
externen Quarz mit 20MHz läuft, kann ich da kein Problem erkennen. Und 
auch bei 8MHz wären 42kHz auch noch unter dem geforderten Wert.

Deshalb verstehe ich nicht wirklich wo das Problem liegt. Hat jemand 
dazu eine Idee?

Quelltext(Auszug):
1
#define EXTCLK_FALING_EDGE    0x06
2
#define TIMER0_OVINT_ENABLED    TIMSK0 |= (1<<TOIE0)
3
#define TIMER2_OVINT_ENABLED    TIMSK2 |= (1<<TOIE2)
4
#define START_TIMER0      TCCR0B  = EXTCLK_FALING_EDGE
5
#define START_TIMER2      TCCR2B  = 0x07  
6

7
int main(void)
8
{
9
  setup(); //ruft unter Anderem timer() und counter() auf.
10
  OVERFLOW=0;
11
  OVERFLOW2=0;
12

13
    while(1)
14
    {
15
      sei();
16
    }
17
}
18

19
void timer()
20
{
21
  START_TIMER2;       
22
TIMER2_OVINT_ENABLED;            
23
}
24

25
void counter()
26
{
27
  START_TIMER0;  
28
TIMER0_OVINT_ENABLED;
29
}
30

31

32
ISR(TIMER0_OVF_vect)
33
{
34
  cli();
35
  overflow_flag++;
36
  if (overflow_flag==255)
37
  {
38
    overflow2_flag=1;
39
    overflow_flag=0;
40
  }
41
}
42

43
ISR(TIMER2_OVF_vect)
44
{
45
  cli();
46
  TICK_COUNT=TCNT0;
47
  tick_sum=tick_sum+TICK_COUNT;
48
  OVERFLOW=overflow_flag;
49
  OVERFLOW2=overflow2_flag;
50
  overflow_flag=0;
51
  overflow2_flag=0;
52
}

Der gesamte Quelltext ist etwas zu umfangreich um ihn hier einzustellen. 
(380 Zeilen + Header) Daher nur ein Auszug.

Um feinheiten, wie exakte Werte durch stoppen und wieder starten der 
Timer und den genauen Prescaler des Timer2 habe ich mich noch nicht 
gekümmert. Ich wollte erst einmal einen prinziepiell funktionierenden 
Code.
#3301373
Lesenswert?

Matthias schrieb:
> Der gesamte Quelltext ist etwas zu umfangreich um ihn hier einzustellen.

Dann häng ihn eben an.

Schnipsel bringen garnichts.
Es werden eh nur immer die Schnipsel gepostet, an denen es garantiert 
nicht liegt.
Oder die nichtmal dem Original entsprechen!

Und ja, man darf auch eigene Programme mit Kommentaren versehen, die die 
Funktion beschreiben.
Nicht jeder kann in Deinen Kopf schauen.
Und Du hast nach einem Jahr vieles vergessen.
Gast #3301381
Lesenswert?

Das wäre der Wert für die Frequenzmessung, den ich ebenfalls (in etwa) 
erwartet hätte.

Das cli(); steht da um eine Rekursivität auszuschlißen.
Da das ganze Programm über ISRs läuft war es zumindest denkbar das es zu 
einem Stackoverflow kommt und so die seltsamen Werte produziert werden.

Deshalb werden erst nach beenden einer ISR mit sei(); die Interrups 
wieder freigegeben.
Gast #3301587
Lesenswert?

Peter Dannegger schrieb:
> Lies Dir nochmal im Datenblatt den Abschnitt Interrupthandling in Ruhe
> durch.

Eventuell habe ich mich etwas undeutlich ausgedrückt.

Sei und Cli wurden erst eingefügt, nachdem ich merkte, dass Etwas nicht 
stimmen kann. --> Ausschlussverfahren. Ich habe lieber eine, oder zwei 
Assembleranweisungen zuviel im Code stehen als mir nicht 100% sicher zu 
sein, dass es nicht doch daran liegen könnte.

Falls das ein Hinweis auf einen Fehler sein sollte kann ich ihn nicht 
erkennen. Anderenfalls verstehe ich nicht, was es mit dem eigentlichen 
Problem zu tun hat.
Gast #3301598
Lesenswert?

Matthias schrieb:
> Anderenfalls verstehe ich nicht, was es mit dem eigentlichen
> Problem zu tun hat.

Da wir nur deinen Quellcode(Auszug) kennen, sind vermutlich noch viel 
mehr Maden im Speck.

Matthias schrieb:
> Der gesamte Quelltext ist etwas zu umfangreich um ihn hier einzustellen.
> (380 Zeilen + Header) Daher nur ein Auszug.

Nur 380 Zeilen? Da hast du vermutlich die ganzen Initialisierungen 
vergessen?
Als Dateianhang fällt das nicht ins Gewicht.
#3301639
Lesenswert?

Matthias schrieb:
> Sei und Cli wurden erst eingefügt, nachdem ich merkte, dass Etwas nicht
> stimmen kann.

Dann hast Du gemerkt, daran liegt es nicht, aber uns kannst Du die Gurke 
ja ruhig andrehen?

Es gehört sich einfach nicht, überflüssigen Schrunz, der nichts mit dem 
Problem zu tun hat, im Code drin zu lassen.
Damit schafft man sich keine Freunde.

Man sieht es leider oft, daß bei Problemen man irgendwas verwurschteltes 
mit allen möglichen Trial&Error Codefragmenten unkommentiert vorgesetzt 
kriegt.
Ich gebe Dir mein Wort, das hebt in keinster Weise die Motivation, zu 
helfen.

Poste die erste Version, wo der Fehler zuerst aufgetreten ist und 
kommentiere, welche Funktion Du von welchem Code erwartest.
Gast #3301715
Lesenswert?

Okay, entschuldigung.

Hier der Code in der Ursprünglichen Fassung:
1
#define F_CPU 20000000UL
2

3

4
#define EXTCLK_FALING_EDGE      0x06
5
#define TIMER0_OVINT_ENABLED    TIMSK0 |= (1<<TOIE0)
6
#define TIMER2_OVINT_ENABLED    TIMSK2 |= (1<<TOIE2)
7
#define START_TIMER0            TCCR0B  = EXTCLK_FALING_EDGE
8
#define START_TIMER2            TCCR2B  = 0x07  
9
#define TICK_COUNT              data
10
#define OVERFLOW                data0
11

12
#include <avr/io.h>
13
#include <avr/interrupt.h>
14

15
volatile uint8_t data=0,data0=0,overflow_flag=0;
16

17
int main(void)
18
{
19
  setup(); //ruft unter Anderem timer() und counter() auf.
20
    while(1) //Warte auf die ISRs
21
    {
22
    }
23
}
24

25
void timer()
26
{
27
  START_TIMER2;    //Prescaler 1024 entspricht ca 52ms Messzeit    
28
  TIMER2_OVINT_ENABLED;      //Gibt den Timer Overfl-IR frei      
29
}
30

31
void counter()
32
{
33
  START_TIMER0;  //Setze Clock auf extern fallende Flanke
34
  TIMER0_OVINT_ENABLED; //Gibt den Timer Overfl-IR frei 
35
}
36

37

38
// Timer 0 Zählt die vom Encoder ausgegebenen Pulse bis Timer 2 //"überläuft" 
39
ISR(TIMER0_OVF_vect)
40
{
41
  overflow_flag++; //Zeigt wie oft der Timer0 übergelaufen ist
42
}
43

44
ISR(TIMER2_OVF_vect)
45
{
46
  TICK_COUNT=TCNT0; //Schreibt den Wert des Counters in eine Variable
47
  OVERFLOW=overflow_flag; //Gibt an wie oft der Timer0 überlief
48
  overflow_flag=0;  //Flag zurücksetzen
49

50
}

So sollten alle 52ms die bis dahin gezählten Pulse übergeben werden, um 
die Drehzahl zu ermitteln.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren