Forum: Mikrocontroller und Digitale Elektronik LCD Display


von Christian D. (Gast)


Lesenswert?

hallo,

will ein LCD-Display ansteuern, habe nun gerade nach dem Datenblatt die 
Init geschrieben, nun möchte ich mit der schreib Funktion Anfangen.
Nun stehe ich vor einem Problem und zwar muss ich ja zuerst die DD-RAM 
Adresse setzen dazu steht im Datenblatt:
Set DDRAM address: RS = L, RW = L, DB7 = H, DB6 = AC6, DB5 = AC5, DB4 = 
AC4, DB3 = AC3, DB2 = AC2, DB1 = AC1, DB0 = AC0

Also mit L ist ja Low gemeint also 0, mit H High also 1,
nur was soll ich dann bei AC0 - 6 machen? 0 oder 1 ?

von Michael U. (Gast)


Lesenswert?

Hallo,

naja, vielleicht Datenblatt auch verstehen? ;-)))

AC6...AC0 ist die gewünschte DDRAM-Adresse, an der Du demnächst ein 
Zeichen anzeigen willst.
Die Zuordnung der Adressen zur Darstellung im Display (Zeile, Position) 
steht auch irgendwo im Datenblatt.
Bei HD44xxx-kompatiblen meist Zeile 1 ab 0x00, Zeile 2 ab 0x40 usw.
0x00 -> 00000000
0x40 -> 01000000
DB0...DB6 davon sind Deine Bits für AC0...AC6.
AC soll wohl Adress-Counter heißen oder so.

Gruß aus Berlin
Michael

von *.* (Gast)


Lesenswert?

AC0 - 6 ist die Adresse.

DB7,DB6,......,DB0
1,0,0,0,0,0,0,0 für Adresse 0,
1,0,0,0,0,0,0,1 für Adresse 1 usw.

von Christian D. (Gast)


Lesenswert?

achso ok, ich hab das jetzt so gemacht, es wird aber nichts angezeigt, 
ist das so überhaupts richtig?


// set DD-RAM address
PORTD |= (0 << E);
PORTD |= (0 << RS);
PORTD |= (0 << RW);

PORTB |= (1 << D0);
PORTB |= (0 << D1);
PORTB |= (0 << D2);
PORTB |= (0 << D3);
PORTB |= (0 << D4);
PORTB |= (0 << D5);
PORTD |= (0 << D6);
PORTD |= (1 << D7);


// write data
PORTD |= (0 << E);
PORTD |= (1 << RS);
PORTD |= (0 << RW);

PORTB |= (0 << D0);
PORTB |= (0 << D1);
PORTB |= (0 << D2);
PORTB |= (0 << D3);
PORTB |= (0 << D4);
PORTB |= (0 << D5);
PORTD |= (0 << D6);
PORTD |= (1 << D7);

PORTD |= (1 << E);

von *.* (Gast)


Lesenswert?

Man kann die Fliege auch mit dem Elefanten erschlagen ;)

E muss ein- und  wieder ausgeschaltet werden nachdem das Datenbyte 
angelegt wurde. Dann muss eine Pause mindestens 40µs, sehr wichtig, 
folgen.

von Johannes A. (Gast)


Lesenswert?

Was ich nicht verstehe:

DIESE Frage wird hier im Forum doch inzwischen so zirke 5mal pro Woche 
gestellt. Und immer wieder geduldig von irgendjemandem beantwortet.

Ich habe dazu selber schon einen kompletten funktionierenden Code 
gepostet.

Aber trotzdem, immer wieder neu: "Wie geht LCD-Ansteuerung?"

Meine Antwort: Ohne RTFM und für 2Cent Phantasie sowieso nicht.

Und keine Bange, ich werde mich nie wieder in dieses Thema einschalten.

Gruß Johannes

von Christian D. (Gast)


Lesenswert?

sorry aber wenn mir das alles nicht weiterhilft?

hier mein quelltext:

#include <avr/io.h>
#include <uart.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <util/delay.h>  // headerdatei für _delay_ms();
#include <avr/wdt.h>  // headerdatei für watchdog
#include "main.h"

#define SYSCLK    3686400UL  //3686400 8000000
#define BAUD    300UL
#define UBRR_BAUD  ((SYSCLK/(16*BAUD))-1)
#define VCC 5

//#define ADC_VREF_TYPE 0x00  //External VREF
//#define ADC_VREF_TYPE 0x40  //AVCC
#define ADC_VREF_TYPE 0xc0  //Interne 2,56V Spannung

#define D0 PB0
#define D1 PB1
#define D2 PB2
#define D3 PB3
#define D4 PB4
#define D5 PB5
#define D6 PD6
#define D7 PD7

#define RS PD4
#define RW PD3
#define E  PD2

int crash;
int light;
int wert;
double temp;

int count = 0;
int sec = 0;
int min = 42;
int hour = 20;
int day = 0;
int month = 0;

ISR( TIMER0_OVF_vect )
{
  count++;
  if (count == 1800) {  // (Takt / 8) / 256
  sec++;
  count = 0;
  if (sec == 60) {
  min++;
  sec = 1;
  }
  if (min == 60) {
  hour++;
  min = 0;
  }
  if (hour == 24) {
  day++;
  hour = 1;
  }
  if (day == 30) {
  month++;
  day = 1;
  }
  }
}



