1 | /*******************************************************************************************************/
|
2 | #ifndef lcdRoutines_h
|
3 | #define lcdRoutines_h
|
4 | /*******************************************************************************************************/
|
5 | // LCD-Informationen:
|
6 | //
|
7 | // PortC = LCD-Data
|
8 | // PortA = LCD-Control
|
9 | // A7 = PS (std=High=parallel Mode)
|
10 | // A6 = C86 (std=High=6800 Mode)
|
11 | // A5 = unbenutzt
|
12 | // A4 = /RD = E (Schreibflanke H->L)
|
13 | // A3 = /WR = R/W (Low=Schreiben)
|
14 | // A2 = A0 (Low=ControlData; High=DisplayData)
|
15 | // A1 = /RES (Low=activ; std=High)
|
16 | // A0 = CS1 (ChipSelect=muss Low sein; std=High)
|
17 | /*******************************************************************************************************/
|
18 | #define sbi(ADDRESS,BIT) ((ADDRESS) |= (1<<(BIT)))
|
19 | #define cbi(ADDRESS,BIT) ((ADDRESS) &= ~(1<<(BIT)))
|
20 | /*******************************************************************************************************/
|
21 | // Definition der PORTs
|
22 | #define PortLcdData PORTC
|
23 | #define PortLcdDataPIN PINC
|
24 | #define PortLcdDataDDR DDRC
|
25 | #define PortLcdCtrl PORTA
|
26 | #define PortLcdCtrlDDR DDRA
|
27 | /*******************************************************************************************************/
|
28 | // Initialisierung der Ports
|
29 | void lcdInitPort()
|
30 | {
|
31 | // Port-C als Eingang ohne Pullup konfigurieren (für LCD-Data)
|
32 | // Port-C muß je nach Aktion die ausgeführt wird (schreiben oder lesen) als Ausgang oder Eingang konfiguriert werden
|
33 | PortLcdDataDDR = 0x00;
|
34 | PortLcdData = 0;
|
35 |
|
36 | // Port-A als Ausgang konfigurieren (für LCD-Control)
|
37 | // Bit0 = CS = ChipSelect Low-aktiv
|
38 | // Bit1 = R/W = Low=Schreiben
|
39 | // Bit2 = RS = Low=Control, High=Data
|
40 | // Bit3 = E = Schreibflanke H->L
|
41 | // Bit4 = Reset = Low-aktiv
|
42 | PortLcdCtrlDDR = 0xff;
|
43 | PortLcdCtrl = 0b1100011;
|
44 | }
|
45 | // PE: = Parameter Eingang
|
46 | // PA: = Parameter Ausgang
|
47 | // initialisiert das LCD
|
48 | void lcdInit();
|
49 | // sendet ein Steuerkommando an das LCD
|
50 | // PE: data = Steuerkommando
|
51 | void lcdSendCmd(uint8_t data);
|
52 | /*******************************************************************************************************/
|
53 | // schreibt ein Byte an die aktuelle Position auf dem LCD (aktuelle Position wird weitergesetzt)
|
54 | // PE: data = das Byte
|
55 | void lcdSendData(uint8_t data);
|
56 | /*******************************************************************************************************/
|
57 | // liest ein Byte von der aktuellen Position auf dem LCD (aktuelle Position wird beibehalten)
|
58 | // PA: das glesene Byte
|
59 | uint8_t lcdReadData();
|
60 | // Setzt die Position der nächsten Ausgabe, z.B. für Texte.
|
61 | // Der y-Wert wird auf eine 8er Grenze abgerundet. (0,8,16,24...56)
|
62 | // PE: x = x-Koordinate 0...127; y = y-Koordinate 0...63
|
63 | void lcdSetPos(uint8_t x, uint8_t y);
|
64 | /*******************************************************************************************************/
|
65 | // rückt die angegebenen Zeile zur aktuellen Zeile auf dem LCD (Rolleffekt)
|
66 | // PE: line = Nummer der Linie zu der gerollt werden soll
|
67 | void lcdGotoLine(uint8_t line);
|
68 | /*******************************************************************************************************/
|
69 | // löscht alle angezeigten Daten auf dem LCD
|
70 | void lcdClear();
|
71 | /*******************************************************************************************************/
|
72 | // schaltet die Anzeige aus/ein
|
73 | // PE: on = Ein/Aus 0/1; 0 = Anzeige an; 1 = Anzeige aus (komplett dunkel)
|
74 | void lcdSendCmdOn(uint8_t on);
|
75 | /*******************************************************************************************************/
|
76 | // invertiert die Anzeige (dunkel auf hell/ hell auf dunkel)
|
77 | // PE: on = Aus/Ein 0/1; 0 = Normal (dunkel auf hell); 1 = Invers (hell auf dunkel)
|
78 | void lcdSendCmdReverse(uint8_t jn);
|
79 | /*******************************************************************************************************/
|
80 | // setzt ein Pixel an Position x,y auf dem LCD
|
81 | // PE: x = x-Koordinate 0...127; y = y-Koordinate 0...63
|
82 | void lcdSetPixel(uint8_t x, uint8_t y);
|
83 | /*******************************************************************************************************/
|
84 | // sendet daten an das LCD, wird von lcdSendData() benutzt
|
85 | // PE: data = zu sendende Daten
|
86 | void lcdSend(uint8_t data)
|
87 | {
|
88 | // Bit 3 an Port-A löschen (Schreiben auf LCD)
|
89 | cbi(PortLcdCtrl,3);
|
90 | // Daten auf Port-C
|
91 | PortLcdData = data;
|
92 | // Port-C als Ausgang konfigurieren
|
93 | PortLcdDataDDR = 0xFF;
|
94 | // Bit 0 an Port-A löschen (ChipSelect = An)
|
95 | cbi(PortLcdCtrl,0);
|
96 | // Bit 4 an Port-A setzen; E = 1 (Schreiben mit HighPuls an E)
|
97 | sbi(PortLcdCtrl,4);
|
98 | // Inlineassembler: kurz warten
|
99 | __asm volatile ("nop \n nop \n nop \n");
|
100 | // Bit 4 an Port-A löschen; E = 0
|
101 | cbi(PortLcdCtrl,4);
|
102 | // Bit 0 an Port-A setzten (ChipSelect = Aus)
|
103 | sbi(PortLcdCtrl,0);
|
104 | }
|
105 | /*******************************************************************************************************/
|
106 | // initialisiert das LCD
|
107 | void lcdInit()
|
108 | {
|
109 | _delay_ms(1);
|
110 | // Licht aus
|
111 | PortLcdCtrl &= ~0b00100000;
|
112 | // Bit 0 an Port-A setzten (ChipSelect = Aus)
|
113 | sbi(PortLcdCtrl,0);
|
114 | // Bit 7 an Port-A setzten (parallel on)
|
115 | sbi(PortLcdCtrl,7);
|
116 | // Bit 6 an Port-A setzten (6800 Modus)
|
117 | sbi(PortLcdCtrl,6);
|
118 |
|
119 | // Reset am LCD
|
120 | PortLcdCtrl &= ~0b00000010;
|
121 | _delay_ms(1);
|
122 | PortLcdCtrl |= 0b00000010;
|
123 | _delay_ms(1);
|
124 |
|
125 | // Eine Reihe von Steuerkommandos an das LCD senden (sihe Datenblatt)
|
126 |
|
127 | // internal Reset
|
128 | lcdSendCmd(0xE2);
|
129 | // ADC select
|
130 | lcdSendCmd(0xA0);
|
131 | // COM output scan direction = revers
|
132 | lcdSendCmd(0xC8);
|
133 | // LCD drive voltage bias ratio
|
134 | lcdSendCmd(0xA2);
|
135 |
|
136 | lcdSendCmd(0x2F);
|
137 |
|
138 | lcdSendCmd(0x26);
|
139 | // select booster ratio
|
140 | lcdSendCmd(0xF8);
|
141 |
|
142 | lcdSendCmd(0x00);
|
143 | // set output voltage
|
144 | lcdSendCmd(0x81);
|
145 |
|
146 | lcdSendCmd(0x09);
|
147 | // read-modify-write
|
148 | lcdSendCmd(0xE0);
|
149 | // display on
|
150 | lcdSendCmd(0xAF);
|
151 | }
|
152 | /*******************************************************************************************************/
|
153 | // sendet ein Steuerkommando an das LCD
|
154 | // PE: data = Steuerkommando
|
155 | void lcdSendCmd(uint8_t data)
|
156 | {
|
157 | // Bit 2 an Port-A löschen (Datenart = Steuerkommando)
|
158 | cbi(PortLcdCtrl,2);
|
159 | // Senden
|
160 | lcdSend(data);
|
161 | }
|
162 | /*******************************************************************************************************/
|
163 | // schreibt ein Byte an die aktuelle Position auf dem LCD (aktuelle Position wird weitergesetzt)
|
164 | // PE: data = das Byte
|
165 | void lcdSendData(uint8_t data)
|
166 | {
|
167 | // Bit 2 an Port-A setzten (Datenart = Daten)
|
168 | sbi(PortLcdCtrl,2);
|
169 | // Senden
|
170 | lcdSend(data);
|
171 | }
|
172 | /*******************************************************************************************************/
|
173 | // liest ein Byte von der aktuellen Position auf dem LCD (aktuelle Position wird beibehalten)
|
174 | // PA: das Byte
|
175 | uint8_t lcdReadData()
|
176 | {
|
177 | uint8_t data;
|
178 |
|
179 | // Port-C als Eingang konfiguriren (für lesen)
|
180 | PortLcdDataDDR = 0x00;
|
181 | // Bit 2 an Port-A setzten (Datenart = Daten)
|
182 | sbi(PortLcdCtrl,2);
|
183 | // Bit 3 an Port-A setzten (lesen)
|
184 | sbi(PortLcdCtrl,3);
|
185 | // Bit 0 an Port-A löschen (ChipSelect = An)
|
186 | cbi(PortLcdCtrl,0);
|
187 |
|
188 | // ein DUMMY-lesen nach Adress-Änderung (MUSS SEIN!)
|
189 |
|
190 | // Bit 4 an Port-A setzten (Flanke vorbereiten)
|
191 | sbi(PortLcdCtrl,4);
|
192 | // Inlineassembler: kurz warten
|
193 | __asm volatile ("nop \n nop \n nop \n");
|
194 | // Bit 4 an Port-A löschen
|
195 | cbi(PortLcdCtrl,4);
|
196 |
|
197 | // Ende DUMMY-lesen
|
198 |
|
199 | // Bit 4 an Port-A setzten (Flanke vorbereiten)
|
200 | sbi(PortLcdCtrl,4);
|
201 | // Inlineassembler: kurz warten
|
202 | __asm volatile ("nop \n nop \n nop \n");
|
203 | // Daten an PIN-C holen
|
204 | data=PortLcdDataPIN;
|
205 | // Bit 4 an Port-A löschen
|
206 | cbi(PortLcdCtrl,4);
|
207 |
|
208 | // Bit 0 an Port-A setzten (ChipSelect = Aus)
|
209 | sbi(PortLcdCtrl,0);
|
210 | // Port-C als Ausgang konfigurieren
|
211 | PortLcdDataDDR = 0xFF;
|
212 |
|
213 | return data;
|
214 | }
|
215 | /*******************************************************************************************************/
|
216 | // Setzt die Position der nächsten Ausgabe, z.B. für Texte.
|
217 | // Der y-Wert wird auf eine 8er Grenze abgerundet. (0,8,16,24...56)
|
218 | // PE: x = x-Koordinate 0...127; y = y-Koordinate 0...63
|
219 | void lcdSetPos(uint8_t x, uint8_t y)
|
220 | {
|
221 | // x-Koordinate
|
222 | lcdSendCmd(0b00010000 + (x>>4));
|
223 | lcdSendCmd(0b00000000 + (x & 0x0f));
|
224 | // y-Koordinate
|
225 | lcdSendCmd(0b10110000 + (y>>3));
|
226 | }
|
227 | /*******************************************************************************************************/
|
228 | // rückt die angegebenen Zeile zur aktuellen Zeile auf dem LCD (Rolleffekt)
|
229 | // PE: line = Nummer der Linie zu der gerollt werden soll
|
230 | void lcdGotoLine(uint8_t line)
|
231 | {
|
232 | // Zeile initialisieren
|
233 | lcdSendCmd(0b01000000 + (line & 0b00111111));
|
234 | }
|
235 | /*******************************************************************************************************/
|
236 | // löscht alle angezeigten Daten auf dem LCD
|
237 | void lcdClear()
|
238 | {
|
239 | // die Anzeige besteht 128 * 8 Bytes, welche senkrecht angeordnet sind
|
240 | // in jedem Byte liegt Bit0 oben und Bit7 unten
|
241 | // y-Schleife (senkrecht); 8 mal, da 64 Pixel aus 8 Bytes je 8 Bits bestehen
|
242 | for(uint8_t y=0; y<64; y+=8)
|
243 | {
|
244 | // gehe zu Zeilenanfang
|
245 | lcdSetPos(0,y);
|
246 | // x-Schleife (waagerecht); 128 Pixel sind 128
|
247 | for(uint16_t x=0; x<128; x++)
|
248 | // Byte auf 0 setzen
|
249 | lcdSendData(0);
|
250 | }
|
251 | // aktuelle Position auf linksoben setzen (0,0)
|
252 | lcdSetPos(0,0);
|
253 | }
|
254 | /*******************************************************************************************************/
|
255 | // invertiert die Anzeige (dunkel auf hell/ hell auf dunkel)
|
256 | // PE: on = Aus/Ein 0/1; 0 = Normal (dunkel auf hell); 1 = Invers (hell auf dunkel)
|
257 | void lcdSendCmdReverse(uint8_t jn)
|
258 | {
|
259 | // Anzeige normal/revers
|
260 | lcdSendCmd(0b10100110 + jn);
|
261 | }
|
262 | /*******************************************************************************************************/
|
263 | // schaltet die Anzeige aus/ein
|
264 | // PE: on = Ein/Aus 0/1; 0 = Anzeige an; 1 = Anzeige aus (komplett dunkel)
|
265 | void lcdSendCmdOn(uint8_t on)
|
266 | {
|
267 | // Alle Pixel an/aus
|
268 | lcdSendCmd(0b10100100 + on);
|
269 | }
|
270 | /*******************************************************************************************************/
|
271 | // setzt ein Pixel an Position x,y auf dem LCD
|
272 | // PE: x = x-Koordinate 0...127; y = y-Koordinate 0...63
|
273 | void lcdSetPixel(uint8_t x, uint8_t y)
|
274 | {
|
275 | // gehe zur Position
|
276 | lcdSetPos(x,y);
|
277 | uint8_t data;
|
278 | // Bitmuster für Position des Bits (Pixel) im Byte
|
279 | data = 1<<(y & 0b00000111);
|
280 | // Byte auslesen, Bit setzten, Byte zurückschreiben
|
281 | lcdSendData(lcdReadData()|data);
|
282 | }
|
283 | /*******************************************************************************************************/
|
284 | void lcdChar8(int c) // c ist hier der jeweilige ASCII-Wert (z.B.: "A">65) des gesendeten Charakters
|
285 | {
|
286 | for(uint8_t nColumn=1; nColumn<=7; nColumn++)
|
287 | {
|
288 | lcdSendData(myFont[c][nColumn]);
|
289 | if(nColumn == myFont[c][0]) // wenn das Ende des Charakters im Array erreicht ist...
|
290 | {
|
291 | lcdSendData(0x00); // ... ein 0-Byte (leere Spalte) senden...
|
292 | break; // ... und Funktion verlassen (bzw. nächsten Charakter einlesen)
|
293 | }
|
294 | }
|
295 | }
|
296 | /*******************************************************************************************************/
|
297 | // Bildung einer Zeichenkette aus den einzelnen Charaktern:
|
298 | void lcdString8(const char *data)
|
299 | {
|
300 | while(*data != '\0')
|
301 | lcdChar8(*data++);
|
302 | }
|
303 | /*******************************************************************************************************/
|
304 | // Auswahl der Screens
|
305 | void lcdScreen(uint8_t screenX)
|
306 | {
|
307 | uint8_t xpos = 0;
|
308 | uint8_t ypos = 0;
|
309 |
|
310 | if(screenX == 0) // Startbild
|
311 | {
|
312 | //lcdClear();
|
313 | lcdSetPos(86,0);
|
314 | lcdString8("[press >]");
|
315 |
|
316 | lcdSetPos(10,16);
|
317 | lcdString8("Dynasoft'");
|
318 |
|
319 | ypos = 24;
|
320 | lcdSetPos(19,ypos);
|
321 | for(uint8_t m=0; m<=2; m++)
|
322 | {
|
323 | for(uint8_t n=0; n<=90; n++)
|
324 | {
|
325 | lcdSendData(myFontStart[m][n]);
|
326 | }
|
327 | lcdSetPos(19,ypos += 8); // Y-Position um ein Byte (eine Zeile) weitersetzen
|
328 | }
|
329 | }
|
330 | else if(screenX == 1) // Testbild
|
331 | {
|
332 | //lcdClear();
|
333 | xpos = 0;
|
334 | lcdSetPos(xpos,8);
|
335 | lcdString8("Neonröhre 1");
|
336 | }
|
337 | }
|
338 | /*******************************************************************************************************/
|
339 | #endif
|
340 | /*******************************************************************************************************/
|