Forum: Mikrocontroller und Digitale Elektronik LCD mit 2 Controllern via Assembler ansteuern klappt nicht.


von Flo S. (tuxianer)


Lesenswert?

Ich stell das Thema jetzt nochmal unter meinem Login und unter nem 
besseren Titel rein. Also ich habe für mein 4x40 Display mit assembler 
nen bissl was geschrieben in Anlehnung an das Tutorial hier. Das Problem 
ist jetzt, dass ich jetzt immer Abwechselnd oben oder Unten nen 
schwarzen Balken aufm Display habe und an der Jeweils anderen Seite 2x 
hintereinander Test. hier der Code:
1
.include "m32def.inc"
2
3
.def temp1 = r16
4
.def temp2 = r17
5
.def temp3 = r18
6
.def lcdno = r19
7
8
9
           ldi temp1, LOW(RAMEND)      ; LOW-Byte der obersten
10
RAM-Adresse
11
           out SPL, temp1
12
           ldi temp1, HIGH(RAMEND)     ; HIGH-Byte der obersten
13
RAM-Adresse
14
           out SPH, temp1
15
16
           ldi temp1, 0xFF    ; Port D = Ausgang
17
           out DDRD, temp1
18
19
           cbr lcdno, 0
20
           rcall lcd_init     ; Display initialisieren
21
           rcall lcd_clear    ; Display löschen
22
           sbr lcdno, 0
23
           rcall lcd_init     ; Display initialisieren
24
           rcall lcd_clear    ; Display löschen
25
26
27
           cbr lcdno, 1
28
           ldi temp1, 'T'     ; Zeichen anzeigen
29
           rcall lcd_data
30
31
           ldi temp1, 'e'     ; Zeichen anzeigen
32
           rcall lcd_data
33
34
           ldi temp1, 's'     ; Zeichen anzeigen
35
           rcall lcd_data
36
37
           ldi temp1, 't'     ; Zeichen anzeigen
38
           rcall lcd_data
39
40
41
42
           sbr lcdno, 1
43
           ldi temp1, 'T'     ; Zeichen anzeigen
44
           rcall lcd_data
45
46
           ldi temp1, 'e'     ; Zeichen anzeigen
47
           rcall lcd_data
48
49
           ldi temp1, 's'     ; Zeichen anzeigen
50
           rcall lcd_data
51
52
           ldi temp1, 't'     ; Zeichen anzeigen
53
           rcall lcd_data
54
55
loop:
56
           rjmp loop
57
58
.include "lcd-routines.asm"            ; LCD-Routinen werden hier eingefügt


1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                 LCD-Routinen                ;;
3
;;                 ============                ;;
4
;;              (c)andreas-s@web.de            ;;
5
;;                                             ;;
6
;; 4bit-Interface                              ;;
7
;; DB4-DB7:       PD0-PD3                      ;;
8
;; RS:            PD4                          ;;
9
;; E:             PD5                          ;;
10
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
11
12
13
.equ LCD_PORT = PORTD
14
.equ LCD_DDR  = DDRD
15
.equ PIN_E    = 5
16
.equ PIN_E2   = 6
17
.equ PIN_RS   = 4
18
.equ XTAL  = 16000000
19
20
 ;sendet ein Datenbyte an das LCD
21
lcd_data:
22
           mov temp2, temp1             ; "Sicherungskopie" für
23
                                        ; die Übertragung des 2.Nibbles
24
           swap temp1                   ; Vertauschen
25
           andi temp1, 0b00001111       ; oberes Nibble auf Null setzen
26
           sbr temp1, 1<<PIN_RS         ; entspricht 0b00010000
27
           out LCD_PORT, temp1          ; ausgeben
28
           rcall lcd_enable             ; Enable-Routine aufrufen
29
                                        ; 2. Nibble, kein swap da es
30
schon
31
                                        ; an der richtigen stelle ist
32
           andi temp2, 0b00001111       ; obere Hälfte auf Null setzen
33
           sbr temp2, 1<<PIN_RS         ; entspricht 0b00010000
34
           out LCD_PORT, temp2          ; ausgeben
35
           rcall lcd_enable             ; Enable-Routine aufrufen
36
           rcall delay50us              ; Delay-Routine aufrufen
37
           ret                          ; zurück zum Hauptprogramm
38
39
40
 ; sendet einen Befehl an das LCD
41
42
lcd_command:                            ; wie lcd_data, nur RS=0
43
           mov temp2, temp1
44
           swap temp1
45
           andi temp1, 0b00001111
46
           out LCD_PORT, temp1
