Assembler für Anfänger was zum Nachdenken

Rolf.H

Neues Mitglied
17. Juni 2012
136
0
0
89
25451 Quickborn
Sprachen
Hallo Leute,
ich dachte mir, daß es Zeit wird, mal nen neuen Thread zu eröffnen.
In einem Buch (speziell zum Tin2313) entdeckte ich einen Code, wo ich dachte
"eine LED zum blinken zu bringen...na was ist das schon"!
Aber denkste! Es tauchten so viele neue Befehle und Strukturen auf, was mein Wissen
überforderte.
Alle angesetzten Kommentare stammen von mir. Und es hat an Zeit gekostet, mich dadurch zu kämpfen.
D.h. mit Hilfe eines anderen Buchs, indem die Befehle sehr schön dokumentiert werden, war es möglich
etwas Licht in die Sache zu gewinnen. Vieles habe ich besonders am Anfang umgemodelt. Jetzt weiß ich auch
mit den Variablen (.equ xxxx,xx) umzugehen.
Wie man allerdings auf eine Blinkfrequ. von 500ms kommt...mh!

Na schaut Euch das mal an.

Code:
; Projekt-Name: Projekt01                      Datum: 16.11.2012									

; Datei: Maske.asm (aus dem Buch Seite 61 / test3)              

; PORTB,xx  (Output)
; PINB,xx   (Input)
; DDRB,akku (Datenrichtung)


; AVR: Tiny2313-20PU

  .INCLUDE "tn2313def.inc"  ; Deklaration für Tiny2313
    
  rjmp    reset             ; Reseteinsprung
  .ORG    OVF0addr          ; Interrupt-Vektor
  rjmp    TIMER0_OVF        ; Sprung zur ISR

 .def     akku=r16
 .def     temp1=r17
 .def     stavec=r22
 .def     itmp=r25

 .equ     CNTVAL=0x3D
 .equ     TICKS=0x61

reset:       

  ldi     akku,0x80         ; 0b1000.0000 
  out     DDRB,akku         ; Datenricht.PB7=Output
  clr     akku              ; alle Bits=Low                 
  

; Timer0 initialisieren:
  ldi     akku,(1<<CS02)    ; Prescale = 256 
  out     TCCR0B,akku
  ldi     akku,(1<<TOIE0)    ; Timer Overflow / Interrupt 
  out     TIMSK,akku
  sei                       ; Timer frei

  ldi     stavec,0x00  ;r22 = 00
  clr     akku         ;r16 = 00
  sts     TICKS,akku   ;Speicherinh. r16 in adressiertes Byte im SRAM=61



loop:      
  sbrs    stavec,0     ;überspringe, wenn Bit0 in r22 gesetzt ist
                       ;wird im Interrupt gesetzt
  rjmp    loop
  cbr     stavec,0x01  ;lösche in r22 die Bits,die in dem Maskenbyte=1 sind
  in      akku,PORTB   ;lade r16 mit Inhalt von PORTB (r16=0)
  ldi     temp1,0x80   ;r17 = 80
  eor     akku,temp1   ;verknüpfe r16 mit r17 durch ODER Funkt.
  out     PORTB,akku   ;PORTB,PB7 = 1
  rjmp    loop

  
; Interrupt-ISR

TIMER0_OVF:
 
  in      itmp,SREG     ;lade r25 mit Inhalt Statusreg.
  push    itmp          ;Kopie r25 auf den Stack, danach SP-1
  
  ldi     itmp,CNTVAL   ;lade r25 mit Variable = 0x3D
  ;8bit Aufwärtszähler des Timerregisters TCNT0 wird mit 
  ;einen Anfangswert hex=3D beschrieben.
  out     TCNT0,itmp
  lds     itmp,TICKS    ;lade r25 mit dem direkt adressierten Byte
                        ;aus dem SRAM = hex 61
  inc     itmp          ;Inhalt von r25 + 1
  sts     TICKS,itmp    ;Speicherinh. r25 in adressiertes Byte im SRAM
  cpi     itmp,0x0A     ;vergleiche r25 mit Konst. 0A (wenn ja C=1)
  brlo    TIM0_OVF_DONE ;Verzweigung, wenn C=1
  clr     itmp          ;r25 = 00
  sts     TICKS,itmp    ;Speicherinh. r25 in adressiertes Byte im SRAM
  sbr     stavec,0x01   ;setze in r22 die Bits, die in der Maske=1 sind
  
  TIM0_OVF_DONE:
  pop     itmp          ;SP+1 danach vom Stack in r25
  out     SREG,itmp     ;Inhalt von r25 ins SREG laden
  reti  
  .EXIT

