Forum: Compiler & IDEs ATmega32 mit Timer0 als Basetime


von Corinna (Gast)


Lesenswert?

Hallo,

versuche den Timer 0 im CTC mode zu betreiben.
Folgendes Problem: Die globale Variable uiTimer0High wird im 1ms-Takt
inkrementiert und soll später alle 500ms eine Aktion initiieren. Weil
nichts geht prüfe ich erst mal das MSB ab um zu sehen, ob sie
hochzaehlt, was sie aber nicht macht. Sie wäre ein guter
Zufallsgenerator, aber zaehlt nicht vernünftig hoch? Auf anderen
Controllern läuft sowas, wieso nicht bei Atmels????
Port B0 kommt jede ms ein Puls!

volatile uint16_t uiTimer0High;

INTERRUPT(SIG_OUTPUT_COMPARE0);
void SIG_OUTPUT_COMPARE0(void)
{
  PORTB |=  _BV(PB0);
  uiTimer0High += 1;
  PORTB &= ~_BV(PB0);
}

int main (void)
{
  uint16_t i, u16Time;

  WDTCR = ((1<<WDTOE) | (1<<WDE));
  WDTCR = 0x00;
  OCR0  = 19;             // 20MHz  1024  195,315) = 1000 Hz
  TCCR0 = ( (0<<FOC0)
          | (1<<WGM01) | (0<<WGM00)
          | (0<<COM01) | (0<<COM00)
          | (1<<CS02)  | (0<<CS01)  | (1<<CS00) );

  while(1)
  {
    /*Reinit Controller-Registers*/
    TIMSK  = _BV (OCIE0); // Timer0 = Bastime

    cli();
    // read actual time
    u16Time = uiTimer0High;
    sei();

    if (u16Time & 0x8000)
      PORTB |=  _BV(PB1);
    else
      PORTB &= ~_BV(PB1);
  }
}

von Andreas W. (Gast)


Lesenswert?

Hab jetzt nur mal schnell drüber geschaut, aber:
Wo wird der WatchDog resettet?
Der Puls soll nach 33s kommen (1ms * 32768)?

von johnny.m (Gast)


Lesenswert?

@Andreas:
Nö, das hier
> WDTCR = ((1<<WDTOE) | (1<<WDE));
> WDTCR = 0x00;
schaltet den WDT aus. Dann muss er auch nicht geresettet werden.

von johnny.m (Gast)


Lesenswert?

> INTERRUPT(SIG_OUTPUT_COMPARE0);
> void SIG_OUTPUT_COMPARE0(void)...

Was ist das denn???

von johnny.m (Gast)


Lesenswert?

Lass mich raten: Der Compiler gibt Dir ne Warnung aus, dass die Funktion
SIG_OUTPUT_COMPARE0 nie aufgerufen wird?!? Außerdem arbeitest Du
anscheinend mit einer veralteten AVR-libc-Version. INTERRUPT ist
jedenfalls nicht mehr aktuell und war auch früher (als die libc-Version
noch 'in' war) mit größter Vorsicht zu genießen. Wenn Du keine
Update-Möglichkeit hast, dann benutze bitte SIGNAL anstelle von
INTERRUPT. Darüberhinaus ist Deine ISR leer
('INTERRUPT(SIG_OUTPUT_COMPARE0);'), was dazu führt, dass überhaupt
nix gemacht wird, soll heißen, Deine Variable dürfte sich gar nicht
ändern. Was die Zeile darunter soll, weißt wohl nur Du selber...

von Corinna (Gast)


Lesenswert?

Ob die ISR-Routine korrekt ist, ist sicher fragwürdig, aber wieso kommt
dann der Port B0 so regelmässig im 1-ms-Takt ?

von Karl heinz B. (kbucheg)


Lesenswert?

mal ne ganz banale Frage:
Arbeitest du überhaupt mit AVR-GCC ?

von Corinna (Gast)


Lesenswert?

Ich hab mal die die ISR so aufgerufen:

INTERRUPT(SIG_OUTPUT_COMPARE0)
{
  ...
}

Fehler tritt aber wie gehabt auf!
Das Schlüsselwort SIGNAL hab ich noch nie benutzt, werde es aber gleich
mal testen...
Was soll den mit INTERRUPT(..) nicht funktionieren?

von Corinna (Gast)


Lesenswert?

