1 | #include <stdint.h>
|
2 |
|
3 | //
|
4 | // Anpassungen im makefile:
|
5 | // ATMega8 => MCU=atmega8 im makefile einstellen
|
6 | // lcd-routines.c in SRC = ... Zeile anhängen
|
7 | // Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
|
8 | // http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
|
9 | //
|
10 |
|
11 | #ifndef LCD_ROUTINES_H
|
12 | #define LCD_ROUTINES_H
|
13 |
|
14 | ////////////////////////////////////////////////////////////////////////////////
|
15 | // Hier die verwendete Taktfrequenz in Hz eintragen, wichtig!
|
16 |
|
17 | #ifndef F_CPU
|
18 | #define F_CPU 1000000
|
19 | #endif
|
20 |
|
21 | ////////////////////////////////////////////////////////////////////////////////
|
22 | // Pinbelegung für das LCD, an verwendete Pins anpassen
|
23 | // Alle LCD Pins müssen an einem Port angeschlossen sein und die 4
|
24 | // Datenleitungen müssen auf aufeinanderfolgenden Pins liegen
|
25 |
|
26 | // LCD DB4-DB7 <--> PORTD Bit PD0-PD3
|
27 | #define LCD_PORT PORTD
|
28 | #define LCD_DDR DDRD
|
29 | #define LCD_DB PD0
|
30 |
|
31 | // LCD RS <--> PORTD Bit PD4 (RS: 1=Data, 0=Command)
|
32 | #define LCD_RS PD4
|
33 |
|
34 | // LCD EN <--> PORTD Bit PD5 (EN: 1-Impuls für Daten)
|
35 | #define LCD_EN PD5
|
36 |
|
37 | ////////////////////////////////////////////////////////////////////////////////
|
38 | // LCD Ausführungszeiten (MS=Millisekunden, US=Mikrosekunden)
|
39 |
|
40 | #define LCD_BOOTUP_MS 15
|
41 | #define LCD_ENABLE_US 20
|
42 | #define LCD_WRITEDATA_US 46
|
43 | #define LCD_COMMAND_US 42
|
44 |
|
45 | #define LCD_SOFT_RESET_MS1 5
|
46 | #define LCD_SOFT_RESET_MS2 1
|
47 | #define LCD_SOFT_RESET_MS3 1
|
48 | #define LCD_SET_4BITMODE_MS 5
|
49 |
|
50 | #define LCD_CLEAR_DISPLAY_MS 2
|
51 | #define LCD_CURSOR_HOME_MS 2
|
52 |
|
53 | ////////////////////////////////////////////////////////////////////////////////
|
54 | // Zeilendefinitionen des verwendeten LCD
|
55 | // Die Einträge hier sollten für ein LCD mit einer Zeilenlänge von 16 Zeichen passen
|
56 | // Bei anderen Zeilenlängen müssen diese Einträge angepasst werden
|
57 |
|
58 | #define LCD_DDADR_LINE1 0x00
|
59 | #define LCD_DDADR_LINE2 0x40
|
60 | #define LCD_DDADR_LINE3 0x10
|
61 | #define LCD_DDADR_LINE4 0x50
|
62 |
|
63 | ////////////////////////////////////////////////////////////////////////////////
|
64 | // Initialisierung: muss ganz am Anfang des Programms aufgerufen werden.
|
65 | void lcd_init( void );
|
66 |
|
67 | ////////////////////////////////////////////////////////////////////////////////
|
68 | // LCD löschen
|
69 | void lcd_clear( void );
|
70 |
|
71 | ////////////////////////////////////////////////////////////////////////////////
|
72 | // Cursor in die 1. Zeile, 0-te Spalte
|
73 | void lcd_home( void );
|
74 |
|
75 | ////////////////////////////////////////////////////////////////////////////////
|
76 | // Cursor an eine beliebige Position
|
77 | void lcd_setcursor( uint8_t spalte, uint8_t zeile );
|
78 |
|
79 | ////////////////////////////////////////////////////////////////////////////////
|
80 | // Ausgabe eines einzelnen Zeichens an der aktuellen Cursorposition
|
81 | void lcd_data( uint8_t data );
|
82 |
|
83 | ////////////////////////////////////////////////////////////////////////////////
|
84 | // Ausgabe eines Strings an der aktuellen Cursorposition
|
85 | void lcd_string( const char *data );
|
86 |
|
87 | ////////////////////////////////////////////////////////////////////////////////
|
88 | // Definition eines benutzerdefinierten Sonderzeichens.
|
89 | // data muss auf ein Array[5] mit den Spaltencodes des zu definierenden Zeichens
|
90 | // zeigen
|
91 | void lcd_generatechar( uint8_t code, const uint8_t *data );
|
92 |
|
93 | ////////////////////////////////////////////////////////////////////////////////
|
94 | // Ausgabe eines Kommandos an das LCD.
|
95 | void lcd_command( uint8_t data );
|
96 |
|
97 |
|
98 | ////////////////////////////////////////////////////////////////////////////////
|
99 | // LCD Befehle und Argumente.
|
100 | // Zur Verwendung in lcd_command
|
101 |
|
102 | // Clear Display -------------- 0b00000001
|
103 | #define LCD_CLEAR_DISPLAY 0x01
|
104 |
|
105 | // Cursor Home ---------------- 0b0000001x
|
106 | #define LCD_CURSOR_HOME 0x02
|
107 |
|
108 | // Set Entry Mode ------------- 0b000001xx
|
109 | #define LCD_SET_ENTRY 0x04
|
110 |
|
111 | #define LCD_ENTRY_DECREASE 0x00
|
112 | #define LCD_ENTRY_INCREASE 0x02
|
113 | #define LCD_ENTRY_NOSHIFT 0x00
|
114 | #define LCD_ENTRY_SHIFT 0x01
|
115 |
|
116 | // Set Display ---------------- 0b00001xxx
|
117 | #define LCD_SET_DISPLAY 0x08
|
118 |
|
119 | #define LCD_DISPLAY_OFF 0x00
|
120 | #define LCD_DISPLAY_ON 0x04
|
121 | #define LCD_CURSOR_OFF 0x00
|
122 | #define LCD_CURSOR_ON 0x02
|
123 | #define LCD_BLINKING_OFF 0x00
|
124 | #define LCD_BLINKING_ON 0x01
|
125 |
|
126 | // Set Shift ------------------ 0b0001xxxx
|
127 | #define LCD_SET_SHIFT 0x10
|
128 |
|
129 | #define LCD_CURSOR_MOVE 0x00
|
130 | #define LCD_DISPLAY_SHIFT 0x08
|
131 | #define LCD_SHIFT_LEFT 0x00
|
132 | #define LCD_SHIFT_RIGHT 0x04
|
133 |
|
134 | // Set Function --------------- 0b001xxxxx
|
135 | #define LCD_SET_FUNCTION 0x20
|
136 |
|
137 | #define LCD_FUNCTION_4BIT 0x00
|
138 | #define LCD_FUNCTION_8BIT 0x10
|
139 | #define LCD_FUNCTION_1LINE 0x00
|
140 | #define LCD_FUNCTION_2LINE 0x08
|
141 | #define LCD_FUNCTION_5X7 0x00
|
142 | #define LCD_FUNCTION_5X10 0x04
|
143 |
|
144 | #define LCD_SOFT_RESET 0x30
|
145 |
|
146 | // Set CG RAM Address --------- 0b01xxxxxx (Character Generator RAM)
|
147 | #define LCD_SET_CGADR 0x40
|
148 |
|
149 | #define LCD_GC_CHAR0 0
|
150 | #define LCD_GC_CHAR1 1
|
151 | #define LCD_GC_CHAR2 2
|
152 | #define LCD_GC_CHAR3 3
|
153 | #define LCD_GC_CHAR4 4
|
154 | #define LCD_GC_CHAR5 5
|
155 | #define LCD_GC_CHAR6 6
|
156 | #define LCD_GC_CHAR7 7
|
157 |
|
158 | // Set DD RAM Address --------- 0b1xxxxxxx (Display Data RAM)
|
159 | #define LCD_SET_DDADR 0x80
|
160 |
|
161 | #endif
|
162 |
|
163 | // Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
|
164 | // http://www.mikrocontroller.net/articles/HD44780
|
165 | // http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
|
166 | //
|
167 | // Die Pinbelegung ist über defines in lcd-routines.h einstellbar
|
168 |
|
169 | #include <avr/io.h>
|
170 | //#include "lcd.h"
|
171 | #include <util/delay.h>
|
172 |
|
173 | ////////////////////////////////////////////////////////////////////////////////
|
174 | // Erzeugt einen Enable-Puls
|
175 | static void lcd_enable( void )
|
176 | {
|
177 | LCD_PORT |= (1<<LCD_EN); // Enable auf 1 setzen
|
178 | _delay_us( LCD_ENABLE_US ); // kurze Pause
|
179 | LCD_PORT &= ~(1<<LCD_EN); // Enable auf 0 setzen
|
180 | }
|
181 |
|
182 | ////////////////////////////////////////////////////////////////////////////////
|
183 | // Sendet eine 4-bit Ausgabeoperation an das LCD
|
184 | static void lcd_out( uint8_t data )
|
185 | {
|
186 | data &= 0xF0; // obere 4 Bit maskieren
|
187 |
|
188 | LCD_PORT &= ~(0xF0>>(4-LCD_DB)); // Maske löschen
|
189 | LCD_PORT |= (data>>(4-LCD_DB)); // Bits setzen
|
190 | lcd_enable();
|
191 | }
|
192 |
|
193 | ////////////////////////////////////////////////////////////////////////////////
|
194 | // Initialisierung: muss ganz am Anfang des Programms aufgerufen werden.
|
195 | void lcd_init( void )
|
196 | {
|
197 | // verwendete Pins auf Ausgang schalten
|
198 | uint8_t pins = (0x0F << LCD_DB) | // 4 Datenleitungen
|
199 | (1<<LCD_RS) | // R/S Leitung
|
200 | (1<<LCD_EN); // Enable Leitung
|
201 | LCD_DDR |= pins;
|
202 |
|
203 | // initial alle Ausgänge auf Null
|
204 | LCD_PORT &= ~pins;
|
205 |
|
206 | // warten auf die Bereitschaft des LCD
|
207 | _delay_ms( LCD_BOOTUP_MS );
|
208 |
|
209 | // Soft-Reset muss 3mal hintereinander gesendet werden zur Initialisierung
|
210 | lcd_out( LCD_SOFT_RESET );
|
211 | _delay_ms( LCD_SOFT_RESET_MS1 );
|
212 |
|
213 | lcd_enable();
|
214 | _delay_ms( LCD_SOFT_RESET_MS2 );
|
215 |
|
216 | lcd_enable();
|
217 | _delay_ms( LCD_SOFT_RESET_MS3 );
|
218 |
|
219 | // 4-bit Modus aktivieren
|
220 | lcd_out( LCD_SET_FUNCTION |
|
221 | LCD_FUNCTION_4BIT );
|
222 | _delay_ms( LCD_SET_4BITMODE_MS );
|
223 |
|
224 | // 4-bit Modus / 2 Zeilen / 5x7
|
225 | lcd_command( LCD_SET_FUNCTION |
|
226 | LCD_FUNCTION_4BIT |
|
227 | LCD_FUNCTION_2LINE |
|
228 | LCD_FUNCTION_5X7 );
|
229 |
|
230 | // Display ein / Cursor aus / Blinken aus
|
231 | lcd_command( LCD_SET_DISPLAY |
|
232 | LCD_DISPLAY_ON |
|
233 | LCD_CURSOR_OFF |
|
234 | LCD_BLINKING_OFF);
|
235 |
|
236 | // Cursor inkrement / kein Scrollen
|
237 | lcd_command( LCD_SET_ENTRY |
|
238 | LCD_ENTRY_INCREASE |
|
239 | LCD_ENTRY_NOSHIFT );
|
240 |
|
241 | lcd_clear();
|
242 | }
|
243 |
|
244 | ////////////////////////////////////////////////////////////////////////////////
|
245 | // Sendet ein Datenbyte an das LCD
|
246 | void lcd_data( uint8_t data )
|
247 | {
|
248 | LCD_PORT |= (1<<LCD_RS); // RS auf 1 setzen
|
249 |
|
250 | lcd_out( data ); // zuerst die oberen,
|
251 | lcd_out( data<<4 ); // dann die unteren 4 Bit senden
|
252 |
|
253 | _delay_us( LCD_WRITEDATA_US );
|
254 | }
|
255 |
|
256 | ////////////////////////////////////////////////////////////////////////////////
|
257 | // Sendet einen Befehl an das LCD
|
258 | void lcd_command( uint8_t data )
|
259 | {
|
260 | LCD_PORT &= ~(1<<LCD_RS); // RS auf 0 setzen
|
261 |
|
262 | lcd_out( data ); // zuerst die oberen,
|
263 | lcd_out( data<<4 ); // dann die unteren 4 Bit senden
|
264 |
|
265 | _delay_us( LCD_COMMAND_US );
|
266 | }
|
267 |
|
268 | ////////////////////////////////////////////////////////////////////////////////
|
269 | // Sendet den Befehl zur Löschung des Displays
|
270 | void lcd_clear( void )
|
271 | {
|
272 | lcd_command( LCD_CLEAR_DISPLAY );
|
273 | _delay_ms( LCD_CLEAR_DISPLAY_MS );
|
274 | }
|
275 |
|
276 | ////////////////////////////////////////////////////////////////////////////////
|
277 | // Sendet den Befehl: Cursor Home
|
278 | void lcd_home( void )
|
279 | {
|
280 | lcd_command( LCD_CURSOR_HOME );
|
281 | _delay_ms( LCD_CURSOR_HOME_MS );
|
282 | }
|
283 |
|
284 | ////////////////////////////////////////////////////////////////////////////////
|
285 | // Setzt den Cursor in Spalte x (0..15) Zeile y (1..4)
|
286 |
|
287 | void lcd_setcursor( uint8_t x, uint8_t y )
|
288 | {
|
289 | uint8_t data;
|
290 |
|
291 | switch (y)
|
292 | {
|
293 | case 1: // 1. Zeile
|
294 | data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
|
295 | break;
|
296 |
|
297 | case 2: // 2. Zeile
|
298 | data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
|
299 | break;
|
300 |
|
301 | case 3: // 3. Zeile
|
302 | data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
|
303 | break;
|
304 |
|
305 | case 4: // 4. Zeile
|
306 | data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
|
307 | break;
|
308 |
|
309 | default:
|
310 | return; // für den Fall einer falschen Zeile
|
311 | }
|
312 |
|
313 | lcd_command( data );
|
314 | }
|
315 |
|
316 | ////////////////////////////////////////////////////////////////////////////////
|
317 | // Schreibt einen String auf das LCD
|
318 |
|
319 | void lcd_string( const char *data )
|
320 | {
|
321 | while( *data != '\0' )
|
322 | lcd_data( *data++ );
|
323 | }
|
324 |
|
325 | ////////////////////////////////////////////////////////////////////////////////
|
326 | // Schreibt ein Zeichen in den Character Generator RAM
|
327 |
|
328 | void lcd_generatechar( uint8_t code, const uint8_t *data )
|
329 | {
|
330 | // Startposition des Zeichens einstellen
|
331 | lcd_command( LCD_SET_CGADR | (code<<3) );
|
332 |
|
333 | // Bitmuster übertragen
|
334 | for ( uint8_t i=0; i<8; i++ )
|
335 | {
|
336 | lcd_data( data[i] );
|
337 | }
|
338 | }
|
339 |
|
340 |
|
341 | //
|
342 | #include <avr/io.h>
|
343 | #include "lcd-routines.h"
|
344 |
|
345 | int main(void)
|
346 | {
|
347 | // Initialisierung des LCD
|
348 | // Nach der Initialisierung müssen auf dem LCD vorhandene schwarze Balken
|
349 | // verschwunden sein
|
350 | lcd_init();
|
351 |
|
352 | // Text in einzelnen Zeichen ausgeben
|
353 | lcd_data( 'T' );
|
354 | lcd_data( 'e' );
|
355 | lcd_data( 's' );
|
356 | lcd_data( 't' );
|
357 |
|
358 | // Die Ausgabemarke in die 2te Zeile setzen
|
359 | lcd_setcursor( 0, 2 );
|
360 |
|
361 | // erneut Text ausgeben, aber diesmal komfortabler als String
|
362 | lcd_string("Hello World!");
|
363 |
|
364 | while(1)
|
365 | {
|
366 | }
|
367 |
|
368 | return 0;
|
369 | }
|