1+ /* -----------------------------------------
2+ * G.Raf^engineering
3+ * www.sunriax.at (github.com/0x007e)
4+ * -----------------------------------------
5+ * Platform: Independent
6+ * Hardware: ATTiny406/1606/...
7+ * -----------------------------------------
8+ * Version: 1.0 Release
9+ * Author: G.Raf
10+ * Description:
11+ * Function file for lcd library
12+ * -----------------------------------------
13+ */
14+
15+ #include "lcd.h"
16+
17+ // +---------------------------------------------------------------+
18+ // | LCD initialization |
19+ // +---------------------------------------------------------------+
20+ void lcd_init (void )
21+ {
22+ // Initialize LCD command and data lines
23+ LCD_PORT_DATA .DIRSET = LCD_RS | LCD_E ;
24+ LCD_PORT_CTRL .DIRSET = LCD_DB3 | LCD_DB2 | LCD_DB1 | LCD_DB0 ;
25+
26+ LCD_PORT_DATA .OUTCLR = LCD_RS | LCD_E ;
27+ LCD_PORT_CTRL .OUTCLR = LCD_DB3 | LCD_DB2 | LCD_DB1 | LCD_DB0 ;
28+
29+ // Wait until LCD has started
30+ _delay_ms (LCD_STARTUP_TIME );
31+
32+ // Setup 4 bit mode & wait function time
33+ lcd_set (LCD_FUNCTION );
34+ _delay_us (LCD_FUNCTION_TIME );
35+
36+ // Setup LCD settings
37+ lcd_cmd (LCD_FUNCTION | LCD_FUNCTION_2LINE ); // Setup number of display lines and character font
38+ lcd_cmd (LCD_DISPLAY | LCD_DISPLAY_ON ); // | LCD_CURSOR_ON | LCD_BLINK_ON); // Setup display status, display cursor, display cursor blink
39+ lcd_cmd (LCD_ENTRY | LCD_ENTRY_INCREMENT ); // Setup display cursor move direction
40+
41+ // Clears entire display
42+ lcd_clear ();
43+ }
44+
45+ // +---------------------------------------------------------------+
46+ // | LCD disable function |
47+ // +---------------------------------------------------------------+
48+ void lcd_disable (void )
49+ {
50+ // Disable LCD
51+ LCD_PORT_DATA .OUTCLR = LCD_RS | LCD_E ;
52+ LCD_PORT_CTRL .OUTCLR = LCD_DB3 | LCD_DB2 | LCD_DB1 | LCD_DB0 ;
53+
54+ LCD_PORT_DATA .DIRCLR = LCD_RS | LCD_E ;
55+ LCD_PORT_CTRL .DIRCLR = LCD_DB3 | LCD_DB2 | LCD_DB1 | LCD_DB0 ;
56+ }
57+
58+ // +---------------------------------------------------------------+
59+ // | LCD generate clock |
60+ // +---------------------------------------------------------------+
61+ void lcd_clock (void )
62+ {
63+ LCD_PORT_CTRL .OUTSET = LCD_E ; // Enable E (HIGH) @ control port
64+ _delay_us ((1000000UL /(F_LCD * 2 ))); // Wait half of defined clock period
65+ LCD_PORT_CTRL .OUTCLR = LCD_E ; // Disable E (LOW) @ control port
66+ _delay_us ((1000000UL /(F_LCD * 2 ))); // Wait half of defined clock period
67+ }
68+
69+ // +---------------------------------------------------------------+
70+ // | LCD set nibble at display databus |
71+ // +---------------------------------------------------------------+
72+ // | Parameter: data(7:4) -> higher nibble data |
73+ // +---------------------------------------------------------------+
74+ void lcd_set (unsigned char data )
75+ {
76+ // Reset LCD data port
77+ LCD_PORT_DATA .OUTCLR = LCD_DB3 | LCD_DB2 | LCD_DB1 | LCD_DB0 ;
78+
79+ if (data & (1 <<7 )) // Check if data bit 7 is set
80+ LCD_PORT_DATA .OUTSET = LCD_DB3 ; // Set data bit 3 @ lcd bus
81+ if (data & (1 <<6 )) // Check if data bit 6 is set
82+ LCD_PORT_DATA .OUTSET = LCD_DB2 ; // Set data bit 2 @ lcd bus
83+ if (data & (1 <<5 )) // Check if data bit 5 is set
84+ LCD_PORT_DATA .OUTSET = LCD_DB1 ; // Set data bit 1 @ lcd bus
85+ if (data & (1 <<4 )) // Check if data bit 4 is set
86+ LCD_PORT_DATA .OUTSET = LCD_DB0 ; // Set data bit 0 @ lcd bus
87+
88+ // Generate a clock period
89+ lcd_clock ();
90+ }
91+
92+ // +---------------------------------------------------------------+
93+ // | LCD instruction transfer |
94+ // +---------------------------------------------------------------+
95+ // | Parameter: instruction -> display command |
96+ // +---------------------------------------------------------------+
97+ void lcd_cmd (unsigned char instruction )
98+ {
99+ // Select instruction register
100+ LCD_PORT_CTRL .OUTCLR = LCD_RS ;
101+
102+ lcd_set (instruction ); // Write high nibble to databus
103+ lcd_set ((instruction <<4 )); // Write low nibble to databus
104+
105+ // Wait until instruction is accessed on the LCD
106+ _delay_us (LCD_CMD_TIME );
107+ }
108+
109+ // +---------------------------------------------------------------+
110+ // | LCD character transfer |
111+ // +---------------------------------------------------------------+
112+ // | Parameter: data -> ASCII/defined character |
113+ // +---------------------------------------------------------------+
114+ void lcd_char (unsigned char data )
115+ {
116+ // Select data register
117+ LCD_PORT_CTRL .OUTSET = LCD_RS ;
118+
119+ lcd_set (data ); // Write high nibble to databus
120+ lcd_set ((data <<4 )); // Write low nibble to databus
121+
122+ // Wait until data is accessed on the LCD
123+ _delay_us (LCD_WRITE_TIME );
124+ }
125+
126+ // +---------------------------------------------------------------+
127+ // | LCD string transfer |
128+ // +---------------------------------------------------------------+
129+ // | Parameter: data (ptr) -> ASCII/ defined character array |
130+ // +---------------------------------------------------------------+
131+ void lcd_string (const char * data )
132+ {
133+ // Wait until \0 escape char is reached
134+ while (* data != LCD_NULL )
135+ {
136+ lcd_char ((unsigned char )* data ); // Send character
137+ data ++ ; // Increment data
138+ }
139+ }
140+
141+ // +---------------------------------------------------------------+
142+ // | LCD clear screen |
143+ // +---------------------------------------------------------------+
144+ void lcd_clear (void )
145+ {
146+ lcd_cmd (LCD_CLEAR ); // Clear the LCD screen
147+ _delay_ms (LCD_RETURN_TIME ); // Wait LCD is cleared
148+ }
149+
150+ // +---------------------------------------------------------------+
151+ // | LCD cursor to home position |
152+ // +---------------------------------------------------------------+
153+ void lcd_home (void )
154+ {
155+ lcd_cmd (LCD_HOME ); // Return cursor to the start position (0/0)
156+ _delay_ms (LCD_RETURN_TIME ); // Wait until CURSOR is at home position
157+ }
158+
159+ // +---------------------------------------------------------------+
160+ // | LCD cursor position |
161+ // +---------------------------------------------------------------+
162+ // | Parameter: x -> cursor to X position |
163+ // | y -> cursor to Y position |
164+ // +---------------------------------------------------------------+
165+ void lcd_cursor (unsigned char x , unsigned char y )
166+ {
167+ // Switch to LCD display line
168+ switch (y )
169+ {
170+ case 0 : lcd_cmd (LCD_START_ADDR + x ); break ; // Start at display line 0 and column x
171+ case 1 : lcd_cmd (LCD_START_ADDR + 0x40 + x ); break ; // Start at display line 1 and column x
172+ case 2 : lcd_cmd (LCD_START_ADDR + LCD_COLUMNS * 2 + x ); break ; // Start at display line 2 and column x
173+ case 3 : lcd_cmd (LCD_START_ADDR + 0x50 + x ); break ; // Start at display line 3 and column x
174+ default : return ; // Return if no LCD display line is set
175+ }
176+ }
177+
178+ // +---------------------------------------------------------------+
179+ // | LCD character to next block |
180+ // +---------------------------------------------------------------+
181+ // | Parameter: shift -> 0 = right |
182+ // | 1 = left |
183+ // +---------------------------------------------------------------+
184+ void lcd_shift (LCD_Shift shift )
185+ {
186+ if (shift == LCD_Right )
187+ lcd_cmd (LCD_SHIFT | LCD_SHIFT_DISPLAY | LCD_SHIFT_RIGHT );
188+ else
189+ lcd_cmd (LCD_SHIFT | LCD_SHIFT_DISPLAY );
190+
191+ _delay_us (LCD_SHIFT_TIME );
192+ }
193+
194+ // +---------------------------------------------------------------+
195+ // | LCD save patterns to RAM |
196+ // +---------------------------------------------------------------+
197+ // | Parameter: address -> pattern ram address |
198+ // | predefined: LCD_CGADDR_CHAR0 - (n) |
199+ // | data (ptr) -> pattern array (5 bit x 7 rows) |
200+ // +---------------------------------------------------------------+
201+ void lcd_pattern (LCD_Char address , const unsigned char * data )
202+ {
203+ // Check if address is greater than max. allowed address
204+ if (address > LCD_CGADDDR_MAX )
205+ return ;
206+
207+ lcd_cmd (LCD_CGADDR + (address * 8 )); // Setup LCD display CGADDR start address + which character
208+
209+ // Write data to LCD display CGRAM
210+ for (unsigned char i = 0 ; i < 8 ; i ++ )
211+ lcd_char (data [i ]);
212+
213+ lcd_cmd (LCD_DDADDR ); // Setup LCD display DDADDR (HOME position)
214+ }
215+
216+ // +---------------------------------------------------------------+
217+ // | LCD unsigned long to ASCII |
218+ // +---------------------------------------------------------------+
219+ // | Parameter: data -> number to convert |
220+ // | radix -> 2/10/16 |
221+ // | length -> ASCII characters 1 - 10 |
222+ // +---------------------------------------------------------------+
223+ void lcd_ul2ascii (const unsigned long data , LCD_Base base , unsigned char length )
224+ {
225+ // If base is wrong or length is to short/wide return
226+ if ((base != 2 && base != 10 && base != 16 ) || (length < 1 || length > 10 ))
227+ return ;
228+
229+ unsigned char count = 0 ; // Internal counter for character length
230+ char buffer [(sizeof (unsigned long ) * 8 + 1 )]; // ASCII buffer 9 digits + \0 escape character
231+
232+ // Convert unsigned long to ASCII
233+ ultoa (data , buffer , base );
234+
235+ // Loop until \0 escape char is reached
236+ for (unsigned char i = 0 ; i < sizeof (buffer ); i ++ )
237+ {
238+ // Check if buffer data is not equal to \0 escape char
239+ if (buffer [i ] != LCD_NULL )
240+ count ++ ; // increment data counter
241+ else
242+ break ; // exit loop
243+ }
244+
245+ // Check if length is greater than count
246+ if (count < length )
247+ {
248+ // Write spaces to LCD display until position adjustment is done
249+ for (unsigned char i = 0 ; i < (length - count ); i ++ )
250+ {
251+ if (base != 10 )
252+ lcd_char ('0' );
253+ else
254+ lcd_char (LCD_SPACE );
255+ }
256+ }
257+ // Check if length is lower than count
258+ else if (count > length )
259+ {
260+ // Write \0 escape char to the max. length allowed through position adjustment
261+ buffer [length ] = LCD_NULL ;
262+ }
263+
264+ // Write string to LCD
265+ lcd_string (buffer );
266+ }
267+
268+ // +---------------------------------------------------------------+
269+ // | LCD signed long to ASCII |
270+ // +---------------------------------------------------------------+
271+ // | Parameter: data -> number to convert |
272+ // | radix -> 2/10/16 |
273+ // | length -> ASCII characters 1 - 10 |
274+ // +---------------------------------------------------------------+
275+ void lcd_sl2ascii (const signed long data , LCD_Base base , unsigned char length )
276+ {
277+ // If base is wrong or length is to short/wide return
278+ if ((base != 2 && base != 10 && base != 16 ) || (length < 1 || length > 10 ))
279+ return ;
280+
281+ unsigned char count = 0 ; // Internal counter for character length
282+ char buffer [(sizeof (long ) * 8 + 2 )]; // ASCII buffer 10 digits + \0 escape character
283+
284+ // Convert data to ASCII
285+ ltoa (data , buffer , base );
286+
287+ // Loop until \0 escape char is reached
288+ for (unsigned char i = 0 ; i < sizeof (buffer ); i ++ )
289+ {
290+ // Check if buffer data is not equal to \0 escape char
291+ if (buffer [i ] != LCD_NULL )
292+ count ++ ; // increment data counter
293+ else
294+ break ; // exit loop
295+ }
296+
297+ // Check if length is greater than count
298+ if (count < length )
299+ {
300+ // Write spaces to LCD display until position adjustment is done
301+ for (unsigned char i = 0 ; i < (length - count ); i ++ )
302+ {
303+ if (base != 10 )
304+ lcd_char ('0' );
305+ else
306+ lcd_char (LCD_SPACE );
307+ }
308+ }
309+ // Check if length is lower than count
310+ else if (count > length )
311+ {
312+ // Write \0 escape char to the max. length allowed through position adjustment
313+ buffer [length ] = LCD_NULL ;
314+ }
315+
316+ if (base == 10 )
317+ {
318+ // Write string to LCD
319+ lcd_string (buffer );
320+ }
321+ else
322+ {
323+ if (data < 0 )
324+ lcd_string (& buffer [count - length ]);
325+ else
326+ lcd_string (buffer );
327+ }
328+ }
329+
330+ // +---------------------------------------------------------------+
331+ // | LCD double to ASCII |
332+ // +---------------------------------------------------------------+
333+ // | Parameter: data -> number to convert |
334+ // | radix -> 2/10/16 |
335+ // | length -> ASCII characters 1 - 10 |
336+ // +---------------------------------------------------------------+
337+ void lcd_d2ascii (const double data , signed char length , unsigned char precision )
338+ {
339+ char buffer [60 ];
340+
341+ // Convert double to ASCII
342+ if ((length > 0 ) && (length < 60 ))
343+ dtostrf (data , length , precision , buffer );
344+ else
345+ dtostre (data , buffer , precision , DTOSTR_ALWAYS_SIGN | DTOSTR_UPPERCASE );
346+
347+ // Write string to LCD
348+ lcd_string (buffer );
349+ }
0 commit comments