Если вы очень переживаете за расход электро энергии и жуть как хочется вычислить виновника - это ваш день. Мы соберем датчик тока напишем простую логику для обработки входных значений для пересчета значений в киловаты/ч.

Для сборки я использовал плату Arduino nano (никто не мешаем вам использовать тот же код для ESP или STM плат), LCD экранный шилд, резистор на 56 Ом, резисторы 100 кОм, конденсатор 10 мКф, датчик тока CT - Talema AC103 (с номинальным измерением 30A и максимальным 75A).

Что такое датчик тока?


Датчик тока - это магнитопровод с зазором и обмоткой компенсации, а так же встроенный датчик Холла и плата управления. Датчик Холла размещается в зазоре магнитопровода и реагирует на создаваемое катушкой магнитное поле. Чем сильнее напряженность магнитного поля, тем сильнее датчик Холла подает сигнал, который усиливается платой управления.
Датчики тока бывают для измерения переменного тока и постоянного тока. Наш - CT-Talema AC103 - для переменного.

Соберем наше устройство согласно схеме:


LCD шилд уже имеет выводы для подключения наших аналоговых портов для измерения сигнала - и это удобно.
Через датчик тока нужно пропустить единственный вводной кабель фазы т.к. на нулевой провод зачастую приходит не все напряжение - часть может уходить через заземление.


Не забываем, что нам нужно выполнить калибровку нагрузочного резистора R3. Формула расчета R = V / I - R = 2,5 / 0,042 = 59,5 Ом где 2,5 - опорное напряжение на плате, а 42mA - потребление платы. По тому принимаем самый близкий резистор по номиналу - 56 Ом.
Для деление основного напряжения питания до опорного 5/2 вам потребуется поставить два одинаковых резистора R1 и R2.

Остается только загрузить пример кода в Arduino:

//Michael Klements //The DIY Life //27 October 2014 #include int currentPin = 1; //Assign CT input to pin 1 double kilos = 0; int peakPower = 0; LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //Assign LCD screen pins, as per LCD shield requirements void setup() { lcd.begin(16,2); // columns, rows. use 16,2 for a 16x2 LCD, etc. lcd.clear(); lcd.setCursor(0,0); // set cursor to column 0, row 0 (the first row) lcd.print("Running"); } void loop() { int current = 0; int maxCurrent = 0; int minCurrent = 1000; for (int i=0 ; i<=200 ; i++) //Monitors and logs the current input for 200 cycles to determine max and min current { current = analogRead(currentPin); //Reads current input and records maximum and minimum current if(current >= maxCurrent) maxCurrent = current; else if(current <= minCurrent) minCurrent = current; } if (maxCurrent <= 517) { maxCurrent = 516; } double RMSCurrent = ((maxCurrent - 516)*0.707)/11.8337; //Calculates RMS current based on maximum value int RMSPower = 220*RMSCurrent; //Calculates RMS Power Assuming Voltage 220VAC, change to 110VAC accordingly if (RMSPower > peakPower) { peakPower = RMSPower; } kilos = kilos + (RMSPower * (2.05/60/60/1000)); //Calculate kilowatt hours used delay (2000); lcd.clear(); lcd.setCursor(0,0); // Displays all current data lcd.print(RMSCurrent); lcd.print("A"); lcd.setCursor(10,0); lcd.print(RMSPower); lcd.print("W"); lcd.setCursor(0,1); lcd.print(kilos); lcd.print("kWh"); lcd.setCursor(10,1); lcd.print(peakPower); lcd.print("W"); }

Завершающим шрихом нашей установки станет калибровка. Ее лучше выполнять при включенной эталонной нагрузке известной мощности. Для этого хорошо подходят мощные лампы накаливания. Возьмем лампу на 100 Ват. Включаем плату и высчитываем поправочный коэффициент:
Двойной RMSCurrent = ((maxCurrent - 516) * 0,707) /11,8337 где 11.8337 - подобранный коэффициент для компенсации расхождений в измерениях.

Arduino и добавленная к ней схема заряда могут быть использованы для мониторинга и управления зарядкой никель-металл-гидридных аккумуляторов, например, так:

Законченное устройство

