LCD-Treiber für HD44780 (einmal etwas anderst)
Samstag, 19. Mai 2012
 
 

PIC Mikrocontroller Forum  |  PIC Mikrocontroller  |  Beispielcodes und Projekte  |  LCD-Treiber für HD44780 (einmal etwas anderst) « vorheriges nächstes »
Seiten: [1] Nach unten Drucken
Autor Thema: LCD-Treiber für HD44780 (einmal etwas anderst)  (Gelesen 8801 mal)
 
Schoasch
Sr. Member
****
Offline Offline

Beiträge: 343



Profil anzeigen
« am: September 13, 2005, 19:18:56 »

Hallo!

Die Überschrift mag so manchen bekannt vorkommen :-) doch hier möchte ich einmal einen etwas anderen Treiber vorstellen. Er ist sicher nicht auf beste Art und Weise programmiert und ist auch sicher verbesserungswürdig, jedoch soll dieser Treiber eher mehr zum Denken und umschreiben anregen.

Zuerst einmal ein paar Infos zum Treiber:

  +     Er ist für LCDs mit dem HD44780 Chip geeignet
  +    Die Belegung der LCD-Leitungen am PIC kann frei gewählt werden

Und das ist auch der Grund warum ich diesen Treiber so geschrieben habe. Denn es ist hier möglich, dass jede Leitung an irgendeinem Pin angeschlossen werden kann und man keine Reihenfolge oder Besonderheit beachten muss. Das Einzige was nur Beachtet werden muss ist, dass man die Anschlussbelegung im Treiber dementsprechend ändert (mit Tristate -Register).

Negatives: Der Treiber ist, wie gesagt, noch sehr verbesserungswürdig, vorallem in sachen Timing(es wird zb nie das Busy-Flag geprüft) und anderer Funktion(Zeichen von LCD lesen usw.).

Über Verbesserungsvorschläge und Hinweise würde ich mich freuen und hoffe, dass jemand etwas damit anfangen kann.

Viel Spass damit.

mfg Schoasch[/quote]

* LCD_driver.c (8.21 KB - runtergeladen 609 Mal.)
Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #1 am: September 14, 2005, 19:32:01 »

Zitat
Über Verbesserungsvorschläge und Hinweise würde ich mich freuen

Größere Verbesserungsmöglichkeiten sehe ich im Moment nicht. Spontan hätte ich gesagt, daß
Code:
// Variante 1
data = 0xAA;
D4 = (data & 0b00000001) != 0;
D5 = (data & 0b00000010) != 0;
D6 = (data & 0b00000100) != 0;
D7 = (data & 0b00001000) != 0;

effinzienter ist als
Code:
// Variante 2
data = 0xAA;
D4 = (data & 0b00000001);
D5 = (data & 0b00000010) >> 1;
D6 = (data & 0b00000100) >> 2;
D7 = (data & 0b00001000) >> 3;

Die angegebene Anzahl der Befehlszyklen bezieht sich im folgenden auf das Setzen von D4-D7.

Beim HT-Compiler hätte ich recht gehabt (Variante 1 benötigt 18 Befehlszyklen, Variante 2 benötigt 50). Beim CCS ist aber das Gegenteil der Fall (Variante 1: 52 Befehlszyklen, Variante 2: 47 Befehlszyklen).

Da mir die 47 Befehlszyklen beim CCS etwas zu hoch erschienen, habe ich noch Variante 3 ausprobiert:
Code:
// Variante 3
union
{
  struct
  {
    unsigned int d0:1;
    unsigned int d1:1;
    unsigned int d2:1;
    unsigned int d3:1;
    unsigned int :4;
  } bits;

  unsigned char byte_;

} data_u;

data_u.byte_ = 0xAA;

D4 = data_u.bits.d0;
D5 = data_u.bits.d1;
D6 = data_u.bits.d2;
D7 = data_u.bits.d3;

Der CCS   scheint dafür den optimalen Code zu erzeugen (16 Befehlszyklen), der HT bevorzugt klar die Variante 1 (Variante 3: 41 Befehlszyklen).


Zwei Kleinigkeiten:

In Deinem Code fehlen die Definition für die PORT- und TRIS-Register (#byte PORTx=...). Es sollte zwar eigentlich klar sein, daß sie benötigt werden, aber der Vollständigkeit halber könntest Du es auch im Code noch darstellen.

Die Parameter-Bezeichnung "direction" finde ich etwas irreführend. Unter "Richtung" würde ich einen Parameter zur Umschaltung zwischen Senden und Empfangen verstehen. Als zusätzliche Ergänzung würde ich vorschlagen, diesen Übergabeparameter durch zwei #defines festzulegen, z.B.:
Code:
#define CONTROL_REG   0
#define DATA_REG      1

LCD_sendbyte(0xAA, DATA_REG);

Mit "0" und "1" kann man sich leicht vertun. Durch die symbolischen Konstanten wird der Code lesbarer und es wird klarer, in welche Register man schreibt.


Viele Grüße

Bernd
Gespeichert

Schoasch
Sr. Member
****
Offline Offline

Beiträge: 343



Profil anzeigen
« Antworten #2 am: September 14, 2005, 20:50:25 »

Vielen Danke für die Anregungen. Ich werde sie mal bei Gelegenheit einarbeiten.

Aber ich hätte da noch eine Frage.
Was wird denn hier gemacht? Ich verstehe das hier nicht ganz. Könntest du mir das bitte etwas erklären?

Code:

data = 0xAA;
D4 = (data & 0b00000001) != 0;
D5 = (data & 0b00000010) != 0;
D6 = (data & 0b00000100) != 0;
D7 = (data & 0b00001000) != 0;


mfg SChoasch
Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #3 am: September 14, 2005, 21:28:04 »

Es wird getestet, ob
Code:
data & 0b...

ungleich '0' ist. Das Ergebnis dieses Vergleichs wird dann Dx zugewiesen.

Die Und-Operation liefert entweder "0" (das getestete Bit war '0') oder einen Wert ungleich 0 (das getestet Bit war '1'). Der Ausdruck
Code:
0 != 0;

liefert den logischen Wert "false" (denn '0' ist nicht ungleich '0'), der in ANSI-C als '0' definiert ist, d.h. Dx wird auf '0' gesetzt. Für jeden anderen Wert auf der linken Seite des obigen Ausdrucks ist das Ergebnis der logischen Verknüpfung "true" (denn jeder andere Wert als '0' ist ungleich '0'). Als Ergebnis des logischen Vergleichs wird Dx der Wert '1' (für "true") zugewiesen.

Das funktioniert, weil die Compiler (ich kenne zumindest keine Ausnahme) für die interne Darstellung eines "wahren" Vergleichs immer eine "1" verwenden. Prinzipiell könnte der Compiler auch eine '2' für die interne Darstellung wählen (nach ANSI-C ist ja jeder Wert ungleich '0' "true"), was dazu führen würde, daß die Zuweisung an das einzelne Bit fehlschlägt. Das tritt in der Praxis aber bei keinem mir bekannten Compiler auf.


Viele Grüße

Bernd
Gespeichert

davethebachelor
Newbie
*
Offline Offline

Beiträge: 10



Profil anzeigen
« Antworten #4 am: März 11, 2008, 22:17:05 »

Hallo leute !!!

bin gerade neu auf die pic - schiene gekommen, muss sagen hab vorher noch nicht wirklich viel damit zu tun gehabt udn würde gerne ein display ansteuern..

ich arbeite mit einem dsPIC30f4013 und wollte fragen ob ihr mir dabei etwas helfen könnt :-)

aaaaalsoo... hab mir mal das demo programm runtergeladen und es durch den compiler laufen lassen .... war auch klar dass es nicht funktioniert

ich verwende den ccs compiler (glaub ich halt)

mein code sieht jetzt so aus:

Code:
/*******************************************************************************
********************************************************************************
*                                                                              *
*              Treiber für LCDs die HD44780 kompatibel sind                    *
*                                                                              *
*   Erstellt von: Schoasch             am: 13.September.2005                   *
*                                                                              *
*       lcd_init()   Initialisiert das LCD und muss vor allen anderen Befehlen *
*                    1mal ausgeführt werden                                    *
*                                                                              *
*       lcd_putc(c)  Sendet ein Zeichen oder eine Zeichenkette an die Position *
*                    des Cursor                                                *
*                     Folgende Befehle werden unterstütz:                      *
*                        \f  Anzeige löschen                                   *
*                        \n  Setzt den cursor an die 1. Stelle in der 2.Zeile  *
*                        \b  Verschiebt den Cursor um eine Stelle nach Links   *
*                                                                              *
*       lcd_gotoxy(x,y) Setzt den Cursor an die gewünschte Stelle              *
********************************************************************************
* Hinweis: Der Vorteil dieses Treibers liegt darin, dass die Datenleitungen    *
*          Steuerleitungen an irgendeinem Pin des µC angeschlossen sein können *
*          und sie nicht zwingend in einer gewissen Reihenfolge angeschlossen  *
*          sein müssen. So können alle Datenleitungen auch auf mehrer Ports    *
*          verteilt sein.                                                      *
*          Damit das LCD angesprochen werden kann, muss man lediglich alle     *
*          Steuer- und Datenleitungen für den jeweiligen Fall umändern.        *
*          Wichtig!!! Man darf natürlich auch nicht die Tristate-Register      *
*          vergessen.                                                          *
*******************************************************************************/

