Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit LCD-DIsplay
cantforget
13.07.2011, 16:05
Hallo,
ich habe ein Problem mit meinem Board (RN-MEGA8PLUS V1.5). Dazu habe ich noch den RN-LCD Adapter (BSLCDADAPT) und dieses LCD Display (EADIP204) auch aus dem RN Shop.
Nun habe ich alles angeschlossen (Display Adapter am Display Port), danach habe ich den aufgeführten Code aufgespielt. Jedoch funktioniert das Display Überhaubt nicht. Es blinkt mitsamt der Status Balkenanzeige.
$regfile = "m8def.dat"
'$crystal = 16000000                      'Quarzfrequenz
$crystal = 7372800                                          'Alternative Quarzfrequenz
' Falls ein LCD Display angeschlossen ist
Config Portd = Output
Config Portc = Output
Config Lcd = 20 * 4
Config Lcdpin = Pin , Db4 = Portd.2 , Db5 = Portd.3 , Db6 = Portd.4 , Db7 = Portd.5 , E2 = Portd.7 , Rs = Portc.2
Config Lcdbus = 4
Cls
'Initlcd
Do
Locate 1 , 1
Lcd "Hallo Welt"
'Waitms 500
Loop
Gruß
Dennis
Hallo Dennis, 
ich habe auch einmal mit diesen Displays herumgefuchst und mir gings beim ersten Versuch genauso. 
Dann hab ich ein bisschen herumprobiert und auf einmal hat es funktioniert. Ich habe damals die Zeile
config Lcdbus = 4 
weggelassen. Dann hat es funktioniert. Ich habe nicht die geringste Ahnung warum, aber es hat dann auf anhieb funktioniert. Villeicht weiß ja jemand hier im Forum warum. 
Das könntest du auch einmal ausprobieren, villeicht funktionier es dann ja. 
Warum schreibst du eigentlich E2? reicht da nicht schon E für Enable?
Und du könntest alles mit anderen Output-pins versuchen, bei mir war nämlich einmal einer kaputt und dann hat auch alles nicht funktioniert.
Bin schon gespannt, ob das mit dem lcdbus = 4 weglassen auch bei jemandem anderen funktioniert.
Mfg Thegon
cantforget
13.07.2011, 22:19
Hallo Thegon,
Danke für deine Antwort. Ich werde deinen Vorschlag morgen direkt mal ausprobieren. Das E2 habe ich aus einem Beispielprogramm. Ich denke das LCD ist ein 2-Chip Display. Daher das 2. Enable. Werde dann morgen über den "hoffentlich" Erfolg berichten.
Schönen Abend noch
Dennis
Ich denk mal, das es nicht funktionieren wird.
Das EA204DIP nutzt zwar ein ähnliches Protokoll wie die üblichen HD44780 Displays.
Im Prinzip geht es da beim 4 Zeiligen Display um ein Kommando und andere Adressen für die einzelnen Stellen.
In C sieht das so aus:
_lcd_maxx=lcd_columns;
_base_y[0]=0x00;
_base_y[1]=lcd_columns + 0x0C;
_base_y[2]=lcd_columns + 0x2C;
_base_y[3]=lcd_columns + 0x4C;
_long_delay();
_long_delay();
_lcd_init_write(0x20);  // 4 Bit Modus + RE Bit clear
_long_delay();
_lcd_init_write(0x24);  // 4 Bit Modus + RE Bit set
_long_delay();
_lcd_init_write(0x09); 
_long_delay();
_lcd_init_write(0x20);  // 4 Bit Modus + RE Bit clear
_long_delay();
_lcd_init_write(0x0C);  // Display On
_long_delay();
_lcd_init_write(0x01);  // Clear Display
_long_delay();
_lcd_init_write(0x06);  //Auto Increment on
_long_delay();
Beim HD44780 so:
_lcd_maxx=lcd_columns;
_base_y[2]=lcd_columns+0x80;
_base_y[3]=lcd_columns+0xc0;
_long_delay();
_lcd_init_write(0x30);
_long_delay();
_lcd_init_write(0x30);
_long_delay();
_lcd_init_write(0x30);
_long_delay();
_lcd_init_write(0x20);
_long_delay();
_lcd_write_data(0x28);
_long_delay();
_lcd_write_data(4);
_long_delay();
_lcd_write_data(0x85);
_long_delay();
Wie das nun in BASCOM zu machen ist, kann ich Dir leider auch nicht sagen.
Eventuell hat da aber schon jemand eine fertige LIB für dieses Display.
cantforget
14.07.2011, 15:13
Hallo,
erstmal zu deiner Idee Thegon:
Ich es mal probiert das LCD durch weglassen der Bus-Configuration zum Sprechen zu bewegen, allerdings ohne Erfolg. Bist also noch der einzige mit disem Phänomen.
Nun zu dir wkrug:
Also mein Gedanke dahinter war, mal eben nen bisschen Bascom-Code zu Schreiben, um zu Testen ob das Display geht. Allerdings soll das Projekt, welches daraus entsteht in C programmiert werden. Morgen werde ich mal die Lib aus dem AVR-GCC-Tutorial ausprobieren um zu schauen ob es so geht. Kannst du mir vielleicht sagen was genau ich in der lcd-routines.h anpassen muss, damit es mit meinem 20*4 Zeichen Display funktioniert? Stehe da irgendwie wie ein Ochse vorm Berg mit den Adressen.
Gruß
Dennis
Die Adressen und Ansteuer Sequenzen stehen im Datenblatt des Displays - Nur zur Info
Nicht für AVR GCC aber für CodeVision...
Hier die lcddip.h
/* LCD driver routines
  CodeVisionAVR C Compiler
  (C) 1998-2000 Pavel Haiduc, HP InfoTech S.R.L.
  BEFORE #include -ING THIS FILE YOU
  MUST DECLARE THE I/O ADDRESS OF THE
  DATA REGISTER OF THE PORT AT WHICH
  THE LCD IS CONNECTED!
  EXAMPLE FOR PORTB:
    #asm
        .equ __lcd_port=0x18
    #endasm
    #include <lcddip.h>
Copy the File LCDDIP204.lib into the entire folder
*/
#ifndef _LCD_INCLUDED_
#define _LCD_INCLUDED_
#pragma used+
void _lcd_ready(void);
void _lcd_write_data(unsigned char data);
// write a byte to the LCD character generator or display RAM
void lcd_write_byte(unsigned char addr, unsigned char data);
// read a byte from the LCD character generator or display RAM
unsigned char lcd_read_byte(unsigned char addr);
// set the LCD display position  x=0..39 y=0..3
void lcd_gotoxy(unsigned char x, unsigned char y);
// clear the LCD
void lcd_clear(void);
void lcd_putchar(char c);
// write the string str located in SRAM to the LCD
void lcd_puts(char *str);
// write the string str located in FLASH to the LCD
void lcd_putsf(char flash *str);
// initialize the LCD controller
unsigned char lcd_init(unsigned char lcd_columns);
#pragma used-
#pragma library LCDDIP204.c
#endif
Die dazugehörige LCDDIP204.c
/* LCD driver routines
  CodeVisionAVR C Compiler
  (C) 1998-2004 Pavel Haiduc, HP InfoTech S.R.L.
*/
#asm
    .equ __lcd_direction=__lcd_port-1
    .equ __lcd_pin=__lcd_port-2
    .equ __lcd_rs=0
    .equ __lcd_rd=1
    .equ __lcd_enable=2
    .equ __lcd_busy_flag=7