Grüße

Rolf
 
Hallo Leute,
ich dachte mir, daß es Zeit wird, mal nen neuen Thread zu eröffnen.
In einem Buch (speziell zum Tin2313) entdeckte ich einen Code, wo ich dachte
"eine LED zum blinken zu bringen...na was ist das schon"!
Aber denkste! Es tauchten so viele neue Befehle und Strukturen auf, was mein Wissen
überforderte.
Alle angesetzten Kommentare stammen von mir. Und es hat an Zeit gekostet, mich dadurch zu kämpfen.
D.h. mit Hilfe eines anderen Buchs, indem die Befehle sehr schön dokumentiert werden, war es möglich
etwas Licht in die Sache zu gewinnen. Vieles habe ich besonders am Anfang umgemodelt. Jetzt weiß ich auch
mit den Variablen (.equ xxxx,xx) umzugehen.
Wie man allerdings auf eine Blinkfrequ. von 500ms kommt...mh!

Dazu müßte man wissen, ob ein (welcher ?) Quarz benutzt wurde.

Na schaut Euch das mal an.

Code:
; Projekt-Name: Projekt01                      Datum: 16.11.2012									

; Datei: Maske.asm (aus dem Buch Seite 61 / test3)              

; PORTB,xx  (Output)
; PINB,xx   (Input)
; DDRB,akku (Datenrichtung)


; AVR: Tiny2313-20PU

  .INCLUDE "tn2313def.inc"  ; Deklaration für Tiny2313
    
  rjmp    reset             ; Reseteinsprung
  .ORG    OVF0addr          ; Interrupt-Vektor
  rjmp    TIMER0_OVF        ; Sprung zur ISR

 .def     akku=r16
 .def     temp1=r17
 .def     stavec=r22
 .def     itmp=r25

 .equ     CNTVAL=0x3D
 .equ     TICKS=0x61

reset:       

  ldi     akku,0x80         ; 0b1000.0000 
  out     DDRB,akku         ; Datenricht.PB7=Output
  clr     akku              ; alle Bits=Low

Der letzte Befehl ist überflüssig, oder Du hast hier einen out-Befehl vergessen.

Code:
; Timer0 initialisieren:
  ldi     akku,(1<<CS02)    ; Prescale = 256 
  out     TCCR0B,akku
  ldi     akku,(1<<TOIE0)    ; Timer Overflow / Interrupt 
  out     TIMSK,akku
  sei                       ; Timer frei

  ldi     stavec,0x00  ;r22 = 00
  clr     akku         ;r16 = 00
  sts     TICKS,akku   ;Speicherinh. r16 in adressiertes Byte im SRAM=61



loop:      
  sbrs    stavec,0     ;überspringe, wenn Bit0 in r22 gesetzt ist
                       ;wird im Interrupt gesetzt
  rjmp    loop
  cbr     stavec,0x01  ;lösche in r22 die Bits,die in dem Maskenbyte=1 sind
  in      akku,PORTB   ;lade r16 mit Inhalt von PORTB (r16=0)
  ldi     temp1,0x80   ;r17 = 80
  eor     akku,temp1   ;verknüpfe r16 mit r17 durch ODER Funkt.
  out     PORTB,akku   ;PORTB,PB7 = 1
  rjmp    loop

  
; Interrupt-ISR

TIMER0_OVF:
 
  in      itmp,SREG     ;lade r25 mit Inhalt Statusreg.
  push    itmp          ;Kopie r25 auf den Stack, danach SP-1
  
  ldi     itmp,CNTVAL   ;lade r25 mit Variable = 0x3D

Das ist keine Variable, das ist eine Konstante.

Code:
  ;8bit Aufwärtszähler des Timerregisters TCNT0 wird mit 
  ;einen Anfangswert hex=3D beschrieben.
  out     TCNT0,itmp
  lds     itmp,TICKS    ;lade r25 mit dem direkt adressierten Byte
                        ;aus dem SRAM = hex 61
  inc     itmp          ;Inhalt von r25 + 1
  sts     TICKS,itmp    ;Speicherinh. r25 in adressiertes Byte im SRAM
  cpi     itmp,0x0A     ;vergleiche r25 mit Konst. 0A (wenn ja C=1)

