Hallo,
ik ben bezig met het aansturen van een LCD (hd44780 controller) met een 8051.
De LCD krijg ik aan de praat, maar hij doet totaal niet wat ik vraag. Ik geef in het begin van de code (na intialisatie en zo) de opdracht om naar het begin van het scherm te gaan, en daarna print ik een aantal karakters. Normaal moeten die toch mooi na elkaar komen op het scherm... Maar die karakters staan gewoon overal rond op het scherm.
Ik zie ook dat het display heel lichtjes flikkert.
Nu is het toch zo dat de positie enkel verandert als je een nieuwe karakter schrijft, of heb ik dat mis?
Ik geraak er niet meer aan uit.
MVG,
Bert
Hoe heb je m op je 8051 aangesloten en wat voor initialisatie gebruik je ?. 1 regel of 2 regel display ? Als je t contrast opdraait zie je de "blokjes" verdwijnen na initialisatie ?
Groeten, Bram
Hij is aangesloten met 8 lijnen, en ik gebruik 2 regels.
Als ik hem aanzet zie ik dus 1 regel blokjes (op hoog contrast) en die verdwijnen na mijn initialisatie.
Hij schakelt dus wel degelijk over op 2 regels. Maar het is net alsof die cursor gewoon continu alle plaatsen afloopt, en dat hij de karakter print op de plaats waar hij op dat moment zit. Zo ziet het er althans uit...
MVG,
Bert
Hieronder staat mijn file lcd.c
Kan zijn dat er wel wat rare dingen in staan, want ik heb al vanalles geprobeerd om het werkende te krijgen. Mijn klok is trouwens ingesteld op 24.5 MHz. Daarom steeds die wait_ms tussen de instructies... Misschien heeft het wel iets met die klok te maken, maar ik moet nog andere verwerking doen met de MCU, waardoor die snelheid wel gewenst is. Enig idee wat er zoal mis kan lopen?
void Init_Display(void){
Wait_ms(20); // Meer dan 15 ms wachten na inschakelen
Write_Instruction(Set_Function | Data_Length_8 | Two_Line_Display | Font_5x8);
Wait_ms(5); // Wacht langer dan 4.1 ms
Write_Instruction(Set_Function | Data_Length_8 | Two_Line_Display | Font_5x8);
Wait_ms(1); // Wacht langer dan 0.1 ms
Write_Instruction(Set_Function | Data_Length_8 | Two_Line_Display | Font_5x8);
Wait_ms(1);
Write_Instruction(0x0C);
Write_Instruction(0x01);
Wait_ms(100);
}
void Write_Instruction(char instr){
Check_Ready(); // Wacht tot LCD klaar is om te beginnen
LCD_RS = 0; // RS en RW op 0 voor instructies
LCD_RW = 0;
LCD_PORT = instr; // instructie op de datalijnen zetten
Wait_ms(1);
LCD_ENB = 0;
Wait_ms(2);
LCD_ENB = 1; // Enable pulsen om instructie door te geven aan LCD-controller
}
void Write_Character(char ch){
Check_Ready(); // Wacht tot LCD klaar is om te beginnen
LCD_RS = 1; // RS en RW op 1 en 0 voor karakter
LCD_RW = 0;
LCD_PORT = ch; // instructie op de datalijnen zetten
Wait_ms(1);
LCD_ENB = 0;
Wait_ms(2);
LCD_ENB = 1; // Enable pulsen om instructie door te geven aan LCD-controller
}
char Read_RAM(char addr){
Write_Instruction(Set_DDRAM_Address | addr);
Check_Ready(); // Wacht tot LCD klaar is om te beginnen
LCD_ENB = 0;
SFRPAGE = CONFIG_PAGE;
LCD_PORT = 0xFF; // Poort als input door over te gaan op hoog-impedante staat
P3MDOUT = 0x7F; // DB7 als open drain (BF)
LCD_RS = 1;
LCD_RW = 1;
LCD_ENB = 1;
Wait_ms(1);
ddramdata = LCD_PORT;
Wait_ms(1);
return ddramdata;
}
void Write_String(char st[],int line){
int i;
Write_Instruction(Set_Entry_Mode | Increment_Address | Shift_On);
Write_Instruction(Set_DDRAM_Address | 0);
if(line == 2){
Write_Instruction(Set_DDRAM_Address | Second_Line);
}
for(i=0;i<strlen(st);i++){
Write_Character(st[i]);
//Wait_ms(1);
}
}
// Kijken als controller niet bezig is met uitvoeren van een taak. Check gebeurd aan de hand van Busy Flag (BF)
void Check_Ready(void){
char SFRPAGE_SAVE;
SFRPAGE_SAVE = SFRPAGE;
SFRPAGE = CONFIG_PAGE;
LCD_PORT = 0xFF; // Poort als input door over te gaan op hoog-impedante staat
P3MDOUT = 0x7F; // DB7 als open drain (BF)
LCD_RS = 0; // instellen om BF te lezen
LCD_RW = 1;
while (LCD_BUSY)
{
LCD_ENB = 0; // Enable pulsen zodat we opnieuw kunnen checken
Wait_ms(5);
LCD_ENB = 1;
Wait_ms(5);
}
SFRPAGE = CONFIG_PAGE;
P3MDOUT = 0xFF; // P1 terug Push-Pull
SFRPAGE = SFRPAGE_SAVE;
}
void Wait_ms(int ms)
{
SFRPAGE = TMR2_PAGE;
TMR2L = 0x26;
TMR2H = 0xD0;
TR2 = 1;
while(ms){
TF2 = 0;
while(!TF2); // Wacht op timer2 overflow
ms--; // ms decrementeren
}
TR2 = 0; // Stop Timer 2
}
[Bericht gewijzigd door Henry S. op (0%)]
waarom hang je dat ding niet gewoon aan de adres/data-bus met een adresdecoder, stuur dat display aan als memory-mapped I/O, dan heb je twee adressen, een voor data, een voor instructies.
Maakt de routine veel simpeler.
Er zit tevens nog een fout in je routine, als je data naar je display stuurt moet de enable laag zijn, op het moment dat je die lijn hoog maakt wordt de data overgenomen.
Nu is het zo dat de enable-lijn hoog is als je data aan het schrijven bent. het display kan deze data dan op een willekeurig moment overgenomen worden, wat ook het 'vreemde' gedrag verklaart.
bovendien, als je na de Enable steeds 2 mS wacht hoef je niet meer te testen of je busy-vlag geset is. je bent dan met de timing aan het rommelen.
Ik ga met DC2PCC mee. Gaat alleen niet leuk worden als je die bus niet naar buiten uitgevoerd hebt.
Verder ben je met timing aan het spelen. Die heb ik niet helemaal doorgespit, maar eerste indruk is dat (als die delay werkt) je in elk geval niet te snel bent voor een POC. Ik zie dat je iets met een LCD_BUSY doet, kan alleen niet vinden wanneer en waar die geset / gecleared wordt.
Verder triggerde ik op deze:
P3MDOUT = 0xFF; // P1 terug Push-Pull
Je doet iets met P3 (lijkt het), maar in je commentaar roep je iets over P1. Gaat dat goed?
Die LCD driver doet meen ik inderdaad push-pull. Geen pull-up oid. nodig.
Let ook op je enable. In fig. 27 van de Hitatchi datasheet staat inderdaad dat er nog aan de data gerommeld wordt als E al hoog is. Het lijkt erop dat de falling edge van E die data leest. Dat zou goed moeten zitten. (te lang geleden dat ik die routines geschreven heb, maar op het eerste gezicht ga ik niet mee met DC2PCC in deze!)
Hoe kom je uit met je tas uit diezelfde datasheet? Een 8051 op 24MHz zegt niet zoveel. Een 'echte' doet dan 2 MIPS ofzo, maar er zijn ook klonen die op en nabij 24MIPS lopen op die clock.
bedankt voor de reacties 
Die LCD_BUSY staat in de header file als sbit LCD_BUSY = P3^7;
Ik check dus gewoon wanneer die pin laag gaat. En die p3 is wel correct, ik gebruikte eerst p1, en de commentaar is blijkbaar blijven staan... 
@marco69: je hebt volkomen gelijk, het display neemt de data mee op de VALLENDE flank van de enable. MAAR, vindt een HD44780 het goed dat je aan de R/W lijn rommelt terwijl de Enable hoog is ? uit de timing-diagrammen die ik tegenkom kan ik dat niet opmaken. als de Enable-lijn hoog is wordt de R/W-lijn vastgehouden.
Dus het is wel degelijk de dalende flank van enable die de data binnenpakt?
Blijkbaar is daar wat verwarring rond, want op sommige sites zie ik staan op stijgende flank, en andere op dalende flank.
Ik zal de code eens aanpassen zodat die RW en RS lijnen onveranderd blijven als enable hoog is.
grtz
Ik heb me gebaseerd op de datasheet van Hitatchi, de bakker van die chip. Aangezien bij nader inzien DC2PCC hetzelfde inzicht heeft, ga ik er vanuit dat die enable op de falling edge gedaan wordt.
DC2PCC heeft wel gelijk mbt. rommelen aan andere lijnen. Pak een waveform uit de datasheet en kijk of wat jij doet klopt. Zowel qua sequence / wanneer-verander-ik-wat als qua timing.
Vertel ook eens hoe snel die 8051 is. Aan een clockspeed alleen heb je in deze niet zoveel.
[edit]Kijk ook even naar figure 28 voor een read. Die doe je bij E=1, echter wel na tddr.
Het is nog altijd niet in orde.
Wat me ook opvalt is dat ik veel "|||" en "||" op het scherm te zien krijg.
Waar dat vandaan komt heb ik het raden naar...
grtz
pros
Prosper, yop la boum, c'est le roi du macadam (aldus Maurice Chevalier)
Op 31 maart 2009 16:58:06 schreef DC2PCC:
@marco69: je hebt volkomen gelijk, het display neemt de data mee op de VALLENDE flank van de enable. MAAR, vindt een HD44780 het goed dat je aan de R/W lijn rommelt terwijl de Enable hoog is ? uit de timing-diagrammen die ik tegenkom kan ik dat niet opmaken. als de Enable-lijn hoog is wordt de R/W-lijn vastgehouden.
Als je data van de HD44780 wil kunnen lezen, en de R/W-lijn dus niet vast met GND verbonden is, moet R/W goed ingesteld worden alvorens EN hoog gemaakt wordt.
Is R/W permanent met GND verbonden, dan mag je met de overige lijnen rommelen zoveel je wil, zolang er geen neergaande flank op EN geplaatst wordt.
free_electron
Silicon Member
Professioneel ElectronenTemmer - siliconvalleygarage.com - De voltooid verleden tijd van 'halfgeleider' is 'zand' ... US 8,032,693 / US 7,714,746 / US 7,355,303 / US 7,098,557 / US 6,762,632 / EP 1804159 - Real programmers write Hex into ROM
stomme vraag : welke poort gebruik je ? toch nooit de open collector poort zeker ? hang eens een tros pull-ups op je data lijnen ...
Ik gebruik poort 3 voor de datalijnen.
Ik zal morgen eens pull-ups solderen en hopen dat het zo werkt...
merci
Overigens heb je nog niks geroepen over de snelheid van het ding...
f_e heeft natuurlijk volkomen gelijk. Gezien die regel over 'push-pull' in je code ging ik er min of meer vanuit dat dat wel goed zou zitten. Well, assumption is the mother of all fuck-ups...
Overigens: als ik het mij goed herinner, doet een 'echte' 8051 stiekem wel een vorm van push-pull door als je een pin 'hoog' maakt het ding 1 clock cycle hoog te driven, de pull-up moet dan maar zorgen dat-ie daar blijft. Zo houd je acceptabele flanken.
Als je het nou nog niet aan de gang hebt... Ik moet nog ergens een stuk C code hebben voor een 44780 op 8051. Niet meer dan POC, en bedoeld voor een 1-MIPS variant.
Ik heb het display aan de praat gekregen.
Bedankt voor de hulp!
Ik heb geen pull-ups nodig gehad, het probleem zat hem bij het checken van de busy flag.
grtz Bert
Een update van je werkende code is dan wel gewenst voor de eventuele nieuwkomer.
Of is het nu op eens een closed source project geworden? 
haha, nee tuurlijk niet.
Ik zal ze straks eens posten, ik ben nu nog wat dingen op orde aan het zetten.
grtz