Sida 1 av 1

Vad är det för fel på min LCD-kod?

Postat: 10 mars 2006, 19:38:35
av ASTRX
Jag har kopplat in databussen på min LCD (hd44780) på PORTB på en ATmega16. R/W och Kontrasten går till jord. E ligger på D0, RS på D1.
Tycker att min kod borde fungera, men jag får bara massa konstiga utskrifter. Inga tecken utan teckenrutor som tänd släcks delvis osv. Detta är mitt förta riktiga försök med AVR-arkitekturen. har läst massa i datablad m.m., men antagligen har jag missat nåt.
Om nån skulle vilja hjälpa till att felsöka min kod vore det guld iaf. programmet skall bara skriva ut två skärmar om och om igen:

display_test.c

Kod: Markera allt

#include <avr/delay.h>
#include "lcd.h"

#define F_CPU 1000000

int main()
{
    int i;

    _delay_ms(50);

	init_display();
	
	while(1){
		printrow("-Ojojojo            ",1);
		printrow("-ojojojoj            ",2);

		for(i=0;i<20;i++)
			_delay_ms(200);

		printrow("halaaaashiii      ",1);
		printrow("dfhshshsh        ",2);
	}

	return 0;
}
lcd.h

Kod: Markera allt

extern void init_display();
extern void clear_display();
extern void move_cursor(unsigned char);
extern void printchar(char);
extern void printrow(char text[], int);
lcd.c

Kod: Markera allt

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

void init_display()
{
	DDRD=0x03;		  // Sätter port D till utport
	DDRB=0xFF;		  // Sätter port D till utoprt
	
	PORTD=0b00000000; // RS=0 (instruktioner), RW=0 (write)
	PORTB=0b00110000; // Instruktionen för att starta 
	PORTD=0b00000001; // E=1 ger puls
	_delay_ms(0.01);  // Väntar 10 mikroseks då E regisreras
	PORTD=0b00000000; // E=0 avslutar puls
	_delay_ms(20);	  // Väntar 100 mikrosek. då instruktionen skall exekveras

	PORTB=0b00110000;
	PORTD=0b00000001; 
	_delay_ms(0.01); 
	PORTD=0b00000000; 
	_delay_ms(1);	

	PORTB=0b00110000; 
	PORTD=0b00000001;
	_delay_ms(0.01); 
	PORTD=0b00000000; 
	_delay_ms(0.1);	

	PORTB=0b00111000; 
	PORTD=0b00000001; 
	_delay_ms(0.01);  
	PORTD=0b00000000; 
	_delay_ms(0.1);	

	PORTB=0b00001000; 
	PORTD=0b00000001; 
	_delay_ms(0.01);  
	PORTD=0b00000000; 
	_delay_ms(0.1);	 

	PORTB=0b00000110; 
	PORTD=0b00000001;
	_delay_ms(0.01); 
	PORTD=0b00000000; 
	_delay_ms(0.1);



}


void clear_display()
{
	PORTD=0b00000000;
	PORTB=0b00000001;
	PORTD=0b00000001;
	_delay_ms(0.01); 
	PORTD=0b00000000;
	_delay_ms(5);	 
}

void move_cursor(unsigned char adress)
{
	PORTD=0b00000000;
	PORTB=adress;	 
	PORTD=0b00000001;
	_delay_ms(0.01);  
	PORTD=0b00000000; 
	_delay_ms(0.1);	

}

void printchar(char c)
{
	PORTD=0b00000010; // RS=1 (data), RW=0 (write)
	PORTB=c;	  	  // tecken som skall skrivas ut 
	PORTD=0b00000011; 
	_delay_ms(0.01); 
	PORTD=0b00000010; 
	_delay_ms(0.1);	
}


printrow(char text[], int row)
{
	int i;
	unsigned char disp_adress;
	
	if(row==2)						// sätt skrivadress till rad 2
		disp_adress=0b11000000;
	else if(row==3)				       // sätt skrivadress till rad 3
		disp_adress=0b10010000;
	else if(row==4)				       // sätt skrivadress till rad 4
		disp_adress=0b11010000;
	else						       // annars rad 1
		disp_adress=0b10000000;

	move_cursor(disp_adress);

	
	for(i=0;i<20;i++)
		printchar(text[i]);
}

