Forum: Mikrocontroller und Digitale Elektronik STM32F1 LCD Problem


von Tobi D. (fanti)


Lesenswert?

Moin,
ich bin Einsteiger in der ST32-Welt. Bei 8-Bitern habe ich einiges an 
Erfahrung, trotzdem scheitere ich hier an einem einfachen Problem.

Ich möchte mein STM32f100-Discovery Board an ein Display 2x16 
anschließen.
Ich habe bisher zwei baugleiche Displays getestet, beide funktionieren 
mit einem 8-Bit Prozessor.
Weiterhin habe ich zwei Example Codes ausprobiert, ohne Erfolg.
Um alle Fehler von fremden Code auszuschließen habe ich mir die 
Displayansteuerung nun durch simples I/O setzen selbst geschrieben. Aber 
das Problem löst sich nicht.

Die Initialisierung scheint zu klappen, zumindest verschwindet die eine 
leuchtende Zeile im Display nach dem einschalten.

Im Debug-Modus sieht es ebenfalls gut aus, die Pegel an den I/Os kann 
ich messen.

Infos:
- 8Mhz HSI
- Display 5V
- STM32 3,3V
- LCD-Daten 4-Bit an PC0-PC3 --> D4-D7 am Display
- RS an PC8
- RW an PC7
- EN an PC6
1
#include "stm32f10x_conf.h"
2
3
void Delay(long);
4
5
#define RS  GPIO_Pin_8
6
#define EN  GPIO_Pin_6
7
#define RW  GPIO_Pin_7
8
9
int main(void)
10
{
11
12
13
    SystemInit();
14
15
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
16
17
// I/Os
18
    GPIO_InitTypeDef GPIO_InitStructure;
19
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;
20
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
21
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
22
    GPIO_Init(GPIOC, &GPIO_InitStructure);
23
24
    Delay(300000);
25
    GPIO_WriteBit(GPIOC, RS, Bit_RESET);
26
    GPIO_WriteBit(GPIOC, RW, Bit_RESET);
27
    GPIO_WriteBit(GPIOC, EN, Bit_RESET);
28
//0x03
29
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, SET);
30
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, SET);
31
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
32
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
33
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
34
    Delay(1000);
35
    GPIO_WriteBit(GPIOC, EN, RESET);
36
37
    Delay(41000);
38
//0x03
39
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, SET);
40
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, SET);
41
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
42
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
43
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
44
    Delay(1000);
45
    GPIO_WriteBit(GPIOC, EN, RESET);
46
    Delay(1000);
47
//0x03
48
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, SET);
49
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, SET);
50
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
51
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
52
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
53
    Delay(1000);
54
    GPIO_WriteBit(GPIOC, EN, RESET);
55
//0x02
56
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, RESET);
57
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, SET);
58
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
59
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
60
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
61
    Delay(1000);
62
    GPIO_WriteBit(GPIOC, EN, RESET);
63
//0x28
64
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, RESET);
65
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, SET);
66
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
67
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
68
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
69
    Delay(1000);
70
    GPIO_WriteBit(GPIOC, EN, RESET);
71
    Delay(1000);
72
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, RESET);
73
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, RESET);
74
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
75
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, SET);
76
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
77
    Delay(1000);
78
    GPIO_WriteBit(GPIOC, EN, RESET);
79
//0x04
80
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, RESET);
81
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, RESET);
82
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
83
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
84
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
85
    Delay(1000);
86
    GPIO_WriteBit(GPIOC, EN, RESET);
87
    Delay(1000);
88
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, RESET);
89
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, RESET);
90
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
91
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, SET);
92
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
93
    Delay(1000);
94
    GPIO_WriteBit(GPIOC, EN, RESET);
95
    Delay(1000);
96
//0x01
97
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, RESET);
98
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, RESET);
99
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
100
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
101
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
102
    Delay(1000);
103
    GPIO_WriteBit(GPIOC, EN, RESET);
104
    Delay(1000);
105
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, SET);
106
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, RESET);
107
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
108
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
109
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
110
    Delay(1000);
111
    GPIO_WriteBit(GPIOC, EN, RESET);
112
    Delay(1000);
113
//0x06
114
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, RESET);
115
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, RESET);
116
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
117
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
118
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
119
    Delay(1000);
120
    GPIO_WriteBit(GPIOC, EN, RESET);
121
    Delay(1000);
122
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, RESET);
123
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, SET);
124
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, SET);
125
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
126
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
127
    Delay(1000);
128
    GPIO_WriteBit(GPIOC, EN, RESET);
129
    Delay(1000);
130
//0x0C
131
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, RESET);
132
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, RESET);
133
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, RESET);
134
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
135
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
136
    Delay(1000);
137
    GPIO_WriteBit(GPIOC, EN, RESET);
138
    Delay(1000);
139
    GPIO_WriteBit(GPIOC, GPIO_Pin_0, RESET);
