Timer1 und UART - Atmega resettet sich

Gast #3176357
Lesenswert?

Hallo allerseits,
seit ein paar Tagen sitz ich an einem Problem und weiß nicht, woher es 
kommt. Ich möchte den LTC4151 auslesen, der Strom und Spannung aus 
meinen Solarpanelen ausliest. Das geschieht über i2c und funktioniert 
dank der Bibliothek von Peter Fleury auch prächtig.
Als nächstes sollen diese Daten auf einem LCDisplay angezeigt werden 
(funktioniert auch) und per RS232 ausgegeben werden (hier gibt es Ärger 
- beides jeweils über pfleurys Bibliotheken verwirklicht).

Um die Arbeit zu berechnen, die die Module leisten, wird dazu jede 
Sekunde die aktuelle Leistung auf eine Variable addiert - somit habe ich 
die Ws und geteilt durch 3600s/h die Wh (ich gehe der Einfachheit halber 
davon aus, dass die Leistung innerhalb der Sekunde konstant ist). Die 
Zeit möchte ich möglichst genau haben, weshalb ich einen Timer verwende, 
der jede Sekunde einen Interrupt auslöst. In der Interruptroutine wird 
lediglich eine Variable gesetzt, die dann in meiner Hauptschleife 
ausgewertet wird.

Entferne ich die Kommentare vor den uart-Ausgaben (uart_init stellt 
dabei noch kein Problem dar), wird meine Hauptschleife einmal 
durchlaufen und es erfolgt die korrekte Ausgabe im Terminal; beim 
zweiten Durchlauf der Schleife bricht die Ausgabe bei uart_puts( 
"V\tPsol: " ); ab und der Controller resettet sich.

Meine Vermutung bisher ist, dass der Arbeitsspeicher evtl. voll läuft, 
weil danach eine float-Operation läuft. Dagegen spricht allerdings, dass 
der erste Schleifendurchlauf ja klappt. Wo liegt also mein Problem?

Ursprünglich hatte ich einen Atmega32 vorgesehen, aber keinen mehr übrig 
gehabt, also bin ich auf einen Atmega8 ausgewichen. Der ist mit dem 
Programm derzeit zu etwa 60% belegt (Flash) also auch noch nichts 
dramatisches...

Danke für eure Hinweise!
Angehängte Dateien:
#3176393
Lesenswert?

Das einzige echte Problem, das ich auf die Schnelle sehen kann, befindet 
sich hier
1
void uart_putf( float data ) {
2
  char buffer[ 7 ];
3
  uart_puts( dtostrf( data, 7, 2, buffer ) );
4
}

bzw.
1
void lcd_putf( float data, uint8_t digits ) {
2
  char buffer[ digits ];
3
  lcd_puts( dtostrf( data, digits, 2, buffer ) );
4
}

deine Buffer sind um 1 zu klein.

Auch immer drann denken: Was du hier

     dtostrf( data, 7, 2, buffer )
                   ***

angibst ist die >minimale< 'Fieldwidth', d.h. auf welche Zeichenbreite 
dtostrf die Ausgabe formatieren soll (und daher ist das auch kein Bug 
mit den führenden Leerzeichen, das ist genau das was du angefordert 
hast). Das ist NICHT die Größe des bereitgestellten char-Arrays! Deine 
char-Arrays sind damit erst mal mindestens um 1 zu klein, weil ja ein 
String mit strlen==7 ein Array der Größe 8 braucht.

Aber: dtostrf kann und wird diese minimale Fieldwidth auch 
überschreiten, wenn sich das mit der konkret darzustellenden Zahl nicht 
ausgeht. Bei einer Fieldwidth von zb 5 und 2 Nachkommastellen, passt nun 
mal die Zahl -123.45 nicht mehr in ein Feld der Breite 5 und dtostrf 
erweitert das eigenmächtig zu 7, wodurch der von dir bereitgestellte 
Buffer auf jeden Fall viel zu klein ist und du irgendwas am Stack 
überbügelst.

