Forum: Mikrocontroller und Digitale Elektronik LCD zeigt nichts an


von Snayer I. (Firma: Audi GmbH) (snayer2311)


Angehängte Dateien:

Lesenswert?

Hallo :-)

stehe seit tagen vor einem Problem bei dem ich nicht mehr weiter komme. 
Simple Aufgabe ich möchte das mein display i-was anzeigen soll. Deswegen 
habe ich mal zur Sicherheit das Testbeispiel im AtmegaStudio Projekt 
übernommen. Die libery also lcd-routine.h habe ich natürlich geändert: 
einmal die Taktfrequenz und die Pinbelegung. Dennoch wenn ich dieses 
Programm ausführe zeigt mir nur mein Display das standard initialisierte 
Balkenbild:( Jezt weiss ich nicht wo und was ich jetzt falsch gemacht 
habe, ob es jetzt am programm liegt oder an der Verdrahtung selber. Ich 
habe mein Atmel Addon Board V1.0 am Atmel Evaluation-Board Version 2.0.1 
angeschlossen.
Zusätzlich hänge ich noch oben mein Programm mit den beiden library und 
meine verdrahtung am board. Leider war mir der Schaltplan von diesem 
board nicht so einleuchtend und weiss jetzt nicht ob ich alles so 
richtig mit jedem pin verbunden habe, die betonnung liegt auf richtig!
hoffe ihr könnt mir helfen,

vielen dank im voraus :-)

Ps: hier ist der Schaltplan
http://www.pollin.de/shop/downloads/D810053B.PDF

von Felix (Gast)


Lesenswert?

hi,
deine Belegung passt nicht.
Die Datenleitung leigen bei dir von PA0 - PA3
Auf PA3 liegt aber auch gleichzeitig 'RS' und auf PA1 auf 'EN'.

mfg

von Snayer I. (Firma: Audi GmbH) (snayer2311)


Lesenswert?

Also musss ich in der headerdatei bei lcd-routine.h die Pins ändern?

