This is just a direct copy of Jasper’s Electric Load website, which was mentioned on Hackaday on April 29, 2014. It uses an Arduino to control a MOSFET load in constant current, constant power or constant resistance mode. I was more interested in the hardware than the software but I’ve copied everything here for posterity.

Summary: I designed an electric load. Using an Arduino Nano, the load can be programmed, and the voltage and current are measured. You can set a constant current (CC), a constant power (CP), or a constant resistance (CR) load by simply typing it in to the Arduino Serial Monitor. The circuit is designed for up to 30V, 5A, and 15W. An opamp, a mosfet, and a small sense resistor form the constant current circuit. The current is set using a DAC. Two other opamps measure the power supply voltage and the current. The circuit is powered from the Arduino USB voltage. I reflow soldered the board using the hacked toaster oven at the hackerdojo. Here are pictures of the reflow soldering process. ## Hardware¶

• Custom designed PCB (\$23)
• Arduino Nano board (\$12)
• 2x 15pins 0.1” pitch female header connectors (\$2)
• MCP4725 DAC (\$3)
• IRLZ44Z N-channel MOSFET (\$2)
• SK 129 38mm Heat sink (\$1)
• 0603 resistors and capacitors (\$2)
• screw terminal (\$1)

I chose to use an Arduino Nano board because it is small, cheap, easily interchangeable, it has a power supply that can be used to supply other circuits, and it can easily be programmed with the Arduino IDE. The Arduino is placed on female header connectors on the board. I chose to use the same DAC as on Adafruit and Sparkfun DAC breakout boards. The DAC can be supplied from 5V and the the output voltage is rail-to-rail. A description for using the MCP4725 DAC and library with Arduino can be found here on the Adafruit website. The DAC connects to the Arduino using I2C. Opamp IC1D, mosfet Q1, and the 0.1 Ohm sense resistor form the constant current circuit. I chose the AD8608 opamp because it is a quad opamp, it can be supplied from 5V, and it has rail-to-rail voltage output. The mosfet functions as a voltage dependent resistance, and in the linear range. I chose a popular and widely available mosfet with a gate threshold voltage between 2.5 and 3V for currents up to 5A. I found the heat sink in a local electronics shop for \$1. The mosfet, the heatsink, and their interface, have a combined thermal resistance of about 9 degrees Celsius per Watt. The maximum operation temperature of the mosfet is 175 degrees Celsius. This means that, at 25 degrees Celsius ambient temperature, maximal 15 Watt can be dissipated without active cooling.

To set a current of 1A, the DAC must output 1V. This voltage is divided by 10 using voltage divider R6 and R7 and this 0.1V is applied to the plus input of the opamp. The opamps adjusts it output voltage until it measures the same potential on it minus input, the feedback voltage from the sense resistor. That’s the case when a current of 1A runs through the 0.1 Ohm sense resistor. The capacitor (C4) value in the RC filter may be changed to a suitable cut off frequency, or left out. R5 and C1 are designed to prevent the opamp from oscillating, and the values were taken from a proven design. Opamp IC1B is used to measure the voltage of the power supply. R3 and R4 divide the supply (30V max) voltage by 6, so that it falls within 0-5V range of the 12 bit ADC of the Arduino. The opamp is simply used to buffer the voltage. The capacitor (C2) value in the RC filter may be changed to a suitable cut off frequency.

IC1C is used to measure the actual load current. The voltage over the sense resistor is amplified 10 times, by the opamp, and then connected to the 12 bit ADC pin of the Arduino. The capacitor (C3) value in the RC filter may be changed to a suitable cut off frequency.

Calibration need to be done because of tolerance in components and the USB supply voltage. Step 1: ADC readings depend on the Arduino USB supply voltage. Which is not always 5V. Here https://code.google.com/p/tinkerit/wiki/SecretVoltmeter I found code to measure the Arduino voltage rail. The Arduino power supply voltage is derived from an internal 1.1V reference and then back-calculated. In the “SecretVoltmeter"code I adjusted the 1126400L to 1106706L to match the back-calculated 5V to the actual measured voltage. Step 2: I multiplied load voltage ADC reading with a factor to match it with my multimeter. Step 3: I multiplied load current ADC reading with a factor to match it with my multimeter. Step 4: I multiplied DAC current setting with a factor to match it my multimeter. The accuracy of the voltage and current reading is limited mostly by the 10 bit AD converter. However the current is set with a accuracy of 1.2 mA/bit, which is sufficient to be able to test power supplies.

