LCD HD44780 an STM32F

Gast #4410407
Lesenswert?

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! :)
Angehängte Dateien:
Gast #4411335
Lesenswert?

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?
Gast #4411369
Lesenswert?

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?
Gast #4411569
Lesenswert?

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.
Gast #4411619
Lesenswert?

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.
Gast #4411833
Lesenswert?

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 ....
Gast #4412554
Lesenswert?

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.
Gast #4412641
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren