Hallo zusammen,
bin bei meinem uC-Projekt jetzt das zweite mal mit meinem Latein am Ende
und hoffe, dass mir hier jemand helfen kann.
Worum geht es überhaupt?
Ziel des Projektes ist es einen Hager EHz-Zweirichtungszähler auszulesen
und den Momentanverbrauch/Einspeisewert anzuzeigen. Hierzu benutze ich
einen atmega8, welcher den Wert auf 4 7-Segmentanzeigen wiedergibt.
Beschaltung:
Versorgungsspannung beträgt 12V Gleichstrom die mit einem 1000uF
Kondensator stabilisiert wird und dann mit der im AVR-Tutorial
vorgeschlagenen Schaltung auf 5V gebracht wird.
Der uC läuft mit einem 4 MHz Quarz, PortD wird zur ansteuerung der
einzelnen Segmente genutzt(100 Ohm Wdst), während PortC 0-3 die
einzelnen Displays zum Multiplexen steuert(1000/10000 Ohm an
Transistorbasis). C5 ist mit einem externen 10kOhm Pull-up belegt, und
über einen Phototransistor mit Masse verbunden, hier wird die
Infrarotschnittstelle des Zählers ausgelesen. Der UART wurde nicht
benutzt, da der mir PortD zerlegen würde.
Über B0 soll später ein Relais angesteuert werden (Idee hierzu:
Transistor Kollektor-Emitter liegen 12 V and und die Basis wird mit den
5V vom uC geschaltet), aktuell liegt hier eine LED drauf zur
Funktionsprüfung.
Code:
Befindet sich im Anhang, ist soweit auch gut kommentiert hoffe ich,
falls fragen nur her damit.
Das Problem:
Im Prinzip funktioniert das ganze super und alles was noch fehlt wäre
die Relaisansteuertung, allerdings hört der uC in unregelmäßigen
Abständen auf die Anzeige korrekt zu Multiplexen, im gegebenen Fall
bedeutet das, dass nur noch die ganz rechte Ziffer angezeigt wird, der
rest nicht mehr. Zusätzlich fällt auf, dass die angezeigte Ziffer
flackert, also nicht mehr die 60Hz wiedergabe Frequenz hat, die sie
eigentlich durch das Multiplexen haben sollte.
Resette ich den uC(Strom klauen und wieder anschließen, also
Poweronreset) funktioniert wieder alles.
Den genauen Zeitraum des Ausfalls kann ich nicht benennen, da ich weder
Zeit noch Lust habe, mich die ganze Zeit in den Keller zu setzen und auf
einen Ausfall zu warten. Bisher haben Ausfälle Zeiträume zwischen ein
paar Stunden und einigen Tagen gedauert.
Gruß Florian
Hallo Florian,
wieviel SRAM besitzt der ATMEGA8 und wieviel SRAM verbraucht Dein
Programm?
Wenn Du die 500 Bytes der Variablen "log" erheblich reduzierst, dann
dürfte das Programm vielleicht laufen.
Ein Tip am Rande: Informiere Dich über Speicherklassen in "C".
Bernhard
Flash hab ich 8kB davon sind laut Eclipse 6792 Byte belegt, SRam hat der
Käfer 1kB davon sind laut Eclipse 417 Byte belegt.
Das Programm läuft ja auch, nur steigen die Segmentanzeigen aus.
Die log[] Variable soll demnächst auch komplett verschwinden, da ich das
einlesen on-the-fly implementieren möchte.
Gruß Florian
> SRam hat der Käfer 1kB davon sind laut Eclipse 417 Byte belegt.
Schieb mal die funktionslokalen Variablen in den globalen Bereich, dann
bekommst Du eine grobe Abschätzung (hier: 970 Bytes) was Du tatächlich
verbrauchen kannst.
Ich tippe auf einen Speicherüberlauf.
Florian T. schrieb:> Flash hab ich 8kB davon sind laut Eclipse 6792 Byte belegt, SRam hat der> Käfer 1kB davon sind laut Eclipse 417 Byte belegt.
Die ganzen Float-Variablen sind ziemlich überflüssig, da der
Wertebereich sehr begrenzt ist und mit höherer Genauigkeit durch passend
normierte Integer abgebildet werden kann.
Was passiert denn auf den Datenleitungen zum Display, wenn die Anzeige
hängt?
Bestätige: 6468 Flash, 917 SRam.
Inwiefern würde ein Speicherüberlauf zum Versagen des Multiplexens
führen?
Das eingelesene Protokoll ist immer gleich groß und kürzer als die 500
Byte.
Es kommt etwa alle 1-4 Sekunden ein Protokoll rein und es läuft über
mehrere Tage stabil, wieso sollte es dann plötzlich nach x tausend
Paketen einen überlauf geben?
Auch ist die im Einlese abschnitt
1
for(i=0;i<500;i++){
2
log[i]=readchar();
3
if(log[i]=='!')
4
break;
5
}
in der Bedingung festgemacht, das es nicht zu einem Speicherüberlauf
kommen kann, nach 500 Zeichen bricht er einfach ab.
Aus meinem Blickwinkel kann es an diesem Stück zu keinem Überlauf
kommen, oder übersehe ich was essentielles?
Florian
Edit: @Werner:
Müsste ich auf den nächsten Ausfall warten und mich dann mal mit nem
Multimeter dransetzen. Wenns soweit ist werde ich das dann hier posten.
> Das eingelesene Protokoll ist immer gleich groß und kürzer> als die 500 Byte.
Was passiert bei einem Übertragungsfehler? Oder bei mehreren? Der Stack
brauch ja auch noch Platz. Ein mögliches Szenario ist dass das Ende vom
'log'-Puffer normalerweise(tm) nicht vollschreibst weil das Endsymbol
rechtzeitig gefunden wird. Wenn das mal nicht kommt müllst zu
möglicherweise fröhlich fremden Speicher voll ('fremd' wegen
Überlappung, z.B. mit dem Stack).
Das Beispielpaket, das Du im Quellcode angegeben hast, hat etwa 157
Zeichen. Braucht also wei weitem keine 500 Bytes. Und mit etwas
State-Machine könnte man das noch auf < 20 Bytes (!!) runterbrechen.
g457 schrieb:> Wenn das mal nicht kommt müllst zu> möglicherweise fröhlich fremden Speicher voll
Da steht aber immer noch die Abbruchbedingung im Weg, das Array soll im
Endeffekt sowieso rausfliegen, steht auch irgendwo im Code also TODO
markiert.
Und selbst angenommen ich mülle fremden Speicher zu, warum sollte dann
das Display ausfallen? Überschreibe ich die Multiplexfunktion? Kaum
sonst würde ja nach einem reset nicht alles wieder gehen.
Soweit ich das beurteilen kann funktioniert das restliche Programm auch
bei spinnen der Anzeige richtig, sprich ich sehe sowohl den im Quellcode
als "Einlesepunkt" als auch den "Verarbeitungspunkt" bezeichneten DP auf
den Anzeigen aufblitzen wenn er liest und verarbeitet
Florian
> Da steht aber immer noch die Abbruchbedingung im Weg,
Nein, tut sie nicht, weil im angegebenen Szenario der Speicher
überlappt. Und nein, das sieht man an den Ausgaben von avr-size nicht.
> das Array soll im Endeffekt sowieso rausfliegen, steht auch irgendwo im> Code also TODO markiert.
Mach das. Und wenn Du es richtig(tm) machst brauchst Du statt grob 500
Bytes nur noch die vorhin vorgeschlagenen < grob 20.
> warum sollte dann das Display ausfallen?
Warum sollte es nicht? Fremden Speicher begrapschen == undefinierter
Zustand.
Räum doch mal auf und schau ob sich was tut. Kann auch gut sein, dass
das Problem ganz woanders herkommt. Aber wissen wirst Du es nicht bis Du
es ausprobiert hast.
Florian T. schrieb:> Müsste ich auf den nächsten Ausfall warten und mich dann mal mit nem> Multimeter dransetzen.
Eher ein DSO/LA. Wenn du verstanden hast, was der Prozessor dann tut,
kannst du ihn wenigstens per Watchdog rausreißen, auch wenn die Ursache
damit natürlich noch nicht behoben ist.
Beim nächsten Mal kannst du dann das DSO/LA gezielt auf die Bedingung
triggern.
Hallo nochmal, hatte grad wieder einen Ausfall, das Programm ist
mittlerweile umgeschrieben, das on the fly funktioniert nicht, aber das
log[] array wurde um 340 Byte verkleinert, also noch 160 Byte groß.
Hab mir dann auch gleich mal ein Multimeter geschnappt und geguckt was
an den Pins los ist, n Oszi hab ich noch nicht deshalb Multimeter.
Ergebniss der Messungen: An den Pins tut für die Transistorsteuerung tut
sich gar nichts mehr, kein Strom keine Spannung, sind also auf GND
Niveau.
Werner schrieb, dass man sowas via Watchdog "retten" kann, wie soll das
Funktionieren?
Florian
So ein Interrupt-Aufruf brauch immer etwas Speicher auf dem Stack.
Sollte nun das Programm bedingt durch Stacküberlauf diesen Speicher
verheizt haben, wird zwar trotzdem ein Interrupt immer noch ausgelöst,
aber der Stackpointer sitzt im Nirvana und eine Rücksprungadresse wird
nicht sinnvoll abgespeichert.
Wird die Rücksprungadresse dann gelesen aus dem Nichtdefinierten
Speicherbereich gibts einen Crash.
Wenn es dir nicht zuviel Aufwand ist, könntest du in der ISR ja mal
(vorausgesetzt ein ISR wird immer ausgelöst) einen Punkt auf dem Display
setzen wenn der Stackpointer seinen legalen Bereich verläßt.
Hast du Die Avr beschaltung komplett?
Sprich 100n zwischen Vcc und Gnd, Vcc 10k zu Reset, Gnd 47n Reset
Ich hatte durch einen nicht ordentlich verlöteten Reset Pin recht
Ähnliche unerklährliche ausfälle in einem Mega 16
Mfg
Das ist ne Idee, allerdings hab ich keine Ahnung wie man sowas
implementieren soll, kannst du mir da mal einen Denkanstoss geben?
Wie würde ich denn raus kriegen, dass er seinen legalen Bereich
verlässt?
Florian
Edit: Spannung ist mit Kondensatoren stabilisiert und Reset wird mit 10k
auf VCC gezogen, GND ist allerdings nicht über nen Kondensator mit RESET
verbunden, warum sollte das so sein?
Der Legale Bereich beim AVR Mega8 ist zwischen 0x0060 und 0x045F.
Dieser Beinhaltet natürlich dann auch noch alle global angelegten
Variablen im unteren Bereich.
Hat aber so noch keinen Einfluß auf den ISR selbst.
Die Passenden IO-Register des Stackpointers sind SPL & SPH für Low und
HighByte.
Was mir aber gerade nochmal einfällt, der SRAM-Bereich zwischen 0x0000
und 0x005F sind die üblichen IO-Register endend mit S-REG und SPL/SPH.
Du solltest dann vielleicht schon den Stackpointer < 0x0065 oder ähnlich
prüfen.
Ein Stack-PUSH bei Stackpointer Adresse 0x005F löst noch lange keinen
Fehler aus, überschreiben aber schon SREG & SPH/SPL (den Stackpointer
selbst).
Wenn der Stackpointer natürlich schon 0x005F ist, ist schon alles zu
spät.
Alle Globalen Variable sind verhunzt.
Ich würde sogar sagen, wenn der Stack dein Problem wäre, würdest du das
früher bemerken.
Durch Überschreiben der Globalen Variablen müßte da viel Falsch
berechnet werden etc.
Ich werd bei nach meiner letzten Klausur am Mittwoch mal deinen
vorgeschlagenen Test implementieren.
Du sagst aber das es eher was anderes ist, weil es erst sehr spät
auftritt?
Würde sich mit meiner Unschuldsvermutung decken, da bisher immer
sinnvolle Werte angezeigt werden, außer wenn er sich halt grad mal
getötet hat.
Florian T. schrieb:> Werner schrieb, dass man sowas via Watchdog "retten" kann, wie soll das> Funktionieren?
Dazu mußt du erstmal verstehen, welcher Programmteil im Fehlerfall nicht
geordnet durchlaufen wird. Dort kann man den Befehl zum Löschen des
Watchdog Timers einbauen. Im Fehlerfall wird dann der WDT nicht mehr
regelmäßig gelöscht und es erfolgt automatisch ein Reset.
Besser wäre aber auf jeden Fall, die wahre Fehlerursache zu beseitigen.
ISR(TIMER0_OVF_vect){
icount++;
PORTC=0;
PORTD=show[display[pos]];
PORTC|=(1<<pos);
if(pos==0&&einspeisen==1) /*Punkt ob eingespeist wird oder nicht*/
PORTD&=~(1<<7);
if(pos==1&&powered==1) /*Punkt ob WP gepowered oder nicht*/
PORTD&=~(1<<7);
pos++;
if(pos>3) /*Display hat nur 4 Elemente*/
pos=0;
}
Die globalen Variablen dürften erst spät überschrieben werden.
Den Inhalt von display[pos] solltest du vielleicht vor show[ prüfen.
Ein paar Ideen zur Optimierung:
Die Variable pos wird außerhalb des Refresh-LED-ISR genutzt ?
Wenn nicht mach es als static mit in den ISR.
- ein "if(pos>3)pos=0" kann man auch als "pos &=3" schreiben.
- volatile unsigned char show[11] kannst du in den ROM verschieben.
(PROGMEM) oder mindestens als const deklarieren (volatile wird
überflüssig, da es sich nicht ändert)
while(1){
icount=40; /*Protokoll einlesen und Auswerten dauert etwa 40
Interrupts die nicht gezählt werden*/
sei();
while(PINC&(1<<5));
cli();
ist es möglich das dieses sei() nicht mehr erreicht wird im Fehlerfall ?
Hab die Optimierungen mal umgesetzt und werd das ganze bei Gelegenheit
mal auf den Käfer packen.
Bei der PROGMEM optimierung bin ich mir unsicher, muss ich da nicht
pgm_read_byt verwenden um da dann drauf zuzugreifen?
Florian
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Programmspeicher_.28Flash.29
Dein
volatile unsigned char
show[11]={0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,0b10010
010,0b10000010,0b11111000,0b10000000,0b10010000,0b00000000};
/*Segmentcodes für Display*/
ist ja eh nur ein Byte.
const unsigned char show[11] PROGMEM =
{0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,0b10010010,0b100
00010,0b11111000,0b10000000,0b10010000,0b00000000 };
in der ISR dann
PORTD=show[display[pos]];
wird zu
PORTD=pgm_read_byte(show+display[pos]);
Ah super genauso hab ichs gemacht, außer das da nicht
PORTD=pgm_read_byte(show+display[pos]);
sondern
PORTD=pgm_read_byte(show[display[pos]]);
steht ich nehme an das + war ein Tippfehler?
Werde zusätzlich mal vergleiche etwas kleiner machen, auf 7, das spart
dann 12 Floats ein, also 12*32 Byte. Das ganze auf den Käfer und
beobachten.
Florian
Nach kurzem Schockmoment (auf einmal zeigte er Sachen wie n und P an),
hab ich nochmal genauer nachgelesen und gesehen, dass da ein
Adressoperator fehlt, läuft jetzt erstmal mit den ganzen Optimierungen.
Mal schauen ob er immer noch zu schwachsinn übergeht oder nicht.
Florian
Da bin ich wieder, hatte vorhin nach etwa 23 Std Laufzeit wieder einen
Ausfall.
Angezeigt wurde wie immer nur noch das rechte Display. Was mir
aufgefallen ist, dass ein nicht vorhandener Segmentcode angezeigt wird.
Quasi eine 6 ohne Segment a.
Datenempfang findet immer noch statt, ich sehe sowohl den DP vom ganz
linken Digit aufblinken wenn empfangen wird, also auch den DP vom Digit
rechts daneben wenn die Daten verarbeitet werden.
Habe auch direkt nochmal die Pins vermessen, komplett tot! Bis ich ihn
resette, dann geht wieder alles.
So langsam hab ich Lust es auf den Controller zu schieben, Datenpakete
kommen im Takt 1-4 Sekunden, das heißt die Main ist zwischen 82800 und
20700 mal durchgelaufen ohne Probleme zu machen. Die ISR ist in den 23
Stunden etwa 20 Millionen mal durchgelaufen.
Spannungseinbrüche können mMn auch kein Problem sein, da zum einen die
Versorgungsspannung per Kondensator stabilisiert ist und ich die Brown
out detection anhabe und diese auf 4.8 Volt steht.
Angenommen es wäre ein Stack-Problem, dann müsste ich ja irgendwo
Datenmüll erzeugen, der den Stack mit der Zeit wachsen lässt. Nicht
sicher ob das überhaupt geht.
Florian
Schreibe mal auf die letzten paar Bytes des Stackbereiches bekannte
Werte. Wenn die Kiste wieder abschmiert, lässt Du dir die Werte nach
Tastendruck zuschicken und vergleichst die mit den reingeschriebenen
Werten. Wenn da was anderes drin steht, dann hast Du (d)ein Problem.
unn tschuess
Bernhard
Hab Bernhards Variante mal ausprobiert (schön das man bei nem Steckbrett
einfach alles umsortieren kann).
Ergebniss: Stack läuft nicht über.
Habe mir jetzt einen Watchdog in die ISR eingebaut, da die ja
Auszufallen scheint. Es wird ja nur das erste Digit angezeigt.
In der ISR wird der Watchdog jetzt beim Anzeigen der 3. Digit resettet.
In der Main ist der Watchdog leider nicht zu realisieren, da die bis zu
4 Sekunden für einen Durchlauf braucht.
Des weiteren hab ich noch eingebaut, dass nach 30k Programmdurchläufen
resettet wird, durch den Watchdog, einfach Interrupts aus und
_delay_ms(2000) bei ner anschlagzeit von 500ms.
Hätte noch eine Frage zum Hund und zwar bleibt das ja an nachdem durch
ihn resettet wurde.
Jetzt steht im Tutorial, dass ich den nach Möglichkeit früh kille weil
er ansonsten zubeißt bevor er zurückgesetzt wird und der uC dadurch auf
ewig im Watchdogreset festhängt.
Laut Tutorial soll der Reset/abschalten des Hundes vor der
Variableninitialisierung passieren.
Ich hab aber im Kopf, dass die initialisierung das erste ist was im C
Code passieren muss, wie soll ich den WD also vorher abschalten?
Florian
> Ich hab aber im Kopf, dass die [Variablen]initialisierung das erste ist> was im C Code passieren muss
Nein, klücklicherweise ist dem nicht so.
> wie soll ich den WD also vorher abschalten?
in einer der init-Sections [0].
HTH
[0] http://www.nongnu.org/avr-libc/user-manual/mem_sections.html
Ich hatte ein ähnliches Problem, Programm lief mehrere Stunden stabil,
dann Absturz bzw. Einfrieren, selbst der Watchdog lief nicht weiter. Ich
hatte versehendlich den ADC zu schnell laufen. Kannst du EMV
ausschließen?
Ingo
Das könnte natürlich ein Problem sein, das Ding hängt immerhin mitten im
Stromkasten drinne, hab ich bisher gar nicht dran gedacht. Das Kabel ist
allerdings lang genug, dass ich den Käfer da mal raus holen kann.
Lief bisher die letzten 3 Tage ohne Probleme.
Danke für den Hinweis
Florian
Was ich schon oft beobachten konnte ist, wenn z.B. ein Aussenleiter
Kontakt mit einer Leiterplatte (Der Platine selber) Kontakt bekommt und
diese kein definiertes Potential führt, es zu abstürzen kommen kann.
Abhilfe schafft es z.B. einen 1nF oder weniger von Masse nach Erde.
Wirkt Wunder :). Auch große Metalkörper ohne definiertes Signal können
Bei Berührung zum Absturz führen, wenn ein Ladeungaustausch stattfindet.
Ingo
Undefinierte Kabel oder sonstige Sachen die da dran kommen kann ich
Glücklicherweise ausschließen, es sei denn die Meinzelmännchen kommen
nachts um mich zu ärgern :)
Werd ihn mal aus dem Zählerschrank rausnehmen und gucken wie er sich
dann macht. Könnte es ja schon gewesen sein.
Florian
Florian T. schrieb:> Da bin ich wieder, hatte vorhin nach etwa 23 Std Laufzeit wieder einen> Ausfall.> Angezeigt wurde wie immer nur noch das rechte Display. Was mir> aufgefallen ist, dass ein nicht vorhandener Segmentcode angezeigt wird.> Quasi eine 6 ohne Segment a.> Datenempfang findet immer noch statt, ich sehe sowohl den DP vom ganz> linken Digit aufblinken wenn empfangen wird, also auch den DP vom Digit> rechts daneben wenn die Daten verarbeitet werden.> Habe auch direkt nochmal die Pins vermessen, komplett tot! Bis ich ihn> resette, dann geht wieder alles.>> So langsam hab ich Lust es auf den Controller zu schieben, Datenpakete> kommen im Takt 1-4 Sekunden, das heißt die Main ist zwischen 82800 und> 20700 mal durchgelaufen ohne Probleme zu machen. Die ISR ist in den 23> Stunden etwa 20 Millionen mal durchgelaufen.> Spannungseinbrüche können mMn auch kein Problem sein, da zum einen die> Versorgungsspannung per Kondensator stabilisiert ist und ich die Brown> out detection anhabe und diese auf 4.8 Volt steht.> Angenommen es wäre ein Stack-Problem, dann müsste ich ja irgendwo> Datenmüll erzeugen, der den Stack mit der Zeit wachsen lässt. Nicht> sicher ob das überhaupt geht.>> Florian
Ich versuchs mal so auszudrücken.
Die ISR läuft ja noch ( sonst wären die Dots nicht mit aktualisiert ).
Ich tippe da immernoch auf nicht legale Werte für die Segmentdaten.
Warum auch immer.
Was hälst du davon diesen Teil
PORTD=show[display[pos]];
zu reduzieren auf reines
PORTD=display[pos];
und in "display" nur noch die fertigen Segmentdaten hälst ?
Dein Fehler muß irgendwie in der Main liegen.
Bereichsüberlauf o.ä.
(vielleicht sowas hier http://www.bbc.co.uk/news/uk-12751404)
Dennis Heynlein schrieb:> Ich versuchs mal so auszudrücken.> Die ISR läuft ja noch ( sonst wären die Dots nicht mit aktualisiert ).
Das stimmt so nicht ganz, die Dots die ich sehe werden von der Main
gehandelt.
Mit den ungültigen Segmentcodes hab ich schonmal mit einer if Bedingung
geguckt gehabt. Sprich if dispay>10 dann gib mir nen Errorcode aus. Hat
aber nichts gebracht gehabt, sprich ist auch ausgestiegen ohne
entsprechenden Errorcode anzuzeigen.
/*Timeroverflowinterrupt für das Multiplexen der 4 7-Segment Anzeigen*/
ISR(TIMER0_OVF_vect){
icount++;
PORTC=0;
PORTD=show[display[pos]];
PORTC|=(1<<pos);
************************************************************************
if(pos==0&&einspeisen==1) /*Punkt ob eingespeist wird oder nicht*/
PORTD&=~(1<<7);
if(pos==1&&powered==1) /*Punkt ob WP gepowered oder nicht*/
PORTD&=~(1<<7);
************************************************************************
pos++;
if(pos>3) /*Display hat nur 4 Elemente*/
pos=0;
}
ohne die Zeilen in der ISR wären deine DOTs nicht an.
Die ISR läuft also schon.
Kannst du vielleicht den SRAM beim nächsten Absturz mal rausspielen
(über U(S)ART und Main+Taste z.b.).
Eine Zuordnung welche SRAM-Adresse welche Variable ist sollte nicht so
schwierig sein.
Die Punkte die aufleuchten sind allerdings diese hier aus der Main
/*Einlesepunkt einschalten*/
PORTD=0b01111111;
PORTC=0b00001000;
/*Protokoll einlesen*/
for(i=0;i<loggr;i++){
log[i]=readchar();
if(log[i]=='!')
break;
}
/*Verarbeitungspunkt einschalten*/
PORTC=0b00000100;
der eine Punkt der ganz rechts an ist kann aus nem Fehlerhaften
Segmentcode entstehen.
Fürn UART müsst ich leider die Segmentanzeige zerrupfen. Aber ich schau
mal was sich da machen lässt.
Florian
Muß ja nicht UART sein, solange du weißt wie es codiert ist, kannst du
es an jeden beliebigen Port rausspielen.
SoftUart liese sich einfach realisieren, zumal es nur ums ausgeben geht
mit womöglich fester Bitrate. (Ein Pegelwandler wäre vielleicht aber
dann notwendig)
Und neben SRAM-Zustand wäre auch der Zustand
- des I-Bits im Statusregister nach dem "Absturz".
- des Timer-Interrupt-Freigabe TIMSK
- des Timer-Control-Registers TCCR0
interessant.
Poste mal deine neuesten Sources wenns geht.
Welche Ports sind noch frei ?
Frei ist noch PORTB bis auf B0, aktueller Quelltext ist im Anhang.
Habe inzwischen einen Watchdog eingebaut der nach beim hängenbleiben
einspringt.
Außerdem ist noch ne Eepromnutzung hinzugekommen, er soll immer wenn er
zwischen powered/unpowered wechselt den Status ins Eeprom schreiben,
sodass er wenn der Watchdog zubeißt immer wieder im selben Zustand neu
startet.
Diese Funktion funktioniert allerdings noch nicht, keine Ahnung warum.
Florian
Edit: Der Code frisst inzwischen 90% des Flash, ist zu überlegen da auch
auf nen größeren Käfer umzusteigen? atmega16 bzw atmega32?
Vielleicht kannste auf Fliesskomma verzichten und eher zu Festkomma
greifen ?
Thema Watchdog. Mich würde diese Angstlösung nicht ruhen lassen und ich
würde unbedingt den Fehler finden wollen ;)
Auf Fließkomma verzichten geht, dann brauch ich aber trotzdem 32 Bit
Variablen, Speichergewinn gibts es dadurch also eher nicht.
"Angstlösung" ist nicht wirklich die richtige Bezeichnung eher:
"Damit-ich-weitermachen-kann" Lösung xD
Hast du eine Idee warum der Eeprompart nicht funktioniert?
Prinzipiell soll er den ersten Eintrag suchen der 255 ist und dann den
Wert davor als powered nehmen, wenn der 0. Eintrag schon 255 ist nimmt
er einfach 0 an.
Zum schreiben sucht er den ersten Eintrag der 255 ist und schreibt da
dann den aktuellen status rein. Zumindest in meinem Kopf^^ Wenn im 511.
also letzten Eintrag kein 255 ist das Array voll und er schreibt es
einmal komplett neu mit 255 bevor er ins erste wieder den Status
schreibt.
Eine mögliche Fehlerquelle die ich heut morgen noch gefunden hab ist der
Phototransistor, der ist über die Zeit immer weiter weg vom Zähler
gewandert und je weiter weg der war, desto öfter stand da nur
schwachsinn.
Florian
Die Fliesskomma-LIB frisst ziemlich viel Platz.
Eine mögliche Fehlerquelle die ich heut morgen noch gefunden hab ist der
Phototransistor, der ist über die Zeit immer weiter weg vom Zähler
gewandert und je weiter weg der war, desto öfter stand da nur
schwachsinn.
Das Passt dann gut zur Überlauftheorie in der Main.
Du prüfst auch nicht direkt, ob deine Zahlen wirklich Dezimalzeichen
sind und nicht fehlerhaft gelesenes irgendwas.
Dann mach ich mich mal dran in die Protokollauswertung noch ne
Überprüfung einzubauen die schaut das da wirklich 0-9 steht und nichts
anderes.
Das ganze auf unsigned long umstellen müsste auch gehen. Ich meld mich
dann nichmal wenn ichs soweit am laufen hab.
Florian
So ein EEPROM-Schreibzyklus braucht ne weile.
"EEPROM Write (from CPU) 8448 CLKrc 8.5ms"
Hoffentlich wird nicht während deinem Schreiben der Watchdog ausgelöst.
Ich behaupte mal, dass das nicht passieren kann weil
1
if(powered!=laststate){
2
wdt_disable();
3
writestatus();
4
wdt_enable(WDTO_500MS);
5
}
Edit: Denke ich hab in der write funktion nen Fehler gefunden wenn
Eintrag 0 255 ist, dann geht er gar nicht erst in die Schleife erhöht
also auch gar nicht i, also versucht er dann in eintrag -1 bzw da es ein
unsigned int is in eintrag 65000 oder so zu schreiben.
Hallo, arbeite grade am loswerden der ganzen floats, habe allerdings das
Problem, dass ich keine Idee habe wie ich den float bei der Zeit
loswerden kann, denn angenommen bei der Multiplikation kommt was kleiner
1 raus, dann hab ich da auf einmal 0 stehen und durch 0 teilen ist
ungesung, auch kann ich denn nicht mehr zwischen 1 und 1.9
unterscheiden. Ideen wie ich das Lösen kann?
Florian
Festkommazahlen in C zusammenbasteln.
Z.B nimmst du von einer 16 Bit int 8 Bit für Vorkomma und 8 Bit für
Nachkomma. Musst dann bei jeder Zuweisung und jeder Rechenoperation
aufpassen. Jedes mal nachdenken, ob du um 8 Bit verschieben musst.
Ich denke ich habs jetzt, allerdings zeigt das Display einen gefühlten
Faktor 5 zu wenig an, ich möchte einfach nicht glauben, dass wenn die
Anlage 6kW bringt nur 1kW eingespeist werden obwohl nur mein PC als
großer Verbraucher läuft ;)
Änderungen sind, alle floats sind unsigned long gewichen
Das hier
1
if(klammern==3){
2
i++;
3
kaufen+=(log[i]-48)*100000;
4
i++;
5
kaufen+=(log[i]-48)*10000;
6
i++;
7
kaufen+=(log[i]-48)*1000;
8
i++;
9
kaufen+=(log[i]-48)*100;
10
i++;
11
kaufen+=(log[i]-48)*10;
12
i++;
13
kaufen+=(log[i]-48);
14
i+=2;
15
kaufen+=(log[i]-48)/10.;
16
i++;
17
kaufen+=(log[i]-48)/100.;
18
i++;
19
kaufen+=(log[i]-48)/1000.;
20
i++;
21
kaufen+=(log[i]-48)/10000.;
22
}
ist dem hier gewichen
1
if(klammern==3){
2
i++;
3
kaufen+=(log[i]-48)*1000000000;
4
i++;
5
kaufen+=(log[i]-48)*100000000;
6
i++;
7
kaufen+=(log[i]-48)*10000000;
8
i++;
9
kaufen+=(log[i]-48)*1000000;
10
i++;
11
kaufen+=(log[i]-48)*100000;
12
i++;
13
kaufen+=(log[i]-48)*10000;
14
i+=2;
15
kaufen+=(log[i]-48)*1000;
16
i++;
17
kaufen+=(log[i]-48)*100;
18
i++;
19
kaufen+=(log[i]-48)*10;
20
i++;
21
kaufen+=(log[i]-48)*1;
22
}
die Verarbeitung sieht jetzt anstelle so
1
time=icount*0.004096;
2
timea[eintrag]=time;
3
4
5
6
/*Differenz zum letzten Verkaufenwert ermitteln, auf Joule umrechnen und ins passende Array schreiben*/
7
verkaufendiff=(verkaufen-verkaufenalt);
8
verkaufendiff*=1000;
9
verkaufendiff*=3600;
10
vkauf[eintrag]=verkaufendiff;
so aus
1
time=icount*0.04096;
2
timea[eintrag]=time;
3
4
5
6
/*Differenz zum letzten Verkaufenwert ermitteln, auf Joule umrechnen und ins passende Array schreiben*/
7
verkaufendiff=(verkaufen-verkaufenalt);
8
verkaufendiff*=3600;
9
vkauf[eintrag]=verkaufendiff;
hierbei sind sowohl der time Multiplikator also auch die 3600 um den
Faktor 10 zu groß, so erschummel ich mir eine größere genauigkeit bei
der Zeit.
Die todisplay Funktion wurde auf die unsigned longs angepasst.
unsigned longs entsprechen 32 bit Variablen, sollte also Werte bis 4
Milliarden halten können.
Ich seh grad nicht wo dieser Faktor 5 Verloren gehen soll.
Florian
i++;
kaufen+=(log[i]-48)*1000000000;
Teste mal log[i] auf >=48 && <=57
und eventuell haste noch ein paar Testausgaben :) um mal einen Simulator
damit zu füttern.