1 |
#include <xc.h>
|
2 |
#include <stdio.h>
|
3 |
#include <stdint.h>
|
4 |
#include <stdbool.h>
|
5 |
#include "mcc_generated_files/system/clock.h"
|
6 |
#include "mcc_generated_files/i2c_host/mssp.h"
|
7 |
#include "custom.h"
|
8 |
#include "lcdi2c.h"
|
9 |
|
10 |
// commands
|
11 |
#define LCD_CLEARDISPLAY 0x01
|
12 |
#define LCD_RETURNHOME 0x02
|
13 |
#define LCD_ENTRYMODESET 0x04
|
14 |
#define LCD_DISPLAYCONTROL 0x08
|
15 |
#define LCD_CURSORSHIFT 0x10
|
16 |
#define LCD_FUNCTIONSET 0x20
|
17 |
#define LCD_SETCGRAMADDR 0x40
|
18 |
#define LCD_SETDDRAMADDR 0x80
|
19 |
|
20 |
// flags for display entry mode
|
21 |
#define LCD_ENTRYRIGHT 0x00
|
22 |
#define LCD_ENTRYLEFT 0x02
|
23 |
#define LCD_ENTRYSHIFTINCREMENT 0x01
|
24 |
#define LCD_ENTRYSHIFTDECREMENT 0x00
|
25 |
|
26 |
// flags for display on/off control
|
27 |
#define LCD_DISPLAYON 0x04
|
28 |
#define LCD_DISPLAYOFF 0x00
|
29 |
#define LCD_CURSORON 0x02
|
30 |
#define LCD_CURSOROFF 0x00
|
31 |
#define LCD_BLINKON 0x01
|
32 |
#define LCD_BLINKOFF 0x00
|
33 |
|
34 |
// flags for display/cursor shift
|
35 |
#define LCD_DISPLAYMOVE 0x08
|
36 |
#define LCD_CURSORMOVE 0x00
|
37 |
#define LCD_MOVERIGHT 0x04
|
38 |
#define LCD_MOVELEFT 0x00
|
39 |
|
40 |
// flags for function set
|
41 |
#define LCD_8BITMODE 0x10
|
42 |
#define LCD_4BITMODE 0x00
|
43 |
#define LCD_2LINE 0x08
|
44 |
#define LCD_1LINE 0x00
|
45 |
#define LCD_5x10DOTS 0x04
|
46 |
#define LCD_5x8DOTS 0x00
|
47 |
|
48 |
// flags for backlight control
|
49 |
#define LCD_BACKLIGHT 0x08
|
50 |
#define LCD_NOBACKLIGHT 0x00
|
51 |
|
52 |
#define En 0b00000100 // Enable bit
|
53 |
#define Rw 0b00000010 // Read/Write bit
|
54 |
#define Rs 0b00000001 // Register select bit : Data
|
55 |
#define Co 0b00000000 // Register select bit : command
|
56 |
|
57 |
void expanderWrite(uint8_t data);
|
58 |
void pulseEnable(uint8_t _data);
|
59 |
void write4bits(uint8_t value) ;
|
60 |
void send(uint8_t value, uint8_t mode) ;
|
61 |
inline void command(uint8_t value);
|
62 |
void writeChar(uint8_t value);
|
63 |
void writeStr(char* str);
|
64 |
void writeStrXY(uint8_t col, uint8_t row,char* str);
|
65 |
inline void writeData(char value) ;
|
66 |
bool lcdinit(uint8_t lcd_addr, uint8_t lcd_cols, uint8_t lcd_rows);
|
67 |
bool lcdclose(void);
|
68 |
inline void clear(void);
|
69 |
inline void home(void);
|
70 |
void setCursor(uint8_t col, uint8_t row);
|
71 |
void noDisplay(void);
|
72 |
inline void display(void) ;
|
73 |
void noCursor(void);
|
74 |
void cursor(void) ;
|
75 |
void noBlink(void);
|
76 |
void blink(void) ;
|
77 |
void scrollDisplayLeft(void) ;
|
78 |
void scrollDisplayRight(void) ;
|
79 |
void leftToRight(void) ;
|
80 |
void rightToLeft(void) ;
|
81 |
void autoscroll(void) ;
|
82 |
void noAutoscroll(void) ;
|
83 |
void createChar(uint8_t location, uint8_t charmap[]) ;
|
84 |
void noBacklight(void);
|
85 |
void backlight(void);
|
86 |
bool getBacklight(void);
|
87 |
|
88 |
uint8_t _displayfunction = 0;
|
89 |
uint8_t _displaycontrol = 0;
|
90 |
uint8_t _displaymode = 0;
|
91 |
uint8_t _cols = 0;
|
92 |
uint8_t _rows = 0;
|
93 |
uint8_t _charsize = 0;
|
94 |
uint8_t _backlightval = 0;
|
95 |
|
96 |
unsigned char lcdAddress = 0;
|
97 |
bool _initialized = false;
|
98 |
|
99 |
#define TRY4BITMODE 0x03
|
100 |
#define SET4BITMODE 0x02
|
101 |
|
102 |
inline void expanderWrite(uint8_t data)
|
103 |
{
|
104 |
data |= _backlightval;
|
105 |
//bool I2C1_Write(uint16_t address, uint8_t *data, size_t dataLength)
|
106 |
// & ?
|
107 |
I2C1_Host.Write((uint16_t)lcdAddress, &data, sizeof(data) );
|
108 |
// Wire.endTransmission();
|
109 |
}
|
110 |
|
111 |
inline void pulseEnable(uint8_t _data)
|
112 |
{
|
113 |
expanderWrite(_data | En); // En high
|
114 |
//delayMicroseconds(1); // enable pulse must be >450ns
|
115 |
delayUs(1);
|
116 |
|
117 |
expanderWrite(_data & ~En); // En low
|
118 |
delayUs(50);
|
119 |
//delayMicroseconds(50); // commands need > 37us to settle
|
120 |
}
|
121 |
|
122 |
inline void write4bits(uint8_t value)
|
123 |
{
|
124 |
expanderWrite(value);
|
125 |
pulseEnable(value);
|
126 |
}
|
127 |
|
128 |
// write either command or data
|
129 |
inline void send(uint8_t value, uint8_t mode)
|
130 |
{
|
131 |
uint8_t highnib=value&0xf0;
|
132 |
uint8_t lownib=(value<<4)&0xf0;
|
133 |
write4bits((highnib)|mode);
|
134 |
write4bits((lownib)|mode);
|
135 |
}
|
136 |
|
137 |
inline void command(uint8_t value)
|
138 |
{
|
139 |
uint8_t highnib=value&0xf0;
|
140 |
uint8_t lownib=(value<<4)&0xf0;
|
141 |
write4bits((highnib));
|
142 |
write4bits((lownib));
|
143 |
}
|
144 |
|
145 |
/*********** mid level commands, for sending data/cmds */
|
146 |
|
147 |
/*
|
148 |
inline void command(uint8_t value)
|
149 |
{
|
150 |
send(value, Co);
|
151 |
} */
|
152 |
|
153 |
//inline
|
154 |
inline void writeChar(uint8_t value)
|
155 |
{
|
156 |
// send((uint8_t)value, Rs);
|
157 |
uint8_t highnib=value&0xf0;
|
158 |
uint8_t lownib=(value<<4)&0xf0;
|
159 |
write4bits((highnib)|Rs);
|
160 |
write4bits((lownib)|Rs);
|
161 |
}
|
162 |
|
163 |
inline void writeStr(char* str)
|
164 |
{
|
165 |
for(int i=0; str[i]!='\0'; i++)
|
166 |
writeChar(str[i]);
|
167 |
};
|
168 |
|
169 |
inline void writeStrXY(uint8_t col, uint8_t row,char* str)
|
170 |
{
|
171 |
setCursor(col, row);
|
172 |
writeStr(str);
|
173 |
};
|
174 |
|
175 |
inline void writeData(char value)
|
176 |
{
|
177 |
send((uint8_t)value, Rs);
|
178 |
}
|
179 |
|
180 |
uint8_t setlcdmode = 0b00010000;
|
181 |
|
182 |
inline bool lcdinit(uint8_t lcd_addr, uint8_t lcd_cols, uint8_t lcd_rows)
|
183 |
{
|
184 |
|
185 |
if (lcd_addr == 0)
|
186 |
return(false);
|
187 |
else
|
188 |
lcdAddress = lcd_addr;
|
189 |
|
190 |
_cols = lcd_cols;
|
191 |
_rows = lcd_rows;
|
192 |
_charsize = LCD_5x8DOTS;
|
193 |
_backlightval = LCD_BACKLIGHT;
|
194 |
|
195 |
if (lcd_rows > 1)
|
196 |
setlcdmode |= 0x08;
|
197 |
|
198 |
_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
|
199 |
|
200 |
if (_rows > 1)
|
201 |
{
|
202 |
_displayfunction |= LCD_2LINE;
|
203 |
}
|
204 |
// for some 1 line displays you can select a 10 pixel high font
|
205 |
if ((_charsize != 0) && (_rows == 1))
|
206 |
{
|
207 |
_displayfunction |= LCD_5x10DOTS;
|
208 |
}
|
209 |
|
210 |
// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
|
211 |
// according to datasheet, we need at least 40ms after power rises above 2.7V
|
212 |
// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
|
213 |
delayMs(50);
|
214 |
|
215 |
// Now we pull both RS and R/W low to begin commands
|
216 |
expanderWrite(_backlightval); // reset expanderand turn backlight off (Bit 8 =1)
|
217 |
delayMs(1000);
|
218 |
|
219 |
//put the LCD into 4 bit mode
|
220 |
// this is according to the hitachi HD44780 datasheet
|
221 |
// figure 24, pg 46
|
222 |
|
223 |
// we start in 8bit mode, try to set 4 bit mode
|
224 |
// oder
|
225 |
// write4bits(TRY4BITMODE << 4);
|
226 |
|
227 |
write4bits(TRY4BITMODE << 4);
|
228 |
delayMs(5);
|
229 |
//delayMicroseconds(4500); // wait min 4.1ms
|
230 |
|
231 |
// second try
|
232 |
write4bits(TRY4BITMODE << 4);
|
233 |
//delayMicroseconds(4500); // wait min 4.1ms
|
234 |
delayMs(5);
|
235 |
|
236 |
// third go!
|
237 |
write4bits(TRY4BITMODE << 4);
|
238 |
delayMs(150);
|
239 |
|
240 |
// finally, set to 4-bit interface
|
241 |
// write4bits(0b00101000);
|
242 |
write4bits(SET4BITMODE << 4);
|
243 |
|
244 |
// set # lines, font size, etc.
|
245 |
command(LCD_FUNCTIONSET | _displayfunction);
|
246 |
|
247 |
// turn the display on with no cursor or blinking default
|
248 |
_displaycontrol = LCD_DISPLAYON | LCD_CURSORON | LCD_BLINKOFF;
|
249 |
|
250 |
display();
|
251 |
|
252 |
// clear it off
|
253 |
clear();
|
254 |
|
255 |
// Initialize to default text direction (for roman languages)
|
256 |
_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
|
257 |
|
258 |
// set the entry mode
|
259 |
//// command(LCD_ENTRYMODESET | _displaymode);
|
260 |
|
261 |
home();
|
262 |
_initialized = true;
|
263 |
return(true);
|
264 |
}
|
265 |
|
266 |
bool lcdclose(void)
|
267 |
{
|
268 |
lcdAddress = 0;
|
269 |
_displayfunction = 0;
|
270 |
_displaycontrol = 0;
|
271 |
_displaymode = 0;
|
272 |
_cols = 0;
|
273 |
_rows = 0;
|
274 |
_charsize = 0;
|
275 |
_backlightval = 0;
|
276 |
I2C1_Host.Deinitialize();
|
277 |
_initialized = false;
|
278 |
return(true);
|
279 |
};
|
280 |
|
281 |
/********** high level commands, for the user! */
|
282 |
inline void clear()
|
283 |
{
|
284 |
command(LCD_CLEARDISPLAY);// clear display, set cursor position to zero
|
285 |
delayMs(2);
|
286 |
//delayMicroseconds(2000); // this command takes a long time!
|
287 |
}
|
288 |
|
289 |
inline void home()
|
290 |
{
|
291 |
command(LCD_RETURNHOME); // set cursor position to zero
|
292 |
//delayMicroseconds(2000); // this command takes a long time!
|
293 |
delayMs(2);
|
294 |
}
|
295 |
|
296 |
void setCursor(uint8_t col, uint8_t row)
|
297 |
{
|
298 |
char row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
|
299 |
|
300 |
if (row > _rows)
|
301 |
row = _rows;
|
302 |
row = _rows-1; // we count rows starting w/0
|
303 |
|
304 |
command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
|
305 |
}
|
306 |
|
307 |
// Turn the display on/off (quickly)
|
308 |
void noDisplay()
|
309 |
{
|
310 |
_displaycontrol &= ~LCD_DISPLAYON;
|
311 |
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
312 |
}
|
313 |
|
314 |
inline void display()
|
315 |
{
|
316 |
_displaycontrol |= LCD_DISPLAYON;
|
317 |
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
318 |
}
|
319 |
|
320 |
// Turns the underline cursor on/off
|
321 |
void noCursor()
|
322 |
{
|
323 |
_displaycontrol &= ~LCD_CURSORON;
|
324 |
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
325 |
}
|
326 |
|
327 |
void cursor()
|
328 |
{
|
329 |
_displaycontrol |= LCD_CURSORON;
|
330 |
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
331 |
}
|
332 |
|
333 |
// Turn on and off the blinking cursor
|
334 |
void noBlink()
|
335 |
{
|
336 |
_displaycontrol &= ~LCD_BLINKON;
|
337 |
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
338 |
}
|
339 |
|
340 |
void blink()
|
341 |
{
|
342 |
_displaycontrol |= LCD_BLINKON;
|
343 |
command(LCD_DISPLAYCONTROL | _displaycontrol);
|
344 |
}
|
345 |
|
346 |
// These commands scroll the display without changing the RAM
|
347 |
void scrollDisplayLeft(void)
|
348 |
{
|
349 |
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
|
350 |
}
|
351 |
|
352 |
void scrollDisplayRight(void)
|
353 |
{
|
354 |
command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
|
355 |
}
|
356 |
|
357 |
// This is for text that flows Left to Right
|
358 |
void leftToRight(void)
|
359 |
{
|
360 |
_displaymode |= LCD_ENTRYLEFT;
|
361 |
command(LCD_ENTRYMODESET | _displaymode);
|
362 |
}
|
363 |
|
364 |
// This is for text that flows Right to Left
|
365 |
void rightToLeft(void)
|
366 |
{
|
367 |
_displaymode &= ~LCD_ENTRYLEFT;
|
368 |
command(LCD_ENTRYMODESET | _displaymode);
|
369 |
}
|
370 |
|
371 |
// This will 'right justify' text from the cursor
|
372 |
void autoscroll(void)
|
373 |
{
|
374 |
_displaymode |= LCD_ENTRYSHIFTINCREMENT;
|
375 |
command(LCD_ENTRYMODESET | _displaymode);
|
376 |
}
|
377 |
|
378 |
// This will 'left justify' text from the cursor
|
379 |
void noAutoscroll(void)
|
380 |
{
|
381 |
_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
|
382 |
command(LCD_ENTRYMODESET | _displaymode);
|
383 |
}
|
384 |
|
385 |
// Allows us to fill the first 8 CGRAM locations
|
386 |
// with custom characters
|
387 |
void createChar(uint8_t location, uint8_t charmap[])
|
388 |
{
|
389 |
location &= 0x7; // we only have 8 locations 0-7
|
390 |
command(LCD_SETCGRAMADDR | (uint8_t)(location << 3));
|
391 |
for (int i=0; i<8; i++)
|
392 |
writeData(charmap[i]);
|
393 |
}
|
394 |
|
395 |
// Turn the (optional) backlight off/on
|
396 |
void noBacklight(void)
|
397 |
{
|
398 |
_backlightval=LCD_NOBACKLIGHT;
|
399 |
expanderWrite(0);
|
400 |
}
|
401 |
|
402 |
void backlight(void)
|
403 |
{
|
404 |
_backlightval=LCD_BACKLIGHT;
|
405 |
expanderWrite(0);
|
406 |
}
|
407 |
|
408 |
// Get status of blacklight
|
409 |
bool getBacklight()
|
410 |
{
|
411 |
return(_backlightval == LCD_BACKLIGHT);
|
412 |
}
|
413 |
|
414 |
void load_custom_character(uint8_t char_num, uint8_t *rows)
|
415 |
{
|
416 |
createChar(char_num, rows);
|
417 |
}
|
418 |
|
419 |
void setBacklight(uint8_t new_val)
|
420 |
{
|
421 |
if (new_val)
|
422 |
{
|
423 |
backlight(); // turn backlight on
|
424 |
}
|
425 |
else
|
426 |
{
|
427 |
noBacklight(); // turn backlight off
|
428 |
}
|
429 |
}
|
430 |
|
431 |
bool isinitialized(void)
|
432 |
{
|
433 |
return(_initialized);
|
434 |
};
|
435 |
|
436 |
const lcd_host_t lcd =
|
437 |
{
|
438 |
.init = lcdinit,
|
439 |
.close = lcdclose,
|
440 |
.printC = writeChar,
|
441 |
.printStr = writeStr,
|
442 |
.printStrXY = writeStrXY,
|
443 |
.cls = clear,
|
444 |
.home = home,
|
445 |
.hideDisplay = noDisplay,
|
446 |
.showDisplay = display,
|
447 |
.blinkOff = noBlink,
|
448 |
.blinkOn = blink,
|
449 |
.hideCursor = noCursor,
|
450 |
.showcursor = cursor,
|
451 |
.scrollLeft = scrollDisplayLeft,
|
452 |
.scrollRight = scrollDisplayRight,
|
453 |
.setLeftToRight = leftToRight,
|
454 |
.setRightToLeft = rightToLeft,
|
455 |
.backlightOff = noBacklight,
|
456 |
.backlightOn = backlight,
|
457 |
.getBacklight = getBacklight,
|
458 |
.setAutoscrollMode = autoscroll,
|
459 |
.setNoAutoscrollModel = noAutoscroll,
|
460 |
.createChar = createChar,
|
461 |
.setCursor = setCursor,
|
462 |
.initialized = isinitialized
|
463 |
} ;
|