Аккумуляторные батареи являются отличным способом для питания вашей портативной электроники. Они могут сэкономить вам много денег при правильной зарядке. Для того, чтобы вы могли получить максимальную отдачу от ваших аккумуляторных батарей, их необходимо правильно заряжать. Это означает, что вам необходимо хорошее зарядное устройство. Вы можете потратить кучу денег, купив готовое зарядное устройство, а можете получить удовольствие, сделав его сами. В данной статье мы рассмотрим, как можно создать зарядное устройство, управляемое Arduino.

Во-первых, важно отметить, что не существует универсального способа зарядки, который подходил бы для всех аккумуляторов. Разные типы аккумуляторов используют разные химические процессы, обеспечивающие их работу. В результате, разные типы аккумуляторов необходимо заряжать по-разному. В этой статье мы не сможем охватить все типы аккумуляторных батарей и методы зарядки. Поэтому для простоты мы сосредоточим внимание на наиболее распространенном типе аккумуляторных батарей размера AA, на никель-металл-гидридных аккумуляторах (NiMH).

Комплектующие

Список комплектующих слева направо:

  • мощный резистор 10 Ом (минимум 5 ватт);
  • резистор 1 МОм;
  • конденсатор 1 мкФ;
  • MOSFET транзистор IRF510;
  • датчик температуры TMP36;
  • источник питания 5 вольт;

Как заряжать NiMH AA аккумуляторы

Увеличение скорости заряда увеличивает риск повреждения аккумулятора.

Существует много способов зарядки NiMH аккумуляторов. Выбор используемого вами метода главным образом зависит от того, как быстро вы хотите зарядить аккумулятор. Скорость заряда измеряется по отношению к емкости батареи. Если ваша батарея обладает емкостью 2500 мАч, и вы заряжаете ее током 2500 мА, то вы заряжаете ее со скоростью 1C. Если вы заряжаете этот же аккумулятор током 250 мА, то вы заряжаете его со скоростью C/10.

Во время быстрой зарядки аккумулятора (со скоростью выше C/10), вам необходимо тщательно контролировать напряжение на батарее и ее температуру, чтобы не перезарядить ее. Это может серьезно повредить аккумулятор. Тем не менее, когда вы заряжаете аккумулятор медленно (со скоростью ниже C/10), у вас гораздо меньше шансов повредить батарею, если случайно перезарядите ее. Поэтому медленные методы зарядки, как правило, считаются более безопасными и помогут вам увеличить срок службы батареи. Поэтому в нашем самодельном зарядном устройстве мы будем использовать скорость заряда C/10.

Цепь заряда

Для данного зарядного устройства основой является схема для управления источником питания с помощью Arduino. Схема питается от источника напряжения 5 вольт, например, от адаптера переменного тока или компьютерного блока питания. Большинство USB портов не подходит для данного проекта из-за ограничений по току. Источник 5В заряжает батарею через мощный резистор 10 Ом и мощный MOSFET транзистор. MOSFET транзистор устанавливает величину тока, протекающего через батарею. Резистор добавлен как простой способ контроля тока. Контроль величины тока выполняется подключением каждого вывода резистора к аналоговым входным выводам Arduino и измерением напряжения с каждой стороны. MOSFET транзистор управляется выходным ШИМ выводом Arduino. Импульсы сигнала широтно-импульсной модуляции сглаживаются до постоянного напряжения фильтром на резисторе 1 МОм и конденсаторе 1 мкФ. Данная схема позволяет Arduino отслеживать и управлять током, протекающим через батарею.


Датчик температуры

Датчик температуры служит для предотвращения перезаряда батареи и обеспечения безопасности.

В качестве дополнительной меры предосторожности в зарядное устройство добавлен датчик температуры TMP36 для контроля температуры батареи. Данный датчик выдает напряжение, которое линейно зависит от температуры. Поэтому он, в отличие от термисторов, не требует калибровки или балансировки. Датчик устанавливается в просверленном отверстии в корпусе держателя батареи и приклеивается в отверстии так, чтобы он прижимался к батарее, когда та будет установлена в держатель. Выводы датчика подключаются к шине 5В, к корпусу и к аналоговому входному выводу Arduino.

Держатель AA батареи перед и после установки на макетную плату