wenn itmp < 10

Code:
  brlo    TIM0_OVF_DONE ;Verzweigung, wenn C=1
  clr     itmp          ;r25 = 00
  sts     TICKS,itmp    ;Speicherinh. r25 in adressiertes Byte im SRAM
  sbr     stavec,0x01   ;setze in r22 die Bits, die in der Maske=1 sind
  
  TIM0_OVF_DONE:
  pop     itmp          ;SP+1 danach vom Stack in r25
  out     SREG,itmp     ;Inhalt von r25 ins SREG laden
  reti  
  .EXIT

Gruß Wolfgang
 
Hallo Wolfgang,
danke für Deine Antwort!
Dem Buch nach wurde kein Quarz verwendet. Man ging vom intern erzeugten Takt von 1 MHz aus.
Das wären bei gewählter Prescale von 256 gleich 256ys.
Thema "Variable"
Ich dachte, bei .equ TICKS = 0x61 wäre TICKS der Name der Variable und 61 die Konstante dazu.
Bei Bascom glaube ich war es DIM xxxx,xx.
Gieb mir doch mal als Beispiel eine Variable in Assembler. Wie sieht das denn aus?
Das Buch verwies auch auf
ldi akku, low (Ramend)
out SPL,akku
Das habe ich gelöscht, denn irgend Jemand sagte mir mal das brauch ich beim Tiny2313 nicht,
es würde in der .include stecken...ist das richtig?
Wie schon geschrieben lief das Ganze auf Anhieb, hab mich selbst gewundert.

Grüße

Rolf
 
Hi Rolf,

Ich dachte, bei .equ TICKS = 0x61 wäre TICKS der Name der Variable und 61 die Konstante dazu.
Bei Bascom glaube ich war es DIM xxxx,xx.

Die folgende Datei solltest du im AVR-Studio oder auf der Atmel-Seite finden. Ich weiß nicht mehr genau wo ich sie weg hab.
>> AVR_Assembler_User_Guide_DOC1022.PDF (490kB)

Section 4 - AVRAssembler User Guide

4.5.9 EQU - Set a symbol equal to an expression
The EQU directive assigns a value to a label. This label can then be used in later expressions. A label assigned to a value by the EQU directive is a constant and can not be changed or redefined.

4.5 Assembler directives
The Assembler supports a number of directives. The directives are not translated directly into opcodes. Instead, they are used to adjust the location of the program in memory, define macros, initialize memory and so on. An overview of the directives is given in the following table.
Summary of directives:

Directive - Description

BYTE - Reserve byte to a variable
CSEG - Code Segment
DB - Define constant byte(s)
DEF - Define a symbolic name on a register
DEVICE - Define which device to assemble for
DSEG - Data Segment
DW - Define constant word(s)
ENDMACRO - End macro
EQU - Set a symbol equal to an expression
ESEG - EEPROM Segment
EXIT - Exit from file
INCLUDE - Read source from another file
LIST - Turn listfile generation on
LISTMAC - Turn macro expansion on
MACRO - Begin macro
NOLIST - Turn listfile generation off
ORG - Set program origin
SET - Set a symbol to an expression

Note: All directives must be preceded by a period.

Gruß
Dino
 
