1 | // Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
|
2 | // http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
|
3 | //
|
4 |
|
5 | #include <avr/io.h>
|
6 | #include <util/delay.h>
|
7 |
|
8 | void lcd_data(unsigned char temp1);
|
9 | void lcd_string(char *data);
|
10 | void lcd_command(unsigned char temp1);
|
11 | void lcd_enable(void);
|
12 | void lcd_init(void);
|
13 | void lcd_home(void);
|
14 | void lcd_clear(void);
|
15 | void set_cursor(uint8_t x, uint8_t y);
|
16 |
|
17 | // Hier die verwendete Taktfrequenz in Hz eintragen, wichtig!
|
18 |
|
19 | //#define F_CPU 1000000
|
20 |
|
21 | // LCD Befehle
|
22 |
|
23 | #define CLEAR_DISPLAY 0x01
|
24 | #define CURSOR_HOME 0x02
|
25 |
|
26 | // Pinbelegung für das LCD, an verwendete Pins anpassen
|
27 |
|
28 | #define LCD_PORT PORTD
|
29 | #define LCD_DDR DDRD
|
30 | #define LCD_RS PD0
|
31 | #define LCD_EN PD1
|
32 | #define LCD_DB4 PD5
|
33 | #define LCD_DB5 PD2
|
34 | #define LCD_DB6 PD4
|
35 | #define LCD_DB7 PD3
|
36 | // DB4 bis DB7 des LCD sind mit PD0 bis PD3 des AVR verbunden
|
37 |
|
38 | // Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
|
39 | // http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
|
40 | //
|
41 | // Die Pinbelegung ist über defines in lcd-routines.h einstellbar
|
42 |
|
43 |
|
44 | // sendet ein Datenbyte an das LCD
|
45 | void lcd_data(unsigned char temp1)
|
46 | {
|
47 | unsigned char temp2 = 0x00;
|
48 |
|
49 | LCD_PORT |= (1<<LCD_RS); // RS auf 1 setzen
|
50 |
|
51 | //Übertragung des höherwertigen Nibbels
|
52 | LCD_PORT &= ~((1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7)); // die 4 datenbits auf 0 setzen
|
53 |
|
54 | /*
|
55 | temp2 |= (temp1 & (1<<4))<<LCD_DB4; //schiebt das bit von DB4 auf den platz LCD_DB4
|
56 | temp2 |= (temp1 & (1<<5))<<LCD_DB5; //schiebt das bit von DB5 auf den platz LCD_DB5
|
57 | temp2 |= (temp1 & (1<<6))<<LCD_DB6; //schiebt das bit von DB6 auf den platz LCD_DB6
|
58 | temp2 |= (temp1 & (1<<7))<<LCD_DB7; //schiebt das bit von DB7 auf den platz LCD_DB7
|
59 | */
|
60 | if(temp1 & (1<<4))temp2|=(1<<LCD_DB4);//schiebt das bit von DB4 auf den platz LCD_DB4
|
61 | if(temp1 & (1<<5))temp2|=(1<<LCD_DB5);//schiebt das bit von DB4 auf den platz LCD_DB4
|
62 | if(temp1 & (1<<6))temp2|=(1<<LCD_DB6);//schiebt das bit von DB4 auf den platz LCD_DB4
|
63 | if(temp1 & (1<<7))temp2|=(1<<LCD_DB7);//schiebt das bit von DB4 auf den platz LCD_DB4
|
64 |
|
65 | LCD_PORT |= temp2; // setzen
|
66 | lcd_enable();
|
67 |
|
68 |
|
69 | //Übertragung des niederwertigen Nibbels
|
70 | LCD_PORT &= ~((1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7)); // die 4 datenbits auf 0 setzen
|
71 |
|
72 | temp2 = 0x00;
|
73 | /*
|
74 | temp2 |= (temp1 & (1<<0))<<LCD_DB4; //schiebt das bit von DB4 auf den platz LCD_DB4
|
75 | temp2 |= (temp1 & (1<<1))<<LCD_DB5; //schiebt das bit von DB5 auf den platz LCD_DB5
|
76 | temp2 |= (temp1 & (1<<2))<<LCD_DB6; //schiebt das bit von DB6 auf den platz LCD_DB6
|
77 | temp2 |= (temp1 & (1<<3))<<LCD_DB7; //schiebt das bit von DB7 auf den platz LCD_DB7
|
78 | */
|
79 | if(temp1 & (1<<0))temp2|=(1<<LCD_DB4);//schiebt das bit von DB4 auf den platz LCD_DB4
|
80 | if(temp1 & (1<<1))temp2|=(1<<LCD_DB5);//schiebt das bit von DB4 auf den platz LCD_DB4
|
81 | if(temp1 & (1<<2))temp2|=(1<<LCD_DB6);//schiebt das bit von DB4 auf den platz LCD_DB4
|
82 | if(temp1 & (1<<3))temp2|=(1<<LCD_DB7);//schiebt das bit von DB4 auf den platz LCD_DB4
|
83 |
|
84 | LCD_PORT |= temp2; // setzen
|
85 | lcd_enable();
|
86 |
|
87 | _delay_us(42);
|
88 | }
|
89 |
|
90 | // sendet einen Befehl an das LCD
|
91 | void lcd_command(unsigned char temp1)
|
92 | {
|
93 | unsigned char temp2 = 0x00;
|
94 |
|
95 | //Übertragung des höherwertigen Nibbels
|
96 | LCD_PORT &= ~((1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7)); // die 4 datenbits auf 0 setzen
|
97 |
|
98 | if(temp1 & (1<<4))temp2|=(1<<LCD_DB4);//schiebt das bit von DB4 auf den platz LCD_DB4
|
99 | if(temp1 & (1<<5))temp2|=(1<<LCD_DB5);//schiebt das bit von DB4 auf den platz LCD_DB4
|
100 | if(temp1 & (1<<6))temp2|=(1<<LCD_DB6);//schiebt das bit von DB4 auf den platz LCD_DB4
|
101 | if(temp1 & (1<<7))temp2|=(1<<LCD_DB7);//schiebt das bit von DB4 auf den platz LCD_DB4
|
102 |
|
103 | LCD_PORT |= temp2; // setzen
|
104 | lcd_enable();
|
105 |
|
106 |
|
107 | //Übertragung des niederwertigen Nibbels
|
108 | LCD_PORT &= ~((1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7)); // die 4 datenbits auf 0 setzen
|
109 |
|
110 | temp2 = 0x00;
|
111 | if(temp1 & (1<<0))temp2|=(1<<LCD_DB4);//schiebt das bit von DB4 auf den platz LCD_DB4
|
112 | if(temp1 & (1<<1))temp2|=(1<<LCD_DB5);//schiebt das bit von DB4 auf den platz LCD_DB4
|
113 | if(temp1 & (1<<2))temp2|=(1<<LCD_DB6);//schiebt das bit von DB4 auf den platz LCD_DB4
|
114 | if(temp1 & (1<<3))temp2|=(1<<LCD_DB7);//schiebt das bit von DB4 auf den platz LCD_DB4
|
115 |
|
116 | LCD_PORT |= temp2; // setzen
|
117 | lcd_enable();
|
118 |
|
119 | _delay_us(42);
|
120 | }
|
121 |
|
122 | // erzeugt den Enable-Puls
|
123 | void lcd_enable(void)
|
124 | {
|
125 | // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers einfügen
|
126 | // http://www.mikrocontroller.net/topic/81974#685882
|
127 | LCD_PORT |= (1<<LCD_EN);
|
128 | _delay_us(10); // kurze Pause
|
129 | // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
|
130 | // http://www.mikrocontroller.net/topic/80900
|
131 | LCD_PORT &= ~(1<<LCD_EN);
|
132 | }
|
133 |
|
134 | // Initialisierung:
|
135 | // Muss ganz am Anfang des Programms aufgerufen werden.
|
136 |
|
137 | void lcd_init(void)
|
138 | {
|
139 | unsigned char temp = 0x00;
|
140 | LCD_DDR = LCD_DDR | (1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7) | (1<<LCD_RS) | (1<<LCD_EN); // Port auf Ausgang schalten
|
141 |
|
142 | // folgendes muss 3mal hintereinander gesendet werden zur Initialisierung
|
143 | _delay_ms(150);
|
144 | LCD_PORT &= ~((1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7));//Datenleitungen auf 0 setzen LCD_PORT &= 0xF0;
|
145 |
|
146 | if(0x03 & (1<<0))temp|=(1<<LCD_DB4);//schiebt das bit von DB4 auf den platz LCD_DB4
|
147 | if(0x03 & (1<<1))temp|=(1<<LCD_DB5);//schiebt das bit von DB4 auf den platz LCD_DB4
|
148 | if(0x03 & (1<<2))temp|=(1<<LCD_DB6);//schiebt das bit von DB4 auf den platz LCD_DB4
|
149 | if(0x03 & (1<<3))temp|=(1<<LCD_DB7);//schiebt das bit von DB4 auf den platz LCD_DB4
|
150 | LCD_PORT |= temp;
|
151 | // wurde durch die obigen 4 zeilen ersetzt LCD_PORT |= 0x03; todo wegmachen
|
152 | LCD_PORT &= ~(1<<LCD_RS); // RS auf 0
|
153 | lcd_enable();
|
154 |
|
155 | _delay_ms(50);
|
156 | lcd_enable();
|
157 |
|
158 | _delay_ms(10);
|
159 | lcd_enable();
|
160 | _delay_ms(10);
|
161 |
|
162 | // 4 Bit Modus aktivieren
|
163 | temp = 0x00;
|
164 | LCD_PORT &= ~((1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7));//Datenleitungen auf 0 setzen LCD_PORT &= 0xF0;
|
165 | if(0x02 & (1<<0))temp|=(1<<LCD_DB4);//schiebt das bit von DB4 auf den platz LCD_DB4
|
166 | if(0x02 & (1<<1))temp|=(1<<LCD_DB5);//schiebt das bit von DB4 auf den platz LCD_DB4
|
167 | if(0x02 & (1<<2))temp|=(1<<LCD_DB6);//schiebt das bit von DB4 auf den platz LCD_DB4
|
168 | if(0x02 & (1<<3))temp|=(1<<LCD_DB7);//schiebt das bit von DB4 auf den platz LCD_DB4
|
169 | LCD_PORT |= temp; //vorher wurde es gleich |= 0x02 gemacht
|
170 | lcd_enable();
|
171 | _delay_ms(10);
|
172 |
|
173 | // 4Bit / 2 Zeilen / 5x7
|
174 | lcd_command(0x28);
|
175 | // 4Bit / 1 Zeilen / 5x7
|
176 | //lcd_command(0x20);
|
177 | // Display ein / Cursor aus / kein Blinken
|
178 | lcd_command(0x0C);
|
179 |
|
180 | // inkrement / kein Scrollen
|
181 | lcd_command(0x06);
|
182 |
|
183 | lcd_clear();
|
184 | }
|
185 |
|
186 | // Sendet den Befehl zur Löschung des Displays
|
187 |
|
188 | void lcd_clear(void)
|
189 | {
|
190 | lcd_command(CLEAR_DISPLAY);
|
191 | _delay_ms(5);
|
192 | }
|
193 |
|
194 | // Sendet den Befehl: Cursor Home
|
195 |
|
196 | void lcd_home(void)
|
197 | {
|
198 | lcd_command(CURSOR_HOME);
|
199 | _delay_ms(5);
|
200 | }
|
201 |
|
202 | // setzt den Cursor in Zeile y (1..4) Spalte x (0..15)
|
203 |
|
204 | void set_cursor(uint8_t x, uint8_t y)
|
205 | {
|
206 | uint8_t tmp;
|
207 |
|
208 | switch (y) {
|
209 | case 1: tmp=0x80+0x00+x; break; // 1. Zeile
|
210 | case 2: tmp=0x80+0x40+x; break; // 2. Zeile
|
211 | case 3: tmp=0x80+0x10+x; break; // 3. Zeile
|
212 | case 4: tmp=0x80+0x50+x; break; // 4. Zeile
|
213 | default: return; // für den Fall einer falschen Zeile
|
214 | }
|
215 | lcd_command(tmp);
|
216 | }
|
217 |
|
218 | // Schreibt einen String auf das LCD
|
219 |
|
220 | void lcd_string(char *data)
|
221 | {
|
222 | while(*data) {
|
223 | lcd_data(*data);
|
224 | data++;
|
225 | }
|
226 | }
|
227 |
|
228 |
|
229 | uint16_t ReadChannel(uint8_t mux)
|
230 | {
|
231 | uint8_t i;
|
232 | uint16_t result;
|
233 |
|
234 | ADMUX = mux; // Kanal waehlen
|
235 | //ADMUX |= (0<<REFS1) | (1<<REFS0); // avcc als referenzspannung
|
236 | ADMUX |= (0<<REFS1) | (0<<REFS0); // externe referenzspannung
|
237 | ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler
|
238 | // setzen auf 8 (1) und ADC aktivieren (1)
|
239 |
|
240 | /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
|
241 | also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
|
242 | ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
|
243 | while ( ADCSRA & (1<<ADSC) ) {
|
244 | ; // auf Abschluss der Konvertierung warten
|
245 | }
|
246 | result = ADCW; // ADCW muss einmal gelesen werden,
|
247 | // sonst wird Ergebnis der nächsten Wandlung
|
248 | // nicht übernommen.
|
249 |
|
250 | /* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
|
251 | result = 0;
|
252 | for( i=0; i<8; i++ )
|
253 | {
|
254 | ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
|
255 | while ( ADCSRA & (1<<ADSC) ) {
|
256 | ; // auf Abschluss der Konvertierung warten
|
257 | }
|
258 | result += ADCW; // Wandlungsergebnisse aufaddieren
|
259 | }
|
260 | ADCSRA &= ~(1<<ADEN); // ADC deaktivieren (2)
|
261 |
|
262 | result /= 8; // Summe durch vier teilen = arithm. Mittelwert
|
263 |
|
264 | return result;
|
265 | }
|
266 |
|
267 |
|
268 |
|
269 |
|
270 | char * ltoa(char * buf, uint16_t val, char pad) //todo unsigned long ist zu lang ?
|
271 | {
|
272 | char i;
|
273 | char tmp_buf[10];
|
274 |
|
275 | for(i=0; val>0; val/=10)
|
276 | tmp_buf[i++] = (val % 10) + '0';
|
277 | if(i==0)
|
278 | tmp_buf[i++] = '0';
|
279 |
|
280 | while(i<pad)
|
281 | tmp_buf[i++] = '0';
|
282 |
|
283 | while(i>0){
|
284 | //printf("i=%d\n",i);
|
285 | *(buf++) = *(tmp_buf+(--i)); //falls hier ein fehler passiert, wurde ein string mit "char * string = "abdcd..."" eröffnet
|
286 | }
|
287 |
|
288 | *buf = '\0';
|
289 | return buf;
|
290 | }
|
291 |
|
292 | int main(void)
|
293 | {
|
294 |
|
295 | lcd_init();
|
296 |
|
297 | /*
|
298 | lcd_string("nanu3");
|
299 | lcd_data('T');
|
300 | lcd_data('e');
|
301 | lcd_data('s');
|
302 | lcd_data('t');
|
303 | lcd_data('!');
|
304 |
|
305 |
|
306 |
|
307 | set_cursor(0,3);
|
308 | lcd_string("nanu3");
|
309 | */
|
310 |
|
311 | uint16_t adcval;
|
312 | char * rueckgabe;
|
313 | uint8_t ausgabe;
|
314 | char *ausgabestring = "000000"; //geht nur auf einem uC todo
|
315 | char *ausgabestring2 = "000000";
|
316 |
|
317 |
|
318 | adcval = ReadChannel(0); //liest den analogeingang
|
319 | rueckgabe = ltoa(ausgabestring,adcval,5);
|
320 | set_cursor(0,1);
|
321 | lcd_string("nanu3");
|
322 | //lcd_string(ausgabestring);
|
323 | while(1)
|
324 | {
|
325 |
|
326 | adcval = ReadChannel(0); //liest den analogeingang
|
327 | rueckgabe = ltoa(ausgabestring,adcval,5);
|
328 | set_cursor(0,1);
|
329 | lcd_string("nanu3");
|
330 | //lcd_string(ausgabestring);
|
331 | }
|
332 |
|
333 | return 0;
|
334 | }
|