Forum: Mikrocontroller und Digitale Elektronik Registerverständnisfrage


von André M. (killroymenzel)


Lesenswert?

Hallo....

Ich programmiere derzeit an einem, für mich, "grösseren" Programm,
und jetzt werden meine register knapp.


Den Y und Z Pointer-Register benutze ich auch.
Den X wollte ich mir noch freihalten für zukünftige Adressierungen.

Nun möchte ich evt Register unterhalb r16 benutzen, allerdings habe ich 
nicht gefunden, WAS mann mit den unteren (r0-r15) Register NICHT machen 
kann.

Wo finde ich die Informationen über die unteren register?

von Falk B. (falk)


Lesenswert?

@André Menzel (killroymenzel)

>Den Y und Z Pointer-Register benutze ich auch.
>Den X wollte ich mir noch freihalten für zukünftige Adressierungen.

Die muss man selten exclusiv freihalten, es reicht, sie in der 
jeweiligen Funktion zu nutzen. Die meisten Daten packt man so oser so 
besser in den SRAM und lädt sie bei Bedarf in die Register.

>Nun möchte ich evt Register unterhalb r16 benutzen, allerdings habe ich
>nicht gefunden, WAS mann mit den unteren (r0-r15) Register NICHT machen
>kann.

ldi, cpi ect. geht nicht.

>Wo finde ich die Informationen über die unteren register?

Im Assembler Instruction Set Manual vom AVR. Gibts bei Atmel zum 
Download.

von André M. (killroymenzel)


Lesenswert?

Danke Falk........

Jetzt studiere ich erst mal das

Instruction Set Nomenclature.



André

von Bernie (Gast)


Lesenswert?

In den meisten "größeren" Programmen empfiehlt es sich
öfter gebrauchte Programmabläufe als Unterprogramme
(mit "rcall") aufzurufen.

Dabei muss man sich vorher überlegen, welche Daten in
welchen Registern übergeben werden - und in welchen
Registern das Ergebnis erscheinen soll.

Alle anderen Register, die man im Unterprogramm benötigt,
werden zu Anfang des Unterprogramms mit "push" auf dem
Stack gesichert und vor dem Ende ("ret") mit "pop" so
wiederhergestellt, wie sie vorher waren.

von LostInMusic (Gast)


Lesenswert?

Mit den unteren Registern r0...r15 kannst Du alles machen außer:
1
ldi
2
sbr + cbr
3
ser
4
cpi
5
subi
6
sbci
7
andi + ori
8
adiw + sbiw

Diese Befehle stehen nur für r16...r31 zur Verfügung.

Natürlich kann man auch r0 z. B. mit einem konstanten Wert laden; es 
erfordert halt zwei Instruktionen:
1
ldi  ZL, 248
2
mov  r0, ZL

von c-hater (Gast)


Lesenswert?

André Menzel schrieb:

> Nun möchte ich evt Register unterhalb r16 benutzen, allerdings habe ich
> nicht gefunden, WAS mann mit den unteren (r0-r15) Register NICHT machen
> kann.

Operationen mit "immediate" Operatoren, also Konstanten, die Teil des 
Befehlswortes sind. Also alles, was prinzipiell so aussieht

Befehl Register,Konstante

als da wären:

ldi
andi
ori
subi
sbci
sbr
cbr

Dazu kommen noch Befehle, die zwar auf Quelltextebene nicht sofort 
erkennbar dieses Muster haben, aber auf Opcode-Ebene der gleichen Klasse 
angehören. Dazu fällt mit im Moment nur ein Vertreter ein:

ser

Und, last but not least, ist auch die Verwendung bei der Multiplikation 
nur eingeschränkt möglich, während "mul" auch mit diesen Registern 
arbeitet, sind alle anderen Multiplikationsoperationen dazu nicht in der 
Lage.

von killroymenzel (Gast)


Lesenswert?