Код


Код для данного проекта довольно прост. Переменные в начале исходного кода позволяют настроить зарядное устройство путем ввода значений емкости батареи и точного сопротивления мощного резистора. Также добавлены и переменные безопасных порогов. Максимально допустимое напряжение на батарее устанавливается в значение 1,6 вольта. Максимальная температура батареи установлена на 35 градусов по Цельсию. Максимальное время заряда установлено на 13 часов. Если какой-либо из этих порогов безопасности будет превышен, зарядное устройство выключается.

В теле программы вы можете увидеть, что система постоянно измеряет напряжения на выводах мощного резистора. Это используется для расчета значений напряжения на батарее и протекающего через нее тока. Ток сравнивается с целевым значением, которое составляет C/10. Если рассчитанный ток отличается от целевого значения более, чем на 10 мА, система автоматически подстраивает выходное значение, чтобы подкорректировать его.

Arduino использует последовательный интерфейс для отображения всех текущих данных. Если вы хотите проконтролировать работу вашего зарядного устройства, то можете подключить Arduino к USB порту компьютера, но это необязательно, так как Arduino питается от источника напряжения 5В зарядного устройства.

Int batteryCapacity = 2500; // значение емкости батареи в мАч float resistance = 10.0; // измеренное сопротивление мощного резистора int cutoffVoltage = 1600; // максимальное напряжение на батарее (в мВ), которое не должно быть превышено float cutoffTemperatureC = 35; // максимальная температура батареи, которая не должна быть превышена (в градусах C) //float cutoffTemperatureF = 95; // максимальная температура батареи, которая не должна быть превышена (в градусах F) long cutoffTime = 46800000; // максимальное время заряда в 13 часов, которое не должно быть превышено int outputPin = 9; // провод выходного сигнала подключен к цифровому выводу 9 int outputValue = 150; // значение выходного ШИМ сигнала int analogPinOne = 0; // первый датчик напряжения подключен к аналоговому выводу 0 float valueProbeOne = 0; // переменная для хранения значения на analogPinOne float voltageProbeOne = 0; // рассчитанное напряжение на analogPinOne int analogPinTwo = 1; // второй датчик напряжения подключен к аналоговому выводу 1 float valueProbeTwo = 0; // переменная для хранения значения на analogPinTwo float voltageProbeTwo = 0; // рассчитанное напряжение на analogPinTwo int analogPinThree = 2; // третий датчик напряжения подключен к аналоговому выводу 2 float valueProbeThree = 0; // переменная для хранения значения на analogPinThree float tmp36Voltage = 0; // рассчитанное напряжение на analogPinThree float temperatureC = 0; // рассчитанная температура датчика в градусах C //float temperatureF = 0; // рассчитанная температура датчика в градусах F float voltageDifference = 0; // разница между напряжениями на analogPinOne и analogPinTwo float batteryVoltage = 0; // рассчитанное напряжение на батарее float current = 0; // рассчитанный ток, протекающий через нагрузку в (мА) float targetCurrent = batteryCapacity / 10; // целевой выходной ток (в мА) устанавливается в значение // C/10 или 1/10 от емкости батареи float currentError = 0; // разница между целевым и фактическим токами (в мА) void setup() { Serial.begin(9600); // настройка последовательного интерфейса pinMode(outputPin, OUTPUT); // установить вывод, как выход } void loop() { analogWrite(outputPin, outputValue); // записать выходное значение в выходной вывод Serial.print("Output: "); // показать выходные значения для контроля на компьютере Serial.println(outputValue); valueProbeOne = analogRead(analogPinOne); // считать входное значение на первом пробнике voltageProbeOne = (valueProbeOne*5000)/1023; // рассчитать напряжение на первом пробнике в милливольтах Serial.print("Voltage Probe One (mV): "); // показать напряжение на первом пробнике Serial.println(voltageProbeOne); valueProbeTwo = analogRead(analogPinTwo); // считать входное значение на втором пробнике voltageProbeTwo = (valueProbeTwo*5000)/1023; // рассчитать напряжение на втором пробнике в милливольтах Serial.print("Voltage Probe Two (mV): "); // показать напряжение на втором пробнике Serial.println(voltageProbeTwo); batteryVoltage = 5000 - voltageProbeTwo; // рассчитать напряжение на батарее Serial.print("Battery Voltage (mV): "); // показать напряжение на батарее Serial.println(batteryVoltage); current = (voltageProbeTwo - voltageProbeOne) / resistance; // рассчитать ток заряда Serial.print("Target Current (mA): "); // показать целевой ток Serial.println(targetCurrent); Serial.print("Battery Current (mA): "); // показать фактический ток Serial.println(current); currentError = targetCurrent - current; // разница между целевым и измеренным токами Serial.print("Current Error (mA): "); // показать ошибку установки тока Serial.println(currentError); valueProbeThree = analogRead(analogPinThree); // считать входное значение третьего пробника, tmp36Voltage = valueProbeThree * 5.0; // преобразуя его в напряжение tmp36Voltage /= 1024.0; temperatureC = (tmp36Voltage - 0.5) * 100 ; // преобразование, исходя из зависимости в 10 мВ на градус со сдвиком в 500 мВ // ((напряжение - 500 мВ) умножить на 100) Serial.print("Temperature (degrees C) "); // показать температуру в градусах Цельсия Serial.println(temperatureC); /* temperatureF = (temperatureC * 9.0 / 5.0) + 32.0; //преобразовать в градусы Фаренгейта Serial.print("Temperature (degrees F) "); Serial.println(temperatureF); */ Serial.println(); // дополнительные пустые строки, чтобы облегчить чтение данных при отладке Serial.println(); if(abs(currentError) > 10) // если ошибка установки тока достаточно велика, то подстроить выходное напряжение { outputValue = outputValue + currentError / 10; if(outputValue < 1) // выходное значение никогда не может быть ниже 0 { outputValue = 0; } if(outputValue > 254) // выходное значение никогда не может быть выше 255 { outputValue = 255; } analogWrite(outputPin, outputValue); // записать новое выходное значение } if(temperatureC > cutoffTemperatureC) // остановить зарядку, если температура батареи превысила безопасный порог { outputValue = 0; Serial.print("Max Temperature Exceeded"); } /* if(temperatureF > cutoffTemperatureF) // остановить зарядку, если температура батареи превысила безопасный порог { outputValue = 0; } */ if(batteryVoltage > cutoffVoltage) // остановить зарядку, если напряжение на батарее превысило безопасный порог { outputValue = 0; Serial.print("Max Voltage Exceeded"); } if(millis() > cutoffTime) // остановить зарядку, если время заряда превысило порог { outputValue = 0; Serial.print("Max Charge Time Exceeded"); } delay(10000); // задержка в 10 секунд перед следующей итерацией цикла }

