1 | //----------------------------------------------------------------------
|
2 | // Titel : "2-Draht LC-Display" für den ATmega88/168
|
3 | //----------------------------------------------------------------------
|
4 | // Funktion : Ansteuerung für 2-Draht-LC-Display
|
5 | // : (kompatiebel zum CC2-Interface)
|
6 | // Schaltung : "PC-Lüftersteuerung"
|
7 | //----------------------------------------------------------------------
|
8 | // Prozessor : ATmega88/168
|
9 | // Takt : 16.0000 MHz
|
10 | // Sprache : C
|
11 | // C-Compiler : WinAVR - 20080610 (programmiert in AVR-Studio)
|
12 | // : (http://sourceforge.net/projects/winavr/)
|
13 | // Datum : 10.10.2008
|
14 | // Version : 1.0 R.Degen
|
15 | //----------------------------------------------------------------------
|
16 | #define DF_CPU 16000000 // Taktfrequenz ATmega
|
17 | #include <avr\io.h> // AVR Register und Konstantendefinitionen
|
18 | #include <util\delay.h> // Bibliothek mit Warteroutinen
|
19 | //----------------------------------------------------------------------
|
20 |
|
21 | // Pinbelegung für das LCD, an verwendete Pins anpassen
|
22 |
|
23 | #define lcd_port PORTC // Port für LCD
|
24 | #define lcd_ddr DDRC // Port-Richtung
|
25 | #define lcd_clk PC0 // Clk-Leitung an Schieberegister 74HCT164
|
26 | #define lcd_data PC1 // Data-Leitung an Schieberegister u. Enable-Signal LCD
|
27 |
|
28 | //-----------------------------------------------
|
29 | // Funktions-Routinen
|
30 | //-----------------------------------------------
|
31 |
|
32 | // Clk-Impuls für Schieberegister erzeugen
|
33 | void lcd_clk_impuls()
|
34 | {
|
35 | _delay_us(5); // 5µsec warten
|
36 | lcd_port |= (1<<lcd_clk); // Clk-Pin auf 1
|
37 | _delay_us(10); // 10µsec warten
|
38 | lcd_port &= ~(1<<lcd_clk); // Clk-Pin auf 0
|
39 | _delay_us(5); // 5µsec warten
|
40 | }
|
41 |
|
42 | // Ausgänge des Schieberegisters auf 0 setzen
|
43 | void lcd_clr_schieberegister()
|
44 | {
|
45 | lcd_port &= ~(1<<lcd_data); // Data-Leitung am Eingang des Schieberegisters auf 0
|
46 | uint8_t i; // Bit-Zähler (8Bit Integer ohne Vorzeichen)
|
47 | for (i=0;i<7;i++) // Zählerschleife
|
48 | {
|
49 | lcd_clk_impuls(); // 7x Clk-Impulse am Schieberegister erzeugen
|
50 | } // Zählerschleife beenden?
|
51 | }
|
52 |
|
53 | // Enabled-Impuls am LC-Display erzeugen und danach Schieberegister löschen
|
54 | void lcd_enabled_impuls()
|
55 | {
|
56 | _delay_us(5); // 5µsec warten
|
57 | lcd_port |= (1<<lcd_data); // Data-Leitung auf 1
|
58 | _delay_us(10); // 10µsec warten
|
59 | lcd_clr_schieberegister(); // Schieberegister löschen
|
60 | _delay_us(5);
|
61 | }
|
62 |
|
63 | // sende Hi-Nibble an LC-Display (LCD-init.Mode)
|
64 | void lcd_send_hi_nibble(uint8_t nibble)
|
65 | {
|
66 | lcd_port |= (1<<lcd_data); // Lcd-Enabled-Bit auf 1
|
67 | lcd_clk_impuls(); // Bit ins Schieberegister übertragen
|
68 | lcd_port &=~ (1<<lcd_data); // Lcd-RS-Bit auf 0
|
69 | lcd_clk_impuls(); // Bit ins Schieberegister übertragen
|
70 | uint8_t i; // Bit-Zähler (8Bit Integer ohne Vorzeichen)
|
71 | for (i=0;i<4;i++) // Zählerschleife (4 mal)
|
72 | {
|
73 | if (nibble & 0x80) // Bit7 in nibble prüfen (Bits in nibble mit 0b10000000 maskieren)
|
74 | {
|
75 | lcd_port |= (1<<lcd_data); // wenn Bit7=1 dann Data-Leitung auf 1
|
76 | }
|
77 | else
|
78 | {
|
79 | lcd_port &=~(1<<lcd_data); // wenn Bit7=0 dann Data-Leitung auf 0
|
80 | }
|
81 | lcd_clk_impuls(); // Bit ins Schieberegister übertragen
|
82 | nibble = nibble<<1; // Bits in nibble 1x nach links routieren
|
83 | } // Zählerschleife beenden?
|
84 | lcd_port &= ~ (1<<lcd_data); // erstes Bit im Schieberegister auf 0 setzen (unbenutzt)
|
85 | lcd_clk_impuls(); // Bit ins Schieberegister übertragen
|
86 | lcd_enabled_impuls(); // Lcd-Enabled Impuls erzeugen
|
87 | }
|
88 |
|
89 | // sende ein Byte ans LC-Display
|
90 | // wenn cmd=0 ein LCD-Kommandobyte senden / wenn cmd=1 ein LCD-Datenbyte senden)
|
91 | // in data befindet das Kommando- oder Datenbyte
|
92 | void lcd_send_data(uint8_t cmd, uint8_t data)
|
93 | {
|
94 | uint8_t i1; // Zähler (8Bit Integer ohne Vorzeichen)
|
95 | for (i1=0;i1<2;i1++) // 1.Zählerschleife (2 mal) um high- und low-nibble zu senden
|
96 | {
|
97 | lcd_port |= (1<<lcd_data); // Lcd-Enabled-Bit auf 1
|
98 | lcd_clk_impuls(); // Bit ins Schieberegister übertragen
|
99 | if (cmd==0) // LCD-Kommandobyte ?
|
100 | {
|
101 | lcd_port &=~(1<<lcd_data); // Lcd-RS-Bit auf 0
|
102 | }
|
103 | else
|
104 | {
|
105 | lcd_port |= (1<<lcd_data); // Lcd-RS-Bit auf 1
|
106 | }
|
107 | lcd_clk_impuls(); // Bit ins Schieberegister übertragen
|
108 | uint8_t i2; // Bit-Zähler (8Bit Integer ohne Vorzeichen)
|
109 | for (i2=0;i2<4;i2++) // 2.Zählerschleife (4 mal) für ein nibble
|
110 | {
|
111 | if (data & 0x80) // Bit7 in data prüfen (Bits in data mit 0b10000000 maskieren)
|
112 | {
|
113 | lcd_port |= (1<<lcd_data);// wenn Bit7=1 dann Data-Leitung auf 1
|
114 | }
|
115 | else
|
116 | {
|
117 | lcd_port &=~(1<<lcd_data);// wenn Bit7=0 dann Data-Leitung auf 0
|
118 | }
|
119 | lcd_clk_impuls(); // Bit ins Schieberegister übertragen
|
120 | data = data<<1; // Bits in Data 1x nach links routieren
|
121 | } // 2.Zählerschleife beenden?
|
122 | lcd_port &= ~ (1<<lcd_data); // erstes Bit im Schieberegister auf 0 setzen (unbenutzt)
|
123 | lcd_clk_impuls(); // Bit ins Schieberegister übertragen
|
124 | lcd_enabled_impuls(); // Lcd-Enabled Impuls erzeugen
|
125 | } // 1.Zählerschleife beenden ?
|
126 | _delay_ms(5); // warte bis LCD bereit für nächsten Datenempfang
|
127 | }
|
128 |
|
129 | // Init. LC-Display:4-Bit Interface,5x7 Dots,2 Rows,Cursor on,Line-Cursor on,Display on
|
130 | void lcd_init()
|
131 | {
|
132 | _delay_ms(100); // 100ms warten bis LC-Display bereitnach Power on
|
133 | lcd_clr_schieberegister(); // Schieberegister löschen
|
134 | _delay_us(10); // 10us warten
|
135 | // ab hier: LCD-Resetsequenz
|
136 | lcd_send_hi_nibble(0b00110000);// sende 1.Hi-Nibble an LC-Display
|
137 | _delay_ms(5); // 5ms warten bis LC-Display bereit
|
138 | lcd_send_hi_nibble(0b00110000);// sende 2.Hi-Nibble an LC-Display
|
139 | _delay_ms(5); // 5ms warten bis LC-Display bereit
|
140 | lcd_send_hi_nibble(0b00110000);// sende 3.Hi-Nibble an LC-Display
|
141 | _delay_ms(5); // 5ms warten bis LC-Display bereit
|
142 | // LCD in 4Bit-Mode schalten
|
143 | lcd_send_hi_nibble(0b00100000);// sende Hi-Nibble an LC-Display
|
144 | _delay_ms(5); // 5ms warten bis LC-Display bereit
|
145 | // ab hier ist LCD im 4-Bit Modus
|
146 | // (Parameterliste: 1.Byte = cmd, 2.Byte = Data)
|
147 | lcd_send_data(0,0b00101000); // LCD-Command 2 Zeilen, 5x8 Dots
|
148 | lcd_send_data(0,0b00001000); // LCD-Comand Display aus
|
149 | lcd_send_data(0,0b00000001); // LCD-Comand Display löschen
|
150 | lcd_send_data(0,0b00000110); // LCD-Comand Display Entrymode
|
151 | lcd_send_data(0,0b00001111); // LCD-Comand Display ein
|
152 | }
|
153 |
|
154 | //-----------------------------------------------------------------
|
155 | // Hauptprogramm
|
156 | //-----------------------------------------------------------------
|
157 |
|
158 | int main (void)
|
159 | {
|
160 | lcd_ddr |= (1<<lcd_clk); // Portleitung CLK (Clk-Schieberegister) auf Ausgang konfigurieren
|
161 | lcd_ddr |= (1<<lcd_data); // Portleitung DATA (Data-Schieberegister) auf Ausgang konfigurieren
|
162 | lcd_port &=~(1<<lcd_clk); // CLK auf 0 setzen
|
163 | lcd_port &=~(1<<lcd_data); // DATA auf 0 setzen
|
164 | lcd_init(); // init. LC-Display
|
165 | lcd_send_data(1,'H'); // Text senden
|
166 | lcd_send_data(1,'a');
|
167 | lcd_send_data(1,'l');
|
168 | lcd_send_data(1,'l');
|
169 | lcd_send_data(1,'o');
|
170 | lcd_send_data(1,' ');
|
171 | lcd_send_data(1,'C');
|
172 | lcd_send_data(1,'o');
|
173 | lcd_send_data(1,'m');
|
174 | lcd_send_data(1,'p');
|
175 | lcd_send_data(1,'u');
|
176 | lcd_send_data(1,'t');
|
177 | lcd_send_data(1,'e');
|
178 | lcd_send_data(1,'r');
|
179 | lcd_send_data(1,'C');
|
180 | lcd_send_data(1,'l');
|
181 | lcd_send_data(1,'u');
|
182 | lcd_send_data(1,'b');
|
183 | lcd_send_data(1,' ');
|
184 | lcd_send_data(1,'2');
|
185 | }
|