Forum: Mikrocontroller und Digitale Elektronik Display fällt in unregelmäßigen Abständen aus


von Florian T. (grendal)


Angehängte Dateien:

Lesenswert?

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

von Bernhard R. (barnyhh)


Lesenswert?

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

von Florian T. (grendal)


Lesenswert?

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

von g457 (Gast)


Lesenswert?

> 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.

von Werner (Gast)


Lesenswert?

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?

von Florian T. (grendal)


Lesenswert?

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.

von g457 (Gast)


Lesenswert?

> 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.

von Florian T. (grendal)


Lesenswert?

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

von g457 (Gast)


Lesenswert?

> 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.

von Werner (Gast)


Lesenswert?

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.

von Florian T. (grendal)


Lesenswert?

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

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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.

von Sven (Gast)


Lesenswert?

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

von Florian T. (grendal)


Lesenswert?

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?

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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.

von Florian T. (grendal)


Lesenswert?

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.

von Werner (Gast)


Lesenswert?

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.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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 ?

von Florian T. (grendal)


Lesenswert?

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

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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]);

von Florian T. (grendal)


Lesenswert?

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

von Florian T. (grendal)


Lesenswert?

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

von Florian T. (grendal)


Lesenswert?

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

von Bernhard S. (b_spitzer)


Lesenswert?

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

von Florian T. (grendal)


Lesenswert?

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

von g457 (Gast)


Lesenswert?

> 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

von Ingo (Gast)


Lesenswert?

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

von Florian T. (grendal)


Lesenswert?

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

von Ingo (Gast)


Lesenswert?

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

von Florian T. (grendal)


Lesenswert?

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

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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)

von Florian T. (grendal)


Lesenswert?

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.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

/*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.

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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.

von Florian T. (Gast)


Lesenswert?

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

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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 ?

von Florian T. (grendal)


Angehängte Dateien:

Lesenswert?

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?

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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 ;)

von Florian T. (grendal)


Lesenswert?

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

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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.

von Florian T. (grendal)


Lesenswert?

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

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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.

von Florian T. (grendal)


Lesenswert?

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.

von Florian T. (grendal)


Lesenswert?

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

von Kein Name (Gast)


Lesenswert?

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.

von Florian T. (grendal)


Lesenswert?

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

von Dennis H. (c-logic) Benutzerseite


Lesenswert?

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.

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.