Postat: 10 mars 2006, 23:22:07
av vukan
har själv skrivit ett eget litet program för att skriva ut på lcd'n och så här börjar min funktion för att skriva ut text:
void lcdtext(char *text){

while( *text != '\0' ) {

PORTA = *text++;
med globala deklarationer:
void lcdtext(char *text);
char *namn1 = "test lcd";
anrop av funktionen:
lcdtext(namn1);
kanske kan vara till någon hjälp?

Postat: 11 mars 2006, 14:00:18
av macgyver
om du använder WinAVR skulle jag föreslå att du testar att ta bort alla printrow

och prova istället:

for(i=0;i<20;i++) {
printchar('A');
}

fungerar det?

Postat: 11 mars 2006, 17:40:41
av frejo
jag skulle rent spotant använda _delay_us iställey för _delay_ms(0.X)
visserligen tar _delay_ms double men jag vet inte hur bra det egentligen funkar med så små tal.

Postat: 11 mars 2006, 18:39:38
av bearing
Min display hämtar datan på E:S negativa flank har jag för mig, så du kanske ska låta E ligga högt och sen sänka den när du lagt ut data.

Testa att öka dina delayer, det brukar komma konstiga tecken när någon av dem är för kort, använd höga delayer i början (typ 10ggr så stora)
Om du inte vet på vilken flank datan hämtas på kan du lägga delayer efter varje ändring av E så borde det funka ändå.

Enklaste sättet att testa olika delayer är att använda konstanter. Gör även ett makro för att strobea E så blir även det lätt att ändra.

Kan även vara något fel med init(). Har tyvärr inte orkat kolla igenom den. Ett tips är att lägga in att displayen ska visa markör i init så ser du iaf om init har lyckats.

När du fått det att funka kan du sedan sänka delayerna och testa hur E egentligen ska strobeas.

ps. du kommer bara hinna se första skärmen eftersom det bara är en delay efter den, inte efter andra skärmen. ds.

Postat: 11 mars 2006, 18:59:53
av ASTRX
Mycket nyttiga saker ni påpekar. vad gäller init_display() så är den inte som jag skulle velat. hade en egenskriven kommando-sekvens som jag använt för att initiera displayen i andra sammanhang som fungerat då. Denna skijlde sig från den som fanns i wiki:n (som jag förövrigt inte fann någon logik i), så jag testade den som fanns där.

Hade en fundering till. Jag behöver väl inte koppla in mer än VCC och GND utöver displayen i uC:n? kör ju med intern oscillator.

återkommer när jag provat runt lite. men nu ska jag ut och fira avslutad tentaperiod!!! :D

Postat: 14 mars 2006, 20:05:49
av ASTRX
Grr jag tror jag blir tokig. först så slutade min atmega16 helt plötsligt att fungera. den hittas inte när den sitter i STK500:n och den kör inte sitt program. och jag har ju varit überförsiktig med den...

Jag tycker jag har varit försiktig men ändå lyckats förstöra 2st uC:s. en pajj och en avbrutna ben =/

Så då testade jag med min ATmega8515. när jag simulerar mitt numera förenklade program så funkar det som det sak. men när jag sedan kopplar in den till vald port på STK:n så lyser inte rätt leds när jag anslutit dem till rätt port.

Jag vill så gärna få det att fungera och jag har ju fått en LCD att fungera via paralellporten. så ***** svårt kan det inte vara...

EDIT: Nu har jag testat med lite lösa leds på portarna, och kommit fram till att det är stk:n som visar fel. därmed kan jag ju konstatera att hårdvaran fungerar som den ska och att uC:n ger rätt värden vid 1 och 0.

någon som ser programfelet?


den aktuella koden:

Kod: Markera allt

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

#define DELAY 1000
#define CLR_DELAY 1000

void inline strobe()
{
	PORTD |= 0x01;         // E=1 ger puls
	_delay_ms(1000);  // Väntar då E regisreras
	PORTD &=~0x01;		  // E=0 avslutar puls
}


void clear_display()
{
	PORTD &=~0x02; 		  // RS=0 (instruktioner)
	PORTB=0b00000001; 		   
	strobe();
	_delay_ms(10000);
}


void init_display()
{
	DDRD=0x03;		  // Sätter port D till utport
	DDRB=0xFF;		  // Sätter port B till utport
	
	PORTD &=~0x02; 		  // RS=0 (instruktioner)
	PORTB=0b00001111; // Instruktionen för att starta 
	strobe();
	_delay_ms(10000);	  

	PORTB=0b00111000; // Instruktionen för function set 
	strobe();
	_delay_ms(10000);	 	  

	clear_display(); // Instruktion för att cleara display	   


}


void move_cursor(unsigned char adress)
{
	PORTD &=~0x02; 		  // RS=0 (instruktioner)
	PORTB=adress;	 	
	strobe();
	_delay_us(DELAY);

}

void printchar(unsigned char c)
{
	PORTD |= 0x02; 		  // RS=0 (instruktioner)
	PORTB=c;	 	 
	strobe();
	_delay_ms(DELAY);	 
}


void printstr(unsigned char *text, int row)
{
	int i=0;
	unsigned char disp_adress;
	
	if(row==2){						
		disp_adress=0b11000000;
	}
	else if(row==3){				
		disp_adress=0b10010000;
	}
	else if(row==4){			
		disp_adress=0b11010000;
	}
	else{						
		disp_adress=0b10000000;
	}

	move_cursor(disp_adress);

	
	while(*text!='\0' || i<20){
		printchar(*text++);
		i++;
	}
}

Kod: Markera allt

#include <avr/delay.h>
#include "lcd.h"

#define F_CPU 1000000UL
#define START_DELAY 1000

int main()
{
    int i;

    _delay_ms(START_DELAY);

	init_display();

	return 0;
}

Postat: 16 mars 2006, 12:50:39
av Xyzzy
ASTRX skrev:EDIT: Nu har jag testat med lite lösa leds på portarna, och kommit fram till att det är stk:n som visar fel. därmed kan jag ju konstatera att hårdvaran fungerar som den ska och att uC:n ger rätt värden vid 1 och 0.
Du vet att LEDarna på STKn är inverterade? (hög utgång resulterar i släkt LED och vice versa) - annars är det dax att läsa "manulen".