PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : LC-Display am RN-Control mit C ansteuern



cumi
05.04.2006, 15:59
Hallo Zusammen

Ich krieg es einfach nicht hin, mein LCD anzusteuern. Überall wird geschrieben, dass sei eigentlich nicht so ein Problem, aber bei mir klappts nicht :(

Also das Ganze sieht so aus: Ich habe ein 4x20Zeichen Display. Also 4 Zeilen mit je 20 Zeichen.
Das Datenblatt könnt ihr hier (http://www.shop.robotikhardware.de/shop/catalog/product_info.php?cPath=66&products_id=80) herunterladen.
Ich möchte es im 8-Bit Modus ansteuern. Dann brauche ich das Byte nicht zu zerlegen und für den Moment habe ich genug Ports.
Ich habe das Display folgendermassen mit dem RN-Control verkabelt:
RS auf PORTB, Pin 0
R/W habe ich, da ich nur schreiben möchte auf VSS gelegt (richtig so, oder?)
E auf PORTB, Pin 2
D0-D7 auf PORTC
Dazu erstmal eine Frage. Funktioniert das rein elektronisch? Oder funkt mir da noch irgendwas vom RN-Control rein? Den Motortreiber habe ich entfernt, und alle Jumper rausgezogen.

Mein Code sieht so aus:

b_setH und b_setL ist eine Präprozessordirektiven um ein Bit in einem Byte Hight bzw. Low zu setzten.

Konfiguriert wird das Ding im Haederfile:
m32_lcd.h

#ifndef M32_LCD_H_
#define M32_LCD_H_

// general ---------------------------------------------------------------------
#ifndef F_CPU
#define F_CPU 16000000
#endif

// LCD -------------------------------------------------------------------------
#define CONT_DDR DDRB
#define CONT_PORT PORTB
#define CONT_E 2 // Enable (fallende Flanke)
#define CONT_RS 0 // L:Befehl / H:Daten
#define CONT_RW 1 // H:Read / L:Write
#define DATA_DDR DDRC
#define DATA_PORT PORTC

// EOF -------------------------------------------------------------------------
#endif /*M32_LCD_H_*/


Und hier die Source:
m32_lcd.c

#include <avr/io.h>
#include "m32_lcd.h"
#include "bit.h"

// delay -----------------------------------------------------------------------
void _delay_loop_1(uint8_t __count)
{
__asm__ volatile (
"1: dec %0" "\n\t"
"brne 1b"
: "=r" (__count)
: "0" (__count)
);
}

void _delay_loop_2(uint16_t __count)
{
__asm__ volatile (
"1: sbiw %0,1" "\n\t"
"brne 1b"
: "=w" (__count)
: "0" (__count)
);
}

void _delay_us(double __us)//max: 768us / F_CPU in Mhz
{
uint8_t __ticks;
double __tmp = ((F_CPU) / 3e6) * __us;
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 255)
__ticks = 0; // i.e. 256
else
__ticks = (uint8_t)__tmp;
_delay_loop_1(__ticks);
}

void _delay_ms(double __ms) //max: 260ms / F_CPU in Mhz
{
uint16_t __ticks;
double __tmp = ((F_CPU) / 4e3) * __ms;
if (__tmp < 1.0)
__ticks = 1;
else if (__tmp > 65535)
__ticks = 0; // i.e. 65536
else
__ticks = (uint16_t)__tmp;
_delay_loop_2(__ticks);
}

// testing ---------------------------------------------------------------------
void init(void)
{
b_setH(CONT_DDR,CONT_E);
b_setH(CONT_DDR,CONT_RS);
// b_setH(CONT_DDR,CONT_RW);

b_setL(CONT_PORT,CONT_E); // E nicht setzen
b_setL(CONT_PORT,CONT_RS); // RS nicht setzen
// b_setL(CONT_PORT,CONT_RW); // RW nicht setzen
DATA_DDR = 0xff; // Ausgänge
DATA_PORT= 0x00;
}

// lcd -------------------------------------------------------------------------
void lcd_send(uint8_t data, uint8_t rs) //rs: L:Befehl / H:Daten
{
DATA_PORT = data;
if(rs)
b_setH(CONT_PORT,CONT_RS);
else
b_setL(CONT_PORT,CONT_RS);
_delay_us(45); // kurze Verzögerung, wahrscheinlich überflüssig
b_setH(CONT_PORT,CONT_E);
_delay_us(45);
b_setL(CONT_PORT,CONT_E);

_delay_ms(10); // um Befehl auszuführen, wahrscheinlch viel zu lang
}

void lcd_init(void){
lcd_send(0x34,0); // 8-Bit Datenlänge
lcd_send(0x09,0); // 4 Zeilen Modus
lcd_send(0x0F,0); // Display on, Cursor on, Blink on
lcd_send(0x01,0); // Display löschen, Cursor 1. Spalte, 1. Zeile;
}

void lcd_writeC(uint8_t c, uint8_t z, uint8_t s) //c: char, z: Zeile., s: Spalte
{
lcd_send(c,1);
}

// testing ---------------------------------------------------------------------
int main(void)
{
init();
lcd_init();

lcd_send('a',1);

return 0;
}


Für die, die es noch intressiert, die bit.h


#ifndef BIT_H_
#define BIT_H_

// bit.h -----------------------------------------------------------------------
// n ist immer die Bit-Position von Rechts gezählt im Intervall [0..7]
#define b_maske(n) (1 << n) // generiert Make mit 1 bei n
#define b_ifset(b,n) (b & (1 << n) // liefert true wenn n true, sonst false
#define b_setH(b,n) b |= (1 << n) // setzt n auf 1
#define b_setL(b,n) b &= ~(1 << n) // setzt n auf 0
#define b_inv(b,n) b ^= (1 << n) // invertiert n (1->0, 0->1)

// setzt r auf a jedoch mit dem bit n von b als bit n von r
#define b_qset(a,b,n) (a = (b & (1 << n)) | (a & ~(1 << n))) //n = k
// setzt r auf a jedoch mit dem bit k von b als das bit n von r
#define b_qsetL(a,b,n,k) ((b << (n-k)) & (1 << n)) | (a & ~(1 << n)) // n > k
#define b_qsetR(a,b,n,k) ((b >> (k-n)) & (1 << n)) | (a & ~(1 << n)) // k > n

// rotiert a um ein bit
#define b_rotL(a) b_qsetR((a << 1),a,0,7)
#define b_rotR(a) b_qsetL((a >> 1),a,7,0)

// EOF -------------------------------------------------------------------------
#endif /*BIT_H_*/


Die delay-Funktionen habe ich aus der AVR-Lib-C kopiert.
Die Initialisierung habe ich aus dem Datenblatt des Displays abgeschrieben, ich hoffe die stimmt.

Leider sehe ich auf dem Display überhautp nichts. An der Kontrastspannung liget es nicht, das habe ich überprüft.
Hat jemand eine Idee, wieso, dass das nicht funktioniert?

Vielen Dank für eure Hilfe!

Grüsse cumi[/b]

SprinterSB
05.04.2006, 16:38
Schon mal versucht, nach dem Reset nen delay einzubauen, um dem LCD Zeit für den Startup zu geben? 100ms oder so.

Zum Code:
-- die double-Arithmetik ist überflüssig und dafür _viel_ zu aufwändig und teuer
-- Verwendung von b_ifset wird dir einen Compile-Fehler bringen
-- warum kopierst du Funktionen aus der lib??? Die bekommst du mit #include <avr/delay.h> Die stehen auch nicht in einer Lib, sonder sind als static inline implementiert.

cumi
05.04.2006, 16:50
Vielen Dank für deine Antwort, Sprinter!

Wann soll ich genau Zeit geben? Bevor ich irgendetwas tue? Da hat das Display eine ewigkeit Zeit, denn es hat schon lange vor ich irgendetwas schreibe Strom.
Ich jetzt einmal nach der Initialisierung ein delay reingehauen, bringt aber leider nichits.

Zum delay. Ich habe einfach nach einem schlauen delay gesucht. Natürlich kann ich die Funktionen direkt aus der Library nehmen, nur sehe ich dann nicht, wa ich genau compiliere. Wie implementiert man ein simpleres, delay, für diesen Zweck?

b_ifset habe ich korrigiert. Du meinst schon die Klammer, oder?

SprinterSB
05.04.2006, 17:17
Achso, ich dachte, µC und LCD werden gleichzeitig eingeschaltet... Dann sollte man den µC erst etwas warten lassen vor dem lcd_init().

ich hab mal in meine Sende-Routine geschaut. Ein Byte bzw. Nibble seinden:

E=0
DDR_DATA=OUT
RW=0
RS=rs
PORT_DATA=data
E=1
WAIT
E=0
DDR_DATA=OUT

Das DDR umschalten brauchst du wohl nicht (bei mir gehen noch andere Sachen auf dem Bus ab). Das WAIT ist ein _delay_loop_1(100).
Die Ansteuerung ist für ein VFD, sollte aber für ein LCD genauso gehen.

Fast in jeder Anwendung wird man eine Zeitbasis brauchen, die Ticks in einem bestimmten Zeitraster macht. Damit ist ein wait() dann recht einfach zu realisieren. Oder man nimmt einen freien Timer und zieht den auf und wartet, bis er abgelaufen ist. Das leidige Taktezählen fänd ich viel zu nervig und ungenau ist's nebenbei auch, insbesonders bei hoher IRQ-Last, denn die IRQ-Zyklen werden ja nicht mitgezählt in den Zählschleifen.


Ja da fehlte ne )