#endasm
#pragma used+
static unsigned char _base_y[4]={0x80,0xc0};
unsigned char _lcd_x,_lcd_y,_lcd_maxx;
#pragma used-
void _lcd_ready(void)
{
#asm
    in    r26,__lcd_direction
    andi  r26,0xf                 ;set as input
    out   __lcd_direction,r26
    sbi   __lcd_port,__lcd_rd     ;RD=1
    cbi   __lcd_port,__lcd_rs     ;RS=0
__lcd_busy:
    rcall __lcd_delay
    sbi   __lcd_port,__lcd_enable ;EN=1
    rcall __lcd_delay
    in    r26,__lcd_pin
    cbi   __lcd_port,__lcd_enable ;EN=0
    rcall __lcd_delay
    sbi   __lcd_port,__lcd_enable ;EN=1
    rcall __lcd_delay
    cbi   __lcd_port,__lcd_enable ;EN=0
    sbrc  r26,__lcd_busy_flag
    rjmp  __lcd_busy
#endasm
}
#asm
__lcd_write_nibble:
    andi  r26,0xf0
    or    r26,r27
    out   __lcd_port,r26          ;write
    sbi   __lcd_port,__lcd_enable ;EN=1
    rcall __lcd_delay
    cbi   __lcd_port,__lcd_enable ;EN=0
__lcd_delay:
    ldi   r31,15
__lcd_delay0:
    dec   r31
    brne  __lcd_delay0
    ret
#endasm
void _lcd_write_data(unsigned char data)
{
#asm
    cbi  __lcd_port,__lcd_rd       ;RD=0
    in    r26,__lcd_direction
    ori   r26,0xf7                ;set as output
    out   __lcd_direction,r26
    in    r27,__lcd_port
    andi  r27,0xf
    ld    r26,y
    rcall __lcd_write_nibble      ;RD=0, write MSN
    ld    r26,y
    swap  r26
    rcall __lcd_write_nibble      ;write LSN
    sbi   __lcd_port,__lcd_rd     ;RD=1
#endasm
}
/* write a byte to the LCD character generator or display RAM */
#if funcused lcd_write_byte
void lcd_write_byte(unsigned char addr, unsigned char data)
{
_lcd_ready();
_lcd_write_data(addr);
_lcd_ready();
#asm
    sbi   __lcd_port,__lcd_rs     ;RS=1
#endasm
_lcd_write_data(data);
}
#endif
#if funcused lcd_read_byte || funcused lcd_init
#asm
__lcd_read_nibble:
    sbi   __lcd_port,__lcd_enable ;EN=1
    rcall __lcd_delay
    in    r30,__lcd_pin           ;read
    cbi   __lcd_port,__lcd_enable ;EN=0
    rcall __lcd_delay
    andi  r30,0xf0
    ret