Mir ist nicht klar warum  das jetzt falsch ist:( Die pins sind ja nicht 
miteinander am board verbunden.
wie sehe das denn jetzt richtig aus z.b ?

von Karl H. (kbuchegg)


Lesenswert?

Mit den von dir gezeigten LCD-Routinen wird das nichts.
Dazu müsstest du den Port für die Steuerleitungen getrennt vom Port für 
die Datenleitungen einstellen können. Dafür sind diese Funktionen aber 
nicht vorbereitet.
Entweder du machst dir diese Modifikation selber (was nicht wirklich 
schwer ist), oder du suchst dir andere LCD-Routinen, bei denen das schon 
gemacht wurde.

von Udo S. (urschmitt)


Lesenswert?

3 MB für ein sinnleeres Bild einer Platine und 3 mal 200K für 
Screenshots von Programmlistings in der Größe einiger hundert Bytes.
Junge du hast den Tagespreis für die größt Platzverschwendung gewonnen.
Lese bitte mal Bildformate

von Snayer I. (Firma: Audi GmbH) (snayer2311)


Lesenswert?

Also zusammengefasst muss ich einfach die beiden headerdateien ändern 
mehr nicht dann solllte es funktionieren okay ich schau mal ob ich das 
hinkriege ^^

Danke schonmal

von Karl H. (kbuchegg)


Lesenswert?

Adrian H, schrieb:
> Also zusammengefasst muss ich einfach die beiden headerdateien ändern

Nö.
Zusammengefasst: du müsstest DIESEN Code so umändern, dass du für den 
Zugriff auf die Steuerleitungen einen 2.ten Port benutzen kannst und 
nicht nur LCD_PORT quer durch die ganzen Funktionen verwendet wird.
Aber: so viele Verwendungen sind das dann ja auch wieder nicht, die 
umgestellte werden müssten. (Die Initialisierungen der Port-Richtung 
nicht vergessen)

von snayer2311 (Gast)


Lesenswert?

wie mache ich das dass endlich zugriff auf dem 2 port bekomme?
im moment muss ich ja nur hier in diesem folgenden Code was ändern:
1
#ifndef LCD_PORTS
2
#define LCD_PORTS
3
4
#define LCD_PORT      PORTD
5
#define LCD_DDR       DDRD
6
7
// 4 Bit LCD Datenbus DB4-DB7, das unterste Bit DB4 kann auf den Portbits 0..4 liegen
8
9
//  LCD DB4-DB7 <-->  PORTC Bit PC0-PC3
10
#define LCD_DB        PD0
11
12
// LCD Steuersignale RS und EN
13
14
//  LCD RS      <-->  PORTC Bit PC4     (RS: 0=Data, 1=Command)
15
#define LCD_RS        PD4
16
17
//  LCD EN      <-->  PORTC Bit PC5     (EN: 1-Impuls für Daten)
18
#define LCD_EN        PD5
19
20
#endif // LCD_PORTS

laut dem hier zufolge 
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung

muss bei diesem display PD4 auf RS sein und PD5 auf EN.

ich hab mir das Beispiel erweiterte Ansteuerung angeschaut, jedoch sah 
ich da keinen allzu großen unterschied was mir weiter bringen könnte

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

snayer2311 schrieb:

> ich hab mir das Beispiel erweiterte Ansteuerung angeschaut, jedoch sah
> ich da keinen allzu großen unterschied was mir weiter bringen könnte

Dein Problem ist, dass du dich weigerst dir den Code anzusehen und 
nachzudenken.

Wenn hier ...
1
static void lcd_enable( void )
2
{
3
  LCD_PORT |= (1<<LCD_EN);     // Enable auf 1 setzen
4
  _delay_us( LCD_ENABLE_US );  // kurze Pause
5
  LCD_PORT &= ~(1<<LED_EN);    // Enable auf 0 setzen
6
}
steht, dass der Enable Pin über den LCD_PORT geschaltet wird, bei dir 
aber der LCD_PORT der PORTA ist (wegen der Datenleitungen), die Enable 
Leitung aber auf dem Port B liegt, dann kannst du offensichtlich das 
Schalten der Enable Leitung nicht über LCD_PORT abwickeln, sondern musst 
das umprogrammieren.

Ergo wirst du dir für die Steuerleitungen etwas ähnliches wie den 
LCD_PORT einführen. Nennen wir es mal den LCD_CTRL_PORT (für Control - 
Port. Der Port an dem die Steuerleitungen vom LCD hängen.

IM Header Feil kommt also rein
1
#ifndef LCD_PORTS
2
#define LCD_PORTS
3
4
#define LCD_PORT      PORTA
5
#define LCD_DDR       DDRA
6
7
#define LCD_CTRL_PORT PORTB
8
#define LCD_CTRL_DDR  DDRB
9
10
// 4 Bit LCD Datenbus DB4-DB7, das unterste Bit DB4 kann auf den Portbits 0..4 liegen
11
12
//  LCD DB4-DB7 <-->  PORTC Bit PC0-PC3
13
#define LCD_DB        PA0
14
15
// LCD Steuersignale RS und EN am Control Port
16
17
//  LCD RS      <-->  PORTC Bit PB2     (RS: 0=Data, 1=Command)
18
#define LCD_RS        PB2
19
20
//  LCD EN      <-->  PORTC Bit PB0     (EN: 1-Impuls für Daten)
21
#define LCD_EN        PB0
22
23
#endif // LCD_PORTS

Damit hast du jetzt erst mal grundsätzlich 2 Ports benannt, über die die 
Kommunikation abgewickelt wird. Ob die Pinnummern stimmen, weiß ich 
nicht. Die kann man auf dem Photo so schlecht lesen. An der 
Steckerleiste stehen sie aber dabei, so dass du die nur kontrollieren 
brauchst.

Tja. UNd dann müssen natürlich die Routinen entsprechend geändert 
werden. Zb wird lcd_enable dann eben sein 1 bzw. 0 setzen des Enable 
Pins nicht mehr über den LCD_PORT abwickeln, sondern wird das dann eben 
über den LCD_CTRL_PORT machen.
1
static void lcd_enable( void )
2
{
3
  LCD_CTRL_PORT |= (1<<LCD_EN);     // Enable auf 1 setzen
4
  _delay_us( LCD_ENABLE_US );  // kurze Pause
5
  LCD_CTRL_PORT &= ~(1<<LED_EN);    // Enable auf 0 setzen
6
}

Denn die Enable Leitung ist ja an den PORTB verdrahtet, dem wir den 
Namen LCD_CTRL_PORT verpasst haben.

und so geht man dann eben den Code durch, sieht sich an, was da jeweils 
passiert und überlegt, ob die Port Ausgabe auf den LCD_PORT (die 
Datenleitungen) oder den LCD_CTRL_PORT (die Steuerleitungen) gehen muss.
Auf die Initalisierung nicht vergessen, denn auch die Leitungen auf dem 
LCD_CTRL_PORT müssen mal auf Ausgang geschaltet werden ... und ... wenn 
du keinen Fehler gemacht hast, dann ist der Teil damit erst mal 
erledigt. Wenn das Timing nicht zu knapp ist, müsste sich das LCD schon 
melden.

Aber .... ohne dass du selber ein wenig umprogrammierst wird das nichts 
werden. Wenn ein Code auf eine Anforderung, hier die Trennung von Daten 
und Steuerleitungen auf verschiedene Ports, nicht vorbereitet ist, dann 
muss man eben diese Trennung selber in den Code einbauen. Mit 3 Zahlen 
in 4 #defines austauschen ist es dann nicht getan.

: Bearbeitet durch User
von snayer2311 (Gast)


Lesenswert?

nach deiner großen hilfe :) sehe dann das routinen programm etwa so aus 
also wäre es  zumindest das richtig
1
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
2
// http://www.mikrocontroller.net/articles/HD44780
3
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
4
//
5
// Die Pinbelegung ist über defines in lcd-routines.h einstellbar
6
7
#include <avr/io.h>
8
#include "lcd.h"
9
#include <util/delay.h>
10
11
////////////////////////////////////////////////////////////////////////////////
12
// Erzeugt einen Enable-Puls
13
static void lcd_enable( void )
14
{
15
  LCD_CTRL_PORT |= (1<<LCD_EN);        // Enable auf 1 setzen
16
  _delay_us( LCD_ENABLE_US );       // kurze Pause
17
  LCD_CTRL_PORT &= ~(1<<LCD_EN);      // Enable auf 0 setzen
18
}
19
20
////////////////////////////////////////////////////////////////////////////////
21
// Sendet eine 4-bit Ausgabeoperation an das LCD
22
static void lcd_out( uint8_t data )
23
{
24
  data &= 0xF0;                       // obere 4 Bit maskieren
25
  
26
  LCD_PORT &= ~(0xF0>>(4-LCD_DB));    // Maske löschen
27
  LCD_PORT |= (data>>(4-LCD_DB));     // Bits setzen
28
  lcd_enable();
29
}
30
31
////////////////////////////////////////////////////////////////////////////////
32
// Initialisierung: muss ganz am Anfang des Programms aufgerufen werden.
33
void lcd_init( void )
34
{
35
  DDRA = 0xff;
36
  PORTA = (1<<LCD_PORT);
37
  DDRB = 0xff;
38
  PORTB = (1<<LCD_CTRL_PORT);
39
  
40
  // verwendete Pins auf Ausgang schalten
41
  uint8_t pins = (0x0F << LCD_DB) |           // 4 Datenleitungen
42
  (1<<LCD_RS) |                // R/S Leitung
43
  (1<<LCD_EN);                 // Enable Leitung
44
  LCD_DDR |= pins;
45
  
46
  // initial alle Ausgänge auf Null
47
  LCD_PORT &= ~pins;
48
  
49
  // warten auf die Bereitschaft des LCD
50
  _delay_ms( LCD_BOOTUP_MS );
51
  
52
  // Soft-Reset muss 3mal hintereinander gesendet werden zur Initialisierung
53
  lcd_out( LCD_SOFT_RESET );
54
  _delay_ms( LCD_SOFT_RESET_MS1 );
55
  
56
  lcd_enable();
57
  _delay_ms( LCD_SOFT_RESET_MS2 );
58
  
59
  lcd_enable();
60
  _delay_ms( LCD_SOFT_RESET_MS3 );
61
  
62
  // 4-bit Modus aktivieren
63
  lcd_out( LCD_SET_FUNCTION |
64
  LCD_FUNCTION_4BIT );
65
  _delay_ms( LCD_SET_4BITMODE_MS );
66
  
67
  // 4-bit Modus / 2 Zeilen / 5x7
68
  lcd_command( LCD_SET_FUNCTION |
69
  LCD_FUNCTION_4BIT |
70
  LCD_FUNCTION_2LINE |
71
  LCD_FUNCTION_5X7 );
72
  
73
  // Display ein / Cursor aus / Blinken aus
74
  lcd_command( LCD_SET_DISPLAY |
75
  LCD_DISPLAY_ON |
76
  LCD_CURSOR_OFF |
77
  LCD_BLINKING_OFF);
78
  
79
  // Cursor inkrement / kein Scrollen
80
  lcd_command( LCD_SET_ENTRY |
81
  LCD_ENTRY_INCREASE |
82
  LCD_ENTRY_NOSHIFT );
83
  
84
  lcd_clear();
85
}
86
87
////////////////////////////////////////////////////////////////////////////////
88
// Sendet ein Datenbyte an das LCD
89
void lcd_data( uint8_t data )
90
{
91
  LCD_PORT |= (1<<LCD_RS);    // RS auf 1 setzen
92
  
93
  lcd_out( data );            // zuerst die oberen,
94
  lcd_out( data<<4 );         // dann die unteren 4 Bit senden
95
  
96
  _delay_us( LCD_WRITEDATA_US );
97
}
98
99
////////////////////////////////////////////////////////////////////////////////
100
// Sendet einen Befehl an das LCD
101
void lcd_command( uint8_t data )
102
{
103
  LCD_PORT &= ~(1<<LCD_RS);    // RS auf 0 setzen
104
  
105
  lcd_out( data );             // zuerst die oberen,
106
  lcd_out( data<<4 );           // dann die unteren 4 Bit senden
107
  
108
  _delay_us( LCD_COMMAND_US );
109
}
110
111
////////////////////////////////////////////////////////////////////////////////
112
// Sendet den Befehl zur Löschung des Displays
113
void lcd_clear( void )
114
{
115
  lcd_command( LCD_CLEAR_DISPLAY );
116
  _delay_ms( LCD_CLEAR_DISPLAY_MS );
117
}
118
119
////////////////////////////////////////////////////////////////////////////////
120
// Sendet den Befehl: Cursor Home
121
void lcd_home( void )
122
{
123
  lcd_command( LCD_CURSOR_HOME );
124
  _delay_ms( LCD_CURSOR_HOME_MS );
125
}
126
127
////////////////////////////////////////////////////////////////////////////////
128
// Setzt den Cursor in Spalte x (0..15) Zeile y (1..4)
129
130
void lcd_setcursor( uint8_t x, uint8_t y )
131
{
132
  uint8_t data;
133
  
134
  switch (y)
135
  {
136
    case 1:    // 1. Zeile
137
    data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
138
    break;
139
    
140
    case 2:    // 2. Zeile
141
    data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
142
    break;
143
    
144
    case 3:    // 3. Zeile
145
    data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
146
    break;
147
    
148
    case 4:    // 4. Zeile
149
    data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
150
    break;
151
    
152
    default:
153
    return;                                   // für den Fall einer falschen Zeile
154
  }
155
  
156
  lcd_command( data );
157
}
158
159
////////////////////////////////////////////////////////////////////////////////
160
// Schreibt einen String auf das LCD
161
162
void lcd_string( const char *data )
163
{
164
  while( *data != '\0' )
165
  lcd_data( *data++ );
166
}
167
168
////////////////////////////////////////////////////////////////////////////////
169
// Schreibt ein Zeichen in den Character Generator RAM
170
171
void lcd_generatechar( uint8_t code, const uint8_t *data )
172
{
173
  // Startposition des Zeichens einstellen
174
  lcd_command( LCD_SET_CGADR | (code<<3) );
175
  
176
  // Bitmuster übertragen
177
  for ( uint8_t i=0; i<8; i++ )
178
  {
179
    lcd_data( data[i] );
180
  }
181
}

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

snayer2311 schrieb:
> nach deiner großen hilfe :) sehe dann das routinen programm etwa so aus
> also wäre es  zumindest das richtig


