www.mikrocontroller.net

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


Autor: Lief Erickson (kallisti)
Datum:

Bewertung
0 lesenswert
nicht 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-Tu...

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
//-------------------------------------------------------------------------
//DISPLAY ROUTINEN
//RW = 0 --> uC schreibt auf LCD
//RW = 1 --> uC liest von LCD
//RS = 0 --> Befehl
//RS = 1 --> Daten
//-------------------------------------------------------------------------

//-------------------------------------------------------------------------
//Bibliotheken
//-------------------------------------------------------------------------
#include "lcd-routines.h"

//-------------------------------------------------------------------------
//Sendet 1 Datenbyte an LCD
//-------------------------------------------------------------------------
void lcd_data(unsigned char temp1)
{
  LCD_CTRL = LCD_RS;        //RS auf 1 setzen
  LCD_DATA &= 0x00;
  LCD_DATA |= temp1;       // setzen
  lcd_enable();
  Delay_ms(1);
}

//-------------------------------------------------------------------------
//Enable Puls 
//-------------------------------------------------------------------------
void lcd_enable(void)
{
  LCD_CTRL = LCD_EN;          //Enable setzen/RS=0(BEFEHL)/RW=0(uC schreibt)
  Delay_ms(1); 
  LCD_CTRL &= 0xDF;            //Enable loeschen, rest bleibt
}
 
//-------------------------------------------------------------------------//LCD Initialisierung
//-------------------------------------------------------------------------
void lcd_init(void)
{
  Delay_ms(20);
  
  LCD_DATA = 0x00;            //Datenport loeschen
  LCD_CTRL &= 0x1F;           //RW = 0 (SCHREIBEN)
                              //RS = 0 (BEFEHL)
                              //EN = 0 (wird bei lcd_enable wieder gesetzt)
  
  LCD_DATA_DIR = 0xFF;        //Datenport alles auf Ausgang
  LCD_CTRL_DIR = 0xE0;        //P4.7 bis P4.5 auf Ausgang
  
  LCD_DATA = DB3+DB4+DB5;     //Interface: 8-Bit Datenbus/zwei Zeilen
  lcd_enable();
  Delay_ms(10);
  
  LCD_DATA = DB3+DB4+DB5;     //Interface: 8-Bit Datenbus/zwei Zeilen
  lcd_enable();
  Delay_ms(10);
  
  LCD_DATA = DB3+DB4+DB5;     //Interface: 8-Bit Datenbus/zwei Zeilen
  lcd_enable();
  Delay_ms(10);
  
  LCD_DATA = DB3+DB2+DB1+DB0; //Display ein/ Cursor ein/ Blinken ein
  lcd_enable();
  Delay_ms(10);
  
  LCD_DATA = DB0;             //Clear Display
  lcd_enable();
  Delay_ms(10);
}

2. lcd-routines.h
//-------------------------------------------------------
//Vorwaertsdeklarierung
//-------------------------------------------------------
void lcd_data(unsigned char temp1);
void lcd_enable(void);
void lcd_init(void);
//-------------------------------------------------------
//Bibliotheken
//-------------------------------------------------------
#include <io.h>
#include <signal.h>
#include <stdio.h>
#include <iomacros.h>
#include <string.h>
#include <math.h>
#include <msp430x16x.h>

//-------------------------------------------------------
//Defines
//------------------------------------------------------- 
//Frequenz
#define F_CPU 8000000
 
//LCD Befehle
 
#define CLEAR_DISPLAY 0x01
#define CURSOR_HOME   0x02
 
//Pinbelegung
 
#define LCD_DATA           P5OUT
#define LCD_CTRL           P4OUT

#define LCD_DATA_DIR       P5DIR
#define LCD_CTRL_DIR       P4DIR

#define LCD_RS             0x80
#define LCD_RW             0x40
#define LCD_EN             0x20

#define DB0                0x01
#define DB1                0x02
#define DB2                0x04
#define DB3                0x08
#define DB4                0x10
#define DB5                0x20
#define DB6                0x40
#define DB7                0x80
3. Display.c (mein "Hauptprogramm)
//File: Display.c
//Date: 6.05.2010
//Function: Gebe das Wort "Test" auf Display aus
//------------------------------------------------------------------------------
//Bibliothek
//------------------------------------------------------------------------------
#include <msp430x16x.h>
//------------------------------------------------------------------------------
//Hauptprogramm
//------------------------------------------------------------------------------
void main()
{
  Init_System();
  lcd_init();
  Delay_ms(5);
  
  lcd_data('T');
  Delay_ms(1); 
  lcd_data('e');
  Delay_ms(1); 
  lcd_data('s');
  Delay_ms(1); 
  lcd_data('t');
  
  while(1)
  {
  _NOP();
  }
}

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

Autor: Hc Zimmerer (mizch)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
void lcd_enable(void)
{
  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.

Autor: Micha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und mit
LCD_CTRL &= ~LCD_EN;
wird es sogar noch flexibel hinsichtlich der Verwendung anderer Pins.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Micha schrieb:
> Und mit
>
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.

Autor: g457 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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):
void lcd_enable(void)
{
  LCD_CTRL = LCD_EN;          //Enable setzen/RS=0(BEFEHL)/RW=0(uC schreibt)
  Delay_ms(1); 
  LCD_CTRL &= 0xDF;            //Enable loeschen, rest bleibt
}

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

Autor: Lief Erickson (kallisti)
Datum:

Bewertung
0 lesenswert
nicht 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:
//-------------------------------------------------------------------------
//Delayfunktion --> Diese Funktion kann man verwenden, um eine genaue Ver-
//                  zoegerung zu erhalten. Man uebergibt der Funktion eine
//Zahl,welche groesser ist als 0. Diese wird danach heruntergezaehlt.
//Fuer jedes "Herunterzaehlen" benoetigt der Mikroprozessor
//3 Takte. Man muss also nur die eingestellte Frequenz kennen,
//um zu berechnen, wie lange die Verzoegerung dauern wird. 
//-------------------------------------------------------------------------
void __attribute__((naked)) Delay(unsigned int d) {
      asm("                inc     %0             ; Prevent overflow  (1c)\n"    
          ".LDecDel:       dec     %0             ; Decrement var   (1c)\n"      
          "                jnz     .LDecDel       ; Check if var is '0' (2c)\n"  
          "                ret                    ; Return   (3c?)" ::  "r"(d)); 
}
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
//Delayfunktion ms --> Da wir normalerweise eine Frequenz von 8MHz
// verwenden,habe ich ein Unterprogramm geschrieben, welches die 
//Funktion Delay aufruft und ihr den Wert 2667 uebergibt. 
//Fuer jedes Herunterzaehlen benoetigt die Funktion bekannt-
//lich 3 Takte, das heisst sie benoetigt 8000 Takte (3*2667)
//um von 2667 auf 0 herunter zu zaehlen. Ein Takt ist bei
//8MHz 125ns lang --> 8000 Takte * 125ns = 1ms!
//Der neuen Funktion Delay_ms kann man also einfach einen
//Wert entsprechend der gewuenschten Millisekundenzahl 
//uebergeben.
//-------------------------------------------------------------------------
void Delay_ms(unsigned long d)
{
  unsigned long i; 
  for(i=0; i<=d; i++)
  {
    Delay(2667);
  }
}


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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.