Radio Life - Вольтметр постоянного тока на Arduino

Программа вольтметра постоянного тока
Версия 01.008b


// ================================================================ // подключаем стандартную библиотеку LiquidCrystal #include <LiquidCrystal.h> #define TITLE "Multimeter" #define R2 220.0 // резисторы входного делителя #define R3 10000.0 // в омах // Ячейки, используемые АЦП // float ADC_Kadc; float ADC_Vref; float ADC_Vin; float ADC_Vmax; float ADC_Vmid; float ADC_Vsum; int ADC_count; volatile int ADC_result; // Ячейки, используемые WDT_intr // volatile int WDT_count; // Слово состояния программы volatile unsigned int SYS_status; #define SYS_STARTRDY 0x8000 #define SYS_SCREENRDY 0x4000 #define SYS_ADCRDY 0x2000 #define SYS_VOLTMETER 0x0004 // инициализируем объект-экран, передаём использованные // для подключения контакты на Arduino в порядке: // RS, E, DB4, DB5, DB6, DB7 // LiquidCrystal lcd(12, 11, 7, 6, 5, 4); char s[16]; char adc[16]; char Ver[] = "01.008b"; void setup() { SYS_status = 0; pinMode(LED_BUILTIN, OUTPUT); // настройка светодиода индикации PrintTitle(); cli(); // запрещаем прерывания перед настройкой SetWatchdogTimer(); SetADC(); sei(); // разрешаем прерывания после настройки WDT_count = 0; ADC_Vmax = 0; ADC_Vmid = 0; ADC_count = 0; SYS_status |= SYS_VOLTMETER; } void loop() { // тайм-аут на 3 секунды на заставку if((SYS_status & SYS_STARTRDY) == 0) { if(WDT_count > 6) { SYS_status |= SYS_STARTRDY; WDT_count = 0; lcd.clear(); } } // тайм-аут прошел, можно выполнять программу else { // работа в режиме вольтметра if((SYS_status & SYS_VOLTMETER) != 0) { // выводим на экран статическую информацию if((SYS_status & SYS_SCREENRDY) == 0) { lcd.setCursor(0, 0); lcd.print(" Vin = V"); lcd.setCursor(0, 1); lcd.print(" Vmax = V"); SYS_status |= SYS_SCREENRDY; } // экран готов, можно выводить данные else { if((SYS_status & SYS_ADCRDY) != 0) { ADC_Vin = (ADC_Kadc * ADC_result) / 1000; if(ADC_Vin > ADC_Vmax) ADC_Vmax = ADC_Vin; // расчет среднего напряжения if(ADC_count > 1000) { // Если число отсчетов больше 1000, то производится сброс среднего значения ADC_Vmid = 0; ADC_Vsum = 0; ADC_count = 0; } ADC_count++; ADC_Vsum += ADC_Vin; ADC_Vmid = ADC_Vsum / ADC_count; dtostrf(ADC_Vin, 7, 3, adc); lcd.setCursor(7, 0); lcd.print(adc); dtostrf(ADC_Vmax, 7, 3, adc); lcd.setCursor(7, 1); lcd.print(adc); SYS_status &= ~SYS_ADCRDY; } } } } } // Подпрограмма печати заголовка программы // ======================================= void PrintTitle() { lcd.begin(16, 2); lcd.print(TITLE); // печатаем первую строку на дисплее lcd.setCursor(0, 1); sprintf(s, "Version %s", Ver); lcd.print(s); // печатаем вторую строку на дисплее } // Подпрограмма настройки прерываний сторожевого таймера // ===================================================== void SetWatchdogTimer() { // Настройка сторожевого таймера 0.5 sec // WDTCSR = (1 << WDCE) | (1 << WDE); // необходимо для изменения делителя таймера WDTCSR = (0 << WDP3) | (1 << WDP2) | (0 << WDP1) | (1 << WDP0);// установка делителя 0,5 сек. WDTCSR |= (1 << WDIE); // разрешение прерываний таймера } // Подпрограмма установки режимов АЦП // ================================== void SetADC() { // Настройка делителя входного напряжения АЦП ADC_Vref = 1100; ADC_Kadc = (ADC_Vref * (R2 + R3)) / (1024 * R2); // Установка опорного напряжения 1.1 В. и входа А0 // Устанавливаем только те биты, которые должны быть установлены в "1" ADMUX = (1 << REFS0) | (1 << REFS1); // Установка частоты преобразования // делитель на 128 ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS2) | (1 << ADPS1) |(1 << ADPS0); } // Программа обработки прерывания сторожевого таймера // 1. Обрабатывает светодиод // 2. Обрабатывает запуск АЦП // ================================================== ISR(WDT_vect) { // мигаем светодиодом раз в секунду // digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN)); WDT_count++; // увеличиваем счетчик таймера // В режиме вольтметра запускаем АЦП if((SYS_status & SYS_VOLTMETER) != 0 & (SYS_status & SYS_ADCRDY) == 0) ADCSRA |= (1 << ADSC); } // Программа обработки прерывания АЦП // ================================== ISR(ADC_vect) { SYS_status |= SYS_ADCRDY; // установка флага готовности данных АЦП ADC_result = ADCL; // сохраняем младший байт результата АЦП ADC_result += ADCH << 8; // сохраняем старший байт АЦП }