Hallo, ich habe ein Problem mit meinem HD44780 LCD Display an einem STM32F10x (72MHz). Ich habe nachfolgenden Code im Einsatz, doch das angehängte Bild stellt dar was dabei herauskommt. Das Grundgerüst des Codes habe ich aus dem Internet und dann an Hand des Datenblatts eigentlich so angepasst, dass alles im 4-Bit-Mode laufen müsste. main.c: int main(void) { toLine2(); // Schreibe in die 2. Zeile des Display while(1) { printChar(0x7F); // Schreibe ständig das Zeichen "<-" } } lcd.c: #include "stm32f10x.h" #define LCD_Port GPIOC #define RS GPIO_Pin_1 #define EN GPIO_Pin_3 #define D4 GPIO_Pin_4 #define D5 GPIO_Pin_5 #define D6 GPIO_Pin_6 #define D7 GPIO_Pin_7 void lcdInit(void); void sendCMD(uint8_t c); void printChar(uint8_t c); void printString(uint8_t *s); void clearLCD(void); void toLine1(void); void toLine2(void); void Delay(uint32_t nCount); void strobeEN(void); void upNib(uint8_t c); void downNib(uint8_t c); void lcdInit(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //Init GPIOs GPIO_InitStructure.GPIO_Pin = EN | RS | D4 | D5 | D6 | D7; GPIO_ResetBits(LCD_Port, EN | RS | D4 | D5 | D6 | D7); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(LCD_Port, &GPIO_InitStructure); GPIO_ResetBits(LCD_Port, EN | RS | D4 | D5 | D6 | D7); Delay(0xffff); // Nach Reset 5ms Zeitschleife sendCMD(0x30); sendCMD(0x30); sendCMD(0x30); sendCMD(0x20); // In 4-Bit-Mode wechseln, noch im 8-Bit-Mode Delay(0x3FFFC); // 20ms Zeitschleife sendCMD(0x28); // Function Set, 4-Bit, 2-zeilig, 5x7 Dot Display sendCMD(0x0f); // Display an, Cursor anzeigen, Cursorstelle blinkt sendCMD(0x01); // Display löschen Delay(0xffff); // 5ms Zeitschleife } void strobeEN(void) { Delay(0xffff); GPIO_SetBits(LCD_Port, EN); Delay(0xffff); GPIO_ResetBits(LCD_Port, EN); } void upNib(uint8_t c) { if(c & 0x80) GPIO_SetBits(LCD_Port, D7); else GPIO_ResetBits(LCD_Port, D7); if(c & 0x40) GPIO_SetBits(LCD_Port, D6); else GPIO_ResetBits(LCD_Port, D6); if(c & 0x20) GPIO_SetBits(LCD_Port, D5); else GPIO_ResetBits(LCD_Port, D5); if(c & 0x10) GPIO_SetBits(LCD_Port, D4); else GPIO_ResetBits(LCD_Port, D4); } void downNib(uint8_t c) { if(c & 0x8) GPIO_SetBits(LCD_Port, D7); else GPIO_ResetBits(LCD_Port, D7); if(c & 0x4) GPIO_SetBits(LCD_Port, D6); else GPIO_ResetBits(LCD_Port, D6); if(c & 0x2) GPIO_SetBits(LCD_Port, D5); else GPIO_ResetBits(LCD_Port, D5); if(c & 0x1) GPIO_SetBits(LCD_Port, D4); else GPIO_ResetBits(LCD_Port, D4); } // Befehl senden void sendCMD(uint8_t c) { GPIO_ResetBits(LCD_Port, RS); // RS 0=Byte als Befehl interpretieren upNib(c); // Obere 4 Bits senden strobeEN(); // Enable Leitung downNib(c); // Untere 4 Bits senden strobeEN(); // Enable Leitung } // Byte auf Display ausgeben void printChar(uint8_t c) { // Überprüfen ob "c" ein gültiges Zeichen ist (Zeichensatztabelle) if(((c>=0x20)&&(c<=0x7F)) || ((c>=0xA0)&&(c<=0xFF))) { GPIO_SetBits(LCD_Port, RS); // RS 1=Byte auf Display ausgeben upNib(c); // Obere 4 Bits senden strobeEN(); // Enable Leitung downNib(c); // Untere 4 Bits senden strobeEN(); // Enable Leitung GPIO_ResetBits(LCD_Port, RS); // RS 0=Byte als Befehl interp. } } void printString(uint8_t *s) { uint8_t i=0; while(s[i] != '\0') { printChar(s[i]); i++; } } // Display löschen void clearLCD(void) { sendCMD(0x01); } // In 1. Zeile bewegen void toLine1(void) { sendCMD(0x00); } // In 2. Zeile bewegen void toLine2(void) { sendCMD(0x40); } // Zeitschleife void Delay(uint32_t nCount) { for(; nCount != 0; nCount--); } Stimmt die Initialisierung soweit? Mein Kabellänge zum Display beträgt ca. 12cm ... laut Datenblatt treten Probleme wenn dann ab ca. 20cm auf ... Wäre über Hilfe sehr dankbar! :)
>Stimmt die Initialisierung soweit?
Nein. Die ersten 4 Befehle werden als Nibbles übertragen.
Also
3
3
3
2
Mit sendCMD() wird das nix.
Hallo holger, stimmt - Danke für den Hinweis! Das bedeutet also eine eigene Funktion nur für die ersten vier Befehle. Dazu habe ich noch eine Verständnisfrage: Im 4-Bit-Mode, wir das Byte ja in High-byte und Low-byte aufgeteilt. Das High-Byte soll zuerst übertragen werden, danach das Low-Byte. Ich habe 4 Datenleitungen, das passt. Wie soll ich nun aber dieses Byte im 8-Bit-Mode senden? Ich kann ja auf Grund der 4 Datenleitungen auch nicht alle 8 bits auf einmal senden?! Wie funktioniert das?
Wolfgang schrieb: > Wie funktioniert das? etwa so:
1 | // Nibble senden
|
2 | void sendNibble (uint8_t c) |
3 | {
|
4 | GPIO_ResetBits(LCD_Port, RS); // RS 0=Byte als Befehl interpretieren |
5 | upNib(c); // Obere 4 Bits senden |
6 | strobeEN(); // Enable Leitung |
7 | }
|
Ist das so schwer? Ist es so schwer seine C-Code entsprechend der Richtlinien zu posten?
Hallo Mitlesa, vielen Dank für deine Hilfe und deinen Hinweis bezüglich der Formatierung. Ich habe es nun genau durchgelesen. Das Code-Beispiel von dir erscheint mir richtig, allerdings muss noch ein anderer Fehler im Quellcode sein. Hier nochmal die Initialisierung:
1 | void lcdInit(void) { |
2 | |
3 | GPIO_InitTypeDef GPIO_InitStructure; |
4 | |
5 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); |
6 | |
7 | //Init GPIOs
|
8 | GPIO_InitStructure.GPIO_Pin = EN | RS | D4 | D5 | D6 | D7; |
9 | GPIO_ResetBits(LCD_Port, EN | RS | D4 | D5 | D6 | D7); |
10 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; |
11 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; |
12 | GPIO_Init(LCD_Port, &GPIO_InitStructure); |
13 | GPIO_ResetBits(LCD_Port, EN | RS | D4 | D5 | D6 | D7); |
14 | |
15 | Delay(0xffff); // 5ms Zeitschleife |
16 | |
17 | sendNibble(0x30); |
18 | |
19 | sendNibble(0x30); |
20 | |
21 | sendNibble(0x30); |
22 | |
23 | sendNibble(0x20); // In 4-Bit-Mode wechseln, noch im 8-Bit-Mode |
24 | |
25 | Delay(0x3FFFC); // 20ms Zeitschleife |
26 | |
27 | sendCMD(0x28); // Function Set, 4-Bit, 2-zeilig, 5x7 Dot Display |
28 | |
29 | sendCMD(0x0f); // Display an, Cursor anzeigen, Cursorstelle blinkt |
30 | |
31 | sendCMD(0x01); |
32 | |
33 | Delay(0xffff); // 5ms Zeitschleife |
34 | |
35 | }
|
Noch zur Info: Die R/W Leitung habe ich direkt auf Masse gelötet.
Wolfgang schrieb: > allerdings muss noch ein anderer Fehler im Quellcode sein. Lies das Datenblatt zur Initialisierung eines HD44780. Vor und zwischen dem Senden der Initialisierungs-Nibbles müssen Delays eingebaut sein.
LCD schrieb: > // Zeitschleife > void Delay(uint32_t nCount) > { > for(; nCount != 0; nCount--); > } Da müsstest du dir vielleicht noch etwas intelligenteres einfallen lassen. Im schlimmsten Fall wird dir diese Schleife vom Compiler wegoptimiert sodass dein Delay nahezu Null ist.
Wolfgang schrieb: > Noch zur Info: > > Die R/W Leitung habe ich direkt auf Masse gelötet. Hast Du das beim Probieren dort auch so gemacht? Beitrag "Re: LCD-Modul 2x16 am STM32F4Discovery-Board" Da muß nämlich R/W beschaltet sein.
m.n. schrieb: > Da muß nämlich R/W beschaltet sein. Begündung? Gegenbegründung: Solange man das LCD nur beschreibt, also keinen Handshake macht indem man den Status liest, muss die R/W Leitung auch nicht bedient werden und kann statisch auf Low gezogen werden. Nur das Timing durch Delays muss eingehalten werden ....
Änder mal Deinen Namen in "Nichtleser". Deine unqualifizierten Kommentare beginnen zu nerven.
LCD schrieb: > ich habe ein Problem mit meinem HD44780 LCD Display an einem STM32F10x LCD schrieb: > void upNib(uint8_t c) { > if(c & 0x80) > GPIO_SetBits(LCD_Port, D7); > else > GPIO_ResetBits(LCD_Port, D7); > if(c & 0x40) > GPIO_SetBits(LCD_Port, D6); > else > GPIO_ResetBits(LCD_Port, D6); > if(c & 0x20) > GPIO_SetBits(LCD_Port, D5); > else > GPIO_ResetBits(LCD_Port, D5); > if(c & 0x10) > GPIO_SetBits(LCD_Port, D4); > else > GPIO_ResetBits(LCD_Port, D4); > } Nein. Du hast kein Problem mit deinem HD44780. Du hast hingegen ein ernstes Problem mit deinem STM32F10x - und zwar mit dessen sinnvoller Benutzung. Was du da mit den Portbits anstellst, sieht ja grauenhaft aus. Lies mal das Manual zu deinem Chip, insbesondere dazu:
1 | volatile unsigned long BSRR; /* Bit-SetReset: |
2 | Bits 0..15->set ODR Bits 0..15,
|
3 | Bits 16..31->reset ODR Bits 0..15 */
|
Abgesehen davon sollte dir die meiner Erinnerung nach knapp 1 seitige Tabelle mit den Befehlscodes zum Display genug sagen, um so ein Display sinnvoll ansteuern zu können. W.S.
Hallo W.S., vielen Dank für deinen Tipp. Ich werde mich nun umgehend damit befassen. Aber eigentlich ist es ja nur die Schreibweise die verbessert werden sollte, die Funktion an sich sollte ja trotzdem funktionieren.
@Mitlesa, danke für deinen Tipp mit volatile! Da lag der Fehler - die Zeitschleife wurde wohl wegoptimiert. So funktioniert es jetzt:
1 | void Delay(volatile uint32_t nCount) |
2 | {
|
3 | for(; nCount != 0; nCount--); |
4 | }
|
Vielen Dank!
Wolfgang schrieb: > Da lag der Fehler - die Zeitschleife wurde wohl wegoptimiert. Ja freut mich für dich! Aber etwas gut Definiertes ist das ja nicht mit deiner Zählschleife.
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.