Forum: Mikrocontroller und Digitale Elektronik Assemblercode Hilfestellung (Anfänger)


von Markus (Gast)


Angehängte Dateien:

Lesenswert?

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.

von spess53 (Gast)


Lesenswert?

Hi

>Eingangssignal 4...20mA digital Wandeln und in 10 Schaltstufen
>auflösen,á 1,6 mA

Was ist mit <4mA?

MfG Spess

von Yalu X. (yalu) (Moderator)


Angehängte Dateien:

Lesenswert?

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).

von Markus (Gast)


Lesenswert?

kleiner 4 mA muss verworfen werden als ungültiges Signal.
Für die Steuerungstechnik ein Drahtbruchmelder. 0mA muss Alarm geben.

von Markus (Gast)


Lesenswert?

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. ;)

von Markus (Gast)


Angehängte Dateien:

Lesenswert?

Hier nochmal als asm

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

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.

von Markus (Gast)


Lesenswert?

Dachte der Experte Überblickt auch ohne Kommentare die Funktion.
Ich werde Kommentare einfügen sobald ich wieder am PC bin.

Markus

von Wegstaben V. (wegstabenverbuchsler)


Lesenswert?

Markus schrieb:
> der Experte Überblickt auch ohne Kommentare die Funktion.

der Experte blickt nur auf Funktionen mit Kommentaren ;-)

von spess53 (Gast)


Lesenswert?

Hi

>Stufe_0:
>ldi cmd, 0x80
>ldi cs, 0x1B
>rjmp UART_Send

Wie kommst du eigentlich auf die Checksumme?

MfG Spess

von Markus (Gast)


Lesenswert?

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?

von Markus (Gast)


Angehängte Dateien:

Lesenswert?

Kommentiertes asm Nachgereicht. ;)

von spess53 (Gast)


Lesenswert?

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

von Sascha W. (sascha-w)


Lesenswert?

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

von Jobst M. (jobstens-de)


Angehängte Dateien:

Lesenswert?

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

von codeverwerter (Gast)


Lesenswert?

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. :)

von Jobst M. (jobstens-de)


Lesenswert?

ich habe meinen Code mit Kommentaren geschrieben ;-)


Gruß

Jobst

von Markus (Gast)


Lesenswert?

Bahnhof. ;-)

Kannst du mal die lange Version Posten bitte?

Danke &, Gruß

Markus

von Jobst M. (jobstens-de)


Angehängte Dateien:

Lesenswert?

Long-Version ...

Ich hoffe es hilft!


Gruß

Jobst

von oldmax (Gast)


Lesenswert?

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

von Markus (Gast)


Lesenswert?

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

von spess53 (Gast)


Angehängte Dateien:

Lesenswert?

Hi

Ich werfe mal kommentarlos eine andere Variante ins Rennen.

MfG Spess

von Peter D. (peda)


Lesenswert?

@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

von Jobst M. (jobstens-de)


Lesenswert?

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
Noch kein Account? Hier anmelden.