Ich danke euch allen.....
Wenn mein Programm wieder läuft, werde ich es hier auch mal vorstellen.
Es ist eine Uhr mit normaler Weckfunktion
Und einen Kalender, der mich daran erinnert den Müll,  Papier und Gelbe 
Sack rauszubringen.
Verwendung findet:
DS1307 mit Batterie
AT24C32 für den Kalender
DS18B20 als Raumtemperatur
LCD 16×2 zur Anzeige

 Derzeit noch mit einem ATMega128,
Da ich noch nicht weiß wie groß das Programm wird.
Momentan bin ich bei 9k
 Gesteuert bzw eingestellt wird das ganze mit dem PC-Terminal
Ich hoffe ich schaffe das am Wochenende zum Laufen zu bekommen.

später soll das ganze auf große 16 Segment oder DOTMatrix angezeigt 
werden.
Und evt. mit SD und Netzwerk ausgestattet werden.

Andre

von Thomas (kosmos)


Lesenswert?

ich mache das so
1
.dseg
2
Ergebniss0:      .byte 1  ;Reserviert jeweils 1 Byte im SRAM
3
Ergebniss1:      .byte 1
4
Ergebniss2:      .byte 1
5
Ergebniss3:      .byte 1
6
Ergebniss4:      .byte 1
7
Ergebniss5:      .byte 1
8
Ergebniss6:      .byte 1
9
Ergebniss7:      .byte 1
10
11
Berechnung:
12
sts Ergebniss1, temp  ;Ergebniss(Register) im SRAM speichern

nachdem man es also im SRAM abgelegt hat kann man temp wieder 
anderweitig nutzen. Und wenn man das Ergebnis wieder braucht holt man es 
sich wieder in ein Register zurück.
1
lds temp, Ergebniss1

von killroymenzel (Gast)


Lesenswert?

Derzeit sieht das bei mir so aus:
1
;----------------------
2
;Register Defs
3
;----------------------
4
.def    Null    =  r0
5
.def    DayOld    =  r1      ;
6
.def    RTC_count  =  r2      ;
7
.def    Adr1    =  r3      ;TWI Word Adresse 1
8
.def    Adr2    =  r4      ;TWI Word Adresse 2 (für EEProm)
9
.def    full    =  r5
10
.def    half    =  r6
11
.def    accu    =  r16      ;Hauptarbeitsregister
12
.def    temp    =  r17      ;Zählregister
13
.def    index    =  r18      ;Hauptindex
14
.def    IRQ_index  =  r19      ;IRQ sekundenzähler
15
.def    TWI_IC    =  r20      ;TWI Ic Adresse
16
.def    Flag    =  r23      ;Flag
17
18
.equ    restmuell  =  0      ;restmuell rausstellen
19
.equ    papiertonne  =  1      ;Papiertonne rausstellen
20
.equ    gelbersack  =  2      ;Gelber Sack rausstellen
21
.equ    WireError  =  3      ;One Wire presence Error
22
.equ    Flash_RAM  =  4      ;Ausgabe aus Flash oder Ram
23
.equ    LCD_RS232  =  5      ;Ausgabe auf LCD oder UART
24
.equ    TWI_Adr    =  6      ;2 Wordadresse nötig?
25
.equ    Wecker_on  =  7      ;Wecker ist aus oder an
26
27
.def      rawlow     =    r24          ;Rohwert DS18B20 LSB
28
.def      rawhigh   =    r25      ;Rohwert DS18B20 MSB
29
.def    nachkomma  =  r26
30
31
.equ    DQ     =    7              ;Datenleitung des Ds18B20
32
.equ      DS_DDR      =    DDRC      ;Port des DS18B20
33
.equ      DS_Port   =    PortC      ;
34
.equ      DS_Pin    =    PinC      ;
35
.equ    LCD    =  PortB      ;LCD-Datenport
36
.equ    LCDDDR    =  DDRB      ;
37
.equ    LCMD    =  PortA      ;LCD-kommandoport
38
.equ    LCMDDR    =  DDRA      ;
39
.equ    EN    =  1      ;Enable-Leitung
40
.equ    RS    =  0      ;Kommando / Daten Leitung
41
42
.equ    XTAL    =  4000000      ;Quartzfrequenz
43
.equ    BAUD    =  19200      ;Baudrate für UART
44
  
