Forum: Compiler & IDEs include headerfiles in Assembler


von Dominik (Gast)


Lesenswert?

Hallo,
ich bin neu in Assembler und komme nicht ganz mit der $include Funktion 
bzw. den headerfiles in Assembler zurecht. Als IDE benutzte ich Keil.

Ich habe ein Programm geschrieben, mit dem ich auf ein LCD Display 
zugreifen kann. Um alles etwas zu vereinfachern möchte ich das ganze 
jetzt als externe Datei haben und eben die einzelnen 
Methoden/Unterprogramme so aufrufen.
Allerdings funktioniert es nicht ganz so wie ich es mir vorstelle, trotz 
Tutorials und Erklärungen.

Zudem habe ich niergends gefunden, ob die Variablendeklaration, so wie 
ich es gemacht habe überhaupt funktionieren kann. Oder ob ich die 
Register für meine externe Datei verwenden darf.

Wie gesagt bin ich blutiger Anfänger, ich hoffe trotzdem, dass mir 
jemand helfen kann.

Einzubinden habe ich es auf diesem Weg versucht:
1
$include(lcd_display.h)
2
3
ORG 00h
4
  SJMP INIT_PROGRAMM
5
  
6
INIT_PROGRAMM:
7
  MOV P1,#00110011b
8
9
  ACALL LCD_INIT // Unterprogramm aus lcd_display
10
    
11
  MOV A, #41h // A
12
  ACALL LCD_DATA // Unterprogramm aus lcd_display
13
  
14
  MOV P1,#11001100b
15
END

Das ist das Programm, welches ich gerne als Headerfile benutzten würde:
1
U  EQU  31    ;Variable um Upper Nibble zu speichern
2
L  EQU  32    ;Variable um Lower Nibble zu speichern
3
  
4
PORT   EQU  P2   ; Port direkt
5
D4     EQU  p2.0 ; Datenbus
6
D5     EQU  p2.1 ; Datenbus
7
D6     EQU  p2.2 ; Datenbus
8
D7    EQU  p2.3 ; Datenbus
9
HG     EQU  p2.7 ; ?
10
RS    EQU  p2.6 ; Register Select ( 0 = Befehl / 1 = Daten )
11
RW    EQU  p2.5 ; Read / Write ( 0 = Schreiben / 1 = Lesen )
12
EN    EQU  p2.4 ; Enable
13
14
  
15
LCD_INIT:
16
  CLR RS
17
  SETB RW
18
  
19
  // 4-Bit Datenlänge einschalten
20
  MOV PORT, #0
21
  SETB D5
22
  ACALL DELAY
23
24
  // 4-Bit Datenlänge, 2-zeiliges Display, 5x7 Front
25
  MOV PORT, #0
26
  SETB D5
27
  ACALL DELAY
28
  
29
  MOV PORT, #0
30
  SETB D7
31
  ACALL DELAY
32
  
33
  // Display ein, Cursor ein, Cursor blinken
34
  MOV PORT, #0
35
  ACALL DELAY
36
  
37
  MOV PORT, #0
38
  SETB D4
39
  SETB D5
40
  SETB D6
41
  SETB D7
42
  ACALL DELAY
43
  
44
  // Display löschen, Cursor auf Position 1 setzen
45
  MOV PORT, #0
46
  ACALL DELAY
47
  
48
  MOV PORT, #0
49
  SETB D4
50
  ACALL DELAY
51
  
52
  // Cursor Auto-Increment
53
  MOV PORT, #0
54
  ACALL DELAY  
55
  
56
  MOV PORT, #0
57
  SETB D5
58
  SETB D6
59
  ACALL DELAY  
60
  ACALL WAIT_L
61
RET
62
63
SEPARATOR: // Seperator teilt das Byte in Upper und Lower Nibble, um den 4bit Datentransport zu ermöglichen
64
  // Beispielsbuchstabe: 0101 0011
65
    mov  L ,A     ; schreibe 0101 0011 in Lower Nibble
66
    
67
    ANL  L, #00001111b ; AND prüfen mit 0101 0011 mit 0000 1111, ergibt 0000 0011
68
    
69
    SWAP A       ;  Tausche Akkuinhalt 0101 0011 ergibt 0011  0101
70
    
71
    MOV  U, A     ; schreibe 0011 0101 in Upper Nibble
72
    ANL  U, #00001111b ; AND prüfen mit 0011 0101 mit 0000 1111, ergibt 0000 0101
73
RET 
74
75
76
LCD_DATA: // Daten an LCD senden
77
  SETB RS
78
  //RS (Register Select) ist die Auswahl zwischen 0: "Instruction-Register" und 1: "Data-Register"
79
  // Instruction-Register (0) ist für Befehle, Data-Register (1) ist für Daten (z.B. Texte schreiben)
80
81
  ACALL  SEPARATOR
82
  ORL L, #11000000b ; OR prüfen mit 0000 0011 mit 1100 0000, ergibt 1100 0011
83
  ORL U, #11000000b ; OR prüfen mit 0000 0101 mit 1100 0000, ergibt 1100 0101
84
            ; laut Beschreibung sollte #10000000b statt #11000000b verwendet werden, 
85
            ; da RW auf 0 für Schreiben ist,
86
            ; allerdings funktioniert der Datentransport dann nicht
87
  ACALL  MOVE_TO_PORT
88
RET 
89
  
90
91
LCD_CMD: // Befehle an LCD senden
92
  CLR RS ; 
93
  SETB RW
