Обнуление показания тока при нажатии на кнопку (ACS712)
- Войдите на сайт для отправки комментариев
Здравствуйте, знатаки, помогите пожалуйста. Сделал достаточно точный Ваттметр с использованием 2-х датчиков ACS712 и ADS1115, всё налажено и показывает ток очень точно, но не в этом суть. К примеру, готовый прибор лёжа в корпусе на столе возле компа где занимался отладкой показаний датчиков, при отключенной нагрузке показания на дисплее равны нулю как и должно быть, а стоит мне отодвинуть на метр прибор, нулевые показания либо повышаются на 20-30mA, либо идут в минус (ну это нормально для этих датчиков, из-за воздействия внешних магнитных полей).
Так вот в чём нужна помощь, хочу сделать так: в местах где буду использовать прибор для измерения тока и т.д. сделать обычную тактовую кнопку, при коротком нажатии на которую просто произойдёт обнуление показаний (именно в том месте где будет лежать прибор) и измерения будут происходить от обнуления.
По сути нужно тоже самое, как Обнуление ТАРЫ в обычных весах.
Не могу понять как реализовать такую возможность программно. В инете что-то не смог найти то, что нужно или как это реализовать.
Помогите пожалуйста куском кода - как образец (как это реализеется с объяснением).
P.S. подключить кнопку и как её считать false или true - это без проблем. а как сделать значение Current с выводом показаний с учётом обнуления не знаю.
Если нужно, полностью рабочий код под спойлером:
/****************************************** Ваттметр с ЖК-дисплеем v.3.0 Июнь 2019 ------------------------------------------- Железо: - Arduino Pro mini - 16-bit ADC модуль на основе ADS1115 - LCD дисплей 1602 по шине I2C - 2 датчика тока ACS712 на 20 Ампер ------------------------------------------- Возможности (КРАТКОВРЕМЕННЫЕ, максимальные): - Измерение Напряжения до 32V - Измерение Тока до 20A - Измерение Мощности до 640W - Измерение залитой ёмкости через Ваттметр до 9999Ah ******************************************/ //Подключаем библиотеки #include <Wire.h> #include <Adafruit_ADS1015.h> //#include <LiquidCrystal_I2C.h> //Библиотека Дисплея (закомментировал, так как использую аналогичную библиотеку с Русскими буквами) #include <LCD_1602_RUS.h> //Библиотека Дисплея "LiquidCrystal_I2C", только с Русскими буквами #include <SPI.h> #include <SmartDelay.h> // Библиотека для ожидания без Delay() //--НАСТРОЙКА КОМПЕНСАЦИЙ И ЧУВСТВИТЕЛЬНОСТИ--// #define voltageZeroCorrection -0.055 //Компенсирует смещение нулевой точки в канале ADC0 #define currentZeroCorrection -0.0697 //Компенсирует разницу нулевых точек между двумя модулями ACS712 #define voltageSensitivity 0.12486 //Чувствительность ADS1115 = 0.125 для GAIN_ONE (подробности смотрите в datasheet ADS1115) #define currentSensitivity 0.20375 //Чувствительность двух ACS712 (датчики подключены в противоположном направлении) #define NOISE_SUPPRESSOR 1 //Шумоподавление (Прокомментируйте эту строку, чтобы отключить шумоподавитель) //--ЗАДАЁМ I2C АДРЕСА МОДУЛЕЙ--// #define ADC_I2C_ADDR 0x48 //Аналого-цифровой преобразователь адреса I2C = 72 #define DSP_I2C_ADDR 0x3F //Дисплей LCD1602 I2C адрес = 63 //--ОБЪЕКТЫ--// Adafruit_ADS1115 ads(ADC_I2C_ADDR); //ADC (АЦП) объект //LiquidCrystal_I2C lcd(DSP_I2C_ADDR, 16, 2); //Дисплейный объект: 16 символов подряд, 2 строки LCD_1602_RUS lcd(DSP_I2C_ADDR, 16, 2); //Тоже самое, что и "LiquidCrystal_I2C", только с выводом Русских букв SmartDelay AntiDelay(150000UL); //Ожидание в Микросекундах. Задаём интервал в 150 миллисекунд. Простое ожидание без задержки //--ПЕРЕМЕННЫЕ ДЛЯ ИЗМЕРЕНИЯ ТОКА И НАПРЯЖЕНИЯ--// float Voltage = 0.0; //Результат измерения напряжения float Current = 0.0; //Результат измерения тока float Watt = 0.0; //Результат измерения мощности float Capacity = 0.0; //Начальная ёмкость в Ah unsigned long prevMillis; //Переменная таймера используются для расчёта измерителя ёмкости //------ Возвращать результаты как среднее из <итераций> образцов напряжения ------ // 1-й аргумент - номер канала ADC (АЦП) (0 - канал напряжения, 1 и 2 - токовые каналы) // 2-й аргумент - коэффициент деления входного напряжения (5 - канал напряжения, 1 - канал тока) // 3-й аргумент - количество итераций (повторите измерение для <итераций> раз и верните среднее значение) float measureSingleEnded(uint8_t channel, uint8_t divider, uint8_t iterations) { int16_t adc; //16-разрядное целое число, полученное из ADC (АЦП) long accum = 0; //сумма <итераций> измерений из <итераций> измерения for (int i = 0; i < iterations; i++) { adc = ads.readADC_SingleEnded(channel); //Присваиваем переменной adc значения из channel accum += adc; } /* Voltage = accum * divider * voltageSensitivity / 1000 / iterations (Так происходит расчёт измерения Напряжения) где: accum - сумма измерений накопленная а accum divider - коэффициент деления входного напряжения voltageSensitivity - 0.1875 for GAIN_TWOTHIRDS(усиление две третих); 0.125 for GAIN_ONE(однократное усиление); 0.0625 for GAIN_TWO(2-х кратное усиление) (подробности смотрите в datasheet ADS115) 1000 - преобразование mV в V iterations - количество измерений для усреднения */ return accum * divider * voltageSensitivity / 1000 / iterations; } //--ИЗМЕРЕНИЕ НАПРЯЖЕНИЯ И ТОКА И ВЫВОД РЕЗУЛЬТАТА НА ДИСПЛЕЙ--// void measure(void) { //++++ измерение напряжения ++++ // Канал 0, коэффициент входного делителя = 8, среднее из 10 итераций // добавление коррекции для компенсации смещения нулевой точки входа ADC (АЦП) Voltage = measureSingleEnded(0, 8, 10) + voltageZeroCorrection; // сократить отрицательные значения Voltage = (Voltage > 0) ? Voltage : 0; //++++ измерение тока ++++ // Канал 1 и 2, без делителя, в среднем 10 итераций float Chan1 = measureSingleEnded(1, 1, 10); float Chan2 = measureSingleEnded(2, 1, 10); // Рассчитать значения для коррекции и компенсации нулевой разницы двух модулей ACS712 Current = (Chan1 - Chan2) / currentSensitivity + currentZeroCorrection; //++++ вычисление мощности ++++ Watt = Voltage * Current; // Расчёт Мощности нагрузки в Реальном времени. //++++ вычисление залитой ёмкости ++++ Capacity += (Current * (millis() - prevMillis) / 3600000); //расчёт залитой ёмкости в Ампер-Часах (Ач) через Ваттметр prevMillis = millis(); #ifdef NOISE_SUPPRESSOR //++++ обрабатывать значения напряжения менее 5мВ как ноль для подавления шума вблизи нуля ++++ if (Voltage < 0.005) { Voltage = 0; } //++++ обрабатывать значения тока менее 20мА как ноль для подавления шума вблизи нуля ++++ if (abs(Current) < 0.020) { Current = 0; } //++++ обрабатывать значения мощности менее 21мВт как ноль для подавления шума вблизи нуля ++++ if (abs(Watt) < 0.021) { Watt = 0; } #endif //++++ Вывод НАПРЯЖЕНИЯ на Дисплей ++++ lcd.setCursor(2, 0); //Устанавливаем курсор в позицию (на 2 колонку 1-й строки) lcd.print(" "); //выводим на дисплей пробелы (что бы очищалась колонка после увеличения напряжения до 10V и более и дальнейшего его снижения менее 10V)) if (Voltage >= 10.0) { //Если напряжение с переменной "Voltage" больше или равно 10, то... lcd.setCursor(2, 0); //... устанавливаем курсор на (2 колонку 1-й строки) } else { //Иначе... lcd.setCursor(3, 0); //Переводим курсор на (3 колонка 1-й строки) } lcd.print(Voltage, 2); //выводим на дисплей значение переменной "Voltage" с 2-ми знаками после запятой. //++++ Вывод ТОКА на Дисплей ++++ lcd.setCursor(2, 1); //Устанавливаем курсор в позицию (на 2 колонку 2-й строки) lcd.print(" "); //выводим на дисплей пробелы (что бы очищалась колонка после увеличения тока до 10A и более и дальнейшего его снижения менее 10А) if (Current < 0) { //Если ток с переменной "Current" меньше нуля, то... lcd.setCursor(2, 1); //... устанавливаем курсор на (2 колонку 2-й строки) } else { //Иначе... lcd.setCursor(3, 1); //Переводим курсор на (3 колонка 2-й строки) } lcd.print(Current, 2); //выводим на дисплей значение переменной "Current" с 2-ми знаками после запятой. //++++ Вывод МОЩНОСТИ на Дисплей ++++ lcd.setCursor(10, 0); //Устанавливаем курсор в позицию (на 10 колонку 1-й строки) lcd.print(" "); //выводим на дисплей пробелы (что бы очищалась колонка после увеличения мощности до 10W и более и дальнейшего его снижения менее 10W)) if (Watt >= 10.0) { //Если мощность с переменной "Watt" больше или равно 10W, то... lcd.setCursor(10, 0); //... устанавливаем курсор на (10 колонку 1-й строки) } else { //Иначе... lcd.setCursor(11, 0); //Переводим курсор на (11 колонку 1-й строки) } lcd.print(Watt, 2); //выводим на дисплей значение переменной "Watt" с 2-ми знаками после запятой. //++++ Вывод залитой ЁМКОСТИ через Ваттметр на Дисплей ++++ lcd.setCursor(11, 1); //Переводим курсор на (11 колонку 2-й строки) lcd.print(Capacity, 3); //выводим на дисплей значение переменной "Capacity" с 3-ми знаками после запятой. } //--ОТОБРАЖЕНИЕ СТАТИЧЕСКИХ СИМВОЛОВ В ЗАВИСИМОСТИ ОТ РЕЖИМА--// void setDisplayMode() { lcd.clear(); //Очистить дисплей lcd.setCursor(0, 0); //Переместить курсор на 1 строку и 1 символ lcd.print("U:"); //Показать букву "U:" (Напряжение) lcd.setCursor(0, 1); //Переместить курсор на 2 строку и 1 символ lcd.print("I:"); //Показать букву "I:" (Ток) lcd.setCursor(8, 0); //Переместить курсор на 1 строку и 8 символ lcd.print("W:"); //Показать букву "W:" (Мощность) lcd.setCursor(8, 1); //Переместить курсор на 1 строку и 8 символ lcd.print("Ah:"); //Показать букву "Ah:" (Ёмкость) lcd.noBlink(); //Отключить мигание курсора } //******************************* // ИНИЦИАЛИЗАЦИЯ //******************************* void setup(void) { // инициализировать модуль ADC (АЦП) ads.begin(); ads.setGain(GAIN_ONE); //4.096V полная величина Спектра // инициализировать LCD Дисплей lcd.begin(); lcd.backlight(); // выводим надпись на Дисплей перед загрузкой кода lcd.setCursor(0, 0); lcd.print(" Ваттметр Otto"); lcd.setCursor(5, 1); lcd.print("4 в 1"); delay(2500); // подготовить экран setDisplayMode(); } //******************************** // ОСНОВНОЙ ЦИКЛ ПРОГРАММЫ //******************************** void loop(void) { if (AntiDelay.Now()) { // Обновление данных на дисплее раз в 150 миллисекунд без задержки. measure(); //Измеряет напряжение,ток, мощность и ёмкость в Ah и отображает результаты на дисплее. } }
Вам нужна установка нуля, так? Ну
1. заведите переменную "поправка".
2. показывайте всегда не ток, который Вы считали с датчика, а "считанный ток" минус "поправка".
3. изначально переменная "поправка" равна 0 (т.е. показывается то, что считали с датчика).
4. в момент нажатия кнопки считывайте ток и считанное значение присвойте переменной "поправка".
Прибор тут же начнёт показывать 0 (см п.2 выше). И впредь (до нового нажатия кнопки или включения питания) будет показывать результаты с запомненной поправкой.
Это то, что нужно?
добавлю к сообщению Евгения
То, что он написал - надо сделать и для тока и для напряжения.
И еще полезно по этой же кнопке обнулять сумму емкости, которую вы там в подсчитываете
ЕвгенийП и b707, спасибо вам большое за пояснения. Написал код как вы сказали, работает так как я и задумал.
Завтра выложу готовый код, может кто захочет повторить проект или кому пригодятся куски кода.
Выкладываю рабочий код + Схема
Код:
Пару фоток готового Устройства в коробочке от Мыльницы.
Начинка:
Готовое устройство:
Проверка заряда по нажатию кнопки сделал на компораторе LM339N и 4-х светодиодах (просто заранее готовый валялся уже), но можно сделать это через свободные аналоговые порты Ардуинки или свободный pin ADS1115.
блоки просто лежат в коробочке и никак не закреплены?
Нет конечно. Всё достаточно крепко на термоклей закреплено, а провода "мёртво" большим количеством залиты супер клеем во много слоёв.ничего не болтается, даже если сильно трясти (чего не будет происходить) :)
Просто достаточно аккуратно делать старался, хоть и видно в дальнейшем не будет)
у каждого свои понятия о аккуратности :)
Я стараюсь все блоки крепить на плату, а уже плату - в корпус. И выглядит прилично, и любую деталь легко заменить, не отдирая сопли клея
даже когда это просто макетка для тестов (кликабельно, сорри за качество - фотографировалось на телефон при низком освещении)
b707, главное - такой открытый SPI не параллелить с чем-то ещё. А то я как-то сдурил - решил устройство с Ethernet шить через SPI и вывесил контакты. Так девайс меня потом с ума свёл - когда хотел, тогда сетевой модуль и "терял".
b707, главное - такой открытый SPI не параллелить с чем-то ещё. А то я как-то сдурил - решил устройство с Ethernet шить через SPI и вывесил контакты. Так девайс меня потом с ума свёл - когда хотел, тогда сетевой модуль и "терял".
в этом случае можно предложить соединять Ethernet разъемом на эти самые штырьки :) - тогда при прошивке волей-неволей будешь отключать модуль и проблем не будет
Otto
Здравствуйте!
В скрипте Вами предоставленном на 88 строке выдает ошибку: exit status 1
Спасибо!
Otto
Здравствуйте!
В скрипте Вами предоставленном на 88 строке выдает ошибку: exit status 1
Спасибо!
Очевидно, в 88-й строке и исправлять.
Otto
Здравствуйте!
В скрипте Вами предоставленном на 88 строке выдает ошибку: exit status 1
Спасибо!
в скрипте Отто такой ошибки в 88 строке нет.
Очевидно, что вы неправильно скопировали код. Скорее всего , взяли код не как текст. а как HTML. вот у вас и лезет при компиляции всякая ерунда.
Здравствуйте!
Спасибо за ответ, скрипт копировал через Блокнот как текст. Скриншот ошибки прилагаю. Я пока не силен в скриптах, по сему прошу помощи.
Вы всерьез думаете, что на этом скриншоте что-то можно разобрать?
Описание ошибки нужно вставлять текстом и полностью. А перед этим обязательно по правилам форума вставить скетч, который ведет к этой ошибке. Не ссылку, а именно сам скетч.
Вот код. Он взят из сообщения Otto #4.
Привет. Вот ссылка на проект. Сразу не подумал выложить дополнительные библиотеки. Попробуйте с ними. К тому же по ссылке можете скачать *.ino файлик.
https://sysfile.sytes.net/index.php/s/GBLyut4v3TJKgN0
Здравствуйте!
Спасибо за ответ, скрипт копировал через Блокнот как текст. Скриншот ошибки прилагаю. Я пока не силен в скриптах, по сему прошу помощи.
У вас же скопирован код криво.... с порядковыми номерами, ещё бы он не скомпилировался :)
Я пока не силен в скриптах, по сему прошу помощи.
насколько надо быть "не силеным" в скриптах, чтобы скопировать код с номерами строк и пытаться его компилировать? - голову включайте хоть чуть-чуть!
Нафига вообще браться за ардуину, если в программировании ноль?. Какой смысл тупо повторять чужое, как попугай?
Вот код. Он взят из сообщения Otto #4.
Ну, собственно, я не ошибся, попросив Вас выложить код, который Вы пытаетесь компилировать.
Вы сами то разницу между тем, что было в сообщении Отто, и тем, что выложили Вы, видите?
Когда наводите курсор на область кода, в верхнем правом углу появляется небольшая панель инструментов. Надо нажать на самую левую кнопку "<>", откроется дополнительное окно. Вот из него и надо копировать.
Спасибо! Обложили ху...ми, обос...ли. Как всегда от профессионалов..., получил по полной. Чем мне заниматься и чем не заниматься это не Ваше дело.
Отто СПАСИБО!!! Вечером попробую с Вашими библиотеками и кодами.
Здравствуйте!
Спасибо!!! Вечером попробую.
Чем мне заниматься и чем не заниматься это не Ваше дело.
дело, конечно, ваше... но если не научитесь понимать написанное - все равно ни хера не выйдет
Отто еще раз огромное спасибо!!!
Я вот только немножко поправил скетч:
lcd begin заменил на lcd init.
При begin не проходила успешно компиляция.
Вечером прикручу к Ардуинке периферию и посмотрю результаты практической работы Вашего устройства.
Еще раз Вам СПАСИБО!!!
73! RX6KR Yuriy
Я вот только немножко поправил скетч:
lcd begin заменил на lcd init.
значит не ту библиотеку для экрана взяли
Если нужно, можете скачать библиотеки по ссылке