Details | Last modification | View Log | SVN | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 160 | eqlazer | 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 "lcd.h" |
||
| 29 | |||
| 30 | |||
| 31 | |||
| 32 | /* |
||
| 33 | ** constants/macros |
||
| 34 | */ |
||
| 35 | #define DDR(x) (*(&x - 1)) /* address of data direction register of port x */ |
||
| 36 | #if defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) |
||
| 37 | /* on ATmega64/128 PINF is on port 0x00 and not 0x60 */ |
||
| 38 | #define PIN(x) ( &PORTF==&(x) ? _SFR_IO8(0x00) : (*(&x - 2)) ) |
||
| 39 | #else |
||
| 40 | #define PIN(x) (*(&x - 2)) /* address of input register of port x */ |
||
| 41 | #endif |
||
| 42 | |||
| 43 | |||
| 44 | #if LCD_IO_MODE |
||
| 45 | #define lcd_e_delay() __asm__ __volatile__( "rjmp 1f\n 1:" ); |
||
| 46 | #define lcd_e_high() LCD_E_PORT |= _BV(LCD_E_PIN); |
||
| 47 | #define lcd_e_low() LCD_E_PORT &= ~_BV(LCD_E_PIN); |
||
| 48 | #define lcd_e_toggle() toggle_e() |
||
| 49 | #define lcd_rw_high() LCD_RW_PORT |= _BV(LCD_RW_PIN) |
||
| 50 | #define lcd_rw_low() LCD_RW_PORT &= ~_BV(LCD_RW_PIN) |
||
| 51 | #define lcd_rs_high() LCD_RS_PORT |= _BV(LCD_RS_PIN) |
||
| 52 | #define lcd_rs_low() LCD_RS_PORT &= ~_BV(LCD_RS_PIN) |
||
| 53 | #endif |
||
| 54 | |||
| 55 | #if LCD_IO_MODE |
||
| 56 | #if LCD_LINES==1 |
||
| 57 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE |
||
| 58 | #else |
||
| 59 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES |
||
| 60 | #endif |
||
| 61 | #else |
||
| 62 | #if LCD_LINES==1 |
||
| 63 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_1LINE |
||
| 64 | #else |
||
| 65 | #define LCD_FUNCTION_DEFAULT LCD_FUNCTION_8BIT_2LINES |
||
| 66 | #endif |
||
| 67 | #endif |
||
| 68 | |||
| 69 | #if LCD_CONTROLLER_KS0073 |
||
| 70 | #if LCD_LINES==4 |
||
| 71 | |||
| 72 | #define KS0073_EXTENDED_FUNCTION_REGISTER_ON 0x24 /* |0|010|0100 4-bit mode extension-bit RE = 1 */ |
||
| 73 | #define KS0073_EXTENDED_FUNCTION_REGISTER_OFF 0x20 /* |0|000|1001 4 lines mode */ |
||
| 74 | #define KS0073_4LINES_MODE 0x09 /* |0|001|0000 4-bit mode, extension-bit RE = 0 */ |
||
| 75 | |||
| 76 | #endif |
||
| 77 | #endif |
||
| 78 | |||
| 79 | /* |
||
| 80 | ** function prototypes |
||
| 81 | */ |
||
| 82 | #if LCD_IO_MODE |
||
| 83 | static void toggle_e(void); |
||
| 84 | #endif |
||
| 85 | |||
| 86 | /* |
||
| 87 | ** local functions |
||
| 88 | */ |
||
| 89 | |||
| 90 | |||
| 91 | |||
| 92 | /************************************************************************* |
||
| 93 | delay loop for small accurate delays: 16-bit counter, 4 cycles/loop |
||
| 94 | *************************************************************************/ |
||
| 95 | static inline void _delayFourCycles(unsigned int __count) |
||
| 96 | { |
||
| 97 | if ( __count == 0 ) |
||
| 98 | __asm__ __volatile__( "rjmp 1f\n 1:" ); // 2 cycles |
||
| 99 | else |
||
| 100 | __asm__ __volatile__ ( |
||
| 101 | "1: sbiw %0,1" "\n\t" |
||
| 102 | "brne 1b" // 4 cycles/loop |
||
| 103 | : "=w" (__count) |
||
| 104 | : "0" (__count) |
||
| 105 | ); |
||
| 106 | } |
||
| 107 | |||
| 108 | |||
| 109 | /************************************************************************* |
||
| 110 | delay for a minimum of <us> microseconds |
||
| 111 | the number of loops is calculated at compile-time from MCU clock frequency |
||
| 112 | *************************************************************************/ |
||
| 113 | #define delay(us) _delayFourCycles( ( ( 1*(XTAL/4000) )*us)/1000 ) |
||
| 114 | |||
| 115 | |||
| 116 | #if LCD_IO_MODE |
||
| 117 | /* toggle Enable Pin to initiate write */ |
||
| 118 | static void toggle_e(void) |
||
| 119 | { |
||
| 120 | lcd_e_high(); |
||
| 121 | lcd_e_delay(); |
||
| 122 | lcd_e_low(); |
||
| 123 | } |
||
| 124 | #endif |
||
| 125 | |||
| 126 | |||
| 127 | /************************************************************************* |
||
| 128 | Low-level function to write byte to LCD controller |
||
| 129 | Input: data byte to write to LCD |
||
| 130 | rs 1: write data |
||
| 131 | 0: write instruction |
||
| 132 | Returns: none |
||
| 133 | *************************************************************************/ |
||
| 134 | #if LCD_IO_MODE |
||
| 135 | static void lcd_write(uint8_t data,uint8_t rs) |
||
| 136 | { |
||
| 137 | unsigned char dataBits ; |
||
| 138 | |||
| 139 | |||
| 140 | if (rs) { /* write data (RS=1, RW=0) */ |
||
| 141 | lcd_rs_high(); |
||
| 142 | } else { /* write instruction (RS=0, RW=0) */ |
||
| 143 | lcd_rs_low(); |
||
| 144 | } |
||
| 145 | lcd_rw_low(); |
||
| 146 | |||
| 147 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) |
||
| 148 | && (LCD_DATA0_PIN == 0) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) ) |
||
| 149 | { |
||
| 150 | /* configure data pins as output */ |
||
| 151 | DDR(LCD_DATA0_PORT) |= 0x0F; |
||
| 152 | |||
| 153 | /* output high nibble first */ |
||
| 154 | dataBits = LCD_DATA0_PORT & 0xF0; |
||
| 155 | LCD_DATA0_PORT = dataBits |((data>>4)&0x0F); |
||
| 156 | lcd_e_toggle(); |
||
| 157 | |||
| 158 | /* output low nibble */ |
||
| 159 | LCD_DATA0_PORT = dataBits | (data&0x0F); |
||
| 160 | lcd_e_toggle(); |
||
| 161 | |||
| 162 | /* all data pins high (inactive) */ |
||
| 163 | LCD_DATA0_PORT = dataBits | 0x0F; |
||
| 164 | } |
||
| 165 | else |
||
| 166 | { |
||
| 167 | /* configure data pins as output */ |
||
| 168 | DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN); |
||
| 169 | DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN); |
||
| 170 | DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN); |
||
| 171 | DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN); |
||
| 172 | |||
| 173 | /* output high nibble first */ |
||
| 174 | LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN); |
||
| 175 | LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN); |
||
| 176 | LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN); |
||
| 177 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); |
||
| 178 | if(data & 0x80) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); |
||
| 179 | if(data & 0x40) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); |
||
| 180 | if(data & 0x20) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); |
||
| 181 | if(data & 0x10) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); |
||
| 182 | lcd_e_toggle(); |
||
| 183 | |||
| 184 | /* output low nibble */ |
||
| 185 | LCD_DATA3_PORT &= ~_BV(LCD_DATA3_PIN); |
||
| 186 | LCD_DATA2_PORT &= ~_BV(LCD_DATA2_PIN); |
||
| 187 | LCD_DATA1_PORT &= ~_BV(LCD_DATA1_PIN); |
||
| 188 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); |
||
| 189 | if(data & 0x08) LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); |
||
| 190 | if(data & 0x04) LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); |
||
| 191 | if(data & 0x02) LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); |
||
| 192 | if(data & 0x01) LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); |
||
| 193 | lcd_e_toggle(); |
||
| 194 | |||
| 195 | /* all data pins high (inactive) */ |
||
| 196 | LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); |
||
| 197 | LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); |
||
| 198 | LCD_DATA2_PORT |= _BV(LCD_DATA2_PIN); |
||
| 199 | LCD_DATA3_PORT |= _BV(LCD_DATA3_PIN); |
||
| 200 | } |
||
| 201 | } |
||
| 202 | #else |
||
| 203 | #define lcd_write(d,rs) if (rs) *(volatile uint8_t*)(LCD_IO_DATA) = d; else *(volatile uint8_t*)(LCD_IO_FUNCTION) = d; |
||
| 204 | /* rs==0 -> write instruction to LCD_IO_FUNCTION */ |
||
| 205 | /* rs==1 -> write data to LCD_IO_DATA */ |
||
| 206 | #endif |
||
| 207 | |||
| 208 | |||
| 209 | /************************************************************************* |
||
| 210 | Low-level function to read byte from LCD controller |
||
| 211 | Input: rs 1: read data |
||
| 212 | 0: read busy flag / address counter |
||
| 213 | Returns: byte read from LCD controller |
||
| 214 | *************************************************************************/ |
||
| 215 | #if LCD_IO_MODE |
||
| 216 | static uint8_t lcd_read(uint8_t rs) |
||
| 217 | { |
||
| 218 | uint8_t data; |
||
| 219 | |||
| 220 | |||
| 221 | if (rs) |
||
| 222 | lcd_rs_high(); /* RS=1: read data */ |
||
| 223 | else |
||
| 224 | lcd_rs_low(); /* RS=0: read busy flag */ |
||
| 225 | lcd_rw_high(); /* RW=1 read mode */ |
||
| 226 | |||
| 227 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) |
||
| 228 | && ( LCD_DATA0_PIN == 0 )&& (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) ) |
||
| 229 | { |
||
| 230 | DDR(LCD_DATA0_PORT) &= 0xF0; /* configure data pins as input */ |
||
| 231 | |||
| 232 | lcd_e_high(); |
||
| 233 | lcd_e_delay(); |
||
| 234 | data = PIN(LCD_DATA0_PORT) << 4; /* read high nibble first */ |
||
| 235 | lcd_e_low(); |
||
| 236 | |||
| 237 | lcd_e_delay(); /* Enable 500ns low */ |
||
| 238 | |||
| 239 | lcd_e_high(); |
||
| 240 | lcd_e_delay(); |
||
| 241 | data |= PIN(LCD_DATA0_PORT)&0x0F; /* read low nibble */ |
||
| 242 | lcd_e_low(); |
||
| 243 | } |
||
| 244 | else |
||
| 245 | { |
||
| 246 | /* configure data pins as input */ |
||
| 247 | DDR(LCD_DATA0_PORT) &= ~_BV(LCD_DATA0_PIN); |
||
| 248 | DDR(LCD_DATA1_PORT) &= ~_BV(LCD_DATA1_PIN); |
||
| 249 | DDR(LCD_DATA2_PORT) &= ~_BV(LCD_DATA2_PIN); |
||
| 250 | DDR(LCD_DATA3_PORT) &= ~_BV(LCD_DATA3_PIN); |
||
| 251 | |||
| 252 | /* read high nibble first */ |
||
| 253 | lcd_e_high(); |
||
| 254 | lcd_e_delay(); |
||
| 255 | data = 0; |
||
| 256 | if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x10; |
||
| 257 | if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x20; |
||
| 258 | if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x40; |
||
| 259 | if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x80; |
||
| 260 | lcd_e_low(); |
||
| 261 | |||
| 262 | lcd_e_delay(); /* Enable 500ns low */ |
||
| 263 | |||
| 264 | /* read low nibble */ |
||
| 265 | lcd_e_high(); |
||
| 266 | lcd_e_delay(); |
||
| 267 | if ( PIN(LCD_DATA0_PORT) & _BV(LCD_DATA0_PIN) ) data |= 0x01; |
||
| 268 | if ( PIN(LCD_DATA1_PORT) & _BV(LCD_DATA1_PIN) ) data |= 0x02; |
||
| 269 | if ( PIN(LCD_DATA2_PORT) & _BV(LCD_DATA2_PIN) ) data |= 0x04; |
||
| 270 | if ( PIN(LCD_DATA3_PORT) & _BV(LCD_DATA3_PIN) ) data |= 0x08; |
||
| 271 | lcd_e_low(); |
||
| 272 | } |
||
| 273 | return data; |
||
| 274 | } |
||
| 275 | #else |
||
| 276 | #define lcd_read(rs) (rs) ? *(volatile uint8_t*)(LCD_IO_DATA+LCD_IO_READ) : *(volatile uint8_t*)(LCD_IO_FUNCTION+LCD_IO_READ) |
||
| 277 | /* rs==0 -> read instruction from LCD_IO_FUNCTION */ |
||
| 278 | /* rs==1 -> read data from LCD_IO_DATA */ |
||
| 279 | #endif |
||
| 280 | |||
| 281 | |||
| 282 | /************************************************************************* |
||
| 283 | loops while lcd is busy, returns address counter |
||
| 284 | *************************************************************************/ |
||
| 285 | static uint8_t lcd_waitbusy(void) |
||
| 286 | |||
| 287 | { |
||
| 288 | register uint8_t c; |
||
| 289 | |||
| 290 | /* wait until busy flag is cleared */ |
||
| 291 | while ( (c=lcd_read(0)) & (1<<LCD_BUSY)) {} |
||
| 292 | |||
| 293 | /* the address counter is updated 4us after the busy flag is cleared */ |
||
| 294 | delay(2); |
||
| 295 | |||
| 296 | /* now read the address counter */ |
||
| 297 | return (lcd_read(0)); // return address counter |
||
| 298 | |||
| 299 | }/* lcd_waitbusy */ |
||
| 300 | |||
| 301 | |||
| 302 | /************************************************************************* |
||
| 303 | Move cursor to the start of next line or to the first line if the cursor |
||
| 304 | is already on the last line. |
||
| 305 | *************************************************************************/ |
||
| 306 | static inline void lcd_newline(uint8_t pos) |
||
| 307 | { |
||
| 308 | register uint8_t addressCounter; |
||
| 309 | |||
| 310 | |||
| 311 | #if LCD_LINES==1 |
||
| 312 | addressCounter = 0; |
||
| 313 | #endif |
||
| 314 | #if LCD_LINES==2 |
||
| 315 | if ( pos < (LCD_START_LINE2) ) |
||
| 316 | addressCounter = LCD_START_LINE2; |
||
| 317 | else |
||
| 318 | addressCounter = LCD_START_LINE1; |
||
| 319 | #endif |
||
| 320 | #if LCD_LINES==4 |
||
| 321 | #if KS0073_4LINES_MODE |
||
| 322 | if ( pos < LCD_START_LINE2 ) |
||
| 323 | addressCounter = LCD_START_LINE2; |
||
| 324 | else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE3) ) |
||
| 325 | addressCounter = LCD_START_LINE3; |
||
| 326 | else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE4) ) |
||
| 327 | addressCounter = LCD_START_LINE4; |
||
| 328 | else |
||
| 329 | addressCounter = LCD_START_LINE1; |
||
| 330 | #else |
||
| 331 | if ( pos < LCD_START_LINE3 ) |
||
| 332 | addressCounter = LCD_START_LINE2; |
||
| 333 | else if ( (pos >= LCD_START_LINE2) && (pos < LCD_START_LINE4) ) |
||
| 334 | addressCounter = LCD_START_LINE3; |
||
| 335 | else if ( (pos >= LCD_START_LINE3) && (pos < LCD_START_LINE2) ) |
||
| 336 | addressCounter = LCD_START_LINE4; |
||
| 337 | else |
||
| 338 | addressCounter = LCD_START_LINE1; |
||
| 339 | #endif |
||
| 340 | #endif |
||
| 341 | lcd_command((1<<LCD_DDRAM)+addressCounter); |
||
| 342 | |||
| 343 | }/* lcd_newline */ |
||
| 344 | |||
| 345 | |||
| 346 | /* |
||
| 347 | ** PUBLIC FUNCTIONS |
||
| 348 | */ |
||
| 349 | |||
| 350 | /************************************************************************* |
||
| 351 | Send LCD controller instruction command |
||
| 352 | Input: instruction to send to LCD controller, see HD44780 data sheet |
||
| 353 | Returns: none |
||
| 354 | *************************************************************************/ |
||
| 355 | void lcd_command(uint8_t cmd) |
||
| 356 | { |
||
| 357 | lcd_waitbusy(); |
||
| 358 | lcd_write(cmd,0); |
||
| 359 | } |
||
| 360 | |||
| 361 | |||
| 362 | /************************************************************************* |
||
| 363 | Send data byte to LCD controller |
||
| 364 | Input: data to send to LCD controller, see HD44780 data sheet |
||
| 365 | Returns: none |
||
| 366 | *************************************************************************/ |
||
| 367 | void lcd_data(uint8_t data) |
||
| 368 | { |
||
| 369 | lcd_waitbusy(); |
||
| 370 | lcd_write(data,1); |
||
| 371 | } |
||
| 372 | |||
| 373 | |||
| 374 | |||
| 375 | /************************************************************************* |
||
| 376 | Set cursor to specified position |
||
| 377 | Input: x horizontal position (0: left most position) |
||
| 378 | y vertical position (0: first line) |
||
| 379 | Returns: none |
||
| 380 | *************************************************************************/ |
||
| 381 | void lcd_gotoxy(uint8_t x, uint8_t y) |
||
| 382 | { |
||
| 383 | #if LCD_LINES==1 |
||
| 384 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x); |
||
| 385 | #endif |
||
| 386 | #if LCD_LINES==2 |
||
| 387 | if ( y==0 ) |
||
| 388 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x); |
||
| 389 | else |
||
| 390 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x); |
||
| 391 | #endif |
||
| 392 | #if LCD_LINES==4 |
||
| 393 | if ( y==0 ) |
||
| 394 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+x); |
||
| 395 | else if ( y==1) |
||
| 396 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+x); |
||
| 397 | else if ( y==2) |
||
| 398 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE3+x); |
||
| 399 | else /* y==3 */ |
||
| 400 | lcd_command((1<<LCD_DDRAM)+LCD_START_LINE4+x); |
||
| 401 | #endif |
||
| 402 | |||
| 403 | }/* lcd_gotoxy */ |
||
| 404 | |||
| 405 | |||
| 406 | /************************************************************************* |
||
| 407 | *************************************************************************/ |
||
| 408 | int lcd_getxy(void) |
||
| 409 | { |
||
| 410 | return lcd_waitbusy(); |
||
| 411 | } |
||
| 412 | |||
| 413 | |||
| 414 | /************************************************************************* |
||
| 415 | Clear display and set cursor to home position |
||
| 416 | *************************************************************************/ |
||
| 417 | void lcd_clrscr(void) |
||
| 418 | { |
||
| 419 | lcd_command(1<<LCD_CLR); |
||
| 420 | } |
||
| 421 | |||
| 422 | |||
| 423 | /************************************************************************* |
||
| 424 | Set cursor to home position |
||
| 425 | *************************************************************************/ |
||
| 426 | void lcd_home(void) |
||
| 427 | { |
||
| 428 | lcd_command(1<<LCD_HOME); |
||
| 429 | } |
||
| 430 | |||
| 431 | |||
| 432 | /************************************************************************* |
||
| 433 | Display character at current cursor position |
||
| 434 | Input: character to be displayed |
||
| 435 | Returns: none |
||
| 436 | *************************************************************************/ |
||
| 437 | void lcd_putc(char c) |
||
| 438 | { |
||
| 439 | uint8_t pos; |
||
| 440 | |||
| 441 | |||
| 442 | pos = lcd_waitbusy(); // read busy-flag and address counter |
||
| 443 | if (c=='\n') |
||
| 444 | { |
||
| 445 | lcd_newline(pos); |
||
| 446 | } |
||
| 447 | else |
||
| 448 | { |
||
| 449 | #if LCD_WRAP_LINES==1 |
||
| 450 | #if LCD_LINES==1 |
||
| 451 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) { |
||
| 452 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0); |
||
| 453 | } |
||
| 454 | #elif LCD_LINES==2 |
||
| 455 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) { |
||
| 456 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0); |
||
| 457 | }else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ){ |
||
| 458 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0); |
||
| 459 | } |
||
| 460 | #elif LCD_LINES==4 |
||
| 461 | if ( pos == LCD_START_LINE1+LCD_DISP_LENGTH ) { |
||
| 462 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE2,0); |
||
| 463 | }else if ( pos == LCD_START_LINE2+LCD_DISP_LENGTH ) { |
||
| 464 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE3,0); |
||
| 465 | }else if ( pos == LCD_START_LINE3+LCD_DISP_LENGTH ) { |
||
| 466 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE4,0); |
||
| 467 | }else if ( pos == LCD_START_LINE4+LCD_DISP_LENGTH ) { |
||
| 468 | lcd_write((1<<LCD_DDRAM)+LCD_START_LINE1,0); |
||
| 469 | } |
||
| 470 | #endif |
||
| 471 | lcd_waitbusy(); |
||
| 472 | #endif |
||
| 473 | lcd_write(c, 1); |
||
| 474 | } |
||
| 475 | |||
| 476 | }/* lcd_putc */ |
||
| 477 | |||
| 478 | |||
| 479 | /************************************************************************* |
||
| 480 | Display string without auto linefeed |
||
| 481 | Input: string to be displayed |
||
| 482 | Returns: none |
||
| 483 | *************************************************************************/ |
||
| 484 | void lcd_puts(const char *s) |
||
| 485 | /* print string on lcd (no auto linefeed) */ |
||
| 486 | { |
||
| 487 | register char c; |
||
| 488 | |||
| 489 | while ( (c = *s++) ) { |
||
| 490 | lcd_putc(c); |
||
| 491 | } |
||
| 492 | |||
| 493 | }/* lcd_puts */ |
||
| 494 | |||
| 495 | |||
| 496 | /************************************************************************* |
||
| 497 | Display string from program memory without auto linefeed |
||
| 498 | Input: string from program memory be be displayed |
||
| 499 | Returns: none |
||
| 500 | *************************************************************************/ |
||
| 501 | void lcd_puts_p(const char *progmem_s) |
||
| 502 | /* print string from program memory on lcd (no auto linefeed) */ |
||
| 503 | { |
||
| 504 | register char c; |
||
| 505 | |||
| 506 | while ( (c = pgm_read_byte(progmem_s++)) ) { |
||
| 507 | lcd_putc(c); |
||
| 508 | } |
||
| 509 | |||
| 510 | }/* lcd_puts_p */ |
||
| 511 | |||
| 512 | |||
| 513 | /************************************************************************* |
||
| 514 | Initialize display and select type of cursor |
||
| 515 | Input: dispAttr LCD_DISP_OFF display off |
||
| 516 | LCD_DISP_ON display on, cursor off |
||
| 517 | LCD_DISP_ON_CURSOR display on, cursor on |
||
| 518 | LCD_DISP_CURSOR_BLINK display on, cursor on flashing |
||
| 519 | Returns: none |
||
| 520 | *************************************************************************/ |
||
| 521 | void lcd_init(uint8_t dispAttr) |
||
| 522 | { |
||
| 523 | #if LCD_IO_MODE |
||
| 524 | /* |
||
| 525 | * Initialize LCD to 4 bit I/O mode |
||
| 526 | */ |
||
| 527 | // LED_ON |
||
| 528 | |||
| 529 | if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) |
||
| 530 | && ( &LCD_RS_PORT == &LCD_DATA0_PORT) && ( &LCD_RW_PORT == &LCD_DATA0_PORT) && (&LCD_E_PORT == &LCD_DATA0_PORT) |
||
| 531 | && (LCD_DATA0_PIN == 0 ) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) |
||
| 532 | && (LCD_RS_PIN == 4 ) && (LCD_RW_PIN == 5) && (LCD_E_PIN == 6 ) ) |
||
| 533 | { |
||
| 534 | /* configure all port bits as output (all LCD lines on same port) */ |
||
| 535 | DDR(LCD_DATA0_PORT) |= 0x7F; |
||
| 536 | } |
||
| 537 | else if ( ( &LCD_DATA0_PORT == &LCD_DATA1_PORT) && ( &LCD_DATA1_PORT == &LCD_DATA2_PORT ) && ( &LCD_DATA2_PORT == &LCD_DATA3_PORT ) |
||
| 538 | && (LCD_DATA0_PIN == 0 ) && (LCD_DATA1_PIN == 1) && (LCD_DATA2_PIN == 2) && (LCD_DATA3_PIN == 3) ) |
||
| 539 | { |
||
| 540 | /* configure all port bits as output (all LCD data lines on same port, but control lines on different ports) */ |
||
| 541 | DDR(LCD_DATA0_PORT) |= 0x0F; |
||
| 542 | DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN); |
||
| 543 | DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN); |
||
| 544 | DDR(LCD_E_PORT) |= _BV(LCD_E_PIN); |
||
| 545 | } |
||
| 546 | else |
||
| 547 | { |
||
| 548 | /* configure all port bits as output (LCD data and control lines on different ports */ |
||
| 549 | DDR(LCD_RS_PORT) |= _BV(LCD_RS_PIN); |
||
| 550 | DDR(LCD_RW_PORT) |= _BV(LCD_RW_PIN); |
||
| 551 | DDR(LCD_E_PORT) |= _BV(LCD_E_PIN); |
||
| 552 | DDR(LCD_DATA0_PORT) |= _BV(LCD_DATA0_PIN); |
||
| 553 | DDR(LCD_DATA1_PORT) |= _BV(LCD_DATA1_PIN); |
||
| 554 | DDR(LCD_DATA2_PORT) |= _BV(LCD_DATA2_PIN); |
||
| 555 | DDR(LCD_DATA3_PORT) |= _BV(LCD_DATA3_PIN); |
||
| 556 | LED_ON |
||
| 557 | } |
||
| 558 | delay(16000); /* wait 16ms or more after power-on */ |
||
| 559 | |||
| 560 | /* initial write to lcd is 8bit */ |
||
| 561 | LCD_DATA1_PORT |= _BV(LCD_DATA1_PIN); // _BV(LCD_FUNCTION)>>4; |
||
| 562 | LCD_DATA0_PORT |= _BV(LCD_DATA0_PIN); // _BV(LCD_FUNCTION_8BIT)>>4; |
||
| 563 | lcd_e_toggle(); |
||
| 564 | delay(4992); /* delay, busy flag can't be checked here */ |
||
| 565 | |||
| 566 | /* repeat last command */ |
||
| 567 | lcd_e_toggle(); |
||
| 568 | delay(64); /* delay, busy flag can't be checked here */ |
||
| 569 | |||
| 570 | /* repeat last command a third time */ |
||
| 571 | lcd_e_toggle(); |
||
| 572 | delay(64); /* delay, busy flag can't be checked here */ |
||
| 573 | |||
| 574 | /* now configure for 4bit mode */ |
||
| 575 | LCD_DATA0_PORT &= ~_BV(LCD_DATA0_PIN); // LCD_FUNCTION_4BIT_1LINE>>4 |
||
| 576 | lcd_e_toggle(); |
||
| 577 | delay(64); /* some displays need this additional delay */ |
||
| 578 | |||
| 579 | /* from now the LCD only accepts 4 bit I/O, we can use lcd_command() */ |
||
| 580 | #else |
||
| 581 | /* |
||
| 582 | * Initialize LCD to 8 bit memory mapped mode |
||
| 583 | */ |
||
| 584 | |||
| 585 | /* enable external SRAM (memory mapped lcd) and one wait state */ |
||
| 586 | MCUCR = _BV(SRE) | _BV(SRW); |
||
| 587 | |||
| 588 | /* reset LCD */ |
||
| 589 | delay(16000); /* wait 16ms after power-on */ |
||
| 590 | lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ |
||
| 591 | delay(4992); /* wait 5ms */ |
||
| 592 | lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ |
||
| 593 | delay(64); /* wait 64us */ |
||
| 594 | lcd_write(LCD_FUNCTION_8BIT_1LINE,0); /* function set: 8bit interface */ |
||
| 595 | delay(64); /* wait 64us */ |
||
| 596 | #endif |
||
| 597 | |||
| 598 | #if KS0073_4LINES_MODE |
||
| 599 | /* Display with KS0073 controller requires special commands for enabling 4 line mode */ |
||
| 600 | lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_ON); |
||
| 601 | lcd_command(KS0073_4LINES_MODE); |
||
| 602 | lcd_command(KS0073_EXTENDED_FUNCTION_REGISTER_OFF); |
||
| 603 | #else |
||
| 604 | lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */ |
||
| 605 | #endif |
||
| 606 | lcd_command(LCD_DISP_OFF); /* display off */ |
||
| 607 | lcd_clrscr(); /* display clear */ |
||
| 608 | lcd_command(LCD_MODE_DEFAULT); /* set entry mode */ |
||
| 609 | lcd_command(dispAttr); /* display/cursor control */ |
||
| 610 | |||
| 611 | }/* lcd_init */ |