#include <p30f4013.h>  // Hier stehen nur die Adressen der Ports drinn.
                         
           
/******************************************************************************/
/*    Steuerleitungen                                                         */
/******************************************************************************/
#define RS  LATBbits.LATB0          // RS ist an RB0 angeschlossen
#define RW  LATBbits.LATB1          // RW ist an RB1 angeschlossen
#define E   LATBbits.LATB2          // E ist an RB2 angeschlossen
/******************************************************************************/
/******************************************************************************/

/******************************************************************************/
/*    Datenleitungen                                                          */
/******************************************************************************/
#define D4  LATBbits.LATB4          // D4 ist an RB4 angeschlossen
#define D5  LATBbits.LATB5          // D5 ist an RB5 angeschlossen
#define D6  LATBbits.LATB6          // D6 ist an RB6 angeschlossen
#define D7  LATBbits.LATB7          // D7 ist an RB7 angeschlossen
/******************************************************************************/
/******************************************************************************/

#define lcd_line_two 0x40     // LCD RAM address for the second line
#define line_on      0x02     // Unterstriches aktivieren
#define blink_on      0x01     // BLinkenden Cursor aktivieren
#define Display_on    0x0C     // Display einschalten

#define line_off      0x00    // Unterstrich deaktivieren
#define blink_off      0x00    // Blinkenden Cursor deaktivieren
#define Display_off    0x08    // Display ausschalten


// Nibble senden
void send_nibble(int data,int direction)
{
    // Datenregister oder Steuerregister auswählen
    RS = direction;
    // Schreibmodus einstellen
    RW = 0;
    // Enable-Leitung auf 0 setzen
    E = 0;

    // IO-Ports als Ausgänge einstellen
    TRISBbits.TRISB4 = 0; // TRIS_D4 = 0;
    TRISBbits.TRISB5 = 0; // TRIS_D5 = 0;
    TRISBbits.TRISB6 = 0; // TRIS_D6 = 0;
    TRISBbits.TRISB7 = 0; // TRIS_D7 = 0;

    // Enable-Leitung auf 1 setzen
    E = 1;
    // Daten auf den Pins ausgeben
    D4 = (data & 0b00000001);
    D5 = (data & 0b00000010) >> 1;
    D6 = (data & 0b00000100) >> 2;
    D7 = (data & 0b00001000) >> 3;
    delay_us(2000);
    // Erzeugen der fallenden Flanke, bei der die Daten vom LCD übernommen werden
    E = 0;
    // LCD aufs Steuerregister einstellen
    RS = 0;
}  /* Ende: send_nibble() */


/*******************************************************************************
*           Byte senden                                                        +
*******************************************************************************/
void LCD_sendbyte(int data, int direction)
{
    // Senden des 1. Nibbles (Bit7 - Bit4)
    send_nibble((data & 0xF0)>>4,direction);
    delay_us(1000);
    // Senden des 2. Nibbles (Bit3 - Bit0)
    send_nibble(data&0x0F,direction);
    delay_us(1000);
}  /* Ende: LCD_sendbyte() */


/*******************************************************************************
*           LCD initialisieren                                                 *
*******************************************************************************/
void LCD_init()
{
   TRISBbits.TRISB0 = 0; // TRIS_RS = 0;
   TRISBbits.TRISB1 = 0; // TRIS_RW = 0;
   TRISBbits.TRISB2 = 0; // TRIS_E  = 0;
   
   //Initialisierungsdaten ans LCD senden
   send_nibble(3,0);
   delay_ms(50);
   send_nibble(3,0);
   delay_us(1500);
   send_nibble(3,0);
   delay_us(1000);

   // Auf 4-Bit Modus umstellen
   send_nibble(2,0);
   delay_ms(10);

   // System-Set ins Register schreiben
   send_nibble(2,0);
   delay_us(1000);
   send_nibble(8,0);
   delay_ms(10);

   // Display ein/aus; Cursor ein/aus; Blink ein/ aus
   send_nibble(0,0);
   delay_us(1000);
   send_nibble(Display_on | line_on | blink_off ,0); //
   delay_us(1000);

   // Entry-mode-Einstellung
   send_nibble(0,0);
   delay_us(1000);
   send_nibble(6,0);
   delay_us(1000);

   // Löschen der Anzeige
   send_nibble(0,0);
   delay_us(1000);
   send_nibble(1,0);
   delay_us(1000);

   // Cursor an die folgende Position stellen: 1. Zeile; 1. Position
   send_nibble(0,0);
   delay_us(1000);
   send_nibble(2,0);
   delay_us(1000);
}  /* Ende: LCD_init() */


/*******************************************************************************
*      Cursor positionieren                                                    *
*******************************************************************************/
void LCD_gotoxy( BYTE x, BYTE y)
{
   BYTE address;

   if(y!=1)
     address=lcd_line_two;
   else
     address=0;
   address+=x-1;
   lcd_sendbyte(0x80|address,0);  // Senden der Cursor-Adresse ans LCD
}  /* Ende: LCD_gotoxy() */


