/*********************** ATmega328P und 16MHz CPU-Takt *********************** V1.1 - Spannungshysterese zum Schalten des LEDPIN - Atomic Absicherung gegen Verfälschung von uint16_t adc_wert durch etwaige Unterbrechung (warum auch immer) während uint16_t Vergleich durch ISR(ADC_vect) - Ermittlung der ADC-Min-Max-Werte über eine volle 50 Hz Netzperiode - Entprellung der Schaltschwelle V1.0 Pseudocode Messung der Spannung eines 48V LiFePO4-Akkus an seinen Polklemmen mit ATmega328P und 16MHz CPU-Takt Spannungsteiler zur Messung der Batteriespannung: R1 = 100 kOhm, R2 = 1,8 kOhm, C2_block 100 nF ... 10µF zur Glättung Mit ADCref = 1,1V ergibt sich rechnerisch ein Spannungsmessbereich von 0V ... 62,2V. Das sollte mit einem guten Multimeter bei unbelastetem Akku kalibriert werden, bevor UBATTLOW_LIM berechnet wird. Wichtig: ein ADC-Wert = 1023 entspricht dann einer Spannung von rechnerisch 62,14V! Berechnung von UBATTLOW_LIM (z.B. 45V): -> UBATTLOW_LIM = 45V * 1024 / 62,2V = 741 ADC-Inkremente Das Unterschreiten von UBATTLOW_LIM wird durch die LED des Arduino angezeigt */ #include #include #include #include #include #include #include #define UBATTLOW_LIM 741 // ADC-Wert für Abschaltschwelle (ca. 45V) #define UB_HYSTERESE 35 // ADC-Inkremente für Hystereseschwelle (ca. 2V) #define ANZ_ADC_EVAL 192 // Anzahl ADC-Messungen zur Bestimmung der ADC-Min-Max-Werte über eine volle 50 Hz Netzperiode // ANZ_ADC_EVAL = 125000 Hz ADC-Frequenz / 13 ADC-Takte pro ADC-Messung / 50 Hz Netzfrequenz #define ENTPRELL_LIM 100 // Entprellwert für Schaltschwelle #define LED_PIN PB5 // Arduino Uno Pin13 #define LED_PIN_LOW (PORTB &= ~(1< ADC0 //ADC initialisieren ADMUX = (1< adc_wert_max) {// entspricht am ehesten Ubatt unbelastet adc_wert_max = atomic_adc_wert; } } else {// Ende ADC-Min-Max Evaluierungsperiode, ADC-Min-Max-Werte bereit und auswerten, neue Evaluierung beginnen anz_ADC_eval = 0; if (adc_wert_min < UBATTLOW_LIM) // ADC-Min-Wert als Schaltkriterium { entprell_cnt++; if (entprell_cnt >= ENTPRELL_LIM) { LED_PIN_HIGH; // Unterspannungswarnung anzeigen } } else if (adc_wert_min >= UBATTLOW_LIM + UB_HYSTERESE) { LED_PIN_LOW; } else { entprell_cnt = 0; } tmp_adc_min = adc_wert_min; // nur für Ausgabe tmp_adc_max = adc_wert_max; // nur für Ausgabe adc_wert_min = adc_wert_max = atomic_adc_wert; } } if(anz_ADC_eval == 0) {/********* Ausgabe *********/ Serial.print("ADC_min=" ); Serial.print(tmp_adc_min); Serial.print(" ADC_max =" ); Serial.print(tmp_adc_max); Serial.print(" entprell_cnt=" ); Serial.print(entprell_cnt); Serial.print(" LEDPIN =" ); Serial.println(LED_PIN_GET); } } } ISR(ADC_vect) { adc_wert = ADC; adc_wert_bereit = true; anz_ADC_eval++; }