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.

