Forum: Mikrocontroller und Digitale Elektronik ATtiny13A, TCCR0B Prescaler für Timer in main() mehfach ändern?


von A. L. (vantage)


Lesenswert?

Hallo,

für das generieren von mehreren festen Testfrequenzen (25 Hz, 50 Hz, 100 
Hz...) über einen ATtiny13A muss ich den Prescaler bemühen, damit ich 
möglichst nah an der Zielfrequenz dran bin.

Leider funktioniert das neu setzen des Prescalers in TCCR0B  innerhalb 
von einer Schleife in main() nicht, wie erhofft; der erste Counter läuft 
wie erwartet, ab der nächsten Änderung (im Code unten setzen des 
Prescalers auf 64) sind die Ergebnisse nicht mehr determinierbar.
Ich vermute, das ich irgendeine Initialisierungsreihenfolge übersehen 
habe, habt Ihr dazu einen Tip? Prescaler Artefacts sind für eine 
Frequenzerzeugung wie unten kein echtes Problem, da sie nur den ersten 
Durchlauf von OCR0A betreffen, korrekt?

Danke,
Adrian
1
//
2
// *** ATTiny13A with 1.2 MHz as shipped ***
3
//
4
#define F_CPU 1200000UL 
5
6
#include <util/delay.h>
7
#include <avr/power.h>
8
#include <avr/interrupt.h>
9
#define SEQ_DELAY 5000  
10
11
int main (void)
12
{
13
14
// set PB0 as output port
15
DDRB |= (1 << PB0);
16
17
//set CTC Mode
18
TCCR0A |= (1 << WGM01); 
19
 
20
// set Timer/Counter0 Output Compare Match A Interrupt Enable
21
TIMSK0 |= (1 << OCIE0A); 
22
23
sei();
24
 
25
   for (;;)
26
   {
27
   //  set prescaler to 256
28
   TCCR0B |= (1 << CS02);   
29
30
   OCR0A   = 180;
31
   _delay_ms(SEQ_DELAY);
32
33
34
   //  set prescaler to 64
35
   TCCR0B |= (1 << CS00);   
36
   TCCR0B |= (1 << CS01); 
37
38
   OCR0A   = 93;  
39
   _delay_ms(SEQ_DELAY);
40
  }
41
}
42
 
43
ISR(TIM0_COMPA_vect)
44
{
45
  // create a single pulse with 1 ms duration
46
  PORTB |= (1<< PINB0);
47
  _delay_ms(1);
48
  PORTB &= ~(1<< PINB0);
49
  
50
  // Enable Interrupts again
51
  SREG |= (1 << 7);
52
}

von JW (Gast)


Lesenswert?

Hallo Adrian,

und wer löscht CS2 ??

probier mal
1
  //  set prescaler to 256
2
   TCCR0B = (1 << CS02);   
3
4
   OCR0A   = 180;
5
   _delay_ms(SEQ_DELAY);
6
7
8
   //  set prescaler to 64
9
   TCCR0B =   (1 << CS00)
10
            | (1 << CS01);

Gruß,
Jürgen

von Gastofatz (Gast)


Lesenswert?

>für das generieren von mehreren festen Testfrequenzen (25 Hz, 50 Hz, 100
>Hz...) über einen ATtiny13A muss ich den Prescaler bemühen, damit ich
>möglichst nah an der Zielfrequenz dran bin.

Versteh ich nicht. 1000 Hz kannst Du genau [*] generieren (Timer Mode = 
CTC, Prescaler = 8, OC-Wert = 150 bzw. 75) und aus 1000 Hz kannst Du 500 
Hz, 250 Hz, 200 Hz, 125 Hz, 100 Hz, 50 Hz, 40 Hz, 25 Hz, 20 Hz, 10 Hz 
und noch viele andere Frequenzen problemlos per Softwareteilung 
ableiten.

[*] Wobei "genau" bei Verwendung des internen RC-Oszillators als 
Taktquelle relativ ist.

von A. L. (vantage)


Lesenswert?

Jürgen, vielen Dank! Peinlicher Fehler, alle drei Bits gesetzt ist nicht 
dokumentiert, kein Wunder daß das nicht funktioniert.

