1 | #include <avr/io.h>
|
2 | #include <stdint.h>
|
3 | #include <util/delay.h>
|
4 | #include "LCD_HD44780_4Bit.h"
|
5 |
|
6 | #define nop() \
|
7 | asm volatile ("nop")
|
8 |
|
9 | LCD_HD44780_4Bit::LCD_HD44780_4Bit (
|
10 | volatile uint8_t *Port, // Der Port, an dem das LCD angeschlossen ist
|
11 | int DB4, // Der Pin, der mit ... verbunden ist.
|
12 | int DB5,
|
13 | int DB6,
|
14 | int DB7,
|
15 |
|
16 | int RS,
|
17 | int E,
|
18 |
|
19 | Lines ZeilenZahl,
|
20 | Pixel PunkteProPixel,
|
21 | Scrolling Scrollverhalten,
|
22 | Cursor cursor,
|
23 | Display display,
|
24 | CursorFlashing CursorBlinkverhalten,
|
25 | WritingBehavior Schreibverhalten
|
26 | )
|
27 | {
|
28 |
|
29 | this->_Port = Port;
|
30 | this->_DB4 = DB4;
|
31 | this->_DB5 = DB5;
|
32 | this->_DB6 = DB6;
|
33 | this->_DB7 = DB7;
|
34 |
|
35 | this->_RS = RS;
|
36 | this->_E = E;
|
37 |
|
38 | this->_lines = ZeilenZahl;
|
39 | this->_pixel = PunkteProPixel;
|
40 | this->_scrolling = Scrollverhalten;
|
41 | this->_cursor = cursor;
|
42 | this->_display = display;
|
43 | this->_cursorFlashing = CursorBlinkverhalten;
|
44 | this->_writingBehavior = Schreibverhalten;
|
45 |
|
46 | }
|
47 |
|
48 | void LCD_HD44780_4Bit::init()
|
49 | {
|
50 |
|
51 | // LCD-Kontroller Zeit für seine eigene Initialisierung zu geben
|
52 | Pause_ms(250);
|
53 | // 3 muss zur Initialisierung 3mal hintereinander gesendet werden
|
54 | Write4BitToPort(3, 0); // 0b00000011
|
55 | // 1
|
56 | enable();
|
57 | Pause_ms(5);
|
58 | // 2
|
59 | enable();
|
60 | Pause_ms(5);
|
61 | // und 3!
|
62 | enable();
|
63 | Pause_ms(5);
|
64 | // 4bit-Modus einstellen
|
65 | Write4BitToPort(2, 0); // 0b00000010
|
66 | enable();
|
67 | Pause_ms(5);
|
68 |
|
69 |
|
70 | uint8_t Konfiguration =
|
71 | (1<<5) | // Bit gibt die Konfigurations-Art an
|
72 | (0<<4) | // 4-Bit Interface
|
73 | (this->_lines<<3) | // Wird durch this->_lines = 1- oder 2-Zeilig bestimmt. Der enum wert wird in einen Int-konvertiert (0 oder 1)
|
74 | (this->_pixel<<2); // Wie this->_lines
|
75 | this->command(Konfiguration);
|
76 |
|
77 |
|
78 | uint8_t On_Off_control =
|
79 | (1<<3) | // Bit gibt die Konfigurations-Art an
|
80 | (this->_display<<2) | // Wird durch this->_display = On oder Off bestimmt. Der enum wert wird in einen Int-konvertiert (1 oder 0)
|
81 | (this->_cursor<<1) | // Wird durch this->_cursor = On oder Off bestimmt. Der enum wert wird in einen Int-konvertiert (1 oder 0)
|
82 | (this->_cursorFlashing<<0); // Wird durch this->_cursorFlashingy = Yes oder No bestimmt. Der enum wert wird in einen Int-konvertiert (1 oder 0)
|
83 | this->command(On_Off_control);
|
84 |
|
85 | uint8_t Entry_mode =
|
86 | (1<<2) | // Bit gibt die Konfigurations-Art an
|
87 | (this->_writingBehavior<<1) | // Wird durch this->_writingBehavior = decrement oder increment bestimmt. Der enum wert wird in einen Int-konvertiert (0 oder 1)
|
88 | (this->_scrolling<<0); // Wird durch this->_scrolling = No oder Yes bestimmt. Der enum wert wird in einen Int-konvertiert (0 oder 1)
|
89 | this->command(Entry_mode);
|
90 |
|
91 | return;
|
92 | }
|
93 |
|
94 | uint8_t LCD_HD44780_4Bit::SWAP(uint8_t val)
|
95 | {
|
96 | // Trennen der Bits und setzen der passenden Nibbles auf 0
|
97 | uint8_t upper = val & 0xF0; // 0b11110000 -> Oberes Nibble bleibt erhalten
|
98 | uint8_t lower = val & 0x0F; // 0b00001111 -> Unteres Nibble bleibt erhalten
|
99 |
|
100 | // Verschieben der Bits um 4 stellen durch Addition sind die Nibbles dann vertauscht
|
101 | upper >>= 4;
|
102 | lower <<= 4;
|
103 |
|
104 | // Rückgben der Summe
|
105 | return upper | lower;
|
106 | }
|
107 |
|
108 | void LCD_HD44780_4Bit::enable()
|
109 | {
|
110 | // Enable high
|
111 | *this->_Port = (1<<this->_E);
|
112 | // mindestens 3 Taktzyklen warten
|
113 | nop();
|
114 | nop();
|
115 | nop();
|
116 | nop();
|
117 | // Enable wieder low
|
118 | *this->_Port = (0<<this->_E);
|
119 | // Und wieder zurück
|
120 | return;
|
121 | }
|
122 |
|
123 |
|
124 |
|
125 | void LCD_HD44780_4Bit::Write4BitToPort(uint8_t val, bool RS )
|
126 | {
|
127 | // Filtern der Passenden Bits...
|
128 | /* Durch die UND-Verknüpfung zwischen val und dem Bit wird geprüft, ob das jeweilige Bit gesetzt ist. Wenn es
|
129 | * gesetzt ist, ist der Wert >= 1. Dieser bool-Wert wird dann auf den Jeweiligen Pin geschoben. */
|
130 | uint8_t b1 = (((val & (1 << 0)) >= 1) << this->_DB4); // Normalerweise: 0000|0001
|
131 | uint8_t b2 = (((val & (1 << 1)) >= 1) << this->_DB5); // Normalerweise: 0000|0010
|
132 | uint8_t b3 = (((val & (1 << 2)) >= 1) << this->_DB6); // Normalerweise: 0000|0100
|
133 | uint8_t b4 = (((val & (1 << 3)) >= 1) << this->_DB7); // Normalerweise: 0000|1000
|
134 | *this->_Port = (b1 | b2 | b3 | b4 | (RS<<this->_RS));
|
135 |
|
136 | return;
|
137 | }
|
138 |
|
139 | void LCD_HD44780_4Bit::command(uint8_t command)
|
140 | {
|
141 | // wie lcd_data, nur RS=0
|
142 |
|
143 | // Beide Nibble-Blöcke werden in Zwei Variablen zerlegt
|
144 | // Oberes Nibble
|
145 | uint8_t upper = SWAP(command);
|
146 | // Unteres Nibble
|
147 | uint8_t lower = (command);
|
148 | // Oberes Nibble übertragen
|
149 | Write4BitToPort(upper, 0);
|
150 | enable();
|
151 | // Unteres Nibble übertragen
|
152 | Write4BitToPort(lower, 0);
|
153 | enable();
|
154 | // Kurze Pause
|
155 | Pause_us(50);
|
156 | return;
|
157 | }
|
158 |
|
159 | void LCD_HD44780_4Bit::WriteChar( unsigned char val)
|
160 | {
|
161 | // Trennen der Nibbles
|
162 | uint8_t upper = SWAP(val);
|
163 | uint8_t lower = val;
|
164 |
|
165 | // Über RS wird ausgewählt, ob man einen Befehl oder ein Datenbyte an das LCD schicken möchte.
|
166 | // Beim Schreiben gilt: ist RS Low, dann wird das ankommende Byte als Befehl interpretiert;
|
167 | // Ist RS high, wird das Byte auf dem LCD angezeigt (genauer: ins Data-Register geschrieben, kann auch für den CG bestimmt sein).
|
168 |
|
169 | // Oberes Nibble ausgeben
|
170 | Write4BitToPort(upper, 1);
|
171 | // Enable, damit das LCD das Datenbyte interpretiert
|
172 | enable();
|
173 |
|
174 | // Unteres Nibble ausgeben
|
175 | Write4BitToPort(lower, 1);
|
176 | // Enable, damit das LCD das Datenbyte interpretiert
|
177 | enable();
|
178 |
|
179 | // 50µs warten
|
180 | Pause_us(50);
|
181 |
|
182 | return;
|
183 | }
|
184 |
|
185 | void LCD_HD44780_4Bit::Clear()
|
186 | {
|
187 | command(1);
|
188 | Pause_ms(5);
|
189 | return;
|
190 | }
|
191 |
|
192 |
|
193 |
|
194 | void * LCD_HD44780_4Bit::operator new( size_t size )
|
195 | {
|
196 | return malloc(size);
|
197 | }
|
198 |
|
199 | void LCD_HD44780_4Bit::operator delete( void * ptr )
|
200 | {
|
201 | free(ptr);
|
202 | }
|
203 |
|
204 | void LCD_HD44780_4Bit::Pause_us(double duration)
|
205 | {
|
206 | for (int i = 0; i < duration; i++)
|
207 | _delay_us(1);
|
208 | }
|
209 | void LCD_HD44780_4Bit::Pause_ms(double duration)
|
210 | {
|
211 | for (int i = 0; i < duration; i++)
|
212 | _delay_ms(1);
|
213 | }
|