47
           rcall lcd_enable
48
           andi temp2, 0b00001111
49
           out LCD_PORT, temp2
50
           rcall lcd_enable
51
           rcall delay50us
52
           ret
53
54
55
56
 ; erzeugt den Enable-Puls
57
lcd_enable:
58
           sbrs lcdno, 1
59
       sbi LCD_PORT, PIN_E          ; Enable high
60
       sbrc lcdno, 1
61
       sbi LCD_PORT, PIN_E2          ; Enable high
62
           nop                          ; 3 Taktzyklen warten
63
           nop
64
           nop
65
           cbi LCD_PORT, PIN_E          ; Enable wieder low
66
       cbi LCD_PORT, PIN_E2
67
           ret
68
                                ; Und wieder zurück
69
70
71
72
 ; Pause nach jeder Übertragung
73
delay50us:                              ; 50us Pause
74
           ldi  temp1, ( XTAL * 50 / 4 ) / 1000000
75
delay50us_:
76
           dec  temp1
77
           nop                          ; tu nichts
78
           brne delay50us_
79
           ret
80
81
 ; Längere Pause für manche Befehle
82
delay5ms:                               ; 5ms Pause
83
           ldi  temp1, ( XTAL * 5 / 607 ) / 1000
84
WGLOOP0:   ldi  temp2, $C9
85
WGLOOP1:   dec  temp2
86
           brne WGLOOP1
87
           dec  temp1
88
           brne WGLOOP0
89
           ret                          ; wieder zurück
90
; wieder zurück
91
92
 ; Initialisierung: muss ganz am Anfang des Programms aufgerufen werden
93
lcd_init:
94
           ldi   temp1, 0xFF            ; alle Pins am Ausgabeport auf
95
Ausgang
96
           out   LCD_DDR, temp1
97
98
           ldi   temp3,6
99
powerupwait:
100
           rcall delay5ms
101
           dec   temp3
102
           brne  powerupwait
103
           ldi   temp1,    0b00000011   ; muss 3mal hintereinander
104
gesendet
105
           out   LCD_PORT, temp1        ; werden zur Initialisierung
106
           rcall lcd_enable             ; 1
107
           rcall delay5ms
108
           rcall lcd_enable             ; 2
109
           rcall delay5ms
110
           rcall lcd_enable             ; und 3!
111
           rcall delay5ms
112
           ldi   temp1, 0b00000010      ; 4bit-Modus einstellen
113
           out   LCD_PORT, temp1
114
           rcall lcd_enable
115
           rcall delay5ms
116
           ldi   temp1, 0b00101000      ; 4 Bot, 2 Zeilen
117
           rcall lcd_command
118
           ldi   temp1, 0b00001100      ; Display on, Cursor off
119
           rcall lcd_command
120
           ldi   temp1, 0b00000100      ; endlich fertig
121
           rcall lcd_command
122
           ret
123
124
125
126
 ; Sendet den Befehl zur Löschung des Displays
127
lcd_clear:
128
           ldi   temp1, 0b00000001      ; Display löschen
129
           rcall lcd_command
130
           rcall delay5ms
131
           ret
132
133
 ; Sendet den Befehl: Cursor Home
134
lcd_home:
135
           ldi   temp1, 0b00000010      ; Cursor Home
136
           rcall lcd_command
137
           rcall delay5ms
138
           ret
kann mir da jemand weiterhelfen?

von Thorsten (Gast)


Lesenswert?

cbr und sbr arbeiten jeweils mit Bitmasken, anstatt mit Bitnummern.

Um z.B. Bit 0 zu löschen musst du schreiben:

cbr flags, 1<<0

setzen erfolgt nach gleichem Schema

sbr flags, 1<<0

Ändere das mal bei dir.

von Flo S. (tuxianer)


Lesenswert?

und wieso flags?

von Thorsten (Gast)


Lesenswert?

Ersetze "flags" durch ein Register deiner Wahl. War nur ein Beispiel.

von ozo (Gast)


Lesenswert?

Ich schätze mal, hier liegt der Hund im Pfeffer:

.equ PIN_E    = 5
.equ PIN_E2   = 6
.equ PIN_RS   = 4

Das sollten alles Zweierpotenzen sein, wenn du einzelne Pins selektieren 
willst.

von Flo S. (tuxianer)


Lesenswert?

ich habs mal geändert ist das korrekt so?
1
.include "m32def.inc"
2
 
3
.def temp1 = r16
4
.def temp2 = r17
5
.def temp3 = r18
6
.def lcdno = r19
7
 