int main(void)
{

int status = 0;


// LCD Init Start

DDRB = 0xff; // PORTB als Ausgang
DDRD = 0xff; // PORTD als Ausgang

// Function Set
PORTD |= (0 << E);
PORTD |= (0 << RS);
PORTD |= (0 << RW);

PORTB |= (0 << D0);
PORTB |= (0 << D1);
PORTB |= (1 << D2); // Display On
PORTB |= (0 << D3); // 1 Line Mode
PORTB |= (1 << D4);
PORTB |= (1 << D5);
PORTD |= (0 << D6);
PORTD |= (0 << D7);
_delay_us(40);

// Display On
PORTD |= (0 << E);
PORTD |= (0 << RS);
PORTD |= (0 << RW);

PORTB |= (1 << D0);
PORTB |= (1 << D1);
PORTB |= (1 << D2);
PORTB |= (1 << D3);
PORTB |= (0 << D4);
PORTB |= (0 << D5);
PORTD |= (0 << D6);
PORTD |= (0 << D7);
_delay_us(40);

// Display clear
PORTD |= (0 << E);
PORTD |= (0 << RS);
PORTD |= (0 << RW);

PORTB |= (1 << D0);
PORTB |= (0 << D1);
PORTB |= (0 << D2);
PORTB |= (0 << D3);
PORTB |= (0 << D4);
PORTB |= (0 << D5);
PORTD |= (0 << D6);
PORTD |= (0 << D7);
_delay_ms(2);

// Entry mode set
PORTD |= (0 << E);
PORTD |= (0 << RS);
PORTD |= (0 << RW);

PORTB |= (1 << D0);
PORTB |= (1 << D1);
PORTB |= (1 << D2);
PORTB |= (0 << D3);
PORTB |= (0 << D4);
PORTB |= (0 << D5);
PORTD |= (0 << D6);
PORTD |= (0 << D7);
_delay_us(40);

// Init Ende

while (status == 0)
{

// set DD-RAM address
PORTD |= (0 << E);
PORTD |= (0 << RS);
PORTD |= (0 << RW);

PORTB |= (1 << D0);
PORTB |= (0 << D1);
PORTB |= (0 << D2);
PORTB |= (0 << D3);
PORTB |= (0 << D4);
PORTB |= (0 << D5);
PORTD |= (0 << D6);
PORTD |= (1 << D7);
_delay_us(40);

// write data
PORTD |= (0 << E);
PORTD |= (1 << RS);
PORTD |= (0 << RW);

PORTB |= (0 << D0);
PORTB |= (0 << D1);
PORTB |= (0 << D2);
PORTB |= (1 << D3);
PORTB |= (0 << D4);
PORTB |= (0 << D5);
PORTD |= (1 << D6);
PORTD |= (1 << D7);
_delay_us(44);

PORTD |= (1 << E);
PORTD &= ~( 1 << E);

_delay_us(40);

}
// Schleifen Ende

}

von Michael U. (Gast)


Lesenswert?

Hallo,

@Johannes A.:
ich verstehe es auch nicht.......

Datenblatt Controller
Timingdiagramm lesen und verstehen!

E ist der Übernahme-Eingang.
Der ist immer L
Dann Daten und RS und RW passend setzen

DANN E auf H, mindestens ca. 750ns auf H lassen, dann wieder auf L

Während E auf H ist, müssen Daten, RS, RW stabil am Display anliegen.
Dann gibt es noch Haltezeiten vor und nach dem E-Impuls, die sind aber 
bei üblichen AVR-Taktfrequenzen unkritisch.

Außerdem fällt es sehr schwer Deinen Code zu lesen. Schau Dir mal 
einfach an, wie andere es machen. Mache Dinge sind in einer Zeile 
zusammen merklich lesbarer.

Du steuerst das Display im 8-Bit-Mode an. Da kannman das Datenwort doch 
eher in eine OUT-Anweisung zusammenfassen.

Wenn ich ein "A" ans Display schicken will, schicke ich doch auch ein A 
und zerlege es nicht erst in einzelne Bits.

Auch schon hundertmal geschrieben: die 0-Schieberei ist witzlos.

PORTB |= (0 << D0);
PORTB |= (0 << D1);
PORTB |= (1 << D2); // Display On  Wieso hier Font auf 5x10`?
PORTB |= (0 << D3); // 1 Line Mode Warum? Ich denke, Du hast ein 2x16???
PORTB |= (1 << D4);
PORTB |= (1 << D5);
PORTD |= (0 << D6);
PORTD |= (0 << D7);

PORTB = 0x34; // Display On, 1 Zeile

finde ich lesbarer.

Gruß aus Berlin
Michael

von pumpkin (Gast)


Lesenswert?

darf man fragen warum du deine datenleitungen auf PB und PD 
aufsplittest? unkomfortabler geht es wirklich nicht.

du solltest dafür sorgen, dass du erst deine daten anlegst und dann 
executest.

pumpkin

von Johannes A. (Gast)


Lesenswert?

@Michael

Danke!

und @Christian D.

Sorry, aber wenn Du DIESEN Code nicht selber langsam echt krank findest,
wird Dir wohl kaum noch jemand helfen können...

Und Tschüss
Johannes

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.