140
    GPIO_WriteBit(GPIOC, GPIO_Pin_1, RESET);
141
    GPIO_WriteBit(GPIOC, GPIO_Pin_2, SET);
142
    GPIO_WriteBit(GPIOC, GPIO_Pin_3, SET);
143
    GPIO_WriteBit(GPIOC, EN, Bit_SET);
144
    Delay(1000);
145
    GPIO_WriteBit(GPIOC, EN, RESET);
146
    Delay(1000);
147
148
  while(1)
149
    {
150
//irgendein Zeichen schreiben
151
      Delay(10000);
152
      GPIO_WriteBit(GPIOC, GPIO_Pin_0, SET);
153
      GPIO_WriteBit(GPIOC, GPIO_Pin_1, RESET);
154
      GPIO_WriteBit(GPIOC, GPIO_Pin_2, SET);
155
      GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
156
      GPIO_WriteBit(GPIOC, EN, Bit_SET);
157
      Delay(1000);
158
      GPIO_WriteBit(GPIOC, EN, RESET);
159
      Delay(1000);
160
      GPIO_WriteBit(GPIOC, GPIO_Pin_0, SET);
161
      GPIO_WriteBit(GPIOC, GPIO_Pin_1, RESET);
162
      GPIO_WriteBit(GPIOC, GPIO_Pin_2, SET);
163
      GPIO_WriteBit(GPIOC, GPIO_Pin_3, RESET);
164
      GPIO_WriteBit(GPIOC, EN, Bit_SET);
165
      Delay(1000);
166
      GPIO_WriteBit(GPIOC, EN, RESET);
167
    Delay(10000);
168
169
    }
170
}
171
172
void Delay(long nCount)
173
{
174
175
  for(; nCount != 0; nCount--);
176
177
}


Irgendwas ist faul, die Frage ist nur wo liegt mein Fehler?

von Olaf (Gast)


Lesenswert?

> Die Initialisierung scheint zu klappen,
> zumindest verschwindet die eine
> leuchtende Zeile im Display nach dem einschalten.

Timingprobleme?

> Irgendwas ist faul, die Frage ist nur wo liegt mein Fehler?

Du benutzt den Debugger deiner Entwicklungsumgebung nicht um damit nach 
Fehlern zu suchen? :-)

Du hast noch nicht begriffen das man Wartezeiten besser mit Timern 
realisiert?

Oh..und du solltest mal ueber den Optimierer in deinem Compiler 
nachdenken.

Olaf

von Tobi D. (fanti)


Lesenswert?

Hey,
danke für die schnelle Antwort.

Timingprobleme habe ich auch vermutet, aber dann müsste es 
funktionieren, wenn ich Debug-Modus jeden schritt einzeln durchführe und 
die Pegel an den Pins messe/vergleiche.

Zum Thema Wartezeiten gebe ich dir recht, aber zum Einstieg wollte ich 
Probleme mit Fehlern bei der Timereinstellung vermeiden.
Deshalb habe ich auch auf jegliche Funktionen oder Makros verzichtet.

Für den Optimierer habe ich bisher überhaupt keinen Gedanken verwendet, 
da werde ich mich demnächst reinlesen.

von Linüx (Gast)


Lesenswert?

Tobi D. schrieb:
> - Display 5V
> - STM32 3,3V

Da fällt dir nix auf ???

Tobi D. schrieb:
> Display 2x16

Dazu passnd: welch Treiber? Display 3V3 kompatibel, ...

von Uwe B. (derexponent)


Lesenswert?

Hi Tobi,

also mal abgesehen davon, das dein Programmierstil nicht gerade
effizient ist, ist vermutlicht das hier dein Fehler :

beim schreiben von DATEN auf das Display muss der Pin "RS" High-Pegel 
haben (bei Commands Lo-Pegel)

P.S. wenn du nicht alles selbst programmieren willst,
gibt es eine fertige LIB für ein 2x16 Zeichen Text LCD unter :

http://mikrocontroller.bplaced.net


Gruss Uwe

von Juergen G. (jup)


Angehängte Dateien:

Lesenswert?

Ich war bei den AVR's mit der Fleury LCD Lib immer sehr zufrieden und 
habe sie deshalb auf die STM32 umgestrickt.

Wer also vorher mit der Fleury Lib an AVR's gearbeitet hat sollte 
relativ schnell sein Display auch an einem STM zum laufen bringen.

Ich betreibe die normalen 5V Displays am STM.

Das 3.3V Problem loese ich mit einer ChargePump am Contrast Pin des 
Displays
welche von einem Pin des STM versorgt wird, auch eine PWM fuer die 
Hintergrundbeleuchtung ist in der Lib mit drin.
So laesst sich der Kontrast und die Beleuchtung durch Software 
einstellen.
Beides ist per Preprozessor ein oder abzuschalten.
Die Timer die verwendet werden muss natuerlich jeder nach seinen 
Beduerfnissen anpassen.