nein.


>   DDRA = 0xff;
>   PORTA = (1<<LCD_PORT);
>   DDRB = 0xff;
>   PORTB = (1<<LCD_CTRL_PORT);

was soll das denn sein?

>  // verwendete Pins auf Ausgang schalten
>  uint8_t pins = (0x0F << LCD_DB) |           // 4 Datenleitungen
>  (1<<LCD_RS) |                // R/S Leitung
>  (1<<LCD_EN);                 // Enable Leitung
>  LCD_DDR |= pins;

das geht so nicht mehr. Denn LCD_RS und LCD_EN liegen ja nicht mehr am 
LCD_PORT für den LCD_DDR zuständig ist.

>  // initial alle Ausgänge auf Null
>  LCD_PORT &= ~pins;

geht auch nicht mehr.

vergiss die pins Variable. Setze die Pisn einzeln. So wie du das gelernt 
hast. Das muss nicht hoch-optimiert ablaufen.

> void lcd_command( uint8_t data )
> {
>   LCD_PORT &= ~(1<<LCD_RS);    // RS auf 0 setzen

LCD_RS liegt nicht mehr am LCD_PORT

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
// LCD Steuersignale RS und EN am Control Port
2
3
//  LCD RS      <-->  PORTC Bit PB2     (RS: 0=Data, 1=Command)
4
#define LCD_RS        PB2
5
6
//  LCD EN      <-->  PORTC Bit PB0     (EN: 1-Impuls für Daten)
7
#define LCD_EN        PB0

ist Ernst zu nehmen!
Überall, wo LCD_RS oder LCD_EN vorkommt, muss eingegriffen werden!
Denn die beiden Leitungen sind nicht mehr über LCD_PORT zu schalten, 
sondern über LCD_CTRL_PORT. Und das betrifft ALLE Belange! Sei es das 
Schalten auf Ausgang über das DDRx Register, sei es das setzen auf 1, 
sei es das setzen auf 0, etc. etc. Überall! Quer durch den ganzen Code.

von snayer2311 (Gast)


Angehängte Dateien:

Lesenswert?

Ich hab mal alles nochmal von neu begonnen und mir selber jetzt einzelne 
Codes geschrieben. Bei der Initialisierung war ich mir nicht sicher. 
Dafür hab ich hoffe mal darauf geachtet das die die Pinne RS und EN 
nicht über den Datenbus PORTA laufen. Ich stelle dies mal als 
worddokument mit rein. Noch weissi ich nicht ob es funktioniert werde es 
mal morgen testen.

von holger (Gast)


Lesenswert?

>Ich hab mal alles nochmal von neu begonnen und mir selber jetzt einzelne
>Codes geschrieben.

Also mein Compiler frisst keine Word Dokumente.

von snayer2311 (Gast)


Lesenswert?

ich weiss hab mom kein atmel wegen windows 8. mein system hat gerade 
gestreikt bei der installation von avr studio -.-

von Karl H. (kbuchegg)


Lesenswert?

?
Soll das heißen du hast das direkt im Word geschrieben?

Dann schau ich gar nicht erst rein (würde ich sowieso nicht tun. Bin 
doch nicht wahnsinnig und lade mir ein Word-File down).

Lass es erst mal durch den Compiler, behebe alle Probleme und DANN sehen 
wir weiter. So hat das keinen Sinn.

von snayer2311 (Gast)


Lesenswert?

okay bin schon dabei^^

von snayer2311 (Gast)


Angehängte Dateien:

Lesenswert?

bitte die dateien^^

von snayer2311 (Gast)


Lesenswert?

diese datei ist falsch initialisiert werde es überarbeiten
hab jetzt meine fehler soweit selber heraus gebessert. Werde es dann 
komplett wieder hochlasen^^

von Karl H. (kbuchegg)


Lesenswert?

Die Funktion hier
1
////////////////////////////////////////////////////////////////////////////////
2
// Sendet eine 4-bit Ausgabeoperation an das LCD
3
static void lcd_out(uint8_t data)
4
{
5
  data &= 0xF0;
6
  LCD_PORT &= ~(0xF0 >> (4 - LCD_DB1)); //obere 4 Bit maskieren
7
8
  LCD_PORT &= ~(0xF0 >> (4 - LCD_DB2)); //Maske löschen
9
  LCD_PORT &= ~(0xF0 >> (4 - LCD_DB3));
10
  LCD_PORT &= ~(0xF0 >> (4 - LCD_DB4));
11
  LCD_PORT &= ~(0xF0 >> (4 - LCD_DB5));
12
  LCD_PORT &= ~(0xF0 >> (4 - LCD_DB6));
13
  LCD_PORT &= ~(0xF0 >> (4 - LCD_DB7));
14
15
  LCD_PORT &= (data >> (4 - LCD_DB1)); //Bits setezn
16
  LCD_PORT &= (data >> (4 - LCD_DB2));
17
  LCD_PORT &= (data >> (4 - LCD_DB3));
18
  LCD_PORT &= (data >> (4 - LCD_DB4));
19
  LCD_PORT &= (data >> (4 - LCD_DB5));
20
  LCD_PORT &= (data >> (4 - LCD_DB6));
21
  LCD_PORT &= (data >> (4 - LCD_DB7));
22
  
23
24
}

ist auch kompletter Unsinn.
Was ist ihre eigentliche Aufgabe?
Ihre AUfgabe ist es 4(!) Bit auszugeben! Warum 4? Weil in diesem Code 
das LCD im 4 Bit Modus betrieben wird. D.h. 1 Byte wird so zum LCD 
gesendet, dass die 8 Bit in 2 Teile zu je 4 Bit aufgeteilt wird und dann 
diese 4 Bit getrennt voneinander in 2 Aktionen übertragen werden.
Und genau für letzteres, das anlegen von 4 Bits an die Datenleitungen, 
ist diese Funktion zuständig.

Jetzt zähl mal deine Bit-Setz Aktionen. Wieviele sind das? Das sind 
nicht 4. Das sind interesssanterweise aber auch nicht 8, wie man es bei 
einem Byte erwarten würde. Nein, das sind 7. Wieso 7? 7 macht in diesem 
Zusammenhang überhaupt keinen Sinn.

Halte dich an die Vorlage und änder nicht gleich alles um. Wenn der Code 
erst mal für den 4 Bit Modus ausgelegt ist, dann bring ihn erst mal 
damit mit deiner Hardware zum laufen. Und erst dann, wenn er läuft, dann 
änderst du den Rest. Du änderst im Moment schon zu viel, ohne dass du 
die Änderungen testen kannst.


Das hier
1
void lcd_init(void)
2
{
3
  //verwendete Pins auf Ausgang schalten
4
5
  LCD_DDR = 0xff;
6
  LCD_PORT = 0x00;
7
  
8
  LCD_CTRL_PORT = 0x00;
9
  LCD_CTRL_DDR = 0xff;

ist auch schelcht. Du willst an dieser Stelle NUR und ausschliesslich 
die Bits vom jeweiligen Port bearbeiten, die du auch tatsächlich 
brauchst! Solche Rundumsdchlagzuweisungen sorgen regelmässig für Ärger. 
Am Control Port brauchst du nur 2 Bits, nicht alle 8. Die restlichen 6 
gehen dich nichts an, also lass sie in Ruhe!
1
  LCD_CTRL_PORT &= ~( (1<<LCD_RS) | (1<<LCD_EN));
2
  LCD_CTRL_DDR  |= (1<<LCD_RS) | (1<<LCD_EN);

Selbiges für die Datenleitungen.
Erstens brauchst du nur 4 (wegen dem 4 Bit Modus), zweitens lass die 
restlichen 4 Leitungen in Ruhe! Der LCD-Code kann nicht wissen, und er 
will es auch gar nicht wissen, ob da an den nicht von ihm benutzen 
Leitungen an diesem Port irgendwas angeschlossen ist oder nicht. Im 
Zweifelsfall geht er davon aus, dass da etwas angeschlossen ist, und das 
er sich von diesen Leitungen fern halten soll. Die Devise heißt: 
defensiv arbeiten! Bei Funktionsgruppen, die Standard Character haben 
(also in x Projekten eingesetzt werden) ist so etwas das um und auf zur 
Wiederverwendbarkeit.

: Bearbeitet durch User
von snayer2311 (Gast)


Lesenswert?

Im moment bekomme ich die richtigen Signale die ich für das schreiben 
und Empfangen bekommen möchte. Also die funktion enable funktioniert 
schonmal.
Auch sehe ich dass daten verschickt werden nach dem das Enable gesetzt 
wurden ist. Jedoch wenn ich das schreiben möchte kommmt es tdem nicht 
bis zum display an

void lcd_init(void)
{
  //verwendete Pins auf Ausgang schalten

  LCD_DDR =0xf0;// PORTA Pin 4-7 auf Ausgang gestellt
  LCD_CTRL_PORT = LCD_CTRL_PORT & ~( (1<<LCD_RS) | (1<<LCD_EN));
 // An PortB wird RS und EN zur Sichherheit auf Low geschaltet
  LCD_CTRL_DDR=0x05;      }

static void lcd_out(uint8_t data)
{
  LCD_PORT = data & 0xf;
  #ifndef _mydebug
  _delay_us(LCD_WRITEDATA_US);      //kurze Pause
  #endif
}
static void lcd_enable(void)
{
  LCD_CTRL_PORT |= (1 << LCD_EN);  //Enable auf 1 setzen
  _delay_us(LCD_ENABLE_US);       //kurze Pause
  LCD_CTRL_PORT &= ~(1 << LCD_EN); //Enable auf 0 setzen

void lcd_data(uint8_t data)
{
  LCD_CTRL_PORT |= ~(1 << LCD_RS);   //RS auf 0 setzen
  lcd_out(data & 0xf0);             //zuerst die oberen 0b11110000
  _delay_us(LCD_COMMAND_US);
  lcd_enable();
  lcd_out(data << 4);             //dann die unteren
  _delay_us(LCD_COMMAND_US);
  lcd_enable();
}
void lcd_command(uint8_t data)
{
  LCD_CTRL_PORT &= ~(1<<LCD_RS); // RS auf 0 setzen

  lcd_out( data & 0xf0);              // zuerst die oberen, 0b11110000
  lcd_enable();
  lcd_out( data << 4);           // dann die unteren 4 Bit senden
  lcd_enable();
}
void lcd_string(const char *data)
{
  while (*data != '\0')
  lcd_data(*data++);

}

von Hubert G. (hubertg)


Lesenswert?

Wollte das mal praktisch mit dem Board probieren, bin mir aber nicht 
klar welchen Kontroller du verwendest. Im *.c seht was von Mega8?

von snayer2311 (Gast)


Lesenswert?

nee atmega32pu16

von snayer2311 (Gast)


Angehängte Dateien:

Lesenswert?

ich hab das jetzt mal versucht einfacher zu schreiben jedoch wenn ich 
dieses programm debuggen möchte hängt er in der delay.h fest und macht 
gar nichts mehr
jetzt weiss ich nicht mehr wo da der fehler jetzt sein könnte

von snayer2311 (Gast)


Lesenswert?

snayer2311 schrieb:
> ich hab das jetzt mal versucht einfacher zu schreiben jedoch wenn
> ich
> dieses programm debuggen möchte hängt er in der delay.h fest und macht
> gar nichts mehr
> jetzt weiss ich nicht mehr wo da der fehler jetzt sein könnte

verwerden das display hd44780

von Karl H. (kbuchegg)


Lesenswert?

Dein Code wird immer schlimmer und immer falscher.

Wirf ihn weg und hol dir vom Peter Fleury die LCD-Routinen.
Die kannst du auf einzelne Pins konfigurieren.
In ein paar Monaten, wenn du dazu gelernt hast, kannst du es ja noch mal 
probieren. Aber im Moment sind deine Änderungen so ziemlich alle 
kontraproduktiv bis einfach nur falsch.

: Bearbeitet durch User
von snayer2311 (Gast)


Angehängte Dateien:

Lesenswert?

von wegen wegwerfen-.- der code ist um einiges einfacher zu verstehen 
als das was im internet zu verstehen ist!

Ich bin fertig mit mein Projekt und siehe da es funktiert. Es lag 
hauptsächlich an die falsche Initialisierung des Displays. Aber ich 
leugne nicht dass es nicht nur der eine Fehler gewesen ist. Ich glaube 
dass besonders du Karl Heinz das eine oder andere mal mit dem Kopf 
schütteln musstest. Sorry im Vorfeld AVR Programmierung ist für mich was 
neu ich programmiere selten hardware spezifisch deswegen musste ich oft 
hier um hilfe fragen. Manches hat mir geholfen manches naja ging so eher 
weniger:(
Ich möchte mich auch dafür entschuldigen dass ich einfach zu viele 
Datein reingestellt haben die das Maß an Grenzen deutlich überschritten. 
Ich wusste das gerade nicht.

Nun gut, das wollte ich nochmal kurz loswerden. Jetz zu meinem Projekt. 
Als Hilfe für andere die dann das selbe Problem wie ich hatte stelle ich 
mein Projekt hier rein. Es Funktioniert für das Display HD448780! Bei 
den anderen Displays weiss ich es leider nicht. Denke mal da muss man 
nur die Initialisierung ändern. Findet man alles im Handbuch.

Was nicht gerade funktioniert ist dass ich keine Umlaute ausgeben kann. 
Er erkennt z.B kein ä oder ein ß. Ich weiss i-was mit dem Ascii-Code 
programmiert werden muss. Wie genau das funktionieren soll weiss ich 
momentan nicht. Wäre cool wenn mir da einer eine Lösung dafür hätte.

lg
snayer2311

von Hubert G. (hubertg)


Lesenswert?

Was für Zeichen werden angezeigt?
Es haben nicht alle Display den gleichen ROM-Code.
Richtig ausgeben sollte es ein Display mit den ROM-Code A2.

von snayer2311 (Gast)


Lesenswert?

Hubert G. schrieb:
> Was für Zeichen werden angezeigt?
> Es haben nicht alle Display den gleichen ROM-Code.
> Richtig ausgeben sollte es ein Display mit den ROM-Code A2.

bei ä kommt dann ein mikcro zeichen
sowie auch jeweils bei den anderen Umlaute wie ö ü oder ß.

wie kann man das best möglich programmieren?

von holger (Gast)


Lesenswert?

>sowie auch jeweils bei den anderen Umlaute wie ö ü oder ß.

Dann vermeide Umlaute oder bau dir eine Übersetzungstabelle.
1
#if DEFAULT_TABLE
2
 // Standard conversion table used by most displays
3
 switch(ps)
4
  {
5
   case 'ä' : ps = 0xE1; break;
6
   case 'ö' : ps = 0xEF; break;
7
   case 'ü' : ps = 0xF5; break;
8
   case 'ß' : ps = 0xE2; break;
9
   case '°' : ps = 0xDF; break;
10
   case 'µ' : ps = 0xE4; break;
11
   case 'Ä' : ps = 0x00; break;  // Point to CG-RAM
12
   case 'Ö' : ps = 0x01; break; // self defined characters
13
   case 'Ü' : ps = 0x02; break;
14
  }
15
#endif
16
17
 return ps;

von snayer2311 (Gast)


Lesenswert?

wie setze ich diese Tabelle in meiner Funktion ein direkt bei 
lcd_string?

von Karl H. (kbuchegg)


Lesenswert?

snayer2311 schrieb:
> wie setze ich diese Tabelle in meiner Funktion ein direkt bei
> lcd_string?

Gar nicht.

Du machst dir eine Funktion lcd_char, welche 1 Zeichen ausgibt und 
gegebenfalls die Umsetzung macht
1
////////////////////////////////////////////////////////////////////////////////
2
// Schreibt ein Zeichen aufs LCD
3
4
void lcd_char( char ps )
5
{
6
  switch(ps)
7
  {
8
   case 'ä' : ps = 0xE1; break;
9
   case 'ö' : ps = 0xEF; break;
10
   case 'ü' : ps = 0xF5; break;
11
   case 'ß' : ps = 0xE2; break;
12
   case '°' : ps = 0xDF; break;
13
   case 'µ' : ps = 0xE4; break;
14
   case 'Ä' : ps = 0x00; break;  // Point to CG-RAM
15
   case 'Ö' : ps = 0x01; break; // self defined characters
16
   case 'Ü' : ps = 0x02; break;
17
  }
18
  lcd_data(ps);
19
}

und benutzt dann diese Funktion überall dort, wo ein Zeichen auszugeben 
ist
1
////////////////////////////////////////////////////////////////////////////////
2
3
void lcd_string(const char *data)
4
{
5
  while (*data != '\0')
6
    lcd_char(*data++);
7
}

der Grund warum da eine eigene Funktion fällig wird liegt darin, dass du 
die Umsetzung nicht in lcd_data machen kannst, da lcd_data auch für 
andere Ausgaben benötigt wird.

von Karl H. (kbuchegg)


Lesenswert?

Hast du eigentlich deine lcd_init Funktion schon gesäubert?
Im letzten C-File sah die noch furchtbar aus.

von snayer2311 (Gast)


Lesenswert?

Karl Heinz schrieb:
> Hast du eigentlich deine lcd_init Funktion schon gesäubert?
> Im letzten C-File sah die noch furchtbar aus.

das sind meine initialisierungen
PORTA = 0x00;  // Display ON/OFF oberes Nibble
  enable();    // Enable Funktion einfügen

  PORTA = 0xf0;  // Display ON/OFF unteres Nibble >>> Display ein, 
Cursor ein, Cursor blinken
  enable();    // Enable Funktion einfügen

  PORTA = 0x00;  // Clear Display oberes Nibble
  enable();    // Enable Funktion einfügen

  PORTA = 0x10;  // Clear Display unteres Nibble >>> Display löschen, 
Cursor an 1. Stelle
  enable();    // Enabel Funktion einfügen

  PORTA = 0x00;  // Entry Mode Set oberes Nibble
  enable();    // Enable Funktion einfügen

  PORTA = 0x60;  // Entry Mode Set unteres Nibble >>> Cursor 
Auto-Increment
  enable();    // Enable Funktion einfügen

  lcd_clear();

von snayer2311 (Gast)


Lesenswert?

danke hat funktionier :-)

von snayer2311 (Gast)


Lesenswert?

>
> void lcd_char( char ps )
> {
>   switch(ps)
>   {
>    case 'ä' : ps = 0xE1; break;
>
>
kurz zur tabelle ich verstehe gerade nicht wie du
auf den code bei ä auf 0xE1 kamst?
hast du den hexadezimal code zunächst als binär code umgewandelt also 
für ä schreibst du dann 11100001?
und diesen code lieste dann von der tabelle ab?

von Karl H. (kbuchegg)


Lesenswert?

snayer2311 schrieb:
> Karl Heinz schrieb:
>> Hast du eigentlich deine lcd_init Funktion schon gesäubert?
>> Im letzten C-File sah die noch furchtbar aus.
>
> das sind meine initialisierungen
> PORTA = 0x00;  // Display ON/OFF oberes Nibble
>   enable();    // Enable Funktion einfügen
>
>   PORTA = 0xf0;  // Display ON/OFF unteres Nibble >>> Display ein,
> Cursor ein, Cursor blinken
>   enable();    // Enable Funktion einfügen
>
>   PORTA = 0x00;  // Clear Display oberes Nibble
>   enable();    // Enable Funktion einfügen
>
>   PORTA = 0x10;  // Clear Display unteres Nibble >>> Display löschen,
> Cursor an 1. Stelle
>   enable();    // Enabel Funktion einfügen
>
>   PORTA = 0x00;  // Entry Mode Set oberes Nibble
>   enable();    // Enable Funktion einfügen
>
>   PORTA = 0x60;  // Entry Mode Set unteres Nibble >>> Cursor
> Auto-Increment
>   enable();    // Enable Funktion einfügen
>
>   lcd_clear();

Und warum steht da jetzt PORTA direkt drinnen?
Stell dir einfach mal vor, du hast irgendwann ein anderes Board bei dem 
das LCD nicht mehr am Port A hängt, sondern an einem anderen Port.

genau dazu gibt es die
1
#define LCD_PORT  PORTA

Ausserdem: warum setzt du da die Bits direkt? Dazu gibt es eine 
Funktion, die darüber Bescheid weiss, welche Bits auf welche Portpins zu 
verteilen sind!
Und für die Aufteilung in die beiden 4 Bit Nibbles gibt es ebenfalls 
eine Funktion. Nämlich lcd_command.

Zb. nach dem Kommando 'LCD löschen' musst du eine Wartepause einlegen, 
denn das LCD braucht dazu etwas Zeit. lcd_clear weiß das und 
berücksichtigt das. Das hier
1
  PORTA = 0x00;  // Clear Display oberes Nibble
2
>   enable();    // Enable Funktion einfügen
3
> 
4
>   PORTA = 0x10;  // Clear Display unteres Nibble >>> Display löschen, 
5
> Cursor an 1. Stelle
6
>   enable();    // Enabel Funktion einfügen
berücksichtigt gar nichts.

Kurz und gut:
Dein Code funktioniert jetzt, mit genau DIESEM Display und genau DIESEM 
Port und genau DIESER Anschlussbelegung. Verändere irgendetwas davon, 
und du musst durch deinen kompletten Code durchgehen und nach den 
notwendigen Anpassungen suchen.
Das kann es aber nicht sein.
Wird irgendwas verändert, zb ein anderer Port für die Datenleitungen, 
dann muss es reichen, dafür den
1
#define LCD_PORT PORTD
zu verändern und der Rest des Codes wird vom Compiler anhand dieses 
#define angepasst.

: Bearbeitet durch User
von snayer2311 (Gast)


Lesenswert?

#define  LCD_PORT  PORTC
#define  LCD_DDR  DDRC

#define  LCD_CTRL_PORT    PORTB
#define  LCD_CTRL_DDR    DDRB

habe ich schon definiert :)

von Karl H. (kbuchegg)


Lesenswert?

snayer2311 schrieb:
> #define  LCD_PORT  PORTC
> #define  LCD_DDR  DDRC
>
> #define  LCD_CTRL_PORT    PORTB
> #define  LCD_CTRL_DDR    DDRB
>
> habe ich schon definiert :)

Ja.
Aber du musst das auch in deinem Code BENUTZEN!
Das kann nicht sein, dass im Code

   PORTA = ....

steht.
Da muss

  LCD_PORT = ....

stehen!

(Jetzt mal abgesehen davon, dass das so im Code der Init Funktion 
überhaupt nicht stehen soll. Denn um 1 Nibble auszugeben gibt es die 
Funktion lcd_out für die erste Initialisierung zur Umshcaltung in den 
4-Bit Modus und ab dem Zeitpunkt ist lcd_command ALLEINIG dafür 
zuständig Kommandos an das LCD zu übergeben)


Ich scheine irgendwie ein Problem damit zu haben, dir klar zu machen, 
dass es nicht reicht, wenn ein Code so irgendwie funktioniert. 
Codequalität definiert sich auch dadurch, wie gut er wartbar bzw. an 
andere Gegebenheiten adaptierbar ist. Dazu gehört auch, dass man 
'Wissen', wie zb Portbenutzung und Belegung NICHT quer über x Funktionen 
verstreut, sondern an einer Stelle sammelt.

: Bearbeitet durch User
von snayer2311 (Gast)


Lesenswert?

achso ah jetzt habe ich verstanden was du meintest jaaa hast recht
stimmt dass ist mir gerade in meinem projekt nicht aufgefallen werde das 
selbstverständlich überarbeiten.


Hoffe mal dann ist alles komplett und das Kapitel lcd-Display und vorab 
endgültig abgeschlossen^^

von snayer2311 (Gast)


Angehängte Dateien:

Lesenswert?

Hier ist mein projekt:)


gerne würde ich wissen ob es auch möglich wenn ich ein langen text in 
der ersten spalte ausgeben möchte dass mir das display auch diesen 
anzeigt:)

von snayer2311 (Gast)


Angehängte Dateien:

Lesenswert?

Nun zeigt meine LCD-Anzeige auch den kompletten Text für einige Sekunden 
wie bei einer Werbung. Jedoch zeigt er nicht alles bis zu einer 
bestimmten Anzahl von Zeichen. Dies liegt an dem Display da dieser nicht 
so viele Zeichen aufnhemen kann wie mans gerne hätte.

lg

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.