Assembler Assembler Einstieg

Lohnt sich Assembler zu lernen?

  • Ja

    Stimmen: 10 100,0%
  • Nein

    Stimmen: 0 0,0%

  • Umfrageteilnehmer
    10
Das mit den aufrufen von Funktionen habe ich bereits verstanden. Was ich mich noch Frage, ob man den Funktionen auch Übergabe Parameter mitgeben kann . Quasi wie bei einem Assembler Macro.
 
oben bereits alle Operationen genannt. Mit den vier CALLs kannst Du die Adresse einer Subroutine anspringen, mit RET zurückkehren.
Um die Übergabe irgendwelcher Parameter oder Ergebnisse mußt Du Dich selbst kümmern.
DU(!) denkst zu kompliziert. Der AVR und sein Maschinencode/Assembler ist einfacher. Der macht, was DU(!) ihm aufzwingst.
Du hast von überall her Zugriff auf jede SRAM-Adresse, auf jedes der Rechenregister.
Du kannst also Parameter einfach vorher in ein Rechenregister oder eine SRAM-Adresse übergeben.
"Summiere A und B":
lege A in Register bla ab
lege B in Register blub ab
Rufe Funktion "Addiere" auf.
Summe steht in Register bla

Funktion Addiere macht
ADD Register bla, Register blub
RET

Was stellst Du Dir konkret vor?
Ein Makro, daß das Laden vor Dir versteckt? Dann schreib es!
.MACRO Summe;(A, B)
lade bla, @0
lade blub, @1
RCALL Addiere
.ENDMACRO
Macht bei 'nem ADD keinen Sinn, aber bei komplexeren Berechnungen...
 
  • Like
Reaktionen: Janiiix3
So habe ich mir das vorgestellt..



CodeBox Assembler
;*************************************************************************   

; Issues a start condition and sends address and transfer direction.

; return 0 = device accessible, 1= failed to access device

;

; extern unsigned char i2c_start(unsigned char addr);

;    addr = r24, return = r25(=0):r24

;*************************************************************************


    .global i2c_start

    .func   i2c_start

i2c_start:

    sbi     SDA_DDR,SDA    ;force SDA low

    rcall     i2c_delay_T2    ;delay T/2

   

    rcall     i2c_write    ;write address

    ret

    .endfunc


Wo wird da die Variable die ich übergebe verarbeitet? Das ist jetzt eine Funktion die man in aufrufen kann. Da steht was von R24..?
 
R25:R24 bilden zusammen auch ein Doppelregister. Darauf kann man zB ADIW anwenden.
In Zeile 22 wird ein Bit eines Ports (also ein Bein) auf Ausgang geschaltet. Wenn das korrespondierende Port-Bit low ist, erfolgt hier ein Wechsel von tristate auf Gnd.
In Zeile 24 wird eine Zeitvernichtungsroutine aufgerufen,
In Zeile 28 eine Senderoutine.

Den Kommentaren nach zu schließen muß sich vorher die Slave-Adresse (nebst R/W-Bit) in R24 befinden (bzw im 16Bit-Doppelregister R25:R24, wobei der High-Anteil irrelevant sein könnte). Nach dem Return Steht in R25:R24 entweder 0x0000 oder 0x0001. Das letzte Bit ist das Enpfangene ACK/NACK.
Das (Bit oder Register) kannst Du jetzt irgendwohin schreiben, oder direkt aus R24 heraus weiterverarbeiten (->SBRS/SBRC zB, oder Du schiebst es mit LSR/ROR/ASR ins Carry und springst mit BRCC/BRCS, oder Du verANDest es und reagierst auf das Z-Flag oder mit 'nem Compare (der R24 dabei nicht ändert... oder .. oder...)

P.S.: versuch mal in Zukunft, den Code ohne unnötige Leerzeilen zu C&Pn.
 
Wo steht denn das der Übergabe Parameter in R24 geschrieben wird? Woher weiß ich das denn? Ich sehe nirgends eine Zuweisung..

Klar.. Ich versuche dran zu denken. Bin aktuell mit Handy unterwegs.
 
In Assembler brauchen keine Variablen übergeben zu werden. Du kannst von überall auf jede beliebige Speicherstelle und jedes beliebige Register zugreifen, wie @LotadaC schon sagte.

Wenn Du unbedingt Variablen wie in C übergeben willst, geht das in Registern oder auf dem Stack.
In dem Fall wäre es allerdings einfacher, gleich C zu benutzen... ;)
 
