1 | // Time-stamp: "23.06.09 07:58 lcd-routines.c klaus@wachtler.de"
|
2 | //
|
3 | // Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
|
4 | // [1] http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial
|
5 | // [2] http://www.mikrocontroller.net/topic/88543#751982
|
6 | //
|
7 | // Die Pinbelegung ist über defines in lcd-routines.h einstellbar
|
8 | //
|
9 | // Änderungen:
|
10 | // 23.06.2009 kw - von außen nicht aufzurufende Funktionen static
|
11 | // gemacht:
|
12 | // lcd_data(), lcd_command(), lcd_enable()
|
13 | // - gemeinsamen Code aus lcd_command() und lcd_data()
|
14 | // in neue Funktion lcd_byte() ausgelagert
|
15 | // - Shiften und Maskieren in lcd_byte() eliminiert
|
16 | // - in lcd_set_cursor() Adressberechnung korrigiert
|
17 | // für blaues LCD
|
18 |
|
19 | #include <avr/io.h>
|
20 | #include "lcd-routines.h"
|
21 | #include <util/delay.h>
|
22 |
|
23 |
|
24 | // erzeugt den Enable-Puls
|
25 | static void lcd_enable( void )
|
26 | {
|
27 | // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers einfügen
|
28 |
|
29 | // http://www.mikrocontroller.net/topic/81974#685882
|
30 | LCD_EN1_PORT |= (1<<LCD_EN1);
|
31 |
|
32 | _delay_us(1); // kurze Pause
|
33 | // Bei Problemen ggf. Pause gemäß Datenblatt des LCD Controllers verlängern
|
34 | // http://www.mikrocontroller.net/topic/80900
|
35 | LCD_EN1_PORT &= ~(1<<LCD_EN1);
|
36 | }
|
37 |
|
38 |
|
39 | // sendet ein Daten- oder Kommandobyte (RS am LCD muß vorher
|
40 | // entsprechend gesetzt sein)
|
41 | static void lcd_byte( unsigned char data )
|
42 | {
|
43 | // oberes Nibble auf den LCD-Pins 4..7 ausgeben:
|
44 | LCD_PORT_4 &= ~(1<<LCD_D4);
|
45 | LCD_PORT_5 &= ~(1<<LCD_D5);
|
46 | LCD_PORT_6 &= ~(1<<LCD_D6);
|
47 | LCD_PORT_7 &= ~(1<<LCD_D7);
|
48 |
|
49 | if( data & 0x10 ) LCD_PORT_4 |= (1<<LCD_D4);// setzen
|
50 | if( data & 0x20 ) LCD_PORT_5 |= (1<<LCD_D5);
|
51 | if( data & 0x40 ) LCD_PORT_6 |= (1<<LCD_D6);
|
52 | if( data & 0x80 ) LCD_PORT_7 |= (1<<LCD_D7);
|
53 | lcd_enable();
|
54 |
|
55 | // unteres Nibble auf den LCD-Pins 4..7 ausgeben:
|
56 | LCD_PORT_4 &= ~(1<<LCD_D4);
|
57 | LCD_PORT_5 &= ~(1<<LCD_D5);
|
58 | LCD_PORT_6 &= ~(1<<LCD_D6);
|
59 | LCD_PORT_7 &= ~(1<<LCD_D7);
|
60 |
|
61 | if( data & 0x01 ) LCD_PORT_4 |= (1<<LCD_D4);// setzen
|
62 | if( data & 0x02 ) LCD_PORT_5 |= (1<<LCD_D5);
|
63 | if( data & 0x04 ) LCD_PORT_6 |= (1<<LCD_D6);
|
64 | if( data & 0x08 ) LCD_PORT_7 |= (1<<LCD_D7);
|
65 | lcd_enable();
|
66 |
|
67 | // Dem LCD Zeit geben, das Kommando auszuführen
|
68 | _delay_us(42);
|
69 | }
|
70 |
|
71 |
|
72 | // sendet ein Datenbyte an das LCD
|
73 | static void lcd_data( unsigned char data )
|
74 | {
|
75 | LCD_RS_PORT |= (1<<LCD_RS); // RS auf 1 setzen
|
76 | lcd_byte( data );
|
77 | }
|
78 |
|
79 |
|
80 | // sendet einen Befehl an das LCD
|
81 | static void lcd_command( unsigned char command )
|
82 | {
|
83 | LCD_RS_PORT &= ~(1<<LCD_RS); // RS auf 0 setzen
|
84 | lcd_byte( command );
|
85 | }
|
86 |
|
87 |
|
88 | // Initialisierung:
|
89 | // Muss ganz am Anfang des Programms aufgerufen werden.
|
90 | void lcd_init( void )
|
91 | {
|
92 | // Ports auf Ausgang schalten
|
93 | LCD_DDR_4 |=(1<<LCD_D4);
|
94 | LCD_DDR_5 |=(1<<LCD_D5);
|
95 | LCD_DDR_6 |=(1<<LCD_D6);
|
96 | LCD_DDR_7 |=(1<<LCD_D7);
|
97 |
|
98 | LCD_EN1_DDR |= (1<<LCD_EN1);
|
99 |
|
100 | LCD_RS_DDR |= (1<<LCD_RS);
|
101 |
|
102 | // muss 3 mal hintereinander gesendet werden zur Initialisierung
|
103 |
|
104 | _delay_ms(15);
|
105 |
|
106 | LCD_PORT_4 |= (1<<LCD_D4);
|
107 | LCD_PORT_5 |= (1<<LCD_D5);
|
108 | LCD_PORT_6 &= ~(1<<LCD_D6);
|
109 | LCD_PORT_7 &= ~(1<<LCD_D7);
|
110 |
|
111 | LCD_RS_PORT &= ~(1<<LCD_RS); // RS auf 0
|
112 | lcd_enable();
|
113 |
|
114 | _delay_ms(5);
|
115 | lcd_enable();
|
116 |
|
117 | _delay_ms(1);
|
118 | lcd_enable();
|
119 | _delay_ms(1);
|
120 |
|
121 | // 4 Bit Modus aktivieren
|
122 | LCD_PORT_4 &= ~(1<<LCD_D4);
|
123 | LCD_PORT_5 |= (1<<LCD_D5);
|
124 | LCD_PORT_6 &= ~(1<<LCD_D6);
|
125 | LCD_PORT_7 &= ~(1<<LCD_D7);
|
126 |
|
127 | lcd_enable();
|
128 | _delay_ms(1);
|
129 |
|
130 | // 4Bit / 2 Zeilen / 5x7
|
131 | lcd_command(0x28);
|
132 |
|
133 | // Display ein / Cursor aus / kein Blinken
|
134 | lcd_command(0x0C);
|
135 |
|
136 | // inkrement / kein Scrollen
|
137 | lcd_command(0x06);
|
138 |
|
139 | lcd_clear();
|
140 | }
|
141 |
|
142 |
|
143 | // Sendet den Befehl zur Löschung des Displays
|
144 | void lcd_clear( void )
|
145 | {
|
146 | lcd_command(CLEAR_DISPLAY);
|
147 | _delay_ms(5);
|
148 | }
|
149 |
|
150 |
|
151 | // Sendet den Befehl: Cursor Home
|
152 | void lcd_home( void )
|
153 | {
|
154 | lcd_command(CURSOR_HOME);
|
155 | _delay_ms(5);
|
156 | }
|
157 |
|
158 |
|
159 | // setzt den Cursor in Zeile y (1..4) Spalte x (0..15)
|
160 | void lcd_set_cursor( uint8_t x, uint8_t y )
|
161 | {
|
162 | uint8_t tmp;
|
163 |
|
164 | switch (y)
|
165 | {
|
166 | // Originalversion von [1]:
|
167 | //case 1: tmp=0x80+0x00+x; break; // 1. Zeile
|
168 | //case 2: tmp=0x80+0x40+x; break; // 2. Zeile
|
169 | //case 3: tmp=0x80+0x10+x; break; // 3. Zeile
|
170 | //case 4: tmp=0x80+0x50+x; break; // 4. Zeile
|
171 |
|
172 | // Klappt mit 4x20 blau ("Blue Line" von Electronic Assembly
|
173 | // EA W204B-NLW bzw. Reichelt LCD204BBL)
|
174 | case 1: tmp=0x80+0x00+x; break; // 1. Zeile
|
175 | case 2: tmp=0x80+0x40+x; break; // 2. Zeile
|
176 | case 3: tmp=0x80+0x14+x; break; // 3. Zeile
|
177 | case 4: tmp=0x80+0x54+x; break; // 4. Zeile
|
178 | default: return;
|
179 | }
|
180 | lcd_command(tmp);
|
181 | }
|
182 |
|
183 |
|
184 | // Schreibt einen String auf das LCD
|
185 | void lcd_string( const char *data )
|
186 | {
|
187 | while(*data)
|
188 | {
|
189 | lcd_data(*data);
|
190 | data++;
|
191 | }
|
192 | }
|