Forum: Mikrocontroller und Digitale Elektronik LCD, Schieberegister, Timing-Verständnis?


von Santiago (Gast)


Lesenswert?

Hallo,

ich habe ein (recyceltes) LCD (das standardgemäß funktionieren könnte, 
aber ohne Datenblatt) an 2 Schieberegister angeschlossen.
Das eine ist für den 8bit Datenbus zuständig, das andere für die 
Steuerungsleitungen. Die Schieberegister bekommen die Bits von einer 
Tina23 via SPI rein gedrückt.

Die Initialisierung scheint zu klappen, denn nach dem Einschalten ist 
nur eine Zeile dunkel, nach der Initialisierungssequenz habe ich 2 
dunkle Zeilen.

Die Textübertragung klappt noch nicht.

Bislang mache ich es so, dass ich jeweils 2 Byte (Daten und Steuerung) 
zweimal übertrage. Bei der ersten Übertragung ist das enable-bit 
gesetzt, beim zweiten Mal wird es gelöscht (bei sonst identischen 
Daten).

Ist das vom Ansatz her richtig, oder müsste ich die Daten 3mal 
übertragen (und dann beim 2ten Mal enable einschalten)?
Ich habe es versuchsweise auch mal umgekehrt übertragen.

Ach ja, die Schieberegister bekommen den RCK-Puls nach dem Schieben von 
2 Bytes. Die Befehle habe ich mit einem "seriellen Debugger" (2 
Schieberegister mit LEDs an den Ausgängen) überprüft.

Falls die Frage schon mal gestellt wurde, bitte ich um Nachsicht, dass 
ich nicht alle Freds, die zu LCDs gefunden werden, gelesen habe.

von Peter D. (peda)


Lesenswert?

Ein Schieberegister ohne Latch reicht völlig:

Beitrag "Standard LCD über nur 3 Drähte"


Peter

