Hallo Community, Hier führe ich den Post weiter, der nach der Frage der Programmiersprache angefangen hat. Folgendes Projekt. Ein µC, Atmel ATMega 168A soll diese Aufgaben lösen: Eingangssignal 4...20mA digital Wandeln und in 10 Schaltstufen auflösen,á 1,6 mA je nach ermittelter Schaltstufe sollen bestimmte Telegramme über den UART ausgegeben werden. Das schaut so aus: [Startbyte] [Adressbyte] [Kommandobyte] [Datenbyte] [Checksum] 0x00 0xFF 1x9C var var Ich habe bisher einen Code geschrieben, welcher zuerstmal das Senden über den UART nach Bedingung PIN Eingang x = 1 realisieren soll. Der ADC ist noch außen vor. Ich bitte ein Expertenauge mal über den Code zu schauen und mir eine Meinung, Fehler, oder Verbesserungsvorschläge mitzuteilen.
Hi >Eingangssignal 4...20mA digital Wandeln und in 10 Schaltstufen >auflösen,á 1,6 mA Was ist mit <4mA? MfG Spess
Noch ein kleiner Hinweis: Wenn du deiner Assemblerdatei beim nächsten Mal die Endung .asm verpasst, wird für den Anhang automatisch ein Link "Codeansicht" generiert, der den Code in buntig anzeigt (s. Beispiel).
kleiner 4 mA muss verworfen werden als ungültiges Signal. Für die Steuerungstechnik ein Drahtbruchmelder. 0mA muss Alarm geben.
Yalu X. schrieb: > Noch ein kleiner Hinweis: Wenn du deiner Assemblerdatei beim nächsten > Mal die Endung .asm verpasst, wird für den Anhang automatisch ein Link > "Codeansicht" generiert, der den Code in buntig anzeigt (s. Beispiel). Danke Yalu. Nächstes mal. ;)
Markus schrieb: > Hier nochmal als asm ist eigentlich bei Assemblerprogrammen Komentar verpönt, oder gar verboten und führt zu einem Übersetzungsfehler wegen zu einfacher Verständlichkeit? Daß bei einer prozeduralen Hochsprache (welcher Komplexität auch immer) durch geschickte Wahl von Objektnamen, und durch geschickte Textformatierung Kommentare häufig überflüssig sind, ist ja "bekannt". Bei diesen Assembler-Buchstabensalat würde ich jedoch nach 2 Tagen nicht mehr wissen, wofür das ganze war und wie es funktioniert.
Dachte der Experte Überblickt auch ohne Kommentare die Funktion. Ich werde Kommentare einfügen sobald ich wieder am PC bin. Markus
Markus schrieb: > der Experte Überblickt auch ohne Kommentare die Funktion. der Experte blickt nur auf Funktionen mit Kommentaren ;-)
Hi >Stufe_0: >ldi cmd, 0x80 >ldi cs, 0x1B >rjmp UART_Send Wie kommst du eigentlich auf die Checksumme? MfG Spess
spess53 schrieb: > Wie kommst du eigentlich auf die Checksumme? > > MfG Spess alle Bytes addieren, den Überlauf ignorieren. Bin mir nicht sicher wie die CS sich bei Carry verhält. Hast du einen anderern Ansatz zur Berechnung?
Hi >Bin mir nicht sicher wie die CS sich bei Carry verhält. $FF + $10 = $0F + CY. Also wäre dein CS = $0F >Hast du einen anderern Ansatz zur Berechnung? XOR-Vernüpfung. MfG Spess
Hallo, also in deiner UART_send: um einen Wert in ein Register zu laden musst du ldi temp,0x00 schreiben! bei checkTXR: ldi temp, UCSR0A ;falsch >lds temp, UCSR0A ;richtig Alle I/O-Register, die mit IN/OUT erreichbar sind, sind in den Definitionsdateien auch mit diese Adresse hinterlegt. Wenn du auf ein solches Register mit LDS/STS zugreifst, musst du 0x20 zur definierten I/O-Registeradresse dazurechnen. Und ja Kommentare sind in ASM-Code sehr willkommen, sonst weißt du selbst nach ein paar Wochen nicht mehr was dein Code machen soll, und andere schon gar nicht. Sascha
Moin! Wie sieht eigentlich die Hardware aus? In meinem Beispiel habe ich ADC0 als Eingang gewählt und unterstelle einen Shunt von 47Ω. Ich hänge das File hier nun in der kurzen und unkommentierten Form an. Sollte die lange Form erwünscht sein, reicht eine kurze Nachricht hier. Wie gesagt, ist ungetestet, läuft aber ohne Protest durch den Kompiler. Sascha Weber schrieb: > Und ja Kommentare sind in ASM-Code sehr willkommen, sonst weißt du > selbst nach ein paar Wochen nicht mehr was dein Code machen soll, und > andere schon gar nicht. ;-) Gruß Jobst
Jobst M. schrieb: > Sascha Weber schrieb: >> Und ja Kommentare sind in ASM-Code sehr willkommen, sonst weißt du >> selbst nach ein paar Wochen nicht mehr was dein Code machen soll, und >> andere schon gar nicht. > > ;-) ...und du merkst beim Schreiben der Kommentare, dass der Code nicht das tut, was er sollte! Mir jedenfalls hilft das Kommentieren während des Codens manchmal auf die Sprünge. :)
ich habe meinen Code mit Kommentaren geschrieben ;-) Gruß Jobst
Bahnhof. ;-) Kannst du mal die lange Version Posten bitte? Danke &, Gruß Markus
Hi Nun, da wundert mich nicht, wenn Assembler den Ruf hat, nicht erweiterbar zu sein. Sicherlich sind Sprünge in abgesetzte Routinen nicht notwendig, erleichtern aber das Arbeiten ungemein. Wird mit kleinen Programmsequenzen gearbeitet, läßt sich ein Code nicht nur wesentlich besser aufbauen, er läßt sich sogar prima pflegen. Im Prinzip :
1 | Reset: |
2 | JMP INIT ; Sprung über die IVT zu Init |
3 | |
4 | Init: |
5 | ; alles, was parametriert werden muß. z.B. |
6 | CALL INIT_UART |
7 | CALL INIT_I_O |
8 | CALL INIT_Timer |
9 | Loop: ;(Main oder was sonst noch auf's Hauptprogramm zutrifft) |
10 | CALL Read_IO ; Lesen der Eingänge |
11 | CALL Debounce ; entprellen und Flankenbits setzen |
12 | CALL Read_Uart ; Ringpuffer Empfang prüfen |
13 | CALL Chk_Event ; Ereignisbearbeitung |
14 | CALL Set_Job ; Ausgaben aufbereiten |
15 | CALL Write_IO ; Ausgaben zuweisen |
16 | CALL Send_Uart ; Senden der Ergebnisse |
17 | JMP Loop |
Auch wenn es den Code geringfügig aufbläht, durch diese Aufrufe erhält man Codebereiche, die einzeln gut zu prüfen sind. Die Informationen können über Variablen oder Registerinhalte durchgereicht werden. Ich persönlich bevorzuge eine solche Struktur, da sie mir erlaubt, ein Programm schrittweise aufzubauen und dabei den Überblick zu behalten. Ellenlange Codeabschnitte sind nicht grad das gelbe vom Ei. Außerdem lassen sich solche "Unterprogramme" sehr gut dokumentieren, in dem man am Anfang mit Kommentarzeilen die Funktion und die verwendeten oder aufbereiteten Variablen schreibt.
1 | ;*********************************** |
2 | ;* Read_IO list die Eingänge * |
3 | ;* und sschreibt diese in die * |
4 | ;* Variable New_In * |
5 | ;*********************************** |
6 | Read_IO: |
7 | |
8 | Ret |
Ab jetzt interessieren nicht mehr die Portbits. In New_In sind die Bits völlig anders zugeordnet. Dadurch ist diese kleine Routine auch leicht an eine andere Hardware anzupassen. Aber bei der Gestaltung der Programmstruktur hat jeder so seine Philosophie. Warum auch nicht. Gruß oldmax
Danke für deine Arbeit Jobst. Zum Verständnis ein paar Fragen zu deinem Code.
1 | ldi tmp2, 233 ; x*233>>12 = 0-10 |
2 | mul temp, tmp2 ; |
3 | mov temp, r1 |
4 | swap temp ; :256(weil MSB) :16 = :4096 |
5 | andi temp, 15 |
6 | ; sollte an dieser Stelle 11-15 heraus kommen, wird 'Error' gesendet |
7 | ; - oder man ergänzt die Zeilen unten |
8 | |
9 | ldi tmp2, 5 ; Ein Datensatz hat 5 Byte |
10 | mul temp, tmp2 ; Multipliziere mit 5 |
Kannst du mir die Schritte näher erklären? Warum die ADC Wert Multiplikation mit 233? Warum Nibbletausch und die oberen 4 bits auf 0? Wie geht der Verweis auf "Error bei 11-15"? Warum multiplizierst du den Wert dann nochmal mit 5? Gruß Markus
Hi Ich werfe mal kommentarlos eine andere Variante ins Rennen. MfG Spess
@Spess, CLR geht direkt auf R2. Nur Befehle mit I am Ende (LDI, SUBI usw.) gehen nur auf R16..31. SBR/CBR sind umbenannte ORI/ANDI. Ich würde für SREG Sicherung ein Register (R3) spendieren, spart je Interrupt 4 Befehle (2*PUSH, 2*POP). Peter
oldmax schrieb: > Im Prinzip Jo. Aber dafür ist mir dieses Projekt zu klein und ist trotzdem gut zu lesen. Bei größeren Projekten mache ich das auch so. Markus schrieb: > Kannst du mir die Schritte näher erklären? Ganz kurz ... ;-) > Warum die ADC Wert Multiplikation mit 233? > Warum Nibbletausch und die oberen 4 bits auf 0? Ich nehme eine Festkommamultiplikation vor. 233 ist Binär 11101001 Ich setze mein Komma in dem 16-Bit Ergebnis an die 4. Stelle von vorn: xxxx.xxxx xxxxxxxx Die 233 darauf gesehen sind 0000.0000 11101001 und sind damit dezimal 0,0568... oder 10/176 z.B. 176 mit 0,0568 multipliziert sind 10,0117... Oder auch 10110000 x (0000,0000)11101001 = 1010,000000110000 Den Rest hinter dem Komma schneide ich ab. -> 1010 = 10 dez Aus 10100000 (in R1) wird nach swap 00001010 und dann muß ich noch die oberen 4 Bit sicher auf 0 setzen (ist hier schon - ist aber nicht immer) > Wie geht der Verweis auf "Error bei 11-15" ? Error steht einfach für die Werte 11 bis 15 unten in den Datenzeilen. > Warum multiplizierst du den Wert dann nochmal mit 5? Die 5 ist die Länge eines Datensatzes, der verschickt werden soll. Die Daten starten also bei 'pakete', 'pakete+5', 'pakete+10', usw. Ich habe nach der obigen Berechnung eine Ganzzahl von 0 bis 10 (bzw. 15) Würde ich die 5 gleich mit bei obiger Berechnung einfliessen lassen, würde bei 4,5mA z.B. die letzten drei Byte von dem ersten Datenpaket und die ersten zwei Byte vom zweiten Datenpaket verschickt. Also nehme ich die 0-10, multipliziere diese mit 5 und weiß nun, an welcher Stelle ab 'pakete' meine 5 Byte zum verschicken stehen. Ich muß los :-) Gruß Jobst
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.