Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1702 | - | 1 | /* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */ |
2 | //this code is heavily borrowed from official Arduino source v.0017 |
||
3 | // link to original http://code.google.com/p/arduino/source/browse/trunk/hardware/libraries/LiquidCrystal/LiquidCrystal.cpp |
||
4 | #include "Max_LCD.h" |
||
5 | #include "Max3421e.h" |
||
6 | |||
7 | #include <stdio.h> |
||
8 | #include <string.h> |
||
9 | #include <inttypes.h> |
||
10 | #include "WProgram.h" |
||
11 | |||
12 | // When the display powers up, it is configured as follows: |
||
13 | // |
||
14 | // 1. Display clear |
||
15 | // 2. Function set: |
||
16 | // DL = 1; 8-bit interface data |
||
17 | // N = 0; 1-line display |
||
18 | // F = 0; 5x8 dot character font |
||
19 | // 3. Display on/off control: |
||
20 | // D = 0; Display off |
||
21 | // C = 0; Cursor off |
||
22 | // B = 0; Blinking off |
||
23 | // 4. Entry mode set: |
||
24 | // I/D = 1; Increment by 1 |
||
25 | // S = 0; No shift |
||
26 | // |
||
27 | // Note, however, that resetting the Arduino doesn't reset the LCD, so we |
||
28 | // can't assume that it's in that state when a sketch starts |
||
29 | |||
30 | // pin definition and set/clear |
||
31 | |||
32 | #define RS 0x04 // RS pin |
||
33 | #define E 0x08 // E pin |
||
34 | |||
35 | #define SET_RS lcdPins |= RS |
||
36 | #define CLR_RS lcdPins &= ~RS |
||
37 | #define SET_E lcdPins |= E |
||
38 | #define CLR_E lcdPins &= ~E |
||
39 | |||
40 | #define SENDlcdPins() MAX3421E::gpioWr( lcdPins ) |
||
41 | |||
42 | #define LCD_sendcmd(a) { CLR_RS; \ |
||
43 | sendbyte(a); \ |
||
44 | } |
||
45 | |||
46 | #define LCD_sendchar(a) { SET_RS; \ |
||
47 | sendbyte(a); \ |
||
48 | } |
||
49 | |||
50 | static byte lcdPins; //copy of LCD pins |
||
51 | |||
52 | Max_LCD::Max_LCD() |
||
53 | { |
||
54 | lcdPins = 0; |
||
55 | } |
||
56 | |||
57 | |||
58 | void Max_LCD::init() |
||
59 | { |
||
60 | _displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS; |
||
61 | |||
62 | // MAX3421E::gpioWr(0x55); |
||
63 | |||
64 | begin(16, 1); |
||
65 | } |
||
66 | |||
67 | void Max_LCD::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) { |
||
68 | if (lines > 1) { |
||
69 | _displayfunction |= LCD_2LINE; |
||
70 | } |
||
71 | _numlines = lines; |
||
72 | _currline = 0; |
||
73 | |||
74 | // for some 1 line displays you can select a 10 pixel high font |
||
75 | if ((dotsize != 0) && (lines == 1)) { |
||
76 | _displayfunction |= LCD_5x10DOTS; |
||
77 | } |
||
78 | |||
79 | // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION! |
||
80 | // according to datasheet, we need at least 40ms after power rises above 2.7V |
||
81 | // before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50 |
||
82 | delayMicroseconds(50000); |
||
83 | lcdPins = 0x30; |
||
84 | SET_E; |
||
85 | SENDlcdPins(); |
||
86 | CLR_E; |
||
87 | SENDlcdPins(); |
||
88 | delayMicroseconds(10000); // wait min 4.1ms |
||
89 | //second try |
||
90 | SET_E; |
||
91 | SENDlcdPins(); |
||
92 | CLR_E; |
||
93 | SENDlcdPins(); |
||
94 | delayMicroseconds(10000); // wait min 4.1ms |
||
95 | // third go! |
||
96 | SET_E; |
||
97 | SENDlcdPins(); |
||
98 | CLR_E; |
||
99 | SENDlcdPins(); |
||
100 | delayMicroseconds(10000); |
||
101 | // finally, set to 4-bit interface |
||
102 | lcdPins = 0x20; |
||
103 | //SET_RS; |
||
104 | SET_E; |
||
105 | SENDlcdPins(); |
||
106 | //CLR_RS; |
||
107 | CLR_E; |
||
108 | SENDlcdPins(); |
||
109 | delayMicroseconds(10000); |
||
110 | // finally, set # lines, font size, etc. |
||
111 | command(LCD_FUNCTIONSET | _displayfunction); |
||
112 | |||
113 | // turn the display on with no cursor or blinking default |
||
114 | _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF; |
||
115 | display(); |
||
116 | |||
117 | // clear it off |
||
118 | clear(); |
||
119 | |||
120 | // Initialize to default text direction (for romance languages) |
||
121 | _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; |
||
122 | // set the entry mode |
||
123 | command(LCD_ENTRYMODESET | _displaymode); |
||
124 | } |
||
125 | |||
126 | /********** high level commands, for the user! */ |
||
127 | void Max_LCD::clear() |
||
128 | { |
||
129 | command(LCD_CLEARDISPLAY); // clear display, set cursor position to zero |
||
130 | delayMicroseconds(2000); // this command takes a long time! |
||
131 | } |
||
132 | |||
133 | void Max_LCD::home() |
||
134 | { |
||
135 | command(LCD_RETURNHOME); // set cursor position to zero |
||
136 | delayMicroseconds(2000); // this command takes a long time! |
||
137 | } |
||
138 | |||
139 | void Max_LCD::setCursor(uint8_t col, uint8_t row) |
||
140 | { |
||
141 | int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; |
||
142 | if ( row > _numlines ) { |
||
143 | row = _numlines-1; // we count rows starting w/0 |
||
144 | } |
||
145 | |||
146 | command(LCD_SETDDRAMADDR | (col + row_offsets[row])); |
||
147 | } |
||
148 | |||
149 | // Turn the display on/off (quickly) |
||
150 | void Max_LCD::noDisplay() { |
||
151 | _displaycontrol &= ~LCD_DISPLAYON; |
||
152 | command(LCD_DISPLAYCONTROL | _displaycontrol); |
||
153 | } |
||
154 | void Max_LCD::display() { |
||
155 | _displaycontrol |= LCD_DISPLAYON; |
||
156 | command(LCD_DISPLAYCONTROL | _displaycontrol); |
||
157 | } |
||
158 | |||
159 | // Turns the underline cursor on/off |
||
160 | void Max_LCD::noCursor() { |
||
161 | _displaycontrol &= ~LCD_CURSORON; |
||
162 | command(LCD_DISPLAYCONTROL | _displaycontrol); |
||
163 | } |
||
164 | void Max_LCD::cursor() { |
||
165 | _displaycontrol |= LCD_CURSORON; |
||
166 | command(LCD_DISPLAYCONTROL | _displaycontrol); |
||
167 | } |
||
168 | |||
169 | |||
170 | // Turn on and off the blinking cursor |
||
171 | void Max_LCD::noBlink() { |
||
172 | _displaycontrol &= ~LCD_BLINKON; |
||
173 | command(LCD_DISPLAYCONTROL | _displaycontrol); |
||
174 | } |
||
175 | void Max_LCD::blink() { |
||
176 | _displaycontrol |= LCD_BLINKON; |
||
177 | command(LCD_DISPLAYCONTROL | _displaycontrol); |
||
178 | } |
||
179 | |||
180 | // These commands scroll the display without changing the RAM |
||
181 | void Max_LCD::scrollDisplayLeft(void) { |
||
182 | command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); |
||
183 | } |
||
184 | void Max_LCD::scrollDisplayRight(void) { |
||
185 | command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); |
||
186 | } |
||
187 | |||
188 | // This is for text that flows Left to Right |
||
189 | void Max_LCD::leftToRight(void) { |
||
190 | _displaymode |= LCD_ENTRYLEFT; |
||
191 | command(LCD_ENTRYMODESET | _displaymode); |
||
192 | } |
||
193 | |||
194 | // This is for text that flows Right to Left |
||
195 | void Max_LCD::rightToLeft(void) { |
||
196 | _displaymode &= ~LCD_ENTRYLEFT; |
||
197 | command(LCD_ENTRYMODESET | _displaymode); |
||
198 | } |
||
199 | |||
200 | // This will 'right justify' text from the cursor |
||
201 | void Max_LCD::autoscroll(void) { |
||
202 | _displaymode |= LCD_ENTRYSHIFTINCREMENT; |
||
203 | command(LCD_ENTRYMODESET | _displaymode); |
||
204 | } |
||
205 | |||
206 | // This will 'left justify' text from the cursor |
||
207 | void Max_LCD::noAutoscroll(void) { |
||
208 | _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; |
||
209 | command(LCD_ENTRYMODESET | _displaymode); |
||
210 | } |
||
211 | |||
212 | // Allows us to fill the first 8 CGRAM locations |
||
213 | // with custom characters |
||
214 | void Max_LCD::createChar(uint8_t location, uint8_t charmap[]) { |
||
215 | location &= 0x7; // we only have 8 locations 0-7 |
||
216 | command(LCD_SETCGRAMADDR | (location << 3)); |
||
217 | for (int i=0; i<8; i++) { |
||
218 | write(charmap[i]); |
||
219 | } |
||
220 | } |
||
221 | |||
222 | /*********** mid level commands, for sending data/cmds */ |
||
223 | |||
224 | inline void Max_LCD::command(uint8_t value) { |
||
225 | LCD_sendcmd(value); |
||
226 | delayMicroseconds(100); |
||
227 | } |
||
228 | |||
229 | inline void Max_LCD::write(uint8_t value) { |
||
230 | LCD_sendchar(value); |
||
231 | } |
||
232 | |||
233 | void Max_LCD::sendbyte( uint8_t val ) |
||
234 | { |
||
235 | lcdPins &= 0x0f; //prepare place for the upper nibble |
||
236 | lcdPins |= ( val & 0xf0 ); //copy upper nibble to LCD variable |
||
237 | SET_E; //send |
||
238 | SENDlcdPins(); |
||
239 | delayMicroseconds(2); |
||
240 | CLR_E; |
||
241 | delayMicroseconds(2); |
||
242 | SENDlcdPins(); |
||
243 | lcdPins &= 0x0f; //prepare place for the lower nibble |
||
244 | lcdPins |= ( val << 4 ) & 0xf0; //copy lower nibble to LCD variable |
||
245 | SET_E; //send |
||
246 | SENDlcdPins(); |
||
247 | CLR_E; |
||
248 | SENDlcdPins(); |
||
249 | delayMicroseconds(100); |
||
250 | } |