Hallo,
Hab vor mir ein 2x16 Zeilen LCD liegen. Textausgabe funktioniert
einwandfrei, nur wenn ich versuche das Display zu löschen, schreibt es 2
irgenwelche kryptische Zeichen hin, ohne die Anzeige zu löschen.
Außerdem kann ich nicht in die 2. Zeile hüpfen. Erst wenn ich (glaub ich
halt) einen Überlauf produzier komm ich in die nächste Zeile.
Hab mal den C-Code angehängt. Die Ausgabe zu diesem Code sieht so aus:
test53685**abcde
456789HALLO!:
wobei für * diese kryptischen "Zeichen" einzusetzen ist, die ich aber
hier nicht darstellen kann (sind glaub ich gar nicht im ASCII
enthalten).
main.c
1
// ATMega8 1MHz
2
// Verwendetes Prog: Programmers Notepad 2
3
// LCD: PVC160101PTN03
4
// Anschlussbelegung:
5
/* Db4 = Portb.0
6
Db5 = Portb.1
7
Db6 = Portb.2
8
Db7 = Portb.3
9
E = Portb.4
10
Rs = Portb.5
11
*/
12
13
#include<avr/io.h>
14
#include"lcd-routines.h"
15
#include<util/delay.h>
16
#ifndef F_CPU
17
#define F_CPU 1000000
18
#endif
19
20
voiddelay_ms(intms)
21
{
22
intt;
23
for(t=0;t<=ms;t++)
24
_delay_ms(1);
25
}
26
27
intmain(void)
28
{
29
DDRB=0xFF;// Port B komplett als Ausgang einstellen
30
lcd_init();//Initialisierung
31
lcd_clear();
32
lcd_out("test53685");
33
delay_ms(2000);// 2 Sekunden Verzögerung
34
lcd_clear();//LCD löschen
35
jumpline();//In die 2. Zeile springen
36
delay_ms(2000);
37
lcd_out("abcdefghijklmnopqrstuvwxyz");
38
lcd_out("123456789");
39
lcd_data('H');
40
lcd_data('A');
41
lcd_data('L');
42
lcd_data('L');
43
lcd_data('O');
44
lcd_data('!');
45
lcd_data(':');
46
return0;
47
}
und da die dazugehörende lcd_routines.c:
1
#include<avr/io.h>
2
#include<util/delay.h>
3
#include"lcd-routines.h"
4
#define DELAY50US() _delay_us(25); _delay_us(25)
5
// LCD Befehle
6
#define CLEAR_DISPLAY 0x01
7
#define CURSOR_HOME 0x02
8
// Pinbelegung für das LCD
9
#define PORT_LCD PORTB
10
#define LCD_RS 5
11
#define LCD_EN 4
12
// sendet einen Befehl an das LCD
13
// wie lcd_data, nur ohne RS zu setzen
14
voidlcd_command(unsignedchartemp1)
15
{
16
unsignedchartemp2=temp1;
17
temp1=temp1>>4;// oberes Nibble holen
18
temp1=temp1&0x0F;// maskieren
19
PORT_LCD&=0xF0;
20
PORT_LCD|=temp1;// setzen
21
lcd_enable();
22
23
temp2=temp2&0x0F;// unteres Nibble holen und maskieren
24
PORT_LCD&=0xF0;
25
PORT_LCD|=temp2;// setzen
26
lcd_enable();
27
28
DELAY50US();
29
}
30
31
// erzeugt den Enable-Puls
32
voidlcd_enable(void)
33
{
34
PORT_LCD|=(1<<LCD_EN);
35
asm("nop");
36
asm("nop");
37
asm("nop");
38
PORT_LCD&=~(1<<LCD_EN);
39
}
40
41
// Initialisierung:
42
voidlcd_init(void)
43
{
44
unsignedchartemp3=50;
45
46
while(temp3!=0)
47
{
48
_delay_ms(5);// 5ms = 250ms warten
49
temp3=temp3-1;
50
}
51
// muss 3mal hintereinander gesendet werden zur Initialisierung
52
PORT_LCD&=0xF0;
53
PORT_LCD|=0x03;// 0b00000011
54
lcd_enable();
55
PORT_LCD|=0x03;
56
lcd_enable();
57
PORT_LCD|=0x03;
58
lcd_enable();
59
60
// 4bit-Modus einstellen
61
PORT_LCD|=0x02;// 0b00000010
62
lcd_enable();
63
_delay_ms(5);
64
65
// 4Bit / 2 Zeilen / 5x7
66
lcd_command(0x28);//Mache das 3mal wegen Timing (einfach ausprobiert)
67
lcd_command(0x28);
68
lcd_command(0x28);
69
70
// Display ein / Cursor aus / kein Blinken
71
lcd_command(0x0C);
72
73
// inkrement / kein Scrollen
74
lcd_command(0x06);
75
}
76
77
// Sendet den Befehl zur Löschung des Displays
78
voidlcd_clear(void)
79
{
80
lcd_command(CLEAR_DISPLAY);
81
_delay_ms(7);
82
}
83
84
// Sendet den Befehl: Cursor Home
85
voidlcd_home(void)
86
{
87
lcd_command(CURSOR_HOME);
88
_delay_ms(5);
89
}
90
91
voidlcd_out(char*s)
92
{
93
while(*s)//so lange *s != '\0' also ungleich dem "String-Endezeichen"
94
{
95
lcd_data(*s);//Zeichen ausgeben
96
s++;
97
}
98
}
99
100
101
voidjumpline(void)
102
{
103
lcd_command(0xC0);//in 2. zeile springen (2nd line starts at 40h)
104
_delay_ms(5);
105
}
Hoffentlich kann mir da jemand weiterhelfen!
lg spyder
@ spyder (Gast)
>Außerdem kann ich nicht in die 2. Zeile hüpfen. Erst wenn ich (glaub ich>halt) einen Überlauf produzier komm ich in die nächste Zeile.
Dann scheint deine Funktion lcd_command nicht ganz zu funktionieren.
Ist auch klar, du MUSST RS expliziet auf NUll setzen! Das tust du nicht.
Ausserdem ist dein Initialisierung nicht ganz korrekt, du musst zwischen
den 3 Initialisierungsbefehlen jeweils Pausen einlegen.
Und warum verwendest du mehrere Versionen von Warteschleifen? Das ist
nicht gut. Kostest Sinnlos Programmspeicher und wird schnell
unübersichtlich.
MfG
Falk
Komisch, dass ist eigentlich der Code ausn LCD-Tut. Naja, was solls. Ähm
könntest du mir sagen, wo genau RS auf Null setzen muss und meinst du
mit Initialisierungsbefehlen "lcd_command(0x28);" ??
lg spyder
Im Tutorial gibt es leider drei verschiedene Routinen
1/ die Assembler Routine
2/ die C Routine analog zur Assembler Routine
1
// sendet einen Befehl an das LCD
2
// wie lcd_data, nur ohne RS zu setzen
3
voidlcd_command(unsignedchartemp1)
4
{
5
unsignedchartemp2=temp1;
6
7
temp1=temp1>>4;// oberes Nibble holen
8
temp1=temp1&0x0F;// maskieren
9
PORTD=temp1;// setzen
10
lcd_enable();
11
12
temp2=temp2&0x0F;// unteres Nibble holen und maskieren
13
PORTD=temp2;// setzen
14
lcd_enable();
15
16
DELAY50US();
17
}
3/ eine weitere C Routine mit dem Zusatz
1
// Ich habe kein Hardwareaufbau und kann das Programm nicht testen
2
// deshalb bitte ich jemanden kurz das Programm zu verifizieren.
1
// sendet einen Befehl an das LCD
2
// wie lcd_data, nur ohne RS zu setzen
3
voidlcd_command(unsignedchartemp1)
4
{
5
unsignedchartemp2=temp1;
6
7
temp1=temp1>>4;// oberes Nibble holen
8
temp1=temp1&0x0F;// maskieren
9
PORT_LCD&=0xF0;// <==================== BUG!
10
PORT_LCD|=temp1;// setzen
11
lcd_enable();
12
13
temp2=temp2&0x0F;// unteres Nibble holen und maskieren
14
PORT_LCD&=0xF0;// <==================== BUG!
15
PORT_LCD|=temp2;// setzen
16
lcd_enable();
17
18
DELAY50US();
19
}
Du verwendest die 3. Variante. Und die hat einen Bug - Falk Brunner
bemerkt zu recht, dass RS an dieser Stelle NICHT auf 0 gesetzt wird, im
Gegenteil...
Bei den C-Makros (http://www.mikrocontroller.net/articles/C_Makros
) ist ein Löschmakro vorhanden
Damit ist hinter der den beiden betreffenden Zeilen jeweils diese Zeile
einzufügen:
clear_bit(PORT_LCD, LCD_RS);
Das Tutorial wurde an dieser Stelle korrigiert (mit der ausformulierten,
nicht der Makroversion).
Danke für die Info!!
Hab das mal so wie Falk Brunner es gepostet hat reinprogrammiert -
funktioniert super. Nur mag der Zeilenwechsel immer noch nicht :(
Der Compiler schreit bei der set_cursor Funktion immer: "error: expected
';' before ':' token". Ich hab den Code mit Copy-Paste eingefügt, also
sollte da ja wohl nix sein. Zum Test hab ich meinen Aufruf jumpline();
ausprobiert. Sollte ja das gleiche nur vereinfacht bewirken (in die 2.
Zeile springen).
Jetzt spuckt der Compiler keine Fehlermeldungen aus, aber das LCD ist
anscheinend immer noch nicht zufrieden.
bei diesem Codeabschnitt:
1
lcd_out("abcdefghi");
2
set_cursor(0x00,0x02);
3
lcd_out("123456789");
schreibt das LCD in die 1. Zeile: "abcdefghi" und dann nichts mehr,
weder in die 1. noch in die 2. Zeile. Hab jetzt nochmal im Datenblatt
nachgeschaut:
In 1-line display mode (N=0, NW=0), DDRAM address is from "00H" to
"4FH".
In 2-line display mode (N=1, NW=0), DDRAM address in the 1st line is
from "00H" to "27H",and DDRAM address in
the 2nd line is from "40H" to "67H".
Also müsste das eigentlich passen, wenn ich die Adresse auf 0xC0
setzen??
lg spyder
@ spyder (Gast)
>Jetzt spuckt der Compiler keine Fehlermeldungen aus, aber das LCD ist>anscheinend immer noch nicht zufrieden.>bei diesem Codeabschnitt:
lcd_out("abcdefghi");
set_cursor(0x00, 0x02);
lcd_out("123456789");
>Also müsste das eigentlich passen, wenn ich die Adresse auf 0xC0>setzen??
Das macht doch set_cursor(), 0xC0 = 0x80 + 0x40;
Hmm, keine Ahnung.
MFG
Falk
Ja, das ist mir schon klar, dass das set_cursor() macht, aber irgendwie
macht es dann doch nicht. Vielleicht hats da was mit der DDRAM
Adresse?!?
bitte helft mir
> set_cursor(0x00, 0x02);
Ich denke Du hast ein zwei Zeilen LCD?
Dann hat (üblicherweise) die zweite Zeile die Nummer 1 und nicht 2.
set_cursor(0x00, 0x01);
@ Werner B. (Gast)
>Ich denke Du hast ein zwei Zeilen LCD?>Dann hat (üblicherweise) die zweite Zeile die Nummer 1 und nicht 2.>set_cursor(0x00, 0x01);
Ein Blick auf den Quellcode verrät schnell, dass die Zeilen von der
Funktion als 1..4 gezählt werden.
MFG
Falk
@ spyder (Gast)
>Und wo kann nun der Fehler liegen?
Probier mal in der ERSTEN Zeile den Cursor an verschiedene Postitionen
zu setzen. Das würde erstmal zeigen, dass das halbwegs funktioniert.
Dann soltest du mal verschiedene Zeichen ausgeben, wo jeweils nur ein
Bit gesetzt ist. Also 0x01, 0x02, 0x04, 0x08 etc. Das testet deine
Verkabelung. Und wenn du hast mit dem Oszi mal alle Leitungen anschauen.
MfG
Falk