Forum: Mikrocontroller und Digitale Elektronik LCD-Ansteuerung funktioniert nicht (HD44780)


von Lief E. (kallisti)


Lesenswert?

Guten Tag

Ich bin gerade dabei ein zwei-zeiliges Display anzusteuern und habe mich 
hierbei auf diese Codes gestuetzt:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung

Ich steuere das Display jedoch nicht mit einem AVR an,
sondern mit dem uC MSP430F1611. Ich habe das Display folgendermassen 
beschalten: (Die LED-Spannung fehlt in diesem Schema noch, sie ist aber 
auf dem Print vorhanden)
http://666kb.com/i/biz45nyvep30gfusk.jpg

Hier meine Programmierung:
Ich habe alles auf mehrere Files aufgeteilt:
1. lcd-routines.c
1
//-------------------------------------------------------------------------
2
//DISPLAY ROUTINEN
3
//RW = 0 --> uC schreibt auf LCD
4
//RW = 1 --> uC liest von LCD
5
//RS = 0 --> Befehl
6
//RS = 1 --> Daten
7
//-------------------------------------------------------------------------
8
9
//-------------------------------------------------------------------------
10
//Bibliotheken
11
//-------------------------------------------------------------------------
12
#include "lcd-routines.h"
13
14
//-------------------------------------------------------------------------
15
//Sendet 1 Datenbyte an LCD
16
//-------------------------------------------------------------------------
17
void lcd_data(unsigned char temp1)
18
{
19
  LCD_CTRL = LCD_RS;        //RS auf 1 setzen
20
  LCD_DATA &= 0x00;
21
  LCD_DATA |= temp1;       // setzen
22
  lcd_enable();
23
  Delay_ms(1);
24
}
25
26
//-------------------------------------------------------------------------
27
//Enable Puls 
28
//-------------------------------------------------------------------------
29
void lcd_enable(void)
30
{
31
  LCD_CTRL = LCD_EN;          //Enable setzen/RS=0(BEFEHL)/RW=0(uC schreibt)
32
  Delay_ms(1); 
33
  LCD_CTRL &= 0xDF;            //Enable loeschen, rest bleibt
34
}
35
 
36
//-------------------------------------------------------------------------//LCD Initialisierung
37
//-------------------------------------------------------------------------
38
void lcd_init(void)
39
{
40
  Delay_ms(20);
41
  
42
  LCD_DATA = 0x00;            //Datenport loeschen
43
  LCD_CTRL &= 0x1F;           //RW = 0 (SCHREIBEN)
44
                              //RS = 0 (BEFEHL)
45
                              //EN = 0 (wird bei lcd_enable wieder gesetzt)
46
  
47
  LCD_DATA_DIR = 0xFF;        //Datenport alles auf Ausgang
48
  LCD_CTRL_DIR = 0xE0;        //P4.7 bis P4.5 auf Ausgang
49
  
50
  LCD_DATA = DB3+DB4+DB5;     //Interface: 8-Bit Datenbus/zwei Zeilen
51
  lcd_enable();
52
  Delay_ms(10);
53
  
54
  LCD_DATA = DB3+DB4+DB5;     //Interface: 8-Bit Datenbus/zwei Zeilen
55
  lcd_enable();
56
  Delay_ms(10);
57
  
58
  LCD_DATA = DB3+DB4+DB5;     //Interface: 8-Bit Datenbus/zwei Zeilen
59
  lcd_enable();
60
  Delay_ms(10);
61
  
62
  LCD_DATA = DB3+DB2+DB1+DB0; //Display ein/ Cursor ein/ Blinken ein
63
  lcd_enable();
64
  Delay_ms(10);
65
  
66
  LCD_DATA = DB0;             //Clear Display
67
  lcd_enable();
68
  Delay_ms(10);
69
}

2. lcd-routines.h
1
//-------------------------------------------------------
2
//Vorwaertsdeklarierung
3
//-------------------------------------------------------
4
void lcd_data(unsigned char temp1);
5
void lcd_enable(void);
6
void lcd_init(void);
7
//-------------------------------------------------------
8
//Bibliotheken
9
//-------------------------------------------------------
10
#include <io.h>
11
#include <signal.h>
12
#include <stdio.h>
13
#include <iomacros.h>
14
#include <string.h>
15
#include <math.h>
16
#include <msp430x16x.h>
17
18
//-------------------------------------------------------
19
//Defines
20
//------------------------------------------------------- 
21
//Frequenz
22
#define F_CPU 8000000
23
 
