I2CLCD
Driver for HD44780 LCD via I2C interface
 All Functions Groups Pages
i2clcd.c
1 /*****************************************************************************
2 
3  i2clcd.c - LCD over I2C library
4  Designed for HD44870 based LCDs with I2C expander PCF8574X
5  on Atmels AVR MCUs
6 
7  Copyright (C) 2006 Nico Eichelmann and Thomas Eichelmann
8  2014 clean up by Falk Brunner
9 
10  This library is free software; you can redistribute it and/or
11  modify it under the terms of the GNU Lesser General Public
12  License as published by the Free Software Foundation; either
13  version 2.1 of the License, or (at your option) any later version.
14 
15  This library is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public
21  License along with this library; if not, write to the Free Software
22  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 
24  You can contact the authors at info@computerheld.de
25 
26 *****************************************************************************/
27 
28 /*
29  Version 0.11
30  Requires I2C-Library from Peter Fleury http://jump.to/fleury
31 
32  See i2clcd.h for description and example.
33 */
34 
35 #include <avr/pgmspace.h>
36 #include <stdbool.h>
37 #include <stdint.h>
38 #include "main.h"
39 #include <util/delay.h>
40 #include "i2clcd.h"
41 #include "i2cmaster.h"
42 
43 // global variable für light control
44 
45 static uint8_t lightOn=0;
46 
47 //- Display initialization sequence
48 
49 void lcd_init(void) {
50 
51  lcd_light(false);
52 
53  _delay_ms(15); //- Wait for more than 15ms after VDD rises to 4.5V
54  lcd_write(CMD_D1 | CMD_D0); //- Set interface to 8-bit
55  _delay_ms(5); //- Wait for more than 4.1ms
56  lcd_write(CMD_D1 | CMD_D0); //- Set interface to 8-bit
57  _delay_ms(0.1); //- Wait for more than 100us
58  lcd_write(CMD_D1 | CMD_D0); //- Set interface to 8-bit
59  lcd_write(CMD_D1); //- Set interface to 4-bit
60 
61  //- From now on in 4-bit-Mode
65  _delay_ms(2);
67 }
68 
69 //- Write data to i2c
70 
71 void lcd_write_i2c(uint8_t value) {
72  i2c_start_wait(LCD_I2C_DEVICE+I2C_WRITE);
73  i2c_write(value);
74  i2c_stop();
75 }
76 
77 //- Write nibble to display with pulse of enable bit
78 // map pinout between PCF8574 and LCD
79 
80 void lcd_write(uint8_t value) {
81  uint8_t data_out=0;
82 
83  // map data to LCD pinout
84  if (value & CMD_D0) data_out |= LCD_D4;
85  if (value & CMD_D1) data_out |= LCD_D5;
86  if (value & CMD_D2) data_out |= LCD_D6;
87  if (value & CMD_D3) data_out |= LCD_D7;
88  if (value & CMD_RS) data_out |= LCD_RS;
89  if (value & CMD_RW) data_out |= LCD_RW;
90  if (!lightOn) data_out |= LCD_LIGHT_N;
91 
92  lcd_write_i2c(data_out | LCD_E); //- Set new data and enable to high
93  lcd_write_i2c(data_out); //- Set enable to low
94 }
95 
96 //- Read data from i2c
97 
98 uint8_t lcd_read_i2c(void) {
99  uint8_t lcddata = 0x00;
100 
101  i2c_start_wait(LCD_I2C_DEVICE+I2C_READ);
102  lcddata = i2c_readNak();
103  i2c_stop();
104  return lcddata;
105 }
106 
107 //- Read data from display over i2c (lower nibble contains LCD data)
108 
109 uint8_t lcd_read(bool mode) {
110  uint8_t lcddata, data;
111 
112  if(mode == LCD_DATA) {
113  lcddata = (LCD_E | LCD_RS | LCD_RW | LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7);
114  } else {
115  lcddata = (LCD_E | LCD_RW | LCD_D4 | LCD_D5 | LCD_D6 | LCD_D7);
116  }
117 
118  if (!lightOn) lcddata |= LCD_LIGHT_N;
119  lcd_write_i2c(lcddata);
120  lcddata = lcd_read_i2c();
121 
122  data=0;
123  // map data from LCD pinout to internal positions
124  if (lcddata & LCD_D4) data |= CMD_D0;
125  if (lcddata & LCD_D5) data |= CMD_D1;
126  if (lcddata & LCD_D6) data |= CMD_D2;
127  if (lcddata & LCD_D7) data |= CMD_D3;
128 
129  lcddata=0;
130  if (!lightOn) lcddata |= LCD_LIGHT_N;
131  lcd_write_i2c(lcddata);
132 
133  return data;
134 }
135 
136 //- Read one complete byte via i2c from display
137 
138 uint8_t lcd_getbyte(bool mode) {
139  uint8_t hi, lo;
140 
141  hi = lcd_read(mode);
142  lo = lcd_read(mode);
143  return (hi << 4) + (lo & 0x0F);
144 }
145 
146 //- Issue a command to the display (use the defined commands above)
147 
148 void lcd_command(uint8_t command) {
149 
150  lcd_write((command >> 4));
151  lcd_write((command & 0x0F));
152 }
153 
154 //- Print string to cursor position
155 
156 void lcd_print(char *string) {
157 
158  while(*string) {
159  lcd_putchar(*string++);
160  }
161 }
162 
163 //- Print string from flash to cursor position
164 
165 void lcd_print_P(PGM_P string) {
166  uint8_t c;
167 
168  while((c=pgm_read_byte(string++))) {
169  lcd_putchar(c);
170  }
171 }
172 
173 //- Put char to atctual cursor position
174 
175 void lcd_putchar(char lcddata) {
176 
177  lcd_write((lcddata >> 4) | CMD_RS);
178  lcd_write((lcddata & 0x0F) | CMD_RS);
179 }
180 
181 //- Put char to position
182 
183 bool lcd_putcharlc(uint8_t line, uint8_t col, char value) {
184 
185  if(!lcd_gotolc(line, col)) return false;
186  lcd_putchar(value);
187 
188  return true;
189 }
190 
191 //- Print string to position (If string is longer than LCD_COLS overwrite first chars)(line, row, string)
192 
193 bool lcd_printlc(uint8_t line, uint8_t col, char *string) {
194 
195  if (!lcd_gotolc(line, col)) return false;
196 
197  while(*string) {
198  lcd_putchar(*string++);
199  col++;
200  if(col > LCD_COLS) {
201  col = 1;
202  lcd_gotolc(line, col);
203  }
204  }
205  return true;
206 }
207 
208 //- Print string from flash to position
209 // (If string is longer than LCD_COLS overwrite first chars)(line, row, string)
210 
211 bool lcd_printlc_P(uint8_t line, uint8_t col, char *string) {
212  char c;
213 
214  if (!lcd_gotolc(line, col)) return false;
215 
216  while((c=pgm_read_byte(string++))) {
217  lcd_putchar(c);
218  col++;
219  if(col > LCD_COLS) {
220  col = 1;
221  lcd_gotolc(line, col);
222  }
223  }
224  return true;
225 }
226 
227 //- Print string to position (If string is longer than LCD_COLS continue in next line)
228 
229 bool lcd_printlcc(uint8_t line, uint8_t col, char *string) {
230 
231  if (!lcd_gotolc(line, col)) return false;
232 
233  while(*string) {
234  lcd_putchar(*string++);
235  col++;
236  if(col > LCD_COLS) {
237  line++;
238  col = 1;
239  if(line > LCD_LINES) {
240  line = 1;
241  }
242  lcd_gotolc(line, col);
243  }
244  }
245  return true;
246 }
247 
248 //- Print string from flash to position
249 // (If string is longer than LCD_COLS continue in next line)
250 
251 bool lcd_printlcc_P(uint8_t line, uint8_t col, char *string) {
252  char c;
253 
254  if (!lcd_gotolc(line, col)) return false;
255 
256  while((c=pgm_read_byte(string++))) {
257  lcd_putchar(c);
258  col++;
259  if(col > LCD_COLS) {
260  line++;
261  col = 1;
262  if(line > LCD_LINES) {
263  line = 1;
264  }
265  lcd_gotolc(line, col);
266  }
267  }
268  return true;
269 }
270 
271 //- Go to position (line, column)
272 
273 bool lcd_gotolc(uint8_t line, uint8_t col ) {
274  uint8_t lcddata=0;
275 
276  if( (line > LCD_LINES) ||
277  (col > LCD_COLS) ||
278  ((line == 0) || (col == 0)) ) return false;
279 
280  switch (line) {
281  case 1: lcddata = LCD_LINE1; break;
282  case 2: lcddata = LCD_LINE2; break;
283  case 3: lcddata = LCD_LINE3; break;
284  case 4: lcddata = LCD_LINE4; break;
285  }
286  lcddata |= 0x80;
287  lcddata += (col-1);
288  lcd_command(lcddata);
289  return true;
290 }
291 
292 //- Go to nextline (if next line > (LCD_LINES-1) return false)
293 
294 bool lcd_nextline(void) {
295  uint8_t line, col;
296 
297  lcd_getlc(&line, &col);
298  if (!lcd_gotolc(line + 1, 1)) {
299  return false;
300  } else {
301  return true;
302  }
303 }
304 
305 //- Get line and row (target byte for line, target byte for row)
306 
307 bool lcd_getlc(uint8_t *line, uint8_t *col) {
308  uint8_t lcddata;
309 
310  lcddata = lcd_getbyte(LCD_ADDRESS);
311  if (lcddata & (1 << 7)) return false; // LCD busy
312 
313  if (lcddata >= LCD_LINE1 && lcddata < (LCD_LINE1+LCD_COLS)) {
314  *line = 1;
315  *col = lcddata - LCD_LINE1 + 1;
316  return true;
317  } else if (lcddata >= LCD_LINE2 && lcddata < (LCD_LINE2+LCD_COLS)) {
318  *line = 2;
319  *col = lcddata - LCD_LINE2 + 1;
320  return true;
321  } else if (lcddata >= LCD_LINE3 && lcddata < (LCD_LINE3+LCD_COLS)) {
322  *line = 3;
323  *col = lcddata - LCD_LINE3 + 1;
324  return true;
325  } else if (lcddata >= LCD_LINE4 && lcddata < (LCD_LINE4+LCD_COLS)) {
326  *line = 4;
327  *col = lcddata - LCD_LINE4 + 1;
328  return true;
329  }
330 
331  return false;
332 }
333 
334 // turn light on/off
335 
336 void lcd_light(bool light) {
337 
338  if (!light) {
339  lightOn = 1;
340  lcd_write_i2c(LCD_LIGHT_ON);
341  } else {
342  lightOn = 0;
343  lcd_write_i2c(LCD_LIGHT_OFF);
344  }
345 }
346 
347 //- Check if busy
348 
349 bool lcd_busy(void) {
350  uint8_t state;
351 
352  state = lcd_getbyte(LCD_ADDRESS);
353  if (state & (1 << 7)) {
354  return true;
355  } else {
356  return false;
357  }
358 }
#define LCD_LINE1
Definition: i2clcd.h:112
void lcd_light(bool light)
Turn backlight ON/OFF.
Definition: i2clcd.c:336
bool lcd_printlc(uint8_t line, uint8_t col, char *string)
Print string to position (If string is longer than LCD_COLS overwrite first chars in line) ...
Definition: i2clcd.c:193
#define LCD_LIGHT_N
Definition: i2clcd.h:161
#define LCD_CLEAR
Definition: i2clcd.h:197
uint8_t lcd_read(bool mode)
Read data from display over i2c (for internal use)
Definition: i2clcd.c:109
bool lcd_printlcc(uint8_t line, uint8_t col, char *string)
Print string to position (If string is longer than LCD_COLS continue in next line) ...
Definition: i2clcd.c:229
void lcd_write_i2c(uint8_t value)
Write data to i2c (for internal use)
Definition: i2clcd.c:71
#define LCD_RS
Definition: i2clcd.h:159
#define LCD_DISPLAYSHIFTOFF
Definition: i2clcd.h:207
bool lcd_printlc_P(uint8_t line, uint8_t col, char *string)
Print string from Flash to position (If string is longer than LCD_COLS overwrite first chars in line)...
Definition: i2clcd.c:211
#define LCD_LINE3
Definition: i2clcd.h:114
#define LCD_CURSORON
Definition: i2clcd.h:215
#define LCD_BLINKINGOFF
Definition: i2clcd.h:218
uint8_t lcd_read_i2c(void)
Read data from i2c (for internal use)
Definition: i2clcd.c:98
void lcd_command(uint8_t command)
Issue a command to the display.
Definition: i2clcd.c:148
#define LCD_D7
Definition: i2clcd.h:157
#define LCD_D5
Definition: i2clcd.h:155
#define LCD_COLS
Definition: i2clcd.h:109
bool lcd_busy(void)
Check if LCD is busy.
Definition: i2clcd.c:349
#define LCD_E
Definition: i2clcd.h:162
void lcd_putchar(char lcddata)
Put char to cursor position.
Definition: i2clcd.c:175
#define LCD_ADDRESS
Definition: i2clcd.h:178
#define LCD_LINE2
Definition: i2clcd.h:113
#define LCD_INCREASE
Definition: i2clcd.h:204
uint8_t lcd_getbyte(bool mode)
Read one byte over i2c from display.
Definition: i2clcd.c:138
#define LCD_5X7
Definition: i2clcd.h:239
void lcd_print_P(PGM_P string)
Print string from Flash to cursor position.
Definition: i2clcd.c:165
void lcd_print(char *string)
Print string to cursor position.
Definition: i2clcd.c:156
bool lcd_getlc(uint8_t *line, uint8_t *col)
Get line and col of the cursor position.
Definition: i2clcd.c:307
void lcd_write(uint8_t value)
Write nibble to display with toggle of enable-bit.
Definition: i2clcd.c:80
#define LCD_RW
Definition: i2clcd.h:160
#define LCD_DATA
Definition: i2clcd.h:179
bool lcd_nextline(void)
Go to nextline (if next line > LCD_LINES return false)
Definition: i2clcd.c:294
#define LCD_DISPLAYON
Definition: i2clcd.h:213
#define LCD_LINE4
Definition: i2clcd.h:115
#define LCD_I2C_DEVICE
Definition: i2clcd.h:107
#define LCD_LINES
Definition: i2clcd.h:108
#define LCD_LINE_MODE
Definition: i2clcd.h:110
void lcd_init(void)
Display initialization sequence.
Definition: i2clcd.c:49
#define LCD_D6
Definition: i2clcd.h:156
bool lcd_printlcc_P(uint8_t line, uint8_t col, char *string)
Print string from flash to position (If string is longer than LCD_COLS continue in next line) ...
Definition: i2clcd.c:251
#define LCD_D4
Definition: i2clcd.h:154
bool lcd_gotolc(uint8_t line, uint8_t col)
Go to position.
Definition: i2clcd.c:273