Forum: Mikrocontroller und Digitale Elektronik Timer Zeit Rechnung geht nicht auf


von Haburt (Gast)


Angehängte Dateien:

Lesenswert?

Guten Abend,

Vor mir liegt ein AtTiny84 dessen Timer0 ich im CTC-Mode Betreibe, 
konfiguriert wie im Bild zusehen.

Auf der Skizze links oben sieht man, dass ein Durchlauf des Timer 
(0...19)
mit 200 Hz vonstatten geht, also 0,005 s braucht.
Demzufolge müssten 200 Durchläufe des Timers doch ca. 1 s dauern, tun 
sie aber nicht... viel eher 2000 Durchläufe, wo liegt den mein Fehler?

Hier noch schnell der Code, bei dem durch das Setzen der Pins eine LED 
theoretisch jede Sekunde zum leuchten gebracht werden sollte...
1
void count()
2
{
3
  if(TCNT0==19)
4
  {
5
      counter++;
6
  }
7
  if(counter==200)
8
  {
9
   PORTA &= (~(1<<PA0));
10
   PORTA |= (1<<PA6);
11
   _delay_ms(10);
12
   clearLEDs();
13
   counter = 0; 
14
  }

von ich, nicht du (Gast)


Lesenswert?

also, dann fangen wir mal an:

1) 1 mHz / 256 = 4 kHz

ist schonmal komplett falsch berechnet.
- erstens ist 1 milli-herz wohl falsch, nehme ich an denn du meinst 
sicherlich 1 MHz also ein megaherz
- zweitens ist 1000000 / 256 nich 4000 sondern 3906,25 also nur 3,90625 
kHz

2) solltest du angaben zur verwendeten chip-clock quelle und dem 
gesetzten system prescaler machen. wenn der nämlich auf div 8 gesetzt 
ist mit einem 1 Mhz kristall erklärt das wohl dein problem.

3) es fehlt der code abschnitt in dem du die register für den timer 
setzt, wenn da der fehler drin sein sollte können wir hier lange raten

4) wozu steht da ein delay im code?

von Karl H. (kbuchegg)


Lesenswert?

5) wenn du CTC Modus benutzt, wofür es keinen Beweis gibt ausser deinem 
Wort, wozu machst du das zählen dann so? Dafür gibt es einen Interrupt, 
damit man nicht auf irgendwelche dubiose Vergleiche mit dem TCNTx 
Register angewiesen ist, denn das macht dann die Hardware. Und die 
übersieht keinen einzigen Gleichstand, was man von einem Programm nicht 
unbedingt sagen kann. Hängt das Programm irgendwo ein wenig länger und 
wird count() nicht rechtzeitig aufgerufen, dann geht dir ein Zählerstand 
von 19 verloren und wird nicht gezählt.

FAQ: Timer

Keine Angst vor Interrupts! Das geht einfacher als du denkst.

: Bearbeitet durch User
von Haburt (Gast)


Lesenswert?

1
#include<avr/io.h>
2
#include <util/delay.h>
3
int counter;
4
5
void setup(){
6
  DDRA=0xFF;
7
  DDRB=0xFF;
8
  TCCR0A = (1 << WGM01);
9
  TCCR0B = (1 << CS02);
10
  OCR0A = 19;
11
  clearLEDs();
12
  
13
}
14
15
void loop()
16
{
17
count();
18
}
19
20
void count()
21
{
22
  if(TCNT0==19)
23
  {
24
      counter++;
25
  }
26
  if(counter==1600)
27
  {
28
   PORTA &= (~(1<<PA0));
29
   PORTA |= (1<<PA6);
30
   _delay_ms(10);
31
   clearLEDs();
32
   counter = 0; 
33
  }
34
}
35
36
37
void clearLEDs()
38
{
39
   PORTA |= (1<<PA0)|(1<<PA1)|(1<<PA2);
40
   PORTA &= ~( (1<<PA6) | (1<<PA7) );
41
   PORTB &= (~(1<<PB2));
42
}

Der Delay ist da um das Aufleuchten der LED zu sehen.

Der Plan ist später eine LED-Matrix anzusteuern, bisher 3x3.
Jede LED leuchtet für 2 der 20 Zählschritte auf, mit Interrupts müsst 
ich ja den Timer bis bis 2 Zählen lassen und die Interrupts mindestenz 9 
mal zählen lassen.

Mir ist bewusst dass es bessere Wege gibt, z.B. Iterrieren einer Seite, 
aber für Lernzwecke möchte ich es zunächst so betreiben.

von Karl H. (kbuchegg)


Lesenswert?

Haburt schrieb:

> Der Delay ist da um das Aufleuchten der LED zu sehen.

Dann schalte halt ganz einfach die LED um, anstatt sie bei jedem 
Gleichstand ein/aus zu schalten.
1
...
2
3
  if( count == 1600 )
4
    PORTA ^= ( 1 << PA0 );
5
...

dann siehst du deine LED im 1 Sekundentakt blinken.


> Der Plan ist später eine LED-Matrix anzusteuern

spätestens jetzt muss ich dir sagen:

Interrupts, Interrupts, Interrupts.

Alles andere ist Unsinn. Wer eine Matrix, bzw. generell Multiplexing, 
ohne Timer-Interrupt macht, hat etwas ganz wesentliches nicht begriffen.

> Jede LED leuchtet für 2 der 20 Zählschritte auf, mit Interrupts müsst
> ich ja den Timer bis bis 2 Zählen lassen und die Interrupts mindestenz 9
> mal zählen lassen.

Nö.

In einem Interrupt Aufruf wird eine komplette Zeile der Matrix 
eingeschaltet. Die leuchtet dann so lange, bis der nächste Interrupt 
kommt. Dann wird auf die nächste Zeile weiter geschaltet. D.h. bei einer 
3*3 Matrix sieht die Interrupt Routine so aus
1
ISR( ... )
2
{
3
  aktuelle Zeile abschalten
4
5
  Zeilenummer++;
6
  if( Zeilennummer == 3 )
7
    Zeilennummer = 0;
8
9
  Led_Muster für die Zeile 'Zeilennummer' ausgeben
10
11
  Zeile 'Zeilennummer' aktivieren
12
}

da wird nirgends gewartet.

So wird das gemacht und genau so funktioniert das auch zuverlässig.

Die Technik mit: Ich lasse je nach Bedarf eine LED nach der anderen 
leuchten, ist nicht vernünftig. Das mag bei einer 3*3 Matrix gerade noch 
so funktionieren, aber bei einer nur ein bischen größeren Matrix versagt 
das kläglich. Also mach es gleich richtig und lern, wie man das richtig 
macht.

> Mir ist bewusst dass es bessere Wege gibt, z.B. Iterrieren einer Seite,
> aber für Lernzwecke möchte ich es zunächst so betreiben.

Genau darum geht es. Deine Lernzwecke führen dich jetzt genau in die 
Richtung, wie man eine Matrix-Ansteuerung NICHT macht.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

>
1
> ISR( ... )
2
> {
3
>

ach, entschuldigung.
Das ist ja offenbar Arduino Code. Da ist die Syntax ein bischen anders, 
wenn man es nach den Arduino Regeln macht.
Ändert aber nichts am Prinzip.

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.