45
.equ    DS1307    =  0xD0      ;TWI Adresse 
46
.equ    AT24C32    =  0xA0      ;TWI Adresse
47
48
49
/************************************************
50
*  Speicherreservierung im SRAM    *
51
************************************************/
52
.dseg
53
Wecker_copy:    .byte    5      ;Wecker Speicher
54
TWI_copy:    .byte    32      ;I²C Temp Speicher
55
RomCopy:    .byte    20      ;RomAdresse DS18B20      
56
Tempcopy:    .byte    10      ;+xx,x°C
57
Timecopy:    .byte    15      ;xx:xx:xx_
58
DateCopy:    .byte    15      ;xx.xx.20xx
59
DayCopy:    .byte    20      ;Mo____
60
RTC_Copy:    .byte    10      ;Speicher zum RTC einstellen
61
CompareCopy:    .byte    5      ;temporärer Speicher

: Bearbeitet durch User
von Cyblord -. (cyblord)


Lesenswert?

Sprachenmix bei Bezeichnern ist allgemeine ein schlechter Stil. Lege 
dich doch auf eine Sprache fest.
Vor allem innerhalb EINER Variablen ist es übel:
> Wecker_on

Und ist es wirklich Sinnvoll konkrete Ereignisse fest 
einzuprogrammieren? Wenn dann würde man doch das Definieren von 
beliebigen Terminen bzw. Erinnerungen vorsehen. Selbst wenn es keine 
Interaktion von aussen ist, sollte man einen solchen Mechanismus 
wenigstens innerhalb des Programmes vorsehen.

: Bearbeitet durch User
von killroymenzel (Gast)


Lesenswert?

cyblord ---- schrieb:
> Sprachenmix bei Bezeichnern ist allgemeine ein schlechter Stil. Lege
> dich doch auf eine Sprache fest.

Da muss ich dir leider rechtgeben.
Allerdings ist das Programm "naturgewachsen", so dass noch viiel 
schlimmere Dinge passiert sind......
1
Beispiel:
2
LCD_Tag:  ldi      zl,low(Wochentag*2)
3
    ldi      zh,high(Wochentag*2)
4
    rjmp    LCD_string
5
LCD_Datum:  ldi      zl,low(Datum*2)
6
    ldi      zh,high(Datum*2)
7
    rjmp    LCD_string
8
LCD_Zeit:  ldi      zl,low(Uhrzeit*2)
9
    ldi      zh,high(Uhrzeit*2)
10
    rjmp    LCD_string
11
LCD_Time:  rcall    LCD_home
12
    ldi    zl,low(TimeCopy)      
13
    ldi      zh,high(TimeCopy)    
14
    rjmp    LCD_stringram
15
LCD_Temp:    cursor,9,0
16
    ldi      zl,low(tempcopy)      
17
    ldi      zh,high(tempcopy)    
18
    rjmp    LCD_stringram          
19
LCD_Day:  rcall    LCD_2z
20
    ldi      zl,low(DayCopy)
21
    ldi      zh,high(DayCopy)
22
    rjmp    LCD_stringram
23
LCD_Date:    cursor,6,1  
24
    ldi      zl,low(DateCopy)
25
    ldi      zh,high(DateCopy)
26
    rjmp    LCD_stringram

ABER..... Wenn ich das ganze Programm zum laufen bekomme, werde ich 
organisatorisch noch viel zu ändern habe.

: Bearbeitet durch User
von Karol B. (johnpatcher)


Lesenswert?

killroymenzel schrieb:
> ABER..... Wenn ich das ganze Programm zum laufen bekomme, werde ich
> organisatorisch noch viel zu ändern habe.