...Thema "Variable"
Ich dachte, bei .equ TICKS = 0x61 wäre TICKS der Name der Variable und 61 die Konstante dazu.
Bei Bascom glaube ich war es DIM xxxx,xx.
Gieb mir doch mal als Beispiel eine Variable in Assembler. Wie sieht das denn aus?
...
Du hast wohl das richtige gemeint, und es nur ungünstig ausgedrückt. "TICKS" ist der Name (einer Assembler-Konstante), die den Wert 0x61 hat. "TICKS" taucht im Controller aber nie auf - wird der Programmcode assembliert, wird überall dort, wo "TICKS" stand STATTDESSEN 0x61 eingebaut (bei LDI zB direkt mit in den Opcode hineinkodiert). Es ist eine Konstante für den Assembler.
Was wäre zur Laufzeit eine Variable? Nun, eine feste Position, die variable Inhalte annehmen kann. Eine Speicherzelle. Ob im (richtigen) SRAM, im I/O-Space (zB GPIOR), oder einem Rechenregister, ist Wurscht. Die Bezeichnung Variable ergibt sich dann also eher aus der Verwendung dieses Speichers. Indem Du im Assembler-Code der Adresse der Zelle (Konstante) einen Namen gibst.
...Das Buch verwies auch auf
ldi akku, low (Ramend)
out SPL,akku
Das habe ich gelöscht, denn irgend Jemand sagte mir mal das brauch ich beim Tiny2313 nicht,
es würde in der .include stecken...ist das richtig?...
Nicht ganz:
-RAMEND ist eine Konstante, die in der inkludierten Prozessordefinitionsdatei definiert ist. RAMEND ist eine Zahl, die gleich der Adresse der letzten Zelle im SRAM (des Tiny2313) ist. Deswegen kann man mit den beiden Codezeilen den Stackpointer auf des Ram-Ende reinitialisieren. Soweit klar, und so wird das auch bei vielen Controllern gemacht. Warum ans Ende? Das liegt an der arbeitsweise des Stacks. Mit Push wächst der von hinten nach vorne, mit Pop schrumpft er von vorne nach hinten. Du brauchst also VOR der initialisierten Zelle soviele frei verfügbare RAM-Zellen, wie der Stack wachsen können soll (es muß also nicht immer zwangsläufig das Ende sein).
Warum brauchst Du das jetzt aber trotzdem nicht?
Nunja, beim Reset (also auch beim power up) werden fast(*) alle I/O-Register mit vordefinierten Werten beladen. Mit Initialwerten. Die Stack-Pointer-Register (der Tiny2313 verwendet nur SPL, da nur 128 SRAM, 32 Rechen- und 64 I/O-Register). sind natürlich I/Os, für SPL beträgt das initial value beim Tiny2313 bereits sinnigerweise RAMEND (siehe S.11 im Datenblatt).

(*) Einige Register sind fest mit irgendwelchen Externa verbunden - die PIN-Register zB. Hier entspricht das jeweilige Bit also dem logischen Pegel des korrespondierenden Prozessorbeinchens.
 
Hi Rolf
Thema "Variable"
Ich dachte, bei .equ TICKS = 0x61 wäre TICKS der Name der Variable und 61 die Konstante dazu.
Bei Bascom glaube ich war es DIM xxxx,xx.
Gieb mir doch mal als Beispiel eine Variable in Assembler. Wie sieht das denn aus?
Das Buch verwies auch auf
ldi akku, low (Ramend)
out SPL,akku
Das habe ich gelöscht, denn irgend Jemand sagte mir mal das brauch ich beim Tiny2313 nicht,
es würde in der .include stecken...ist das richtig?
Eine Variable wird in der Regel in einem Speicherbereich deklariert. Auch Register sind im Speicherbereich angesiedelt, haben aber einen größeren Funktionsumfang, während Variablen eigentlich nur Werte aufnehmen und wiedergeben. In den Hochsprachen wie auch in Assembler werden den Variablen Namen gegeben und damit der Speicher definiert. Es interessiert nicht, ob die Variable "Ergebnis" auf Speicherzelle 7FHC0098 hex ( 32 Bit) liegt. Das kann sich sowieso keiner merken. Bei den kleinen µC ist das ja noch überschaubar, aber trotzdem ist bei 1 K SRam schon 1 Wort zur Adressierung erforderlich. Da ist es leichter, den Compiler die Arbeit machen zu lassen, denn der legt sich eine Tabelle an und setzt statt dem Variablennamen die Adresse in den Programmcode.
Code:
.DSEG                       ; Anfang vom SRAM für unendlich beschreibbaren Speicher
Ergebnis:      .Byte 1   ; ordnet der ersten Adresse des SRAM den Namen "Ergebnis" zu
Die Compilerdirektive .Byte n erfaßtdie Größe des Speicherblocks. So ist auch
Code:
Puffer:        .Byte 20   ; Array von 20 Speicherzellen
möglich. Der Zugriff auf die einzelnen Speicherzellen erfolgt dann mithilfe der Doppelregister "X", "Y" und "Z". Kannst du aber noch detailierter nachlesen....
Gruß oldmax
 
