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