Heißt im Endeffekt man hätte bei der Funktion auch mit Register R16 arbeiten können? Da würde der Wert dann von "addr" enthalten sein?
 
Wo steht denn das der Übergabe Parameter in R24 geschrieben wird? Woher weiß ich das denn?


CodeBox Assembler
;************************************************************************* 
; Issues a start condition and sends address and transfer direction.
; return 0 = device accessible, 1= failed to access device
;
; extern unsigned char i2c_start(unsigned char addr)
;
;    addr = r24, return = r25(=0):r24
;*************************************************************************

Offensichtlich erwartet die Subroutine aber 'ne Adresse in R24, und liefert das erhaltene ACK/NACK auch in R24 zurück (zumindest steht das in den Kommentaren).
Genauso hätte die Routine auch mit R16 oder irgendwelchen anderen Registern geschrieben werden können. Oder mit fixen SRAM Adressen. Oder mit einer definierten, dynamischen Struktur im SRAM. einem Stack zB.
Oder Parametern im Eeprom.
Man könnte auch irgendwas im Flash ablegen und von da laden (macht nur nicht wirklich Sinn, aber machbar wäre es)

Ich sehe nirgends eine Zuweisung..
Der AVR kennt keine Variablen - er hat nur seine Speicherzellen. In den Rechenregistern, salopp gesagt auch in den I/O-Registern, im SRAM, im Eeprom, im Flash.
Und ASM-Code ist nur ein lesbareres Abbild des Maschinencodes.
Es gibt keine Variablen (eben nur die Speicherzellen selbst), und folglich keine Variablenzuweisungen (sondern nur Zugriffe auf die Speicherzellen - die aber ohne irgendwelche Einschränkungen (Gültigkeitsbereiche - Du bist verantwortlich für irgendwelche Regeln - und auch deren Einhaltung...)).


Du kannst zwar mit entsprechenden Direktiven Namen für Adressen vergeben, aber im eigentlichen Code bleiben es Adressen. Du schraubst für Dich nur'n Griff dran.

Wie gesagt: Ich hab Dir oben ALLE(!) Instruktionen die die AVR können aufgelistet. Mehr ist's nicht. Alles, was in irgendeiner Hochsprache codiert wird, wird (nur) mit diesen Instruktionen umgesetzt (wobei nicht jeder Controller alle Instruktionen kann)
 
Frage zum INTerrupt:


CodeBox Assembler
ldi tmp , ( 1<<WGM12 | ( 1<<CS12 | 1<<CS10 ) ) ; Normal Mode -> CTC

out TCCR1B , tmp ; Register beschreiben
ldi tmp , 1<<OCIE1A ; Output Compare Match Enable

out TIMSK , tmp ; Timer Interrupt Register beschreiben

ldi tmp , 255 ; Output Compare Match Wert

out OCR1AL , tmp ; .. Register beschreiben

ldi tmp , 100 ; Output Compare Match Wert

out OCR1AH , tmp ; .. Register beschreiben
sei ; Interrupts freigeben

mainLoop:
rjmp mainLoop

;##########################################################
; Timer Interrupt - Compare Match A
;##########################################################
timer0CmpInt:
eor eorReg, tmp
andi eorReg , 1<<1
out PORTB , eorReg
reti


Ich will eine LED Togglen.. Das klappt auch.. Er springt wohl in die ISR rein..
Aber sobald ich hier einen Wert >99 rein schreibe, kackt irgendwas ab???


CodeBox Assembler
ldi tmp , 100 ; Output Compare Match Wert
 
Wo steht denn das der Übergabe Parameter in R24 geschrieben wird? Woher weiß ich das denn? Ich sehe nirgends eine Zuweisung..
Offensichtlich versuchst Du von Assembler aus eine C-Funktion aufzurufen. Dann mußt Du Dich natürlich an die C-Konventionen halten. Der erste Byte-Parameter wird immer in R24 übergeben, der Rückgabewert steht in R24:R25.
Es gibt eine AN von Atmel, in der das beschrieben ist, heißt, wenn ich mich recht erinnere: Mixing Assembly and C.
 
Offensichtlich versuchst Du von Assembler aus eine C-Funktion aufzurufen. Dann mußt Du Dich natürlich an die C-Konventionen halten. Der erste Byte-Parameter wird immer in R24 übergeben, der Rückgabewert steht in R24:R25.
Es gibt eine AN von Atmel, in der das beschrieben ist, heißt, wenn ich mich recht erinnere: Mixing Assembly and C.

