1 | #define F_CPU 8000000 //interner 1MHz OSzillator
|
2 | #include <avr/io.h>
|
3 | #include <lcd_routines.h>
|
4 | #include <util/delay.h>
|
5 | #include <stdlib.h>
|
6 | #include <stdio.h>
|
7 |
|
8 | void ADC_Init(void){ //ADC initialisieren
|
9 |
|
10 | uint16_t result; //Ergebnisvariable "result"
|
11 |
|
12 | ADMUX = (1<<REFS0); //Referenzspannung von Avcc
|
13 |
|
14 | ADCSRA = (1<<ADPS1) | (1<<ADPS0); //Vorteiler = 8
|
15 | ADCSRA = (1<<ADEN); //ADC aktivieren
|
16 |
|
17 | result = ADCW;
|
18 |
|
19 | }
|
20 |
|
21 | /* ADC Einzelmessung */
|
22 | uint16_t ADC_Read( uint8_t channel )
|
23 | {
|
24 | // Kanal waehlen, ohne andere Bits zu beeinflußen
|
25 | ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
|
26 | ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
|
27 | while (ADCSRA & (1<<ADSC) ) { // auf Abschluss der Konvertierung warten
|
28 | }
|
29 | return (ADCW); // ADC auslesen und zurückgeben
|
30 | }
|
31 |
|
32 | /* ADC Mehrfachmessung mit Mittelwertbbildung */
|
33 | /* beachte: Wertebereich der Summenvariablen */
|
34 | uint16_t ADC_Read_Avg( uint8_t channel, uint8_t nsamples )
|
35 | {
|
36 | uint32_t sum = 0;
|
37 |
|
38 | for (uint8_t i = 0; i < nsamples; ++i ) {
|
39 | sum += ADC_Read( channel );
|
40 | }
|
41 |
|
42 | return (uint16_t)( sum / nsamples );
|
43 | }
|
44 |
|
45 | ////////////////////////////////////////////////////////////////////////////////
|
46 | // Erzeugt einen Enable-Puls
|
47 | static void lcd_enable( void )
|
48 | {
|
49 | LCD_PORT |= (1<<LCD_EN); // Enable auf 1 setzen
|
50 | _delay_us( LCD_ENABLE_US ); // kurze Pause
|
51 | LCD_PORT &= ~(1<<LCD_EN); // Enable auf 0 setzen
|
52 | }
|
53 |
|
54 | ////////////////////////////////////////////////////////////////////////////////
|
55 | // Sendet eine 4-bit Ausgabeoperation an das LCD
|
56 | static void lcd_out( uint8_t data )
|
57 | {
|
58 | data &= 0xF0; // obere 4 Bit maskieren
|
59 |
|
60 | LCD_PORT &= ~(0xF0>>(4-LCD_DB)); // Maske löschen
|
61 | LCD_PORT |= (data>>(4-LCD_DB)); // Bits setzen
|
62 | lcd_enable();
|
63 | }
|
64 |
|
65 | ////////////////////////////////////////////////////////////////////////////////
|
66 | // Initialisierung: muss ganz am Anfang des Programms aufgerufen werden.
|
67 | void lcd_init( void )
|
68 | {
|
69 | // verwendete Pins auf Ausgang schalten
|
70 | uint8_t pins = (0x0F << LCD_DB) | // 4 Datenleitungen
|
71 | (1<<LCD_RS) | // R/S Leitung
|
72 | (1<<LCD_EN); // Enable Leitung
|
73 | LCD_DDR |= pins;
|
74 |
|
75 | // initial alle Ausgänge auf Null
|
76 | LCD_PORT &= ~pins;
|
77 |
|
78 | // warten auf die Bereitschaft des LCD
|
79 | _delay_ms( LCD_BOOTUP_MS );
|
80 |
|
81 | // Soft-Reset muss 3mal hintereinander gesendet werden zur Initialisierung
|
82 | lcd_out( LCD_SOFT_RESET );
|
83 | _delay_ms( LCD_SOFT_RESET_MS1 );
|
84 |
|
85 | lcd_enable();
|
86 | _delay_ms( LCD_SOFT_RESET_MS2 );
|
87 |
|
88 | lcd_enable();
|
89 | _delay_ms( LCD_SOFT_RESET_MS3 );
|
90 |
|
91 | // 4-bit Modus aktivieren
|
92 | lcd_out( LCD_SET_FUNCTION |
|
93 | LCD_FUNCTION_4BIT );
|
94 | _delay_ms( LCD_SET_4BITMODE_MS );
|
95 |
|
96 | // 4-bit Modus / 2 Zeilen / 5x7
|
97 | lcd_command( LCD_SET_FUNCTION |
|
98 | LCD_FUNCTION_4BIT |
|
99 | LCD_FUNCTION_2LINE |
|
100 | LCD_FUNCTION_5X7 );
|
101 |
|
102 | // Display ein / Cursor aus / Blinken aus
|
103 | lcd_command( LCD_SET_DISPLAY |
|
104 | LCD_DISPLAY_ON |
|
105 | LCD_CURSOR_OFF |
|
106 | LCD_BLINKING_OFF);
|
107 |
|
108 | // Cursor inkrement / kein Scrollen
|
109 | lcd_command( LCD_SET_ENTRY |
|
110 | LCD_ENTRY_INCREASE |
|
111 | LCD_ENTRY_NOSHIFT );
|
112 |
|
113 | lcd_clear();
|
114 | }
|
115 |
|
116 | ////////////////////////////////////////////////////////////////////////////////
|
117 | // Sendet ein Datenbyte an das LCD
|
118 | void lcd_data( uint8_t data )
|
119 | {
|
120 | LCD_PORT |= (1<<LCD_RS); // RS auf 1 setzen
|
121 |
|
122 | lcd_out( data ); // zuerst die oberen,
|
123 | lcd_out( data<<4 ); // dann die unteren 4 Bit senden
|
124 |
|
125 | _delay_us( LCD_WRITEDATA_US );
|
126 | }
|
127 |
|
128 | ////////////////////////////////////////////////////////////////////////////////
|
129 | // Sendet einen Befehl an das LCD
|
130 | void lcd_command( uint8_t data )
|
131 | {
|
132 | LCD_PORT &= ~(1<<LCD_RS); // RS auf 0 setzen
|
133 |
|
134 | lcd_out( data ); // zuerst die oberen,
|
135 | lcd_out( data<<4 ); // dann die unteren 4 Bit senden
|
136 |
|
137 | _delay_us( LCD_COMMAND_US );
|
138 | }
|
139 |
|
140 | ////////////////////////////////////////////////////////////////////////////////
|
141 | // Sendet den Befehl zur Löschung des Displays
|
142 | void lcd_clear( void )
|
143 | {
|
144 | lcd_command( LCD_CLEAR_DISPLAY );
|
145 | _delay_ms( LCD_CLEAR_DISPLAY_MS );
|
146 | }
|
147 |
|
148 | ////////////////////////////////////////////////////////////////////////////////
|
149 | // Sendet den Befehl: Cursor Home
|
150 | void lcd_home( void )
|
151 | {
|
152 | lcd_command( LCD_CURSOR_HOME );
|
153 | _delay_ms( LCD_CURSOR_HOME_MS );
|
154 | }
|
155 |
|
156 | ////////////////////////////////////////////////////////////////////////////////
|
157 | // Setzt den Cursor in Spalte x (0..15) Zeile y (1..4)
|
158 |
|
159 | void lcd_setcursor( uint8_t x, uint8_t y )
|
160 | {
|
161 | uint8_t data;
|
162 |
|
163 | switch (y)
|
164 | {
|
165 | case 1: // 1. Zeile
|
166 | data = LCD_SET_DDADR + LCD_DDADR_LINE1 + x;
|
167 | break;
|
168 |
|
169 | case 2: // 2. Zeile
|
170 | data = LCD_SET_DDADR + LCD_DDADR_LINE2 + x;
|
171 | break;
|
172 |
|
173 | case 3: // 3. Zeile
|
174 | data = LCD_SET_DDADR + LCD_DDADR_LINE3 + x;
|
175 | break;
|
176 |
|
177 | case 4: // 4. Zeile
|
178 | data = LCD_SET_DDADR + LCD_DDADR_LINE4 + x;
|
179 | break;
|
180 |
|
181 | default:
|
182 | return; // für den Fall einer falschen Zeile
|
183 | }
|
184 |
|
185 | lcd_command( data );
|
186 | }
|
187 |
|
188 | ///////
|
189 | /////////////////////////////////////////////////////////////////////////
|
190 | // Schreibt einen String auf das LCD
|
191 |
|
192 | void lcd_string( const char *data )
|
193 | {
|
194 | while( *data != '\0' )
|
195 | lcd_data( *data++ );
|
196 | }
|
197 |
|
198 | ////////////////////////////////////////////////////////////////////////////////
|
199 | // Schreibt ein Zeichen in den Character Generator RAM
|
200 |
|
201 | void lcd_generatechar( uint8_t code, const uint8_t *data )
|
202 | {
|
203 | // Startposition des Zeichens einstellen
|
204 | lcd_command( LCD_SET_CGADR | (code<<3) );
|
205 |
|
206 | // Bitmuster übertragen
|
207 | for ( uint8_t i=0; i<8; i++ )
|
208 | {
|
209 | lcd_data( data[i] );
|
210 | }
|
211 | }
|
212 |
|
213 |
|
214 | void st(void){
|
215 | while (bit_is_set(PINB,0)){}
|
216 | PORTB |= _BV(PB4);
|
217 | lcd_setcursor(0,1);
|
218 | lcd_string(" PSU 30/1500");
|
219 | lcd_setcursor(0,2);
|
220 | lcd_string("(Soft.-vers 1.1)");
|
221 | _delay_ms(2000);
|
222 | PORTB |= _BV(PB5);
|
223 | lcd_clear();
|
224 | lcd_setcursor(15,1);
|
225 | lcd_string("V");
|
226 | lcd_setcursor(6,1);
|
227 | lcd_string("A");
|
228 | }
|
229 |
|
230 |
|
231 | void standby(void){
|
232 | lcd_clear();
|
233 | lcd_setcursor(1,1);
|
234 | lcd_string(" Goodbye!");
|
235 | _delay_ms(2000);
|
236 | PORTB &= ~_BV(PB4);
|
237 | PORTB &= ~_BV(PB5);
|
238 | while (bit_is_set(PINB,0)){}
|
239 | st();
|
240 |
|
241 | }
|
242 |
|
243 | int main(void){
|
244 |
|
245 | DDRB = 0b11110010;
|
246 | PORTB = PORTB | _BV(PB0) | _BV(PB2) | _BV(PB3);
|
247 | TCCR1A = (1<<WGM11) | (1<<WGM10) | (1<<COM1A1);
|
248 | TCCR1B = (1<<CS10);
|
249 |
|
250 | ADC_Init();
|
251 | lcd_init();
|
252 | st();
|
253 |
|
254 | uint16_t delay = 0;
|
255 | uint16_t adcval;
|
256 | uint16_t volt;
|
257 | uint16_t amp;
|
258 | double resv;
|
259 | double resa;
|
260 | char strv[10];
|
261 | char stra[10];
|
262 |
|
263 | while(1){
|
264 |
|
265 | adcval = ADC_Read(0);
|
266 | volt = ADC_Read(1);
|
267 | amp = ADC_Read(2);
|
268 | OCR1A = adcval;
|
269 |
|
270 | if (bit_is_clear(PINB,2)){
|
271 | standby();
|
272 | }
|
273 |
|
274 | if (delay > 40000){
|
275 | resa = amp;
|
276 | resa /= 100 * 4.8876;
|
277 | dtostrf(resa, 5, 2, stra);
|
278 | lcd_setcursor(0,1);
|
279 | lcd_string(stra);
|
280 |
|
281 | resv = volt;
|
282 | resv /= 1000 * 4.8876;
|
283 | dtostrf(resv, 5, 2, strv);
|
284 | lcd_setcursor(9,1);
|
285 | lcd_string(strv);
|
286 | delay = 0;
|
287 | }
|
288 | delay ++;
|
289 | }
|
290 | }
|