94
  //RS (Register Select) ist die Auswahl zwischen 0: "Instruction-Register" und 1: "Data-Register"
95
  // Instruction-Register (0) ist für Befehle, Data-Register (1) ist für Daten (z.B. Texte schreiben)
96
97
  ACALL  SEPARATOR 
98
  ACALL  MOVE_TO_PORT
99
RET 
100
101
102
LCD_CLEAR: // Display löschen, Cursor auf Position 1 setzen
103
  MOV PORT, #0
104
  ACALL DELAY
105
  
106
  MOV PORT, #0
107
  SETB D4
108
  ACALL DELAY
109
RET
110
 
111
112
MOVE_TO_PORT: // Sende die Daten (Lower-& Upper-Nibble) an den Port  
113
  CLR RW // setze RW auf 0, bedeutet: Schreiben
114
  MOV PORT, U // Zuerst Upper Nibble
115
  ACALL DELAY
116
  
117
  CLR RW
118
  MOV PORT, L // Danach Lower Nibble
119
120
  ACALL DELAY  
121
RET
122
123
124
MOVE_CURSOR_RIGHT: // Cursor nach rechts bewegen
125
  CLR RS
126
  CLR RW
127
  // BEFEHL:
128
  
129
  // D7 D6 D5 D4 D3 D2 D1 D0
130
  //  0  0  0  1 SC RL  *  * 
131
  
132
  // RL: 0=Links 1=Rechts    SC: 0=Cursor 1=Display(Shift)  
133
  
134
  MOV A, #00010100b
135
  ACALL LCD_CMD
136
RET
137
138
139
MOVE_CURSOR_LEFT: // Cursor nach links bewegen
140
  CLR RS
141
  CLR RW
142
  MOV A, #00010000b
143
  ACALL LCD_CMD
144
RET
145
146
147
SHIFT_DISPLAY_RIGHT: // Display nach rechts verschieben
148
  CLR RS
149
  CLR RW
150
  MOV A, #00011100b
151
  ACALL LCD_CMD
152
RET
153
154
155
SHIFT_DISPLAY_LEFT: // Display nach links verschieben
156
  CLR RS
157
  CLR RW
158
  MOV A, #00011000b
159
  ACALL LCD_CMD
160
RET
161
162
163
DELAY: // Das Enable-Bit wird gesetzt, danach kurz gewartet und wieder gelöscht. 
164
       // So wird ein Befehl an das Display gesendet
165
  SETB  EN   
166
  ACALL WAIT
167
  CLR  EN    
168
RET
169
170
171
// Kürzeste WAIT-Schleife für LCD Display
172
WAIT:
173
  MOV R7 , #7
174
  l1: MOV R6 , #7
175
  l2: DJNZ R6, l2
176
    DJNZ R7, l1
177
RET
178
179
// Längere WAIT-Schleife für sichtbare Veränderungen
180
WAIT_L:
181
  MOV R5 , #60
182
  c1: MOV R4 , #60
183
  c2: MOV R3 , #60
184
  c3: DJNZ R3, c3
185
    DJNZ R4, c2
186
    DJNZ R5, c1
187
RET

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Dominik schrieb:
> $include(lcd_display.h)

Das solltest du erst an der Stelle im Code schreiben, an der es passt. 
Im Moment steht es vor dem Reset Vektor und damit wird vermutlich etwas 
überschrieben, spätestens, wenn das .ORG Statement kommt. Also erst an 
einer Stelle einfügen, wo es passt.

von Heinz V. (heinz_v)


Lesenswert?

Was zeigt die IDE denn im Meldungsfenster?

von Dominik (Gast)


Lesenswert?

Habe den $include Befehl jetzt nach INIT_PROGRAMM eingefügt, allerdings 
funktioniert es noch immer nicht.

Die IDE zeigt keine Warnings oder Fehler.

von Heinz V. (heinz_v)


Lesenswert?

BTW. liegt die Include Datei (wieso eigentlich xxx.h und nicht xxx.inc?) 
denn im selben Verzeichniss wie dein Quellcode? Oder erwartet Keil vll 
sowieso eine absolute Pfad Angabe?

von Volker S. (vloki)


Lesenswert?

Das macht man doch heutzutage nicht mehr so, oder?
(ORG und Programmcode über include einfügen. Dafür hat man doch den 
Linker)

Keil kabe schon seit Ewigkeiten nicht mehr benutzt, aber ich kann mir 
irgendwie nicht so recht vorstellen, dass das der Weg ist.
Frage an erfahrene Keil Assembler Nutzer: "Irre ich mich da total?"

von Heinz V. (heinz_v)


Lesenswert?

Volker S. schrieb:
> Das macht man doch heutzutage nicht mehr so, oder?
> (ORG und Programmcode über include einfügen. Dafür hat man doch den
> Linker)

Include bindet einfach weiteren Quelltext ein, zur Zeit des 
Assemblierens, das ist aber kein einfaches 'merging' bei MASM32 oder A86 
werden nur die Prozeduren übersetzt die das Hauptprogramm auch 
verwendet.

Der org Pseudoopcode legt den Programmstart fest, doch manchmal ist das 
wohl nötig (x.bin Dateien starten normalerweise bei 0 und wei DOS/WIN 
Executables steht ein jmp Startaddresse am Anfang des Programmheaders.)

von Volker S. (vloki)


Lesenswert?

Hmmm, auf den ersten Blick sah das für mich so nach 8051 Assembler aus.
Ist wohl einfach zu lange her ;-)

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.