-> an dieser Stelle lohnt es nicht zu kleckern! Dimensioniere deine 
Arrays ausreichend groß und mit fixen Zahlen! Der Speicher wird sowieso 
immer nur kurzzeitig während der Abarbeitung der Funktion benötigt und 
ist danach wieder frei.


Abgesehen davon, sehe ich jetzt erst mal nichts großartig schlimmes. Ok, 
die Sache mit dem _delay_ms kann man noch ankreiden, aber das ist erst 
mal kein Showstopper.
Gast #3176432
Lesenswert?

Hallo,
vielen Dank für die Antworten! Ja, ich denke dann auch mal stark, dass 
es an meinem zu kleinen Buffer liegt; das war mir irgendiwe entgangen. 
Habe es jetzt mal auf 10 hochgestellt, damit für Komma, Minus und ggf. 
String-Terminator Platz ist. Werde es heute Nachmittag gleich testen und 
berichten!

Memory Usage mit Änderungen:
1
avr-size --mcu=atmega8 -C atm32test.elf
2
AVR Memory Usage
3
----------------
4
Device: atmega8
5

6
Program:    4998 bytes (61.0% Full)
7
(.text + .data + .bootloader)
8

9
Data:        194 bytes (18.9% Full)
10
(.data + .bss + .noinit)

Grüße
Gast #3177033
Lesenswert?

Ok,
nochmal meinen herzlichen Dank! Jetzt klappt's!

Steht schön am Display 0,29A bei 36,9V -> 10,6W und entsprechend auch 
alle Werte nochmal aus der Seriellen ;)

Hab jetzt auch noch eine kleine routine drin, die die Arbeit alle 10 
Minuten im EEPROM speichert, d.h. wenn mal Strom für µC ausfällt, hab 
ich die Messwerte noch parat.

Grüße
Gast #3177380
Lesenswert?

Hallo  Thinksilicon!


Nur ne kleine Idee:

Häng doch ne I²C-Uhr mit Notstrom-Knopfzelle mit ran.
Dadurch hast Du Batterie-gestützten Ram, in dem Du Deine Leistungswerte 
seit Installation ablegen kannst (auf dem EEPROM wird also nicht 
rumradiert) und Du hast stets ne genau Zeit (incl. Sec-Tick), selbst 
wenn Du zu Wartungszwecken o.ä. das Gerät mal zerlegen/abklemmen musst.


Gruss - Sonne
Gast #3177478
Lesenswert?

Ok,
die Idee klingt gut! Vorallem, weil ich da noch genaueres Zeitsignal 
habe. Kannst du da einen Baustein empfehlen? Auf die Schnelle hätte ich 
jetzt mal den DS1307 gefunden, der noch 56 Byte freien nvRAM hat. Da 
gibts auch bei der Bucht paar günstige Module - ja ich glaub, da werd 
ich wohl mal noch ne RTC einbauen ;)
Gast #3177583
Lesenswert?

Bisher habe ich nur mit den MCP79410 (von anderen wurde hier im Forum 
wegen mangelnder Genauhigkeit abgeraten) gearbeitet.

http://www.reichelt.de/ICs-MCP-6-9-/MCP-79410-I-SN/3/index.html?;ACTION=3;LA=446;ARTICLE=109808;GROUPID=5473;artnr=MCP+79410-I%2FSN

Eckdaten:

Preis:       1,10€
Spannung:    1,8V bis 5,5V
EEPROM:      1k
SRAM:        64Byte
Calibration: -127 bis +127ppm digital (also kein Trimm-C!)

weiterhin:
1Hz-Signal-Ausgang
Kalender mit Tag/Monat/Jahr incl. Schaltjahr-Berücksichtigung
einfache Schaltung ohne Trimm-C


Habe damit ein Steck-Modülchen gebaut und ist in diversen Schaltungen 
brav mit dabei.


Gruss - Sonne

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren