Sida 1 av 2

Får inte fart på en OLED (HD44780), mikroC

Postat: 15 oktober 2008, 19:09:37
av Greve Hamilton
Hallå där.

Jag sitter och försöker få igång på en display, men det vill sig inte alls; det är bara svart.

Programmet körs på en PIC16F877A i 20MHz:

Kod: Markera allt

/*

    Display i 4-bit läge
    
    PORTD       LCD
    RD7   ->    D7
    RD6   ->    D6
    RD5   ->    D5
    RD4   ->    D4

    RD3   ->    E
    RD2   ->    RS

    WR på LCD är ansluten till GND.

*/

#define   E     PORTD.F3
#define   RS    PORTD.F2
#define   LEDG  PORTC.F7

void Lcd_Send4bit(char lcd_data) {
     E = 0;
     PORTD = (PORTD & 0x0F) | (lcd_data & 0xF0);      // Send upper nibble
     E = 1;
     delay_us(40);
     E = 0;
     PORTD = (PORTD & 0x0F) | (lcd_data << 4);        // Send lower nibble
     E = 1;
     delay_us(40);
}

void Lcd_Text(char ascii_) {
     RS = 1;                    // Send to LCD-DDRAM (Data)
     Lcd_Send4bit(ascii_);
}

void Init_Lcd() {

     delay_ms(40);            // Wait for LCD to power up

     RS = 0;                  // Instructions

     E = 0;
     PORTD = 0b00110000;      // 0x30
     E = 1;
     delay_ms(5);
     E = 0;
     PORTD = 0b00110000;      // 0x30
     E = 1;
     delay_us(100);
     E = 0;
     PORTD = 0b00110000;      // 0x30
     E = 1;
     delay_us(40);

     E = 0;
     PORTD = 0b00100000;      // set 4-bit
     E = 1;
     delay_us(40);

     Lcd_Send4bit(0b00101000);                       // 4-bit, 2 lines, 5x8

     Lcd_Send4bit(0b00010100);                       // Cursor move right

     Lcd_Send4bit(0b00001100);                       // LCD on, cursor/blink off

     Lcd_Send4bit(0b00000110);                       // Entry mode set

     Lcd_Send4bit(0b00000010);                       // Address=0 (return home)
     delay_ms(2);                                    // > 1.52 ms

     Lcd_Send4bit(0b00000001);                       // Clear display

     delay_ms(20);

}

void main () {

/* I/O Settings */

TRISA = 0b11111111;
TRISB = 0b11111111;
TRISC = 0b00010100;
TRISD = 0b00000001;
TRISE = 0b11111000;

PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
PORTE = 0x00;

Init_Lcd();

Lcd_Text(0b01000011);               // Print "C"

while (1) {
    LEDG = 1;                       // Fastnade inte i init, således.
}

}
Någon som vet vad som kan vara knas? Hårdvaran är OK, då LCD:n fungerar med ett annat program. På det fungerande programmet skrev jag inte rutinerna till LCD:n själv.

EDIT: Ändrade rubrik: LCD -> OLED.

/GH

Postat: 15 oktober 2008, 19:18:59
av sodjan
> det är bara svart.

Definiera "svart".
Är det en tvåraders ?
Fungerar kontrastjusteringen ?
Får du en grå och en blank rad ?

Postat: 15 oktober 2008, 22:06:16
av Greve Hamilton
Egentligen är det en OLED, därav mitt slarviga ordval, ber om ursäkt. Jag menar att det inte blir några tecken på displayen alls.

Tvåraders OLED med fungerande kontrast (eftersom den fungerar bra med en annan programkod).

Postat: 15 oktober 2008, 22:29:44
av sodjan
Aha, OLED, glöm mina frågor, speciellt den sista...

Postat: 15 oktober 2008, 22:51:56
av slatte
Kör du inte initieringen för 8-bitars interface ser ut som det, hade för mig att 4-bit interfacet skickade man.
0011
(delay 5ms)
0011
0011
.
.
.

Postat: 15 oktober 2008, 22:54:53
av sodjan
"0011" är ju samma sak som "0011xxxx" om man inte använder "xxxx"...

Och innan man växlar till 4-bit så är själva LCD'n i 8-bits mode, oavsett
om man har kopplat 4 eller 8 trådar till den.

Postat: 15 oktober 2008, 22:56:49
av Greve Hamilton
Slatte:

Men det blir väl samma sak eftersom D0-D3 på displayen är kopplade till GND och alltså kommer att tolkas som nollor de första gångerna fram tills att jag byter till 4-bit?

EDIT: SuperSodjan hann före.

Postat: 15 oktober 2008, 22:57:35
av slatte
inte helt hundra att jag hänger med men skickar inte han
0011
0000
0011
0000
0011
0000

EDIT: BAH BAH sry nu såg jag oki jag hänger med sry !!!
Läste något som inte fanns där ;-)

Postat: 15 oktober 2008, 23:10:27
av sodjan
> ...eftersom D0-D3 på displayen är kopplade till GND

Har går uppfattningen lite isär. Jag tror att man ska lämna de oanvända
datalinjerna på LCD'n öppna, de har interna pullups på själva LCD modulen.
Anledningen är att man kan råka sätta den i "read-mode", speciellt innan
processorn har startat upp riktigt, och då kommer LCD'n att försöka
driva alla 8 datalinjerna vilket ger en kortis till GND på 4 av dom.

Det stämmer även övrens om man googlar lite eller kollar ett (original)
datablad för HD44780...

Så, lämna de bara "öppna"...

Postat: 16 oktober 2008, 10:22:25
av BEEP
Har du kollat att alla fördröjningar är tillräckligt långa och rätt placerade?

Postat: 16 oktober 2008, 11:41:44
av Marta
Funktionen som skickar 4-bit till displayen sänker ju inte E efter att den lagt ut tecknet. Det är den negativa flanken som låser data.

Vad genererar compilern för kod på alla de logiska operationerna och skiften? Nu är jag kanske ute på rejält hal is, men kan det vara så att den använder porten som temporärt register för dessa? I så fall går det käpprätt åt h-e eftersom E kommer att fladdra som ett höstlöv.

Postat: 16 oktober 2008, 14:24:51
av Greve Hamilton
sodjan: OK, jag ska göra så. Just nu är dock kortet etsat, så jag får väl plocka fram dremeln och fräsa.

BEEP: Ja, vad jag kan se är alla fördröjningar korrekta, har trippelkollat.

Marta: Satan, det är ju den negativa flanken som låser. Jag fick för mig att det var på positiv flank. Jag ändrade i programmet nu, men det hjälpte inte alls.

Nu ser det ut så här:

Kod: Markera allt

/*

    OLED i 4-bit-läge:

    PORTD       LCD
    RD7   ->    D7
    RD6   ->    D6
    RD5   ->    D5
    RD4   ->    D4

    RD3   ->    E
    RD2   ->    RS

    WR på OLED är ansluten till GND.

*/

#define   E     PORTD.F3
#define   RS    PORTD.F2
#define   LEDG  PORTC.F7

void E_toggle() {
     E = 1;
     asm {
     nop 
     nop 
     nop
     };           // Delay 0,6us
     E = 0;
}

void Lcd_Send4bit(char lcd_data) {
     PORTD = (PORTD & 0x0F) | (lcd_data & 0xF0);      // Send upper nibble
     E_toggle();
     delay_us(40);
     PORTD = (PORTD & 0x0F) | (lcd_data << 4);        // Send lower nibble
     E_toggle();
     delay_us(40);
}

void Lcd_Text(char ascii_) {
     RS = 1;                    // Send to LCD-DDRAM (Data)
     Lcd_Send4bit(ascii_);
}