Скачиваемую версию исходного кода вы можете найти по ссылке, приведенной ниже.

В этой статье приводится интересная схема для любителей экспериментов и Arduino . В ней представлен простой цифровой вольтметр, который может безопасно измерять постоянное напряжение в диапазоне от 0 до 30 В. Сама плата Arduino может питаться от стандартного источника 9 В.



Как известно, с помощью аналогового входа Arduino можно измерить напряжение от 0 до 5 В (при стандартном опорном напряжении 5 В). Но этот диапазон можно расширить, воспользовавшись делителем напряжения.


Делитель понижает измеряемое напряжение до приемлемого для аналогового входа уровня. Затем специально написанный код высчитывает фактическое напряжение.



Аналоговый датчик в составе Arduino определяет напряжение на аналоговом входе и преобразует его в цифровой формат, воспринимаемый микроконтроллером. К аналоговому входу A0 мы подключаем делитель напряжения, образованный сопротивлениями R1 (100K) и R2 (10K). С такими значениями сопротивлений на Arduino можно подавать до 55 В, поскольку коэффициент деления в данном случае получается 11, поэтому 55В/11=5В. Для того, чтобы быть уверенным в безопасности измерений для платы, лучше проводить измерение напряжения в диапазоне от 0 до 30 В.



Если показания дисплея не соответствуют показанием поверенного вольтметра, следует использовать прецизионный цифровой мультиметр для нахождения точных значений R1 и R2. При этом в коде нужно будет заменить R1=100000.0 и R2=10000.0 своими значениями. Затем стоит проверить питание, измерив на плате напряжение между 5V и GND. Напряжение может быть 4.95 В. Тогда в коде vout = (value * 5.0) / 1024.0 нужно заменить 5.0 на 4.95. Желательно использовать прецизионные резисторы с погрешностью не более 1%. Помните, что напряжение выше 55 В может вывести плату Arduino из строя!



