1 | #define F_CPU 1000000 // int.Takt auf 1MHz gestellt
|
2 | #include <avr/io.h>
|
3 | #include <util/delay.h>
|
4 |
|
5 | // Präprozessor Makros
|
6 | #define OBER_BEREICH (int16_t)(11.8*1024/15) // oberen Spg-Schwellwert definieren, Formel: OW.MBg*AL/MBg, wird vom Compiler nur ein mal berechnet
|
7 | #define UNTER_BEREICH (int16_t)(10.8*1024/15) // unteren Spg-Schwellwert definieren, Formel: UW.MBg*AL/MBg, wird vom Compiler nur ein mal berechnet
|
8 | #define SET_BIT(port,mask) ((port) |= (1<<mask)) // Ausgangs-Port einschalten
|
9 | #define CLR_BIT(port,mask) ((port) &= ~(1<<mask)) // Ausgangs-Port ausschalten
|
10 | #define LED_HIGH (SET_BIT(PORTB,PB0)); (CLR_BIT(PORTB,PB1)); (CLR_BIT(PORTB,PB2)) // LED1 (Spg. Oberbereich) ein, Rest aus
|
11 | #define LED_MID (CLR_BIT(PORTB,PB0)); (SET_BIT(PORTB,PB1)); (CLR_BIT(PORTB,PB2)) // LED2 (Spg. Mittelbereich) ein, Rest aus
|
12 | #define LED_LOW (CLR_BIT(PORTB,PB0)); (CLR_BIT(PORTB,PB1)); (SET_BIT(PORTB,PB2)) // LED3 (Spg. Unterbereich) ein, Rest aus
|
13 | #define BATT_ON (SET_BIT(PORTB,PB4)) // "Batterie"-Ausgang ein
|
14 | #define BATT_OFF (CLR_BIT(PORTB,PB4)) // "Batterie"-Ausgang aus
|
15 |
|
16 | void ADC_Init(void) // ADC initialisieren
|
17 | {
|
18 | //ADMUX = (0<<REFS1) | (1<<REFS0); // AREF an PB0, internal Vref= off
|
19 | ADMUX = (0<<REFS1) | (0<<REFS0); // AVcc als Referenz benutzen, unabhängig von AREF/PB0
|
20 | //ADMUX = (1<<REFS1) | (0<<REFS0); // interne Referenzspannung 1,1V nutzen
|
21 |
|
22 | //ADCSRA = (0<<ADPS2) | (0<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler 2 // Multiplexer schnell, aber ungenau
|
23 | //ADCSRA = (0<<ADPS2) | (1<<ADPS1) | (0<<ADPS0); // Frequenzvorteiler 4
|
24 | ADCSRA = (0<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler 8 // 1MHz/8=125kHz=8us
|
25 | //ADCSRA = (1<<ADPS2) | (0<<ADPS1) | (0<<ADPS0); // Frequenzvorteiler 16
|
26 | //ADCSRA = (1<<ADPS2) | (0<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler 32
|
27 | //ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0); // Frequenzvorteiler 64
|
28 | //ADCSRA = (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Frequenzvorteiler 128 // Multiplexer langsam, aber genau
|
29 |
|
30 | ADCSRA |= (1<<ADEN); // ADC aktivieren
|
31 |
|
32 | // nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen,
|
33 | // man liest also einen Wert aus und verwirft diesen, um den ADC "warmlaufen zu lassen" (Quelle: FRANZIS-Buch)
|
34 | ADCSRA |= (1<<ADSC); // eine Wandlung starten "single conversion"
|
35 |
|
36 | while (ADCSRA & (1<<ADSC)); // auf Ergenbnis warten
|
37 | // ADCW muss ein mal gelesen werden, sonst wird das Ergebnis der nächsten Wandlung nicht übernomen (Quelle: FRANZIS-Buch)
|
38 |
|
39 | (void) ADCW; // ADCW gibt den 10bit-Messwert (0-1023) zurück
|
40 | }
|
41 |
|
42 | uint16_t ADC_Read(uint8_t Eingang) // ADC Einzelmessung
|
43 | {
|
44 | ADMUX = (ADMUX & ~(0x1F)) | (Eingang & 0x1F); // Eingangskanal wählen, ohne andere Bits zu beeinflußen
|
45 | ADCSRA |= (1<<ADSC); // eine Wandlung starten "single conversion"
|
46 | while (ADCSRA & (1<<ADSC)); // auf Ergenbnis warten
|
47 | return ADCW; // ADCW gibt den 10bit-Messwert (0-1023) zurück
|
48 | }
|
49 |
|
50 | uint16_t ADC_Read_Avg(uint8_t Eingang, uint8_t Durchlauf) // ADC Mehrfachmessung zur arithm. Mittelwertbbildung
|
51 | { // zur Genauigkeitssteigerung
|
52 | uint32_t MesswSum = 0;
|
53 |
|
54 | for (uint8_t i = 0; i < Durchlauf; ++i) // Durchläufe
|
55 | {
|
56 | MesswSum += ADC_Read(Eingang); // Messwerte summieren
|
57 | //_delay_us(250); // warte 250us, Intervall der Messwertauslesung, bei sehr verrauschtem Signal besser
|
58 | }
|
59 | return (uint16_t)(MesswSum / Durchlauf); // Mittelwertbildung
|
60 | }
|
61 |
|
62 | void Warte(uint16_t WarteMS)
|
63 | {
|
64 | while(WarteMS) // Wartezeit
|
65 | {
|
66 | WarteMS--; // runter zählen
|
67 | _delay_ms(1); // 1ms
|
68 | }
|
69 | }
|
70 |
|
71 | void Led_Ein(uint8_t Led) // LEDs auswählen
|
72 | {
|
73 | static uint8_t LetztLed = 0xFF; // 0xFF ... undefeniert // static ... Variable überlebt nach der Funktion
|
74 |
|
75 | if(LetztLed != Led)
|
76 | {
|
77 | switch(Led)
|
78 | {
|
79 | case 1: LED_HIGH; Led=1; break; // LED/high ein, Rest aus
|
80 | case 2: LED_MID; Led=2; break; // LED/mid ein, Rest aus + Mindest-Wartezeit [ms]
|
81 | default: LED_LOW; Led=3; break; // sonst, LED/low ein, Rest aus
|
82 | }
|
83 | LetztLed=Led;
|
84 | }
|
85 | }
|
86 |
|
87 | int main(void) // Hauptprogramm
|
88 | {
|
89 | DDRB &= ~(1<<PB5); // Eingang PB5...Master_OFF, wenn 1
|
90 | DDRB = ((1<<PB4)|(1<<PB2)|(1<<PB1)|(1<<PB0)); // Ausgang PB4=Batt_ON, PB2=low, PB1=mid, PB0=high
|
91 |
|
92 | uint16_t MitWert; // Mittelwert
|
93 | uint8_t Led=2; // LED auswahl
|
94 |
|
95 | //PORTB &= ~((1<<PB4)|(1<<PB2)|(1<<PB1)|(1<<PB0)); // Ausgangsvoreinstellung, PB0, PB1, PB2, PB4 = 0
|
96 | ADC_Init(); // ADC initialize
|
97 |
|
98 | //while((PINB & (1<<PB5)) == 0) //Klappt nicht // auf "0" prüfen
|
99 | //while(PINB & (1<<PB5)) //KLAPPT NICHT // auf "1" prüfen // Endlosschleife solang PB5 = 0
|
100 | while(0)
|
101 | {
|
102 | MitWert=ADC_Read_Avg(3,64); // Mittelwert, (Eingangs-Kanal (3=ADC3), Mess-Durchläufe)
|
103 |
|
104 | if(MitWert>=OBER_BEREICH) // oberer Messbereich
|
105 | {
|
106 | if(Led==3) // von LED3 erst über LED2 nach LED1
|
107 | {
|
108 | Led_Ein(2); // LED/mid ein, Rest aus + Mindest-Wartezeit
|
109 | Warte(2000); // Mindest-Wartezeit [ms]
|
110 | BATT_ON; //??? nur akt. wenn vorger low
|
111 | Led_Ein(1); // LED/high ein, Rest aus
|
112 | Led=1;
|
113 | }
|
114 | else
|
115 | {
|
116 | Led_Ein(1); // LED/high ein, Rest aus
|
117 | BATT_ON;
|
118 | Led=1;
|
119 | }
|
120 | }
|
121 | else if(MitWert<=UNTER_BEREICH) // unterer Messbereich
|
122 | {
|
123 | if(Led==1) // von LED1 erst über LED2 nach LED3
|
124 | {
|
125 | Led_Ein(2); // LED/mid ein, Rest aus + Mindest-Wartezeit
|
126 | Warte(2000); // Mindest-Wartezeit [ms]
|
127 | BATT_OFF; //??? nur akt. wenn vorger high
|
128 | Led_Ein(3); // LED/low ein, Rest aus
|
129 | Led=3; // LED/low ein, Rest aus
|
130 | }
|
131 | else
|
132 | {
|
133 | Led_Ein(3); // LED/low ein, Rest aus
|
134 | BATT_OFF;
|
135 | Led=3;
|
136 | }
|
137 | }
|
138 | else // mittlerer Messbereich
|
139 | {
|
140 | Led_Ein(2); // LED/mid ein, Rest aus + Mindest-Wartezeit
|
141 | Warte(2000); // Mindest-Wartezeit [ms]
|
142 | Led=2;
|
143 | }
|
144 | Warte(100); // [mSek], Wartezeit bis nächste Messwertauswertung
|
145 | }
|
146 | }
|