"Ergebnis:" und "Puffer:" sind label, wie Du sie schon kennst. Der Assembler rechnet sich daraus die entsprechenden Adressen, und bezieht sich dann darauf (wie auch schon bei den Verzweigungen). Durch .DSEG wird bewirkt, daß die folgenden .BYTE-Instruktionen sich aufs SRAM hinter dem I/O-Space beziehen (OLDMAX, bitte bestätigen falls richtig). Wo dieser beim aktuellen Controller adresstechnisch beginnt, entnimmt der Assembler der, in der inkludierten Prozessordefinitionsdatei definierten Konstante "SRAM_START". Der label selbst entspicht logischerweise nur einer(!) Adresse. Wenn also in einem Rutsch mehrere Bytes reserviert werden (Array), bezieht sich der label auf das erste Byte davon. Die Zahl hinter dem .BYTE wirkt sich quasi erst auf die nächste zu reservierende Adresse aus.
Den Zugriff über die indirekte Adressierung (X,Y,Z-Register nimmt die Adresse (also das Label) auf) hatte Oldmax ja schon angedeutet. Du kannst damit aber auch direkt adressieren, zB "LDS Reechenregister, Label". Dann wird der Inhalt der Speicherzelle, die die Adresse "Label" hat ins "Rechenregister" geladen.
 
oh weia, da habe ich ja wieder was zum krüpeln, trotzdem danke an alle!
also ist .equ TICKS = 0x61 eine Konstante, die einen Namen bekommt...hat mit Variablen nichts zu tun.
Nun hab ich mir ein älteres Buch aus der Bascom-Zeit hervor geholt, indem auf verschiedene Variablen-Typen
wie Byte, Word, Integer usw. eingegangen wird. Leider sehe ich in den Assembler-Büchern garnichts darüber.
Hier unterscheidet man unter lokale und globale Variablen. Nehme ich mal die globalen so werden diese mit DIM
für alle Funktionen innerhalb des Programms definiert.

Hier Variablen-Zuweisung: (aus dem Buch als Beispiel)
DIM Variable As Byte 'Byte Variable, sie kann Werte von 0 bis 255 annehmen

Aber hier blicke ich immer noch nicht durch, angenommen ich will der Speicherzelle 0xAF im Datenbereich vom SRAM
einen Namen geben, wie mach ich denn das nur.
Der Speicherzelle 0x3F wäre doch kuttel-muttel, denn die hat ja schon einen mit SREG.
Zeigt mir mal, wie Ihr das effektiv (ohne große Kommentare)machen würdet, vielleicht machts dann "KLICK" bei mir
wie mit den SREG-Register was ich jetzt ganz gut im Griff habe.

Schönen Sonntag wünsche ich

Rolf

Oh, ich sehe hier eine Datei xxxx.bas und da steht zu Beginn

Dim Zahl As Byte
Dim X As Byte

Zahl bzw. X muß doch eine Speicherzelle sein oder?
Und wie setze ich sowas in Assembler um?
 
Hallo Rolf,

oh weia, da habe ich ja wieder was zum krüpeln, trotzdem danke an alle!
also ist .equ TICKS = 0x61 eine Konstante, die einen Namen bekommt...hat mit Variablen nichts zu tun.
Du mußt dir das ähnlich vorstellen wie bei nem Texteditor "Suchen und ersetzen".
Alle Stellen im Quellcode an denen "TICKS" steht werden beim Übersetzungsvorgang durch "0x61" ersetzt.

Nun hab ich mir ein älteres Buch aus der Bascom-Zeit hervor geholt, indem auf verschiedene Variablen-Typen
wie Byte, Word, Integer usw. eingegangen wird. Leider sehe ich in den Assembler-Büchern garnichts darüber.
Hier unterscheidet man unter lokale und globale Variablen. Nehme ich mal die globalen so werden diese mit DIM
für alle Funktionen innerhalb des Programms definiert.
Es gibt bei Assembler keine Variablentypen. Es gibt in dem Sinne auch keine Variablen wie man sie aus anderen Programmiersprachen kennt. Du bastelst dir alles genau so zusammen wie du es grade brauchst. Dafür kannst du Konstrukte erzeugen die keine Hochsprache dir bieten kann.

Hier Variablen-Zuweisung: (aus dem Buch als Beispiel)
DIM Variable As Byte 'Byte Variable, sie kann Werte von 0 bis 255 annehmen
Das ist in Assembler einfach eine Speicherstelle im SRAM oder wenn du es besonders schnell abarbeiten lassen willst dann ein Register.

Bascom:
Code:
DIM Variable As Byte     ' Byte-Variable definieren
Variable = 10               ' Variable mit Wert füllen

