PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : LCD will nicht



millioneer
04.01.2005, 20:59
Hallo,

ich wollte gern ein 16x2 LCD-Display mit meinem ATTiny26 im 8bit-Modus ansteuern. Der Tiny26 hat zwei 8bit-Ports, PORTA verwende ich für den Datenbus, die drei Steuerbits kommen vom PORTB. Taktung ist 16 Mhz.

Das Problem ist nur, mit dem LCD passiert rein garnichts, nicht mal ein zucken.
Ich hab schon zwei verschiedene LCD's ausprobiert ein 16x2 und ein 40x4, beide von Reichelt.
Das 40x4 wird komplett dunkel, das 16x2 bleibt komplett hell. An einem gekauften Mega8-Board funktionieren aber beide.

Laut Datenblatt vom HD44780 muss man eine Initialisierung machen, das hab ich aber schon in den verschiedensten Varianten probiert, null Ergebnis.
Es gibt eine Initialisierung für den Problemfall, daß der Power-On Fehlschlug und der normale Init, falls man nur paar Einstellungen ändern will, beides aber ohne Reaktion.

Im Internet findet man ein ganze Menge von derartigen Schaltungen, aber ich kann kein entscheidenen Unterschied entdecken.


Habt ihr vielleicht schonmal ein LCD angeschlossen und da ähnliche Probleme gehabt und eine Lösung gefunden???



Hier mal mein Quellcode für WinAVR (gcc):


#include <avr/io.h>
#include <avr/delay.h>

// Steuerbits bei PortB
#define LCD_RS 3 //Pin für RS
#define LCD_RW 6 //Pin für Read/Write
#define LCD_E 1 //Pin für Enable

#define wait500ns _delay_loop_1(3)
#define wait1us _delay_loop_1(5)

void avr_init(void);
void LCD_Clear (void);
void LCD_Command (char Data);
void LCD_Data (char Data);
void LCD_Init (void);

void waitms(char ms);
void waitms2(int ms);
void waitus(char us);
void waitus2(int us);

int main(void)
{

avr_init();
LCD_Init();

while(1)
{
LCD_Clear();

waitms2(1000);

LCD_Data('a');
LCD_Data('b');
LCD_Data('c');

waitms2(1000);
}

return 0;
}



void avr_init(void)
{
// Initialize device here.

DDRB = 255;
PORTB=0;

DDRA = 255;
PORTA=0;
}

void LCD_Clear (void)
{
LCD_Command (1); //Clear Display
waitms(160);
LCD_Command (0x80); //Set DD-Ram Adresse = 0
}

void LCD_Command (char Data)
{
cbi(PORTB,LCD_RS); //RS = 0 Steuerregister
cbi(PORTB,LCD_RW); //Zum Schreiben RW-Pin = Low

sbi(PORTB,LCD_E);
PORTA = Data;
wait500ns;
cbi(PORTB,LCD_E);
wait500ns;

waitus(50);
}

void LCD_Data (char Data)
{
sbi(PORTB,LCD_RS); //RS = 1 Datenregister
cbi(PORTB,LCD_RW); //Zum Schreiben RW-Pin = Low

sbi(PORTB,LCD_E);
PORTA = Data;
wait500ns;
cbi(PORTB,LCD_E);
wait500ns;

waitus(50);
}

void LCD_Init (void)
{
waitms2(30);


// --- Variante 1 ---
/*LCD_Command (0%00110000); // init
waitms2(5);

LCD_Command (0%00110000); // init
waitus2(150);

LCD_Command (0%00110000); // init
waitms2(5);

// -----------
LCD_Command (0%00111000); // init
waitus2(150);

LCD_Command (0%00001000); // display off
waitus2(150);

LCD_Command (0%00000001); // display clear
waitus2(150);

LCD_Command (0%00000110); // increment cursor
waitus(150);

// -----------
LCD_Command (0%00001111); // disp on, curs on, blink on
waitus2(150);

LCD_Command (0%10000000); //Set DD-Ram Adresse = 0
waitus2(150);*/

// --- Variante 2 ---
LCD_Command(0%00111000); // 8bit, 2line
LCD_Command(0%00001111); // disp on, curs on, blink on
LCD_Command(0%00000001); // clear
waitms(160);
LCD_Command(0%00000110); // increment cursor

// --- Variante 3 ---
/*LCD_Command(0%00110100);
LCD_Command(0%00001001);
LCD_Command(0%00110000);
LCD_Command(0%00001111);
LCD_Command(0%00000001);
waitms(160);
LCD_Command(0%00000110);*/
}



