Sunday, November 5, 2017

How to Build a Simple DC Electronic Load with Arduino Part 2

In this video we look at how to make a simple DC electronic load with Arduino and some simple components. In part two 2 we add some flexible measurement capabilities.







//***************************Arduino Code*************************************************
#include <Average.h> /* * This code was used for a tutorial on how to build a simple eload with Arduino * The Tutorial can be found on the ForceTronics YouTube Channel * This code is public domain and free for anybody to use at their own risk */ //Uncomment AVGMEAS to print out avg measurement data and uncomment FASTMEAS to print fast voltage or current measur #define AVGMEAS //#define FASTMEAS //uncomment to print fast current measurements, leave commented to print fast voltage measurements //#define FASTAMP //The following variables set the eload sequence const int sValues[] = {20,50,280}; //set the DAC value for each step const unsigned long sTime[] = {350,50,15}; //set the dwell time for each step const int sNum = 3; //number of steps in the sequence, this number should match the number or items in the arrays long repeat = -1; //set the number of times the sequence repeats, -1 means infinite //The following variables control the measurement rates int measInterval = 5; //in milli seconds, fast measurement rate. This should be less than or equal to measAvgInt int measAvgInt = 1000; //this is done in milliseconds and should be a multiple of the meas interval int aCount = 0; //tracks where we are in the sequence unsigned long sStart; //trcks when a sequence step starts its timer unsigned long mStart; //tracks when a new measurement interval starts unsigned long aHours = 0; //holds amp hour value const unsigned long m2Hours = 360000; //constant value for converting mil sec to hours const float lRes = 5.08; //exact value of eload resistor --> 5.08 const float rMult = 1.51; //multiplier for resistor divider network: R1 = 5.08k and R2 = 9.98k ratio is 9.98 / (9.98 + 5.08) = .663 --> 1.51 const byte aDCVolt = A2; //ADC channel for measuring input voltage const byte aDCCurrent = A4; //ADC channel for measuring voltage across resistor Average<float> voltMeas((measAvgInt/measInterval)); //create average obect to handle voltage measurement data Average<float> currMeas((measAvgInt/measInterval)); //create average object to handle current measurement data void setup() { pinMode(A0, OUTPUT); //A0 DAC pin to output analogWriteResolution(10); //default DAC resolution is 8 bit, swith it to 10 bit (max) analogReadResolution(12); //default ADC resolution is 10 bit, change to 12 bit Serial.begin(57600); analogWrite(A0, sValues[aCount]); //Set DAC value for first step sStart = mStart = millis(); //start timer for seq and measure interval } void loop() { while(repeat > 0 || repeat < 0) { //loop controls how often sequence repeats //timer for changing sequence step if(timer(sTime[aCount],sStart)) { aCount++; //go to next sequence step if(aCount >= sNum) aCount = 0; //if at end go back to beginning analogWrite(A0, sValues[aCount]); //Set DAC value for step sStart = millis(); //reset timer } if(timer(measInterval,mStart)) { voltMeas.push(inputVolt(aDC2Volt(analogRead(aDCVolt)))); //push value into average array currMeas.push(inputCurrent(aDC2Volt(analogRead(aDCCurrent)))); //push value into average array //print input voltage value and current values #ifdef FASTMEAS #ifdef FASTAMP Serial.println(currMeas.get((currMeas.getCount() - 1))*1000); //serial print out of fast current measurements #else Serial.println(voltMeas.get((voltMeas.getCount() - 1))); //serial print out of fast voltage measurements #endif #endif mStart = millis(); //reset timer } //print out average, max / min, and amp hour measurements if(voltMeas.getCount() == (measAvgInt/measInterval)) { #ifdef AVGMEAS Serial.print("Average voltage: "); Serial.print(voltMeas.mean()); Serial.println(" V"); //get and print average voltage value float mA = currMeas.mean()*1000; //get average current value in mA Serial.print("Average current: "); Serial.print(mA); Serial.println(" mA"); //print current value Serial.print("Max voltage: "); Serial.print(voltMeas.maximum()); Serial.println(" V"); //print max and min voltage Serial.print("Min voltage: "); Serial.print(voltMeas.minimum()); Serial.println(" V"); Serial.print("Max current: "); Serial.print(currMeas.maximum()*1000); Serial.println(" mA"); //print max and min current Serial.print("Min current: "); Serial.print(currMeas.minimum()*1000); Serial.println(" mA"); float aH = ampHoursCal(measAvgInt,mA); //calculate how much amp hours of current was consumed since start if(aH < 1000) { Serial.print("Amp hours of power source: "); Serial.print(aH); Serial.println(" uAh"); } //print current in uA else { Serial.print("Amp hours of power source: "); Serial.print(aH/1000); Serial.println(" mAh"); } //print current in mA #endif voltMeas.clear(); //clear voltage measurement array currMeas.clear(); //clear current measurement array } if(repeat > 0) repeat--; //increment repeat if not infinite loop } } //timer function that runs in mill second steps. //Inputs are timer interval and timer start time bool timer(unsigned long tInterval, unsigned long tStart) { unsigned long now = millis(); //get timer value if ((now - tStart) > tInterval ) return true; //check if interval is up return false; //interval is not up } //converts raw ADC reading to voltage value based on 3.3V reference //input is 12 bit ADC value float aDC2Volt(int aDC) { return (((float)aDC/4095)*3.3); } //function converts voltage value to input voltage value based off resistor voltage divider constant //input is measured voltage float inputVolt(float aVolt) { return (rMult*aVolt); } //converts voltage measurement at load resistor to current measurement based on load resistor value //Input is measured voltage float inputCurrent(float rVolt) { return (rVolt/lRes); } //This functions calculates amp hours //amp hour = amp hour value + (amps * (mil sec / 360k) //input: measInt is measurement interval in milli sec and aVal is the measured current value in mA float ampHoursCal(int measInt, float aVal) { aHours = aHours + (aVal * ((double)measInt/m2Hours)*1000); //this converts currect measurement to mA return aHours; }



4 comments:

  1. very interesting post.this is my first time visit here.i found so mmany interesting stuff in your blog especially its discussion..thanks for the post! Best Makeup Brush Sets

    ReplyDelete
  2. I think your schema is missing a RC filter on the current measurement. The reason for this is that analogWrite is a PWM signal therefore you may get so much noise that actually, when looking at the pattern, does not correspond to a typical noise pattern. What you might be measuring is the PWM signal where the duty cycle is at the measurement point in time is, sometimes at 5v and some other times at 0v. I made use of a 100K/0.1uF RC filter that gives me a beautiful signal with out "noise". Another thing I missed is the common ground between the Arduino board and the circuit to get a common ground reference.

    ReplyDelete
  3. Naturally, the RC can be moved onto the "DAC output" so the source get loaded by a steady DC signal and not by a PWM one.

    ReplyDelete
  4. I get this error: expected unqualified-id before token in line below please help, I'm new at this.
    float mA = currMeas.mean()*1000; //get average current value in mA

    ReplyDelete