Du könntest es in Assembler also so machen ...
Code:
.equ Variable=0x59     ; Speicheradresse für Variable definieren
ldi r16, 10                  ; Da sts nicht direkt Werte speichern kann muß man es über ein Register machen
sts Variable, r16        ; Variablenwert(10) speichern

Mit nem Rechenregister ...
Code:
.equ Variable=16       ; Register für Variable definieren
ldi r16, 10                  ; Wert in der Variablen ablegen

In Assembler ist diese "Variable" aber weder eine Byte-Variable noch eine Textvariable mit einem Zeichen Länge noch was anderes. Sie ist alles zugleich. Was du mit diesem Byte machst bleibt dir überlassen. Du kannst zB 15 dazuaddieren (wäre ne numerische Funktion) und sie danach einfach auf den UART schieben um sie über die RS232 zum PC zu übertragen (könnte zB nen Print-Befehl für nen Textzeichen bei Bascom sein). Variablentypen sind bei Assembler Schall und Rauch. Es sind lediglich Speicherplätze für Bytes(8Bit) und Words(16Bit). Nicht mehr und nicht weniger.

Der Speicherzelle 0x3F wäre doch kuttel-muttel, denn die hat ja schon einen mit SREG.
Zeigt mir mal, wie Ihr das effektiv (ohne große Kommentare)machen würdet, vielleicht machts dann "KLICK" bei mir
wie mit den SREG-Register was ich jetzt ganz gut im Griff habe.
Das SREG sprichst du normalerweise nur über die einzelnen Flags (Carry, HalfCarry, Sign, T-Bit, ...) an. Du mußt es nur als Byte speichern/zurückholen wenn du mit Interrupts arbeitest weil du ja in dem Programmteil aus dem dich der Interrupt herausgerissen hat nach dem Rücksprung wieder den alten Zustand benötigst.

Gruß
Dino
 
Hallo Rolf
Mach's doch nicht so kompliziert. Du definierst dir eine Variable

Code:
.DSEG
meine_erste_Variable: .Byte 1
So, ist ja schon ein paarmal geschrieben worden. Aber das ist ohne Kommentar alles, was eine Variable definiert. Die Adresse brauchst du nicht. Wozu auch, das ist Sache des Compilers, die in das Programm für dem Controller einzusetzen. Es ist ja so, das der Controller mit den Assemblerbefehlen auch nix anzufangen weiß. Er kennt nur "Einsen" und "Nullen" oder anders gesagt "Spannung Ein" und "Spannung aus". Nur die Kombination von mehreren Bits zu einem Byte oder Word lassen ihn irgendwelche Operationen ausführen. Mit einem LDS kann er nix anfangen. Dafür gibt es den Compiler, der das, was du dem µC in einer Anweisung aufträgst und was für dich verständlich ist, ihm erst mal in einen Hex-Code übersetzt.
Warum du in Assembler keine anderen Variablen wie Byte definieren kannst ? Nun, das denke ich liegt daran, das Assembler sich an der Hardware der Controller orientiert. Wie willst du in ein 8 Bit-Register eine Realzahl hineinbekommen ? Klar, du kannst mit Realzahlen rechnen, aber eben nach Art des Hauses, mit Mantisse und Exponent und einer entsprechenden Programmierung. So definierst du 0,5 mit 2^-01, 0,25 mit 2^-10. Aber das ist etwas für die kalten Wintertage und da gibt es gute Lektüre zu. Ich hab für mich entschieden, wenn ich mal Mathematik brauche, dann greif ich zu einer Hochsprache. Und wenn ich dafür "C" lernen müßte....
Abschließend noch eine Antwort auf:
Oh, ich sehe hier eine Datei xxxx.bas und da steht zu Beginn

Dim Zahl As Byte
Dim X As Byte

Zahl bzw. X muß doch eine Speicherzelle sein oder?
Und wie setze ich sowas in Assembler um? .

Code:
.DSeg
Zahl:      .Byte 1
X:          .Byte1
wobei "X" etwas ungeschickt ist, denn X wurde ja bereits als Doppelregister verwendet. Daher ist "X" nicht verwendbar. Also suchst du im BASCOM alle Zeilen mit der Variablen "X" und setzt dafür "X_Var". Dann hast du keinen Namenskonflikt in Assembler.
Gruß oldmax
 