#endasm
static unsigned char lcd_read_byte0(void)
{
#asm
    rcall __lcd_delay
    rcall __lcd_read_nibble       ;read MSN
    mov   r26,r30
    rcall __lcd_read_nibble       ;read LSN
    cbi   __lcd_port,__lcd_rd     ;RD=0
    swap  r30
    or    r30,r26
#endasm
}
#endif
#if funcused lcd_read_byte
/* read a byte from the LCD character generator or display RAM */
unsigned char lcd_read_byte(unsigned char addr)
{
_lcd_ready();
_lcd_write_data(addr);
_lcd_ready();
#asm
    in    r26,__lcd_direction
    andi  r26,0xf                 ;set as input
    out   __lcd_direction,r26
    sbi   __lcd_port,__lcd_rs     ;RS=1
#endasm
return lcd_read_byte0();
}
#endif
/* set the LCD display position x=0..39 y=0..3 */
#if funcused lcd_gotoxy || funcused lcd_putchar || funcused lcd_puts || funcused lcd_putsf
void lcd_gotoxy(unsigned char x, unsigned char y)
{
_lcd_ready(); // RS=0
_lcd_write_data(_base_y[y]+x+0x80);
_lcd_x=x;
_lcd_y=y;
}
#endif
// clear the LCD
#if funcused lcd_clear || funcused lcd_init
void lcd_clear(void)
{
_lcd_ready();         // RS=0
_lcd_write_data(2);   // cursor home
_lcd_ready();
_lcd_write_data(0xc); // cursor off
_lcd_ready();
_lcd_write_data(1);   // clear
_lcd_x=_lcd_y=0;
}
#endif
#if funcused lcd_putchar || funcused lcd_puts || funcused lcd_putsf
#pragma keep+
void lcd_putchar(char c)
{
#asm
    push r30
    push r31
    ld   r26,y
    set
    cpi  r26,10
    breq __lcd_putchar1
    clt
#endasm
++_lcd_x;
if (_lcd_x>_lcd_maxx)
   {
   #asm("__lcd_putchar1:")
   ++_lcd_y;
   lcd_gotoxy(0,_lcd_y);
   #asm("brts __lcd_putchar0")
   };
#asm
    rcall __lcd_ready
    sbi  __lcd_port,__lcd_rs ;RS=1
    ld   r26,y
    st   -y,r26
    rcall __lcd_write_data
__lcd_putchar0:
    pop  r31
    pop  r30
#endasm
}
#pragma keep-
#endif
// write the string str located in SRAM to the LCD
#if funcused lcd_puts
void lcd_puts(char *str)
{
#ifdef _MODEL_TINY_
#asm
    clr  r31
#endasm
#endif
#ifdef _MODEL_SMALL_
#asm
    ldd  r31,y+1
#endasm
#endif
#asm
    ld   r30,y
__lcd_puts0:
    ld   r26,z+
    tst  r26
    breq __lcd_puts1
    st   -y,r26    
    rcall _lcd_putchar
    rjmp __lcd_puts0
__lcd_puts1:
#endasm
}
#endif
// write the string str located in FLASH to the LCD
#if funcused lcd_putsf
void lcd_putsf(char flash *str)
{
#asm
    ld   r30,y
    ldd  r31,y+1
__lcd_putsf0:
#endasm
#if defined _CHIP_ATMEGA128_ || defined _CHIP_ATMEGA128L_
#asm("elpm")
#else
#asm("lpm")
#endif
#asm
    tst  r0
    breq __lcd_putsf1
    adiw r30,1
    st   -y,r0
    rcall _lcd_putchar
    rjmp __lcd_putsf0
__lcd_putsf1:
#endasm
}
#endif
#if funcused lcd_init
static void _long_delay(void)
{
#asm
    clr   r26
    clr   r27
__long_delay0:
    sbiw  r26,1         ;2 cycles
    brne  __long_delay0 ;2 cycles
#endasm
}
static void _lcd_init_write(unsigned char data)
{
#asm
    cbi  __lcd_port,__lcd_rd       ;RD=0
    in    r26,__lcd_direction
    ori   r26,0xf7                ;set as output
    out   __lcd_direction,r26
    in    r27,__lcd_port
    andi  r27,0xf
    ld    r26,y
    rcall __lcd_write_nibble      ;RD=0, write MSN
    ld    r26,y
    swap  r26
    rcall __lcd_write_nibble      ;write LSN
    sbi   __lcd_port,__lcd_rd     ;RD=1
#endasm
}
// initialize the LCD controller
unsigned char lcd_init (unsigned char lcd_columns)
{
#asm
    cbi   __lcd_port,__lcd_enable ;EN=0
    cbi   __lcd_port,__lcd_rs     ;RS=0
#endasm
_lcd_maxx=lcd_columns;
_base_y[0]=0x00;
_base_y[1]=lcd_columns + 0x0C;
_base_y[2]=lcd_columns + 0x2C;
_base_y[3]=lcd_columns + 0x4C;
_long_delay();
_long_delay();
_lcd_init_write(0x20);  // 4 Bit Modus + RE Bit clear
_long_delay();
_lcd_init_write(0x24);  // 4 Bit Modus + RE Bit set
_long_delay();
_lcd_init_write(0x09); 
_long_delay();
_lcd_init_write(0x20);  // 4 Bit Modus + RE Bit clear
_long_delay();
_lcd_init_write(0x0C);  // Display On
_long_delay();
_lcd_init_write(0x01);  // Clear Display
_long_delay();
_lcd_init_write(0x06);  //Auto Increment on
_long_delay();
#asm
    in    r26,__lcd_direction
    andi  r26,0xf                 ;set as input
    out   __lcd_direction,r26
    sbi   __lcd_port,__lcd_rd     ;RD=1
#endasm
if (lcd_read_byte0()!=5) return 0;
_lcd_ready();
_lcd_write_data(6);
lcd_clear();
return 1;
}
#endif
Und die dazugehörigen Ports mit Adresszuweisung:
// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x02 ;PORTA
#endasm
#include "lcddip.h"
Und die Init Sequenz mit ein wenig Text:
lcd_init(20);
lcd_gotoxy(0,0);
lcd_putsf("4 Chan. MiDi Merger\n");
lcd_putsf("Ver. 1.2\n");
lcd_putsf("Date: 10.Feb.2011");
Und die Anschlußbelegung:
RS (pin4) ------     bit 0
RD (pin 5) ------    bit 1
EN (pin 6) ------    bit 2
DB4 (pin 11) ---    bit 4
DB5 (pin 12) ---    bit 5
DB6 (pin 13) ---    bit 6
DB7 (pin 14) ---    bit 7
Eventuell kannst Du die GCC lib entsprechend anpassen.
Auch mit dieser lib zickt das Display ztw. rum. Die Zeile 3 und 4 lässt sich so bei jedem 20 Start nicht richtig ansprechen.
Ansonstan geht alles wie es soll.
cantforget
15.07.2011, 10:58
Hallo,
danke für deine schnelle Antwort wkrug. Habe das mal mit deiner Lib ausprobiert, allerdings funktioniert mein LCD immer noch nicht. Aber ich denke mal es liegt daran, dass ich das mit der Adressierung einfach nicht hinbekomme. 
Ich habe es jetzt einmal mit nem anderen Board und LCD ausprobiert (Board und LCD von myAVR), das ganze mit der GCC-LCD-Tutorial Lib in C programmiert und siehe da es funktioniert.
Hier die lcd-routines.h:
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
//
 