/*******************************************************************************
*      Zeichen oder Zeichenkette senden                                        *
*******************************************************************************/
void LCD_putc( char c)
{
   switch (c) {
     case '\f'   : lcd_sendbyte(1,0);              // Anzeige löschen
                   delay_ms(2);
                                          break;
     case '\n'   : lcd_gotoxy(1,2);       break;   // Cursor an den Beginn der 2.Zeile setzen
     case '\b'   : lcd_sendbyte(0x10,0);  break;   // Cursor um eine Stelle nach links schieben
     default     : lcd_sendbyte(c,1);     break;   // Zeichen ans LCD senden
   }
}  /* Ende: LCD_putc() */


tut mir leid wenn ich euch mit trivialen problemen nerven muss aber ich komm nicht dahinter und versuchs nun schon seit längeren(~1woche)

ich bekomme folgende fehler:
LCD_driver.c: In function 'send_nibble':
LCD_driver.c:86: warning: implicit declaration of function 'delay_us'
LCD_driver.c: In function 'LCD_init':
LCD_driver.c:119: warning: implicit declaration of function 'delay_ms'
LCD_driver.c: At top level:
LCD_driver.c:164: error: syntax error before 'x'
LCD_driver.c: In function 'LCD_gotoxy':
LCD_driver.c:166: error: 'BYTE' undeclared (first use in this function)
LCD_driver.c:166: error: (Each undeclared identifier is reported only once
LCD_driver.c:166: error: for each function it appears in.)
LCD_driver.c:166: error: syntax error before 'address'
LCD_driver.c:168: error: 'y' undeclared (first use in this function)
LCD_driver.c:169: error: 'address' undeclared (first use in this function)
LCD_driver.c:172: error: 'x' undeclared (first use in this function)
LCD_driver.c:173: warning: implicit declaration of function 'lcd_sendbyte'
LCD_driver.c: In function 'LCD_putc':
LCD_driver.c:186: warning: implicit declaration of function 'lcd_gotoxy'
ihr wist sicher was das ist
ich dachte ich frag mal wen der damit mehr zum tun hat und sich dadurch besser auskennt L&#228;chelnd

lg und danke für die hilfe

EDIT:
damit hab ich die größten probleme:

BYTE .. datentyp ... kann ich den in INT ändern ?
_delay_us
_delay_ms
lcd_sendbyte
lcd_gotoxy

hab gelesen dass ich für die delay_ms oder us die built_in.h benötige Huch


 :-o
« Letzte Änderung: März 11, 2008, 23:02:35 von davethebachelor » Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #5 am: März 12, 2008, 00:00:16 »

Zitat
ich verwende den ccs compiler (glaub ich halt)

Wirklich? Der von Dir gepostete Code (und die Fehlermeldungen) sehen für mich mit an Sicherheit grenzender Wahrscheinlichkeit nach dem Microchip C30 Compiler aus.

Zitat
BYTE .. datentyp ... kann ich den in INT ändern ?

Der Datentyp BYTE ist beim CCS ein vorzeichenloser 8-Bit Wert. Du könntest also BYTE in unsigned char ändern oder den Typ BYTE definieren:

Code:
typedef unsigned char   BYTE;

Damit sollten alle Fehlermeldungen (error) des Compilers schon mal verschwinden. Die Warnungen ("implicit declaration") werden allerdings bleiben und zu einer Fehlermeldung des Linkers führen, da es beim C30 die Funktionen delay_us und delay_ms nicht gibt.

Zitat
hab gelesen dass ich für die delay_ms oder us die built_in.h benötige Huch

Diese Header-Datei gibt es beim C30 nicht. Du könntest für die Delays die vorhandene Funktion __delay32 verwenden, indem Du Makros definierst:

Code:
void __delay32 (unsigned long cycles);   // Prototyp für __delay32

// Beispiel, wenn der PIC mit 30 MIPS arbeitet
// 1 Instruction Cycle = 1 / 30 MHz = 33,333ns
// -> 1 µs = 30 Instruction Cycles
// -> 1 ms = 30000 Instruction Cycles

#define delay_us(n)  __delay32 ((n) * 30uL);     // n maximal 143165576 ((2^32-1) / 30)
#define delay_ms(n)  __delay32 ((n) * 30000uL);  // n maximal 143165    ((2^32-1) / 30000)

Zu den dann noch verbleibenden Warnungen (die ebenfalls eine Fehlermeldung des Linkers hervorrufen werden):

Zitat
LCD_driver.c:173: warning: implicit declaration of function 'lcd_sendbyte'
LCD_driver.c:186: warning: implicit declaration of function 'lcd_gotoxy'

Jeder ANSI-C kompatible Compiler ist "case sensitive" (der CCS ist es nicht), d.h. LCD_gotoxy() und lcd_gotoxy() sind dann zwei unterschiedliche Funktionen. In der Definition wurde "LCD" groß geschrieben, im Funktionsaufruf aber klein. Die Schreibweise des Funktionsnamens in der Deklaration (Funktionsprotyp), der Definition (die Funktion selbst) und im Funktionaufruf selbst müsen identisch sein.