..
In Assembler ist diese "Variable" aber weder eine Byte-Variable noch eine Textvariable mit einem Zeichen Länge noch was anderes. Sie ist alles zugleich. Was du mit diesem Byte machst bleibt dir überlassen...
Genau. Nehmen wir mal an, Du hast einer Speicheradresse den Namen Variable gegeben, und darin den binären Wert 01010101 abgelegt. Was ist das jetzt? Ein Byte. 8 Bit. Und wie ist diese Variable zu interpretieren? Sie ist alles zugleich (->Dino). Wenn Du sie (über ein Rechenregister) ins UART Data Register kopierst, kommt an der Gegenstelle eben auch 01010101 an. Wenn die das als ASCII dekodiert entspricht das einem "U".
Du kannst dieses Byte aber auch als Flag-Register interpretieren (ähnlich Stavec aus Deinem letzten Beispiel). Dann entsprechen die einzelnen Bits eben irgendwelchen Flags...
Oder Du interpretierst es als Byte Zahl: 85 dezimal in dem Fall. Oder 55hex.
Oder Du interpretierst es als vorzeichenbehaftete 7bit-Zahl.
Oder Du siehst es als Speicher für 2 Nibbles. (5 und 5 dezimal).
Was davon jetzt gilt, entscheidest Du mit der Verwendung in Deinem Programm.

Die Variable ist nur eine Vereinfachung für den Zugriff auf den Speicherort. Und auch das nur für die Programmierung, also im Compiler. Zur Laufzeit sind die bereits alle durch die entsprechenden Adressen ersetzt, bzw in die entsprechenden Opcodes mit eingebaut.
Das ist bei Hochsprachen eigentlich auch nicht anders - dort wird nur durch die Typendeklaration erzwungen, wie der Inhalt zu interpretieren ist. Mit allen, sich daraus ergebenden Vor- und Nachteilen (Typenumwandlungen, hin und her-casterei, etc... dafür gibts da dann eben fertige Konstrukte, oder auch nicht - und Du mußt damit auskommen. Bei Assembler gibts in der Hinsicht gar nichts - Du kümmerst Dich selbst um die Interpretation, bist aber in der Hinsicht frei von allen Zwängen, klar?)
 
Nun hab ich mir ein älteres Buch aus der Bascom-Zeit hervor geholt, indem auf verschiedene Variablen-Typen
wie Byte, Word, Integer usw. eingegangen wird. Leider sehe ich in den Assembler-Büchern garnichts darüber.
Wenn Dir ein Byte zu klein ist, um Deine Zahl zu speichern, so kannst Du Dir selbst größere Variablen definieren. Z.B. mit
Code:
.DSEG
    Zahl    .BYTE 2
Je nachdem, wie Du das behandelst könnte das dem entsprechen, was man auf 8-Bit oder 16-Bit Rechnern unter einem WORD (vorzeichenlos) oder einem INTEGER (vorzeichenbehaftet) versteht. Allerdings ist nicht nur die Art, wie Du das verstehst Deine Sache, sondern auch, wie Du damit rechnest, etc.

Dafür kannst Du aber auch entscheiden, daß Dir eine 2-Byte Zahl zu klein, eine 4-Byte Zahl aber unnötig groß erscheint. Dann kannst Du eine 3-Byte Zahl definieren:
Code:
.DSEG
    MeineZahl    .BYTE 3
Sowas gibt es in keiner Hochsprache.
In Assembler hast Du also alle Freiheiten aber auch alle Verpflichtungen.

Gruß Wolfgang
 
Alle Stellen im Quellcode an denen "TICKS" steht werden beim Übersetzungsvorgang durch "0x61" ersetzt.


Es gibt bei Assembler keine Variablentypen. Es gibt in dem Sinne auch keine Variablen wie man sie aus anderen Programmiersprachen kennt. Du bastelst dir alles genau so zusammen wie du es grade brauchst. Dafür kannst du Konstrukte erzeugen die keine Hochsprache dir bieten kann.


Das ist in Assembler einfach eine Speicherstelle im SRAM oder wenn du es besonders schnell abarbeiten lassen willst dann ein Register.


Du könntest es in Assembler also so machen ...
.equ Variable=0x59 ; Speicheradresse für Variable definieren
ldi r16, 10 ; Da sts nicht direkt Werte speichern kann muß man es über ein Register machen
sts Variable, r16 ; Variablenwert(10) speichern[/CODE]