#include LiquidCrystal lcd(7, 8, 9, 10, 11, 12); int analogInput = 0; float vout = 0.0; float vin = 0.0; float R1 = 100000.0; // сопротивление R1 (100K) float R2 = 10000.0; // сопротивление R2 (10K) int value = 0; void setup(){ pinMode(analogInput, INPUT); lcd.begin(16, 2); lcd.print("DC VOLTMETER"); } void loop(){ // считывание аналогового значения value = analogRead(analogInput); vout = (value * 5.0) / 1024.0; vin = vout / (R2/(R1+R2)); if (vin<0.09) { vin=0.0;// обнуляем нежелательное значение } lcd.setCursor(0, 1); lcd.print("INPUT V= "); lcd.print(vin); delay(500); }


Используемые элементы:


Плата Arduino Uno
Резистор 100 КОм
Резистор 10 КОм
Резистор 100 Ом
Потенциометр 10 КОм
LCD-дисплей 16×2

Как известно, ATmega может питаться от широкого диапазона напряжений, поэтому может оставаться "в строю" даже в случае постепенного разряда батареи, выражающегося в уменьшении напряжения. Ситуация эта в робототехнике более чем стандартная, за примером далеко ходить не надо: возьмем проект Voyager . Это робот-космический аппарат, запущенный за пределы солнечной системы и потому лишенный способности питаться от солнечных батарей . На него установлены радиоизотопные термические генераторы (ядерные батарейки), которые на момент старта выдавали 30В / 470Вт, но каждый год они теряют 0.78% своей мощности. Соответственно, в настоящий момент осталось около 60% от первоначальной, и приходится включать исследовательские подсистемы поочередно, чтобы не перегрузить генераторы.

В Arduino нельзя просто взять и подключить Vcc к аналоговому пину напрямую - по умолчанию AREF связан с Vcc и вы всегда будете получать максимальное значение 1023, от какого бы напряжения вы не питались. Спасает подключение к AREF источника напряжения с заранее известным, стабильным напряжением, но это - лишний элемент в схеме.

Еще можно соединить Vcc с AREF через диод : падение напряжение на диоде заранее известно, поэтому вычислить Vcc не составит труда. Однако, при такой схеме через диод постоянно протекает ток , сокращая жизнь батареи, что тоже не очень удачно.

Как же выкрутиться из положения, не добавляя новых элементов в схему и не сокращая время работы батареи? Оказывается, выход - есть, и поможет нам внутренний источник опорного напряжения 1.1В в ATmega (в документации он проходит как bandgap reference), которое не зависит от Vcc. Получается такая формула:

V_BAT=(1.1*1024)/analogRead(14);

где V_BAT - это напряжение Vcc в вольтах, а analogRead(14) - результат прямого чтения АЦП из канала 14.

В Arduino разрешены чтения только из каналов 0-7 (не удивляйтесь, если нашли на своем Diecimila или Duemilanove только 0-5 , возьмите, к примеру, Seeeduino ;)

Чтобы появилась возможность отправлять данные в другие каналы, в том числе в 14, надо изменить маску в библиотеке-ядре Arduino. Для этого откройте файл hardware\cores\arduino\wiring_analog.c и найдите там строку:

ADMUX = (analog_reference

замените ее на:

ADMUX = (analog_reference

После этого можно написать вот такой скетч:

uint16_t raw_bandgap = 0; // значение внутреннего bandgap
float volt_battery = 0.0;

void setup (){
Serial .begin (57600);
}

void loop (){
// Чтение напряжения батареи
analogReference (DEFAULT ); // использовать Vcc как AREF
// холостое чтение после смены AREF (см. 23.5.2 в руководстве)
raw_bandgap = analogRead (14); // измерить значение внутреннего bandgap
volt_battery = (1.1 * 1024) / raw_bandgap; // вычислить Vcc
Serial .print (volt_battery);
Serial .println (" v_bat" );
delay (1000);
}

Тем, кто хочет знать напряжение на батарее, стоит иметь ввиду, что при наличии регулятора (типа L7805CV), мы будем измерять напряжение Vout регулятора, а в случае наличия входного диода - надо учесть напряжение, которое на нем падает.

Вот так выглядят вычисляемые значения в Seeeduino , в момент переключения с питания 5В на 3,3В:

При этом мой вольтметр показывает меньшие значения. Но, тем не менее - скетч работает;)

UPD: Нашел примеры, в которых вместо константы 1.1 используется 1.05. Результат получается гораздо ближе к показаниям вольтметра, ищу теоретическую базу, способную объяснить этот факт...

Представлена полезная схема для любителей поэкспериментировать с Ардуино. Это простой цифровой вольтметр, которым надежно можно измерять постоянное напряжение в диапазоне 0 – 30В. Плату Ардуино, как обычно, можно питать от 9В батареи.

Как вам вероятно известно, аналоговые входы Ардуино можно использовать для измерения постоянного напряжения в диапазоне 0 – 5В и этот диапазон можно увеличить,
используя два резистора в качестве делителя напряжения. Делитель уменьшит измеряемое напряжение до уровня аналоговых входов Ардуино. А затем программа вычислит реальную величину напряжения.

Аналоговый датчик на плате Ардуино определяет наличие напряжения на аналоговом входе и преобразует его в цифровую форму для дальнейшей обработки микроконтроллером. На рисунке напряжение подается на аналоговый вход (А0) через простой делитель напряжения, состоящий из резисторов R1 (100кОм) и R2 (10кОм).

При этих значениях делителя на плату Ардуино можно подавать напряжение от 0 до
55В. На входе А0 имеем измеряемое напряжение деленное на 11,т.е.55В / 11=5В. Иначе говоря, при измерении 55В на входе Ардуино имеем максимально допустимое значение 5В. На практике лучше на этом вольтметре написать диапазон “0 – 30В”, чтобы оставался
Запас по безопасности!

Примечания

Если показания дисплея не совпадают с показаниями промышленного (лабораторного) вольтметра, то необходимо точным прибором измерить величину сопротивлений R1 и R2 и вставить эти значения вместо R1=100000.0 и R2=10000.0 в коде программы. Затем следует измерить лабораторным вольтметром реальное напряжение между выводами 5В и “Земля” платы Ардуино. Получится значение меньшее, чем 5В, например, получилось 4.95В. Это реальное значение следует вставить в строке кода
vout = (value * 5.0) / 1024.0 вместо 5.0.
Кроме того, старайтесь применять прецизионные резисторы с допуском 1%.

Резисторы R1 и R2 обеспечивают некоторую защиту от повышенных входных напряжений.Однако следует помнить, что любые напряжения выше 55В могут вывести из строя плату Ардуино. Кроме того, в этой конструкции не предусмотрены другие виды защиты(от скачков напряжения, от переполюсовки или повышенного напряжения).

Программа цифрового вольтметра

/*
DC Voltmeter
An Arduino DVM based on voltage divider concept
T.K.Hareendran
*/
#include
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
int analogInput = 0;
float vout = 0.0;
float vin = 0.0;
float R1 = 100000.0; // resistance of R1 (100K) -see text!
float R2 = 10000.0; // resistance of R2 (10K) – see text!
int value = 0;
void setup(){
pinMode(analogInput, INPUT);
lcd.begin(16, 2);
lcd.print(“DC VOLTMETER”);
}
void loop(){
// read the value at analog input
value = analogRead(analogInput);
vout = (value * 5.0) / 1024.0; // see text
vin = vout / (R2/(R1+R2));
if (vin<0.09) {
vin=0.0;//statement to quash undesired reading !
}
lcd.setCursor(0, 1);
lcd.print(“INPUT V= “);
lcd.print(vin);
delay(500);
}

Принципиальная схема Ардуино-вольтметра

Перечень компонентов

Плата Arduino Uno
100 кОм резистор
10 кОм резистор
100 Ом резистор
10кОм Подстроечный резистор
LCD дисплей 16?2 (Hitachi HD44780)