Viele Grüße

Bernd
Gespeichert

davethebachelor
Newbie
*
Offline Offline

Beiträge: 10



Profil anzeigen
« Antworten #6 am: März 12, 2008, 10:21:45 »

BUILD SUCCEEDED: Wed Mar 12 10:20:00 2008

VIELEN DANK !!!  Schockiert:

auf das wäre ich warscheinlich erst in 1000 jahren gekommen

so jetzt muss ich nur noch das lcd anstecken und dann noch den code so umschreiben dass ich damit ein 4x20 display ansteuern kann Smiley

aber nochnmals vielen dank erstmals
Gespeichert
davethebachelor
Newbie
*
Offline Offline

Beiträge: 10



Profil anzeigen
« Antworten #7 am: März 12, 2008, 14:45:50 »

Hallo nochmal !

also das compilen und auch das schreiben geht jetzt in ordnung ... nur die zeichen, die ich schreiben will gehen noch nicht so richtig .. ich bekomme immer alles mögliche raus (leider)

Code:

#include <p30f4013.h>  // Hier stehen nur die Adressen der Ports drinn.                   

typedef unsigned char   BYTE;

/******************************************************************************/
/*    Steuerleitungen                                                         */
/******************************************************************************/
#define RS  LATBbits.LATB0          // RS ist an RB0 angeschlossen - PIN4 LCD
#define RW  LATBbits.LATB1          // RW ist an RB1 angeschlossen - PIN5 LCD
#define E   LATBbits.LATB2          // E ist an RB2 angeschlossen  - PIN6 LCD
/******************************************************************************/
/******************************************************************************/

/******************************************************************************/
/*    Datenleitungen                                                          */
/******************************************************************************/
#define D4  LATBbits.LATB9          // D4 ist an RB4 angeschlossen - PIN11 LCD
#define D5  LATBbits.LATB10          // D5 ist an RB5 angeschlossen - PIN12 LCD
#define D6  LATBbits.LATB11          // D6 ist an RB6 angeschlossen - PIN13 LCD
#define D7  LATBbits.LATB12          // D7 ist an RB7 angeschlossen - PIN14 LCD
/******************************************************************************/
/******************************************************************************/

#define lcd_line_two 0x40     // LCD RAM address for the second line
#define lcd_line_three 0x13     // LCD RAM address for the second line
#define lcd_line_four 0x54     // LCD RAM address for the second line
#define line_on      0x02     // Unterstriches aktivieren 0010
#define blink_on      0x01     // BLinkenden Cursor aktivieren 0001
#define Display_on    0x0C     // Display einschalten 1100

#define line_off      0x00    // Unterstrich deaktivieren 0000
#define blink_off      0x00    // Blinkenden Cursor deaktivieren 0000
#define Display_off    0x08    // Display ausschalten 1000

///////////////////////////////////////////////////////////////////////////////

void __delay32 (unsigned long cycles);   // Prototyp für __delay32

#define delay_us(n)  __delay32 ((n/4) * 10uL);     // n maximal 143165576 ((2^32-1) / 30)
#define delay_ms(n)  __delay32 ((n/4) * 10000uL);  // n maximal 143165    ((2^32-1) / 30000)

//////////////////////////////////////////////////////////////////////////////////////

// Nibble senden
void send_nibble(int data,int direction)
{
    // Datenregister oder Steuerregister auswählen
    RS = direction;
    // Schreibmodus einstellen
    RW = 0;
    // Enable-Leitung auf 0 setzen
    E = 0;

    // IO-Ports als Ausgänge einstellen
    TRISBbits.TRISB9  = 0; // TRIS_D4 = 0;
    TRISBbits.TRISB10 = 0; // TRIS_D5 = 0;
    TRISBbits.TRISB11 = 0; // TRIS_D6 = 0;
    TRISBbits.TRISB12 = 0; // TRIS_D7 = 0;

    // Enable-Leitung auf 1 setzen
    E = 1;
    // Daten auf den Pins ausgeben
    D4 = (data & 0b00000001);
    D5 = (data & 0b00000010) >> 1;
    D6 = (data & 0b00000100) >> 2;
    D7 = (data & 0b00001000) >> 3;
    delay_us(2000);
    // Erzeugen der fallenden Flanke, bei der die Daten vom LCD übernommen werden
    E = 0;
    // LCD aufs Steuerregister einstellen
    RS = 0;
}  /* Ende: send_nibble() */


/*******************************************************************************
*           Byte senden                                                        +
*******************************************************************************/
void lcd_sendbyte(int data, int direction)
{
    // Senden des 1. Nibbles (Bit7 - Bit4)
    send_nibble((data & 0xF0)>>4,direction);
    delay_us(1000);
    // Senden des 2. Nibbles (Bit3 - Bit0)
    send_nibble(data & 0x0F,direction);
    delay_us(1000);
}  /* Ende: LCD_sendbyte() */