I ordered the 3 PCBs from OSHPark for just \$25. The boards can be re-ordered here. A solder stencil was ordered from OSHstencils.

Schematic in Eagle and PDF. Layout in Eagle and PDF. Gerber file for PCB. BOM in XLS. Gerber file for Stencil.

There are definitely improvements to be made. One is reverse voltage and over voltage protection of the opamps. Small signal diodes could be used to limit the opamp input voltage between 5V and GND. A second improvement is over load protection. The software should be capable of detecting when the voltage drops too much and reduce the current lineairly. A third improvement is changing the code to apply a pulsed load.

## Software¶

``````  1/*
3 - CC constant current load
4 - CP constant power load
5 - CR constant resistance load
6 Current output, voltage input, and current input calibrated
7 Voltage measurement 10bit 0-30V: 30mV/bit
8 Current measurement 10bit 0-5A : 5mA/bit
9 Power calculation              : 60mW/bit
10 Current setting 12bit 0-5A:      1.2mA/bit
11 */
12
13#include <Wire.h>
16
17int LedPin      = 13;
18int VoltPin     = A1;
19int CurrentPin  = A0;
20
21int VoltPinValue,CurrentPinValue,int_value;
22float VoltPinVoltage,FltVoltPinValue,FltCurrentPinValue,LdVoltage,LdCurrent,LdPower,IntVolt;
23long previousMillis = 0;      //
24int ledState = LOW;           // ledState used to set the LED
25long interval = 500;          // interval to to flash LED
26long ArduinoVccInmV;          // Arduino Vcc voltage
27float SetCurrCalFactor = 1.006;// calibration multiplication factor
28
29static char line;
30boolean haveLine, ret;
31char c;
32
33void setup() {
34  Serial.begin(9600);           // setup serial
35  dac.begin(0x62);              // DAC address with A0 connected to GND
36  pinMode(LedPin, OUTPUT);      // Set LedPin as Output
37  int value=0;                  // from 0 to 4095 is from 0V to 5V
38  int storeflag=false;           // store value in EEPROM (max 20,000 times)
39  dac.setVoltage(value, storeflag); // set the load to default value
40  Serial.println("Type 'cc100' to set 100mA, 'cp100' for 100mW, or 'cr100' for 100 Ohm");
41}
42
44  int result;
46  delay(2); // Wait for Vref to settle
51  //Original code below
52  //result = 1125300L/ result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000
53  //Calibrated code below
54  result = 1106706L/ result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000*(4940/5023)
55  return result; // Vcc in millivolts
56}
57
61  FltVoltPinValue= float(VoltPinValue);      // convert VoltagePinValue to float
62  VoltPinVoltage = (FltVoltPinValue/1023.0)*IntVolt; // calculate voltage on voltage pin
63  LdVoltage = 6.030* VoltPinVoltage;         // calculate load voltage, calibrated
64  Serial.print(LdVoltage);                   // print load voltage
65  Serial.print(" V, ");                      // print load voltage
66  FltCurrentPinValue= float(CurrentPinValue);// convert CurrentPinValue to float
67  LdCurrent = (FltCurrentPinValue/1023.0)*IntVolt*1.034;// calculate load current
68  Serial.print(LdCurrent);                  // print load current
69  Serial.print(" A, ");                     // print load current
70  LdPower = LdVoltage * LdCurrent;          // calculate load power
71  Serial.print(LdPower);                    // print load power
72  Serial.print(" W");                       // print load power
73  if(LdCurrent>5){                        // warn if power is too high
74    Serial.print("Current to high!");
75  }
76  if(LdVoltage>30){                        // warn if power is too high
77    Serial.print("Voltage to high!");
78  }
79  if(LdPower>15000){                        // warn if power is too high
80    Serial.print("Power too high for heatsink!");
81  }
82}
83
84// CONSTANT CURRENT MODE
85void CC(int DesiredmA){    // DesiredmA in mA
86  Serial.print("cc, ");
88  Serial.println("");
89  float value=(DesiredmA/5000.0)*4095.0*SetCurrCalFactor; // calculate value to set the right current
90  int_value=int(value);                               // convert float to integer
91  dac.setVoltage(int_value, false);                   // value from 0 to 4095
92}
93
94//CONSTANT POWER MODE
95void CP(int DesiredmW){
96  Serial.print("cp, ");
98  float SetmA=DesiredmW/LdVoltage;
99  Serial.println("");
100  float value=(SetmA*4095*SetCurrCalFactor)/5000;
101  int_value=int(value);
102  dac.setVoltage(int_value, false); // value from 0 to 4095
103}
104
105//CONSTANT RESISTANCE MODE
106void CR(int Resistance){
107  Serial.print("cr, ");
109  float SetmA=LdVoltage/Resistance;
110  Serial.println("");
111  float value=(SetmA*4095*SetCurrCalFactor)/IntVolt;
112  int_value=int(value);
113  dac.setVoltage(int_value, false); // value from 0 to 4095
114}
115
116bool EditLine(char cin, char *cout, char line[], int size)
117{
118  static int pos = 0;
119  *cout = cin;// echo by default
120  switch (cin) {// carriage return is ignored
121  case '\r':
122    break;
123  case '\n':  // end-of-line
124    line[pos] = '\0';
125    pos = 0;
126    return true;
127  case 0x7F:
128  case 0x08:// backspace
129    if (pos > 0) {
130      pos--;
131    }
132    break;
133  default:
134    if (pos < (size - 1)) {// store char as long as there is space to do so
135      line[pos++] = cin;
136    }
137    else {
138      *cout = 0x07; // bell
139    }
140    break;
141  }
142  return false;
143}
144
145void loop() {
146  ArduinoVccInmV = readVcc();     // returns Arduino internal voltage in mV
147  IntVolt = ArduinoVccInmV/1000.0;// changes mV to Volt
148
149  unsigned long currentMillis = millis();        // flashes a LED
150  if(currentMillis - previousMillis > interval) {// as long as LED is flashing program runs
151    previousMillis = currentMillis;
152    ledState = !ledState;
153    digitalWrite(LedPin, ledState);
154  }
155
156  while (Serial.available() && !ret) {// read from serial until return
157    haveLine = EditLine(Serial.read(), &c, line, sizeof(line));
158    Serial.print(c);
159  }
160
161  if (haveLine) {
162    if (strncmp(line, "cc", 2) == 0) {
163      int value = atoi(line+2);
164      CC(value);
165    }
166    if (strncmp(line, "cr", 2) == 0) {
167      int value = atoi(line+2);
168      CR(value);
169    }
170    if (strncmp(line, "cp", 2) == 0) {
171      int value = atoi(line+2);
172      CP(value);
173    }
174  }// end of if (haveLine)
175
176}//end of void loop()
``````
Add picture from clipboard (Maximum size: 1 GB)
{"ft_lang_label":"__label__en","ft_lang_prob":0.68466014,"math_prob":0.95449793,"size":11285,"snap":"2021-31-2021-39","text_gpt3_token_len":3104,"char_repetition_ratio":0.13261236,"word_repetition_ratio":0.046383213,"special_character_ratio":0.31351352,"punctuation_ratio":0.13926941,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9814312,"pos_list":[0,1,2,3,4,5,6,7,8],"im_url_duplicate_count":[null,2,null,2,null,2,null,2,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2021-07-27T21:54:00Z\",\"WARC-Record-ID\":\"<urn:uuid:ac5b1f13-94ef-4e69-bf1b-2c925634ed43>\",\"Content-Length\":\"54011\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:4bb6c00c-4ec3-4f05-ad80-9f066ddcb49d>\",\"WARC-Concurrent-To\":\"<urn:uuid:978ae030-5076-4563-8a1a-e0451b15bbdf>\",\"WARC-IP-Address\":\"162.219.0.35\",\"WARC-Target-URI\":\"https://mixdown.ca/redmine/projects/mixdown/wiki/Jasper's_Electric_Load\",\"WARC-Payload-Digest\":\"sha1:2CY6Y7ZFOJI3KCQTSHUYNMQTAXBCJV3W\",\"WARC-Block-Digest\":\"sha1:6VLR736HXI7HGBDMNXA47CONR4OHXAKO\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2021/CC-MAIN-2021-31/CC-MAIN-2021-31_segments_1627046153491.18_warc_CC-MAIN-20210727202227-20210727232227-00667.warc.gz\"}"}