1 | /****************************************************************************
|
2 | Title : HD44780U LCD library
|
3 | Author: Peter Fleury <pfleury@gmx.ch> http://jump.to/fleury
|
4 | File: $Id: LCD.c,v 1.14.2.1 2006/01/29 12:16:41 peter Exp $
|
5 | Software: AVR-GCC 3.3
|
6 | Target: any AVR device, memory mapped mode only for AT90S4414/8515/Mega
|
7 |
|
8 | DESCRIPTION
|
9 | Basic routines for interfacing a HD44780U-based text LCD display
|
10 |
|
11 | Originally based on Volker Oth's LCD library,
|
12 | changed LCD_init(), added additional constants for LCD_command(),
|
13 | added 4-bit I/O mode, improved and optimized code.
|
14 |
|
15 | Library can be operated in memory mapped mode (LCD_IO_MODE=0) or in
|
16 | 4-bit IO port mode (LCD_IO_MODE=1). 8-bit IO port mode not supported.
|
17 |
|
18 | Memory mapped mode compatible with Kanda STK200, but supports also
|
19 | generation of R/W signal through A8 address line.
|
20 |
|
21 | USAGE
|
22 | See the C include LCD.h file for a description of each function
|
23 |
|
24 | *****************************************************************************/
|
25 | #include <inttypes.h>
|
26 | #include <avr/io.h>
|
27 | #include <avr/pgmspace.h>
|
28 | #include <stdlib.h>
|
29 |
|
30 | #include "LCD.h"
|
31 |
|
32 | #define Header "LCD V2.2 07.2013"
|
33 |
|
34 | #define false 0
|
35 |
|
36 | /*
|
37 | ** constants/macros
|
38 | */
|
39 | #define DDR(x) (*(&x - 1)) /* address of data direction register of port x */
|
40 | #if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__)
|
41 | /* on ATmega64/128 PINF is on port 0x00 and not 0x60 */
|
42 | #define PIN(x) ( &PORTF==&(x) ? _SFR_IO8(0x00) : (*(&x - 2)) )
|
43 | #else
|
44 | #define PIN(x) (*(&x - 2)) /* address of input register of port x */
|
45 | #endif
|
46 |
|
47 |
|
48 | #if LCD_IO_MODE
|
49 | #define LCD_e_delay() __asm__ __volatile__( "rjmp 1f\n 1:" );
|
50 | #define LCD_e_high() LCD_E_PORT |= _BV(LCD_E_PIN);
|
51 | #define LCD_e_low() LCD_E_PORT &= ~_BV(LCD_E_PIN);
|
52 | #define LCD_e_toggle() toggle_e()
|
53 | #define LCD_rw_high() LCD_RW_PORT |= _BV(LCD_RW_PIN)
|
54 | #define LCD_rw_low() LCD_RW_PORT &= ~_BV(LCD_RW_PIN)
|
55 | #define LCD_rs_high() LCD_RS_PORT |= _BV(LCD_RS_PIN)
|
56 | #define LCD_rs_low() LCD_RS_PORT &= ~_BV(LCD_RS_PIN)
|
57 | #endif
|
58 |
|
59 | #if LCD_IO_MODE
|
60 | #if LCD_LINES==1
|
61 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE
|
62 | #else
|
63 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES
|
64 | #endif
|
65 | #else
|
66 | #if LCD_LINES==1
|
67 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE
|
68 | #else
|
69 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES
|
70 | #endif
|
71 | #endif
|
72 |
|
73 | #if LCD_CONTROLLER_KS0073
|
74 | #if LCD_LINES==4
|
75 |
|
76 | #define KS0073_EXTENDED_FUNCTION_REGISTER_ON 0x24 /* |0|010|0100 4-bit mode extension-bit RE = 1 */
|
77 | #define KS0073_EXTENDED_FUNCTION_REGISTER_OFF 0x20 /* |0|000|1001 4 lines mode */
|
78 | #define KS0073_4LINES_MODE 0x09 /* |0|001|0000 4-bit mode, extension-bit RE = 0 */
|
79 |
|
80 | #endif
|
81 | #endif
|
82 |
|
83 | /*
|
84 | ** function prototypes
|
85 | */
|
86 | #if LCD_IO_MODE
|
87 | static void toggle_e(void);
|
88 | #endif
|
89 |
|
90 | /*
|
91 | ** local functions
|
92 | */
|
93 |
|
94 | /*************************************************************************
|
95 | delay loop for small accurate delays: 16-bit counter, 4 cycles/loop
|
96 | *************************************************************************/
|
97 | static inline void _delayFourCycles(unsigned int __count)
|
98 | {
|
99 | if ( __count == 0 )
|
100 | __asm__ __volatile__( "rjmp 1f\n 1:" ); // 2 cycles
|
101 | else
|
102 | __asm__ __volatile__ (
|
103 | "1: sbiw %0,1" "\n\t"
|
104 | "brne 1b" // 4 cycles/loop
|
105 | : "=w" (__count)
|
106 | : "0" (__count)
|
107 | );
|
108 | }
|
109 |
|
110 |
|
111 | /*************************************************************************
|
112 | delay for a minimum of <us> microseconds
|
113 | the number of loops is calculated at compile-time from MCU clock frequency
|
114 | *************************************************************************/
|
115 | #define delay(us) _delayFourCycles( ( ( 1*(XTAL/4000) )*us)/1000 )
|
116 |
|
117 |
|
118 | #if LCD_IO_MODE
|
119 | /* toggle Enable Pin to initiate write */
|
120 | static void toggle_e(void)
|
121 | {
|
122 | LCD_e_high();
|
123 | LCD_e_delay();
|
124 | LCD_e_low();
|
125 | }
|
126 | #endif
|
127 |
|
128 |
|
129 | /*************************************************************************
|
130 | Low-level function to write byte to LCD controller
|
131 | Input: data byte to write to LCD
|
132 | rs 1: write data
|
133 | 0: write instruction
|
134 | Returns: none
|
135 | *************************************************************************/
|
136 | #if LCD_IO_MODE
|
137 | static void LCD_write(uint8_t data,uint8_t rs)
|
138 | {
|
139 | unsigned char dataBits ;
|
140 |
|
141 |
|
142 | if (rs) { /* write data (RS=1, RW=0) */
|
143 | LCD_rs_high();
|
144 | } else { /* write instruction (RS=0, RW=0) */
|
145 | LCD_rs_low();
|
146 | }
|
147 | LCD_rw_low();
|
148 |
|
149 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
150 | && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) )
|
151 | {
|
152 | /* configure data pins as output */
|
153 | DDR(LCD_DATA0_PORT) |= 0x0F;
|
154 |
|
155 | /* output high nibble first */
|
156 | dataBits = LCD_DATA0_PORT & 0xF0;
|
157 | LCD_DATA0_PORT = dataBits |((data>>4)&0x0F);
|
158 | LCD_e_toggle();
|
159 |
|
160 | /* output low nibble */
|
161 | LCD_DATA0_PORT = dataBits | (data&0x0F);
|
162 | LCD_e_toggle();
|
163 |
|
164 | /* all data pins high (inactive) */
|
165 | LCD_DATA0_PORT = dataBits | 0x0F;
|
166 | }
|
167 | else
|
168 | {
|
169 | /* configure data pins as output */
|
170 | DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
|
171 | DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
|
172 | DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
|
173 | DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
|
174 |
|
175 | /* output high nibble first */
|
176 | LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
|
177 | LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
|
178 | LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
|
179 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
|
180 | if(data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
181 | if(data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
182 | if(data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
183 | if(data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
184 | LCD_e_toggle();
|
185 |
|
186 | /* output low nibble */
|
187 | LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN);
|
188 | LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN);
|
189 | LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN);
|
190 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN);
|
191 | if(data & 0x08) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
192 | if(data & 0x04) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
193 | if(data & 0x02) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
194 | if(data & 0x01) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
195 | LCD_e_toggle();
|
196 |
|
197 | /* all data pins high (inactive) */
|
198 | LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN);
|
199 | LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN);
|
200 | LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN);
|
201 | LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN);
|
202 | }
|
203 | }
|
204 | #else
|
205 | #define LCD_write(d,rs) if (rs) *(volatile uint8_t*)(LCD_IO_DATA) = d; else *(volatile uint8_t*)(LCD_IO_FUNCTION) = d;
|
206 | /* rs==0 -> write instruction to LCD_IO_FUNCTION */
|
207 | /* rs==1 -> write data to LCD_IO_DATA */
|
208 | #endif
|
209 |
|
210 |
|
211 | /*************************************************************************
|
212 | Low-level function to read byte from LCD controller
|
213 | Input: rs 1: read data
|
214 | 0: read busy flag / address counter
|
215 | Returns: byte read from LCD controller
|
216 | *************************************************************************/
|
217 | #if LCD_IO_MODE
|
218 | static uint8_t LCD_read(uint8_t rs)
|
219 | {
|
220 | uint8_t data;
|
221 |
|
222 |
|
223 | if (rs)
|
224 | LCD_rs_high(); /* RS=1: read data */
|
225 | else
|
226 | LCD_rs_low(); /* RS=0: read busy flag */
|
227 | LCD_rw_high(); /* RW=1 read mode */
|
228 |
|
229 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
230 | && ( LCD_DATA0_PIN == 0 )&& (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) )
|
231 | {
|
232 | DDR(LCD_DATA0_PORT) &= 0xF0; /* configure data pins as input */
|
233 |
|
234 | LCD_e_high();
|
235 | LCD_e_delay();
|
236 | data = PIN(LCD_DATA0_PORT) << 4; /* read high nibble first */
|
237 | LCD_e_low();
|
238 |
|
239 | LCD_e_delay(); /* Enable 500ns low */
|
240 |
|
241 | LCD_e_high();
|
242 | LCD_e_delay();
|
243 | data |= PIN(LCD_DATA0_PORT)&0x0F; /* read low nibble */
|
244 | LCD_e_low();
|
245 | }
|
246 | else
|
247 | {
|
248 | /* configure data pins as input */
|
249 | DDR(LCD_DATA0_PORT) &= ~_BV(LCD_DATA0_PIN);
|
250 | DDR(LCD_DATA1_PORT) &= ~_BV(LCD_DATA1_PIN);
|
251 | DDR(LCD_DATA2_PORT) &= ~_BV(LCD_DATA2_PIN);
|
252 | DDR(LCD_DATA3_PORT) &= ~_BV(LCD_DATA3_PIN);
|
253 |
|
254 | /* read high nibble first */
|
255 | LCD_e_high();
|
256 | LCD_e_delay();
|
257 | data = 0;
|
258 | if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x10;
|
259 | if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x20;
|
260 | if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x40;
|
261 | if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x80;
|
262 | LCD_e_low();
|
263 |
|
264 | LCD_e_delay(); /* Enable 500ns low */
|
265 |
|
266 | /* read low nibble */
|
267 | LCD_e_high();
|
268 | LCD_e_delay();
|
269 | if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x01;
|
270 | if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x02;
|
271 | if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x04;
|
272 | if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x08;
|
273 | LCD_e_low();
|
274 | }
|
275 | return data;
|
276 | }
|
277 | #else
|
278 | #define LCD_read(rs) (rs) ? *(volatile uint8_t*)(LCD_IO_DATA+LCD_IO_READ) : *(volatile uint8_t*)(LCD_IO_FUNCTION+LCD_IO_READ)
|
279 | /* rs==0 -> read instruction from LCD_IO_FUNCTION */
|
280 | /* rs==1 -> read data from LCD_IO_DATA */
|
281 | #endif
|
282 |
|
283 |
|
284 | /*************************************************************************
|
285 | loops while LCD is busy, returns address counter
|
286 | *************************************************************************/
|
287 | static uint8_t LCD_waitbusy(void)
|
288 |
|
289 | {
|
290 | register uint8_t c;
|
291 |
|
292 | /* wait until busy flag is cleared */
|
293 | while ( (c=LCD_read(0)) & (1<<LCD_BUSY)) {}
|
294 |
|
295 | /* the address counter is updated 4us after the busy flag is cleared */
|
296 | delay(2); // 2
|
297 |
|
298 | /* now read the address counter */
|
299 | return (LCD_read(0)); // return address counter
|
300 |
|
301 | }/* LCD_waitbusy */
|
302 |
|
303 |
|
304 | /*************************************************************************
|
305 | Move cursor to the start of next line or to the first line if the cursor
|
306 | is already on the last line.
|
307 | *************************************************************************/
|
308 | static inline void LCD_newline(uint8_t pos)
|
309 | {
|
310 | register uint8_t addressCounter;
|
311 | int y;
|
312 |
|
313 | addressCounter = 0;
|
314 |
|
315 |
|
316 | #if LCD_LINES==1
|
317 | LCD_write((1<<LCD_DDRAM)+addressCounter,0);
|
318 | #endif
|
319 | #if LCD_LINES==2
|
320 | if (pos < (LCD_START_LINE2) )
|
321 | addressCounter = LCD_START_LINE2;
|
322 | else
|
323 | addressCounter = LCD_START_LINE1;
|
324 | LCD_write((1<<LCD_DDRAM)+addressCounter,0);
|
325 | #endif
|
326 | #if LCD_LINES==4
|
327 | #if KS0073_4LINES_MODE
|
328 | if (pos < LCD_START_LINE2 )
|
329 | addressCounter = LCD_START_LINE2;
|
330 | else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE3) )
|
331 | addressCounter = LCD_START_LINE3;
|
332 | else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE4) )
|
333 | addressCounter = LCD_START_LINE4;
|
334 | else
|
335 | addressCounter = LCD_START_LINE1;
|
336 | LCD_write((1<<LCD_DDRAM)+addressCounter,0);
|
337 |
|
338 | #else
|
339 | if ((pos >= LCD_START_LINE1) && (pos < (LCD_START_LINE1+LCD_DISP_LENGTH))) y=1;
|
340 | else if ((pos >= LCD_START_LINE2) && (pos < (LCD_START_LINE2+LCD_DISP_LENGTH))) y=2;
|
341 | else if ((pos >= LCD_START_LINE3) && (pos < (LCD_START_LINE3+LCD_DISP_LENGTH))) y=3;
|
342 | else if ((pos >= LCD_START_LINE4) && (pos < (LCD_START_LINE4+LCD_DISP_LENGTH))) y=4;
|
343 |
|
344 | LCD_gotoxy(0,y);
|
345 | #endif
|
346 | #endif
|
347 |
|
348 |
|
349 | }/* LCD_newline */
|
350 |
|
351 |
|
352 | /*
|
353 | ** PUBLIC FUNCTIONS
|
354 | */
|
355 |
|
356 | /*************************************************************************
|
357 | Send LCD controller instruction command
|
358 | Input: instruction to send to LCD controller, see HD44780 data sheet
|
359 | Returns: none
|
360 | *************************************************************************/
|
361 | void LCD_command(uint8_t cmd)
|
362 | {
|
363 | LCD_waitbusy();
|
364 | LCD_write(cmd,0);
|
365 | }
|
366 |
|
367 |
|
368 | /*************************************************************************
|
369 | Send data byte to LCD controller
|
370 | Input: data to send to LCD controller, see HD44780 data sheet
|
371 | Returns: none
|
372 | *************************************************************************/
|
373 | void LCD_data(uint8_t data)
|
374 | {
|
375 | LCD_waitbusy();
|
376 | LCD_write(data,1);
|
377 | }
|
378 |
|
379 |
|
380 |
|
381 | /*************************************************************************
|
382 | Set cursor to specified position
|
383 | Input: x horizontal position (0: left most position)
|
384 | y vertical position (0: first line)
|
385 | Returns: none
|
386 | *************************************************************************/
|
387 | void LCD_gotoxy(uint8_t x, uint8_t y)
|
388 | {
|
389 | #if LCD_LINES==1
|
390 | LCD_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
|
391 | #endif
|
392 | #if LCD_LINES==2
|
393 | if ( y==0 )
|
394 | LCD_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
|
395 | else
|
396 | LCD_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);
|
397 | #endif
|
398 | #if LCD_LINES==4
|
399 | if ( y==0 )
|
400 | LCD_command((1<<LCD_DDRAM)+LCD_START_LINE1+x);
|
401 | else if ( y==1)
|
402 | LCD_command((1<<LCD_DDRAM)+LCD_START_LINE2+x);
|
403 | else if ( y==2)
|
404 | LCD_command((1<<LCD_DDRAM)+LCD_START_LINE3+x);
|
405 | else if ( y==3)
|
406 | LCD_command((1<<LCD_DDRAM)+LCD_START_LINE4+x);
|
407 | #endif
|
408 |
|
409 | }/* LCD_gotoxy */
|
410 |
|
411 |
|
412 | /*************************************************************************
|
413 | *************************************************************************/
|
414 | int LCD_getxy(void)
|
415 | {
|
416 | return LCD_waitbusy();
|
417 | }
|
418 |
|
419 |
|
420 | /*************************************************************************
|
421 | Clear display and set cursor to home position
|
422 | *************************************************************************/
|
423 | void LCD_clrscr(void)
|
424 | {
|
425 | LCD_command(1<<LCD_CLR);
|
426 | }
|
427 |
|
428 |
|
429 | /*************************************************************************
|
430 | Set cursor to home position
|
431 | *************************************************************************/
|
432 | void LCD_home(void)
|
433 | {
|
434 | LCD_command(1<<LCD_HOME);
|
435 | }
|
436 |
|
437 |
|
438 | /*************************************************************************
|
439 | Display character at current cursor position
|
440 | Input: character to be displayed
|
441 | Returns: none
|
442 | *************************************************************************/
|
443 | void LCD_putc(char c) {
|
444 | uint8_t pos;
|
445 |
|
446 |
|
447 | pos = LCD_waitbusy(); // read busy-flag and address counter
|
448 | switch (c) {
|
449 | case '\r': {
|
450 | LCD_newline(pos);
|
451 | break;
|
452 | }
|
453 | default: {
|
454 | LCD_write(c, 1);
|
455 | pos = LCD_waitbusy();
|
456 |
|
457 | #if LCD_WRAP_LINES==1
|
458 | #if LCD_LINES==1
|
459 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {
|
460 | LCD_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
|
461 | }
|
462 | #elif LCD_LINES==2
|
463 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {
|
464 | LCD_write((1<<LCD_DDRAM)+LCD_START_LINE2,0);
|
465 | }else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ){
|
466 | LCD_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
|
467 | }
|
468 | #elif LCD_LINES==4
|
469 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) {
|
470 | LCD_write((1<<LCD_DDRAM)+LCD_START_LINE2,0);
|
471 | }else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ) {
|
472 | LCD_write((1<<LCD_DDRAM)+LCD_START_LINE3,0);
|
473 | }else if ( pos == LCD_START_LINE3+LCD_DISP_LENGTH ) {
|
474 | LCD_write((1<<LCD_DDRAM)+LCD_START_LINE4,0);
|
475 | }else if ( pos == LCD_START_LINE4+LCD_DISP_LENGTH ) {
|
476 | LCD_write((1<<LCD_DDRAM)+LCD_START_LINE1,0);
|
477 | }
|
478 | #endif
|
479 | #endif
|
480 | break;
|
481 | }
|
482 | }
|
483 |
|
484 | }/* LCD_putc */
|
485 |
|
486 |
|
487 | /*************************************************************************
|
488 | Display string without auto linefeed
|
489 | Input: string to be displayed
|
490 | Returns: none
|
491 | *************************************************************************/
|
492 | void LCD_puts(const char *s)
|
493 | /* print string on LCD (no auto linefeed) */
|
494 | {
|
495 | register char c;
|
496 |
|
497 | while ( (c = *s++) ) {
|
498 | LCD_putc(c);
|
499 | }
|
500 |
|
501 | }/* LCD_puts */
|
502 |
|
503 |
|
504 | /*************************************************************************
|
505 | Display string from program memory without auto linefeed
|
506 | Input: string from program memory be be displayed
|
507 | Returns: none
|
508 | *************************************************************************/
|
509 | void LCD_puts_p(const char *progmem_s)
|
510 | /* print string from program memory on LCD (no auto linefeed) */
|
511 | {
|
512 | register char c;
|
513 |
|
514 | while ( (c = pgm_read_byte(progmem_s++)) ) {
|
515 | LCD_putc(c);
|
516 | }
|
517 |
|
518 | }/* LCD_puts_p */
|
519 |
|
520 |
|
521 |
|
522 | void LCD_puti_alt(uint8_t inpv) {
|
523 | int rest;
|
524 | LCD_putc((int)inpv/100 | '0');
|
525 | rest = inpv % 100;
|
526 | LCD_putc((int)rest/10 | '0');
|
527 | rest = rest % 10;
|
528 | LCD_putc((int)rest | '0');
|
529 | }
|
530 |
|
531 |
|
532 | //---------------------------------------------------------------
|
533 | void LCD_puti(int zahl, int sges) {
|
534 | //Senden der Integerzahl (16-Bit) als Zeichenkette formatiert mit sges Stellen
|
535 | //als Zeichenkette (-32768 .. 32767)
|
536 | char buffer[16];
|
537 | uint8_t l=0,n;
|
538 | char *z=buffer;
|
539 | itoa(zahl,buffer,10);
|
540 | while(*z!=0){l++; z++;} //Bufferlänge l
|
541 | for(n=l;n<sges;n++) LCD_putc('0');
|
542 | LCD_puts(buffer);
|
543 | }
|
544 |
|
545 |
|
546 | //---------------------------------------------------------------
|
547 | void LCD_putl(long zahl, int sges) {
|
548 | //Senden der Longzahl (32-Bit) als Zeichenkette formatiert mit sges Stellen
|
549 | //als Zeichenkette (-2147483648 .. 2147483647)
|
550 | char buffer[16];
|
551 | uint8_t l=0,n;
|
552 | char *z=buffer;
|
553 | ltoa(zahl,buffer,10);
|
554 | while(*z!=0){l++; z++;} //Bufferlänge l
|
555 | for(n=l;n<sges;n++) LCD_putc('0');
|
556 | LCD_puts(buffer);
|
557 | }
|
558 |
|
559 |
|
560 |
|
561 | //---------------------------------------------------------------
|
562 | void LCD_putif(int zahl, int sges, int floats) {
|
563 | //Senden der Integerzahl zahl als Zeichenkette formatiert mit sges Stellen
|
564 | //als Zeichenkette setzt Dezimalpunkt for die n(float) letzte Stelle!
|
565 | char buffer[16];
|
566 | int i,j=0;
|
567 | uint8_t l=0,n;
|
568 | char *z=buffer;
|
569 |
|
570 | itoa(zahl,buffer,10);
|
571 | i=0;
|
572 | if (buffer[0] == '-') {LCD_putc('-'); ++z; i++;}
|
573 | else LCD_putc(' ');
|
574 |
|
575 | while(*z!=0){l++; z++;}//Bufferlänge l
|
576 | for(n=l;n<sges;n++) {
|
577 | LCD_putc('0');
|
578 | ++j;
|
579 | if (j==(sges-floats)) LCD_putc(',');
|
580 | }
|
581 | while (buffer[i] != 0) {
|
582 | LCD_putc(buffer[i]);
|
583 | ++j;
|
584 | if (j==(sges-floats)) LCD_putc(',');
|
585 | ++i;
|
586 | }
|
587 | }
|
588 |
|
589 |
|
590 | //---------------------------------------------------------------
|
591 | void LCD_putlf(long zahl, int sges, int floats) {
|
592 | //Senden der Integerzahl zahl als Zeichenkette formatiert mit sges Stellen
|
593 | //als Zeichenkette setzt Dezimalpunkt for die n(float) letzte Stelle!
|
594 | char buffer[16];
|
595 | int i,j=0;
|
596 | uint8_t l=0,n;
|
597 | char *z=buffer;
|
598 |
|
599 | ltoa(zahl,buffer,10);
|
600 | i=0;
|
601 | if (buffer[0] == '-') {LCD_putc('-'); ++z; i++;}
|
602 | else LCD_putc(' ');
|
603 |
|
604 | while(*z!=0){l++; z++;}//Bufferlänge l
|
605 | for(n=l;n<sges;n++) {
|
606 | LCD_putc('0');
|
607 | ++j;
|
608 | if (j==(sges-floats)) LCD_putc(',');
|
609 | }
|
610 | while (buffer[i] != 0) {
|
611 | LCD_putc(buffer[i]);
|
612 | ++j;
|
613 | if (j==(sges-floats)) LCD_putc(',');
|
614 | ++i;
|
615 | }
|
616 | }
|
617 |
|
618 |
|
619 |
|
620 |
|
621 | /*************************************************************************
|
622 | Initialize display and select type of cursor
|
623 | Input: dispAttr LCD_DISP_OFF display off
|
624 | LCD_DISP_ON display on, cursor off
|
625 | LCD_DISP_ON_CURSOR display on, cursor on
|
626 | LCD_DISP_CURSOR_BLINK display on, cursor on flashing
|
627 | Returns: none
|
628 | *************************************************************************/
|
629 | void LCD_init(uint8_t dispAttr, char *Title)
|
630 | {
|
631 | #if LCD_IO_MODE
|
632 | /*
|
633 | * Initialize LCD to 4 bit I/O mode
|
634 | */
|
635 |
|
636 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
637 | && ( &LCD_RS_PORT == &LCD_DATA0_PORT) && ( &LCD_RW_PORT == &LCD_DATA0_PORT) && (&LCD_E_PORT == &LCD_DATA0_PORT)
|
638 | && (LCD_DATA0_PIN == 0 ) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3)
|
639 | && (LCD_RS_PIN == 4 ) && (LCD_RW_PIN == 5) && (LCD_E_PIN == 6 ) )
|
640 | {
|
641 | /* configure all port bits as output (all LCD lines on same port) */
|
642 | DDR(LCD_DATA0_PORT) |= 0x7F;
|
643 | }
|
644 | else if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT )
|
645 | && (LCD_DATA0_PIN == 0 ) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) )
|
646 | {
|
647 | /* configure all port bits as output (all LCD data lines on same port, but control lines on different ports) */
|
648 | DDR(LCD_DATA0_PORT) |= 0x0F;
|
649 | DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
|
650 | DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
|
651 | DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
|
652 | }
|
653 | else
|
654 | {
|
655 | /* configure all port bits as output (LCD data and control lines on different ports */
|
656 | DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN);
|
657 | DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN);
|
658 | DDR(LCD_E_PORT) |= _BV(LCD_E_PIN);
|
659 | DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN);
|
660 | DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN);
|
661 | DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN);
|
662 | DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN);
|
663 | }
|
664 | delay(16000); /* wait 16ms == 16000 or more after power-on */
|
665 |
|
666 | /* initial write to LCD is 8bit */
|
667 | LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); // _BV(LCD_FUNCTION)>>4;
|
668 | LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); // _BV(LCD_FUNCTION_8BIT)>>4;
|
669 | LCD_e_toggle();
|
670 | delay(4992); /* ??? 4992 delay, busy flag can't be checked here */
|
671 |
|
672 | /* repeat last command */
|
673 | LCD_e_toggle();
|
674 | delay(64); /* delay, busy flag can't be checked here */
|
675 |
|
676 | /* repeat last command a third time */
|
677 | LCD_e_toggle();
|
678 | delay(64); /* delay, busy flag can't be checked here */
|
679 |
|
680 | /* now configure for 4bit mode */
|
681 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // LCD_FUNCTION_4BIT_1LINE>>4
|
682 | LCD_e_toggle();
|
683 | delay(64); /* some displays need this additional delay */
|
684 |
|
685 | /* from now the LCD only accepts 4 bit I/O, we can use LCD_command() */
|
686 | #else
|
687 | /*
|
688 | * Initialize LCD to 8 bit memory mapped mode
|
689 | */
|
690 |
|
691 | /* enable external SRAM (memory mapped LCD) and one wait state */
|
692 | MCUCR = _BV(SRE) | _BV(SRW);
|
693 |
|
694 | /* reset LCD */
|
695 | delay(16000); /* wait 16ms after power-on */
|
696 | LCD_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
697 | delay(4992); /* wait 5ms */
|
698 | LCD_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
699 | delay(64); /* wait 64us */
|
700 | LCD_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */
|
701 | delay(64); /* wait 64us */
|
702 | #endif
|
703 |
|
704 | #if KS0073_4LINES_MODE
|
705 | /* Display with KS0073 controller requires special commands for enabling 4 line mode */
|
706 | LCD_command(KS0073_EXTENDED_FUNCTION_REGISTER_ON);
|
707 | LCD_command(KS0073_4LINES_MODE);
|
708 | LCD_command(KS0073_EXTENDED_FUNCTION_REGISTER_OFF);
|
709 | #else
|
710 | LCD_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */
|
711 | #endif
|
712 | LCD_command(LCD_DISP_OFF); /* display off */
|
713 | LCD_clrscr(); /* display clear */
|
714 | LCD_command(LCD_MODE_DEFAULT); /* set entry mode */
|
715 | LCD_command(dispAttr); /* display/cursor control */
|
716 |
|
717 | if (*Title == 0) LCD_puts(Header);
|
718 | else LCD_puts(Title);
|
719 |
|
720 | }/* LCD_init */
|
721 |
|
722 | //--------------------------------------------------------------
|
723 | void LCD_putui_hex(unsigned int zahl, int sges){
|
724 | //Senden der nur-positiven Integerzahl zahl als Zeichenkette formatiert mit sges Stellen
|
725 | // das Ausgabeformat ist hex (TSC)
|
726 | char buffer[17];
|
727 | uint8_t l=0,n;
|
728 | char *z=buffer;
|
729 | utoa(zahl,buffer,16);
|
730 | while(*z!=0){l++; z++;}//Bufferlänge l
|
731 | for(n=l;n<sges;n++) LCD_putc(' ');
|
732 | LCD_puts(buffer);
|
733 | }
|
734 | //--------------------------------------------------------------
|
735 | void LCD_putui_bin(unsigned int zahl, int sges){
|
736 | //Senden der Integerzahl zahl als Zeichenkette formatiert mit sges Stellen
|
737 | // Das Ausgabeformat ist binär. Leerstellen werden mit 0 aufgefüllt.
|
738 | char buffer[17];
|
739 | uint8_t l=0,n;
|
740 | char *z=buffer;
|
741 | utoa(zahl,buffer,2);
|
742 | while(*z!=0){l++; z++;}//Bufferlänge l
|
743 | for(n=l;n<sges;n++) LCD_putc('0');
|
744 | LCD_puts(buffer);
|
745 | }
|
746 | //--------------------------------------------------------------
|
747 |
|
748 | void LCD_putb(uint8_t a){
|
749 | //Senden einer 8-Bit-Zahl binär(TSC)
|
750 | LCD_putui_bin(a,8);
|
751 | }
|
752 |
|
753 | //--------------------------------------------------------------
|
754 |
|
755 | void LCD_clear_char(uint8_t x, uint8_t y, uint8_t n){
|
756 | uint8_t i;
|
757 | //Loescht ab Pos(x,y) n Zeichen und setzt Pos. auf (x,y)
|
758 | LCD_gotoxy(x,y);
|
759 | for(i=0; i<n; ++i) LCD_putc(' ');
|
760 | LCD_gotoxy(x,y);
|
761 | }
|
762 |
|
763 | //--------------------------------------------------------------
|
764 |
|
765 | void LCD_Info(char *header, char *autor){
|
766 | static unsigned char old = false;
|
767 | if (old == false) {
|
768 | old = !false;
|
769 | LCD_clrscr();
|
770 | if(*header == 0) LCD_puts(Header);
|
771 | else LCD_puts(header);
|
772 | LCD_gotoxy(0,1);
|
773 | if(*autor == 0) LCD_puts(" Zielinski");
|
774 | else LCD_puts(autor);
|
775 | }
|
776 | }
|