Genau das wollte ich wissen. Was ist aber nun wenn ich mehrere Parameter übergebe?
 
Hab es glaube ich gefunden..

upload_2018-9-14_12-58-59.png
Was bedeutet "b2b" in Register "r22" ?
 
Hmmmm....
Druckfehler. Sollte eigentlich b2 heissen, wenn man sich die abfolge der bytes anschaut.
73 de addi
 
Aber sobald ich hier einen Wert >99 rein schreibe, kackt irgendwas ab???
Wo "hier"?
Dein Timer sollte mit Prescaler 1024 im CTC laufen, OCR1A bestimmt die Reichweite/Überlauffrequenz.
Du hast 0x64FF nach OCR1A geschrieben, die Systemfrequenz kenne ich nicht. Geht man von 16MHz aus, sollte der IRQ etwa alle zwei Sekunden triggern (0,6Hz).

Aber was soll Deine komische ISR machen?
Dein tmp-Register war ja (zuletzt) mit 100=0x64=&B01100100 beladen.
Beim eorRegister maskierst Du mit dem ANDI jedesmal alle Bits auf null, außer Bit1.
Bit1 ist im tmp-Register null, also wird dieses Bit durch EOR nicht verändert. Alle anderen Bits bleiben wegen ANDI immer null (korrekter: sind nach ANDI...)
 
Zuletzt bearbeitet:
Aber was soll Deine komische ISR machen?
Dein tmp-Register war ja (zuletzt) mit 100=0x64=&B01100100 beladen.
Das habe ich mich auch gefragt. Wollte einfach nur mal eine Led toggeln, es war aber der Fall das die ganze Zeit der ganze Port beteidigt war. Daher habe ich irgendwie versucht nur das eine Bit zu maksieren.. Hat wie du angemerkt hast nicht wirklich geklappt.

Ist eigentlich viel einfacher..


CodeBox Assembler
;##########################################################
;   Timer Interrupt - Compare Match A
;##########################################################
timer0CmpInt:
               ldi tmp, 1
               eor toggleBit, tmp
               out PORTB , toggleBit
               reti
 
Ist eigentlich viel einfacher..
Naja, Du hattest diese komische Routine geschrieben, Du solltest also ein Ziel damit gehabt haben.
Zu der Neuen:
EOR manipuliert das SREG, außerdem werden zwei Rechenregister verändert.
Da Dein Hauptprogramm nie weiß, wann/ob der IRQ zuschlägt, sind diese Register (also auch das SREG) nie verwendbar.
Klar kannst Du (bei reinem Assemblercode) Rechenregister für eine oder alle ISRs reservieren, ansonsten mußt Du Dich aber um das retten der Inhalte kümmern.
Wenn Du Rechenregister reservierst, mußt DU das im gesamten restlichen Programm beachten.

Eine(!) Alternative wäre in Deinem Fall, den direkten Zugriff auf die Bits des I/O-Registers mit bedingten SKIPs auszunutzen.

P.S.: viele modernere AVR (zumindest bei den Tinies) toggeln das Bein, wenn man eine "1" ins PIN-Register-Bit schreibt. Der M32 scheint allerdings nicht dazu zu gehören.
Bei den XMegas (und X-Core-Tinies?) gibts AFAIR spezielle I/O-Register zum toggeln.
 
OR manipuliert das SREG, außerdem werden zwei Rechenregister verändert.
Da Dein Hauptprogramm nie weiß, wann/ob der IRQ zuschlägt, sind diese Register (also auch das SREG) nie verwendbar.
Klar kannst Du (bei reinem Assemblercode) Rechenregister für eine oder alle ISRs reservieren, ansonsten mußt Du Dich aber um das retten der Inhalte kümmern.
Wenn Du Rechenregister reservierst, mußt DU das im gesamten restlichen Programm beachten.
Was willst du mir damit jetzt sagen? Sollte ich vorher die Daten auf dem Stack sichern? Das war jetzt ja nur ein Test um zu sehen wie man ein Bit toggelt..
 
Genau, wenn Dir das klar ist, ist alles in Ordnung. Wenn nur Register verwendet werden, deren Inhalt sonst (zB hier im Test) egal ist, brauchst Du nichts zu tun. Sonst mußt Du Dich selbst darum kümmern.
Deswegen kann es manchmal sinniger sein, auf Operationen zu verzichten, die Registerinhalte manipulieren, wenn es einen anderen Weg gibt.
 
Was genau bedeuten die eingeklammerten Adressen?
Unbenannt.jpg
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)