mikrocontroller.net

Forum: Compiler & IDEs timer und prscaler


Autor: Daniela Schröm (idapinky)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
So, da bin ich wieder mit noch dummeren Fragen!!!

Hab jetz versucht einen Timer einzubauen.

Und jetzt kommen die Fragen:

Sitz alles an der richtigen Stelle?

wo setz ich das sei(); richtig?

an der Stelle, an der ich den Prescaler setz muss ich da bei einem 
Prescaler von 1024 auch die CS21 und CS20 "definieren oder setzten oder 
wie man das nennt"?
und wenn ja wie?

Hab ich den  Prescler und Preloader für 10ms im 16bit-timer?

Bitte jeden, der irgendwas dazu weiß zu antworten?

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was soll denn das mit dem
TCCR1 = (1024<<CS22);
?

Welche der CS-Bits gesetzt werden müssen, um einen Prescaler von 1024 
einzustellen, steht in einer Tabelle im Datenblatt. Abgesehen davon ist 
TCCR1 ein 8-Bit-Register, und da passt die Zahl 1024 gar nicht rein, 
erst recht nicht, wenn Du sie auch noch nach links schiebst! Schau Dir 
mal den Artikel zur Bitmanipulation an.

Abgesehen steht der ganze Block mit den Initialisierungen im 
Niemandsland, was nicht zulässig ist! Zuweisungen an Variablen (und dazu 
zählen auch die I/O-Register) dürfen ausschließlich innerhalb von 
Funktionen stehen. Einzige Ausnahme sind Initialisierungen von globalen 
Variablen, die in der selben Zeile deklariert werden.

Das hier:
TCNT1 = 65379.75 
ist, abgesehen von dem fehlenden Semikolon am Ende, Unsinn. TCNT1 kann 
nur ganzzahlige Werte annehmen!

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch das hier:
#ifndef SIGNAL
#   include <avr/signal.h>
#endif
ist Quatsch.

Bitte lies Dir das AVR-GCC-Tutorial gründlich durch. Da sind noch 
einige Dinge, die Du offensichtlich noch nicht wirklich verstanden hast. 
Allerdings auch ein paar C-Grundlagen fehlen, also sollte auch ein 
vernünftiges C-Buch her.

