Abend,
ich arbeite gerade an einer Wasserstandsmessung für einen Bach. Das
Programm ist schon sehr umfangreich und leider noch schlecht
kommentiert. Deshalb denke ich nicht, dass es was bringt wenn ich es
hochlade. Es läuft alles so wie es soll nur nach ca. 15-20 Minuten geht
auf einmal gar nichts mehr. Dann hilft nur noch ein Reset oder den Strom
auszuschalten. Woran kann das den liegen? Es ist ein Atmega 32 mit 4MHz
interner Takt auf einem STK500. Ich lesen den Messwert über TWI ein und
schreibe alle 15 Minuten auf eine TWI EEPROM. Die Uhrzeit kommt vom
DCF77-Empfänger. Die 15 Minuten sind nicht deckungsgleich mit dem
Absturz. Am Atmega hängt noch ein LCD, außerdem nutze ich den ADC7 den
INT2 und alle drei Timer. Mir ist das Problem bisher nicht aufgefallen
weil er nie solange am Stück lief.
Am Watchdogtimer kann es nicht liegen der ist aus und außerdem ist die
Zeit doch viel zu groß, oder?
Gruß Michael
Michael Mayer schrieb:> Mir ist das Problem bisher nicht aufgefallen> weil er nie solange am Stück lief.
Du hast ein umfangreiches Programm geschrieben, das im
Viertelstundentakt Aktivität entwickeln soll, es aber nie auch nur eine
Viertelstunde lang laufen lassen?
Beeindruckend.
Du hast das Problem schon gelöst:
> Das Programm ist schon sehr umfangreich und leider noch schlecht> kommentiert.
Du solltest das Programm nicht kommentieren, sondern den Code so lesbar
hinschreiben, daß Du auf Kommentare verzichten kannst. Kommentare sind
nicht zur Erklärung des Code, sondern zur Dokumentation von
Designentscheidungen.
Mein Tip: Versuche das Programm so lesbar zu gestalten, daß Du es selbst
verstehst. Wenn Du das gemacht hast, dann poste Deinen Code und wir
können Dir weiterhelfen.
mfg, Stefan.
> Du hast ein umfangreiches Programm geschrieben, das im> Viertelstundentakt Aktivität entwickeln soll, es aber nie auch nur eine> Viertelstunde lang laufen lassen?
Ich hab immer nur die erste viertel Stunde abgewartet da ist es nie
aufgetreten. Und es soll nicht alle 15 minuten etwas tun sonder immer um
xx:00 xx:15 xx:30 und xx:45 Uhr deshalb auch DCF77. Ich hab mir schlecht
ausgedrückt.
>Stacküberlauf?
Wie kann ich das testen? Aber dann müsste die Zeit doch auch immer
gleich sein. Sie schwankt aber zwischen 15 und 20 Minuten.
Gruß Michael
Stefan May schrieb:> Mein Tip: Versuche das Programm so lesbar zu gestalten, daß Du es selbst> verstehst. Wenn Du das gemacht hast, dann poste Deinen Code und wir> können Dir weiterhelfen.>> mfg, Stefan.
Ich verstehe mein Porgramm schon. Nur denke ich das es für euch schwer
werden kann, da ich bestimmt einiges unkonventionell gelöst habe, bin
noch Anfänger.
Ohne Programmanalyse kann man da so gut wie gar nichts sagen. Der Fehler
kann überall sein.
Fang ein neues Programm an.
Dort übernimmst du nacheinander Teile aus deinem jetzigen Programm und
machst nach jeder Übernahme Langzeittests. Ein vorhergehendes Abklappern
der jeweils zu übernehmenden Programmteile nach offensichtlichen Fehlern
ist allerdings auf jeden Fall ratsam.
Michael Mayer schrieb:> Stefan May schrieb:>> Mein Tip: Versuche das Programm so lesbar zu gestalten, daß Du es selbst>> verstehst. Wenn Du das gemacht hast, dann poste Deinen Code und wir>> können Dir weiterhelfen.>>>> mfg, Stefan.>> Ich verstehe mein Porgramm schon.
Große Worte :-)
> Nur denke ich das es für euch schwer> werden kann,
Du kannst dir gar nicht vorstellen, mit welchen Programmgrößen und
abstrusen Ideen die Profis hier Tag für Tag zu tun haben. Mach dir
deswegen keine Sorgen.
Und wenn, dann zeigen dir die Leute hier schon, wie man die Dinge besser
lösen kann.
> da ich bestimmt einiges unkonventionell gelöst habe,
und das ist meistens eine schlechte Idee. Vor allem wenn man Anfänger
ist.
>Große Worte :-)
War vllt. etwas hoch gegriffen. Ich glaube es zu verstehen.
Und hier mal das ganze Programm ich hoffe es ist verständlich. Sonst
einfach fragen.
Und schon mal danke euch allen das ihr euch so bemüht.
Assembler für ein Projekt dieser Größe? Bist du Masochist?
Na dann viel Spass, wo du ein Register zu pushen/poppen vergessen hast
bzw. den Stack in Unordnung gebracht hast.
Ich kann leider nichts anderes und wir machen in der Ausbildung und in
der Schule auch nur ASM.
Den Tipp mit dem neuen Programm werde ich morgen oder übermorgen machen.
Karl Heinz Buchegger schrieb:> Na dann viel Spass, wo du ein Register zu pushen/poppen vergessen hast> bzw. den Stack in Unordnung gebracht hast.
Insbesondere, wenn eine Unterroutine wie z.B. der int2_handler zig
Rücksprünge hat. So ein Assembler-Programm kannst du nur beherrschen,
wenn du in einer Unterroutine genau 1 Eintritts und 1 Austrittspunkt
hast. Alles andere mag zwar trickreich, schnell und speichersparend
sein, es führt garantiert zum Chaos...
Autsch.
Du hast vieles durch endlose hin- und herspring-Orgien gelöst. Das ist
Spaghetticode erster Sahne und wahnsinnig schwer nachzuvollziehen, wie
da der Kontrollfluss durch deinen Code läuft, was gerade am Stack liegt,
welche Register wo gebraucht werden, welche frei sind etc.
Die Dinge wären einfacher, wenn du dir Subroutinen bauen würdest, die
mittels rcall oder call aufgerufen werden und mittels ret zu ihrer
Aufrufstelle zurückkehren.
Michael Mayer schrieb:> Das Programm ist schon sehr umfangreich und leider noch schlecht> kommentiert. Deshalb denke ich nicht, dass es was bringt wenn ich es> hochlade.
Dagegen ist es unmöglich, Fehler in einem Programm zu finden, was man
nicht einmal kennt. Wie stellst du dir das vor?
Ne Frage aus Interesse: Wieviel Flashspeicher frisst der Wurschtelcode
schon?
Naja, der einfachste Weg aus deinem Dilemma ist eigentlich:
Karl Heinz Buchegger schrieb:> Fang ein neues Programm an.
Schreibe Unterfunktionen, die sich auf ihre Sachen konzentrieren (was
hat adc_read mit der PORT-Ausgabe zu tun?)
So werden die Funktionen kleiner, und du gerätst nicht in Versuchung,
wild durch die Gegend zu hüpfen.
Im Hautprogramm rufst du dann nur noch diese Funktionen auf. Außerdem
solltest du die mal mit Flashtabellen anfreunden, dann sind so
EEPROM-Geschichten mit festen Datensätzen 2-Zeiler. :-)
Und ganz wichtig, testen.
Nach kurzem Überfliegen fiel mir folgendes direkt auf:
1
wert_aktuell:
2
in temp, sreg
3
push temp
4
push temp1
5
push temp2
6
push temp3
7
8
cpi anzeige, 1
9
brne loop
Muss jetzt nicht 'der' Fehler sein, aber viele solcher Sprünge hält der
Stack nicht aus.
Ist wohl auch ein gutes Beispiel, für das, was die Leute vorher meinten
bzgl. Strukturierung.
Die LCD-Routinen in einer ISR aufrufen ist nicht gerade eine gute
Lösung, da diese sehr viel Zeit in Anspruch nehmen und du immer noch in
einer ISR hängst.
Mark
Hi
Assembler muss nicht unbedingt ein Problem sein. Allerdings würde ich
die Interruptroutinen mal unter die Lupe nehmen und nachsehen, ob alle
Bearbeiungen innerhalb der ISR notwendig ist. Ich hab mal den Code
überflogen.. Auszug aus
Bist du sicher, das du all die Programmschritte innerhalb der ISR
erledigen mußt., einschließlich der Unterprogrammaufrufe ?
Soweit ich es sehe, ist diese ISR doch nur zur Erfassung eines
Ereignisses. Also setz dir ein Bit und arbeite dies in der
Programmschleife ab. Dadurch behälst du den Überblick und du kommst
nicht in Versuchung, ein ungerettetes Register über den Umweg RCALL ...
zu verwenden, denn auch die so aufgerufenen Programmteile kommen aus der
ISR. Ich hab es nicht überprüft, falls du doch daran gedacht hast.
Ich gehe da so vor
1
irgend_ein_Interrupt:
2
push temp
3
in temp, sreg
4
push temp
5
Lds Temp, ISR_Flag
6
Ori Temp, 0b00000001
7
STS ISR_Flag, Temp
8
POP Temp
9
Out SReg, Temp
10
POP Temp
11
RETI
um dann in der Programmschleife das Bit in ISR_Flag zu testen, die
entsprechenden Routinen aufzurufen und das Bit zu löschen. Hilfreich ist
gerade für solche Anwendungen mein kleines Tool OpenEye. Du findest hier
irgendwo den Download und die Beschreibung dazu. Es liefert dir zur
Laufzeit die Variablenwerte über RS 232 auf den PC zur Ansicht.
Grß oldmax
Ein Programm, dass alle 15 min was mache soll braucht einen Timer
bestenfalls als Zeitbasis, sonst gar nichts. Der Rest erfolgt einfach
und umkompliziert in der Hauptschleife, siehe Interrupt. Die meiste
Zeit verbringt der Controller im Sleep Mode.
DFC77 nutzt man nur, um vielleicht einmal am Tag seine interne Uhr zu
synchronisieren, keinesfalls um dauerhaft eine Zeitbasis daraus
abzuleiten. Denn dazu ist der Empfang viel zu unberechenbar. Kann auch
ein Grund für den Absturz sein.
Siehe AVR - Die genaue Sekunde / RTC
> Ich kann leider nichts anderes> und wir machen in der Ausbildung und in der Schule auch nur ASM.
Hm, ist dieser Programmierstil wirklich das was man so in der Schule
lehrt und lernt ???? *** schauder ****
@ Wegstaben Verbuchsler (wegstabenverbuchsler)
>Hm, ist dieser Programmierstil wirklich das was man so in der Schule>lehrt und lernt ???? *** schauder ****
Vielleicht haben die einen italienischen Informatiklehrer?
"Ise programire die Controller so wie meine Mama machte die Spaghetti. .
."
;-)
@ Michael Mayer (eos400dman)
> * Main.asm (20.5 KB, 68 Downloads) | Codeansicht> * adc2.asm (1.2 KB, 16 Downloads) | Codeansicht> * dcf77dec.asm (3.8 KB, 17 Downloads) | Codeansicht> * eeprom_logdaten_schreiben.asm (5.4 KB, 17 Downloads) | Codeansicht> * EEPROM_routine.asm (1.2 KB, 7 Downloads) | Codeansicht> * extrem_wert.asm (5.5 KB, 16 Downloads) | Codeansicht> * lcd-routines.asm (8.9 KB, 16 Downloads) | Codeansicht> * Messvorgang.asm (2.4 KB, 15 Downloads) | Codeansicht> * twi_routine.asm (1.4 KB, 8 Downloads) | Codeansichthttp://www.mikrocontroller.net/articles/Bildformate#Mehrere_Dateien_zusammenfassen>War vllt. etwas hoch gegriffen. Ich glaube es zu verstehen.
Wer glaubt zu wissen, muß wissen er glaubt.
>Und hier mal das ganze Programm ich hoffe es ist verständlich.
Teils teils.
http://www.mikrocontroller.net/articles/Strukturierte_Programmierung_auf_Mikrocontrollern#Benennung_von_Variablen.2C_Makros.2C_Nutzung_von_Anweisungen
Gerade bei Assembler muss man ausgiebeig kommentieren. Das geht los bei
einer Funktionsbeschreibeung für JEDE Funktion bis hin zu Kommentaren
für fast jede Zeile, wenn es eine knifflige Funktion ist.
Der Hammer ist natürlich die Sache mit anzeige1-7. Du schreibst jetz
100mal in Schönschrift.
"Eine Funktion ist eine Funktion und wird IMMMER mit (R)CALL augerufen
und RET verlassen!"
Wenn gleich es hier funktioniert, so wirst du dier mit diesem
Kauderwelsch ganz fix ins Knie schiessen.
Und was macht INT2? Hängt dort ein Taster dran? Mit dem amn die Anzeige
weiterschalten kann? Die Ausgabe dort ist ganz schlecht, denn
währenddessen sind dein Ineterrupts gesperrt. Solche langsamen,
zeitunkritischen, geradezu nebensächlichen Ausgaben macht man in aller
Ruhe in der Hauptschleife. Ausserdem muss so ein Taster entprellt
werden, siehe Entprellung. Macht man meist sinnvollerweise in
Software in einem Timer-Interrupt.
Es ist ja auch sch, dass du versucht Interrupts zu nutzen, aber man kann
es auch überteiben. Für das bischen Messung braucht man keinen
ADC-Interrupt, macht die Sache nur unnötig komplex und bringt kaum was.
Nimm einer normale Funktion.
Vor allem in ASM sollte man mit RJMP sparsam umgehen. Praktisch nur für
Verzweigungen nach Vergleichen und ähnliches. Ansonsten packt man alles
in Funktion und nutzt (R)CALL.
MFG
Falk
Wegstaben Verbuchsler schrieb:>> Ich kann leider nichts anderes>> und wir machen in der Ausbildung und in der Schule auch nur ASM.>> Hm, ist dieser Programmierstil wirklich das was man so in der Schule> lehrt und lernt ???? *** schauder ****
In der Schule lernt man in der Regel gar keinen Programmierstil.
@Simon K. (simon) Benutzerseite
>In der Schule lernt man in der Regel gar keinen Programmierstil.
Naja, würde ich nicht so sagen. Ich hab damals schon ein paar
grundlegend richtige Programmiertechniken gelernt bekommen, auch wenn
ich sie nur widerwillig angenommen habe ;-)
Als Basic-Programmierer dann in Pascal plötzlich das geliebte GOTO nicht
mehr nutzen zu dürfen war schon hart. Aber am Ende hat die Vernunft
gesiegt.
MFG
Falk
Hi
Nun, hoffe, ihr habt euch jetzt ausgetobt.....
Haben wir nicht alle mal klein angefangen und mal ehrlich, sind eure
esten Programme gleich perfekt gewesen ? Grabt mal in euren (ur) alten
Unterlagen und es wird euch schaudern. Er wird schon feststellen, das
man nicht alles in einer ISR machen muß, was die ISR auslöst. Aber dazu
muß er wissen, das ein (sehr ) schnelles Eeignis nur erfaßt und später
reagiert werden kann. So ein Controller ist schon ein fixes Teil, aber
einen kleinen Pieks auf der Leitung ist beim Pollen schon mal
durchgewischt..
>Als Basic-Programmierer dann in Pascal plötzlich das geliebte GOTO nicht>mehr nutzen zu dürfen war schon hart.
Obwohl die ersten Pascals noch ein Goto hatten... (warum wohl ?)
Gruß oldmax
Da muss ich mich oldmax anschliessen. Meine ersten Gehversuche mit eine
AVR168 erschrecken mich vom Stil heute auch. C sei Dank hat mehr
funktioniert als ich heute glauben möchte.
Meinen Respekt dafür das Du es in ASM soweit geschafft hast.
Evtl. ist jetzt, wo Du wirklich mit der Anwendung vertraut bist der
richtige Zeitpunkt am weissen Blatt Papier die Aufgaben zu
strukturieren. Wenn das gut gemacht ist, ist es einigermassen egal ob Du
das in ASM, C, Java, Basic oder sonstwas umsetzen willst.
Vergeblich ist die in den Code gesteckte Zeit mit Sicherheit nicht
gewesen.
viel Erfolg
Hauspapa
Als ich 1986 (oder so) von gwbasic auf Turbo Pascal 3.0 umgestiegen bin,
war ich froh, endlich diese blöde Zeilennummerierung los zu sein und
(ohne debug.exe und "a") .COM-Dateien machen zu können. :D
Das GOTO habe ich von Anfang an nie vermisst.
Michael Mayer schrieb:> ich arbeite gerade an einer Wasserstandsmessung für einen Bach.
Da die Aufgabenstellung klar ist und die Lösung im Grunde funktioniert,
würde ich die Probleme mit ASM als Anlaß nehmen, auf 'C' umzusteigen.
Alles ist viel einfacher und transparenter, kein Vertun mit byte, int,
long und deren Vergleichsoperationen und bedingten Verzweigungen; kein
Problem mit der Formulierung irgendwelcher Berechnungen.
Was mit ASM 20 Zeilen brauchte, steht in einer Zeile und ist leicht
verständlich.
Nach ein bißchen Einarbeitung wirst Du 'C' als Segen empfinden!
Hi
>Was mit ASM 20 Zeilen brauchte, steht in einer Zeile und ist leicht>verständlich.
Und erzeugt Code wie 50 Zeilen Assembler (musste sein).
Strukturierte und lesbare Programmierung ist auch in Assembler möglich.
Michael hat versucht mehrere Programme/Programmfragmente zu einem
großen, wobei groß relativ ist, Programm zusammen zu pappen und ist
mangels Know How etwas gescheitert. Sein Code lässt sich bei halbwegs
geschickter Programmierung auf mindestens die Hälfte reduzieren. Seine
'adc2.asm' kann man (getestet) mit weniger als 30 Programmzeilen (gegen
78) realisieren. An etlichen anderen Stellen sieht es ähnlich aus.
Aber kein Grund die Flinte ins Korn zu werfen.
MfG Spess
Frank Q. schrieb:> ..., auf 'C' umzusteigen.
Ich würde eher sagen: "Die Menge der nutzbaren Werkzeuge um C zu
erweitern."
Mit einem Traktor kann man kein Formel-1 Rennen gewinnen und mit einem
Formel-1 Boliden kann man keinen Pflug über das Feld ziehen. Will sagen:
Jedes Werkzeug dafür, wofür es am besten geeignet ist. Wenn man ein
kleines Programm schreibt, das zu einem hohen Anteil an einzelnen Bits
herumfummelt und bei dem genaues Timing wichtig ist, ist Assembler die
richtige Wahl. Wenn man hingegen ein Programm schreibt, das komplexe
Abfolgen abbildet, nimmt man eher C. C ist nicht besser als Assembler
und Assembler ist nicht besser als C.
Noch etwas: Wenn ein Programmieranfänger mangels Führung und Hilfe ein
unübersichtliches Riesenmoloch an Programm schreibt, ist das keine
Blamage, sondern ein Hinweis darauf, dass derjenige "heiß" darauf ist,
geile Programme zu hacken und vor großen Aufgaben nicht zurückschreckt.
:-) Daumen hoch!
@ Frank Q. (franki)
>würde ich die Probleme mit ASM als Anlaß nehmen, auf 'C' umzusteigen.
Ich nicht. Er kann die Grundprinzipien der strukturierten Programmierung
an diesem Beispiel auch und besonders in ASM umstetzen. Dazu muss er
nicht den Code wegschmeißen und neu schreiben, aber halt mal gescheit
strukturieren. Und das halt vor allem durch Nachdenken mit dem berühmten
Blatt Papier.
>Alles ist viel einfacher und transparenter, kein Vertun mit byte, int,>long und deren Vergleichsoperationen und bedingten Verzweigungen;
Wenn das mal kein Irrtum ist. Wieviele Leute/Anfänger fallen auf die
impliziten INT Konstanten rein . . .?
Taufrisch
Beitrag "unsigned long int Berechnung"
Das man mit C sich viel Krümelkram von Hals hält und deutlich höhere
Komplexitäten mit deutlich weniger Aufwand beherrschen kann steht ausser
Frage.
MFG
Falk
Falk Brunner schrieb:> Dass man mit C sich viel Krümelkram von Hals hält und deutlich höhere> Komplexitäten mit deutlich weniger Aufwand beherrschen kann steht ausser> Frage.
Und darum geht es doch wohl!
spess53 schrieb:> Und erzeugt Code wie 50 Zeilen Assembler (musste sein).
Und weil heutige Compiler recht gut optimieren, ist auch die Codegröße
des fertigen Programmes voll in Ordnung. (mußte auch sein :-)
Mindstens der Pfad hier geht schief, weil mehr gepusht wird als gepopt:
wert_aktuell: push
loop:
messen_sprung:
messen: push+pop
extrem_wert: push+pop
wert_aktuell: push
Michael Mayer schrieb:> wir machen in der Ausbildung und in> der Schule auch nur ASM
Damit hat sich hier wohl die (übliche) Streiterei um C/ASM erübrigt, bzw
sollte mit dem entsprechenden Lehrer weitergeführt werden. 'C' zu nehmen
ist hier wohl so ein sinnvoller Vorschlag wie jemandem bei Problemen in
Algebra ein Stochastik-buch zu empfehlen ;-)
Aber mal konkret zum Thema:
Ich denke(nach Durchsicht des gesamten Codes), außer dem o.g. Fehler in
'wert_aktuell' sehe ich zumindest keine strukturellen Probleme, auch
wenn ich jetzt nicht überprüft habe, ob zu jedem push auch das pop
vorhanden ist.
Nimm die PUSHs und POPs aus der 'wert_aktuell', die sind im Zusammenhang
überflüssig und das 'brne loop' füllt da es die 'pop's überspringt nach
und nach den Stack. Wenn ich das richtig sehe, wird 'counter' alle
256.000 Takte inkrementiert, alle 15-mal landet das in der
'wert_aktuell'-Routine (ca. 1/sec) und holt dann ggf. 4 bytes nicht vom
Stack, das Ganze 512-mal und der SRAM ist voll (nachdem alle
gespeicherten Werte überschrieben wurden).
Ich habe mich nicht genau in den ganzen Programmablauf eingedacht, aber
die Zeit mit 15-20 Minuten bis Absturz könnte passen. Durch die langen
ISRs wird ggf. der Timer0ovfl mal übersprungen.
BTW: ich habe '84 schon Lehrer zur Verzweifelung getrieben wenn ich die
Aufgaben außer in Pascal auch in Assembler abgegeben habe (der Größen-
und Geschwindigkeitsvergleich war wohl 'etwas' hart für die Leute)
Mark
>'adc2.asm' kann man (getestet) mit weniger als 30 Programmzeilen (gegen>78) realisieren.
Kannst du das bitte mal hoch laden?? Wäre echt net.
>sondern ein Hinweis darauf, dass derjenige "heiß" darauf ist,>geile Programme zu hacken und vor großen Aufgaben nicht zurückschreckt
Finde ich auch. Lieber ist es nicht top strukturiert aber ich versuche
es hinzu bekomme als wenn ich gleich aufgebe und es sein lasse.
ich mach mich jetzt mal an die Umsetzung der Tipps.
Gruß Michael
Hi
>Kannst du das bitte mal hoch laden?? Wäre echt net.
Gern:
1
adc_holen:
2
push r16
3
in r16,SREG
4
push r16
5
push r17
6
push r18
7
push ZL
8
push ZH
9
10
in r18,ADCH
11
12
clr r16
13
ldi ZL,Low(limits<<1)
14
ldi ZH,High(limits<<1)
15
16
adc_holen10:
17
lpm r17,Z+
18
cp r18,r17
19
brcc adc_holen20
20
21
sec
22
ror r16
23
rjmp adc_holen10
24
25
adc_holen20:
26
out PortA,r16
27
28
pop ZH
29
pop ZL
30
pop r18
31
pop r17
32
pop r16
33
out SREG,r16
34
pop r16
35
reti
36
37
limits: .db $FF,$EA,$D5,$C0,$A8,$90,$70,$00
Der Code basiert allerdings auf der Annahme eines Fehlers in deinem
Programm. Bei deiner Abfrage
> cpi temp, $70> brsh zwei_an> cpi temp, $69> brlo eine_an
ist zwischen $6F und 69 eine 'Lücke', bei der nichts ausgegeben wird.
Ich gehe davon aus, das das nicht beabsichtigt war.
MfG Spess