1 | // Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
|
2 | // http://www.mikrocontroller.net/articles/HD44780
|
3 | // http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
|
4 | //
|
5 | // Die Pinbelegung ist über defines in lcd.h einstellbar
|
6 |
|
7 | #include <avr/io.h>
|
8 | #include "main.h"
|
9 | #include "lcd.h"
|
10 | #include <util/delay.h>
|
11 |
|
12 | /////////////////////////////////////////////////////////////////////////////////
|
13 | // Erzeugt einen Enable-Puls
|
14 |
|
15 | static void lcd_enable( void ) {
|
16 | LCD_PORT |= (1<<LCD_EN); // Enable auf 1 setzen
|
17 | _delay_us( LCD_ENABLE_US ); // kurze Pause
|
18 | LCD_PORT &= ~(1<<LCD_EN); // Enable auf 0 setzen
|
19 | }
|
20 |
|
21 | ////////////////////////////////////////////////////////////////////////////////
|
22 | // Sendet eine 4-bit Ausgabeoperation an das LCD
|
23 | static void lcd_out( uint8_t data ) {
|
24 | data &= 0xF0; // obere 4 Bit maskieren
|
25 | LCD_PORT &= ~(0xF0>>(4-LCD_DB)); // Maske löschen
|
26 | LCD_PORT |= (data>>(4-LCD_DB)); // Bits setzen
|
27 | lcd_enable();
|
28 | }
|
29 |
|
30 | ////////////////////////////////////////////////////////////////////////////////
|
31 | // Initialisierung: muss ganz am Anfang des Programms aufgerufen werden.
|
32 | void lcd_init( void ) {
|
33 | // verwendete Pins auf Ausgang schalten
|
34 | uint8_t pins = (0x0F << LCD_DB) | // 4 Datenleitungen
|
35 | (1<<LCD_RS) | // R/S Leitung
|
36 | (1<<LCD_EN); // Enable Leitung
|
37 | LCD_DDR |= pins;
|
38 |
|
39 | // initial alle Ausgänge auf Null
|
40 | LCD_PORT &= ~pins;
|
41 |
|
42 | // warten auf die Bereitschaft des LCD
|
43 | _delay_ms( LCD_BOOTUP_MS );
|
44 |
|
45 | // Soft-Reset muss 3mal hintereinander gesendet werden zur Initialisierung
|
46 | lcd_out( LCD_SOFT_RESET );
|
47 | _delay_ms( LCD_SOFT_RESET_MS1 );
|
48 |
|
49 | lcd_enable();
|
50 | _delay_ms( LCD_SOFT_RESET_MS2 );
|
51 |
|
52 | lcd_enable();
|
53 | _delay_ms( LCD_SOFT_RESET_MS3 );
|
54 |
|
55 | // 4-bit Modus aktivieren
|
56 | lcd_out( LCD_SET_FUNCTION |
|
57 | LCD_FUNCTION_4BIT );
|
58 | _delay_ms( LCD_SET_4BITMODE_MS );
|
59 |
|
60 | // 4-bit Modus / 2 Zeilen / 5x7
|
61 | lcd_command( LCD_SET_FUNCTION |
|
62 | LCD_FUNCTION_4BIT |
|
63 | LCD_FUNCTION_2LINE |
|
64 | LCD_FUNCTION_5X7 );
|
65 |
|
66 | // Display ein / Cursor aus / Blinken aus
|
67 | lcd_command(LCD_SET_DISPLAY |
|
68 | LCD_DISPLAY_ON |
|
69 | LCD_CURSOR_OFF |
|
70 | LCD_BLINKING_OFF);
|
71 |
|
72 | // Cursor inkrement / kein Scrollen
|
73 | lcd_command( LCD_SET_ENTRY |
|
74 | LCD_ENTRY_INCREASE |
|
75 | LCD_ENTRY_NOSHIFT );
|
76 |
|
77 | lcd_clear();
|
78 | }
|
79 |
|
80 | ////////////////////////////////////////////////////////////////////////////////
|
81 | // Sendet ein Datenbyte an das LCD
|
82 | void lcd_data( uint8_t data ) {
|
83 | LCD_PORT |= (1<<LCD_RS); // RS auf 1 setzen
|
84 |
|
85 | lcd_out( data ); // zuerst die oberen,
|
86 | lcd_out( data<<4 ); // dann die unteren 4 Bit senden
|
87 |
|
88 | _delay_us( LCD_WRITEDATA_US );
|
89 | }
|
90 |
|
91 | ////////////////////////////////////////////////////////////////////////////////
|
92 | // Sendet einen Befehl an das LCD
|
93 | void lcd_command( uint8_t data ) {
|
94 | LCD_PORT &= ~(1<<LCD_RS); // RS auf 0 setzen
|
95 |
|
96 | lcd_out( data ); // zuerst die oberen,
|
97 | lcd_out( data<<4); // dann die unteren 4 Bit senden
|
98 |
|
99 | _delay_us(LCD_COMMAND_US );
|
100 | }
|
101 |
|
102 | ////////////////////////////////////////////////////////////////////////////////
|
103 | // Sendet den Befehl zur Löschung des Displays
|
104 | void lcd_clear( void ) {
|
105 | lcd_command( LCD_CLEAR_DISPLAY );
|
106 | _delay_ms( LCD_CLEAR_DISPLAY_MS );
|
107 | }
|
108 |
|
109 | ////////////////////////////////////////////////////////////////////////////////
|
110 | // Sendet den Befehl: Cursor Home
|
111 | void lcd_home( void ) {
|
112 | lcd_command( LCD_CURSOR_HOME );
|
113 | _delay_ms( LCD_CURSOR_HOME_MS );
|
114 | }
|
115 |
|
116 | ////////////////////////////////////////////////////////////////////////////////
|
117 | // Setzt den Cursor in Zeile y (0..3) Spalte x (0..15)
|
118 |
|
119 | void lcd_setcursor( uint8_t x, uint8_t y ) {
|
120 | uint8_t data;
|
121 |
|
122 | switch (y) {
|
123 | case 0: // 1. Zeile
|
124 | data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
|
125 | break;
|
126 | case 1: // 2. Zeile
|
127 | data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
|
128 | break;
|
129 | case 2: // 3. Zeile
|
130 | data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
|
131 | break;
|
132 | case 3: // 4. Zeile
|
133 | data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
|
134 | break;
|
135 | default:
|
136 | return; // für den Fall einer falschen Zeile
|
137 | }
|
138 |
|
139 | lcd_command( data );
|
140 | }
|
141 |
|
142 | ////////////////////////////////////////////////////////////////////////////////
|
143 | // Schreibt einen String auf das LCD
|
144 |
|
145 | void lcd_string( const char *data ) {
|
146 | while( *data != '\0' )
|
147 | lcd_data( *data++ );
|
148 | }
|
149 |
|
150 | void lcd_string_xy( uint8_t x, uint8_t y, const char *data ) {
|
151 | lcd_setcursor( x, y );
|
152 | lcd_string( data );
|
153 | }
|
154 |
|
155 | ////////////////////////////////////////////////////////////////////////////////
|
156 | // Schreibt eine Zahl auf das LCD
|
157 |
|
158 | void lcd_number( uint8_t number, uint8_t len, uint8_t fill ) {
|
159 | uint8_t digit1 = 0;
|
160 | uint8_t digit2 = 0;
|
161 | while (number >= 100) {
|
162 | digit1++;
|
163 | number -= 100;
|
164 | }
|
165 | while (number >= 10) {
|
166 | digit2++;
|
167 | number -= 10;
|
168 | }
|
169 | if (len > 2) lcd_data( (digit1 != 0) ? digit1+'0' : fill );
|
170 | if (len > 1) lcd_data( ((digit1 != 0) || (digit2 != 0)) ? digit2+'0' : fill );
|
171 | lcd_data( number+'0' );
|
172 | }
|
173 |
|
174 | void lcd_number_xy( uint8_t x, uint8_t y, uint8_t number, uint8_t len, uint8_t fill ) {
|
175 | lcd_setcursor( x, y );
|
176 | lcd_number( number, len, fill );
|
177 | }
|
178 |
|
179 | ////////////////////////////////////////////////////////////////////////////////
|
180 | // Schreibt einen String auf das LCD
|
181 | // String liegt direkt im Flash Speicher
|
182 |
|
183 | void lcd_string_P( PGM_P data ) {
|
184 | uint8_t tmp;
|
185 |
|
186 | tmp = pgm_read_byte( data );
|
187 | while( tmp != '\0' ) {
|
188 | lcd_data( tmp );
|
189 | data++;
|
190 | tmp = pgm_read_byte( data );
|
191 | }
|
192 | }
|
193 |
|
194 | ////////////////////////////////////////////////////////////////////////////////
|
195 | // Schreibt ein Zeichen in den Character Generator RAM
|
196 | // Daten liegen direkt im RAM
|
197 |
|
198 | void lcd_generatechar( uint8_t code, const uint8_t *data, uint8_t lines ) {
|
199 | uint8_t i;
|
200 |
|
201 | // Startposition des Zeichens einstellen
|
202 | lcd_command( LCD_SET_CGADR | (code<<3) );
|
203 | // Bitmuster übertragen
|
204 | for ( i=0; i<lines; i++ ) {
|
205 | lcd_data( *data++ );
|
206 | }
|
207 | }
|
208 |
|
209 | ////////////////////////////////////////////////////////////////////////////////
|
210 | // Schreibt ein Zeichen in den Character Generator RAM
|
211 | // Daten liegen direkt im Flash-Speicher
|
212 |
|
213 | void lcd_generatechar_P( uint8_t code, PGM_P data, uint8_t lines ) {
|
214 | uint8_t i;
|
215 |
|
216 | // Startposition des Zeichens einstellen
|
217 | lcd_command( LCD_SET_CGADR | (code<<3) );
|
218 | // Bitmuster übertragen
|
219 | for ( i=0; i<lines; i++ ) {
|
220 | lcd_data( pgm_read_byte(data) );
|
221 | data++;
|
222 | }
|
223 | }
|