/*******************************************************************************
*           LCD initialisieren                                                 *
*******************************************************************************/
void lcd_init()
{
   TRISBbits.TRISB0 = 0; // TRIS_RS = 0;
   TRISBbits.TRISB1 = 0; // TRIS_RW = 0;
   TRISBbits.TRISB2 = 0; // TRIS_E  = 0;

send_nibble(0x3,0); // 0000 0011
   delay_ms(20); 

   //Initialisierungsdaten ans LCD senden
   send_nibble(0x3,0);
   send_nibble(0x23,0);
   send_nibble(0x3,0);
   delay_ms(10);

   send_nibble(0x23,0);
   send_nibble(0x3,0);
   delay_us(250);

   send_nibble(0x23,0);
   send_nibble(0x3,0);
   delay_us(250);

   // Auf 4-Bit Modus umstellen
   send_nibble(0x2,0);
   send_nibble(0x22,0);
   send_nibble(0x2,0);
   delay_us(250);

   send_nibble(0x28,0);
   send_nibble(0x1,0);
   delay_ms(2);
   send_nibble(0x2,0);
   delay_ms(2);
   send_nibble(0x0C,0);
}
 


/*******************************************************************************
*      Cursor positionieren                                                    *
*******************************************************************************/
void lcd_gotoxy( BYTE x, BYTE y)
{
   BYTE address;

   if(y!=1)
     address = lcd_line_two;
   else
     address = 0;
   address += x-1;
   lcd_sendbyte(0x80|address,0);  // Senden der Cursor-Adresse ans LCD
}  /* Ende: LCD_gotoxy() */


/*******************************************************************************
*      Zeichen oder Zeichenkette senden                                        *
*******************************************************************************/
void lcd_putc( char *c)
{  switch (*c) {
     case '\f'   : lcd_sendbyte(1,0);              // Anzeige löschen
                   delay_ms(2);
                                          break;
     case '\n'   : lcd_gotoxy(1,2);       break;   // Cursor an den Beginn der 2.Zeile setzen
     case '\b'   : lcd_sendbyte(0x10,0);  break;   // Cursor um eine Stelle nach links schieben
     default     : lcd_sendbyte(*c,1);     break;   // Zeichen ans LCD senden
   }
}  /* Ende: LCD_putc() */





//*** main () *****************************************************************/

int main(void)
{
lcd_init();
//TRISDbits.TRISD0  = 0;
while(1) /*Repeat continously*/
{

lcd_putc("LCD TEST");
delay_ms(100);

}
return(0);
}

der compiler meint jetzt nur noch das das EOF fehlt ... ist aber nur eine warnung (KA wie man die wegbekommt)

ich hänge das datenblatt meines displays mal an. :mrgreen:

meine frage :
ich kann nur noch ein einziges zeichen ausgeben und zwar das, welches als erstes steht "lcd_putc("LCD TEST"); gibt nur L aus"

wie kann ich da alles ausgeben ?

und was genau müsste ich ändern damit ich mit dem gotoxy die 4x20 ganz auswählen kann ?
im moment schreibt er bei mir in die erste zeile und dann in die dritte  dann erst in die zweite und in die vierte ... aber nur wenn es einen überlauf gibt  (das lcd is so gebaut das is normal - denk ich mir )

 :yahoo:

* LCD_driver_upload.c (9.37 KB - runtergeladen 177 Mal.)
* lcd_dave.pdf (518.69 KB - runtergeladen 245 Mal.)
« Letzte Änderung: März 12, 2008, 20:27:15 von davethebachelor » Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #8 am: März 20, 2008, 00:15:46 »

Zitat
meine frage :
ich kann nur noch ein einziges zeichen ausgeben und zwar das, welches als erstes steht "lcd_putc("LCD TEST"); gibt nur L aus"

Nicht weiter verwunderlich, da die Ursprungs-Funktion lcd_putc() (aus dem Original-Code) als Argument ein Zeichen (char) erwartet und auch nur ein ein einziges Zeichen ausgibt. Der korrekte Aufruf der Funktion

Code:
lcd_putc (char c)

wäre z.B.

Code:
lcd_putc ('L');   // Character-Konstante L ausgeben

Du hast die Funktion so verändert, daß sie einen String akzeptiert:

Code:
void lcd_putc( char *c)

aber sie gibt dennoch nur ein Zeichen aus. Ich würde die Originalfunktion lcd_putc() unverändert lassen und eine neue Funktion für die Ausgabe eine Strings verwenden:

Code:
void lcd_puts (const char *string)
{
    while (*string != '\0')     // '\0` ist die "Endekennung" eines Strings in C
    {
lcd_putc (*string++);   // der dereferenzierte Zeiger auf den String ist vom Typ "Zeichen"
                                // das Postinkrement (++) inkrementiert den Zeiger, d.h.
                                // der Zeiger string zeigt auf das nächste Zeichen des Strings
    }

}

Außerdem: Das Makro

Zitat
Code:
#define delay_ms(n)  __delay32 ((n/4) * 10000uL);

ist etwas unglücklich gewählt, da es für jedes n < 4 das Statement

Code:
__delay32 (0);

genereriert (der C30 erzeugt dann ein Delay von 11 Instruction-Cycles). Sinnvollerweise solltest Du definieren:

Code:
#define delay_ms(n)  __delay32 ((n) * 2500uL)

Der generierte Delay ist zudem nur korrekt, wenn Du einen 10 MHz Quarz verwendest und der PIC ohne PLL arbeitet (die Configuration-Bits fehlen in Deinem Code, daher kann ich keine Aussage darüber treffen, ob Deine Delays diesbezüglich korrekt sind).


Viele Grüße

Bernd
Gespeichert

davethebachelor
Newbie
*
Offline Offline

Beiträge: 10



Profil anzeigen
« Antworten #9 am: März 21, 2008, 12:51:25 »

HAHA es geht Schockiert)

ich kann schon mal buchstaben und strings ausgeben :-)

hab da noch ein kleines problem glaub ich ... das display schrebt die zeichen sehr sauber und kontrastreich hinaus, jedoch die ersten 8 zeuchen der ersten zeile udn die der zweiten (darunter) sind leider sehr blass - könnte daran liegen dass diese immer refreshed werden ?

ich muss mir das mal mit einem oszi ansehen hab leider im moment keines zu hand - ich glaub meine delays sind noch nicht danz richtig

Code: (cpp)
#define delay_us(n)  __delay32 ((n) * 3uL);     
#define delay_ms(n)  __delay32 ((n) * 2500uL);   

Hier ist mein init :
Code: (cpp)
void lcd_init()
{
   TRISBbits.TRISB0 = 0; // TRIS_RS = 0;
   TRISBbits.TRISB1 = 0; // TRIS_RW = 0;
   TRISBbits.TRISB2 = 0; // TRIS_E  = 0;

   send_nibble(0x3,0); // 0000 0011
   delay_ms(20); 

   //Initialisierungsdaten ans LCD senden
   send_nibble(0x3,0);
   send_nibble(0x23,0);
   send_nibble(0x3,0);
   delay_ms(10);

   send_nibble(0x23,0);
   send_nibble(0x3,0);
   delay_us(250);

   send_nibble(0x23,0);
   send_nibble(0x3,0);
   delay_us(250);

   // Auf 4-Bit Modus umstellen
   send_nibble(0x2,0);
   send_nibble(0x22,0);
   send_nibble(0x2,0);
   delay_us(250);

   send_nibble(0x28,0);
   send_nibble(0x1,0);
   delay_ms(2);
   send_nibble(0x2,0);
   delay_ms(2);
   send_nibble(0x0C,0);
}

naja ... ich habs jetzt so umgebaut:
Code: (cpp)
/*******************************************************************************
*      Zeichen oder Zeichenkette senden                                        *
*******************************************************************************/
void lcd_putc( char *text)
{  int i=0;
for(i=0;i<strlen(text);i++)
{ lcd_sendbyte(text[i],1);
delay_us(50);   
    }
}  /* Ende: LCD_putc() */

deine methode ist natürlich eleganter, jedoch versteh ich meine besser, und ich denke sie machen beide das gleiche :D (hoff ich zumindest)

wie kann ich jetzt eigendlich einen INT wert ausgeben ?
normalerweise müsste ich ihn ja einfach atoi casten und dann aufs lcd schicken ?
aber mein compiler versteht leider das atoi nicht und ich hab noch nichts gefunden wie es bei dem hier heisst...

man könnte es sich natürlich selbst schreiben aber ich denke der compiler hat sowas ja wohl schon eingebaut - wird ja eigendlich öfter verwendet ?

lg
Gespeichert
Schoasch
Sr. Member
****
Offline Offline

Beiträge: 343



Profil anzeigen
« Antworten #10 am: März 21, 2008, 16:02:38 »

Hi

Probiers doch mal mit sprintf... oder mit itoa(falls das vorhanden ist).
Gespeichert
Encinasola
Gast
« Antworten #11 am: Mai 14, 2008, 08:59:26 »

Hi,

hab mich auch mal an die Datei LCD_driver.c gewagt.

Ich habe einen PIC18F4620 und das PICDEM 2 PLUS DEMO BOARD.

Hab ein Hauptprogramm geschrieben.

Code:
/**INCLUDES*******************************************************/
#include <p18cxxx.h>
#include "LCD_driver.c"
#include "delays.h" //für die Warteschleife