24
//LCD Befehle
25
 
26
#define CLEAR_DISPLAY 0x01
27
#define CURSOR_HOME   0x02
28
 
29
//Pinbelegung
30
 
31
#define LCD_DATA           P5OUT
32
#define LCD_CTRL           P4OUT
33
34
#define LCD_DATA_DIR       P5DIR
35
#define LCD_CTRL_DIR       P4DIR
36
37
#define LCD_RS             0x80
38
#define LCD_RW             0x40
39
#define LCD_EN             0x20
40
41
#define DB0                0x01
42
#define DB1                0x02
43
#define DB2                0x04
44
#define DB3                0x08
45
#define DB4                0x10
46
#define DB5                0x20
47
#define DB6                0x40
48
#define DB7                0x80
3. Display.c (mein "Hauptprogramm)
1
//File: Display.c
2
//Date: 6.05.2010
3
//Function: Gebe das Wort "Test" auf Display aus
4
//------------------------------------------------------------------------------
5
//Bibliothek
6
//------------------------------------------------------------------------------
7
#include <msp430x16x.h>
8
//------------------------------------------------------------------------------
9
//Hauptprogramm
10
//------------------------------------------------------------------------------
11
void main()
12
{
13
  Init_System();
14
  lcd_init();
15
  Delay_ms(5);
16
  
17
  lcd_data('T');
18
  Delay_ms(1); 
19
  lcd_data('e');
20
  Delay_ms(1); 
21
  lcd_data('s');
22
  Delay_ms(1); 
23
  lcd_data('t');
24
  
25
  while(1)
26
  {
27
  _NOP();
28
  }
29
}

Ich weiss, dass meine Delays viel zu lange sind...
Ich habe noch kein us-Delay programmiert, daher verwende ich mein 
ms-Delay.

Warum muss man bei der Initialisierung die Einstellung dreimal senden?
Gibt es in meinem Code einen Fehler?
Ich konnte ihn kompilieren und herunterladen, leider passiert - wie 
schon erwaehnt - auf dem Display gar nichts.

Vielen Dank für eure Hilfe!
Gruss

von Hc Z. (mizch)


Lesenswert?

1
void lcd_enable(void)
2
{
3
  LCD_CTRL = LCD_EN;          //Enable setzen/RS=0(BEFEHL)/RW=0(uC schreibt)
Das setzt alle anderen Kontrollsignale zurück.  Es muss |= heißen. 
Weiter habe ich nicht geschaut.

von Micha (Gast)


Lesenswert?

Und mit
1
LCD_CTRL &= ~LCD_EN;
wird es sogar noch flexibel hinsichtlich der Verwendung anderer Pins.

von Karl H. (kbuchegg)


Lesenswert?

Micha schrieb:
> Und mit
>
1
LCD_CTRL &= ~LCD_EN;
> wird es sogar noch flexibel hinsichtlich der Verwendung anderer Pins.

Wenns nach dem geht, muss er sowieso noch ein paar mal durch den Code 
durch. Das sind auch ein paar andere Stellen.

> Ich weiss, dass meine Delays viel zu lange sind...

Wer hat das Delay_ms geschrieben? Du?

Möglicherweise , je nach Compiler und Optimierungseinstellungen sind sie 
auch viel zu kurz.

von g457 (Gast)


Lesenswert?

> Warum muss man bei der Initialisierung die Einstellung dreimal senden?

Das steht im Datenblatt. Such mal nach dem generischen (ausführlichem) 
welchen vom HD44780, gibts u.a. bei datasheetarchive.

Den Code hab ich mir nicht genauer angesehen, aber folgendes ist mir ins 
Auge gestochen (weils pfui ist - an anderer Stelle analog):
1
void lcd_enable(void)
2
{
3
  LCD_CTRL = LCD_EN;          //Enable setzen/RS=0(BEFEHL)/RW=0(uC schreibt)
4
  Delay_ms(1); 
5
  LCD_CTRL &= 0xDF;            //Enable loeschen, rest bleibt
6
}

Wenn Du schon so schöne Makros^WDefines vergeben hast, dann nimm sie 
doch auch her, das erspart viel Sucherei und verbessert die Lesbarkeit 
massiv. Und bist Du sicher, dass Du den gesamten Port vom LCD_CTRL 
(alles ausser LCD_EN) auf 0 setzen willst? (Hinthinthint: In lcd_data() 
wird LCD_RS zwar gesetzt, aber dann in lcd_enable() wieder 
weggebügelt!).

Und: Macht ★Deine★ Delay_ms() wirklich das, was sie soll (find oben 
weder Deklaration (ok, die kann ich mir dazudenken) noch Definition (die 
ist potenziell fehleranfällig)).

Achja die Timings stehen übrigens auch im Datenblatt, alternativ kann 
man auch das busy-Flag zurücklesen (das machst aber besser erst, wenn 
die Initialisierung als solche klappt).

HTH und happy debugging

von Lief E. (kallisti)


Lesenswert?

"Das setzt alle anderen Kontrollsignale zurück.  Es muss |= heißen.
Weiter habe ich nicht geschaut."

Danke, das | vergesse ich staendig....

"Und: Macht ★Deine★ Delay_ms() wirklich das, was sie soll (find oben
weder Deklaration (ok, die kann ich mir dazudenken) noch Definition (die
ist potenziell fehleranfällig))."

Hier die Delayroutinen:
1
//-------------------------------------------------------------------------
2
//Delayfunktion --> Diese Funktion kann man verwenden, um eine genaue Ver-
3
//                  zoegerung zu erhalten. Man uebergibt der Funktion eine
4
//Zahl,welche groesser ist als 0. Diese wird danach heruntergezaehlt.
5
//Fuer jedes "Herunterzaehlen" benoetigt der Mikroprozessor
6
//3 Takte. Man muss also nur die eingestellte Frequenz kennen,
7
//um zu berechnen, wie lange die Verzoegerung dauern wird. 
8
//-------------------------------------------------------------------------
9
void __attribute__((naked)) Delay(unsigned int d) {
10
      asm("                inc     %0             ; Prevent overflow  (1c)\n"    
11
          ".LDecDel:       dec     %0             ; Decrement var   (1c)\n"      
12
          "                jnz     .LDecDel       ; Check if var is '0' (2c)\n"  
13
          "                ret                    ; Return   (3c?)" ::  "r"(d)); 
14
}
15
//-------------------------------------------------------------------------
16
//-------------------------------------------------------------------------
17
//Delayfunktion ms --> Da wir normalerweise eine Frequenz von 8MHz
18
// verwenden,habe ich ein Unterprogramm geschrieben, welches die 
19
//Funktion Delay aufruft und ihr den Wert 2667 uebergibt. 
20
//Fuer jedes Herunterzaehlen benoetigt die Funktion bekannt-
21
//lich 3 Takte, das heisst sie benoetigt 8000 Takte (3*2667)
22
//um von 2667 auf 0 herunter zu zaehlen. Ein Takt ist bei
23
//8MHz 125ns lang --> 8000 Takte * 125ns = 1ms!
24
//Der neuen Funktion Delay_ms kann man also einfach einen
25
//Wert entsprechend der gewuenschten Millisekundenzahl 
26
//uebergeben.
27
//-------------------------------------------------------------------------
28
void Delay_ms(unsigned long d)
29
{
30
  unsigned long i; 
31
  for(i=0; i<=d; i++)
32
  {
33
    Delay(2667);
34
  }
35
}

Jetzt wo ich die Funktion anschaue, faellt mir ein, dass ich gar keine 
definierte Frequenz eingestellt habe. Muesste ich ueberpruefen.
Die Funktion ist nebenbei nicht von mir, hab sie von einem 
Arbeitskollegen bekommen.

"Wenn Du schon so schöne Makros^WDefines vergeben hast, dann nimm sie
doch auch her, das erspart viel Sucherei und verbessert die Lesbarkeit
massiv. Und bist Du sicher, dass Du den gesamten Port vom LCD_CTRL
(alles ausser LCD_EN) auf 0 setzen willst? (Hinthinthint: In lcd_data()
wird LCD_RS zwar gesetzt, aber dann in lcd_enable() wieder
weggebügelt!)"

Ja der Gedanke kam mir schon bei der Programmierung. Eigentlich könnte 
ich EN immer auf 1 lassen, bis ich die Daten übergeben will.


Thx for support

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.