void waitms(char ms)
{
for (;ms>0;ms--)
{
_delay_loop_2(4000); // 1 = 4 cycles
}
}

void waitms2(int ms)
{
for (;ms>0;ms--)
{
_delay_loop_2(4000); // 1 = 4 cycles
}
}

void waitus(char us)
{
for (;us>0;us--)
{
_delay_loop_1(4); // 1 = 4 cycles
}
}

void waitus2(int us)
{
for (;us>0;us--)
{
_delay_loop_1(4); // 1 = 4 cycles -> 16 cycles
}
}

lorcan
04.01.2005, 22:56
Tja, wenn ich mir Deine Definitionen für die Steuerbits so ansehe, fällt mir auf, dass Du einfache die Pin-Nummern genommen hast, sehe ich das richtig? Das funktioniert aber nicht! Für LCD_E klappt es, das ist Pin 1,
für Pin 3(LCD_RS) musst Du 4 benutzen und für Pin 6(LCD_RW) 32.

Bei Deiner Definition aktiviert LCD_RS Pin 1 & 2, LCD_RW PIN 2 & 4 und LCD_E Pin 1.
(Ja ich weiß das die Pins eigentlich von 0 bis 7 gezählt werden :-s )

Du musst Dir die Ansteuerung so vorstellen: Der AVR schreibt einen 8-bittigen Wert ins Port-Register und dieser Wert wird binär ausgegeben.
Da bei hat jeder Pin einen festen Wert(1,2,4,6,8,16,32,64 & 128), ob der Wert eines Pins dazu gehört oder nicht wird durch eine logische 1 am Pin signalisiert, die dazugehörigen Werte werden dann addiert.
Beispiel: Es soll 100 ausgegeben werde
PIN 0 1 2 3 4 5 6 7
Wert 1 2 4 8 16 32 64 128
Log 0 0 1 0 0 1 1 0
ergibt: 4 + 32 + 64 = 100, die PINs 2, 5 und 6 füren eine logische 1.

Warum hast Du die Pins eigentlich so verteilt?

millioneer
05.01.2005, 11:44
Hallo lorcan,

upps, das muss ich heute gleich mal ausprobieren, wenn das der Fehler ist, dann... Schrei!

Die Pins verteile ich so, weil ich noch zwei Pins vom PORTB für I2C brauch und da will ich die dafür vorgesehenen Standard-Pins nehmen und zwei der PORTB-Pins sind für XTAL1+2 gedacht, die ich aber nun doch nicht brauch, weil ich den internen 16MhZ-PLL-Takt verwende.

Ich vermute bisher immer ein Problem mit der Taktung, aber die Taktlängen können wahrscheinlich lang sein wie sie wollen nur nicht zu kurz.

millioneer
05.01.2005, 18:15
@lorcan
Ja aber ich setzt die Bits doch mit der Funktion sbi(<PORT>,<Bit>) und cbi(<PORT>,<Bit>). Der Compiler macht da intern den passenden PORT-Befehl draus, indem er das gewünschte Bit soweit nach links schiebt bis die resultierende Bitmaske passt (1<<Bit) und OR-t das dann zu den bereits bestehenden PORT-Bits.
Das ist wohl nicht der Grund, die PINS leuchten nämlich auch korrekt mit einer angeschlossenen Leuchtdiode, hab ich mal im Slow-Mode durchprobiert.

@all
Ist der Tiny26 vielleicht anders als andere Chips?