#ifndef LCD_ROUTINES_H
#define LCD_ROUTINES_H
 
////////////////////////////////////////////////////////////////////////////////
// Hier die verwendete Taktfrequenz in Hz eintragen, wichtig!
 
#ifndef F_CPU
#define F_CPU 3686400
#endif
 
////////////////////////////////////////////////////////////////////////////////
// Pinbelegung für das LCD, an verwendete Pins anpassen
// Alle LCD Pins müssen an einem Port angeschlossen sein und die 4
// Datenleitungen müssen auf aufeinanderfolgenden Pins liegen
 
//  LCD DB4-DB7 <-->  PORTD Bit PD0-PD3
#define LCD_PORT      PORTD
#define LCD_DDR       DDRD
#define LCD_DB        PD4
 
//  LCD RS      <-->  PORTD Bit PD4     (RS: 0=Data, 1=Command)
#define LCD_RS        PD2
 
//  LCD EN      <-->  PORTD Bit PD5     (EN: 1-Impuls für Daten)
#define LCD_EN        PD3
 
////////////////////////////////////////////////////////////////////////////////
// LCD Ausführungszeiten (MS=Millisekunden, US=Mikrosekunden)
 
#define LCD_BOOTUP_MS           15
#define LCD_ENABLE_US           1
#define LCD_WRITEDATA_US        46
#define LCD_COMMAND_US          42
 
#define LCD_SOFT_RESET_MS1      5
#define LCD_SOFT_RESET_MS2      1
#define LCD_SOFT_RESET_MS3      1
#define LCD_SET_4BITMODE_MS     5
 
#define LCD_CLEAR_DISPLAY_MS    2
#define LCD_CURSOR_HOME_MS      2
 
////////////////////////////////////////////////////////////////////////////////
// Zeilendefinitionen des verwendeten LCD
// Die Einträge hier sollten für ein LCD mit einer Zeilenlänge von 16 Zeichen passen
// Bei anderen Zeilenlängen müssen diese Einträge angepasst werden
 
#define LCD_DDADR_LINE1         0x00
#define LCD_DDADR_LINE2         0x40
#define LCD_DDADR_LINE3         0x10
#define LCD_DDADR_LINE4         0x50
 
////////////////////////////////////////////////////////////////////////////////
// Initialisierung: muss ganz am Anfang des Programms aufgerufen werden.
void lcd_init( void );
 
////////////////////////////////////////////////////////////////////////////////
// LCD löschen
void lcd_clear( void );
 
////////////////////////////////////////////////////////////////////////////////
// Cursor in die 1. Zeile, 0-te Spalte
void lcd_home( void );
 
////////////////////////////////////////////////////////////////////////////////
// Cursor an eine beliebige Position 
void lcd_setcursor( uint8_t spalte, uint8_t zeile );
 