8
 
9
           ldi temp1, LOW(RAMEND)      ; LOW-Byte der obersten RAM-Adresse
10
           out SPL, temp1
11
           ldi temp1, HIGH(RAMEND)     ; HIGH-Byte der obersten RAM-Adresse
12
           out SPH, temp1
13
 
14
           ldi temp1, 0xFF    ; Port D = Ausgang
15
           out DDRD, temp1
16
 
17
       sbr lcdno, 1<<0
18
       rcall lcd_init     ; Display initialisieren
19
       rcall lcd_clear    ; Display löschen
20
       cbr lcdno, 1<<0
21
       rcall lcd_init     ; Display initialisieren
22
           rcall lcd_clear    ; Display löschen
23
 
24
25
           sbr lcdno, 1<<0
26
           ldi temp1, 'T'     ; Zeichen anzeigen
27
           rcall lcd_data
28
 
29
           ldi temp1, 'e'     ; Zeichen anzeigen
30
           rcall lcd_data
31
           
32
           ldi temp1, 's'     ; Zeichen anzeigen
33
           rcall lcd_data
34
 
35
           ldi temp1, 't'     ; Zeichen anzeigen
36
           rcall lcd_data
37
38
39
40
           cbr lcdno, 1<<0
41
       ldi temp1, 'T'     ; Zeichen anzeigen
42
           rcall lcd_data
43
 
44
           ldi temp1, 'e'     ; Zeichen anzeigen
45
           rcall lcd_data
46
           
47
           ldi temp1, 's'     ; Zeichen anzeigen
48
           rcall lcd_data
49
 
50
           ldi temp1, 't'     ; Zeichen anzeigen
51
           rcall lcd_data
52
 
53
loop:
54
           rjmp loop
55
 
56
.include "lcd-routines.asm"            ; LCD-Routinen werden hier eingefügt

aber bringen tuts nix...

von Flo S. (tuxianer)


Lesenswert?

oh...du hast Bit 0 gestezt in meinem 2. Code war jedoch noch Bit 1...ich 
glaub jetzt gehts...

von Thorsten (Gast)


Lesenswert?

Ja, du hast recht.

Du setzt/löscht Bit 0 und prüfst auf Bit 1.

Wenn du dir das bit als Konstante definierst wird das ganze auch besser 
lesbar.

.equ SELECT = 0

sbr lcdno, 1<<SELECT

cbr lcdno, 1<<SELECT

bzw.

sbrs lcdno, SELECT

sbrc lcdno, SELECT

Namen kannst Du dir ja nen passenenden ausdenken.

von Flo S. (tuxianer)


Lesenswert?

ja danke...es geht ich hab es auch als konstante definiert...nur steh 
ich jetzt vor der nächsten herausforderung:

http://www.mikrocontroller.net/articles/AVR-Tutorial:_LCD#Ausgabe_eines_konstanten_Textes


konstanter text...so wird das nix mit 2 Controllern ich wüste 
zumindestens nicht wie...

von Thorsten (Gast)


Lesenswert?

Du könntest dir im SRAM ein Speicherbereich nehmen, der so groß wie die 
Zeichenanzahl auf deinem LCD ist.

Alle ausgaben die aufs LCD gehen sollen biegst du dann so um, dass sie 
ins SRAM an die gewünschte Position schreiben.

Den Inhalt vom SRAM gibts du dann von einem Timer gesteuert z.B. alle 
paar ms komplett auf das Display aus. So besteht das Display für dein 
Programm aus einem linear zusammenhängenen Bereich.

Die Aufteilung in Zeilen und Controller macht dann die Routine, die 
alles aufs Display schaufelt.

z.B.

Display mit 4x27 Zeichen (5€-Teil bei Pollin)

Speicher im SRAM ist dann 4x27 = 108 Bytes groß.

Die Schreibroutine selektiert dann zuerst Controller 1, Zeile 1 und 
schaufelt die ersten 27 Bytes raus.
Dann wird auf Zeile 2 umgeschaltet. Addresse und Befehl dafür steht im 
Datenblatt vom Display und raus gehen die nächsten 27 Byte.

gleiches Spiel dann mit Controller 2

von Flo S. (tuxianer)


Lesenswert?

Ui...timer so weit bin ich im tutorial noch gar nicht...ich werde wohl 
das Display erstmal 2 Zeilig betreiben und dann später wenn ich mehr 
kann hier weiter machen...

von Flo S. (tuxianer)


Lesenswert?

ach noch was...wie kann ich mit Assembler eigene Zeichen erstellen?

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.