Mit nem Rechenregister ...
Code:
.equ Variable=16       ; Register für Variable definieren
ldi r16, 10                  ; Wert in der Variablen ablegen



Das SREG sprichst du normalerweise nur über die einzelnen Flags (Carry, HalfCarry, Sign, T-Bit, ...) an. Du mußt es nur als Byte speichern/zurückholen wenn du mit Interrupts arbeitest weil du ja in dem Programmteil aus dem dich der Interrupt herausgerissen hat nach dem Rücksprung wieder den alten Zustand benötigst.

Gruß
Dino

das verstehe ich erst mal für heute.
Das Andere von LotadaC...oldmax und Wolfgang werde ich morgen in aller Frühe durcharbeiten.
Danke für alles, habe mein Bascom Buch schnell wieder weggelegt.

Grüße an alle
wir sind schon bei Seite 2
 
ja, ich habe es 3x durchgelesen.....kapiere es langsam!
Über diesen "sts" Befehl steht im Ass.-Buch:
Speichere das Quellregister Rr in das direkt adressierte Byte im SRAM
als Beispiel:

sts tab,r16 ;SRAM Byte direkt adressiert
.DSEG ;Datensegment im SRAM
tab: .BYTE 1 ;1 Byte reserviert

Das muß ein Anfänger erst mal begreifen, aber Dank Eurer Hilfe kommt das schon.

Grüße

Rolf
 
:victory:
hinter tab verbirgt sich nur eine Zahl. Eine 16-bit-Konstante. Du hättest sie genauso mit .equ festlegen können, ABER der Sinn von .dseg und .byte ist, daß Du Dich selbst nicht um die Zuweisung der Adressen kümmern mußt. Es werden einfach (automatisch) fortlaufende Adressen (als Zahlen) verwendet. Wieviele jetzt zu einer Konstante gehören sollen (und welche Adresse zur nächsten gehört), legst Du mit der (An-)Zahl hinter .byte fest.
Insofern ist die Bezeichnung "reservieren" etwas unpassend, sowas gibts in ASM gar nicht, Du hast ja überall vollen Zugriff. Du kannst problemlos 'ne andere Konstante definieren, die dieselbe Speicherzelle referenziert ( .equ lustigerName=tab).
Zu STS: Das ist direkte Adressierung. Wenn Du indirekt adressiert speichern willst, verwendest Du analog dazu ST. Dazu wird zuerst die Adresse (tab - wir erinnern uns, ein 16-Bit-Wort) in eins der Doppelregister geladen (X,Y,Z - also high(tab) nach XH, low(tab) nach XL), und dann mit dem entsprechenden ST-Befehl gespeichert. Hierbei gibt es jetzt zusätzlich die Option, das Doppelregister dabei (automatisch) zu inkrementieren/dekrementieren, um so mit einem Rutsch 'n größeren Posten zu speichern. Das Lade-Äquivalent dazu ist LD.
 
Hi,

Wenn Du indirekt adressiert speichern willst, verwendest Du analog dazu ST. Dazu wird zuerst die Adresse (tab - wir erinnern uns, ein 16-Bit-Wort) in eins der Doppelregister geladen (X,Y,Z - also high(tab) nach XH, low(tab) nach XL), und dann mit dem entsprechenden ST-Befehl gespeichert. Hierbei gibt es jetzt zusätzlich die Option, das Doppelregister dabei (automatisch) zu inkrementieren/dekrementieren, um so mit einem Rutsch 'n größeren Posten zu speichern. Das Lade-Äquivalent dazu ist LD.
dazu gibt es tolle Abbildungen am Anfang der Instruction-Summary von Atmel.

Gruß
Dino
 
Hallo,

ich hab mal aus den drei Beiträgen wegen ...

Titel: "und wieder mal was Neues, damit ich nicht den Faden verliere! "

und ...

Hallo Rolf
tu dir und uns doch einen Gefallen und öffne mit neuen Problemen auch einen neuen Thread. Dann werden das nicht so ellen lange Beiträge.

einen neuen Thread erzeugt :cool:

Ist hier zu finden ...

AVR-Mikrocontrollerfamilie >> Hardware >> ExtINT >> Interrupts beim Tiny2313 (Assembler)

Ich hoffe der Titel gefällt und der Bereich paßt. Ging ja scheinbar um Externe Interrupts (INT und PCINT)

Gruß
Dino
 

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