////////////////////////////////////////////////////////////////////////////////
// Ausgabe eines einzelnen Zeichens an der aktuellen Cursorposition 
void lcd_data( uint8_t data );
 
////////////////////////////////////////////////////////////////////////////////
// Ausgabe eines Strings an der aktuellen Cursorposition 
void lcd_string( const char *data );
 
////////////////////////////////////////////////////////////////////////////////
// Definition eines benutzerdefinierten Sonderzeichens.
// data muss auf ein Array[5] mit den Spaltencodes des zu definierenden Zeichens
// zeigen
void lcd_generatechar( uint8_t code, const uint8_t *data );
 
////////////////////////////////////////////////////////////////////////////////
// Ausgabe eines Kommandos an das LCD.
void lcd_command( uint8_t data );
 
 
////////////////////////////////////////////////////////////////////////////////
// LCD Befehle und Argumente.
// Zur Verwendung in lcd_command
 
// Clear Display -------------- 0b00000001
#define LCD_CLEAR_DISPLAY       0x01
 
// Cursor Home ---------------- 0b0000001x
#define LCD_CURSOR_HOME         0x02
 
// Set Entry Mode ------------- 0b000001xx
#define LCD_SET_ENTRY           0x04
 
#define LCD_ENTRY_DECREASE      0x00
#define LCD_ENTRY_INCREASE      0x02
#define LCD_ENTRY_NOSHIFT       0x00
#define LCD_ENTRY_SHIFT         0x01
 
// Set Display ---------------- 0b00001xxx
#define LCD_SET_DISPLAY         0x08
 
#define LCD_DISPLAY_OFF         0x00
#define LCD_DISPLAY_ON          0x04
#define LCD_CURSOR_OFF          0x00
#define LCD_CURSOR_ON           0x02
#define LCD_BLINKING_OFF        0x00
#define LCD_BLINKING_ON         0x01
 
// Set Shift ------------------ 0b0001xxxx
#define LCD_SET_SHIFT           0x10
 
#define LCD_CURSOR_MOVE         0x00
#define LCD_DISPLAY_SHIFT       0x08
#define LCD_SHIFT_LEFT          0x00
#define LCD_SHIFT_RIGHT         0x04
 
// Set Function --------------- 0b001xxxxx
#define LCD_SET_FUNCTION        0x20
 
#define LCD_FUNCTION_4BIT       0x00
#define LCD_FUNCTION_8BIT       0x10
#define LCD_FUNCTION_1LINE      0x00
#define LCD_FUNCTION_2LINE      0x08
#define LCD_FUNCTION_5X7        0x00
#define LCD_FUNCTION_5X10       0x04
 
#define LCD_SOFT_RESET          0x30
 
// Set CG RAM Address --------- 0b01xxxxxx  (Character Generator RAM)
#define LCD_SET_CGADR           0x40
 
#define LCD_GC_CHAR0            0
#define LCD_GC_CHAR1            1
#define LCD_GC_CHAR2            2
#define LCD_GC_CHAR3            3
#define LCD_GC_CHAR4            4
#define LCD_GC_CHAR5            5
#define LCD_GC_CHAR6            6
#define LCD_GC_CHAR7            7
 
// Set DD RAM Address --------- 0b1xxxxxxx  (Display Data RAM)
#define LCD_SET_DDADR           0x80
 
#endif 
Hier die lcd-routines.c:
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
// http://www.mikrocontroller.net/articles/HD44780
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
//
// Die Pinbelegung ist über defines in lcd-routines.h einstellbar
 
#include <avr/io.h>
#include "lcd-routines.h"
#include <util/delay.h>
 
////////////////////////////////////////////////////////////////////////////////
// Erzeugt einen Enable-Puls
static void lcd_enable( void )
{
    LCD_PORT |= (1<<LCD_EN);     // Enable auf 1 setzen
    _delay_us( LCD_ENABLE_US );  // kurze Pause
    LCD_PORT &= ~(1<<LCD_EN);    // Enable auf 0 setzen
}
 
////////////////////////////////////////////////////////////////////////////////
// Sendet eine 4-bit Ausgabeoperation an das LCD
static void lcd_out( uint8_t data )
{
    data &= 0xF0;                       // obere 4 Bit maskieren
 
    LCD_PORT &= ~(0xF0>>(4-LCD_DB));    // Maske löschen
    LCD_PORT |= (data>>(4-LCD_DB));     // Bits setzen
    lcd_enable();
}
 
