Если вы когда-нибудь работали с батареями (аккумуляторами), импульсными (SMPS) или любыми другими источниками питания у вас наверняка возникала потребность в проверке их работы в различных условиях, то есть под различной нагрузкой. Устройство, которое обычно используется для этих целей, называется нагрузкой постоянного тока (Constant Current DC Load) и позволяет проверить выходной ток вашего источника питания и поддерживать его постоянным до тех пор пока не понадобится изменение условий его работы. В данной статье мы рассмотрим создание регулируемой электронной нагрузки постоянного тока на основе платы Arduino с максимальным входным напряжением 24V и силой тока до 5A. Для этого проекта в компании AllPCB была изготовлена печатная плата. Вы можете изготовить печатную плату, используя необходимые для этого файлы, у любого другого производителя.
Наша регулируемая электронная нагрузка будет работать на основе операционного усилителя и MOSFET транзистора. Управлять всеми процессами в схеме будет плата Arduino Nano.
Схема нашего проекта будет состоять из 3-х частей. Первая часть будет содержать плату Arduino Nano, вторая – цифро-аналоговый преобразователь (ЦАП), а третья часть будет представлять собой чисто аналоговую схему, в которой двойной операционный усилитель (в едином корпусе) будет использоваться для управления секцией нагрузки.
Наша электронная нагрузка будет иметь следующие особенности:
- Два переключателя для увеличения и уменьшения нагрузки.
- ЖК дисплей, на котором будет отображаться установленная нагрузка, текущая нагрузка и напряжение нагрузки.
- Максимальный ток нагрузки - 5A.
- Максимальное входное напряжение нагрузки - 24V.
Необходимые компоненты
- Плата Arduino Nano (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Два разъема (barrel socket).
- Mosfet irf540n (купить на AliExpress).
- Цифро-аналоговый преобразователь Mcp4921 (купить на AliExpress).
- Операционный усилитель Lm358 (купить на AliExpress).
- Шунтирующий резистор 0,1 Ом 5 Вт.
- Резистор 1 кОм (купить на AliExpress).
- Резистор 10 кОм – 6 шт. (купить на AliExpress).
- Резистор 2 кОм – 2 шт. (купить на AliExpress).
- Конденсатор 1 мкФ 50В.
- Теплоотвод (радиатор).
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Схема проекта
Схема регулируемой электронной нагрузки постоянного тока на основе платы Arduino представлена на следующем рисунке.
В представленной схеме операционный усилитель имеет 2 секции: одна управляет MOSFET транзистором, а другая усиливает измеряемый ток. Первая секция содержит резисторы R12, R13 и MOSFET. Резистор R12 используется для уменьшения действия нагрузки в цепи обратной связи, а R13 является резистором затвора MOSFET транзистора. Более подробно про работу схемы и назначение ее элементов вы можете посмотреть на видео, приведенном в конце статьи, правда, на английском языке.
Дополнительные два резистора R8 и R9 используются для измерения напряжения, поступающего от источника питания. Исходя из их номиналов по правилу делителя напряжения легко определить что максимальное измеряемое напряжение составит 24V, если напряжение будет больше 24V, то оно может повредить контакт платы Arduino, поскольку на него в этом случае будет поступать напряжение более 5 В.
R7 является нагрузочным резистором, его сопротивление составляет 0,1 Ом и он может рассеивать мощность до 5 Вт. Исходя из формулы для расчета мощности P = I2R он может выдерживать ток до 7A, но в целях безопасности лучше ограничить ток, протекающий через данный резистор, значением 5A. Таким образом, получается что наша регулируемая электронная нагрузка постоянного тока (то есть эквивалент нагрузки) рассчитано на напряжение до 24V и ток до 5A.
Другая секция операционного усилителя работает как обычный усилитель с коэффициентом усиления 6x. При протекании тока через какой либо электронный элемент на нем создается падение напряжения. К примеру, если ток 5A протекает через шунтирующий резистор сопротивлением 0,1 Ом, то в нем по закону Ома (V = I x R) создается падение напряжения 0,5 В. Наш неинвертирующий усилитель усилит это значение в 6 раз, следовательно, на выходе второй секции операционного усилителя будет напряжение 3V. Это напряжение подается на аналоговый контакт платы Arduino Nano, которая измеряет его и на основе этого рассчитывает силу протекающего через шунтирующий резистор тока.
Первая часть операционного усилителя работает как повторитель напряжения и управляет работой MOSFET транзистора, который выступает в роли обратной связи для тока, протекающего через шунтирующий резистор.
MCP4921 представляет собой цифро-аналоговый преобразователь (ЦАП), который получает цифровые данные от платы Arduino по протоколу SPI и преобразует их в соответствующие аналоговые значения, которые в нашей схеме подаются на вход операционного усилителя.
Плата Arduino Nano передает цифровые данные ЦАПу MCP4921 по протоколу SPI и, таким образом, производит управление нашей электронной нагрузкой. Также она отображает необходимые данные на экране ЖК дисплея 16x2. Также к плате Arduino Nano подключены две кнопки для увеличения и уменьшения значения нагрузки. Вместо их подключения к цифровым контактам (как обычно) мы их подключили к аналоговым контактам платы Arduino. Поэтому вместо них можно в проекте использовать другие типы переключателей, например, слайдеры или аналоговые энкодеры. Также, при помощи небольших изменений в коде программы можно непосредственным образом подавать "сырые" (необработанные) аналоговые данные (raw analog data) в цепь операционного усилителя для управления нагрузкой. Подключение кнопок к аналоговым контактам также устраняет проблему, связанную с дребезгом их контактов (debounce problem).
Таким образом, в нашей схеме плата Arduino Nano передает данные ЦАПу в цифровой форме, ЦАП преобразует их в аналоговый вид и подает на вход операционного усилителя, который управляет работой MOSFET транзистора. Протекающий через шунтирующий резистор ток создает падение напряжения на нем, которое усиливается вторым каналом микросхемы LM358 и поступает на плату Arduino Nano, которая отображает его значение на экране ЖК дисплея. При помощи кнопок можно увеличивать и уменьшать значение тока через нагрузку.
Изготовление печатной платы для проекта
Спроектированная нами печатная плата для рассматриваемого в данной статье проекта регулируемой электронной нагрузки на основе платы Arduino показана на следующем рисунке.
Скачать Gerber файлы этой печатной платы вы можете по следующей ссылке - Download Adjustable Electronic DC Load Gerber File.
Заказать печатную плату можно, к примеру, на сервисе allpcb.com, или у любого другого изготовителя печатных плат. Процессы заказа и оплаты изготовления печатной платы на сервисе allpcb.com показаны на следующих рисунках.
После изготовления печатная плата пришла авторам проекта вот в такой вот коробке:
Внешний вид пришедшей печатной платы показан на следующем рисунке. Качество изготовления, как видите, хорошее.
После сборки проекта на основе этой печатной платы получился следующий окончательный вид конструкции нашего проекта:
Объяснение программы для Arduino
Полный код программы приведен в конце статьи, здесь же мы кратко рассмотрим его основные фрагменты. Комментарии к коду программы также переведены в конце статьи, в этой части статьи я их оставил без перевода.
Вначале в коде программы мы подключим необходимые библиотеки (SPI.h и LiquidCrystal.h). Также установим максимальный логический уровень напряжения, значение сопротивления шунтирующего резистора, определим необходимые контакты.
1 2 3 4 5 6 7 |
#include <SPI.h> #include <LiquidCrystal.h> #define SS_PIN 10 #define MAX_VOLT 5.0 // maximum logic voltage #define load_resistor 0.1 // shunt resistor value in Ohms #define opamp_gain 6 // gain of the op-amp #define average 10 // average time |
Далее в программе объявим необходимые переменные.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
const int slaveSelectPin = 10; // Chip select pin int number = 0; int increase = A2; // Increase pin int decrease = A3; //decrease pin int current_sense = A0; //current sense pin int voltage_sense = A1; // voltage sense pin int state1 = 0; int state2 = 0; int Set = 0; float volt = 0; float load_current = 0.0; float load_voltage = 0.0; float current = 0.0; float voltage = 0.0; LiquidCrystal lcd(7, 6, 5, 4, 3, 2); // LCD pins |
В функции void setup() зададим режимы работы для используемых контактов (на ввод или вывод данных), инициализируем ЖК дисплей и связь по протоколу SPI. Также выведем приветственное сообщение на экран ЖК дисплея.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void setup() { pinMode(slaveSelectPin, OUTPUT); pinMode(increase, INPUT); pinMode(decrease, INPUT); pinMode(current_sense, INPUT); pinMode(voltage_sense, INPUT); // initialize SPI: SPI.begin(); //set up the LCD's number of columns and rows: lcd.begin(16, 2); // Print a message to the LCD. lcd.print("Digital Load"); lcd.setCursor(0, 1); lcd.print("Circuit Digest"); delay (2000); } |
В функции convert_DAC мы будем производить цифро-аналоговое преобразование сигналов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
void convert_DAC(unsigned int value) { /*Step Size = 2^n, Therefore 12bit 2^12 = 4096 For 5V reference, the step will be 5/4095 = 0.0012210012210012V or 1mV (approx)*/ unsigned int container ; unsigned int MSB; unsigned int LSB; /*Step: 1, stored the 12 bit data into the container Suppose the data is 4095, in binary 1111 1111 1111*/ container = value; /*Step: 2 Creating Dummy 8 bit. So, by dividing 256, upper 4 bits are captured in LSB LSB = 0000 1111*/ LSB = container/256; /*Step: 3 Sending the configuration with punching the 4 bit data. LSB = 0011 0000 OR 0000 1111. Result is 0011 1111 */ LSB = (0x30) | LSB; /*Step:4 Container still has the 21bit value. Extracting the lower 8 bits. 1111 1111 AND 1111 1111 1111. Result is 1111 1111 which is MSB*/ MSB = 0xFF & container; /*Step:4 Sending the 16bits data by dividing into two bytes. */ digitalWrite(slaveSelectPin, LOW); delay(100); SPI.transfer(LSB); SPI.transfer(MSB); delay(100); // take the SS pin high to de-select the chip: digitalWrite(slaveSelectPin, HIGH); } |
В следующем фрагменте программы производится определение силы тока, протекающего через шунтирующий резистор.
1 2 3 4 5 6 7 8 9 10 |
float read_current (void){ load_current = 0; for (int a = 0; a < average; a++){ load_current = load_current + analogRead(current_sense); } load_current = load_current / average; load_current = (load_current* MAX_VOLT) / 1024; load_current = (load_current / opamp_gain) / load_resistor; return load_current; } |
Это значение силы тока будет использоваться для расчета напряжения нагрузки.
1 2 3 4 5 6 7 8 9 |
float read_voltage (void){ load_voltage = 0; for (int a = 0; a < average; a++){ load_voltage = load_voltage + analogRead(voltage_sense); } load_voltage = load_voltage / average; load_voltage = ((load_voltage * MAX_VOLT)/1024.0)*6; return load_voltage; } |
Далее в функции void loop () мы будем непрерывно измерять требуемые нам значения тока и напряжения и передавать соответствующие данные ЦАПу. Требуемые и измеренные значения тока и напряжения отображаются на экране ЖК дисплея.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
void loop () { state1 = analogRead(increase); if (state1 > 500){ delay(50); state1 = analogRead(increase); if (state1 > 500){ volt = volt+0.02; } } state2 = analogRead(decrease); if (state2 > 500){ delay(50); state2 = analogRead(decrease); if (state2 > 500){ if (volt == 0){ volt = 0; } else{ volt = volt-0.02; } } } number = volt / 0.0012210012210012; convert_DAC (number); voltage = read_voltage(); current = read_current(); lcd.setCursor(0, 0); lcd.print("Set Value"); lcd.print("="); Set = (volt/2)*10000; lcd.print(Set); lcd.print("mA "); lcd.setCursor(0, 1); lcd.print("I"); lcd.print("="); lcd.print(current); lcd.print("A "); lcd.print(" V"); lcd.print("="); lcd.print(voltage); lcd.print("V"); // lcd.print(load_voltage); //lcd.print("mA "); // delay(1000); //lcd.clear(); } |
После того, как с кодом программы закончили, можно приступать к тестированию работы электронной нагрузки.
Тестирование работы проекта
Для питания схемы мы использовали источник питания с напряжением 12V. В качестве тестируемого источника питания мы выбрали литиевую батарею напряжением 7.4V. Для проверки правильности работы схемы мы использовали токовые клещи (clamp meter).
Как вы можете видеть на представленном рисунке, установленное значение тока составляет 300mA, значение потребляемого тока в нашей схеме также равно 300, а токовые клещи показывают значение протекающего тока, равное 310mA.
Более подробно работу проекта вы можете посмотреть на видео, приведенном в конце статьи.
Исходный код программы (скетча)
Скетч достаточно простой, у начинающих, единственное, могут возникнуть небольшие проблемы с пониманием работы с ЦАПом (но я надеюсь, они решаемые).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
#include <SPI.h> #include <LiquidCrystal.h> #define SS_PIN 10 #define MAX_VOLT 5.0 #define load_resistor 0.1 #define opamp_gain 6 #define average 10 const int slaveSelectPin = 10; int number = 0; int increase = A2; int decrease = A3; int current_sense = A0; int voltage_sense = A1; int state1 = 0; int state2 = 0; int Set = 0; float volt = 0; float load_current = 0.0; float load_voltage = 0.0; float current = 0.0; float voltage = 0.0; LiquidCrystal lcd(7, 6, 5, 4, 3, 2); void setup() { // устанавливаем контакт slaveSelectPin на вывод данных pinMode(slaveSelectPin, OUTPUT); pinMode(increase, INPUT); // контакт кнопки на ввод данных pinMode(decrease, INPUT); // контакт кнопки на ввод данных pinMode(current_sense, INPUT); // pinMode(voltage_sense, INPUT); // // initialize SPI: SPI.begin(); //set up the LCD's number of columns and rows: lcd.begin(16, 2); // выводим приветственное сообщение на экран ЖК дисплея lcd.print("Digital Load"); lcd.setCursor(0, 1); lcd.print("Circuit Digest"); delay (2000); } void convert_DAC(unsigned int value) { /*размер шага = 2^n, следовательно 12bit 2^12 = 4096 для опорного напряжения 5V шаг будет равен 5/4095 = 0.0012210012210012V или примерно 1mV */ unsigned int container ; unsigned int MSB; unsigned int LSB; /*Шаг 1: сохраняем 12 бит данных в контейнер если значение данных равно 4095, то в двоичном виде это будет 1111 1111 1111*/ container = value; /*Шаг 2: Creating Dummy 8 bit. Таким образом, разделив на 256, мы получим что старшие 4 бита перейдут в LSB (младший разряд) LSB = 0000 1111*/ LSB = container/256; /*Шаг 3: Передаем настройки с помощью преобразования 4 бит данных. LSB = 0011 0000 OR 0000 1111. Result is 0011 1111 */ LSB = (0x30) | LSB; /*Шаг 4: Контейнер все еще содержит 21 битное значение. Извлечем младшие 8 бит. 1111 1111 AND 1111 1111 1111. Result is 1111 1111 which is MSB*/ MSB = 0xFF & container; // старший разряд /*Шаг 5: Передаем 16 бит данных разделив их на 2 байта */ digitalWrite(slaveSelectPin, LOW); delay(100); SPI.transfer(LSB); SPI.transfer(MSB); delay(100); // take the SS pin high to de-select the chip: digitalWrite(slaveSelectPin, HIGH); } float read_current (void){ load_current = 0; for (int a = 0; a < average; a++){ load_current = load_current + analogRead(current_sense); } load_current = load_current / average; load_current = (load_current* MAX_VOLT) / 1024; load_current = (load_current / opamp_gain) / load_resistor; return load_current; } float read_voltage (void){ load_voltage = 0; for (int a = 0; a < average; a++){ load_voltage = load_voltage + analogRead(voltage_sense); } load_voltage = load_voltage / average; load_voltage = ((load_voltage * MAX_VOLT)/1024.0)*6; return load_voltage; } void loop () { state1 = analogRead(increase); if (state1 > 500){ delay(50); state1 = analogRead(increase); if (state1 > 500){ volt = volt+0.02; } } state2 = analogRead(decrease); if (state2 > 500){ delay(50); state2 = analogRead(decrease); if (state2 > 500){ if (volt == 0){ volt = 0; } else{ volt = volt-0.02; } } } number = volt / 0.0012210012210012; convert_DAC (number); voltage = read_voltage(); current = read_current(); lcd.setCursor(0, 0); lcd.print("Set Value"); lcd.print("="); Set = (volt/2)*10000; lcd.print(Set); lcd.print("mA "); lcd.setCursor(0, 1); lcd.print("I"); lcd.print("="); lcd.print(current); lcd.print("A "); lcd.print(" V"); lcd.print("="); lcd.print(voltage); lcd.print("V"); // lcd.print(load_voltage); //lcd.print("mA "); // delay(1000); //lcd.clear(); } |