www.mikrocontroller.net

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


Autor: A. L. (vantage)
Datum:

Bewertung
0 lesenswert
nicht 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
//
// *** ATTiny13A with 1.2 MHz as shipped ***
//
#define F_CPU 1200000UL 

#include <util/delay.h>
#include <avr/power.h>
#include <avr/interrupt.h>
#define SEQ_DELAY 5000  

int main (void)
{

// set PB0 as output port
DDRB |= (1 << PB0);

//set CTC Mode
TCCR0A |= (1 << WGM01); 
 
// set Timer/Counter0 Output Compare Match A Interrupt Enable
TIMSK0 |= (1 << OCIE0A); 

sei();
 
   for (;;)
   {
   //  set prescaler to 256
   TCCR0B |= (1 << CS02);   

   OCR0A   = 180;
   _delay_ms(SEQ_DELAY);


   //  set prescaler to 64
   TCCR0B |= (1 << CS00);   
   TCCR0B |= (1 << CS01); 

   OCR0A   = 93;  
   _delay_ms(SEQ_DELAY);
  }
}
 
ISR(TIM0_COMPA_vect)
{
  // create a single pulse with 1 ms duration
  PORTB |= (1<< PINB0);
  _delay_ms(1);
  PORTB &= ~(1<< PINB0);
  
  // Enable Interrupts again
  SREG |= (1 << 7);
}
 
 


Autor: JW (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Adrian,

und wer löscht CS2 ??

probier mal
  //  set prescaler to 256
   TCCR0B = (1 << CS02);   

   OCR0A   = 180;
   _delay_ms(SEQ_DELAY);


   //  set prescaler to 64
   TCCR0B =   (1 << CS00)
            | (1 << CS01); 

Gruß,
Jürgen

Autor: Gastofatz (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: A. L. (vantage)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Gastofatz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>ich hab bisher der Einfachheit halber auf eine Softwareteilung verzichtet

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

Autor: A. L. (vantage)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ähm
ISR(TIM0_COMPA_vect)
{
  // create a single pulse with 1 ms duration
  PORTB |= (1<< PINB0);
  _delay_ms(1);
  PORTB &= ~(1<< PINB0);
  
  // Enable Interrupts again
  SREG |= (1 << 7);
}
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:
  // Enable Interrupts again
  SREG |= (1 << 7);
}
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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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)

Autor: A. L. (vantage)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Gastofatz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Folgender Codeschnipsel möge das Prinzip der Softwareteilung 
verdeutlichen:
    t = t + 1;

    IF (t==n)
      {
      t = 0;
      a = ~a;
      <Portpin gemaess a auf L oder H setzen>
      }

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

Autor: A. L. (vantage)
Datum:

Bewertung
0 lesenswert
nicht 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 :)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.