von Santiago (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Peter,

danke für den Tip. Ich hatte eher gehofft, etwas über das Zeitverhalten 
von LCDs zu erfahren, bzw. darüber, wann denn die Daten verarbeitet 
werden.

Nun gut.

Habe mir also einen Treiber mit dem 74HC164 aufgebaut, alles 
angeschlossen und das Proggy für die Tina umgeschrieben, aber es will 
noch net.

Könnte bitte jemand das Programm mal kontrollieren und mir Viehtbäck 
geben, ob mein Fehler Programm ist, oder ich mich von meinem LCD 
verabschieden muss?!?

von BerndB (Gast)


Lesenswert?

Hallo,

haste den Kontrast auch richtig eingestellt ???

gruß BerndB

von Santiago (Gast)


Lesenswert?

Hallo,

> haste den Kontrast auch richtig eingestellt ???

Habe mir extra noch eine Huckepack-Platine mit einem Spannungsinverter 
gemacht, um beide Fälle der Kontrastspannung durchprobieren zu können.
Ob er richtig ist, kann ich nicht beurteilen. Bin Neuling in Sachen HW.
Ich sehe auf jeden Fall schwarze Balken und eine Veränderung nach der 
Initialisierung - insofern scheint die Kommunikation zumindest 
grundsätzlich zu klappen.

Ich habe es inzwischen auch mit diesem LCD probiert:
http://www.pollin.de/shop/detail.php?pg=NQ==&a=NzY3OTc4OTk=
Muss dazu sagen, dass ich das Folienkabel entfernt und ein Flachband 
angelötet habe. Das Flachband habe ich so beschaltet, dass das Enable 
des 2. Controllers nach DB7 kommt, sodass ich in den ersten Leitungen 
identische Belegung mit einem 2zeiligen Display habe.
Nach dem Umlöten habe ich mit einem Durchgangsprüfer alle Pins getestet, 
um einen evtl. Kurzschluss zu entdecken (Das 1.27 Raster war ziemlich 
heftig für mich - aber mit Löthonig habbichs schließlich hinbekommen).

Das WD-C2704 (nur ein Controller angeschlossen) verhält sich noch 
seltsamer, wie mein recyceltes Optrex. Anfangs hatte ich es frei auf dem 
Tisch liegen und da rasten die Buchstaben/Zeichen wild über mehrere 
Zeilen (eine blieb ganz schwarz). Dann habe ich es richtig angeschraubt 
und die Steuerplatine anders verkabelt - jetzt ist Ruhe.

So sehr Ruhe, dass nach den schwarzen Balken sich nix mehr ändert.

Da ich Neuling bin, bin ich recht verunsichert und weiß nicht, ob ich 
bei dem Umschreiben des Programmes, oder in der HW, oder beidem einen 
Fehler gemacht habe.

von Peter D. (peda)


Lesenswert?

Santiago wrote:

> danke für den Tip. Ich hatte eher gehofft, etwas über das Zeitverhalten
> von LCDs zu erfahren, bzw. darüber, wann denn die Daten verarbeitet
> werden.

So kritisch ist das Timing nicht.
Die Initsequenz lt. Datenblatt sollte eingehalten werden.
Der Enable-Puls sollte ~1µs lang sein.
Nach einem Byte ~40µs warten, nach Clear ~1,5ms.


> Könnte bitte jemand das Programm mal kontrollieren und mir Viehtbäck
> geben, ob mein Fehler Programm ist, oder ich mich von meinem LCD
> verabschieden muss?!?

Ginge es vielleicht als ZIP und mit Zeilenende (CR+LF)?


Peter

von Santiago (Gast)


Angehängte Dateien:

Lesenswert?

> So kritisch ist das Timing nicht.
> Die Initsequenz lt. Datenblatt sollte eingehalten werden.
> Der Enable-Puls sollte ~1µs lang sein.
> Nach einem Byte ~40µs warten, nach Clear ~1,5ms.

Ja, DIE timings konnte ich auch dem Datenblatt entnehmen.
Was mir fehlt, ist wann die LCD-Controller üblicherweise die Daten 
verarbeiten. Wird von Enable der Pegel ausgewertet, oder die steigende 
oder fallende Flanke getriggert ...
... auch wenn es vielleicht umständlich sein sollte - ich denke, es 
sollte auch mit den beiden 595ern von meinem ersten Treiber auch funzen. 
Wenn ich wüßte, worauf es ankommt, könnte ich das Proggy ja entsprechend 
umbauen.

Ich habe ein Baureihen-Handbuch von Optrex, weiß allerdings nicht, ob 
meines sich entsprechend verhält. Unter der Annahme dass dem so wäre, 
würde ich das Diagramm so interpretieren, dass die Busdaten bei jedem 
Flankenwexel von Enable verarbeitet werden.
Das würde meinem ursprünglichen Ansatz entgegen kommen, denn dann 
bräuchte ich dieselben Daten nicht mehrfach senden?!?

>> Könnte bitte jemand das Programm mal kontrollieren und mir Viehtbäck
>> geben, ob mein Fehler Programm ist, oder ich mich von meinem LCD
>> verabschieden muss?!?
>
> Ginge es vielleicht als ZIP und mit Zeilenende (CR+LF)?

OK, sorry - da ich GVim (zusammen mit TC) auch unter Windows nutze, 
spüre ich von derlei Ärgernissen nix.
Hoffe das Format passt jetzt. Habe einfach in vim den Dateityp auf "DOS" 
geändert und neu gespeichert.

von Santiago (Gast)


Angehängte Dateien:

Lesenswert?

... und hier die Sauce als ZIP.

von Santiago (Gast)


Lesenswert?

Hallo,

habe gerade nochmal nachgerechnet. Hat jetzt zwar nix mit der LCD 
Funktionalität zu tun, trotzdem sollte die Zeile 43 von clock.h wie 
folgt lauten:
1
#define TIMER_IPS ((uint16_t)(((uint16_t)((F_CPU / 0xFFFF) + 0.999) + 1 / 2) * 2))

von Peter D. (peda)


Lesenswert?

Santiago wrote:
> ... und hier die Sauce als ZIP.

Sieht fast o.k. aus.

Die Bittabelle im Progmem kann meines Wissens aber nicht als BITNO[i] 
gelesen werden. Schau mal ins Listing, ob da LD oder LPM verwendet wird.
Es tut aber auch nicht so weh, 8 Konstanten im SRAM zu belassen.


Peter

von Santiago (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Peter,

danke für Deine Unterstützung!

> Sieht fast o.k. aus.

;)

> Die Bittabelle im Progmem kann meines Wissens aber nicht als BITNO[i]
> gelesen werden. Schau mal ins Listing, ob da LD oder LPM verwendet wird.
> Es tut aber auch nicht so weh, 8 Konstanten im SRAM zu belassen.

Hm, ja ... leuchtet ein.
Habe die beiden Arrays (das Gleiche gilt ja auch für das Array der 
Monate?!?) aus dem Progmem entfernt, jetzt blinkt die 2. Zeile in 
unregelmäßigen Abständen. Allerdings komplett als schwarze Blöcke. 
Zeichen sind keine erkennbar.

Meine Assemblerkenntnisse lassen doch sehr zu wünschen übrig, jedoch 
wenn ich die richtige Stelle gefunden habe, wird dort LD verwendet.
Wollte erst ein diff posten, allerdings sind alle Adressen verschoben, 
sodass ein diff nicht wirklich Sinn macht. Deshalb also beide Listings.

von Santiago (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

möchte an dieser Stelle nochmals nachhaken, denn geschoben (mit dem 
74HC164) läuft bei mir noch immer nix.

Folgender Testaufbau:
Ein ATtiny2313 steuert (gleichzeitig) ein LCD parallel und eines seriell 
an. Beide sollen das gleiche ausgeben - aber nur bei dem mit paralleler 
Ansteuerung funktioniert es auch.

Im beigefügten Archiv ist, neben dem Schaltplan der Schiebung, jeweils 
eine Aufnahme mit einem LCD parallel und dem anderen seriell 
angesteuert. Damit es nicht heißt, es liegt an Kontrast, Anschluss oder 
LCD selber, habe ich die Displays auch vertauscht angeschlossen (bei dem 
großen ist Enable des zweiten Controllers nicht angeschlossen, deshalb 
bringt dessen erste Zeile Müll).

Die Platine mit dem Schieberegister habe ich mehrfach durchgemessen und 
auch nach Kurzschluss gesucht. Hardwäre-mäßig fällt mir an der Stelle 
nix mehr ein, was ich noch prüfen könnte.

Vielleicht liegt es ja doch an der Software (um die Richtigkeit der 
Bit-Definitionen überprüfen zu können, liegt der Schaltplan im Archiv, 
den ich per Durchgangsprüfer auch verifiziert habe).

Die betreffenden Funktionen sehen so aus:
1
#include <inttypes.h>
2
#include <avr/io.h>
3
#include <avr/pgmspace.h>
4
#include <util/delay.h>
5
#include "Config.h"
6
#define USE_SINGLE_PINS 1
7
8
static void lcdSample(void);
9
PROGMEM char defLine0[] = "LCD Module SRD-20 HP";
10
PROGMEM char defLine1[] = "20 Digits x 2 Lines.";
11
PROGMEM char clrLine[]  = "                    ";
12
//static uint8_t Bits[] = { 0x02, 0x04, 0x08, 0x01, 0x40, 0x20, 0x10, 0x80 };
13
static uint8_t Bits[] = { 0x80, 0x10, 0x20, 0x40, 0x01, 0x08, 0x04, 0x02 };
14
15
16
static void lcdWriteByte(uint8_t d, uint8_t isData) {
17
   uint8_t  i=0;
18
19
   /*
20
    * first the serial data ...
21
    */
22
   for (i=0; i < 8; i++) {
23
      PORT_LCD_SER_CLOCK &= (uint8_t) ~(1 << PIN_LCD_SER_CLOCK);
24
25
      if (d & Bits[i]) PORT_LCD_SER_DATA |= 1 << PIN_LCD_SER_DATA;
26
      else             PORT_LCD_SER_DATA &= (uint8_t) ~(1 << PIN_LCD_SER_DATA);
27
28
      PORT_LCD_SER_CLOCK |= 1 << PIN_LCD_SER_CLOCK;
29
   }
30
   
31
   if (isData) {
32
      PORT_LCD_SER_DATA |= 1 << PIN_LCD_SER_DATA;
33
      PORT_LCD_RS       |= 1 << PIN_LCD_RS;
34
   } else {
35
      PORT_LCD_SER_DATA &= (uint8_t) ~(1 << PIN_LCD_SER_DATA);
36
      PORT_LCD_RS       &= (uint8_t) ~(1 << PIN_LCD_RS);
37
   }
38
39
   PORT_LCD_ENABLE   |= 1 << PIN_LCD_ENABLE;
40
   PORT_LCD_SER_SYNC |= 1 << PIN_LCD_SER_SYNC;
41
42
   /*
43
    * and now the parallel data ...
44
    */
45
#if(USE_SINGLE_PINS)
46
   if (d & 0x01) PORT_LCD_D0 |= 1 << PIN_LCD_D0;
47
   else          PORT_LCD_D0 &= (uint8_t) ~(1 << PIN_LCD_D0);
48
   if (d & 0x02) PORT_LCD_D1 |= 1 << PIN_LCD_D1;
49
   else          PORT_LCD_D1 &= (uint8_t) ~(1 << PIN_LCD_D1);
50
   if (d & 0x04) PORT_LCD_D2 |= 1 << PIN_LCD_D2;
51
   else          PORT_LCD_D2 &= (uint8_t) ~(1 << PIN_LCD_D2);
52
   if (d & 0x08) PORT_LCD_D3 |= 1 << PIN_LCD_D3;
53
   else          PORT_LCD_D3 &= (uint8_t) ~(1 << PIN_LCD_D3);
54
   if (d & 0x10) PORT_LCD_D4 |= 1 << PIN_LCD_D4;
55
   else          PORT_LCD_D4 &= (uint8_t) ~(1 << PIN_LCD_D4);
56
   if (d & 0x20) PORT_LCD_D5 |= 1 << PIN_LCD_D5;
57
   else          PORT_LCD_D5 &= (uint8_t) ~(1 << PIN_LCD_D5);
58
   if (d & 0x40) PORT_LCD_D6 |= 1 << PIN_LCD_D6;
59
   else          PORT_LCD_D6 &= (uint8_t) ~(1 << PIN_LCD_D6);
60
   if (d & 0x80) PORT_LCD_D7 |= 1 << PIN_LCD_D7;
61
   else          PORT_LCD_D7 &= (uint8_t) ~(1 << PIN_LCD_D7);
62
#else   
63
   PORT_LCD_DATA = d;
64
#endif
65
   PORT_LCD_SER_SYNC &= (uint8_t) ~(1 << PIN_LCD_SER_SYNC);
66
   PORT_LCD_ENABLE   &= (uint8_t) ~(1 << PIN_LCD_ENABLE);
67
68
   _delay_us(45);
69
}
70
71
void lcdInit(void) {
72
   /*
73
    * serial connection
74
    */
75
   DDR_LCD_SER_DATA  |= 1 << PIN_LCD_SER_DATA;
76
   DDR_LCD_SER_SYNC  |= 1 << PIN_LCD_SER_SYNC;
77
   DDR_LCD_SER_CLOCK |= 1 << PIN_LCD_SER_CLOCK;
78
79
   /*
80
    * parallel connection
81
    */
82
   DDR_LCD_ENABLE |= 1 << PIN_LCD_ENABLE;
83
   DDR_LCD_RS     |= 1 << PIN_LCD_RS;
84
#if(USE_SINGLE_PINS)
85
   DDR_LCD_D0     |= 1 << PIN_LCD_D0;
86
   DDR_LCD_D1     |= 1 << PIN_LCD_D1;
87
   DDR_LCD_D2     |= 1 << PIN_LCD_D2;
88
   DDR_LCD_D3     |= 1 << PIN_LCD_D3;
89
   DDR_LCD_D4     |= 1 << PIN_LCD_D4;
90
   DDR_LCD_D5     |= 1 << PIN_LCD_D5;
91
   DDR_LCD_D6     |= 1 << PIN_LCD_D6;
92
   DDR_LCD_D7     |= 1 << PIN_LCD_D7;
93
#else
94
   DDR_LCD_DATA    = 0xFF;
95
#endif   
96
97
   _delay_ms(16);
98
   lcdCommand(0x38);
99
   _delay_ms(5);
100
   lcdCommand(0x38);
101
   _delay_us(110);
102
   lcdCommand(0x38);
103
   lcdCommand(0x38);
104
   lcdCommand(0x08);
105
   lcdCommand(0x01);
106
   lcdCommand(0x06);
107
   lcdEnable(1);
108
109
   lcdSample();
110
111
   _delay_ms(5000);
112
}

von Peter D. (peda)


Lesenswert?

Deine Bitzuordnung stimmt nicht mit dem Schaltplan überein.

Zuerst gibst Du Bit7 aus (0x80), QH ist aber mit DB0 verbunden.

Also müßte es richtig heißen:
1
static uint8_t Bits[] = { 0x01, ...


Peter

von Santiago (Gast)


Lesenswert?

Hallo Peter,

danke für Deine Aufmerksamkeit.

> Deine Bitzuordnung stimmt nicht mit dem Schaltplan überein.

QH ist mit DB0 verbunden - Ja.

Also das ist jetzt so eine Situation, die ich garnicht mag :(
Es funktioniert - und ich versteh nicht warum.

Habe mir nach Deinem Einwand nochmal den Plan angeschaut und dachte mir, 
ok, dann habe ich die Richtung für die Bitmuster falsch gewählt und bin 
auf die auskommentierte Zeile gekommen.
1
//static uint8_t Bits[] = { 0x10, 0x80, 0x40, 0x20, 0x02, 0x04, 0x08, 0x01 };
2
static uint8_t Bits[] = { 0x01, 0x08, 0x04, 0x02, 0x20, 0x40, 0x80, 0x10 };

Wollte schon posten, dass es immer noch nicht tut - da viel mir auf, 
dass Du geschrieben hattest - mit 0x01 anfangen. Meine Liste angeschaut 
- diese umgedreht und jetzt funzt es.

Nur versteh ich net, warum ich von hinten anfangen muss?
Entspricht nicht QA dem LSB?

Ich glaube, jetzt bin ich völlig durcheinander.
Für etwas mehr Licht im Dunkel wäre ich sehr dankbar.

von Peter D. (peda)


Lesenswert?

Das Schieberegister schiebt von vorn nach hinten.
Ehe das Eingangsbit an QH erscheint, muß es also 8-mal geschoben werden.
Es muß das höchstwertigste zuerst eingeschoben werden (MSB first).


Peter


P.S.:
Oftmals läßt sich ein Fehler nur finden, wenn man auch den Schaltplan 
postet.

von Santiago (Gast)


Lesenswert?

Hallo Peter,

herzlichen Dank für Deine Geduld.

> Ehe das Eingangsbit an QH erscheint, muß es also 8-mal geschoben werden.

Wenn ich das Datenblatt in Ruhe nochmal anschaue, dann kann man es 
"eigentlich" garnicht anderst interpretieren.
Schätze an der Ecke bin ich noch lange nicht sattelfest. MSB, LSB, 
steigende oder fallende Flanke ... puh! Bißchen viel auf einmal.

Jedenfalls kann ich jetzt mein Proggy wieder aufräumen. Das ist ja auch 
was :)

> Oftmals läßt sich ein Fehler nur finden, wenn man auch den Schaltplan
> postet.

Ich versuche auch in diesen Punkten dazu zu lernen.

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.