////////////////////////////////////////////////////////////////////////////////
// Initialisierung: muss ganz am Anfang des Programms aufgerufen werden.
void lcd_init( void )
{
    // verwendete Pins auf Ausgang schalten
    uint8_t pins = (0x0F << LCD_DB) |           // 4 Datenleitungen
                   (1<<LCD_RS) |                // R/S Leitung
                   (1<<LCD_EN);                 // Enable Leitung
    LCD_DDR |= pins;
 
    // initial alle Ausgänge auf Null
    LCD_PORT &= ~pins;
 
    // warten auf die Bereitschaft des LCD
    _delay_ms( LCD_BOOTUP_MS );
    
    // Soft-Reset muss 3mal hintereinander gesendet werden zur Initialisierung
    lcd_out( LCD_SOFT_RESET );
    _delay_ms( LCD_SOFT_RESET_MS1 );
 
    lcd_enable();
    _delay_ms( LCD_SOFT_RESET_MS2 );
 
    lcd_enable();
    _delay_ms( LCD_SOFT_RESET_MS3 );
 
    // 4-bit Modus aktivieren 
    lcd_out( LCD_SET_FUNCTION |
             LCD_FUNCTION_4BIT );
    _delay_ms( LCD_SET_4BITMODE_MS );
 
    // 4-bit Modus / 2 Zeilen / 5x7
    lcd_command( LCD_SET_FUNCTION |
                 LCD_FUNCTION_4BIT |
                 LCD_FUNCTION_2LINE |
                 LCD_FUNCTION_5X7 );
 
    // Display ein / Cursor aus / Blinken aus
    lcd_command( LCD_SET_DISPLAY |
                 LCD_DISPLAY_ON |
                 LCD_CURSOR_OFF |
                 LCD_BLINKING_OFF); 
 
    // Cursor inkrement / kein Scrollen
    lcd_command( LCD_SET_ENTRY |
                 LCD_ENTRY_INCREASE |
                 LCD_ENTRY_NOSHIFT );
 
    lcd_clear();
}
  
////////////////////////////////////////////////////////////////////////////////
// Sendet ein Datenbyte an das LCD
void lcd_data( uint8_t data )
{
    LCD_PORT |= (1<<LCD_RS);    // RS auf 1 setzen
 
    lcd_out( data );            // zuerst die oberen, 
    lcd_out( data<<4 );         // dann die unteren 4 Bit senden
 
    _delay_us( LCD_WRITEDATA_US );
}
 
////////////////////////////////////////////////////////////////////////////////
// Sendet einen Befehl an das LCD
void lcd_command( uint8_t data )
{
    LCD_PORT &= ~(1<<LCD_RS);    // RS auf 0 setzen
 
    lcd_out( data );             // zuerst die oberen, 
    lcd_out( data<<4 );           // dann die unteren 4 Bit senden
 
    _delay_us( LCD_COMMAND_US );
}
 
////////////////////////////////////////////////////////////////////////////////
// Sendet den Befehl zur Löschung des Displays
void lcd_clear( void )
{
    lcd_command( LCD_CLEAR_DISPLAY );
    _delay_ms( LCD_CLEAR_DISPLAY_MS );
}
 
////////////////////////////////////////////////////////////////////////////////
// Sendet den Befehl: Cursor Home
void lcd_home( void )
{
    lcd_command( LCD_CURSOR_HOME );
    _delay_ms( LCD_CURSOR_HOME_MS );
}
 
////////////////////////////////////////////////////////////////////////////////
// Setzt den Cursor in Spalte x (0..15) Zeile y (1..4) 
 
void lcd_setcursor( uint8_t x, uint8_t y )
{
    uint8_t data;
 
    switch (y)
    {
        case 1:    // 1. Zeile
            data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
            break;
 
        case 2:    // 2. Zeile
            data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
            break;
 
        case 3:    // 3. Zeile
            data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
            break;
 
        case 4:    // 4. Zeile
            data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
            break;
 
        default:
            return;                                   // für den Fall einer falschen Zeile
    }
 
    lcd_command( data );
}
 
////////////////////////////////////////////////////////////////////////////////
// Schreibt einen String auf das LCD
 
void lcd_string( const char *data )
{
    while( *data != '\0' )
        lcd_data( *data++ );
}
 
////////////////////////////////////////////////////////////////////////////////
// Schreibt ein Zeichen in den Character Generator RAM
 
void lcd_generatechar( uint8_t code, const uint8_t *data )
{
    // Startposition des Zeichens einstellen
    lcd_command( LCD_SET_CGADR | (code<<3) );
 
    // Bitmuster übertragen
    for ( uint8_t i=0; i<8; i++ )
    {
        lcd_data( data[i] );
    }
}
Und hier das Programm:
/*
 * LCD_Test.c
 *
 * Created: 14.07.2011 08:08:53
 *  Author: Dennis
 */ 
#include <avr/io.h>
#include <avr/delay.h>
#include "lcd-routines.h"
 
