1 /*
2   OrangutanLCD.h - Library for using the LCD on the Orangutan LV, SV, SVP, X2, or 3pi robot.
3 */
4 
5 /*
6  * Copyright (c) 2008-2012 Pololu Corporation. For more information, see
7  *
8  *   http://www.pololu.com
9  *   http://forum.pololu.com
10  *   http://www.pololu.com/docs/0J18
11  *
12  * You may freely modify and share this code, as long as you keep this
13  * notice intact (including the two links above).  Licensed under the
14  * Creative Commons BY-SA 3.0 license:
15  *
16  *   http://creativecommons.org/licenses/by-sa/3.0/
17  *
18  * Disclaimer: To the extent permitted by law, Pololu provides this work
19  * without any warranty.  It might be defective, in which case you agree
20  * to be responsible for all resulting costs and damages.
21  *
22  * This library incorporates some code originally written by Tom Benedict
23  * as part of Orangutan-Lib and released into the public domain.
24  */
25 
26 #ifndef OrangutanLCD_h
27 #define OrangutanLCD_h
28 
29 #include <avr/pgmspace.h>
30 #include <avr/io.h>
31 #include "../OrangutanResources/include/OrangutanModel.h"
32 
33 
34 #define LCD_LEFT			0
35 #define LCD_RIGHT			1
36 #define CURSOR_SOLID		0
37 #define CURSOR_BLINKING		1
38 
39 
40 #ifdef _ORANGUTAN_SVP
41 
42 #define LCD_DB4				PORTC2		// PC2
43 #define LCD_DB5				PORTC3		// PC3
44 #define LCD_DB6				PORTC4		// PC4
45 #define LCD_DB7				PORTC5		// PC5
46 
47 #define LCD_RS_DDR			DDRB
48 #define LCD_RS_PORT			PORTB
49 #define LCD_E_DDR			DDRB
50 #define LCD_E_PORT			PORTB
51 #define LCD_RW_DDR			DDRB
52 #define LCD_RW_PORT			PORTB
53 
54 #define LCD_RS				PORTB0
55 #define LCD_RW				PORTB1
56 #define LCD_E				PORTB2
57 
58 #define LCD_BF_DDR			DDRC
59 #define LCD_BF_PIN			PINC
60 #define LCD_BF_PORT			PORTC
61 #define LCD_BF_MASK			(1 << LCD_DB7)
62 
63 // Since we're only using four data lines, and since the pins they're
64 // wired up to don't start with 0, we need to shift them into
65 // position in order to load their values into the LCD.
66 //
67 //	PortC:     7 6 5 4 3 2 1 0
68 //  LCD Data:      3 2 1 0
69 //
70 //  Pass your 4-bit LCD data value to the LCD_PORTC_DATA macro to get
71 //  the appropriate PORTC value.  You can use the macro as follows:
72 //
73 //  PORTC &= ~LCD_PORTC_MASK;
74 //  PORTC |= LCD_PORTC_DATA(lcdData);
75 
76 #define LCD_PORTC_MASK			((1 << LCD_DB4) | (1 << LCD_DB5) | (1 << LCD_DB6) | (1 << LCD_DB7))
77 #define LCD_PORTC_DATA(data)	((data & 0x0F) << LCD_DB4)
78 
79 
80 #elif defined(_ORANGUTAN_X2)
81 
82 #define LCD_RS_DDR			DDRB
83 #define LCD_RS_PORT			PORTB
84 #define LCD_E_DDR			DDRB
85 #define LCD_E_PORT			PORTB
86 #define LCD_RW_DDR			DDRB
87 #define LCD_RW_PORT			PORTB
88 
89 #define LCD_RS				PORTB0
90 #define LCD_RW				PORTB1
91 #define LCD_E				PORTB3
92 
93 #define LCD_BF_DDR			DDRC
94 #define LCD_BF_PIN			PINC
95 #define LCD_BF_PORT			PORTC
96 #define LCD_BF_MASK			(1 << PORTC7)
97 
98 
99 #else
100 
101 // On the Orangutan LV-168 and 3pi robot, the LCD control lines are split between
102 // ports B and D:
103 
104 #define LCD_DB4				PORTB1		// PB1
105 #define LCD_DB5				PORTB4		// PB4
106 #define LCD_DB6				PORTB5		// PB5
107 #define LCD_DB7				PORTD7		// PD7
108 
109 #define LCD_RS_DDR			DDRD
110 #define LCD_RS_PORT			PORTD
111 #define LCD_E_DDR			DDRD
112 #define LCD_E_PORT			PORTD
113 #define LCD_RW_DDR			DDRB
114 #define LCD_RW_PORT			PORTB
115 
116 #define LCD_RW				PORTB0
117 #define LCD_RS				PORTD2
118 #define LCD_E				PORTD4
119 
120 #define LCD_BF_DDR			DDRD
121 #define LCD_BF_PIN			PIND
122 #define LCD_BF_PORT			PORTD
123 #define LCD_BF_MASK			(1 << LCD_DB7)
124 
125 // Since we're only using four data lines, and since the pins they're
126 // wired up to don't start with 0, we need to shift them into
127 // position in order to load their values into the LCD.  Port B uses
128 // bits 1, 4, and 5.  We need to make our data line up like this:
129 //
130 //	PortB:     7 6 5 4 3 2 1 0
131 //  LCD Data:      2 1     0
132 //
133 //  PortD:     7 6 5 4 3 2 1 0
134 //  LCD Data:  3
135 //
136 //  Pass your 4-bit LCD data value to the LCD_PORTB_DATA and LCD_PORTD_DATA
137 //  macros to get the respective PORTB and PORTD values.  You can use them
138 //  as follows:
139 //
140 //  PORTB &= ~LCD_PORTB_MASK;
141 //  PORTB |= LCD_PORTB_DATA(lcdData);
142 //  PORTD &= ~LCD_PORTD_MASK;
143 //  PORTD |= LCD_PORTD_DATA(lcdData);
144 
145 #define LCD_PORTB_MASK			((1 << LCD_DB4) | (1 << LCD_DB5) | (1 << LCD_DB6))
146 #define LCD_PORTD_MASK			(1 << LCD_DB7)
147 #define LCD_PORTB_DATA(data)	(((data & 0x01) <<1 ) | ((data & 0x06) << 3))
148 #define LCD_PORTD_DATA(data)	((data & 0x08) << 4)
149 
150 
151 #endif
152 
153 // Commands
154 
155 #define LCD_CLEAR		0x01
156 #define LCD_SHOW_BLINK	0x0F
157 #define LCD_SHOW_SOLID	0x0E
158 #define LCD_HIDE		0x0C
159 #define LCD_CURSOR_L	0x10
160 #define LCD_CURSOR_R	0x14
161 #define LCD_SHIFT_L		0x18
162 #define LCD_SHIFT_R		0x1C
163 
164 #ifdef __cplusplus
165 
166 class OrangutanLCD
167 {
168   public:
169 
170     // constructor
171 	OrangutanLCD();
172 
173 	// Send either data or a command
174 	// If we are using a 4-bit interface, only the low nibble is
175 	// sent when numSends == 1; otherwise, first the high nibble is sent
176 	// and then the low nibble is sent.
177 	// If we are using an 8-bit interface, numSends has no effect: the data is
178 	// sent via a single 8-bit transfer.
179 	static void send(unsigned char data, unsigned char rs, unsigned char numSends);
180 
send_cmd(unsigned char cmd)181 	static inline void send_cmd(unsigned char cmd)
182 	{
183 		send(cmd, 0, 2);
184 	}
185 
send_4bit_cmd(unsigned char cmd)186 	static inline void send_4bit_cmd(unsigned char cmd)
187 	{
188 		send(cmd, 0, 1);
189 	}
190 
send_data(unsigned char data)191 	static inline void send_data(unsigned char data)
192 	{
193 		send(data, 1, 2);
194 	}
195 
196 	// clears the LCD screen and returns the cursor to position (0, 0)
197 	static void clear();
198 
199 	// prints an ASCII character at the current LCD cursor position
200 	static void print(char character);
print(unsigned char character)201 	static inline void print(unsigned char character)
202 	{
203 		print((char)character);
204 	};
205 
206 	// sends a string to the LCD.  You can send a string
207 	// longer than 8 characters, but only eight characters show up.
208 	// The string is printed from wherever the cursor is, and will
209 	// not span lines.  (This lets you concatenate print statements.)
210 	static void print(const char *str);
211 
212 	// Sends a PROGMEM string to the LCD.
213 	static void printFromProgramSpace(const char *str);
214 
215 #ifndef LIB_ORANGUTAN
216 	static void printIn(const char *str);  // for compatibility with other libs
217 #endif
218 
219 	// prints signed and unsigned integer values at the current cursor
220 	// position and will not span lines.
221 	static void print(unsigned long value);
222 	static void print(long value);
print(unsigned int value)223 	static inline void print(unsigned int value)
224 	{
225 		print((unsigned long)value);
226 	};
print(int value)227 	static inline void print(int value)
228 	{
229 		print((long)value);
230 	};
231 
232 	// prints a two-byte value (word) in hex at your current
233 	// cursor location.
234 	static void printHex(unsigned int word);
235 
236 	// prints a one-byte value in hex at your current location
237 	static void printHex(unsigned char byte);
238 
239 	// lcd_binary prints a byte in binary starting at your current cursor location.
240 	static void printBinary(unsigned char byte);
241 
242 	// Go to an (X,Y) location on the LCD.  The top line is Y=0, the
243 	// leftmost character is X=0.
244 	static void gotoXY(unsigned char x, unsigned char y);
245 
246 	// Shows the cursor as either a BLINKING or SOLID block
247 	// cursorType should be either CURSOR_BLINKING or CURSOR_SOLID
248 	static void showCursor(unsigned char cursorType);
249 
250 	// Hide the cursor
251 	static void hideCursor();
252 
253 	// shifts the cursor LEFT or RIGHT the given number of positions.
254 	// direction should be either LCD_LEFT or LCD_RIGHT
255 	static void moveCursor(unsigned char direction, unsigned char num);
256 
257 	// shifts the display LEFT or RIGHT the given number of
258 	// positions, delaying for delay_time milliseconds between each shift.
259 	// This is what you'd use for a scrolling display.
260 	// direction should be either LCD_LEFT or LCD_RIGHT
261 	static void scroll(unsigned char direction, unsigned char num,
262 						unsigned int delay_time);
263 
264 	// Loads a custom character into the character memory of the LCD.
265 	// The parameter 'number' is a character value between 0 and 7,
266 	// which represents the character that will be customized.  That is
267 	// The pointer 'picture_p' is a pointer to an 8 byte array in
268 	// program space containing the picture data.  This kind of array
269 	// may be defined as follows:
270 	//
271 	// #include <avr/pgmspace.h>
272 	// const char pi[] PROGMEM = { 0b11100, .... }
273 	//
274 	// The first byte represets row one, which has, in this example,
275 	// three black pixels on the left, followed by two clear
276 	// pixels.  Subsequent values specify the pixels for the remaining
277 	// rows of the 5x8 character.
278 	//
279 	// After loading all desired custom characters, clear() should be
280 	// called to reset the LCD.
281 	static void loadCustomCharacter(const char *picture_p, unsigned char number);
282 
283 	// Initializes the LCD library for printf support.  After this,
284 	// printf will start sending characters to the LCD.
285 	static void initPrintf();	// uses default width and height for device
286 	static void initPrintf(unsigned char lcdWidth, unsigned char lcdHeight);
287 
288 
289   private:
290 
init()291 	static inline void init()
292 	{
293 		static unsigned char initialized = 0;
294 
295 		if (!initialized)
296 		{
297 			initialized = 1;
298 			init2();
299 		}
300 	}
301 
302 	// initializes the LCD hardware; this function MUST be called before
303 	// the LCD can be used.  It is called if needed by the inline
304 	// member function init(), which is called if needed by send().
305 	static void init2();
306 
307   	// Wait for the busy flag to clear on a 4-bit interface
308 	// This is necessarily more complicated than the 8-bit interface
309 	// because E must be strobed twice to get the full eight bits
310 	// back from the LCD, even though we're only interested in one
311 	// of them.
312 	static void busyWait();
313 
314 	// Send data via the 4- or 8-bit interface.  This assumes the busy flag
315 	// is clear, that our DDRs are all set, etc.  Basically all it does is
316 	// line up the bits and send them out the appropriate I/O lines while
317 	// strobing the E control line.
318 	static void sendData(unsigned char data);
319 
320 	// prints a hex nibble (half of a hex byte) at
321 	// your current cursor location.
322 	static void printHexNibble(unsigned char nibble);
323 };
324 
325 extern "C" {
326 #endif // __cplusplus
327 
328 void lcd_init_printf(void);
329 void lcd_init_printf_with_dimensions(unsigned char width, unsigned char height);
330 void clear(void);
331 void print(const char *str);
332 void print_from_program_space(const char *str);
333 void print_character(char c);
334 void print_long(long value);
335 void print_unsigned_long(unsigned long value);
336 void print_binary(unsigned char value);
337 void print_hex(unsigned int value);
338 void print_hex_byte(unsigned char value);
339 void lcd_goto_xy(unsigned char col, unsigned char row);
340 void lcd_show_cursor(unsigned char cursorType);
341 void lcd_hide_cursor(void);
342 void lcd_move_cursor(unsigned char direction, unsigned char num);
343 void lcd_scroll(unsigned char direction, unsigned char num,
344 		unsigned int delay_time);
345 void lcd_load_custom_character(const char *picture, unsigned char number);
346 
347 #ifdef __cplusplus
348 }
349 #endif
350 
351 #endif
352 
353 
354 // Local Variables: **
355 // mode: C++ **
356 // c-basic-offset: 4 **
357 // tab-width: 4 **
358 // indent-tabs-mode: t **
359 // end: **
360