void Init_Lcd() {

     delay_ms(40);              // Wait for LCD to power up

     RS = 0;                    // Instructions

     PORTD = 0b00110000;        // 0x30
     E_toggle();
     delay_ms(5);
     PORTD = 0b00110000;        // 0x30
     E_toggle();
     delay_us(100);
     PORTD = 0b00110000;        // 0x30
     E_toggle();
     delay_us(40);

     PORTD = 0b00100000;        // Set 4-bit
     E_toggle();
     delay_us(40);

     Lcd_Send4bit(0b00101000);           // 4-bit, 2 lines, 5x8

     Lcd_Send4bit(0b00010100);           // Cursor move right

     Lcd_Send4bit(0b00001100);           // LCD on, cursor/blink off

     Lcd_Send4bit(0b00000110);           // Entry mode set

     Lcd_Send4bit(0b00000010);           // Address=0 (return home)
     delay_ms(2);                        // Delay > 1.52 ms

     Lcd_Send4bit(0b00000001);           // Clear display

     delay_ms(20);

}

void main () {

/* I/O Settings */

TRISA = 0b11111111;
TRISB = 0b11111111;
TRISC = 0b00010100;
TRISD = 0b00000001;
TRISE = 0b11111000;

PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
PORTE = 0x00;

Init_Lcd();

Lcd_Text(0b01000011);               // Print "C"

while (1) {
    LEDG = 1;                       // Fastnade inte i init, således.
}

}
Jag har mycket begränsade kunskaper i assembler, men så här ser koden ut för de logiska funktionerna i rutinen Lcd_Send4bit.

Kod: Markera allt

// PORTD = (PORTD & 0x0F) | (lcd_data & 0xF0);

MOVLW	15
BCF	STATUS, RP1
BCF	STATUS, RP0
ANDWF	PORTD, 0
MOVWF	STACK_1
MOVLW	240
ANDWF	FARG_Lcd_Send4bit+0, 0
MOVWF	STACK_0
MOVF	STACK_0, 0
IORWF	STACK_1, 0
MOVWF	PORTD
och...

Kod: Markera allt

// PORTD = (PORTD & 0x0F) | (lcd_data << 4);

MOVLW	15
ANDWF	PORTD, 0
MOVWF	STACK_2
MOVF	FARG_Lcd_Send4bit+0, 0
MOVWF	STACK_0
RLF	STACK_0, 1
BCF	STACK_0, 0
RLF	STACK_0, 1
BCF	STACK_0, 0
RLF	STACK_0, 1
BCF	STACK_0, 0
RLF	STACK_0, 1
BCF	STACK_0, 0
MOVF	STACK_0, 0
IORWF	STACK_2, 0
MOVWF	PORTD
Jag testade att byta ur PORTD just inne i maskningen till en temporär variabel i stil med:

Kod: Markera allt

void Lcd_Send4bit(char lcd_data) {
     char temp_portd = PORTD;
     PORTD = (temp_portd & 0x0F) | (lcd_data & 0xF0);
     ...
     ...
     PORTD = (temp_portd & 0x0F) | (lcd_data << 4);
     ...
     ...
}
Men det hjälpte inte.

Postat: 16 oktober 2008, 14:43:47
av Marta
Förfärligt ineffektiv kod som compilern skapar, men den gör det den skall och använder en temporär adress och något annat var väl inte hellre väntat.

Är initieringen OK, med alla analoga saker o.dyl. avstängda, om där nu finns sådant?

Postat: 16 oktober 2008, 15:08:05
av Icecap
Jag skulle föreslå att du sänker hastigheten våldsamt och faktisk kollar medelst 4 st LED + en till vardera Enable och R/S och ser om handskakningen och data är korrekt.

Postat: 16 oktober 2008, 15:09:53
av Greve Hamilton
Tack Marta, du ledde mig in på rätt spår.

Jag hade råkat sätta TRISE så att PSPMODE aktiverades, vilket använder PORTD.

"TRISE = 0b00000000;" blir rätt.

Tack för hjälpen, nu fungerar det.