cumi
05.04.2006, 22:54
danke für dein antwort!
Ich werde morgen das mit dem wait noch anpassen.
Aber wenn ich das sonst so anschaue, dann man ich doch ziemlich alles gleich, oder? Also wirklich einen Fehler finde ich nicht.

Was mich noch intressieren würde ist, wie man Zeichen genau schreibt. Also so wie ich das bis jetzt verstanden habe, brauche ich einfach die DD RAM Adresse dorthin zu setzen (Mit dem DD RAM Adress Set Befehl), wo ich hinschreiben will und dann ein data-byte mit dem gewünschten Zeichen zu senden. Der Rest (also das anzeigen auf dem Display) muss ich nicht noch speziell auslösen, oder?

cumi

SprinterSB
06.04.2006, 08:20
Das müsste eigentlich in deinem Datenblatt stehen.
Ich kenn es von den HD44-kompatiblen, das man nur schreiben muss. Je nach Einstellungen rutscht dann auch Cursor etc mit.

tschensen
06.04.2006, 08:44
Was hast du mit dem Restet Pin gemacht?

cumi
06.04.2006, 10:37
@Sprinter: Hmm, das Datenblatt, welches ich habe ist ziemlich mager. Aber ich finde sicher eins vom HD44780, zu dem soll der von meinem LCD kompatibel sein.

