Hallo,
ich habe nun seit geraumer Zeit mich mit C beschäftigt, etliche Bücher
und Forumbeiträge gelesen und natürlich viel ausprobiert.
Nun wollte ich mal ein wenig was umsetzen und scheitere leider an meinen
Code, vermutlich eine Kleinigkeit und ich bekomme das mit eure Hilfe
gebacken. Wichtig für mich ist aber auch das ich das dann verstanden
habe :)
Eigentlich ganz einfache Aufgabe:
Watchdog aktivieren und schlafen legen, nach ca. 16 Sekunden aufwachen
eine Ledgruppe hoch und einmal runter Faden und wieder schlafen und das
immer so weiter.
Problematik: Die leds sind anfangs sofort an, obwohl sie mit OCR0A=255
aus sein müssten.
Die leds faden zwar aber pausieren nie wirklich, als ob sie in einer
Endlosschleife sind, dabei setze ich doch den status=0 ?
Wo liegt mein Denkfehler?
Bin um jede Hilfe dankbar.
Reduziere dein Programm, um herauszufinden, woran es scheitert. Ich
würde mal damit beginnen, den den WDT, und den Sleep Modus raus zu
werfen.
Solltest du weitere fragen haben, zeige uns deinen Schaltplan und ein
Foto vom Aufbau.
Paul schrieb:> ISR(WDT_vect)> {> WDTCR = (1<<WDIE);> inkr++;
was machst du hier? oben hast du noch
Paul schrieb:> WDTCR = (1<<WDIE) | (1<<WDE) | (1<<WDP3) | (1<<WDP0); // 8s
definiert, und du vergisst in der isr WDCE zu setzen, mal davon
abgesehen dass du den prescaler änderst. ich nehme ganz stark and dass
in dieser Zeile einfach nichts passiert und dir der wdt den µC
zurücksetzt (vor/im zweiten wdt interrupt), da du WDE auch gesetzt hast.
S. Landolt schrieb:>> for(byte i=255; i>=0; i--)>> Ich habe fast keine Ahnung von C, aber kann 'byte' negativ werden?> Vielleicht mal i>0 versuchen.
In der Tat, das ist eine Endlosschleife, wie auch der gcc -Wextra
schildert:
1
$ gcc -Wall -Wextra a.c
2
a.c: In function ‘main’:
3
a.c:5:20: warning: comparison is always true due to limited range of data type [-Wtype-limits]
S. Landolt schrieb:> Ich habe fast keine Ahnung von C, aber kann 'byte' negativ werden?> Vielleicht mal i>0 versuchen.
byte ist kein C typ, es kann entweder negativ werden oder bis zu 255
halten. benutze lieber typen wie uint8_t dann wird es ein wenig
offensichtlicher.
aber so oder so sitzt du hier in einer Endlosschleife und der wdt
resettet dir alle 16s den tiny, das wirst du aber noch garnicht merken.
WDIE setzt sich nach jeden Interrupt wieder zurück, setzt man in der ISR
nicht erneut ist der nächste Interrupt ein Reset vom WDT.
Ich habe nun den Code sehr oft reduziert und vieles versucht und habe
einen funktionierenden Gefunden
So funktioniert er wie gewollt
uint8_t musst und solltest du nicht selber definieren, dafür machst du
ein
#include <inttypes.h>
da sind 8,16,32 bit signed und unsigend ints nach dem gleichen schema
definiert (und int_least... int_fast..., intptr_t für leute die das
brachen) im Endeffekt wird stdint_gcc.h eingebunden, also sollte es z.b.
in ateml studio auch ohne include gehen.
das Problem ist dass besonders bei µC ein int nicht immer gleich groß
ist, deswegen nimmt man besser gleich Typen bei denen man die Länge
kennt:
byte = char => int8_t
als unsigned => uint8_t
ein int (32 bit) => int32_t
wenn dir 16 bit reichen => int16_t
kürzere Typen sind schneller auf einem 8 bit µC, können aber auch nicht
so große Werte.
was mir noch aufgefallen ist, aber kein Gemecker sein soll, sieh es als
Tipp den du gerne ignorieren kannst:
Die init funktionen kannst du besonders auf einem Tiny entweder inline
machen oder als Makro definieren, bei nur einem einzigen Aufruf kann man
sich den overhead für einen Funktionsaufruf sparen.
warum schaltest du den wdt innerhalb deiner while(cycle <= 4) Schleife
an, das ergibt wenig Sinn. anschalten solltest du den entweder erst nach
der schleife, oder vorher und dann zurücksetzen, sonst läuft der schon
los während du noch fadest (außer das ist gewünscht).
Paul schrieb:> Eigentlich ganz einfache Aufgabe:> Watchdog aktivieren und schlafen legen, nach ca. 16 Sekunden aufwachen> eine Ledgruppe hoch und einmal runter Faden und wieder schlafen und das> immer so weiter.
Könntest du mal erläutern, was du tatsächlich brauchst?
Den Watchdog kann man auf mehrere Arten nutzen:
- WD zum Abfangen von Dead-Locks. Nach Ablauf der WD-Zeit wird ein Reset
ausgeführt, wenn er nicht regelmäßig zurückgesetzt wird. Scharf machst
du den mit WDE oder ohne Softwareeinfluss über eine Fuse.
- WD als Timer, der dann nach Ablauf der Zeit die Interruptroutine
anspringt. Das wird mit WDIE aktiviert. Kann man nutzen als Timer und
zum Wecken aus dem Tiefschlaf. Das verwende ich regelmäßig.
- Beides zusammen. Dann wird beim ersten Ablauf der WD-Zeit die ISR
angesprungen und wenn er dann noch immer nicht zurückgesetzt wird, dann
wird beim zweiten Ablauf der Reset ausgeführt. Dazu muss WDE und WDIE
aktiviert werden.
K. S. schrieb:> Die init funktionen kannst du besonders auf einem Tiny entweder inline> machen oder als Makro definieren, bei nur einem einzigen Aufruf kann man> sich den overhead für einen Funktionsaufruf sparen.
Wenn man die Optimierung nicht abschaltet, macht der AVR-GCC das schon
von selbst.
Laß also alle einmal aufgerufenen Funktionen als Funktion. Lesbarkeit
geht vor und kostet hier nichts.
Sogar Funktionen in verschiedenen Compile-Units können werden geinlined
werden mit entsprechenden Compileroptionen.