@ Karl Heinz: Ja, hab WinAVR GCC 3.4.1 (war wohl der grösste Fehler den
ich machen konnte) :-(

von Corinna (Gast)


Lesenswert?

Wie würdet ihr denn die paar Zeilen Code schreiben?
Dann kann ich mal eure Ideen testen.

von Karl heinz B. (kbucheg)


Lesenswert?

Als aller erstes holst du dir mal einen neuen
Compiler.
Die aktuelle Version ist 4.irgendwas

von johnny.m (Gast)


Lesenswert?

INTERRUPT leitet eine unterbrechbare ISR ein. So etwas sollte man nur
dann verwenden, wenn man 100%ig sicher ist, was man tut. Ich würde vor
allem die Erzeugung dieser kurzen Impulse in der ISR bleiben lassen und
den Pin einfach jeweils toggeln. Das gibt ein sauberes Signal und nicht
irgendwas, das jede ms für ein paar 100ns auf High-Pegel geht.
Zumindest an den Initialisierungen kann ich jetzt keinen Fehler
entdecken.

von Karl heinz B. (kbucheg)


Lesenswert?

> Die aktuelle Version ist 4.irgendwas

und dann schreibst du:


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

volatile uint16_t uiTimer0High;

ISR( TIMER0_COMP_vect )
{
  PORTB |=  _BV(PB0);
  uiTimer0High += 1;
  PORTB &= ~_BV(PB0);
}

int main (void)
{
  uint16_t u16Time;

  DDRB = 0x02;    // untersten 2 Bit von Port B sind Ausgang

  OCR0  = 19;             // 20MHz  1024  195,315) = 1000 Hz
  TCCR0 = ( (1<<WGM01) | (0<<WGM00)
          | (0<<COM01) | (0<<COM00)
          | (1<<CS02)  | (0<<CS01)  | (1<<CS00) );

  TIMSK  = _BV (OCIE0); // Timer0 = Bastime
  sei();

  while(1)
  {
    cli();
    // read actual time
    u16Time = uiTimer0High;
    sei();

    if (u16Time & 0x8000)
      PORTB |=  _BV(PB1);
    else
      PORTB &= ~_BV(PB1);
  }
}

* Wenn man einen Port als Ausgang benutzen will, dann
  sollte man auch das entsprechende DDR Bit setzen

* Lass den Watchdog in Ruhe
  Der ist beim Hochfahren sowieso ausgeschaltet.
  Kein Grund da an den Bits rumzupfriemeln.

* Innerhalb der while Schleife am Interrupt Bit
  rumzumachen ist keine gute Idee. Im besten Fall
  passiert nichts, im schlimmsten Fall initialisiert
  sich alles neu. Keine Ahnung wie das beim AVR ist.
  Ich halte mich an die alte Regel: Initialisert wird
  nur einmal, bzw. dann wenn eine Umkonfigurierung
  notwendig ist. Ansonsten laesst man die Konfig in Ruhe.

von Karl heinz B. (kbucheg)


Lesenswert?

> * Wenn man einen Port als Ausgang benutzen will, dann
>   sollte man auch das entsprechende DDR Bit setzen

Selbst reingefallen.
Du benutzt ja PB0 und PB1. Also:

  DDRB = 0x03;

Ist mir im Simulator nicht aufgefallen

von Corinna (Gast)


Lesenswert?

Das mit der Reinitialisierung hat wichtige "Lang-Laufzeitgründe". Wenn
die SW monatelang ununterbrochen laufen muss, beschreib ich
grundsätzlich alle Register immer wieder, wenn ihr Inhalt statisch
bleibt. Bei EMV-Störungen könnten sonst ein Register seinen Wert
verlieren und die uC-Schaltung kommt ohne Spannungsunterbrechnung nie
wieder auf die Beine.

Beim Watchdog stimm ich Dir voll und ganz zu. Den will ich auch wieder
beleben, wenn das Ganze mal grundsätzlich funzt.

Die Int-Bit Manipulation ist notwendig, da die 16 Bit Operation doch
durch einen Int unterbrochen werden kann, deshalb schalt ich ihn für
diese Zuweisung ab!

Inzwischen hab ich auch die jüngste Version des WinAVR runtergeladen...
und bereu' es bitter!!!!
Die WinAVR-Macher halten wohl nicht's von gewissen
Abwärtskomatibilitäten... Jedenfalls kennt die neue Version kein
einziges Register mehr...   Na prima!

von Karl heinz B. (kbucheg)


Lesenswert?

Kann nicht sein.
Ich benutze selbst die neueste Version und bis auf
ein paar kleinen Änderungen lief dein Pgm auf
Anhieb durch den Compiler.

von Karl heinz B. (kbucheg)


Lesenswert?

Eine der Anderungen waren zb.
die includes ganz am Anfang.
Ohne die ist es klar: nichts geht mehr, nicht ist mehr bekannt :-)

von Corinna (Gast)


Lesenswert?

Compiler läuft wieder, hatte makefile aus dem demo Beispiel verwendet
und den falschen Controller-Typ noch aktiv.
Tut mir leid WinAVR!
Trotzdem funzt die Sache draussen auf der HW NICHT !
Selbes Bild wie bisher.
Port B1 muss doch im 32,76 Sek. Takt toggeln ?!?!?!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

> Bei EMV-Störungen könnten sonst ein Register seinen Wert
> verlieren und die uC-Schaltung kommt ohne Spannungsunterbrechnung
nie
> wieder auf die Beine.

Nein, die IO-Register haben nach einem Hardware-Reset definierte
Werte (die im Datenblatt stehen), egal ob der Reset ein power-on,
externer oder watchdog reset war.  Nach einer EMV-Störung ohne
Reset weiterzuarbeiten ist sowieso tödlich.

Bist du dir eigentlich sicher, dass deine Hardware überhaupt richtig
funktioniert?  Karl Heinz hat dir das Beispiel ja nun wirklich bis
ins letzte funktionsfähig übergeben.

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.