@tschensen: Der Resetping liegt doch auf keinem benützen Pin. Der habe ich natürlich nicht gezogen. Das der Controller läuft weiss ich. Ich lass eine LED blinken...

tschensen
06.04.2006, 13:22
Ist das Datenblatt ausführlicher?
http://www.lcd-module.de/eng/pdf/zubehoer/ks0073.pdf

tschensen
06.04.2006, 13:54
Ich hock auch garade vor nem ähnlichen Display (DIP204-6) und bekomme es auch nicht zum laufen. Bekommst du schwarze Kästen auf dein Bildschirm, wenn du das Display einschaltest?

fwallenwein
06.04.2006, 14:20
Ich hock auch garade vor nem ähnlichen Display (DIP204-6) und bekomme es auch nicht zum laufen.

Wenn Du interesse daran hast das Display im seriellen Modus zu betreiben.
( als nur mit 2 Leitungen ), dann kannst Du hier einen Treiber finden.
http://www.tklinux.de/ks0073.html
Ich verwende das Display nur noch im seriellen Modus - wie gesagt, braucht nur 2 Leitungen und ist auch schnell genug. Man muss nur auf dem Display eine Brücke umlöten.
Die Software ist zwar ein Treiber für NutOS - aber die relevanten Teile kannst Du Dir ja rausholen. Ansonsten kann ich auch einen Treiber für "Nur AVR" ohne den NutOS Teil mailen.
Benutzung des Displays - siehe http://www.gadgetpool.de -> SeaTalk Nmea Bridge

Gruss
Frank

tschensen
06.04.2006, 15:22
Das wäre schon eine gute Sache, ich möchte aber zuerst einmal das Diusplay so zum laufen bekommen. Im Moment sehe ich ja nicht einmal die schwarzen, bzw im meinem Fall weißen Balken, die man nach dem einschalten eigentlich sehen müsste.
Jemand ne Idee woran es liegen könnte?
Der Kontrast ist wie im Datenblatt beschrieben angeschlossen

cumi
06.04.2006, 21:34
Danke fwallenwein für deinen Link. Doch ehrlichgesgat geht es mir gleich wie tschensen. Ich möchte das Disply einfach einmal im 8Bit Modus zum laufen bekommen.
@tschensen: Ich kriege nur weiss. Ausser ich stelle den Kontrast brutal hoch, dann wird es natürlich auch schwarz. Aber das Display will weiss anzeigen :)
Das Datenblatt ist viel ausführlicher! Danke. Ich schau morgen einmal rein.

tschensen
18.04.2006, 19:00
Hey Cumi,
wie siehts denn eigentlich bei dir aus, hastes zum laufen bekommen? Wenn ja, woran lag es bei dir?

cumi
18.04.2006, 19:11
nein, bei mir läuft immernoch nicht, was auch nicht so verwunderlich ist, da ich es noch nicht weiter versucht habe.
Ich werde es mir nächsten Wochenende wahrscheinlich nochmals anschauen und schreibe auf jedenfall, wenns klappt.