int main(void)
{
  // Initialisierung des LCD
  // Nach der Initialisierung müssen auf dem LCD vorhandene schwarze Balken
  // verschwunden sein
  lcd_init();
    // Text in einzelnen Zeichen ausgeben
  lcd_data( 'T' );
  lcd_data( 'e' );
  lcd_data( 's' );
  lcd_data( 't' );
 
  // Die Ausgabemarke in die 2te Zeile setzen
  lcd_setcursor( 0, 2 );
 
  // erneut Text ausgeben, aber diesmal komfortabler als String
  lcd_string("Hello World!");
  
  while(1)
  {
  }
 
  return 0;
}
Allerdings hat der Code (mit dem AVR-Studio 5 compiliert) eine Größe von 7036 Byte. Das kann doch nicht sein oder? Da is mein kleiner Mega8 ja schon voll. Kann es sein das er beim brennen der .hex Datei die .h und die .c der Lib auch auf den AVR schreibt?
Nun werde ich das ganze noch einmal mit dem RN-Mega8-plus Board und dem myavr-LCD ausprobieren, vielleicht ist ja doch nur ein Port kaputt.
Gruß
Dennis
radbruch
15.07.2011, 12:55
Allerdings hat der Code (mit dem AVR-Studio 5 compiliert) eine Größe von 7036 Byte.Dann machst du irgendetwas falsch:
19334
Kompiliert mit WinAVR-20100110.
delay.h befindet sich jetzt in util/
cantforget
15.07.2011, 13:20
Hallo,
aha danke dir Radbruch, ich habe den Fehler gefunden. 
Im AVR-Studio 5 kann man im "Solution Explorer" bei "Solution 'Dateiname'" rechts klicken, danach wählt man den "Configuration Manager" an und stellt bei "Configuration" satt "Debug" "Release" ein. Danach hat mein Programm nun 486 Bytes. Wo allerdings der Unterschied zu deiner Größe kommt, kann ich mir nicht erklären.
Kompiliert mit WinAVR-20100110.
delay.h befindet sich jetzt in util/ Bei mir ging es erst nicht im util/, aber nun geht es seltsamer weise.
Sag mal Radbruch hast du eine Idee wie ich mein oben beschriebenes LCD mit der Lib die ich gepostet habe zum laufen bekomme?
Gruß
Dennis
radbruch
15.07.2011, 13:29
$crystal = 7372800 
...
#ifndef F_CPU
#define F_CPU 3686400
#endif
? Bei falscher Taktfrequenz stimmt das Timeing durch delay.h nicht mehr. Ich muss mich erst mal einlesen (und die Datenblätter suchen) ...
P.S.: Schwäbisch sparsam kompiliert ;)
Hubert.G
15.07.2011, 13:30
Ich arbeite immer mit der Lib von P.Fleury, in der kann man den KS0073 einstellen. Es gibt da in der Init einen unterschied.
cantforget
15.07.2011, 13:49
Hallo,
also Radbruch ist nett von dir wenn du das für mich machst. Also der code sollte im Projekt schon in C geschrieben werden, also ich meinte das im Obersten Post beschriebene LCD und die Lib's aus Post nummer 7. Bei der Taktfrequenz sehe ich auch gerade da habe ich wohl was vertauscht, weil ich 2 Boards hier liegen habe. Die richtige ist 7372800 Hz. 
Das Problem war halt, das ich das 20*4 LCD nicht mit dem RN-MEGA8-plus Board betreiben kann. Die Ports habe ich die von der Display-Buchse genommen.
Und Hubert.G hast du auch schon mit meinem LCD gearbeitet? Denn ich hatte es zuerst mit der Fleury lib probiert, allerdings kam ich damit auch nicht zu einer funktionierenden Lösung. >Ich sehe gerade, dass es ein paar änderungen in der lib gab, werde mir das später aber nocheinmal genauer ansehen. 
Gruß
Dennis
Hubert.G
15.07.2011, 15:01
Mit deinem speziellen LCD habe ich noch nicht gearbeitet. Allerdings mit LCDs mit einem KS0073, diese haben nur mit der Einstellung für diesen Kontrollertyp funktioniert.
cantforget
15.07.2011, 16:54
Hallo,
@Hubert.G:
So habe die lib nun mal umgeschrieben bin mir aber mit der Adressierung unsicher könntest du mal schauen ob die richtig ist?
#define LCD_LINES           4     /**< number of visible lines of the display */
#define LCD_DISP_LENGTH    20     /**< visibles characters per line of the display */
#define LCD_LINE_LENGTH  0x20     /**< internal line length of the display    */
#define LCD_START_LINE1  0x00     /**< DDRAM address of first char of line 1 */
#define LCD_START_LINE2  0x40     /**< DDRAM address of first char of line 2 */
#define LCD_START_LINE3  0x10     /**< DDRAM address of first char of line 3 */
#define LCD_START_LINE4  0x60     /**< DDRAM address of first char of line 4 */
#define LCD_WRAP_LINES      0     /**< 0: no wrap, 1: wrap at end of visibile line */
Das ist dieses LCD:
http://www.robotikhardware.de/download/eadip204_datenblatt.pdf
Ich hoffe mal ich bekomme das irgendwie nochmal hin. Finde das schon nicht so einfach ein LCD einzubinden.
Gruß
Dennis
Hubert.G
15.07.2011, 23:10
Die Startadressen der Zeilen sind für den Anfang nicht so wichtig, da hast du vielleicht verschobenen Text.
Viel wichtiger ist ob die Initialisierung funktioniert.
radbruch
16.07.2011, 12:48
Hallo
Ich habe nun die Datenblätter des RNMega8Plus und des RN-LCD-Adapters angeschaut und die Pinbelegungen der Steckverbindungen überprüft:
// Pinout LCD Display-Anschluß nach Roboternetznorm RN-LCD-Adapter
// Pin 1   LCD DB7
// Pin 2   LCD DB6
// Pin 3   LCD DB5
// Pin 4   LCD DB4
// Pin 5   Licht ein/aus per Port (da EN2 hier nicht benötigt wird)
// Pin 6   LCD EN
// Pin 7   LCD R/W
// Pin 8   LCD RS
// Pin 9   GND             LCD GND und Licht Kathode
// Pin 10  +5V             LCD VCC und Licht Anode//  LCD DB4-DB7 <-->  PORTD Bit PD0-PD3
// Pinout LCD Display-Anschluß nach Roboternetznorm RNMEGA8PLUS
// Pin 1 DB7   PD5
// Pin 2 DB6   PD4
// Pin 3 DB5   PD3
// Pin 4 DB4   PD2
// Pin 5 EN2   PD7  (wird nur bei manchen LCDs benötigt)
// Pin 6 EN    PC3
// Pin 7 R/W   PD6
// Pin 8 RS    PC2
// Pin 9 GND
// Pin 10 +5V
#define LCD_PORT      PORTD
#define LCD_DDR       DDRD
#define LCD_DB        PD4
//  LCD RS      <-->  PORTD Bit PD4     (RS: 0=Data, 1=Command)
#define LCD_RS        PD2
//  LCD EN      <-->  PORTD Bit PD5     (EN: 1-Impuls für Daten)
#define LCD_EN        PD3
Oben: Belegung des RN-LCD-Adapters. Laut Schaltplan stimmt auch die Verbindung zu den 2x9 Pins des aufsteckbaren LCD.
Mitte: Belegung des LCD-Ports auf dem RNMega8Plus. Stimmt mit der Abschluß am Adapter überein bis auf E2
Unten: Die Defines in lcd-routines.h passen nicht zu der Belegung vom RNMega8Plus!!!
Außerdem wird der R/W-Pin nicht definiert. Da beim Schreiben das Busy nicht geprüft wird und auch keine lesenden Funktionen vorhanden sind gehe ich davon aus, dass die Lib davon ausgeht, dass R/W low ist (Brücke zu GND. Ohne Brücke ist auch die jumperbare Verbindung der freien D0 bis D3 zu GND kritisch!).
Gruß
mic
http://www.robotikhardware.de/download/rnmega8plus.pdf
http://www.robotikhardware.de/download/rn_LCD_adapter.pdf
[Edit]
// Pinout LCD Display-Anschluß nach Roboternetznorm RNMEGA8PLUS
// Pin 1 DB7   PD5
// Pin 2 DB6   PD4
// Pin 3 DB5   PD3
// Pin 4 DB4   PD2
// Pin 5 EN2   PD7  (wird nur bei manchen LCDs benötigt)
// Pin 6 EN    PC3
// Pin 7 R/W   PD6
// Pin 8 RS    PC2
// Pin 9 GND
// Pin 10 +5V
// Defines der Ports des RNMega8Plus für die LCD-Lib von Peter Fleury (http://www.jump.to/fleury)
// R/W geht auf PD6!
#define LCD_PORT         PORTD        /**< port for the LCD lines   */
#define LCD_DATA0_PORT   LCD_PORT     /**< port for 4bit data bit 0 */
#define LCD_DATA1_PORT   LCD_PORT     /**< port for 4bit data bit 1 */
#define LCD_DATA2_PORT   LCD_PORT     /**< port for 4bit data bit 2 */
#define LCD_DATA3_PORT   LCD_PORT     /**< port for 4bit data bit 3 */
#define LCD_DATA0_PIN    2            /**< pin for 4bit data bit 0  */
#define LCD_DATA1_PIN    3            /**< pin for 4bit data bit 1  */
#define LCD_DATA2_PIN    4            /**< pin for 4bit data bit 2  */
#define LCD_DATA3_PIN    5            /**< pin for 4bit data bit 3  */
#define LCD_RS_PORT      PORTC	     /**< port for RS line         */
#define LCD_RS_PIN       2            /**< pin  for RS line         */
#define LCD_RW_PORT      PORTD	     /**< port for RW line         */
#define LCD_RW_PIN       6            /**< pin  for RW line         */
#define LCD_E_PORT       PORTC	     /**< port for Enable line     */
#define LCD_E_PIN        3            /**< pin  for Enable line     */
cantforget
19.07.2011, 08:40
Hallo,
entschuldigt bitte, dass ich so lange nicht geantwortet habe. Es kam leider wie immer wenn man basteln will etwas dazwischen. Danke für die Mühe des Vergleichs radbruch, verstehe ich das richtig, dass ich in der .h die Data_Pins 0 bis 3 in 4 bis 7 ändern muss und dem entsprechend auch die Pins in der .c Datei? Wenn ja wäre das ein ziemlicher Aufwand.
Gruß
Dennis
radbruch
19.07.2011, 09:18
Hallo
Du brauchst nur die Defines in der Headerdatei (.h) ändern bzw. anpassen. Später werden die Pins nur über die Defines angesprochen und die Anpassung wird so automatisch überall im Programm wirksam.
Die (ungetestete) Anpassung an die Lib von Peter Fleury habe ich oben ja schon gepostet. Diese Lib würde ich bevorzugen, weil sie die bei deiner Beschaltung vorhandene R/W-Leitung verwendet und deshalb das Busy-Signal des LCD auswerten kann.
Gruß
mic
 
Powered by vBulletin® Version 4.2.5 Copyright ©2025 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.