/**Configuration**************************************************/
#pragma config OSC = XT
#pragma config PWRT = ON
#pragma config BOREN = OFF
#pragma config WDT = OFF
#pragma config LVP = OFF

/**DECLARATION****************************************************/
#pragma code
void main()
{
LCD_init();
LCD_putc('a');
}

Wenn ich es jetzt überstze dan kommen folgende Meldungen.

Executing: "C:\MCC18\bin\mcc18.exe" -p=18F4620 "test_LCD.c" -fo="test_LCD.o" -Ou- -Ot- -Ob- -Op- -Or- -Od- -Opa-
MPLAB C18 v3.11 (demo)
Copyright 1999-2005 Microchip Technology Inc.
Days remaining until demo becomes feature limited:  53
J:\Projekt_18F4620\C_Program\LCD\test_LCD.c:17:Warning [2058] call of function without prototype
Executing: "C:\MCC18\bin\mplink.exe" /l"C:\MCC18\lib" "J:\Projekt_18F4620\C_Program\LCD\18f4620.lkr" "J:\Projekt_18F4620\C_Program\LCD\LCD_driver.o" "J:\Projekt_18F4620\C_Program\LCD\test_LCD.o" /o"Test_LCD.cof" /M"Test_LCD.map" /W
MPLINK 4.11, Linker
Copyright (c) 2007 Microchip Technology Inc.
Error - symbol 'send_nibble' has multiple definitions.
Errors    : 1

Link step failed.
BUILD FAILED: Wed May 14 09:54:37 2008


Was muss ich ändern, was mach ich falsch? Wer kann mir helfen?

Gruss Encinasola
Gespeichert
Encinasola
Gast
« Antworten #12 am: Mai 14, 2008, 11:13:00 »

Hi, ich noch mal.

Also die Warning Meldung hab ich wegbekommen.

Aber der Error mit dem send_nibble besteht leider immer noch.

"MPLINK 4.11, Linker
Copyright (c) 2007 Microchip Technology Inc.
Error - symbol 'send_nibble' has multiple definitions.
Errors    : 1

Link step failed.
BUILD FAILED: Wed May 14 12:08:38 2008"

Hatte noch niemand das gleiche Problem? Oder weiss wenigstens in welche Richtung ich gehen muss um einen Lösung zu finden?

Wäre echt dankbar über jeden Hinweis.

Gruss Encinasola
Gespeichert
Encinasola
Gast
« Antworten #13 am: Mai 16, 2008, 09:57:19 »

Ich nochmal. Ich versuchs einfach weiter, vielleicht hat ja mal jemand nen Tipp.

Stand: Ich hab es zum laufen gebracht.
Mein Code:
Code:
/**INCLUDES*******************************************************/
#include <p18f4620.h>
#include "delays.h" //für die Warteschleife

/**Configuration**************************************************/
#pragma config OSC = XT
#pragma config PWRT = ON
#pragma config BOREN = OFF
#pragma config WDT = OFF
#pragma config LVP = OFF


/**DECLARATION****************************************************/
//#pragma code
 int x = 0;
 int y = 0;
void main()
{
LCD_init();
while(1)
{
lcd_gotoxy(1,1);
/*LCD_putc('H');
LCD_putc('a');
LCD_putc('l');
LCD_putc('l');
LCD_putc('o');
lcd_gotoxy(1,2);
LCD_putc('m');
LCD_putc('e');
LCD_putc('i');
LCD_putc('n');
lcd_gotoxy(6,2);
LCD_putc('S');
LCD_putc('c');
LCD_putc('h');
LCD_putc('a');
LCD_putc('t');
LCD_putc('z');*/
LCD_puts('Hallo\0');
}
}

Wenn ich das jetzt übersetze, kommen Warnungen
J:\Projekt_18F4620\C_Program\LCD\test_LCD.c:19:Warning [2058] call of function without prototype
J:\Projekt_18F4620\C_Program\LCD\test_LCD.c:22:Warning [2058] call of function without prototype
J:\Projekt_18F4620\C_Program\LCD\test_LCD.c:40:Warning [2058] call of function without prototype

Was mach ich beim Aufruf von z.B. LCD_init() falsch?
wie muss ich den Text bei LCD_puts in der Klammer schreiben, wenn ich diesen Programmteil nutze?

Code:
void LCD_puts( char *text)
{  int i=0;
for(i=0;i<strlen(text);i++)
{ lcd_sendbyte(text[i],1);
delay_us(5);   
    }
}  /* Ende: LCD_puts() */

Oder ist die Version von Bernd besser. Wie müsste mein LCD_puts dann aussehen.

Gruss Encinasola
Gespeichert
Seiten: [1] Nach oben Drucken 
« vorheriges nächstes »
Gehe zu:  

Powered by MySQL Powered by PHP Made for Mozilla (Firefox) Made for Internet Explorer
Seite erstellt in 0.065 Sekunden mit 18 Zugriffen.
 
Top! Top!