Gastofatz, ich hab bisher der Einfachheit halber auf eine 
Softwareteilung verzichtet. Bis zu 2-3% Fehlerrate reicht bei meiner 
Anwendung, und das bekomme ich mit zwei Teilern (64 und 256) problemlos 
hin.  Mit dem internen RC Oszillator schwankt die Ausgabe bei 
Zimmertemperatur um 0.3-0.5%, da kann ich auch gut mit leben.

Vielen Dank für die Unterstützung,
Adrian

von Gastofatz (Gast)


Lesenswert?

>ich hab bisher der Einfachheit halber auf eine Softwareteilung verzichtet

Ich find die Softwareteilung ja viel einfacher, aber jeder wie er mag 
:-)

von A. L. (vantage)


Lesenswert?

Dann habe ich den falschen Ansatz im Kopf, erklär mal bitte kurz den 
Ansatz. Ich fand den CTC Timer schon recht einfach, aber wenn es noch 
einfacher geht... ;)

Danke!

von Karl H. (kbuchegg)


Lesenswert?

Ähm
1
ISR(TIM0_COMPA_vect)
2
{
3
  // create a single pulse with 1 ms duration
4
  PORTB |= (1<< PINB0);
5
  _delay_ms(1);
6
  PORTB &= ~(1<< PINB0);
7
  
8
  // Enable Interrupts again
9
  SREG |= (1 << 7);
10
}
Der delay da drinnen ist jetzt aber nicht dein Ernst. Oder?
Was glaubst du, wie das die 'Genauigkeit' deines
   _delay_ms(SEQ_DELAY);
in der Hauptschleife beeinflussen wird :-)

Grrrr:
1
  // Enable Interrupts again
2
  SREG |= (1 << 7);
3
}
Lass das Interrupt Flag im SREG in Ruhe!
Interrupts sind in einer ISR automatisch ausgeschaltet und werden nach 
Beeindigung der ISR automatisch wieder eingeschaltet. Mit deiner Aktion 
da oben bettelst du praktisch um Schwierigkeiten.

von Karl H. (kbuchegg)


Lesenswert?

A. L. schrieb:
> Dann habe ich den falschen Ansatz im Kopf, erklär mal bitte kurz den
> Ansatz. Ich fand den CTC Timer schon recht einfach, aber wenn es noch
> einfacher geht... ;)
>

Dazu müsste man erst mal genau wissen, was eigentlich das Ziel ist. 
Willst du hintereinander an einem Pin 2 verschiedene Frequenzen jeweils 
eine bestimmte Zeitdauer ausgeben? (zumindest sieht es so aus)

von A. L. (vantage)


Lesenswert?

Nebenschauplatz, ist auch nicht mein Ernst, wie Du schon erraten hat :) 
Danke für den SREG Tip, ich war der Annahme, daß ich am Ende der ISR die 
Interrupts wieder aktivieren muss.

SEQ_DELAY soll die jeweils aktuelle Frequenz ein paar Sekunden für die 
Ansicht am Scope ausgeben. Das Programm oben ist nur ein schnell 
reingehackter Test der Idee, in ein Tachoadapter Projekt noch eine 
Kalibrierfunktion für den Tacho mit einzubauen.

von Gastofatz (Gast)


Lesenswert?

Folgender Codeschnipsel möge das Prinzip der Softwareteilung 
verdeutlichen:
1
    t = t + 1;
2
3
    IF (t==n)
4
      {
5
      t = 0;
6
      a = ~a;
7
      <Portpin gemaess a auf L oder H setzen>
8
      }

Diese Routine rufst Du in Deinem Fall 2000 mal pro Sekunde auf. Um die 
Toggle-Frequenz f des Portpins zu ändern, musst Du nur den Wert von n 
passend setzen:

n = 1    -->  f = 1000 Hz
n = 2    -->  f = 500 Hz
n = 4    -->  f = 250 Hz
n = 5    -->  f = 200 Hz
n = 10   -->  f = 100 Hz
n = 20   -->  f = 50 Hz
n = 40   -->  f = 25 Hz
n = 50   -->  f = 20 Hz
n = 100  -->  f = 10 Hz
n = 200  -->  f = 5 Hz

von A. L. (vantage)


Lesenswert?

Danke für die Erklärung, ich rechne am Wochenende mal durch, mit welchen 
Hardware/Softwareteilern ich am besten auf meine Zielfrequenzen komme. 
Und bringe den Code mal in eine saubere Form, damit Karl Heinz keine 
Zustände bekommt :)

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.