von Juergen G. (jup)


Angehängte Dateien:

Lesenswert?

Kleiner Nachtrag, bevor jemand seinen STM beschaedigt.

Im obigen Post habe ich geschrieben das ich die 5V Displays verwende.
Das ist richtig, ich betreibe diese aber mit den gleichen 3.3V am VCC 
wie den STM.

im Anhang ein Bild wie man das ganze verkabelt.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Juergen G. schrieb:
> Das ist richtig, ich betreibe diese aber mit den gleichen 3.3V am VCC
> wie den STM.

Das sieht interessant aus. Kannst du mit PWM auf der Contrastclock dann 
den Kontrast einstellen?

von Juergen G. (jup)


Lesenswert?

Kontrast ist keine PWM, sondern einfach eine Frequenz so um die 70KHz 
die die Ladungspumpe versorgt.
Durch Aenderung der Frequenz so zwischen 60kHz und 80KHz kann der 
Kontrast eingestellt werden.
Um die Frequenz zu Aendern einfach den Wert im ARR des Timers aendern.
Muss man ein bisschen probieren um die richtigen Werte zu bekommen, das 
ist von Display zu Display unterschiedlich.

von Tobi D. (fanti)


Lesenswert?

Linüx: Es ist ein 44780. Pegel sollten passen (High-Pegel_min = 2,4V).

Uwe: Du hast recht! Aber gelöst hat sich mein Problem dadurch leider 
nicht, auch wenn es nun ein Fehler weniger ist^^
Das ist kein Programmierstil, sondern extra nur für die Fehlersuche 
geschrieben worden. Ich würde/werde fertige Libs benutzen, wenn es 
funktioniert.

Jürgen: Jop, die Fleury Lib habe ich bisher immer verwendet, die ist 
wirklich toll. Deine Lib macht Sinn, danke fürs veröffentlichen, aber 
ich kann nicht bestätigen, dass die 5V Displays mit 3,3V laufen. Laut 
Datenblatt brauchen die mindestens 4,5V Versorgung und mit dem STK-Board 
habe ich diese Erfahrung auch gemacht.

von Linüx (Gast)


Lesenswert?

Tobi D. schrieb:
> Linüx: Es ist ein 44780. Pegel sollten passen (High-Pegel_min = 2,4V).

Du weißt, dass nicht überall 44780 drin ist wo 44780 kompatibel drauf 
steht? Nur so. Ich würde da immer explizit das Datenblatt meines 
Displays befragen.

von Tobi D. (fanti)


Lesenswert?

Sooo, nach nun einigen Stunden mit diesem blöden Fehler ist es 
geschafft, danke für eure Hilfe.

Das Problem war die ganze Zeit das Timing, einfach mal ein Delay mit 
1000 Takten geht nicht, da MUSS man schon die Zeiten im Datenblatt 
einhalten und das ist ohne genauen Takt unmöglich.
Ich hätte mich zuerst mit den Oszillatoreinstellungen befassen sollen 
anstatt mit irgendeiner laufenden Einstellung direkt loszuprogrammieren.

Nun heißt es, "Gehe zurück auf Start" und weiter mit Takteinstellungen 
und Grundlagen :P

***gelöst und closed ***

von Juergen G. (jup)


Lesenswert?

Ist zwar geloest und geschlossen, aber ich schreib da trotzdem nochmal 
was dazu.

Das mit den 4.5V im Datenblatt der 5V Displays ist richtig, die ASICS 
sind aber die selben wie sie auch in den 3V Displays verbaut sind.
Einziger Unterschied ist der Widerstand fuer den internen Oscillator des 
ASICS und die Widerstaende fuer die Hintergrundbeleuchtung(falls sie 
bestueckt sind).
Das Problem ist, das der Kontrast so um die 4.5V unter VCC sein muss. Da 
hat man natuerlich schlechte Karten wenn man das 5V Display ohne 
weiteres an 3V haengt.

Die Loesung von oben benutzt die Ladungspumpe um eine negative 
Hilfsspannung fuer den Kontrast Pin zu erzeugen.

Ich habe bestimmt schon 30 Displays der verschiedensten Hersteller auf 
diese Weise verbaut und alle haben auf Anhieb funktioniert.

von Uwe B. (derexponent)


Lesenswert?

>da MUSS man schon die Zeiten im Datenblatt
>einhalten und das ist ohne genauen Takt unmöglich.

dann hab ich das unmögliche möglich gemacht :-)

ich benutz auch nur eine Schleife (keinen Timer)
und hab mich von großen Werte zu kleineren rangetastet
(bis das Display nicht mehr reagiert)

hier meine Counterwerte
nach dem PowerOn : 100000
zwischen den Commands : 50000
beim Clock : 1000

wenn die CPU mit 168MHz läuft, passt das bei mir

(aber mit Timer bist du natürlich auf der sichereren Seite)

Gruss Uwe

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.