lcd.c


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
}