Hallo, ich versuche seit geraumer Zeit etwas auf einem LCD mit dem Controller ST7920 auszugeben. Leider ohne Erfolg! Hat jemand Erfahrung mit diesem Controller?
DaS Netz ist voll mit libs und Code dazu. Daher stellt sich die Frage, was du bisher probiert hast, und auch, womit? Oliver
Erst schon mal danke, daß du auf meine Frage reagierst. Ganz so viele Codes sind im Netz nicht vorhanden und wenn dann nur in C, was mir nicht weiterhilft. Probiert habe ich schon so ziemlich alles, aber ich scheine etwas noch nicht verstanden zu haben. Init und Commands sind kein Problem, aber ich bekomme keine Anzeige, außer dem Curser. Mir ist nicht klar wie ich Zugriff bekomme auf die ASCII Bytes im HCGROM. Nur den Curser setzen und 2 Bytes schreiben funktioniert nicht. Ich kann natürlich auch gerne meine asm-Code-Schnipsel zeigen wenn das hilft.
Aha. Also kein C, und im Nebensatz steht was von ASM. Und das schon im zweiten Beitrag... Vielleicht denkst du doch nocmal drüber nach, wie denn jemand was zu deiner Frage schreiben soll, wenn kein Mensch weiß, womit und worauf du da rumprogrammierst? Oliver
Meinen ersten Beitrag habe ich schon mit AVR ASM überschrieben, aber aus Erfahrung weiß ich, daß darauf kaum jemand reagiert. Meine Fragen sind aber eigentlich unabhängig von der Programmiersprache, sondern betreffen die Interpretation des Datenblattes. Wenn dann noch jemand Interesse an meinem Code hat, dann natürlich umso besser.
Hallo, hier mal ein Codeschnipsel, leider nicht in ASm, aber es geht um das Verständnis: (das Datenblatt nochmals zu studieren geht mit zu lange) Beitrag "DG14032 Grafikdisplay und ST7920-Demo-Programm" mfG
:
Bearbeitet durch User
Christian S. schrieb: > hier mal ein Codeschnipsel vom Prinzip her habe ich das auch x-mal so versucht. Der Teufel liegt sicherlich im Detail. GLCD_Write(RS_CMD,CMD_SET_DDRAM_ADR|(y*16+(x&0x1E))); was bedeutet diese Zeile genau? RS_CMD - heißt das RS setzen? y*16+(x&0x1E) - ich nehme an y ist die Zeile und x die Spalte. Wenn ich also die Startposition haben will, dann bleibt nur 0x1E weil x und y 0 sind. Ist das richtig?
Ich habe mir den gesamten Code von DG14032 nochmals angesehen und kann meine Fragen teilweise selbst beantworten: #define RS_CMD 0 #define CMD_SET_DDRAM_ADR 0x80 CMD_SET_DDRAM_ADR|(y*16+(x&0x1E)) bedeutet bei x und y = 0: 0b10011110 richtig?
> CMD_SET_DDRAM_ADR|(y*16+(x&0x1E)) bedeutet bei x und y = 0: 0b10011110
stimmt nicht! Ich habe das & nicht berücksichtigt. Die Antwort ist also
0x80
#define RS_DATA 1 #define RS_CMD 0 ist eine Konstante static void RS (uint8_t val) { if (val) PORT_RS |= (1<<BIT_RS); else PORT_RS &= ~(1<<BIT_RS); } setzt den RS-Ausgang bei 1 und löscht ihn bei 0 _______________________________ GLCD_Write(RS_CMD,CMD_SET_DDRAM_ADR|(y*16+(x&0x1E))); links des Kommas ist also 0; 0x80 bitweise verodert mit (( 16 mal y plus (x bitweise verundet mit 0x1E)) https://de.wikibooks.org/wiki/C-Programmierung:_Ausdr%C3%BCcke_und_Operatoren#Bitweises_UND_/_AND_& Bei Fehlern bitte korrigieren. mfG
also nochmals meine Frage: CMD_SET_DDRAM_ADR|(y*16+(x&0x1E)) bedeutet bei x und y = 0: 0x80 da #define CMD_SET_DDRAM_ADR 0x80
Bruno M. schrieb: > also nochmals meine Frage: > CMD_SET_DDRAM_ADR|(y*16+(x&0x1E)) bedeutet bei x und y = 0: 0x80 > > da #define CMD_SET_DDRAM_ADR 0x80 korrekt 0x80 mfG
Dann gebe ich auf, denn so habe ich es immer gemacht. Trotzdem danke für die Hilfe!
Ich will nicht klugscheißen - so nur mal ein Gedankengang: man könnte auch eine Arduino Lib nehmen und die Sequenzen aus den cpp File entnehmen und weiter verwenden bzw. analysieren. So wie ich das sehe,suchst/brauchst Du die Sequenzen um das Display zum laufen zu bringen. Auch kannst Du mit der Lib erst einmal testen ob die Hardware überhaupt läuft. Aber wie gesagt nur mal so einen Idee - ich bin auch kein Profi.
Hier hast Du mal einen Ansatz, wie man so etwas angehen kann - zwar für den "Standard HD44780" aber mit Datenblatt-Studium kann man timing und Befehle entsprechend umsetzen: http://web.alfredstate.edu/faculty/weimandn/programming/lcd/ATmega328/LCD_code_asm_8ds.html
Bruno M. schrieb: > Ich kann natürlich auch gerne meine asm-Code-Schnipsel zeigen wenn das > hilft. Na, wo sind sie denn nun?
Hugo H. schrieb: > Hier hast Du mal einen Ansatz, wie man so etwas angehen kann - zwar für > den "Standard HD44780" aber mit Datenblatt-Studium kann man timing und > Befehle entsprechend umsetzen: > > http://web.alfredstate.edu/faculty/weimandn/programming/lcd/ATmega328/LCD_code_asm_8ds.html Nett gemeint, aber: 1. Muss er kein "timing" umsetzen, da er SPI verwendet 2. Das Datenblatt des ST7920 ist eine lausig und missverständliche Übersetzung aus dem Chinesischen, also nichts so einfach zu lesendes wie der HD44780 Daher ist das schon ein bisschen herausfordernder...
John Doe schrieb: > Na, wo sind sie denn nun?
1 | .equ LCD_Fun_Bas = 0b00100000 |
2 | |
3 | .equ LCD_ON = 0b00001100 |
4 | .equ LCD_OFF = 0b00001000 |
5 | .equ LCD_Curser_ON = 0b00001110 |
6 | .equ LCD_Curser_OFF = 0b00001100 |
7 | .equ LCD_Blink_ON = 0b00001111 |
8 | .equ LCD_Blink_OFF = 0b00001110 |
9 | .equ LCD_SHIFT = 0b00010100 ;Curser shifts right |
10 | |
11 | .equ LCD_HOME = 0b00000010 |
12 | .equ LCD_Entry = 0b00000110 ;Curser moves right |
13 | .equ LCD_CLEAR = 0b00000001 |
14 | |
15 | .equ LCD_DDRAM_1 = 0b10000000 ;1. Zeile, jeweils Reihe 0 bis 7 (80H...87H) |
16 | .equ LCD_DDRAM_2 = 0b10010000 ;2. Zeile (90H...97H) |
17 | .equ LCD_DDRAM_3 = 0b10001000 ;3. Zeile (88H...8FH) |
18 | .equ LCD_DDRAM_4 = 0b10011000 ;4. Zeile (98H...9FH) |
19 | |
20 | .equ LCD_Fun_Ext = 0b00100100 |
21 | .equ LCD_GDRAM_V = 0b01000000 |
22 | .equ LCD_GDRAM_H = 0b01000000 |
23 | |
24 | ;******************************************************************************************* |
25 | LCD_init: |
26 | rcall _Reset |
27 | ldi Daten, LCD_Fun_Bas ;Basis Funktionen |
28 | rcall lcd_writecom |
29 | rcall delay100us |
30 | ldi Daten, LCD_Fun_Bas ;Basis Funktionen |
31 | rcall lcd_writecom |
32 | rcall delay100us |
33 | ldi Daten, LCD_ON ;Display an, Curser und Blinken aus |
34 | rcall lcd_writecom |
35 | rcall delay100us |
36 | ldi Daten, LCD_Clear ;Display clear |
37 | rcall lcd_writecom |
38 | rcall delay50us |
39 | ldi Daten, LCD_Entry ;Curser springt weiter und Adresszähler wird erhöht |
40 | rcall lcd_writecom |
41 | rcall delay50us |
42 | ret |
43 | |
44 | ;************************************************************************************************** |
45 | Ausgabe: |
46 | rcall _Reset |
47 | ldi Daten, LCD_DDRAM_1 |
48 | rcall lcd_writecom |
49 | rcall delay50ms |
50 | ldi Daten, 0 |
51 | rcall lcd_writebyte |
52 | rcall delay50us |
53 | ldi Daten, 'A' |
54 | rcall lcd_writebyte |
55 | rcall delay50us |
56 | ldi Daten, 0 |
57 | rcall lcd_writebyte |
58 | rcall delay50us |
59 | ldi Daten, 'B' |
60 | rcall lcd_writebyte |
61 | rcall delay50us |
62 | ret |
63 | |
64 | ;************************************************************************************* |
65 | ;Ausgabe eines Befehls |
66 | lcd_writecom: |
67 | ldi temp, 0b11111000 ;11111-Synchronizing Bits, 0-RW, 0-RS, 0 |
68 | out SPDR, temp |
69 | rcall Wait_Transmit |
70 | push Daten |
71 | andi Daten, 0b11110000 |
72 | out SPDR, Daten ;High nibble raus |
73 | rcall Wait_Transmit |
74 | |
75 | rcall delay50us |
76 | pop Daten |
77 | swap Daten |
78 | andi Daten, 0b11110000 |
79 | out SPDR, Daten ;Low nibble raus |
80 | rcall Wait_Transmit |
81 | rcall delay50us |
82 | ret |
83 | |
84 | ;Ausgabe von Daten |
85 | lcd_writebyte: |
86 | ldi temp, 0b11111010 ;11111-Synchronizing Bits, 0-RW, 1-RS, 0 |
87 | out SPDR, temp |
88 | rcall Wait_Transmit |
89 | push Daten |
90 | andi Daten, 0b11110000 |
91 | out SPDR, Daten ;High nibble raus |
92 | rcall Wait_Transmit |
93 | |
94 | rcall delay50us |
95 | pop Daten |
96 | swap Daten |
97 | andi Daten, 0b11110000 |
98 | out SPDR, Daten ;Low nibble raus |
99 | rcall Wait_Transmit |
100 | rcall delay50us |
101 | ret |
John Doe schrieb: > 1. Muss er kein "timing" umsetzen, da er SPI verwendet Schwätzer - auch das HD44780 hat ein Timing, welches es einzuhalten gilt. Es gibt massig Datenblätter in ordentlichem Englisch, z. B. https://www.crystalfontz.com/controllers/Sitronix/ST7920/ wenn man so etwas nicht lesen kann hat man das falsche Hobby gewählt.
Hugo H. schrieb: > John Doe schrieb: >> 1. Muss er kein "timing" umsetzen, da er SPI verwendet > > Schwätzer - auch das HD44780 hat ein Timing, welches es einzuhalten > gilt. Selber Schwätzer. Genau das meinte ich nämlich: Beim HD44780 muss man aufs Timing der einzelnen Pins achten, beim ST7920 nicht, wenn man SPI nutzt. > Es gibt massig Datenblätter in ordentlichem Englisch, z. B. > > https://www.crystalfontz.com/controllers/Sitronix/ST7920/ > > wenn man so etwas nicht lesen kann hat man das falsche Hobby gewählt. Gelesen hast Du das Datenblatt sicher nicht, von unklaren Formulierungen bis hin zu dicken Fehlern ist da alles dabei. Die vom HD44780, SSD1306, ILI9341, ST7735, etc. sind da deutlich einfacher zu lesen. Und wenn dann ein Einsteiger gleich so ein blödes Datenblatt bekommt, kann ich gut verstehen, dass er damit ein paar Schwierigkeiten hat.
Wie kommt es zu diesem 'rcall delay50us', im Datenblatt steht doch bei fast jedem Befehl 'Exec time 72 us'?
Auch das
1 | rcall delay50us |
zwischen Highnibble und Lownibble in lcd_writecom und lcd_writebyte ist unnötig laut Datenblatt. Die 24 Bit/3 Byte werden am Stück rausgetaktet.
Für andere als die von mir angewandte Variante "Grafik-LCD-Display DG14032 8-bit-Modus ausgewählt,", wie 4-Bit-Modus oder SPI kann der Code nicht passen. mfG
S. Landolt schrieb: > Wie kommt es zu diesem 'rcall delay50us' Ich habe eigentlich immer 100us (2 x 50us), da sowohl in der Ausgaberoutine als auch im Code 50us eingebaut sind. Die Kommandos funktionieren auch völlig problemlos, das habe ich mit dem Curser mehrmals getestet. Sogar bei der Ausgabe der Bytes springt der Curser weiter. Es wird nur nichts angezeigt. Inzwischen muß ich davon ausgehen, daß das Display eine Macke hat!
Sehr wahrscheinlich haben Sie das bereits versucht, ich möchte es aber trotzdem angesprochen haben: was passiert, wenn statt $00 'A' und $00 'B' ausgegeben wird: 'A' 'B' und 'C' 'D'? Mir ist die vorangestellte Null nicht klar. (aber ohne die Hardware ist eben schlecht raten, dies war also mein zweiter&letzter Versuch)
S. Landolt schrieb: > Mir ist die vorangestellte > Null nicht klar. Laut Datenblatt sind die normalen fonts 16x16 bits. Zusätzlich gibt es aber half-width fonts (das sind die ASCII fonts). Auch wenn ich mit letzteren arbeiten will, muß ich immer 16x16 bits ausgeben. Meine Version würde dann (Space)A(Space)B ausgeben und deine AABB.
Habe ich noch nicht verstanden - "Space" soll $00 sein? Und im Datenblatt lese ich 'To display HCGROM fonts ... The data is among 02H~7FH'; ich hätte naiv angenommen, dass dieses vorangestellte $00 das 'CGRAM' anspricht: 'To display CGRAM fonts ... Only 0000H, 0002H, 0004H and 0006H are acceptable'.
Ich fasse es nicht!!!! Du hast recht. Um ehrlich zu sein habe ich das von irgendwo übernommen, ohne ernsthaft darüber nachzudenken. Space wäre natürlich ' '
Toll! Es kommt AABB auf dem Display an. Das würde ich mich auch freuen. Die Lösung ist trivial, den Weg, diese zu finden, allerdings nicht. mfG
Hallo, ich muß mich noch einmal melden, u.z. hänge ich jetzt bei der Grafik. Ich habe den Grafikmodus eingeschaltet und den Bildschirm geleert. So weit so gut. Als nächstes wollte ich den Bildschirm komplett füllen. Wenn ich diesen Befehl unmittelbar nach dem Einschalten des Grafikmodus ausführe ist alles OK. Wenn ich aber zuerst leere und dann fülle, dauert es erstmal ewig bis er anfängt und dann wird die V-Adresse nicht auf 0 gestellt, sondern er macht erst die Zeile 31 und springt dann in die zweite Zeile. Im Ergebnis läßt er die Zeile 0 also immer aus. Den gleichen Effekt habe ich auch wenn ich zuerst fülle und dann leere.
1 | .equ LCD_Fun_Ext = 0b00100100 ;Extended Function |
2 | .equ LCD_GRAPH_ON = 0b00100110 ;Grafik ein |
3 | .equ LCD_GDRAM_V = 0b10000000 ;0 bis 3F (63) |
4 | .equ LCD_GDRAM_H = 0b10000000 ;0 bis F (15) |
5 | |
6 | ;************************************************************************************************ |
7 | Home_GDRAM: |
8 | ldi Daten, LCD_GDRAM_V |
9 | rcall lcd_writecom |
10 | rcall delay50us |
11 | ldi Daten, LCD_GDRAM_H |
12 | rcall lcd_writecom |
13 | rcall delay50us |
14 | ret |
15 | |
16 | ;******************************************************************************************************* |
17 | Clear_GDRAM: |
18 | rcall _Reset |
19 | ldi temp1, 1 ;Zähler für vertikale Adresse |
20 | rcall Home_GDRAM |
21 | _Clear_GDRAM: |
22 | clr temp ;Zähler für horizontale Adresse |
23 | Clear_GDRAM_loop: ;Schleife zum löschen von 2 horizontalen Reihen (0 und 32, 1 und 33, 2und 34 usw.) |
24 | ldi Daten, 0x00 |
25 | rcall lcd_writebyte |
26 | rcall delay50us |
27 | rcall lcd_writebyte |
28 | rcall delay50us |
29 | inc temp |
30 | cpi temp, 16 |
31 | breq SET_H_Loop |
32 | rcall delay100ms |
33 | rjmp Clear_GDRAM_loop |
34 | SET_H_Loop: ;Schleife zum Weiterzählen der vertikalen Adresse |
35 | ldi Daten, LCD_GDRAM_V |
36 | or Daten, temp1 ;nächste V-Adresse |
37 | rcall lcd_writecom |
38 | ldi Daten, LCD_GDRAM_H |
39 | rcall lcd_writecom ;H-Adresse auf 0 |
40 | rcall delay50us |
41 | inc temp1 |
42 | cpi temp1, 32 |
43 | breq exit1 |
44 | rjmp _Clear_GDRAM |
45 | |
46 | ;******************************************************************************************************* |
47 | exit1: |
48 | ret |
49 | |
50 | ;******************************************************************************************************* |
51 | Fill_GDRAM: |
52 | rcall _Reset |
53 | rcall Home_GDRAM |
54 | ldi temp1, 1 ;Zähler für vertikale Adresse |
55 | _Fill_GDRAM: |
56 | clr temp ;Zähler für horizontale Adresse |
57 | Fill_GDRAM_loop: ;Schleife zum löschen von 2 horizontalen Reihen (0 und 32, 1 und 33, 2und 34 usw.) |
58 | ldi Daten, 0xFF |
59 | rcall lcd_writebyte |
60 | rcall delay50us |
61 | rcall lcd_writebyte |
62 | rcall delay50us |
63 | inc temp |
64 | cpi temp, 16 |
65 | breq SET_H_Loop_Fill |
66 | rcall delay100ms |
67 | rjmp Fill_GDRAM_loop |
68 | SET_H_Loop_Fill: ;Schleife zum Weiterzählen der vertikalen Adresse |
69 | ldi Daten, LCD_GDRAM_V |
70 | or Daten, temp1 ;nächste V-Adresse |
71 | rcall lcd_writecom |
72 | ldi Daten, LCD_GDRAM_H |
73 | rcall lcd_writecom ;H-Adresse auf 0 |
74 | rcall delay50us |
75 | inc temp1 |
76 | cpi temp1, 32 |
77 | breq exit1 |
78 | rjmp _Fill_GDRAM |
Hinweis: den delay 100ms habe ich eingefügt, damit ich den Ablauf beobachten kann.
Nachtrag: Wie ich soeben festgestellt habe, kann ich das Problem mit 2 Home-Befehlen und einer dazwischen liegenden Dummy Ausgabe lösen. Was allerdings bleibt ist der extrem lange Zeitraum dazwischen. Eine Erklärung ist das natürlich auch nicht!
> dauert es erstmal ewig
Unklar - ich dachte, es erfolgt keinerlei Rückmeldung vom ST7920, dann
läge es doch ausschließlich am Programm selbst: einfach die Schleifen
durchzählen, oder im schlimmsten Fall das Programm in den Simulator
stecken und diiesen zählen lassen. Falls nicht: an welcher Stelle wird
auf die Rückmeldung gewartet?
Allgemein ist es sicher unnötig, nach jedem Byte 50 us zu warten, die
72 im Datenblatt gelten ja pro Befehl.
Und was genau heißt "ewig"?
S. Landolt schrieb: > Und was genau heißt "ewig"? Ich hatte schon alles ausgeschaltet, aber auf diese Frage hin habe ich es nochmals angemacht um es zu stoppen und siehe da jetzt ging es normal schnell. Vorher waren es geschätzt mindestens 30s. Was mich aber eher beschäftigt ist die Frage, warum er auf den ersten Home Befehl nicht richtig reagiert. Stimmt vielleicht das timing nicht und wenn ja wo?
>Stimmt vielleicht das timing nicht
Ich kann nur wiederholen: im Datenblatt steht 72 us nach einem Befehl,
bei Ihnen sehe ich überall 50 us. Wohingegen das Warten zwischen Bytes
eines Befehls unnötig ist.
Da mir aber die Hardware fehlt, sollte ich mich verabschieden, es wird
sonst zu einer reinen Raterei.
Hallo, im Beispiel, das ich vor etlichen Jahren mir heraus gesucht habe, erfolgt ein dummy-read und danach wird zwei Mal gelesen. Wozu und warum ist mir ohne längeres Studium des Dablas und ohne mit dem Code zu experimentieren nicht mehr klar. setzt einen Punkt auf im Grafikspeicher: void GLCD_SetPixel(uint8_t x,uint8_t y, uint8_t color) { uint8_t subpos; uint8_t pix; uint8_t pixel_low; uint8_t pixel_high; GLCD_SetExtendedMode(); GLCD_Write(RS_CMD,CMDE_SET_GDRAM_ADR|(MASK_GDRAM_ADR_VER&y)); //erstes Byte senden: vertikale Adresse 5 Bytes -->> 0..63; 0x80 = Bit7 oder 0x3F = 11 1111, GLCD_Write(RS_CMD,CMDE_SET_GDRAM_ADR|(MASK_GDRAM_ADR_HOR&(x>>4)));// als zweites Byte senden: die horizontale Adresse 0...15 GLCD_Read(RS_DATA); pixel_high = GLCD_Read(RS_DATA); pixel_low = GLCD_Read(RS_DATA); subpos = x & 0x0F; //Maskieren: nur 0..15 relevant GLCD_Write(RS_CMD,CMDE_SET_GDRAM_ADR|(MASK_GDRAM_ADR_VER&y)); GLCD_Write(RS_CMD,CMDE_SET_GDRAM_ADR|(MASK_GDRAM_ADR_HOR&(x>>4))); //horizontal sind nur obere 4 Bits relevant if (subpos < 8) { pix = color ? (1<<(7-subpos))|pixel_high : (~(1<<(7-subpos)))&pixel_high; GLCD_Write(RS_DATA,pix); GLCD_Write(RS_DATA,pixel_low); } else { pix = color ? (1<<(15-subpos))|pixel_low : (~(1<<(7-subpos)))&pixel_low; GLCD_Write(RS_DATA,pixel_high); GLCD_Write(RS_DATA,pix); } } mfG
Hallo, ich habe den ST7920 bisher mal im seriellen Modus und mal im parallelen 4-Bit-Modus (mit PIC16F18326) angesteuert. Ohne Kenntnis des ST7920-Datenblatts ist man natürlich aufgeschmissen! Da im seriellen Modus nur Schreiben und damit keine Statusabfrage möglich ist, muss man (vgl. S. Landolt) nach jedem Befehl besagtes Delay 72 us einfügen. Im Worst case mit +/- 20% Clock-Abweichung sind das sogar ca. 85 us. Damit kommt man z.B. mit ca. 1100 Bytes für eine Grafikseite und 1-MHz Serial Clock bei 3 Bytes pro Befehl auf 110 ... 120 ms Übertragungszeit pro 128x64-Grafikseite. Im parallelen Modus mit Abfrage des Statusbits zeigt sich, dass nur wenige Bytes das volle Delay brauchen, sondern vor allem die Daten-Bytes schneller hintereinander übertragen werden. Ich habe im 4-Bit-Modus mit Oszi ca. 40 ms für eine Grafikseite gemessen. Im 8-Bit-Modus spart man nicht sehr viel, weil hauptsächlich dieses geforderte Delay die gesamte Übertragungszeit ausmacht. Zum Textmodus ist zu sagen: durch seine eigentümliche Ansteuerung, die immer nur word-weise geht, müssen immer paarweise Character gesendet werden. Wer sich aktiv mit ST7920- und/oder HD44780-Displays beschäftigt hat, weiss natürlich, dass Beide nicht vergleichbar sind. MfG Wuff_W
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.