/
hd44780.c
274 lines (229 loc) · 5.88 KB
/
hd44780.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
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/* HD44780 Library by Peter Fuhrmann
* this uses 4bit mode only for now.
* The Data Lines 7:4 shall be connected to the Display Port 3:0
*/
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "hd44780.h"
//set this for 4bit mode
//The Data Lines 7:4 shall be connected to the Display Port 3:0 then
//#define IF4BIT
#if 0
#undef IF4BIT
#define PIN_RS PD5
#define PIN_E PD6
#define PIN_RW PD7
#define DISP_DDR_D DDRC
#define DISP_PORT_D PORTC
#define DISP_PIN PINC
#define DISP_DDR_C DDRD
#define DISP_PORT_C PORTD
#else
#define PIN_RS PD5
#define PIN_RW PD7
#define PIN_E PD6
//Port, to which the Datalines of the Display are connected
#define DISP_DDR_D DDRD
#define DISP_PORT_D PORTD
#define DISP_PIN PIND
//Port, to which the Control Lines of the Display are connected
#define DISP_DDR_C DDRD
#define DISP_PORT_C PORTD
#define DISP_LEN 16
#define DISP_LINES 2
#endif
/* Instructions */
#define CLEAR 0x01 /* no params */
#define HOME 0x02 /* no params */
#define ENTRY_MODE 0x04 /* B1 = cursor direction(1=right) B0 = do display shift */
#define ON_OFF 0x08 /* B2 = Display B1 = Cursor B0 = Blink */
#define SHIFT 0x10 /* B3 = Move Cursor(1)/ Shift Display(0) B2 = Shift Direction */
#define FUNCTION 0x20 /* B4 = Data Length (0=4, 1=8) B3 = Num of lines B2 = Font(0) */
#define SET_CGRAM 0x40 /* Character Generator Address */
#define SET_DDRAM 0x80 /* Character Address */
void wait50ms(){
uint16_t x; char y;
for (y=1;y<8;y++){
for (x=1;x<50000;x++){};
}
}
void wait200us(){
uint8_t x;
for (x=1;x<200;x++){};
}
void hd44780_send(uint8_t data){
uint8_t busy;
#ifdef IF4BIT
DISP_PORT_C |= _BV(PIN_E);
DISP_PORT_D &= 0xF0;
DISP_PORT_D |= ((data >> 4) & 0x0F);
DISP_PORT_C &= ~_BV(PIN_E);
DISP_PORT_C |= _BV(PIN_E);
DISP_PORT_D &= 0xF0;
DISP_PORT_D |= (data & 0x0F);
DISP_PORT_C &= ~_BV(PIN_E);
#else
DISP_PORT_C |= _BV(PIN_E);
DISP_PORT_D = (data);
DISP_PORT_C &= ~_BV(PIN_E);
#endif
#ifdef IF4BIT
DISP_DDR_D &= 0XF0; //Data lines 3:0 to Input
DISP_PORT_D |= 0x0F; //Pullups on on Data lines
#else
DISP_DDR_D = 0x00; //Data lines to Input
DISP_PORT_D = 0xFF; //Pullups on
#endif
DISP_PORT_C = (DISP_PORT_C | 1<<PIN_RW) & ~(1<<PIN_RS);
do{
DISP_PORT_C |= _BV(PIN_E);
asm volatile ("nop\n\tnop\n\t"::);
#ifdef IF4BIT
busy = (DISP_PIN & 0x08);
DISP_PORT_C &= ~_BV(PIN_E);
DISP_PORT_C |= _BV(PIN_E);
DISP_PORT_C &= ~_BV(PIN_E);
#else
busy = (DISP_PIN & 0x80);
DISP_PORT_C &= ~_BV(PIN_E);
#endif
}while(busy);
DISP_PORT_C &= ~(1<<PIN_RW | 1<<PIN_RS );
#ifdef IF4BIT
DISP_DDR_D |= 0x0F; //Data Lines to Output
#else
DISP_DDR_D = 0xFF;
#endif
}
// send Data to display without checking the Busy Flag, needed for iniializing Display
void hd44780_send_nobusy(uint8_t data){
#ifdef IF4BIT
DISP_PORT_C |= _BV(PIN_E);
DISP_PORT_D &= 0xF0;
DISP_PORT_D |= (data >> 4);
DISP_PORT_C &= ~_BV(PIN_E);
wait200us();
DISP_PORT_C |= _BV(PIN_E);
DISP_PORT_D &= 0xF0;
DISP_PORT_D |= (data & 0x0F);
DISP_PORT_C &= ~_BV(PIN_E);
wait200us();
#else
DISP_PORT_C |= _BV(PIN_E);
DISP_PORT_D = data;
DISP_PORT_C &= ~_BV(PIN_E);
wait200us();
#endif
}
/* reads and returns the address counter */
uint8_t hd44780_read(){
uint8_t address;
#ifdef IF4BIT
DISP_DDR_D &= 0xF0;
DISP_PORT_D |= 0x0F;
DISP_PORT_C &= ~(1<<PIN_RS);
DISP_PORT_C |= (1<<PIN_RW);
DISP_PORT_C |= 1<<PIN_E;
asm volatile ("nop\n\tnop\n\t"::);
address = DISP_PIN & 0x07; //dont read busy flag
DISP_PORT_C &= ~_BV(PIN_E);
address <<= 4;
DISP_PORT_C |= _BV(PIN_E);
asm volatile ("nop\n\tnop\n\t"::);
address |= DISP_PIN & 0x0F;
DISP_PORT_C &= ~_BV(PIN_E);
DISP_PORT_C &= ~(1<<PIN_RW);
DISP_DDR_D |= 0x0F;
#else
DISP_DDR_D = 0x00;
DISP_PORT_D = 0xFF;
DISP_PORT_C &= ~(1<<PIN_RS);
DISP_PORT_C |= (1<<PIN_RW);
DISP_PORT_C |= 1<<PIN_E;
asm volatile ("nop\n\tnop\n\t"::);
address = DISP_PIN & 0x7F; //dont read busy flag
DISP_PORT_C &= ~_BV(PIN_E);
DISP_PORT_C &= ~(1<<PIN_RW);
DISP_DDR_D = 0xFF;
#endif
return address;
}
void hd44780_command(uint8_t command){
DISP_PORT_C &= ~(1<<PIN_RS);
hd44780_send(command);
}
void hd44780_data(uint8_t data){
DISP_PORT_C |= 1<<PIN_RS;
hd44780_send(data);
}
/* init the controller and clear the Display */
void hd44780_init(){
#ifdef IF4BIT
DISP_DDR_D |= 0x0F;
DISP_PORT_D &= 0xF0;
#else
DISP_DDR_D = 0xFF;
DISP_PORT_D = 0x00;
#endif
DISP_DDR_C |= (1<<PIN_E|1<<PIN_RW|1<<PIN_RS);
DISP_PORT_C &= ~(1<<PIN_E|1<<PIN_RW|1<<PIN_RS);
wait50ms();
#ifdef IF4BIT
hd44780_send_nobusy(0x33);
hd44780_send_nobusy(0x32);// Put Display in 4bit mode
hd44780_send_nobusy(0x28);// Put Display in 4bit mode
hd44780_command(0x28);// 2 Lines 5x7 DOT
#else
hd44780_send_nobusy(0x30);
hd44780_send_nobusy(0x30);
hd44780_send_nobusy(0x30);
hd44780_send_nobusy(0x30);// Put Display in 8bit mode
hd44780_command(0x30);
hd44780_command(0x38);// 2 Lines 5x7 DOT
#endif
hd44780_command(0x10);// cursor move
hd44780_command(0x0F);//Display on, cursor on, cursor blink
hd44780_command(0x01);//clear Display
}
void hd44780_set_cursor(uint8_t row, uint8_t col){
hd44780_command(0x80|(uint8_t)(row<<6)|col);
}
void hd44780_backspace(uint8_t num){
uint8_t curs_pos = hd44780_read();
uint8_t x;
hd44780_command(SET_DDRAM|(curs_pos-num));
for(x=0;x<num;x++){
hd44780_data(' ');
}
hd44780_command(SET_DDRAM|(curs_pos-1));
}
void hd44780_clear_line(uint8_t line){
uint8_t x;
hd44780_set_cursor(line,0);
for(x=0;x<DISP_LEN;x++){
hd44780_data(' ');
}
hd44780_set_cursor(line,0);
}
void hd44780_print(char * string){
char c;
while ((c = *string++)){
hd44780_data(c);
}
}
void hd44780_print_P(PGM_P string){
char c;
while ((c = pgm_read_byte(string++))){
hd44780_data(c);
}
}
void hd44780_load_font_P(uint8_t charnum, PGM_P data){
uint8_t x, address;
address = hd44780_read();
hd44780_command((uint8_t)(charnum<<3)|0x40); //set cgram address
for (x=0;x<8;x++){
hd44780_data(pgm_read_byte(data++));
}
/*restore position where cursor was */
hd44780_command(0x80|address);
}