Среди начинающих разработчиков электронной техники популярно создавать амперметр и вольтметр на Ардуино. Эти устройства знакомы с курса физики, начиная с 7 класса.
В статье ниже подробно расписана инструкция о том, как создать собственный вольтметр на Ардуино с LCD дисплеем.
Принцип работы
Вольтметром называют приспособление, роль которого – измерение ЕДС, так называемой, электродвижущей силы. Измерения проводятся на определенном отрезке электрической цепи. Если сказать по-простому, задача прибора – замер напряжения.
Полученное в результате число значится Вольтами. Идеальный вариант устройства – девайс с бесконечным сопротивлением, заключенным внутри, для точного измерения напряжения без дополнительных ненужных воздействий на электрическую цепь.
Компоненты
Список компонентов для создания вольтамперметра на Ардуино или каждого устройства по отдельности:
- 1 Arduino;
- 1 Макет (не забудьте прокладки перемычек);
- 1 Дисплей 1602А (16x2 с подсветкой);
- 1 1x16 отсекают заголовки для фиксации дисплея;
- 1 Зуммер;
- 2 винтовые клеммы с двумя контактами;
- 3 Тактильные переключатели (кнопки);
- 1 потенциометр 10k;
- 6 резисторов 10k;
- 2 резистора 100k;
- 1 резистор 100R;
- 1 резистор 10R;
- 1 0.47R 5W силовой резистор.
Компоненты должны быть собраны в макете следующим образом:
Программа для устройства
Ниже приведен отрывок из листинга программы «вольтметр на Ардуино»:
//version #define NAME "Arduino Ammeter" #define VERSION "0.9" //debug flag (avoid enabling. it makes your device slower) //#define DEBUG //pins const int PIN_BACKLIGHT = 2; const int PIN_BUZZER = 3; const int PIN_VOLTAGE = 1; const int PIN_CURRENT = 2; const int PIN_BUTTON_UP = 11; const int PIN_BUTTON_SETUP =12; const int PIN_BUTTON_DOWN = 13; // includes #include <LiquidCrystal.h> #include <EEPROM.h> // initialize the library with the numbers of the interface pins LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //variables //voltage int VOLTAGE_CURRENT; int VOLTAGE_LAST=99999; unsigned long VOLTAGE_MILLIS; float VOLTAGE_CALCULATED; float VOLTAGE_MAP = 50; //default voltage map... calibration needed //current int CURRENT_CURRENT; int CURRENT_LAST=99999; unsigned long CURRENT_MILLIS; float CURRENT_CALCULATED; float CURRENT_MAP = 10; //default current map... calibration needed //buttons boolean BUTTON_PRESSED = false; unsigned long BUTTON_MILLIS = false; byte BUTTON_LAST; boolean SETUP_MODE = false; byte SETUP_ITEM; boolean SETUP_DELAYBEEP; //... unsigned long MILLIS; unsigned long SETUP_BLINKMILLIS; boolean SETUP_BLINKSTATE; //parameters const int SENSOR_INTERVAL = 500; const int BUTTON_HOLDTIME = 2000; const int SETUP_MAXITEMS = 2; const int SETUP_BLINKINTERVAL = 300; const byte EEPROM_VALIDATOR = 73; //random number const float VOLTAGE_STEP = 0.1; const float CURRENT_STEP = 0.1; //configuration const byte EEPROM_CONFIGADDRESS = 0; struct config_t { byte Validator; ///////////////////// float VOLTAGE_MAP; float CURRENT_MAP; ///////////////////// byte ValidatorX2; } EEPROM_DATA; void setup() { //configure pins pinMode(PIN_BACKLIGHT, OUTPUT); pinMode(PIN_BUZZER, OUTPUT); pinMode(PIN_VOLTAGE, INPUT); pinMode(PIN_CURRENT, INPUT); pinMode(PIN_BUTTON_UP, INPUT); pinMode(PIN_BUTTON_SETUP, INPUT); pinMode(PIN_BUTTON_DOWN, INPUT); //set up LCD lcd.begin(16, 2); //initial message lcd.setCursor(0, 0); lcd.print(NAME); lcd.setCursor(0, 1); lcd.print("Version "); lcd.print(VERSION); //lights up digitalWrite(PIN_BACKLIGHT, HIGH); #ifdef DEBUG delay(2000); lcd.setCursor(0, 1); lcd.print("Debug enabled! "); lcd.print(VERSION); Serial.begin(9600); Serial.println("============================"); Serial.println(NAME); Serial.println("Version "); Serial.println(VERSION); Serial.println("============================"); Serial.println("Debug messages:"); Serial.println("----------------------------"); #endif //try to load the configuration loadConfiguration(); //show initial message for a while then clear and beep delay(2000); lcd.clear(); showLabels(); //beep beepStart(); } void loop() { processButtons(); MILLIS = millis(); if ( (MILLIS - VOLTAGE_MILLIS) >= SENSOR_INTERVAL ) { readVoltage(); if (!SETUP_MODE || SETUP_ITEM!=1) { showVoltage(); } VOLTAGE_MILLIS = MILLIS; } if ( (MILLIS - CURRENT_MILLIS) >= SENSOR_INTERVAL ) { readCurrent(); if (!SETUP_MODE || SETUP_ITEM!=2) { showCURRENT(); } CURRENT_MILLIS = MILLIS; } if (SETUP_MODE) { if ( (MILLIS - SETUP_BLINKMILLIS) >= SETUP_BLINKINTERVAL ) { if (SETUP_BLINKSTATE) { if (SETUP_ITEM==1) showVoltage(); else if (SETUP_ITEM==2) showCURRENT(); SETUP_BLINKSTATE = false; } else { if (SETUP_ITEM==1) hideVoltage(); else if (SETUP_ITEM==2) hideCURRENT(); SETUP_BLINKSTATE = true; } SETUP_BLINKMILLIS = MILLIS; } } } void processButtons() { if (digitalRead(PIN_BUTTON_UP) == HIGH) { if (!BUTTON_PRESSED) { #ifdef DEBUG showDebug("Pressed UP"); #endif BUTTON_LAST = PIN_BUTTON_UP; BUTTON_PRESSED = true; } } else if (digitalRead(PIN_BUTTON_SETUP) == HIGH) { if (!BUTTON_PRESSED) { #ifdef DEBUG showDebug("Pressed SETUP"); #endif beepButton(); BUTTON_LAST = PIN_BUTTON_SETUP; BUTTON_MILLIS = millis(); BUTTON_PRESSED = true; SETUP_DELAYBEEP = false; } else { if ((millis() - BUTTON_MILLIS) > BUTTON_HOLDTIME) if (!SETUP_DELAYBEEP) { beepButton(); SETUP_DELAYBEEP = true; } } } else if (digitalRead(PIN_BUTTON_DOWN) == HIGH) { if (!BUTTON_PRESSED) { #ifdef DEBUG showDebug("Pressed DOWN"); #endif BUTTON_LAST = PIN_BUTTON_DOWN; BUTTON_PRESSED = true; } } else { if (BUTTON_PRESSED) { if (BUTTON_LAST == PIN_BUTTON_SETUP) { #ifdef DEBUG showDebug("Released SETUP"); #endif if (!SETUP_MODE && (millis() - BUTTON_MILLIS) > BUTTON_HOLDTIME) { #ifdef DEBUG showDebug("Entered setup mode!"); #endif lcd.setCursor(0, 1); lcd.print(" Setup Mode "); SETUP_MODE = true; SETUP_ITEM = 1; } else { if (SETUP_ITEM == SETUP_MAXITEMS) { #ifdef DEBUG showDebug("Exited setup mode!"); #endif showLabels(); SETUP_MODE = false; SETUP_ITEM = 0; saveConfiguration(); } else { SETUP_ITEM++; } showVoltage(); showCURRENT(); } } else if (BUTTON_LAST == PIN_BUTTON_UP) { #ifdef DEBUG showDebug("Released UP"); #endif if (SETUP_MODE) { beepButton(); if (SETUP_ITEM==1) { //voltage VOLTAGE_MAP+=VOLTAGE_STEP; readVoltage(); #ifdef DEBUG startDebug("New VOLTAGE_MAP: "); Serial.println(VOLTAGE_MAP,6); #endif } else if (SETUP_ITEM==2) { //current CURRENT_MAP+=CURRENT_STEP; readCurrent(); #ifdef DEBUG startDebug("New CURRENT_MAP: "); Serial.println(CURRENT_MAP,6); #endif } } } else if (BUTTON_LAST == PIN_BUTTON_DOWN) { #ifdef DEBUG showDebug("Released DOWN"); #endif if (SETUP_MODE) { beepButton(); if (SETUP_ITEM==1) { //voltage VOLTAGE_MAP-=VOLTAGE_STEP; readVoltage(); #ifdef DEBUG startDebug("New VOLTAGE_MAP: "); Serial.println(VOLTAGE_MAP,6); #endif } else if (SETUP_ITEM==2) { //current CURRENT_MAP-=CURRENT_STEP; readCurrent(); #ifdef DEBUG startDebug("New CURRENT_MAP: "); Serial.println(CURRENT_MAP,6); #endif } } } BUTTON_PRESSED = false; } } } #ifdef DEBUG void showDebug(char* Message) { Serial.print(millis()); Serial.print(": "); Serial.println(Message); } void startDebug(char* Message) { Serial.print(millis()); Serial.print(": "); Serial.print(Message); } #endif void showLabels() { lcd.setCursor(0, 1); lcd.print("Volts Amps"); } void showVoltage() { lcd.setCursor(0, 0); lcd.print(VOLTAGE_CALCULATED, 2); lcd.print(" V"); if (VOLTAGE_CALCULATED<10) lcd.print(" "); } void hideVoltage() { lcd.setCursor(0, 0); lcd.print(" "); } void showCURRENT() { lcd.setCursor(9, 0); if (CURRENT_CALCULATED<10) lcd.print(" "); lcd.print(CURRENT_CALCULATED, 2); lcd.print(" A"); } void hideCURRENT() { lcd.setCursor(9, 0); lcd.print(" "); } void beepStart() { for (int i=0; i<300; i++) { digitalWrite(PIN_BUZZER, HIGH); delayMicroseconds(200); digitalWrite(PIN_BUZZER, LOW); delayMicroseconds(200); } } void beepButton() { for (int i=0; i<20; i++) { digitalWrite(PIN_BUZZER, HIGH); delayMicroseconds(700); digitalWrite(PIN_BUZZER, LOW); delayMicroseconds(700); } } void readVoltage() { VOLTAGE_CURRENT = analogRead(PIN_VOLTAGE); if ( VOLTAGE_CURRENT != VOLTAGE_LAST || SETUP_MODE ) { VOLTAGE_LAST = VOLTAGE_CURRENT; VOLTAGE_CALCULATED = fmap(VOLTAGE_CURRENT, 0, 1023, 0.0, VOLTAGE_MAP); #ifdef DEBUG if (!SETUP_MODE) { startDebug("New voltage: "); Serial.print(VOLTAGE_CALCULATED); Serial.println("V"); } #endif } } void readCurrent() { CURRENT_CURRENT = analogRead(PIN_CURRENT); if ( CURRENT_CURRENT != CURRENT_LAST || SETUP_MODE ) { CURRENT_LAST = CURRENT_CURRENT; CURRENT_CALCULATED = fmap(CURRENT_CURRENT, 0, 1023, 0.0, CURRENT_MAP); #ifdef DEBUG if (!SETUP_MODE) { startDebug("New current: "); Serial.print(CURRENT_CALCULATED); Serial.println("A"); } #endif } } float fmap(float x, float in_min, float in_max, float out_min, float out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } int EEPROM_writeConf() { byte Address = EEPROM_CONFIGADDRESS; const byte* p = (const byte*)(const void*)&EEPROM_DATA; int i; for (i = 0; i < sizeof(EEPROM_DATA); i++) EEPROM.write(Address++, *p++); return i; } int EEPROM_readConf() { byte Address = EEPROM_CONFIGADDRESS; byte* p = (byte*)(void*)&EEPROM_DATA; int i; for (i = 0; i < sizeof(EEPROM_DATA); i++) *p++ = EEPROM.read(Address++); return i; } void loadConfiguration() { //read data from eeprom EEPROM_readConf(); //verify validators if (EEPROM_DATA.Validator == EEPROM_VALIDATOR && EEPROM_DATA.ValidatorX2 == EEPROM_VALIDATOR*2) { //copy data VOLTAGE_MAP = EEPROM_DATA.VOLTAGE_MAP; CURRENT_MAP = EEPROM_DATA.CURRENT_MAP; #ifdef DEBUG showDebug("Configuration loaded from EEPROM!"); startDebug(" VOLTAGE_MAP: "); Serial.println(VOLTAGE_MAP,6); startDebug(" CURRENT_MAP: "); Serial.println(CURRENT_MAP,6); #endif } else { #ifdef DEBUG showDebug("Configuration NOT loaded from EEPROM!"); #endif } } void saveConfiguration() { if ( EEPROM_DATA.VOLTAGE_MAP != VOLTAGE_MAP || EEPROM_DATA.CURRENT_MAP != CURRENT_MAP ) { //copy validators EEPROM_DATA.Validator = EEPROM_VALIDATOR; EEPROM_DATA.ValidatorX2 = EEPROM_VALIDATOR*2; //copy data EEPROM_DATA.VOLTAGE_MAP = VOLTAGE_MAP; EEPROM_DATA.CURRENT_MAP = CURRENT_MAP; //save data to eeprom EEPROM_writeConf(); #ifdef DEBUG showDebug("Configuration saved!"); #endif } else { #ifdef DEBUG showDebug("Configuration not changed!"); #endif } }
Настройка
В основном, требования к запуску проекта «вольтметр на Arduino» на независимой печатной плате – это источник питания 5 В, 16-мегагерцовый кварцевый генератор и, конечно же, связанные выводы микроконтроллера со всеми цифровыми и аналоговыми портами платы Arduino. Диаграмма ниже популярна в Интернете и объясняет, как нужно использовать схему для работы в качестве прототипа.
Новые компоненты, которые необходимо добавить в прототип для работы на печатной плате:
- 1 28-контактный паяльник для пайки (для микроконтроллера Atmega);
- 1 разъем питания для печатной платы;
- 1 регулятор LM78L05;
- 1 1uf конденсатор;
- 1 конденсатор 10футов;
- 1 кварцевый генератор 16 МГц;
С новыми компонентами и выводом микроконтроллера имеем следующую схему проекта «Ардуино-вольтметр»:
Еще на просторах Интернета можно найти такую схему вольтметра:
Благодаря схематическому дизайну можно выполнить проверку дорожек для построения схемы. После размещения всех устройств на плате, чтобы облегчить их подключение, необходимо вручную написать раскладку дорожек, поскольку функции автоматической маршрутизации обычно не выполняют свою работу до конца.
Проверка работоспособности
Для калибровки используются 3 кнопки. Центральная кнопка является конфигурационной и активирует режим калибровки, если нажата в течение 2 секунд, а также подтверждена звуковым сигналом.
Остальные кнопки – слева и справа, должны уменьшать и увеличивать калибровку соответственно, за чем следует один звуковой сигнал. Калибровка начинается с напряжения, затем, при нажатии кнопки конфигурации, снова переключается на ток, а при повторном нажатии сохраняет конфигурацию в EEPROM и возвращает устройство в нормальный режим.
Как повысить точность измерения
Для повышения точности созданного устройства потребуется провести эксперимент. Первое значение получаем от вольтметра на Ардуино с выводом на ПК, вторую – с помощью необходимой функции. Поменяем константу (1.1 * 1023.0 * 1000) на усовершенствованную:
scales_constants = internal1s.1Refs * 1023 * 1000
Первый множитель означает – 1.1 * Vcc1 (с вольтметром) / Vcc2 (с нашей функцией).
В итоге получаем погрешность. Затем, путем подсчета, выходим на настоящие значение напряжения в электрической сети. Предел измерений показаний на Ардуино устройства варьируется между 0 и 50 Вольтами.