Die Frage ist, ob und in welcher Zeit du das Programm in seiner 
aktuellen Form zum Laufen bekommst. Der Ansatz "Ich mach mal alles Quick 
& Dirty, und am Schluss räume ich auf" funktioniert halt bei größeren 
Projekten nicht mehr wirklich. Zumal das Aufräumen in der Praxis sowieso 
oft weg fällt, weil das nächste Projekt schon ruft. Coding Conventions 
und guten Programmierstil muss man soweit verinnerlichen, dass man das 
ganz automatisch macht ;).

Mit freundlichen Grüßen,
Karol Babioch

: Bearbeitet durch User
von killroymenzel (Gast)


Lesenswert?

Da gebe ich dir recht.....
Ich habe die ganzen kleinen LCD Routinen schon wieder  rausgeschmissen. 
...

Ich habe auch meine eigenen kleinen libs geschrieben,  so dass ich bei 
bedarf nur noch die Sachen auf include setzen muss.  So wie z.B.

TWI
LCD
UART
OneWire

Es sieht mittlerweile auch schon ganz organisiert aus.


Andre

von Karol B. (johnpatcher)


Lesenswert?

killroymenzel schrieb:
> Ich habe die ganzen kleinen LCD Routinen schon wieder  rausgeschmissen.

Das z.B. ist nicht einmal unbedingt notwendig. Sofern es Sinn macht 
entsprechende Sprungmarken anzulegen (weil man darauf referenziert), 
macht es ja nichts, wenn es davon viele gibt. Die Kunst ist es alles so 
lokal wie möglich zu halten, damit es nicht zu Namenskonflikten und 
anderen Nebeneffekten kommt. Und da sind die Assembler i.d.R. nicht 
annähernd so mächtig wie C und andere Hochsprachen. Soweit ich weiß (nie 
wirklich damit gearbeitet) bietet der AVR Assembler, welcher mit dem 
Atmel Studio mitgeliefert wird, hierfür keine Möglichkeiten. avr-as 
hingegen bietet Möglichkeiten, um externe Funktionen mittels "global" 
entsprechend zu markieren, sodass ein Großteil der internen Details 
eines Moduls verborgen werden kann.

Mit freundlichen Grüßen,
Karol Babioch

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

killroymenzel schrieb:
> Momentan bin ich bei 9k

Für Assembler ist das schon recht heftig. Da ist bestimmt viel 
Copy&Paste drin, aber kaum Unterfunktionen.

Oder meinst Du die Größe des Hex. Das Hex ist etwa 2,8 mal so groß, wie 
der wirkliche Code.

von Karol B. (johnpatcher)


Lesenswert?

Peter Dannegger schrieb:
> Oder meinst Du die Größe des Hex. Das Hex ist etwa 2,8 mal so groß, wie
> der wirkliche Code.

Wie kommst du zu dieser Zahl? Doppelt so viele Bytes wegen 
Hexdarstellung + Overhead durch Adressen und Prüfsummen?

von killroymenzel (Gast)


Lesenswert?

Ja... ich meine das hex file......

Ich werde es heute abend testen und wenn es läuft lade ich es mal 
hoch.....

Dann könnt ihr much zerreißen. ..... ;-)


Andre

von Peter D. (peda)


Lesenswert?

Hier mal ein 1kB großes Programm:

Beitrag "Zeit + Temperatur auf LCD mit AVR"

von spess53 (Gast)


Lesenswert?

Hi

>Derzeit sieht das bei mir so aus:
>;----------------------
>;Register Defs
>;----------------------
>.def    Null    =  r0
>.def    DayOld    =  r1      ;

Würde ich nicht machen. R1 und R2 werden bei Benutzung des 
Hardwaremultiplizierers zerstört.

Hier

Beitrag "Kalender/Datum/Zeit-Funktionen in Assembler"

hatte ich vor längerer Zeit mal einige Routinen zu Datum/Uhrzeit 
veröffentlicht. Evtl. kannst du etwas davon gebrauchen.

MfG Spess

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.