forked from wwweagle/PIC20Odor
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlcdi2c.c
692 lines (523 loc) · 23 KB
/
lcdi2c.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
/*
* File: lcdi2c.c
* Author: Tony Lab
*
* Created on August 8, 2017, 9:59 AM
*/
#include "hal.h"
#include <i2c.h>
#include "utils.h"
int I2CError = 0;
void initI2C(void) {
unsigned int config2, config1;
/* Baud rate is set for 100 kHz */
config2 = (FCY / 100000 - FCY / 1111111) - 1;
/* Configure I2C for 7 bit address mode */
config1 = (I2C_ON & I2C_IDLE_CON & I2C_CLK_HLD &
I2C_IPMI_DIS & I2C_7BIT_ADD &
I2C_SLW_DIS & I2C_SM_DIS &
I2C_GCALL_DIS & I2C_STR_DIS &
I2C_NACK & I2C_ACK_DIS & I2C_RCV_DIS &
I2C_STOP_DIS & I2C_RESTART_DIS &
I2C_START_DIS);
OpenI2C(config1, config2);
}
void I2C_Write_Byte_Single_Reg(unsigned char deviceADDR, unsigned char val) {
if (I2CError) {
return;
}
uint32_t lcdTimer = millisCounter + 200u;
IdleI2C();
StartI2C();
/* Wait till Start sequence is completed */
while (I2CCONbits.SEN && lcdTimer > millisCounter);
/* Clear interrupt flag */
IFS0bits.MI2CIF = 0;
/* Write Slave address and set master for transmission */
MasterWriteI2C(deviceADDR);
/* Wait till address is transmitted */
while (I2CSTATbits.TBF && lcdTimer > millisCounter); // 8 clock cycles
while (!IFS0bits.MI2CIF && lcdTimer > millisCounter); // Wait for 9th clock cycle
IFS0bits.MI2CIF = 0; // Clear interrupt flag
while (I2CSTATbits.ACKSTAT && lcdTimer > millisCounter);
/* Transmit string of data */
MasterWriteI2C(val);
StopI2C();
/* Wait till stop sequence is completed */
while (I2CCONbits.PEN && lcdTimer > millisCounter);
//
// CloseI2C();
if (lcdTimer <= millisCounter) {
I2CError = 1;
}
}
unsigned char I2C_Read_Byte_Single_Reg(unsigned char deviceADDR) {
IdleI2C();
StartI2C();
/* Wait till Start sequence is completed */
while (I2CCONbits.SEN);
/* Clear interrupt flag */
IFS0bits.MI2CIF = 0;
/* Write Slave address and set master for transmission */
MasterWriteI2C(deviceADDR | 0x01);
/* Wait till address is transmitted */
while (I2CSTATbits.TBF); // 8 clock cycles
while (!IFS0bits.MI2CIF); // Wait for 9th clock cycle
IFS0bits.MI2CIF = 0; // Clear interrupt flag
while (I2CSTATbits.ACKSTAT);
/* Transmit string of data */
unsigned char val = MasterReadI2C();
StopI2C();
/* Wait till stop sequence is completed */
while (I2CCONbits.PEN);
//
// CloseI2C();
return val;
}
// LIQUIDCRYSTAL_I2C_PCF8574 V1.0
// Foreword: To successfully use this library you will to ensure the following.
// 1. Your PCF8574 LCD adaptor board is mapped either the same as outlined below or you have correctly re-assigned the pins for your board. I used the following;
// http://www.ebay.co.uk/itm/1Pcs-IIC-I2C-Serial-Interface-Board-Module-For-Arduino-LCD1602-LCD2004-Display-/281366957696?pt=LH_DefaultDomain_3&hash=item4182c70e80
// 2. You have to implement a simple delay routine capable of delaying in uSecs if you choose not to use the one provided. Which uses Timer 1 in 16bit mode.
// 3. If you change the dimensions of the LCD you adapt the initialisation to suit. This code was written for a 4 by 20.
// 4. You use the PIC18 Peripheral Library for I2C control. If not you will need to adapt your own routines for;
// I2C_Write_Byte_Single_Reg();
// I2C_Read_Byte_Single_Reg();
// Anywhere you may typically need to make changes have been tagged with 'TODO Adapt'
// Note : It was written and tested using the PIC18F2685. MPLABX v2.15, Compiler XC8 v1.35 and ICD 3.
// Some of the inspiration for the library was taken from the Arduino LiquidCrystal library and adapted for the XC8 Compiler
// See here : http://hmario.home.xs4all.nl/arduino/LiquidCrystal_I2C/
// Data sheets and useful information can be found here;
// LCD : https://www.sparkfun.com/datasheets/LCD/HD44780.pdf
// PCF8574 : http://www.nxp.com/documents/data_sheet/PCF8574.pdf
// I2C : http://ww1.microchip.com/downloads/en/AppNotes/00735a.pdf
// http://ww1.microchip.com/downloads/en/DeviceDoc/i2c.pdf
// http://www.nxp.com/documents/application_note/AN10216.pdf
// I2C Lib : C:\Program Files (x86)\Microchip\xc8\v1.35\sources\pic18\plib\i2c
// PIC18F2685 : http://www.microchip.com/wwwproducts/Devices.aspx?product=PIC18F2685
#include "lcdi2c.h"
#define LCD_CLEAR_DISPLAY 0x01 // Mode : Clears display
#define LCD_RETURN_HOME 0x02 // Mode : Returns cursor to home posn.
// Entry Mode Set
#define LCD_ENTRY_MODE_SET 0x04 // Mode : Entry Mode Set, Sets the cursor move dir and specs whether or not to shift the display
#define LCD_INCREMENT 0x02 // Sub Mode of ENTRY_MODE_SET : Increment DDRAM (I/D), Entry Left
#define LCD_DECREMENT 0x00 // Sub Mode of ENTRY_MODE_SET : Decrement DDRAM (I/D), Entry Right
#define LCD_SHIFT_ON 0x01 // Sub Mode of ENTRY_MODE_SET : Shift On (S), Shift Display when byte written. Display Shift
#define LCD_SHIFT_OFF 0x00 // Sub Mode of ENTRY_MODE_SET : Shift Off (S), Don't shift display when byte written. Cursor Move
// Display Function
#define LCD_DISPLAY_ON_OFF 0x08 // Mode : Display On/Off, Sets on/off of all display, Cursor on/off, Cursor Blink on/off
#define LCD_DISPLAY_ON 0x04 // Sub Mode of DISPLAY_ON_OFF : Puts display on (D)
#define LCD_DISPLAY_OFF 0x00 // Sub Mode of DISPLAY_ON_OFF : Puts display off (D)
#define LCD_CURSOR_ON 0x02 // Sub Mode of DISPLAY_ON_OFF : Puts cursor on (C)
#define LCD_CURSOR_OFF 0x00 // Sub Mode of DISPLAY_ON_OFF : Puts cursor off (C)
#define LCD_BLINKING_ON 0x01 // Sub Mode of DISPLAY_ON_OFF : Blinking cursor (B)
#define LCD_BLINKING_OFF 0x00 // Sub Mode of DISPLAY_ON_OFF : Solid cursor (B)
// Display Control
#define LCD_MV_CUR_SHIFT_DISPLAY 0x10 // Mode : Move the cursor and shifts the display
#define LCD_DISPLAY_SHIFT 0x08 // Sub Mode of CURSOR_SHFT_DIS : Display shifts after char print (SC)
#define LCD_CURSOR_SHIFT 0x00 // Sub Mode of CURSOR_SHFT_DIS : Cursor shifts after char print (SC)
#define LCD_SHIFT_RIGHT 0x04 // Sub Mode of CURSOR_SHFT_DIS : Cursor or Display shifts to right (RL)
#define LCD_SHIFT_LEFT 0x00 // Sub Mode of CURSOR_SHFT_DIS : Cursor or Display shifts to left (RL)
// Function Set
#define LCD_FUNCTION_SET 0x20 // Mode : Set the type of interface that the display will use
#define LCD_INTF8BITS 0x10 // Sub Mode of FUNCTION_SET : Select 8 bit interface (DL)
#define LCD_INTF4BITS 0x00 // Sub Mode of FUNCTION_SET : Select 4 bit interface (DL)
#define LCD_TWO_LINES 0x08 // Sub Mode of FUNCTION_SET : Selects two char line display (N)
#define LCD_ONE_LINE 0x00 // Sub Mode of FUNCTION_SET : Selects one char line display (N)
#define LCD_FONT_5_10 0x04 // Sub Mode of FUNCTION_SET : Selects 5 x 10 Dot Matrix Font (F)
#define LCD_FONT_5_7 0x00 // Sub Mode of FUNCTION_SET : Selects 5 x 7 Dot Matrix Font (F)
#define LCD_CG_RAM_ADDRESS 0x40 // Mode : Enables the setting of the Char Gen (CG) Ram Address, to be or'ed with require address
#define LCD_CG_RAM_ADDRESS_MASK 0b00111111 // Used to mask off the lower 6 bits of valid CG Ram Addresses
#define LCD_DD_RAM_ADDRESS 0x80 // Mode : Enables the setting of the Display Data (DD) Ram Address, to be or'ed with require address
#define LCD_DD_RAM_ADDRESS_MASK 0b01111111 // Used to mask off the lower 6 bits of valid DD Ram Addresses
//#define USE_BUSY_FLAG // Define this if you wish to use busy flag polling on slow LCD activities
// Change here for your I2C to 16 pin parallel interface // TODO Adapt
#define Bl 0b00001000 // Backlight enable bit (On = 1, Off =0)
#define En 0b00000100 // Enable bit (Enable on low edge)
#define Rw 0b00000010 // Read/Write bit (Read = 1, Write = 0)
#define Rs 0b00000001 // Register select bit (Data = 1, Control = 0)
// Change here for your I2C to 16 pin parallel interface // TODO Adapt
#define LCD_INIT ((0b00000000 | En) & ~Rs) & (~Rw) // Used to set all the O/Ps on the PCF8574 to initialise the LCD
#define LCD_8BIT_INIT 0b00110000 // Used to initialise the interface at the LCD
#define LCD_4BIT_INIT 0b00100000 // Used to initialise the interface at the LCD
//#define LCD_PCF8574_ADDR 0x4E // Modify this if the default address is altered
#define LCD_PCF8574_WEAK_PU 0b11110000 // Used to turn on PCF8574 Bits 7-4 on. To allow for read of LCD.
#define LCD_BUSY_FLAG_MASK 0b10000000 // Used to mask off the status of the busy flag
#define LCD_ADDRESS_COUNTER_MASK 0b01111111 // Used to mask off the value of the Address Counter
#define LCD_MAX_COLS 16
#define LCD_MAX_ROWS 2
//
// Code was written with the following assumptions as to PCF8574 -> Parallel 4bit convertor interconnections
// controlling a 20 by 4 LCD display. Assumes A0...A2 on PCF8574 are all pulled high. Giving address of 0x4E or 0b01001110 (0x27)
// (the last bit [b0] is I2C R/nW bit)
//
// Pin out for LCD display (16 pins)
// ---------------------------------
// 1 - Gnd
// 2 - Vcc
// 3 - VContrast
// 4 - RS - P0 - Pin 4 PCF8574
// 5 - RW - P1 - Pin 5 PCF8574
// 6 - En - P2 - Pin 6 PCF8574
// 7 - D0 - Don't Care
// 8 - D1 - Don't Care
// 9 - D2 - Don't Care
// 10 - D3 - Don't Care
// 11 - D4 - P4 - Pin 9 PCF8574
// 12 - D6 - P5 - Pin 10 PCF8574
// 13 - D6 - P6 - Pin 11 PCF8574
// 14 - D7 - P7 - Pin 12 PCF8574
// 15 - Anode LED
// 16 - Cathode LED
//
// PCF8574 register and pin mapping
// Bit 0 - RS - P0 - Pin 4 PCF8574
// Bit 1 - RW - P1 - Pin 5 PCF8574
// Bit 2 - En - P2 - Pin 6 PCF8574
// Bit 3 - Led - P3 - Pin 7 PCF8574 (Active High, Led turned on)
// Bit 4 - D4 - P4 - Pin 9 PCF8574
// Bit 5 - D5 - P5 - Pin 10 PCF8574
// Bit 6 - D6 - P6 - Pin 11 PCF8574
// Bit 7 - D7 - P7 - Pin 12 PCF8574
//
// The display is configured as follows:
//
// 1. Display clear
// 2. Function set:
// DL = 1; 4-bit interface data
// N = 0; 2-line display
// F = 0; 5x7 dot character font
// 3. Display on/off control:
// D = 1; Display on
// C = 0; Cursor off
// B = 0; Blinking off
// 4. Entry mode set:
// I/D = 1; Increment by 1
// S = 0; No shift
//
#define LCD_LINE1 0x00 // Constant used to point to start of LCD Line 1
#define LCD_LINE2 0x40 // Constant used to point to start of LCD Line 2
#define LCD_LINE3 0x14 // Constant used to point to start of LCD Line 3
#define LCD_LINE4 0x54 // Constant used to point to start of LCD Line 4
// DDRAM address:
// Display position
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13
// 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 52 53
// 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27
// 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 60 61 62 63 64 65 66 67
// Local variable declarations
static unsigned char _functionset = 0;
static unsigned char _entrymodeset = 0;
static unsigned char _displayfunction = 0;
static unsigned char _displaycontrol = 0;
static unsigned char _numlines = 0;
static unsigned char _backlightval = 0;
// Local function declarations
static void LCDsend(unsigned char value, unsigned char mode);
static unsigned char LCDreceive(unsigned char RsMode);
static void LCDwrite4bits(unsigned char value);
static unsigned char LCDread4bits(unsigned char RsEnMode);
static void LCDpulseEnableNeg(unsigned char value);
static void LCDpulseEnablePos(unsigned char value);
static void LCDwritePCF8574(unsigned char value);
static unsigned char LCDreadPCF8574(void);
void LCD_Init(void) {
//_backlightval &= ~Bl; // Off at start up
_backlightval |= Bl; // On at start up
_numlines = LCD_MAX_ROWS;
// Ensure supply rails are up before config sequence
DelayMicroseconds(50000);
// Set all control and data lines low. D4 - D7, En (High=1), Rw (Low = 0 or Write), Rs (Control/Instruction) (Low = 0 or Control)
I2C_Write_Byte_Single_Reg(LCD_PCF8574_ADDR, LCD_INIT); // Backlight off (Bit 3 = 0)
DelayMicroseconds(100);
// Sequence to put the LCD into 4 bit mode this is according to the hitachi HD44780 datasheet page 109
// we start in 8bit mode
LCDwrite4bits(LCD_8BIT_INIT);
DelayMicroseconds(4500); // wait more than 4.1ms
// second write
LCDwrite4bits(LCD_8BIT_INIT);
DelayMicroseconds(150); // wait > 100us
// third write
LCDwrite4bits(LCD_8BIT_INIT);
DelayMicroseconds(150);
// now set to 4-bit interface
LCDwrite4bits(LCD_4BIT_INIT);
DelayMicroseconds(150);
// set # lines, font size, etc.
_functionset = LCD_INTF4BITS | LCD_TWO_LINES | LCD_FONT_5_7;
LCDcommandWrite(LCD_FUNCTION_SET | _functionset);
//DelayMicroseconds(150);
_displayfunction = LCD_DISPLAY_OFF | LCD_CURSOR_OFF | LCD_BLINKING_OFF;
LCDdisplayOff();
// turn the display on with no cursor or blinking default
LCDdisplayOn();
// set the entry mode
_entrymodeset = LCD_INCREMENT | LCD_SHIFT_OFF; // Initialize to default text direction (for roman languages)
LCDcommandWrite(LCD_ENTRY_MODE_SET | _entrymodeset);
// Display Function set
// _displayfunction = LCD_DISPLAY_ON | LCD_CURSOR_OFF | LCD_BLINKING_OFF;
LCDcommandWrite(LCD_DISPLAY_ON_OFF | _displayfunction);
// Display Control set
_displaycontrol = LCD_DISPLAY_SHIFT | LCD_SHIFT_LEFT;
LCDcommandWrite(LCD_MV_CUR_SHIFT_DISPLAY | _displaycontrol);
// clear display and return cursor to home position. (Address 0)
LCDclear();
}
/********** high level commands, for the user! */
void LCD_Write_Char(char message) {
LCDdataWrite((unsigned char) message);
serialSend(SpLCD_Char, (unsigned char) message);
}
void LCD_Write_Str(const char *message) {
unsigned char *message_ptr = (unsigned char *) message;
while (*message_ptr)
LCDdataWrite((unsigned char) (*message_ptr++));
int iter;
for (iter = 0; message[iter] && iter < 16; iter++) {
serialSend(SpLCD_Char, (unsigned char) message[iter]);
}
}
void LCDclear(void) {
LCDcommandWrite(LCD_CLEAR_DISPLAY); // clear display, set cursor position to zero
#ifdef USE_BUSY_FLAG
while (LCDbusy()) {
};
#else
DelayMicroseconds(30000); // this command takes a long time!
#endif
serialSend(SpLCD_SET_XY, 0x20);
}
void LCDhome(void) {
LCDcommandWrite(LCD_RETURN_HOME); // set cursor position to zero
#ifdef USE_BUSY_FLAG
while (LCDbusy()) {
};
#else
DelayMicroseconds(30000); // this command takes a long time!
#endif
serialSend(SpLCD_SET_XY, 0x20);
}
void LCDsetCursor(unsigned char col, unsigned char row) {
int row_offsets[] = {LCD_LINE1, LCD_LINE2, LCD_LINE3, LCD_LINE4};
if (row >= _numlines) {
row = _numlines - 1; // we count rows starting w/0
}
LCDcommandWrite(LCD_DD_RAM_ADDRESS | (col + row_offsets[row]));
int val = (((col & 0x0f) << 1) | (row & 0x01)) & 0x1F;
serialSend(SpLCD_SET_XY, val);
}
// Turn the display on/off (quickly)
void LCDdisplayOff(void) {
_displayfunction &= ~LCD_DISPLAY_ON;
LCDcommandWrite(LCD_DISPLAY_ON_OFF | _displayfunction);
}
void LCDdisplayOn(void) {
_displayfunction |= LCD_DISPLAY_ON;
LCDcommandWrite(LCD_DISPLAY_ON_OFF | _displayfunction);
}
// Turns the underline cursor on/off
void LCDcursorOff(void) {
_displayfunction &= ~LCD_CURSOR_ON;
LCDcommandWrite(LCD_DISPLAY_ON_OFF | _displayfunction);
}
void LCDcursorOn(void) {
_displayfunction |= LCD_CURSOR_ON;
LCDcommandWrite(LCD_DISPLAY_ON_OFF | _displayfunction);
}
// Turn on and off the blinking cursor
void LCDblinkOff(void) {
_displayfunction &= ~LCD_BLINKING_ON;
LCDcommandWrite(LCD_DISPLAY_ON_OFF | _displayfunction);
}
void LCDblinkOn(void) {
_displayfunction |= LCD_BLINKING_ON;
LCDcommandWrite(LCD_DISPLAY_ON_OFF | _displayfunction);
}
// These commands scroll the display without changing the RAM
void LCDscrollDisplayLeft(void) {
_displaycontrol &= ~LCD_SHIFT_RIGHT;
_displaycontrol |= LCD_DISPLAY_SHIFT;
LCDcommandWrite(LCD_MV_CUR_SHIFT_DISPLAY | _displaycontrol);
}
void LCDscrollDisplayRight(void) {
_displaycontrol |= LCD_SHIFT_RIGHT;
_displaycontrol |= LCD_DISPLAY_SHIFT;
LCDcommandWrite(LCD_MV_CUR_SHIFT_DISPLAY | _displaycontrol);
}
// This is for text that flows Left to Right
void LCDleftToRight(void) {
_entrymodeset |= LCD_INCREMENT;
//_entrymodeset |= LCD_SHIFT_ON;
LCDcommandWrite(LCD_ENTRY_MODE_SET | _entrymodeset);
}
// This is for text that flows Right to Left
void LCDrightToLeft(void) {
_entrymodeset &= ~LCD_INCREMENT;
//_entrymodeset &= ~LCD_SHIFT_ON;
LCDcommandWrite(LCD_ENTRY_MODE_SET | _entrymodeset);
}
// This will 'right justify' text from the cursor. Display shift
void LCDautoscroll(void) {
_entrymodeset |= LCD_SHIFT_ON;
//_entrymodeset |= LCD_INCREMENT;
LCDcommandWrite(LCD_ENTRY_MODE_SET | _entrymodeset);
}
// This will 'left justify' text from the cursor. Cursor Move
void LCDnoAutoscroll(void) {
_entrymodeset &= ~LCD_SHIFT_ON;
//_entrymodeset &= ~LCD_INCREMENT;
LCDcommandWrite(LCD_ENTRY_MODE_SET | _entrymodeset);
}
// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LCDcreateChar(unsigned char location, unsigned char charmap[]) {
location &= 0x7; // we only have 8 locations 0-7
LCDcommandWrite(LCD_CG_RAM_ADDRESS | (location << 3));
int i;
for (i = 0; i < 8; i++)
LCDdataWrite(charmap[i]);
}
// Turn the (optional) backlight off/on
void LCDnoBacklight(void) {
_backlightval &= ~Bl;
LCDwritePCF8574(LCDreadPCF8574()); // Dummy write to LCD, only led control bit is of interest
}
void LCDbacklight(void) {
_backlightval |= Bl;
LCDwritePCF8574(LCDreadPCF8574()); // Dummy write to LCD, only led control bit is of interest
}
/*********** mid level commands, for sending data/cmds */
inline void LCDcommandWrite(unsigned char value) {
LCDsend(value, Rs & ~Rs);
}
inline unsigned char LCDcommandRead(void) {
return LCDreceive(Rs & ~Rs);
}
inline void LCDdataWrite(unsigned char value) {
LCDsend(value, Rs);
}
inline unsigned char LCDdataRead(void) {
return LCDreceive(Rs);
}
unsigned char LCDbusy(void) {
return LCDcommandRead() & LCD_BUSY_FLAG_MASK;
}
unsigned char LCDaddressCounter(void) {
return LCDcommandRead() & LCD_ADDRESS_COUNTER_MASK;
}
unsigned char LCDreadDDRam(unsigned char address) {
LCDcommandWrite(LCD_DD_RAM_ADDRESS | (address & LCD_DD_RAM_ADDRESS_MASK));
return LCDdataRead();
}
unsigned char LCDreadCGRam(unsigned char address) {
LCDcommandWrite(LCD_CG_RAM_ADDRESS | (address & LCD_CG_RAM_ADDRESS_MASK));
return LCDdataRead();
}
/************ low level data write commands **********/
// Change this routine for your I2C to 16 pin parallel interface, if your pin interconnects are different to that outlined above // TODO Adapt
// write either command or data
static void LCDsend(unsigned char value, unsigned char RsMode) {
unsigned char highnib = value & 0xF0;
unsigned char lownib = value << 4;
lownib &= 0xF0;
LCDwrite4bits((highnib) | En | RsMode);
LCDwrite4bits((lownib) | En | RsMode);
}
// Change this routine for your I2C to 16 pin parallel interface, if your pin interconnects are different to that outlined above // TODO Adapt
// read either command or data
static unsigned char LCDreceive(unsigned char RsMode) {
unsigned char highnib;
unsigned char lownib;
LCDwritePCF8574(LCD_PCF8574_WEAK_PU | (En & ~En) | RsMode); // Set P7..P4 = 1, En = 0, RnW = 0, Rs = XX
highnib = LCDread4bits(LCD_PCF8574_WEAK_PU | En | RsMode);
lownib = LCDread4bits(LCD_PCF8574_WEAK_PU | En | RsMode);
LCDwritePCF8574((LCD_PCF8574_WEAK_PU & ~LCD_PCF8574_WEAK_PU) | En | RsMode); // Set P7..P4 = 1, En = 1, RnW = 0, Rs = XX
return (unsigned char) ((highnib & 0xF0) | ((lownib & 0xF0) >> 4));
}
static void LCDwrite4bits(unsigned char nibEnRsMode) {
LCDwritePCF8574(nibEnRsMode & ~Rw);
LCDpulseEnableNeg(nibEnRsMode & ~Rw);
}
static unsigned char LCDread4bits(unsigned char RsEnMode) {
unsigned char b;
LCDpulseEnablePos(RsEnMode | Rw);
b = LCDreadPCF8574(); // Read the data from the LCD just after the rising edge. NOT WELL DOCUMENTED!
LCDpulseEnableNeg(RsEnMode | Rw);
return b;
}
static void LCDpulseEnableNeg(unsigned char _data) {
LCDwritePCF8574(_data | En); // En high
DelayMicroseconds(1); // enable pulse must be >450ns
LCDwritePCF8574(_data & ~En); // En low
DelayMicroseconds(50); // commands need > 37us to settle
}
static void LCDpulseEnablePos(unsigned char _data) {
LCDwritePCF8574(_data & ~En); // En low
DelayMicroseconds(1); // enable pulse must be >450ns
LCDwritePCF8574(_data | En); // En high
DelayMicroseconds(50); // commands need > 37us to settle
}
static void LCDwritePCF8574(unsigned char value) {
I2C_Write_Byte_Single_Reg(LCD_PCF8574_ADDR, value | _backlightval);
}
void DelayMicroseconds(unsigned short t) {
unsigned short i = 0;
while (i < t) {
// Nop();
// Nop();
// Nop();
// Nop();
// Nop();
// Nop();
// Nop();
// Nop();
Nop();
Nop();
Nop();
Nop();
Nop();
Nop();
i++;
}
}
static unsigned char LCDreadPCF8574(void) {
return I2C_Read_Byte_Single_Reg(LCD_PCF8574_ADDR);
}
void lcdWriteNumber_G2(int val, int x, int y) {
int tenK = val / 10000;
int K = (val % 10000) / 1000;
int H = (val % 1000) / 100;
int T = (val % 100) / 10;
int N = val % 10;
int leadFlag = 0;
LCDsetCursor(x, y);
if (tenK) {
LCD_Write_Char('0' + tenK);
LCDsetCursor(++x, y);
leadFlag = 1;
}
if (K || leadFlag) {
LCD_Write_Char('0' + K);
LCDsetCursor(++x, y);
leadFlag = 1;
}
if (H || leadFlag) {
LCD_Write_Char('0' + H);
LCDsetCursor(++x, y);
leadFlag = 1;
}
if (T || leadFlag) {
LCD_Write_Char('0' + T);
LCDsetCursor(++x, y);
}
LCD_Write_Char('0' + N);
}
void splash_G2(const char* line1, const char* line2) {
LCDhome();
LCDclear();
LCD_Write_Str(line1);
LCDsetCursor(0, 1);
LCD_Write_Str(line2);
wait_Sec(1);
}