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!
Das einzige echte Problem, das ich auf die Schnelle sehen kann, befindet
sich hier
1
voiduart_putf(floatdata){
2
charbuffer[7];
3
uart_puts(dtostrf(data,7,2,buffer));
4
}
bzw.
1
voidlcd_putf(floatdata,uint8_tdigits){
2
charbuffer[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.
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:
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
Thinksilicon schrieb:> Hab jetzt auch noch eine kleine routine drin, die die Arbeit alle 10> Minuten im EEPROM speichert,
Tipp: Das EEPROM kann man nicht beliebig oft beschreiben, nach x mal
geht es kaputt. Das Datenblatt gibt über das x Auskunft.
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
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 ;)
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