Rev Author Line No. Line
1269 kakl 1 /* ---------------------------------------------------------------------------
2 * AVR_MLIB - HD 44780 LCD Display Driver
3 * www.mlab.cz miho 2008
4 * ---------------------------------------------------------------------------
5 * LCD display driver for standard Hitachi 1/2/4 line character LCD modules
6 * for AVR processors. It uses 4 or 8 bit interface without readback.
7 * In the Examples section there is a demo application for this library.
8 * ---------------------------------------------------------------------------
9 * 00.00 2008/03/28 First Version
10 * ---------------------------------------------------------------------------
11 */
12  
13 #include "lcd_hd44780.h"
14  
15 // Check Defined Values and use Default Values if possible
16 // -------------------------------------------------------
17 // 1 / 2 / 4 Line
18 #ifndef LCD_CHARS
19 #if LCD_LINES > 2
20 #error "LCD: Undefined LCD_CHARS"
21 #else
22 // Dafault Value
23 #define LCD_CHARS 20
24 #endif
25 #endif
26  
27 #ifndef LCD_LINE_1
28 // Address of the 1st char on the 1st line
29 #define LCD_LINE_1 0
30 #endif
31  
32 #ifndef LCD_LINE_2
33 // Address of the 1st char on the 2nd line
34 #define LCD_LINE_2 64
35 #endif
36  
37 #ifndef LCD_LINE_3
38 // Address of the 1st char on the 3rd line
39 #define LCD_LINE_3 LCD_CHARS
40 #endif
41  
42 #ifndef LCD_LINE_4
43 // Address of the 1st char on the 4th line
44 #define LCD_LINE_4 (LCD_LINE_2 + LCD_CHARS)
45 #endif
46  
47 // Data Interface
48 #if LCD_INTERFACE_BITS == 4
49 #define LCD_DATA_MASK (0x0F << LCD_DATA_BIT)
50 #elif LCD_INTERFACE_BITS==8
51 #define LCD_DATA_MASK (0xFF << LCD_DATA_BIT)
52 #else
53 #error "LCD: Wrong Value: LCD_INTERFACE_BITS"
54 #endif
55  
56 #if LCD_DATA_MASK > 0xFF
57 #error "LCD: Value too Big: LCD_DATA_BIT"
58 #endif
59  
60 #define LCD_E_PORT PORT(LCD_E)
61 #define LCD_E_DDR DDR(LCD_E)
62  
63 #define LCD_RS_PORT PORT(LCD_RS)
64 #define LCD_RS_DDR DDR(LCD_RS)
65  
66 #define LCD_DATA_PORT PORT(LCD_DATA)
67 #define LCD_DATA_DDR DDR(LCD_DATA)
68  
69 #ifdef LCD_RW
70 #define LCD_RW_PORT PORT(LCD_RW)
71 #define LCD_RW_DDR DDR(LCD_RW)
72 #endif
73  
74  
75 // LCD Chip Commands
76 // -----------------
77  
78 // Comand Clear LCD Display
79 #define LCD_HD44780_CLR 0x01
80  
81 // Command Home Cursor
82 #define LCD_HD44780_HOME 0x02
83  
84 // Command Entry Mode (increment/decrement, shift/no shift)
85 #define LCD_HD44780_ENTMODE(inc, shift) \
86 (0x04 | ((inc)? 0x02: 0) | ((shift)? 1: 0))
87  
88 #define LCD_HD44780_ENTMODE_DEF LCD_HD44780_ENTMODE(1,0) // Increment Position, No Shift
89  
90 // Command Display Controll (display on/off, cursor on/off, cursor blinking on/off)
91 #define LCD_HD44780_DISPCTL(disp, cursor, blink) \
92 (0x08 | ((disp)? 0x04: 0) | ((cursor)? 0x02: 0) | ((blink)? 1: 0))
93  
94 #define LCD_HD44780_CURSORON LCD_HD44780_DISPCTL(1,1,0) // on, cursor on,
95 #define LCD_HD44780_CURSOROFF LCD_HD44780_DISPCTL(1,0,0) // on, cursor off
96  
97 // Command Cursor or Display Shift (shift display/cursor, left/right)
98 #define LCD_HD44780_SHIFT(shift, right) \
99 (0x10 | ((shift)? 0x08: 0) | ((right)? 0x04: 0))
100  
101 #define LCD_HD44780_CURSORLEFT LCD_HD44780_SHIFT(0,0)
102 #define LCD_HD44780_CURSORRIGHT LCD_HD44780_SHIFT(0,1)
103  
104 // Command Function Set ( 4/8-bit interface / 1 or 2 lines )
105 #define LCD_HD44780_4BIT1LINE 0x20 // 4-bit 1-line font 5x7
106 #define LCD_HD44780_4BIT2LINES 0x28 // 4-bit 2-lines font 5x7
107 #define LCD_HD44780_8BIT1LINE 0x30 // 8-bit 1-line font 5x7
108 #define LCD_HD44780_8BIT2LINES 0x38 // 8-bit 2-lines font 5x7
109  
110 // Select Apropriate Mode
111 #if LCD_INTERFACE_BITS==4
112 #if LCD_LINES == 1
113 #define LCD_HD44780_FNSET LCD_HD44780_4BIT1LINE // 4-bit 1-line
114 #else
115 #define LCD_HD44780_FNSET LCD_HD44780_4BIT2LINES // 4-bit 2-lines
116 #endif
117 #elif LCD_INTERFACE_BITS==8
118 #if LCD_LINES == 1
119 #define LCD_HD44780_FNSET LCD_HD44780_8BIT1LINE // 8-bit 1-line
120 #else
121 #define LCD_HD44780_FNSET LCD_HD44780_8BIT2LINES // 8-bit 2-lines
122 #endif
123 #endif
124  
125  
126 // User Defined Chars
127 // ------------------
128  
129 // Definitions only.
130 // Because these definitions may be sent to lcd via printf,
131 // it is impossible to contain 0 bytes (end of string in C)
132 // so we ored 0x80 to each byte
133  
134 #define LCD_CHAR_SPACE "\x80\x80\x80\x80\x80\x80\x80\x80" /* space (blank char) */
135 #define LCD_CHAR_BAT100 "\x8E\x9F\x9F\x9F\x9F\x9F\x9F\x1F" /* symbol battery full */
136 #define LCD_CHAR_BAT50 "\x8E\x9F\x91\x91\x93\x97\x9F\x1F" /* symbol baterry half */
137 #define LCD_CHAR_BAT0 "\x8E\x9F\x91\x91\x91\x91\x91\x1F" /* symbol baterry empty */
138 #define LCD_CHAR_UP "\x80\x84\x8E\x95\x84\x84\x84\x80" /* symbol arrow up */
139 #define LCD_CHAR_DOWN "\x80\x84\x84\x84\x95\x8E\x84\x80" /* symbol arrow down */
140 #define LCD_CHAR_LUA "\x84\x8E\x91\x91\x9F\x91\x91\x80" /* A s carkou */
141 #define LCD_CHAR_LLA "\x81\x82\x8E\x81\x9F\x91\x8F\x80" /* a s carkou */
142 #define LCD_CHAR_HUC "\x8A\x8E\x91\x90\x90\x91\x8E\x80" /* C s hackem */
143 #define LCD_CHAR_HLC "\x8A\x84\x8E\x90\x90\x91\x8E\x80" /* c s hackem */
144 #define LCD_CHAR_HUD "\x8A\x9C\x92\x91\x91\x92\x9C\x80" /* D s hackem */
145 #define LCD_CHAR_HLD "\x85\x83\x8D\x93\x91\x91\x8F\x80" /* d s hackem */
146 #define LCD_CHAR_LUE "\x84\x9F\x90\x90\x9E\x90\x9F\x80" /* E s carkou */
147 #define LCD_CHAR_LLE "\x81\x82\x8E\x91\x9F\x90\x8E\x80" /* e s carkou */
148 #define LCD_CHAR_HUE "\x8A\x9F\x90\x9E\x90\x90\x9F\x80" /* E s hackem */
149 #define LCD_CHAR_HLE "\x8A\x84\x8E\x91\x9F\x90\x8E\x80" /* e s hackem */
150 #define LCD_CHAR_LUI "\x84\x8E\x84\x84\x84\x84\x8E\x80" /* I s carkou */
151 #define LCD_CHAR_LLI "\x82\x84\x80\x8C\x84\x84\x8E\x80" /* i s carkou */
152 #define LCD_CHAR_HUN "\x8A\x95\x91\x99\x95\x93\x91\x80" /* N s hackem */
153 #define LCD_CHAR_HLN "\x8A\x84\x96\x99\x91\x91\x91\x80" /* n s hackem */
154 #define LCD_CHAR_LUO "\x84\x8E\x91\x91\x91\x91\x8E\x80" /* O s carkou */
155 #define LCD_CHAR_LLO "\x82\x84\x8E\x91\x91\x91\x8E\x80" /* o s carkou */
156 #define LCD_CHAR_HUR "\x8A\x9E\x91\x9E\x94\x92\x91\x80" /* R s hackem */
157 #define LCD_CHAR_HLR "\x8A\x84\x96\x99\x90\x90\x90\x80" /* r s hackem */
158 #define LCD_CHAR_HUS "\x8A\x8F\x90\x8E\x81\x81\x9E\x80" /* S s hackem */
159 #define LCD_CHAR_HLS "\x8A\x84\x8E\x90\x8E\x81\x9E\x80" /* s s hackem */
160 #define LCD_CHAR_HUT "\x8A\x9F\x84\x84\x84\x84\x84\x80" /* T s hackem */
161 #define LCD_CHAR_HLT "\x8A\x8C\x9C\x88\x88\x89\x86\x80" /* t s hackem */
162 #define LCD_CHAR_LUU "\x82\x95\x91\x91\x91\x91\x8E\x80" /* U s carkou */
163 #define LCD_CHAR_LLU "\x82\x84\x91\x91\x91\x93\x8D\x80" /* u s carkou */
164 #define LCD_CHAR_CUU "\x86\x97\x91\x91\x91\x91\x8E\x80" /* U s krouzkem */
165 #define LCD_CHAR_CLU "\x86\x86\x91\x91\x91\x91\x8E\x80" /* u s krouzkem */
166 #define LCD_CHAR_LUY "\x82\x95\x91\x8A\x84\x84\x84\x80" /* Y s carkou */
167 #define LCD_CHAR_LLY "\x82\x84\x91\x91\x8F\x81\x8E\x80" /* y s carkou */
168 #define LCD_CHAR_HUZ "\x8A\x9F\x81\x82\x84\x88\x9F\x80" /* Z s hackem */
169 #define LCD_CHAR_HLZ "\x8A\x84\x9F\x82\x84\x88\x9F\x80" /* z s hackem */
170  
171  
172 // Program
173 // -------
174  
175  
176 static int8_t lcd_posx; // Mirror Register with Position X (1..LCD_CHARS)
177 #if LCD_LINES > 1
178 static int8_t lcd_posy; // Mirror Register with Position Y (1..LCD_LINES)
179 #endif
180  
181  
182 // Send a Nibble or Byte to the LCD COntroller
183 static void
184 lcd_send_nibble(uint8_t rs, uint8_t data)
185 {
186 // Select Register or Data
187 if (rs)
188 LCD_RS_PORT |= (1<<LCD_RS_BIT);
189 else
190 LCD_RS_PORT &= ~(1<<LCD_RS_BIT);
191  
192 // Put 4bit/8bit data
193 LCD_DATA_PORT = (LCD_DATA_PORT & ~LCD_DATA_MASK) | ((data<<LCD_DATA_BIT)&LCD_DATA_MASK);
194 _delay_us(1); // Data Setup Time
195  
196 // Click Enable on and off
197 LCD_E_PORT |= 1<<LCD_E_BIT;
198 _delay_us(1);
199 LCD_E_PORT &= ~(1<<LCD_E_BIT);
200 _delay_us(40);
201 }
202  
203  
204 // Send a Byte to the LCD Controller
205 #if LCD_INTERFACE_BITS == 4
206 static void
207 lcd_send_byte(uint8_t rs, uint8_t data)
208 {
209 lcd_send_nibble(rs, data >> 4); // High Order Data
210 lcd_send_nibble(rs, data); // Low Order Data
211 }
212 #else
213 #define lcd_send_byte lcd_send_nibble
214 #endif
215  
216  
217 // Send a Command to the LCD Controller (RS=0)
218 #define lcd_send_cmd(n) lcd_send_byte(0, (n))
219  
220  
221 // Send a Data Byte to the LCD Controller (RS=1)
222 #define lcd_send_data(n) lcd_send_byte(1, (n))
223  
224  
225 // Goto Home
226 void
227 lcd_home()
228 {
229 lcd_send_cmd(LCD_HD44780_HOME); // Zero Cursor Position and Offset
230 #if LCD_LINES > 1
231 lcd_posx=lcd_posy=1;
232 #else
233 lcd_posx=1;
234 #endif
235 _delay_ms(2);
236 }
237  
238  
239 // Clear Display
240 void
241 lcd_clear()
242 {
243 lcd_send_cmd(LCD_HD44780_CLR); // Clear Memory
244 _delay_ms(2);
245 }
246  
247  
248 // Switch Cursor On
249 void
250 lcd_cursor_on()
251 {
252 lcd_send_cmd(LCD_HD44780_CURSORON);
253 }
254  
255  
256 // Switch Cursor Off
257 void
258 lcd_cursor_off()
259 {
260 lcd_send_cmd(LCD_HD44780_CURSOROFF);
261 }
262  
263  
264 // Clear Display and Goto Home with no Cursor
265 void
266 lcd_clear_home()
267 {
268 lcd_clear(); // Clear Memory
269 lcd_home(); // Zero Cursor Position and Offset
270 lcd_cursor_off(); // No Cursor
271 }
272  
273  
274 // Move to Position (1,1 is the first position)
275 void lcd_gotoxy(uint8_t x, uint8_t y)
276 {
277 uint8_t Adr;
278  
279 Adr=x-1;
280 #if LCD_LINES > 1
281 switch (y)
282 {
283 case 2:
284 Adr+=LCD_LINE_2;
285 break;
286 #if LCD_LINES > 2
287 case 3:
288 Adr+=LCD_LINE_3;
289 break;
290 case 4:
291 Adr+=LCD_LINE_4;
292 break;
293 #endif
294 }
295 #endif
296  
297 lcd_send_cmd(0x80 | (Adr & 0x7F) );
298 lcd_posx=x;
299 #if LCD_LINES > 1
300 lcd_posy=y;
301 #endif
302 }
303  
304  
305 // Increment Position
306 void
307 lcd_inc_pos()
308 {
309 // Next Position
310 lcd_posx++;
311  
312 // Correct End of Line
313 #if LCD_LINES == 1
314 if (lcd_posx > 40)
315 lcd_posx = 1;
316 #elif LCD_LINES == 2
317 if (lcd_posx > 40)
318 {
319 lcd_posx = 1;
320 lcd_posy++; // on the Next Line
321 }
322 #elif LCD_LINES > 2
323 if ( ((lcd_posy & 1) && (lcd_posx > LCD_CHARS)) // Odd Lines are Short
324 || (lcd_posx > 40-LCD_CHARS) ) // Memory is up to 40 Bytes
325 {
326 lcd_posx = 1; // Position 1
327 lcd_posy++; // on the Next Line
328 }
329 #endif
330  
331 // Correct End of Last Line
332 #if LCD_LINES > 1
333 if (lcd_posy > LCD_LINES)
334 {
335 lcd_posy = 1;
336 }
337 #endif
338 }
339  
340 // Decrement Position
341 void
342 lcd_dec_pos()
343 {
344 // Correct Beginning of Line
345 if (--lcd_posx==0) // Step Left
346 { // If Beginning of the Line
347 #if LCD_LINES > 1
348 if(--lcd_posy==0); // Step Up
349 lcd_posy = LCD_LINES; // If we are on Top Go to the Bottom
350 #endif
351 #if LCD_LINES <= 2
352 lcd_posx = 40;
353 #else
354 if(lcd_posy & 1) // If Odd Line (the Short One)
355 lcd_posx = LCD_CHARS; // Set End of the Short Line
356 else // Else
357 lcd_posx = 40-LCD_CHARS; // Set End of Long Line
358 #endif
359 }
360 }
361  
362 // Move Cursor Left
363 void
364 lcd_cursor_left()
365 {
366 lcd_send_cmd(LCD_HD44780_CURSORLEFT);
367 lcd_dec_pos();
368 }
369  
370  
371 // Move Cursor Right
372 void
373 lcd_cursor_right()
374 {
375 lcd_send_cmd(LCD_HD44780_CURSORRIGHT);
376 lcd_inc_pos();
377 }
378  
379  
380 // Init LCD Display
381 void
382 lcd_init(void)
383 {
384 // Port Init Direction
385 LCD_E_PORT &= ~_BV(LCD_E_BIT); // Enable off
386 LCD_E_DDR |= _BV(LCD_E_BIT); // Enable as Output
387 LCD_RS_DDR |= _BV(LCD_RS_BIT); // Register Select as Output
388 #ifdef LCD_RW
389 LCD_RW_DDR |= _BV(LCD_RW_BIT); // Read Write as Output
390 #endif
391 LCD_DATA_DDR |= LCD_DATA_MASK; // Data as Output
392  
393 // Initial Delay
394 _delay_ms(40); // Delay for Vcc
395  
396 // Sync 8/4 bit Interface
397 #if LCD_INTERFACE_BITS == 4
398 lcd_send_nibble(0, LCD_HD44780_8BIT1LINE >> 4); // 8 bit mode - sync nibble/byte
399 _delay_ms(4.1);
400 lcd_send_nibble(0, LCD_HD44780_8BIT1LINE >> 4);
401 _delay_us(100);
402 lcd_send_nibble(0, LCD_HD44780_8BIT1LINE >> 4);
403 // Set 4 bit mode
404 lcd_send_nibble(0, LCD_HD44780_FNSET >> 4);
405 #elif LCD_INTERFACE_BITS == 8
406 lcd_send_nibble(0, LCD_HD44780_8BIT1LINE); // 8 bit mode - sync nibble/byte
407 _delay_ms(4.1);
408 lcd_send_nibble(0, LCD_HD44780_8BIT1LINE);
409 _delay_us(100);
410 lcd_send_nibble(0, LCD_HD44780_8BIT1LINE);
411 #endif
412  
413 // Set and Init
414 lcd_send_cmd(LCD_HD44780_FNSET); // 4/8 bits 1/2 lines
415 lcd_send_cmd(LCD_HD44780_ENTMODE_DEF); // increment/decrement, shift/no shift
416 lcd_clear_home(); // display on, no cursor, clear and home
417 }
418  
419  
420 // LCD Char Output
421 int
422 lcd_putc(char c)
423 {
424 static uint8_t mode=0;
425  
426 switch (c)
427 {
428 case '\f':
429 lcd_clear_home(); // Clear Display
430 break;
431  
432 case '\n':
433 #if LCD_LINES > 1
434 if (lcd_posy <= LCD_LINES) // Go to the Next Line
435 lcd_posy++;
436 #endif
437  
438 case '\r':
439 #if LCD_LINES > 1
440 lcd_gotoxy(1,lcd_posy); // Go to the Beginning of the Line
441 #else
442 lcd_home();
443 #endif
444 break;
445  
446 case '\b':
447 lcd_cursor_left(); // Cursor (Position) Move Back
448 break;
449  
450 default:
451 if (mode==0 && c=='\v') // Startr of Definition String
452 {
453 mode=1; // Mode Next Char will be Defined Char
454 break;
455 }
456 if (mode==1) // First Char is Position Number
457 {
458 lcd_send_cmd(0x40 | ((c & 0x07)<<3) ); // Set CGRAM Address
459 mode++; // Mode Define Char Patern
460 break;
461 }
462 if (mode==2 && c=='\v') // End of Definition String
463 {
464 mode=0;
465 #if LCD_LINES > 1
466 lcd_gotoxy(lcd_posx,lcd_posy);
467 #else
468 lcd_gotoxy(lcd_posx,1);
469 #endif
470 break;
471 }
472 if (mode != 2) // Ordinary Chars
473 {
474 if (c<0x20) // Remap User Defind Char
475 c &= 0x07; // from rage 0x10-0x1F to 0x00-0x0f
476 lcd_inc_pos(); // Next Position
477 }
478 lcd_send_data(c); // Send Byte to LCD
479 break;
480 }
481  
482 return 0; // Success
483 }
484  
485