Обнуление показания тока при нажатии на кнопку (ACS712)

Otto
Offline
Зарегистрирован: 26.06.2016

Здравствуйте, знатаки, помогите пожалуйста. Сделал достаточно точный Ваттметр с использованием 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 и отображает результаты на дисплее.
  }

}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вам нужна установка нуля, так? Ну 

1. заведите переменную "поправка".
2. показывайте всегда не ток, который Вы считали с датчика, а "считанный ток" минус "поправка".
3. изначально переменная "поправка" равна 0 (т.е. показывается то, что считали с датчика).
4. в момент нажатия кнопки считывайте ток и считанное значение присвойте переменной "поправка".

Прибор тут же начнёт показывать 0 (см п.2 выше). И впредь (до нового нажатия кнопки или включения питания) будет показывать результаты с запомненной поправкой.

Это то, что нужно?

b707
Онлайн
Зарегистрирован: 26.05.2017

добавлю к сообщению Евгения

То, что он написал - надо сделать и для тока и для напряжения.

И еще полезно по этой же кнопке обнулять сумму емкости, которую вы там в подсчитываете

Otto
Offline
Зарегистрирован: 26.06.2016

ЕвгенийП и b707, спасибо вам большое за пояснения. Написал код как вы сказали, работает так как я и задумал.
Завтра выложу готовый код, может кто захочет повторить проект или кому пригодятся куски кода.

Otto
Offline
Зарегистрирован: 26.06.2016

Выкладываю рабочий код + Схема

 

Код:

/******************************************
    Ваттметр с ЖК-дисплеем
       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   //Шумоподавление (Прокомментируйте эту строку, чтобы отключить шумоподавитель)
#define RESET_BUTTON 8       //Кнопка для обнуления напряжения, тока и ёмкости (подключена на pin 8)

//--ЗАДАЁМ 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 AntiDelayLoop(150000UL); //Ожидание в Микросекундах. Задаём интервал в 150 миллисекунд. Простое ожидание без задержки для цикла "loop"


//--ПЕРЕМЕННЫЕ ДЛЯ ИЗМЕРЕНИЯ ТОКА И НАПРЯЖЕНИЯ--//
float PrimaryVoltage = 0.0;    //Первичный (до обнуления) результат измерения напряжения
float AmendmentVoltage = 0.0;  //Поправочная переменная для вычета погрешности из напряжения перед измерением (для обнуления)
float Voltage = 0.0;           //Результат измерения напряжения

float PrimaryCurrent = 0.0;    //Первичный (до обнуления) результат измерения тока
float AmendmentCurrent = 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;
  }
  /*  PrimaryVoltage = 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 (АЦП)
  PrimaryVoltage = measureSingleEnded(0, 8, 10) + voltageZeroCorrection;
  // сократить отрицательные значения
  PrimaryVoltage = (PrimaryVoltage > 0) ? PrimaryVoltage : 0;


  //++++ измерение тока ++++
  // Канал 1 и 2, без делителя, в среднем 10 итераций
  float Chan1 = measureSingleEnded(1, 1, 10);
  float Chan2 = measureSingleEnded(2, 1, 10);
  // Рассчитать значения для коррекции и компенсации нулевой разницы двух модулей ACS712
  PrimaryCurrent = (Chan1 - Chan2) / currentSensitivity + currentZeroCorrection;


  //++++ сброс тока, напряжения и ёмкости в ноль перед началом измерений (при коротком нажатии кнопки) ++++
  Voltage = PrimaryVoltage - AmendmentVoltage;  //"считанный первичное напряжение" минус "поправка напряжения" (изначально "AmendmentVoltage" равен нулю и результат "Voltage" не изменится)
  Current = PrimaryCurrent - AmendmentCurrent;  //"считанный первичный ток" минус "поправка тока" (изначально "AmendmentCurrent" равен нулю и результат "Current" не изменится)

  if (digitalRead (RESET_BUTTON) == !HIGH) {    //читаем состояние кнопки (стоит инверсия, т.к. включён "INPUT_PULLUP"), если она нажата, то...
    AmendmentVoltage = PrimaryVoltage;  //первичное напряжение присваиваем переменной "поправка напряжения", и так же...
    AmendmentCurrent = PrimaryCurrent;  //первичный ток присваиваем переменной "поправка тока"
    Capacity = 0.0; //и ещё обнуляем показания залитой ёмкости через Ваттметр (если это Вам ненужно по какой либо причине, то просто закомментируйте эту строку и ёмкость обнулятся не будет)
  }


  //++++ вычисление мощности ++++
  Watt = Voltage * Current;   // Расчёт Мощности нагрузки в Реальном времени.


  //++++ вычисление залитой ёмкости ++++
  Capacity += (Current * (millis() - prevMillis) / 3600000);  //расчёт залитой ёмкости в Ампер-Часах (Ач) через Ваттметр
  prevMillis = millis();



#ifdef NOISE_SUPPRESSOR
  //++++ обрабатывать значения напряжения менее 5мВ как ноль для подавления шума вблизи нуля ++++
  if (Voltage < 0.005) {
    Voltage = 0;
  }

  //++++ обрабатывать значения тока менее 15мА как ноль для подавления шума вблизи нуля ++++
  if (abs(Current) < 0.015) {
    Current = 0;
  }

  //++++ обрабатывать значения мощности менее 15мВт как ноль для подавления шума вблизи нуля ++++
  if (abs(Watt) < 0.015) {
    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) {
  //Назначаем нашу кнопку как выход с подтягивающим резистором от Arduino
  pinMode(RESET_BUTTON, INPUT_PULLUP);

  // инициализировать модуль 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 (AntiDelayLoop.Now()) {   // Обновление данных на дисплее раз в 150 миллисекунд без задержки.
    measure();  //Измеряет напряжение,ток, мощность и ёмкость в Ah и отображает результаты на дисплее.
  }

}

 

Otto
Offline
Зарегистрирован: 26.06.2016

Пару фоток готового Устройства в коробочке от Мыльницы.

Начинка:

Начинка устройства

Готовое устройство:

Проверка заряда по нажатию кнопки сделал на компораторе LM339N и 4-х светодиодах (просто заранее готовый валялся уже), но можно сделать это через свободные аналоговые порты Ардуинки или свободный pin ADS1115.

b707
Онлайн
Зарегистрирован: 26.05.2017

блоки просто лежат в коробочке и никак не закреплены?

Otto
Offline
Зарегистрирован: 26.06.2016

Нет конечно. Всё достаточно крепко на термоклей закреплено, а провода "мёртво" большим количеством залиты супер клеем во много слоёв.ничего не болтается, даже если сильно трясти (чего не будет происходить) :)

Otto
Offline
Зарегистрирован: 26.06.2016

Просто достаточно аккуратно делать старался, хоть и видно в дальнейшем не будет)

b707
Онлайн
Зарегистрирован: 26.05.2017

Otto пишет:
Просто достаточно аккуратно делать старался, хоть и видно в дальнейшем не будет)

у каждого свои понятия о аккуратности :)

Я стараюсь все блоки крепить на плату, а уже плату - в корпус. И выглядит прилично, и любую деталь легко заменить, не отдирая сопли клея

даже когда это просто макетка для тестов (кликабельно, сорри за качество - фотографировалось на телефон при низком освещении)

sadman41
Offline
Зарегистрирован: 19.10.2016

b707, главное - такой открытый SPI не параллелить с чем-то ещё. А то я как-то сдурил - решил устройство с Ethernet шить через SPI и вывесил контакты. Так девайс меня потом с ума свёл - когда хотел, тогда сетевой модуль и "терял". 

b707
Онлайн
Зарегистрирован: 26.05.2017

sadman41 пишет:

b707, главное - такой открытый SPI не параллелить с чем-то ещё. А то я как-то сдурил - решил устройство с Ethernet шить через SPI и вывесил контакты. Так девайс меня потом с ума свёл - когда хотел, тогда сетевой модуль и "терял". 

в этом случае можно предложить соединять Ethernet разъемом на эти самые штырьки :) - тогда при прошивке волей-неволей будешь отключать модуль и проблем не будет