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); } }
Hab jetzt nur mal schnell drüber geschaut, aber: Wo wird der WatchDog resettet? Der Puls soll nach 33s kommen (1ms * 32768)?
@Andreas: Nö, das hier > WDTCR = ((1<<WDTOE) | (1<<WDE)); > WDTCR = 0x00; schaltet den WDT aus. Dann muss er auch nicht geresettet werden.
> INTERRUPT(SIG_OUTPUT_COMPARE0); > void SIG_OUTPUT_COMPARE0(void)... Was ist das denn???
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...
Ob die ISR-Routine korrekt ist, ist sicher fragwürdig, aber wieso kommt dann der Port B0 so regelmässig im 1-ms-Takt ?
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?
Wie würdet ihr denn die paar Zeilen Code schreiben? Dann kann ich mal eure Ideen testen.
Als aller erstes holst du dir mal einen neuen Compiler. Die aktuelle Version ist 4.irgendwas
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.
> 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.
> * 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
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!
Kann nicht sein. Ich benutze selbst die neueste Version und bis auf ein paar kleinen Änderungen lief dein Pgm auf Anhieb durch den Compiler.
Eine der Anderungen waren zb. die includes ganz am Anfang. Ohne die ist es klar: nichts geht mehr, nicht ist mehr bekannt :-)
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 ?!?!?!
> 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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.