Autor: Daniela (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Muss ganz erlich gestehen ich blicks echt hinten und vorne nich, da habt 
ihr schon recht!

Wenn ich mehr Zeit hätte, würd ich mich auch vorer intensiver damit 
beschäftigen.

muss es "TCNT1 = (1<<CS22)&(1<<CS21)&(1<<CS20);" heißen?
Im Datenblatt steht für 1024 müssen alle drei "1" sein.
Ich les mal noch ein bisschen nach, is wohl besser.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniela wrote:
> da habt ihr schon recht!
          ^^^
"ihr"? Wer ist der andere?

> muss es "TCNT1 = (1<<CS22)&(1<<CS21)&(1<<CS20);" heißen?
Nicht "&"! Es muss "|" sein! Noch mal Bitmanipulation lesen...

> Im Datenblatt steht für 1024 müssen alle drei "1" sein.
Genau. Also hast Du zumindest die Tabelle schon mal gefunden. Weiter so! 
Generell sind die AVR-Datenblätter eigentlich ziemlich übersichtlich, 
und meist gibt es ebenso übersichtliche Tabellen, in denen die 
Steuerbits stehen. Das meiste von den wirklich wichtigen Dingen kann man 
jeweils aus dem Abschnitt "Register Description" entnehmen, indem man 
einfach die dort beschriebenen Steuerregister der Reihe nach durchgeht 
und aussortiert, welche Bits man überhaupt nicht braucht und welche 
entsprechend gesetzt werden müssen.

> Ich les mal noch ein bisschen nach, is wohl besser.
Gut.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, es sitzt leider gar nichts an der richtigen Stelle.

Noch mal zurück zu der ersten geänderten Version und dann die Änderungen 
einbauen für den Timer1 und zwar aus dem Code vom Countdownzähler 
(http://www.gjlay.de/pub/c-code/countdown.html). Dabei die 
Moderinisierung von SIGNAL zu ISR aus der avr-libc berücksichtigen.

Die Idee von Georg ist:

Man gibt vor, wieviele IRQs pro Sekunde kommen sollen. Z.B. willkürlich 
5000, um eine gute Zeitauflösung zu haben. So stellt man auch seinen 
Timer1 ein. Die Einstellung ist von der Taktrate (F_CPU) abhängig. Mit 
dem 16-Bit Timer und 5000 gewünschten IRQs/s kann man alle bei AVR 
möglichen MHz Taktraten abdecken. Bei anderen Werten muss man 
nachrechnen, ob man bei 16-Bit (OCR1A ) oder 8-Bit (interrupt_num_10ms) 
Ganzzahlüberläufe bekommt.

Dann weiss man auch wieviele IRQs in 10ms kommen (1/100-stel vom 1s 
Wert, hier 50). Man zählt die IRQs mit und wenn die Anzahl dem Wert bei 
10ms entspricht, ruft man die Arbeitsfunktion auf, die alle 10ms laufen 
muss.

Hätte man mehrere Arbeitsfunktionen, sollte man die etwas verteilen. Es 
werden die nicht alle bei exakt bei dem "Uhrstand" 10ms, 20ms, 30ms 
auferufen, sondern versetzt zueinander. Also z.B.

Arbeitsroutine 1 bei 10ms, 20ms, 30ms...
Arbeitsroutine 2 bei 10ms+1IRQ, 20ms+1IRQ, 30ms+1IRQ...
Arbeitsroutine 3 bei 10ms+2IRQ, 20ms+2IRQ, 30ms+2IRQ...
...

#include <avr/io.h>
#include <avr/interrupt.h>
#include "dcf.h"

#ifndef F_CPU
#define F_CPU 1000000
#endif

#define IRQS_PER_SECOND     5000
#define IRQS_PER_10MS       (IRQS_PER_SECOND / 100)

// Merkt alle 10 Millisekunden den Portzustand des DCF-Ports
unsigned char volatile dcf_bit = 0xff;
static void job_dcf_10ms(void);

ISR(TIMER1_COMPA_vect)
{
    static uint8_t interrupt_num_10ms;
    uint8_t irq_num = interrupt_num_10ms;

    // interrupt_num_10ms erhöhen und mit 
    // Maximalwert vergleichen
    if (++irq_num == IRQS_PER_10MS)
    {
        // 10 Millisekunden sind vorbei
        // interrupt_num_10ms zurücksetzen
        irq_num = 0;
    }

    if (irq_num == 0)       
      job_dcf_10ms();

    // hier ggf. andere Arbeitsroutinen
    // if (irq_num == 1)       
    //   job_1();
    // if (irq_num == 2)       
    //   job_2();
    // ...

    interrupt_num_10ms = irq_num;
}

void timer1_init (void)
{
    // PoutputCompare für gewünschte Timer1 IRQ-Rate
    OCR1A = (unsigned short) ((unsigned long) F_CPU / IRQS_PER_SECOND-1);

    // Timer1 ist Zähler: Clear Timer on Compare Match (CTC, Mode #4)
    // Timer1 läuft @ F_CPU: prescale = 1
    TCCR1A = 0;
    TCCR1B = (1 << WGM12) | (1 << CS10);

    // OutputCompare-Interrupt A für Timer1
    TIMSK = (1 << OCIE1A);
}

// Alle 10 Millisekunden aufrufen!
// Macht alle 10ms einen Schnappschuss vom DCF-Port (hier an Port B1).
static void job_dcf_10ms(void)
{
  unsigned char bit = 0;

  if (PIND & (1 << PD2))
    bit = 1;

  dcf_bit = bit;
}

int main(void)
{
  timer1_init();  // Timer1 für 10ms Ticken einrichten
  sei();          // Interrupts global enablen, d.h. Timer1 starten

  while (1)
  {
    unsigned char bit = dcf_bit;

    // Sind 10ms vergangen (also dcf_bit in {0,1}?)
    if (bit < 2)
    {
      // Ja:
      // Schnappschuss zuruecksetzen
      dcf_bit = 0xff;

      // Die Zeit tickt 10ms weiter
      time_tick_10ms (& timeinfo, bit);

      // Hier Restcode der Übersichtlichkeit wegen abgeschnitten...
    }
  } // Hauptschleife

  return 0;
} // main


Autor: Daniela (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab die Bitmanipulation glesen, und hab in der zwischenzeit auch 
rausgefunden, dass es | und nicht & heißen müsste. Nächstes mal les ich 
erst und dann frag ich.

Auf die wirre Zahl des Preloaders bin ich durch ne Rechnung gekommen die 
ich online gefunden hab!

Schade, ich war so stolz auf mich, weil ich dachte ich hät´s halbwegs 
selbst gelöst.

Und ganz großen dank für das Program und die spitzen Erklärung dazu!
Ich hatte auch zuerst versucht es auf diesem Weg zu machen, aber dann 
bin ich auf das andere gestoßen und es hat so einfach ausgesehen. Aber 
wie man sieht konnt ich´s trotzdem nicht.

Und nochmal DANKE

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Daniela wrote:

> Schade, ich war so stolz auf mich, weil ich dachte ich hät´s halbwegs
> selbst gelöst.

Deine Idee (möglichst wenige - ideal ein - IRQ exakt zum richtigen 
Zeitpunkt bei 10ms) ist ja nicht verkehrt, nur an der Ausführung hapert 
es.

Wenn du beachtest, dass die Timer mit Ganzzahlen arbeiten und wenn du 
dich weiter in das Thema einliest (z.B. mit [[AVR - Die genaue Sekunde / 
RTC]] und Datenblatt vom AVR), kannst du deinen Weg immer noch 
schaffen.

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.