Hallo, Ich habe hier auf mikrocontroller.net die Beschreibung zur ansteuerung für LCD Bildschirme gelesen und möchte nun einen solchen mithilfe eines MCP23017 (I2C GPIO erweiterung) ansteuern. Hierfür habe ich die Library die hich hier gefunden habe verwendet und sie erweitert. Jedoch scheine ich bereits beim initialiesieren einen Fehler zu haben da nur schwarze Balken angezeigt werden. Die Schaltung ist als Anhang zu finden, ich verwende das Panelolu2 von meinem 3D Drucker! Zum Display selber kann ich sagen das er funktioniert, da er mit dem Arduino und der dazugehörigen Software für den 3D Drucker ohne Probleme funktioniert. Da es anscheinend nur möglich ist Bilder als Anhang zu posten ist hier der Code den ich zum ansprechen des Displays verwende. lcd-routines.h
1 | // Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus |
2 | // http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung |
3 | // |
4 | |
5 | #ifndef LCD_ROUTINES_H |
6 | #define LCD_ROUTINES_H |
7 | |
8 | //////////////////////////////////////////////////////////////////////////////// |
9 | // Hier die verwendete Taktfrequenz in Hz eintragen, wichtig! |
10 | |
11 | #ifndef F_CPU |
12 | #define F_CPU 15000000UL |
13 | #endif |
14 | |
15 | //////////////////////////////////////////////////////////////////////////////// |
16 | // Pinbelegung für das LCD, an verwendete Pins anpassen |
17 | // Alle LCD Pins müssen an einem Port angeschlossen sein und die 4 |
18 | // Datenleitungen müssen auf aufeinanderfolgenden Pins liegen |
19 | |
20 | //Adresse des Slave Devices MCP23017 |
21 | //Die ersten 4 Bit sind laut Datenblatt definiert(0100) |
22 | //Die letzten 3 Bit werden über die Pins A0-A2 definiert |
23 | #define SLAVE 0b0100000 |
24 | |
25 | // LCD DB4-DB7 <--> PORTB an MCP23017 Bit GPB1-GPB4 |
26 | #define LCD_PORT 0x13 //GPIOB Register Addresse des MCP23017 |
27 | #define LCD_DDR 0x01 // IODIRB Register addresse des MCP23017 |
28 | #define LCD_DB 1 // GPB1 |
29 | |
30 | // LCD RS <--> PORTD Bit PD4 (RS: 1=Data, 0=Command) |
31 | #define LCD_RS 7 |
32 | |
33 | // LCD EN <--> PORTD Bit PD5 (EN: 1-Impuls für Daten) |
34 | #define LCD_EN 5 |
35 | |
36 | //////////////////////////////////////////////////////////////////////////////// |
37 | // LCD Ausführungszeiten (MS=Millisekunden, US=Mikrosekunden) |
38 | |
39 | #define LCD_BOOTUP_MS 15 |
40 | #define LCD_ENABLE_US 20 |
41 | #define LCD_WRITEDATA_US 46 |
42 | #define LCD_COMMAND_US 42 |
43 | |
44 | #define LCD_SOFT_RESET_MS1 5 |
45 | #define LCD_SOFT_RESET_MS2 1 |
46 | #define LCD_SOFT_RESET_MS3 1 |
47 | #define LCD_SET_4BITMODE_MS 5 |
48 | |
49 | #define LCD_CLEAR_DISPLAY_MS 2 |
50 | #define LCD_CURSOR_HOME_MS 2 |
51 | |
52 | //////////////////////////////////////////////////////////////////////////////// |
53 | // Zeilendefinitionen des verwendeten LCD |
54 | // Die Einträge hier sollten für ein LCD mit einer Zeilenlänge von 16 Zeichen passen |
55 | // Bei anderen Zeilenlängen müssen diese Einträge angepasst werden |
56 | |
57 | #define LCD_DDADR_LINE1 0x00 |
58 | #define LCD_DDADR_LINE2 0x40 |
59 | #define LCD_DDADR_LINE3 0x14 |
60 | #define LCD_DDADR_LINE4 0x54 |
61 | |
62 | uint_fast8_t _data; |
63 | uint_fast8_t _ddr; |
64 | uint_fast8_t _port; |
65 | static const unsigned char BitReverseTable16[] = |
66 | { |
67 | 0x00, 0x08, 0x04, 0x0C, 0x02, 0x0A, 0x06, 0x0E, 0x01, 0x09, 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x0F |
68 | }; |
69 | //////////////////////////////////////////////////////////////////////////////// |
70 | // Initialisierung: muss ganz am Anfang des Programms aufgerufen werden. |
71 | void lcd_init( void ); |
72 | |
73 | //////////////////////////////////////////////////////////////////////////////// |
74 | // LCD löschen |
75 | void lcd_clear( void ); |
76 | |
77 | //////////////////////////////////////////////////////////////////////////////// |
78 | // Cursor in die 1. Zeile, 0-te Spalte |
79 | void lcd_home( void ); |
80 | |
81 | //////////////////////////////////////////////////////////////////////////////// |
82 | // Cursor an eine beliebige Position |
83 | void lcd_setcursor( uint8_t spalte, uint8_t zeile ); |
84 | |
85 | //////////////////////////////////////////////////////////////////////////////// |
86 | // Ausgabe eines einzelnen Zeichens an der aktuellen Cursorposition |
87 | void lcd_data( uint8_t data ); |
88 | |
89 | //////////////////////////////////////////////////////////////////////////////// |
90 | // Ausgabe eines Strings an der aktuellen Cursorposition |
91 | void lcd_string( const char *data ); |
92 | |
93 | //////////////////////////////////////////////////////////////////////////////// |
94 | // Definition eines benutzerdefinierten Sonderzeichens. |
95 | // data muss auf ein Array[8] mit den Zeilencodes des zu definierenden Zeichens |
96 | // zeigen |
97 | void lcd_generatechar( uint8_t code, const uint8_t *data ); |
98 | |
99 | //////////////////////////////////////////////////////////////////////////////// |
100 | //Schreiben eines Registers des MCP23017 |
101 | void writeOut(uint8_t reg, uint_fast8_t value); |
102 | |
103 | //////////////////////////////////////////////////////////////////////////////// |
104 | // Ausgabe eines Kommandos an das LCD. |
105 | void lcd_command( uint8_t data ); |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | //////////////////////////////////////////////////////////////////////////////// |
112 | // LCD Befehle und Argumente. |
113 | // Zur Verwendung in lcd_command |
114 | |
115 | // Clear Display -------------- 0b00000001 |
116 | #define LCD_CLEAR_DISPLAY 0x01 |
117 | |
118 | // Cursor Home ---------------- 0b0000001x |
119 | #define LCD_CURSOR_HOME 0x02 |
120 | |
121 | // Set Entry Mode ------------- 0b000001xx |
122 | #define LCD_SET_ENTRY 0x04 |
123 | |
124 | #define LCD_ENTRY_DECREASE 0x00 |
125 | #define LCD_ENTRY_INCREASE 0x02 |
126 | #define LCD_ENTRY_NOSHIFT 0x00 |
127 | #define LCD_ENTRY_SHIFT 0x01 |
128 | |
129 | // Set Display ---------------- 0b00001xxx |
130 | #define LCD_SET_DISPLAY 0x08 |
131 | |
132 | #define LCD_DISPLAY_OFF 0x00 |
133 | #define LCD_DISPLAY_ON 0x04 |
134 | #define LCD_CURSOR_OFF 0x00 |
135 | #define LCD_CURSOR_ON 0x02 |
136 | #define LCD_BLINKING_OFF 0x00 |
137 | #define LCD_BLINKING_ON 0x01 |
138 | |
139 | // Set Shift ------------------ 0b0001xxxx |
140 | #define LCD_SET_SHIFT 0x10 |
141 | |
142 | #define LCD_CURSOR_MOVE 0x00 |
143 | #define LCD_DISPLAY_SHIFT 0x08 |
144 | #define LCD_SHIFT_LEFT 0x00 |
145 | #define LCD_SHIFT_RIGHT 0x04 |
146 | |
147 | // Set Function --------------- 0b001xxxxx |
148 | #define LCD_SET_FUNCTION 0x20 |
149 | |
150 | #define LCD_FUNCTION_4BIT 0x00 |
151 | #define LCD_FUNCTION_8BIT 0x10 |
152 | #define LCD_FUNCTION_1LINE 0x00 |
153 | #define LCD_FUNCTION_2LINE 0x08 |
154 | #define LCD_FUNCTION_5x8 0x04 |
155 | #define LCD_FUNCTION_5x11 0x00 |
156 | |
157 | #define LCD_SOFT_RESET 0x30 |
158 | |
159 | // Set CG RAM Address --------- 0b01xxxxxx (Character Generator RAM) |
160 | #define LCD_SET_CGADR 0x40 |
161 | |
162 | #define LCD_GC_CHAR0 0 |
163 | #define LCD_GC_CHAR1 1 |
164 | #define LCD_GC_CHAR2 2 |
165 | #define LCD_GC_CHAR3 3 |
166 | #define LCD_GC_CHAR4 4 |
167 | #define LCD_GC_CHAR5 5 |
168 | #define LCD_GC_CHAR6 6 |
169 | #define LCD_GC_CHAR7 7 |
170 | |
171 | // Set DD RAM Address --------- 0b1xxxxxxx (Display Data RAM) |
172 | #define LCD_SET_DDADR 0x80 |
173 | |
174 | #endif |
lcd-routines.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-routines.h einstellbar |
6 | |
7 | #include <avr/io.h> |
8 | #include "lcd-routines.h" |
9 | #include "TWI_Master.h" |
10 | #include <util/delay.h> |
11 | |
12 | //////////////////////////////////////////////////////////////////////////////// |
13 | // Erzeugt einen Enable-Puls |
14 | static void lcd_enable( void ) |
15 | { |
16 | //Enable auf 1 setzen |
17 | _data |= (1<<LCD_EN); |
18 | writeOut(LCD_PORT, _data); |
19 | //kurze Pause |
20 | _delay_us( LCD_ENABLE_US ); // kurze Pause |
21 | |
22 | //Enable auf 0 setzen |
23 | _data &= ~(1<<LCD_EN); |
24 | writeOut(LCD_PORT, _data); |
25 | } |
26 | |
27 | //////////////////////////////////////////////////////////////////////////////// |
28 | // Sendet eine 4-bit Ausgabeoperation an das LCD |
29 | static void lcd_out( uint8_t data ) |
30 | { |
31 | data &= 0xF0; |
32 | data = data >> 4; |
33 | data = BitReverseTable16[data]; |
34 | data = data << 4; |
35 | |
36 | _data &= ~(0xF0 >> (4-LCD_DB)); |
37 | writeOut(LCD_PORT, _data); |
38 | |
39 | _data |= (data>>(4-LCD_DB)); |
40 | writeOut(LCD_PORT, _data); |
41 | |
42 | lcd_enable(); |
43 | } |
44 | |
45 | //////////////////////////////////////////////////////////////////////////////// |
46 | // Initialisierung: muss ganz am Anfang des Programms aufgerufen werden. |
47 | void lcd_init( void ) |
48 | { |
49 | _data = 0x01; // 0b00000001 schaltet LED des Panelolu 2 aus |
50 | |
51 | _ddr = 0b00000000; |
52 | _port = 0x00; |
53 | |
54 | writeOut(LCD_DDR, _ddr);//Alle benötigten Pins als Ausgang definieren |
55 | |
56 | writeOut(LCD_PORT, _port);//Alle Ausgänge auf 0 setzen |
57 | |
58 | // warten auf die Bereitschaft des LCD |
59 | _delay_ms( LCD_BOOTUP_MS ); |
60 | |
61 | // Soft-Reset muss 3mal hintereinander gesendet werden zur Initialisierung |
62 | _data = LCD_SOFT_RESET; |
63 | lcd_out( _data ); |
64 | _delay_ms( LCD_SOFT_RESET_MS1 ); |
65 | |
66 | lcd_enable(); |
67 | _delay_ms( LCD_SOFT_RESET_MS2 ); |
68 | |
69 | lcd_enable(); |
70 | _delay_ms( LCD_SOFT_RESET_MS3 ); |
71 | |
72 | // 4-bit Modus aktivieren |
73 | _data = (LCD_SET_FUNCTION | LCD_FUNCTION_4BIT); |
74 | lcd_out( _data ); |
75 | _delay_ms( LCD_SET_4BITMODE_MS ); |
76 | |
77 | // 4-bit Modus / 2 Zeilen / 5x7 |
78 | _data = (LCD_SET_FUNCTION | LCD_FUNCTION_4BIT | LCD_FUNCTION_2LINE |LCD_FUNCTION_5x8); |
79 | lcd_command( _data); |
80 | |
81 | // Display ein / Cursor aus / Blinken aus |
82 | _data = (LCD_SET_DISPLAY |LCD_DISPLAY_ON |LCD_CURSOR_OFF |LCD_BLINKING_OFF); |
83 | lcd_command( _data ); |
84 | |
85 | // Cursor inkrement / kein Scrollen |
86 | _data = ( LCD_SET_ENTRY |LCD_ENTRY_INCREASE |LCD_ENTRY_NOSHIFT); |
87 | lcd_command(_data); |
88 | |
89 | lcd_clear(); |
90 | } |
91 | |
92 | //////////////////////////////////////////////////////////////////////////////// |
93 | // Sendet ein Datenbyte an das LCD |
94 | void lcd_data( uint8_t data ) |
95 | { |
96 | _port |= (1<<LCD_RS); |
97 | |
98 | writeOut(LCD_PORT, _port); |
99 | |
100 | lcd_out( data ); // zuerst die oberen, |
101 | lcd_out( data<<4 ); // dann die unteren 4 Bit senden |
102 | |
103 | _delay_us( LCD_WRITEDATA_US ); |
104 | } |
105 | |
106 | //////////////////////////////////////////////////////////////////////////////// |
107 | // Sendet einen Befehl an das LCD |
108 | void lcd_command( uint8_t data ) |
109 | { |
110 | _port &= ~(1<<LCD_RS); |
111 | writeOut(LCD_PORT, _port); |
112 | |
113 | lcd_out( data ); // zuerst die oberen, |
114 | lcd_out( data<<4 ); // dann die unteren 4 Bit senden |
115 | |
116 | _delay_us( LCD_COMMAND_US ); |
117 | } |
118 | |
119 | //////////////////////////////////////////////////////////////////////////////// |
120 | // Sendet den Befehl zur Löschung des Displays |
121 | void lcd_clear( void ) |
122 | { |
123 | lcd_command( LCD_CLEAR_DISPLAY ); |
124 | _delay_ms( LCD_CLEAR_DISPLAY_MS ); |
125 | } |
126 | |
127 | //////////////////////////////////////////////////////////////////////////////// |
128 | // Sendet den Befehl: Cursor Home |
129 | void lcd_home( void ) |
130 | { |
131 | lcd_command( LCD_CURSOR_HOME ); |
132 | _delay_ms( LCD_CURSOR_HOME_MS ); |
133 | } |
134 | |
135 | //////////////////////////////////////////////////////////////////////////////// |
136 | // Setzt den Cursor in Spalte x (0..15) Zeile y (1..4) |
137 | |
138 | void lcd_setcursor( uint8_t x, uint8_t y ) |
139 | { |
140 | uint8_t data; |
141 | |
142 | switch (y) |
143 | { |
144 | case 1: // 1. Zeile |
145 | data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x; |
146 | break; |
147 | |
148 | case 2: // 2. Zeile |
149 | data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x; |
150 | break; |
151 | |
152 | case 3: // 3. Zeile |
153 | data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x; |
154 | break; |
155 | |
156 | case 4: // 4. Zeile |
157 | data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x; |
158 | break; |
159 | |
160 | default: |
161 | return; // für den Fall einer falschen Zeile |
162 | } |
163 | |
164 | lcd_command( data ); |
165 | } |
166 | |
167 | //////////////////////////////////////////////////////////////////////////////// |
168 | // Schreibt einen String auf das LCD |
169 | |
170 | void lcd_string( const char *data ) |
171 | { |
172 | while( *data != '\0' ) |
173 | lcd_data( *data++ ); |
174 | } |
175 | |
176 | //////////////////////////////////////////////////////////////////////////////// |
177 | // Schreibt ein Zeichen in den Character Generator RAM |
178 | |
179 | void lcd_generatechar( uint8_t code, const uint8_t *data ) |
180 | { |
181 | // Startposition des Zeichens einstellen |
182 | lcd_command( LCD_SET_CGADR | (code<<3) ); |
183 | |
184 | // Bitmuster übertragen |
185 | for ( uint8_t i=0; i<8; i++ ) |
186 | { |
187 | lcd_data( data[i] ); |
188 | } |
189 | } |
190 | |
191 | void writeOut(uint8_t reg, uint_fast8_t value) |
192 | { |
193 | if(!TWIM_Start(SLAVE, TWIM_WRITE)) |
194 | { |
195 | TWIM_Stop(); |
196 | } |
197 | else |
198 | { |
199 | TWIM_Write(reg); |
200 | TWIM_Write(value); |
201 | TWIM_Stop(); |
202 | } |
203 | } |
Hoffentlich kann mir jemand helfen! mit freundlichen Grüßen Markus