Ich habe mich erst vor kurzem mit der Materie Programmierne und Mikrocontroller aus einander gesetzt. ein paar kleine Programme wie drücke Taste1 und Led2 geht an habe ich natürlich auch gemacht. Aber nun habe ich ein etwas sinvolleres programm geschrieben und es scheint auch zufunktionieren. Es ist eine digital Uhr für einen Attiny die man auch einstellen kann;-) Habe an meinem Attiny zwar nur 3 74HC595 drann aber die zeigen das richtige an. Meine Frage ist aber ob das totaler mist ist bzw wo man noch was verbessern kann. Ach ich schreibe in Assembler. Mit C komme ich noch nicht klar. Würde aber auch gern Programme für den Pc schreiben hauptsächlich um RS232 auszulesen.
Wenn du auch die .asm Datei anhängst, dann kann man dir sogar helfen :)
Oh wusste nicht, dass man die auch braucht Hier ist sie
Hi >und es scheint auch zufunktionieren. Da habe ich meine Zweifel. Ich fang mal an: > ldi temp, 0b00100011 ;den zähl wert des timers für ein... > out OCR1AL, temp > ldi temp, 0b11110100 > out OCR1AH, temp Beim Schreiben von 16-Bit-Registern erst H-Teil, dann L-Teil. Beim Lesen umgedreht. >ldi temp, 0b00100011 ist absolut unverständlich. -> ldi temp, High($F423) ldi temp, Low($F423) sieht gleich viel besser aus. Da wir gerade beim Timer sind. Deine Interruptroutine: >sec1: > push temp ; temp sichern Hier fehlt das Sichern von SREG > clr temp > out TCNT1H, temp ; Timer1 zurücksetzen > out TCNT1L, temp > pop temp ; temp wiederherstellen Das kannst du dir sparen, wenn du CTC benutzt .... Hierher käme das Zurückschreiben von SREG >loop2:ret ; Allgemeiner rücksprungbefehl Eine Interruptroutine wird mit reti beendet. So etwas: > ausgabe2: > cpi temp, 0 > breq zif0 > cpi temp, 1 > breq zif1 .... > ; Hier sieht man die LEDs der Segmentanzeige >zif0: ; und die dazugehörige Bit nummer > ldi temp, 0b01110111 ;################################### > rjmp back ;# # macht man über eine Tabelle:
1 | ; Ziffer in temp |
2 | |
3 | ldi ZL,Low(ziffern<<1) |
4 | ldi ZH,High(ziffern<<1) |
5 | clr temp2 |
6 | add ZL,temp |
7 | adc ZH,temp2 |
8 | lpm temp,Z ; Muster nach temp |
9 | .... |
10 | |
11 | ziffern: |
12 | .db 0b01110111,0b00100100 |
13 | .db 0b01011101,0b01101101 |
14 | .db 0b00101110,0b01101011 |
15 | .db 0b01111011,0b00100101 |
16 | .db 0b01111111,0b01101111 |
Das ist noch nicht alles. Lass dich aber nicht entmutigen. Ich habe hier schon viel schlimmeres gesehen. MfG Spess
Solche schreibweisen habe ich noch nie gesehen. Ja und das mit den Einzelnden sprungbefehlen sieht wirklich nicht so gut aus. Und zu der interrupt routine hatte ich aber ein kommentar geschrieben. Ich frage das interrupt flag ab ob es gesetzt ist um zu erkennen, dass eine neue zeit zum ausgeben bereit steht. Das hätte ich aber noch geändert. Aber das mit dieser Tabelle kannst du mir ja erklären. Und sage ruhig was noch so schlimm ist. Ich lerne aus meinen fehlern. Und leider kenne ich keinen der mir das näher beibringen könnte. musste mir ja bis jetzt auch alles selber erarbeiten. (so wie viel denke ich mal)
Hi >Solche schreibweisen habe ich noch nie gesehen. Dann nimm dir mal die Zeit und sieh dir die Hilfe zu AVR-Assembler/AVR-Assembler2 in Ruhe an. >Das hätte ich aber noch geändert. Hellseherischen Fähigkeiten hat meine Frau. Allerdings keine Ahnung vom Programmieren. >Aber das mit dieser Tabelle kannst du mir ja erklären. ziffern: .... Legt eine Tabelle im Programmspeicher an. ldi ZL,Low(ziffern<<1) ldi ZH,High(ziffern<<1) 'ziffer' ist eine Adresse im Programmspeicher. Dort repräsentiert eine Adresse aber einen 16-Bit-Wert (Word). 'lpm' verlangt aber eine Adresse für ein Byte (1/2 Word). 'ziffern<<1' entspricht ziffern*2. clr temp2 ; Null für Addition add ZL,temp ; ZL+temp adc ZH,temp2 ; ZH+Übertrag (Carry-Flag) Das ist die Addition eines Bytes zu einem Word lpm temp,Z ; Muster nach temp MfG Spess
Spess53 schrieb: > ist absolut unverständlich. > > -> ldi temp, High($F423) > ldi temp, Low($F423) > > sieht gleich viel besser aus. @Hyronimus. Wobei hier noch nicht einmal die Notwendigkeit gegeben ist, das in Hex-Zahlen zu schreiben. Wenn, wie dein Kommentar verrät, die Absicht ist, 62499 in das Registerpärchen zu schreiben
1 | ldi temp, 0b00100011 ;den zähl wert des timers für ein sec einstellen (16bit)(62499) |
2 | out OCR1AL, temp |
3 | ldi temp, 0b11110100 |
dann schreib das auch unmittelbar so, dass sich diese Absicht direkt im Code niederschlägt und nicht im Kommentar.
1 | ldi temp, High( 62499 ) |
2 | out OCR1AH, temp |
3 | ldi temp, Low( 62499 ) |
4 | out OCR1AL, temp |
Dem Assembler ist es wurscht, ob du eine Zahl angibst, indem du ihr Bitmuster hinschreibst, oder die entsprechende Hex-Zahl oder gleich dezimal. Es passiert sowieso immer das Gleiche: Das entsprechende Bitmuster wird in das Register geladen. Nur für dich als menschlicher Programmierer macht es einen Riesenunterschied. Ganz abgesehen, dass du nicht selber mühsam die Bits bestimmen musst wobei es wieder 20 Möglichkeiten für Fehler gibt.
Hi >Und zu der interrupt routine hatte ich aber ein kommentar geschrieben. >Ich frage das interrupt flag ab ob es gesetzt ist um zu erkennen, dass >eine neue zeit zum ausgeben bereit steht. Jetzt habe ich erst gesehen, was du da machst. Damit blockierst du bis zu 'reti' alle Interrupts. Dann könntest du die Ausgabe auch gleich in der Interruptroutine machen. Wenn du ein Flag benutzen willst, dann bietet sich das T-Flag in SREG an. Das wird vom Controller nicht beeinflußt und steht zu deiner alleinigen Verwendung. MfG Spess
Vielen Vielen dank für die informationen!! Also die schreibweiße eines word habe ich somit umgehend aufgenommen. Hat mich auch immer genervt das im rechner erst zu dezimal umzurechnen. Das ich die routine mit reti verlasse, werde ich noch ändern da die uhr in RGB mit PWM gebaut werden soll. (Dann aber ein Atmega8) Die Tabelle verstehe ich noch nicht so recht vorallem was die carry addition beeinflusst. Ich werde mir demnächst ein paar schöne bücher bestellen und auf göttliche erleuchtung hoffe ;-)
Hi >Die Tabelle verstehe ich noch nicht so recht vorallem was die carry >addition beeinflusst. Das 'adc ZH,Null' berücksichtigt den Übertrag der Addition 'add ZL,temp'. Beispiel: Z: $00FF temp: $FF ZL + temp = $FE Übertrag: 1 (im Carryflag) ZH + Null + Cy = $01 Ergebnis: Z = $01FE Ohne dieses 'adc' wäre $00FE herausgekommen, was offensichtlich falsch ist. Ausführlich bei ATMEL: http://www.atmel.com/dyn/resources/prod_documents/doc0937.pdf http://www.atmel.com/dyn/resources/prod_documents/avr202.zip MfG Spess
So habe jetzt das ganze mal etwas überarbeitet Die erklärungen treffen jetzt vllt nicht mehr 100% zu aber dafür ist der quelcode nur noch 502byte groß Dank einiger optiemierungen und der Tabelle die ich jetzt so halb verstanden habe. Vielen dank an Spess für die offene kritik. Weiter schreib verbesserungen nehme ich gerne entgegen Bin noch fleißig am Lernen
Sieh dir deine Codeformatierung an. Da liegt noch vieles im argen
Hi >Sieh dir deine Codeformatierung an. >Da liegt noch vieles im argen Richtig. Schalte mal Edit->Show Whitespace. Dann wirst du das Chaos erkennen. Tabulatoren haben im Quelltext nichts zu suchen. MfG Spess
Hi >Vielen dank an Spess für die offene kritik. >Weiter schreib verbesserungen nehme ich gerne entgegen >.def sec01 = r17 ; Einerstelle der Sekunden (0-9) >.def sec10 = r18 ; Zenerstelle der Sekunden (0-5) >.def min01 = r19 ; Einerstelle der Minuten (0-9) >.def min10 = r20 ; Zenerstelle der Minuten (0-5) >.def std01 = r21 ; Einerstelle der Stunden (0-9/4) >.def std10 = r22 ; Zenerstelle der Stunden (0-2) Du benutzt für jede Ziffer ein Register. Ich persönlich würde nur mit Stunden, Minuten und Sekunden arbeiten. Die Zerlegung in Einer- und Zehnerstellen kann man bei der Ausgabe machen. Man braucht dafür auch keine Register, denn du hast auch noch RAM. Und wenn schon Register, dann die 'halbstarken' r0...r15. Ich habe dir mal eine Datei mit Routinen angehängt, mit denen du sogar einen Wecker programmieren kannst, der dich schlafen lässt, wenn in deinem Bundesland Feiertag ist. Das Einzige, was noch fehlt ist die Sommer-/Winterzeitumstellung. Ist schon angefangen, aber irgendwie liegen geblieben. Vielleicht hilft es dir. Die DateTime.mac (Makros) ist nur der Vollständigkeit halber dabei. MfG Spess
Oh man dein quelltext ist ja sehr umfangreich. Mit dem sram habe ich noch nie gearbeitet. Werde mich da gleich mal einlesen. Und warum sollte man keine tabulatoren im quelltext verwenden?? Funktioniert doch oder was ist daran falsch.
Hyronimus Herzberg schrieb: > Und warum sollte man keine tabulatoren im quelltext verwenden?? Weil jeder eine andere Vorstellung davon hat, nach wievielen Schritten eine Tabulatorposition einzufügen ist. > Funktioniert doch oder was ist daran falsch. Sieh dir deinen Code weiter oben mal hier im Forum an! Mach beide Versionen auf (ohne und mit automatischer Codeformatierung) und sieh dir mal an, wie da die Einrückungen sind. Sonderlich zuträglich zum Verständnis des Codes ist es gerade nicht, wenn sich alle 2 Seiten das Einrückschema verändert. Dazu auch noch eine Beobachtung: Interessanterweise sind es sehr oft die mit dem allgemein annerkannt grauslichstem Code, die die meisten Fehler in ihren Programmen haben. Und das beschränkt sich nicht nur auf Assembler, das ist in anderen Programmiersprachen genau gleich: Die mit dem Kraut und Rübencode haben meistens die dummen Fehler.
Hi >Oh man dein quelltext ist ja sehr umfangreich. Das kommt dir nur so vor. >Mit dem sram habe ich noch nie gearbeitet. >Werde mich da gleich mal einlesen. Ist eigentlich relativ einfach:
1 | |
2 | .dseg ; Datensegment |
3 | |
4 | aaa: .byte 1 ; ein Byte reservieren |
5 | |
6 | .cseg ; Codesegment |
7 | |
8 | .... |
9 | |
10 | ldi r16,$FF |
11 | sts aaa,r16 ; $FF in aaa speichern |
12 | |
13 | lds r17,aaa ; Inhalt von aaa nach r17 |
MfG Spess
Ich habe meine quelltext nochmal komplett überarbeitet und statt register nun mit dem sram gerechnet. also code ersparniss hatte ich jetzt nocht so viel aber etwas. Habe erst mal die programmierung der uhr rausgeschmissen um das mit dem sram hin zubekommen aber meine uhr zeig nichts mehr an. Da ich es nicht schaffe die werte des sram aufzuteilen also wenn da gespeichert ist "23" brauche ich zuerst die 3 und dann die 2 zum senden. aber ich kann das mathematisch nicht lösen das dass mit allen zahlen funktioniert. Dies ist im "rcall ausgabe". Solche tricks kenne ich einfach noch nicht.
Ich habe ne lösung. Ich subtrahier immer 10 und für jedesmahl zähle ich ein anderes register hoch bis zum carry flag und dann einmal plus 10 und das andere wieder eins runter.
Hi >Ich habe ne lösung. Ich subtrahier immer 10 und für jedesmahl zähle ich >ein anderes register hoch bis zum carry flag und dann einmal plus 10 und >das andere wieder eins runter. Ich wollte dir gerade eine Routine dafür schicken. Aber wenn du selbst darauf gekommen bist, um so besser. Lange niemand hier erlebt, der sich so intelligent anstellt. MfG Spess
Vielen dank. Habe mir nen zettel genommen und die ein paar zahlen als binär und dezimal hingeschrieben und dann die ganze rol und und xor opperationen ausprobiert bis ich dann das subi genommen habe. hatte noch einen kleinen fehler hatte vergessen das temp4 zu löschen aber jetzt läuft die uhr wieder. könnte mit push und pop sogar temp4 sparen mal schauen ob ich das machen muss. ist es so mit der formatierung halbwegs inordnung?
Hi
>ist es so mit der formatierung halbwegs inordnung?
Sieh das nicht so eng. Ich persönlich bin es seit den 8-zigern des
vorigen Jahrhunderts gewohnt, das Labels, Code und Kommentare jeweils in
einer 'Spalte' stehen und eine Zeile Label, Code und Kommentar enthalten
kann. Und dabei bleibe ich auch. Weitere Einrückungen, wie bei höheren
Programmiersprachen machen, meiner Meinung nach, wenig Sinn. Nur sollte
es einheitlich sein. Mit einer Einschränkung: wenn Labels und Code
permanent am linken Rand kleben finde ich das extrem unübersichtlich.
Mach dir einen Reim daraus.
MfG Spess
Habe mir dein Datetime mal angeschaut und das sieht wirklich besser aus. Denke das ich mir das auch noch angewöhnen werde. Mit einem unterschied Das Label bleibt eine Zeile drüber finde ich hübscher;-) Ich möcht mich aber bei dir schon mal bedanken für die vielen tipps! Werde jetzt noch die 8 kanal RGB PWM versuchen zu integrieren mittels SPI und wenn ich da nicht weiter komme melde ich mich noch.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.