12V Battery Tester

A tester that can be used by high school students to test the batteries for capacity.

Similar projects worth following
Testing a 12V car battery can have its capacity tested by discharging it at a certain amperage until the voltage drops to 10.5V. The time that it takes will differentiate a battery that has more capacity.

The amperage that the battery will maintain is 38 - 40 Amps. This would be a simple load operation that will maintain a a constant current, but as the voltage drops the load will have to change. This is done by switching loads in and out of circuit.

To control this circuit a device will have to monitor current (for over/under current scenarios) and voltage (controlling the loads off of this variable).

The device that controls the resistor banks usage and monitoring voltage and current will send this information out of an RS232 port so an external device can log this information into a csv file. From there a student can use this information in a program like excel. This might show other trends in the data.

This project goes over the design of this system.

This tester can be broken down into a few sections:

Controller (Arduino UNO)

Loads (Resistors and Heater Coils)

Output control (Relay Board)

Input Sensor (Current Sensor and Voltage divider)

Data Logger (Computer running software)

The controller uses an UNO. This will monitor the input sensors and control the resistor banks to apply loads to the battery. The selection of when to turn the resistor bank on or off is based on the voltage sensed and the known resistances of the loads. By placing the lowest valued resistor on bank 1, the second lowest on bank 2, the third lowest on bank 3 etc until bank 7 has the highest valued resistance. The UNO then calculates the current that would flow through with the applied voltage. If the amperage that is required (starting at 40 amps) is greater than the amperage that the resistor bank can supply, then the bank is turned on. The calculated resistor amperage is then subtracted from the last known amperage requirement. This value is saved and the next resistor banks amperage is calculated. This value is then checked to see if it is lower than the remaining current that is required. etc.

The loads that were used was a mix. I did not want to spend too much money on the wattage requirements of the resistors. Digging through my parts bin, I found some old heater coils from an old electric dryer that we fixed. The dryers coils were replaced with new coils as these old ones failed in one location. Instead of throwing them away, I held onto them and am glad that I did. By cutting them down I could get approximately 3 ohm segments that could be paralleled to create low ohm resistances that could handle the watt dissipation. One was cut down to 2 ohms, but that is pushing it to the point of glowing a dull red. Using a fan to blow across it prevents it from glowing.

The heater coils took care of the heavy loads, while a 10 ohm and 10x 47 ohm resistors took care of the rest. 5 each 47 ohm resistors were paralleled to roughly create 10 ohms.

To sense the voltage of the battery, a simple voltage divider is used. The values used are 2k and 10k ohms. The 2k was connected to 12V ground which was also tied to the Arduino ground. Selecting a lower ohm value for the bottom resistor allows for the voltage divider to sense up to 27V. The first picture above shows the Seeed Studios board with the two resistors to the left.

To sense the current a DFRobot 50 Amp Current Sensor was used. This can measure +/-50 Amps DC. It outputs an analog signal whose spec can be found here:

To be used as a verification, a shunt ammeter with a display was used. This is located on the back of the controller.

Since the Arduino cannot control 40 amps directly, some reays were used to control those loads. An 8 channel 5V control relay board was found on ebay. This allows for controlling of 10A/channel.

Unfortunately, the loads on bank 1 and 2 are above 10 A, so a couple of 40 A relays were used. These were purchased from an Automotive parts store.

To log the data that the Arduino pumps out of its USB port, a simple logging program was created.

This displays the data on a graph and also shows the last known data from the Arduino below. There is a protocol setup and is as follows:

Program Status, Time (mS) of data, Voltage (divide by 100), Current (divide by 10), Resistor Bank Status, Arduino Voltage

The resistor bank status is currently not used. It was to show what banks are are on/off. After the test is complete, the student can save the data that has been accumulated to a csv file. From there it can be imported/manipulated in excel.

Running a Test:

To start, first connect the battery to the lugs on the back of the controller box:

Once connected (along with the loads connected), connect the Arduino to the computer. Startup the Battery Tester program and locate the com port associated with the Arduino. This can be found by looking the device manager and locating "Arduino UNO". In the screen...

Read more »

  • 1 × Arduino UNO
  • 1 × 8 Channel Relay Board 5V This was purchased off of ebay for around $10. It had relays capable of 10A
  • 2 × 40A 12V Relay Purchased from an automotive store.
  • 1 × Dryer Heater Coils Two sections of Heater coils were cut up to create the half ohm, 1 ohm, 2 ohm and 3 ohm loads.
  • 1 × 10 ohm 25W resistor A scrap 10 ohm resistor that was available

View all 15 components

  • Accuracy/Consistency Concerns

    willbaden01/28/2015 at 01:53 0 comments

    After deliberating to find a better/more consistent method to read voltage and current, I decided to rewrite the calculations for the voltage and current using double type instead of integer type. Maybe I was losing accuracy/consistency there. So below is what I came up with:

      double tempCalculate ;
      double tempAnalogValue ;
      //Save actual Vcc read when compared to on board 1.1V reference
      ActualVoltage = (double)readVcc() / 1000;
      CurrentTime = millis();
      //Read battery voltage.  Need to rescale this according to actual sensor used
      tempAnalogValue = analogRead(VoltageSensor);
      //calculate the voltage from the pin
      tempCalculate = (tempAnalogValue / 1023) * ActualVoltage;
      //calculate the voltage of the 12V source through the voltage divider
      // and prepare to convert back to integer (*100)
      tempCalculate = tempCalculate * 27.25 / 5 * 100;
      BatteryVoltage = (int)tempCalculate;
      //Read in Current.  Need to rescale this according to actual sensor used
      tempAnalogValue = analogRead(CurrentSensor);
      //calculate the voltage from the pin
      tempCalculate = (tempAnalogValue / 1023) * ActualVoltage;
      //calculate amperage from 40mV/A with a 2.5V center
      // and prepare to convert back to integer (*10)
      tempCalculate = (tempCalculate - 2.5) / .04 * 10;
      BatteryCurrent = (int)tempCalculate;
      //Offset current and voltage value according to user definition
      BatteryVoltage = BatteryVoltage + VoltageOffset;
      BatteryCurrent = BatteryCurrent + AmpOffset;

    After running this, it still appears that there is drift as the test goes on, so I don't seem to nail down the current and voltage as I thought I could.

    Rework on Voltage measurements:

    Maybe the voltage divider calculation needs to be more accurate in the scale. Possibly causing a scaled shift as the voltage goes through different values. Or the 1.1V reference is not as accurate as it needs to be.

    Rework on Current measurements:

    Maybe the robotshop current sensor is not as accurate as I had envisioned. Possibly look into tapping into the shunt ammeter and pipe that information over to the UNO. Or the 1.1V reference is not as accurate as it needs to be.

    To shift to a different voltage reference instead of the internal 1.1V reference will just be a matter of adding a chip to the protoshield. This at least would remove the doubt of the 1.1V reference.

  • Test Run with 5V Regulation

    willbaden01/17/2015 at 22:20 0 comments

    The battery tester has been ran with the 5V regulator feeding the relay board. The UNO's voltage now locks in and does not fluctuate with the changing states of the relays. Here is an excerpt from the run:

    Program Run 0 1240 -2 11001 4962
    Program Run 5 1069 335 11101 4940
    Program Run 10 1058 392 11101 4940
    Program Run 15 1058 389 11101 4940
    Program Run 20 1058 387 11101 4940
    Program Run 25 1056 386 11101 4940
    Program Run 30 1053 384 1111101 4940
    Program End 35 1048 397 0 4940

    This test and the prior versions test can be found on github.

  • 5V Regulator

    willbaden01/16/2015 at 12:23 0 comments

    To prevent the Arduino voltage regulator from fluctuating, a 5V L7805CV voltage regulator was added. This will power the relay board that turns the loads on and off. The battery under test will be supplying the power for the relay board. This is being tapped off the 12V voltage divider on the top prototyping board. Here is a picture of the completed regulator:

    The 100uF capacitor is on the output side of the regulator. The Red connector to the right of the cap is the power out to the relay board and the L7805 is next to the connector. Between the connector and regulator are the .33 and .1 capacitors of the regulator. They can't be seen in the above photo. In the photo below is another view of the board but now it is installed on the UNO.

    The next step is to test it out.

  • Voltage/Current Reading Offsetting

    willbaden01/04/2015 at 02:28 0 comments

    After placing a cage around the ends of the high power resistor loads, a test was ran with the new amp meter to verify the robot shop amp meter was being properly read by the UNO. Here is the excerpt of that first test:

    Program Run 55 1054 399 1101 4834
    Program Run 60 1056 404 1101 4855
    Program Run 65 1056 404 1101 4855
    Program Run 70 1051 399 1101 4834

    Keep in mind that the layout of the comma separated values are:

    Program State, Time, Voltage, Current, Resistor loads active, UNO USB voltage

    Looking at time stamps 65 and 70 shows the USB voltage changed values along with the current and voltage readings. The external ammeter and voltmeter were not fluctuating this drastically. This appeared that the USB voltage that was seen by the UNO was affecting the reading of the current and voltage.

    A discrepancy was also seen in the overall reading that was adjusted out with the newly added offset feature. But the adjustment was not able to correct the change in readings as the USB voltage fluctuated. This can be seen by the next test:

    Program Run 15 1060 379 1101 4897
    Program Run 20 1057 404 1101 4834

    Wanting to get rid of the fluctuation, I chose to use an external 9V supply to feed the UNO. This still did not fix the problem as seen by the next test:

    Program Run 70 1135 398 101 4897
    Program Run 75 1137 401 101 4918
    Program Run 80 1133 397 101 4897

    At this point, I started to wonder if it was the external supply or the 5V regulator built into the UNO board. I knew the Relay board could pull a load, but this load may be more than the UNO could supply. To bypass this, I placed an external supply feeding directly into the relay board and USB voltage only to feed the UNO. This did work as seen by the test results:

    Program Run 75 1104 370 101 5051
    Program Run 80 1108 373 101 5073
    Program Run 85 1101 370 101 5051
    Program Run 90 1101 369 101 5051
    Program Run 95 1098 369 101 5051

    The voltage reported by the UNO locked into 5.051V and only once deviated to 5.073V. Along with this, by using the correct offsets for voltage and amperage, the UNO reported values consistent with the external ammeter and volt meter.

    The next step is to install a dedicated 5V regulator that will only feed the relay board and be fed by the 12V battery. This will cause a small deviation in the current readings if wired before the ammeters. This will have to be installed after the ammeters so that they will see the current flow.

    The problem that I do have with this discovery is that the calculations to correct for this discrepancy were not working. This will also be looked into further.

  • Resistor Load Assembly

    willbaden12/25/2014 at 16:16 0 comments

    Wanting to keep the heating coils contained, a cage was built. It was built out of some scrap dividers that were originally used in an office desk. The heater coils rods were mounted to pcs of plexiglass that were then attached to the re-purposed steel dividers. The plexiglass was used to isolate the heater coil buses from the steel dividers.

    A single feed was used for the negative side of the loads (black wire on bottom of above picture) and multiple wires were ran to the different loads of the heater coil (red wires of above picture). These were then wired up into the controller box:

    Eventually, I would like to added perforated steel to completely cage in the coils. That material has yet to be purchased.

  • Controller Box

    willbaden12/07/2014 at 14:37 0 comments

    Wanting to clean up the build, I have been slowly working on fitting the controller into a an old UPS box.

    This is an old failed UPS that would be able to fit all the circuitry inside and leave plenty of room.

    After gutting the UPS I could start placing components inside. First to find a location for the UNO. I wanted this to stay towards the front as the back panel had multiple holes from the UPS. It became apparent that a right angle mount for the UNO was needed. Below is a picture of the finished product. I used some 4-40 aluminum standoffs that needed to be turned on one side to allow for clearance of the pins. There is a screw missing in the picture, but it was included in the install.

    This mount was fastened to the front panel. There was a square port that allowed for the USB connection, but had to open a hole for the power plug of the UNO. Below on the bottom is the relay board. It is using some 6-32 standoffs I made for a different project and just repurposed. Moving to the right is the current sensor. I used some Delrin to mount the current board to. It has four holes, two patterns. One set of holes for the current board mount and one set to mount the delrin to the box.

    Looking at the back of the box, I mounted a terminal block that will be used for the 12V side of the circuit. In the picture, the clear plastic mounting for the lugs of the outputs can also be seen.

    When testing the current sensor circuit, I was not satisfied with the consistency of the current readings. As a fail safe I added a 50A shunt ammeter. This will be a double check that the calculations the UNO is producing is the same as a dedicated ammeter. The shunt can be seen in the below left. It is the long black strip with the black wires coming off of the silver blocks. The ground from the 12V battery is fed through the hall effect sensor the UNO uses, then is fed through the added shunt, and finally fed out the back of the box to be fed as a common to the testing loads.

    Here is a mid build picture as the wiring is being added.

    Finding a place for the shunt ammeter LCD was another trial, but ended up working out placing on an aluminum plate that also has the high amp relays. The relays are below the plate with the connections to the left (large yellow connectors). Using the undercut feature of CamBam allowed for easy installation of the LCD display.

    Here is a side overall view of the top plate with the relays underneath:

    To allow for easy attachment of varying loads, I ended up with a lug of connections. Smaller screws for the smaller loads and a larger screw or the larger load. The top row is the outputs for Resistor banks 2-7 (left to right). Below the row on the left is the positive input (battery) lug with the negative input (battery) lug below that. On the right, just below the row of resistor bank outputs, is the lug for resistor bank 1. The lower right lug is the common (12V gnd) to be fed to all the resistor banks.

    This has been tested to the point of relay/UNO operation, but it has not been tested in a loaded scenario. Prior to running that test, a resistor bank box is being built to make for easier use.

  • Proto Board

    willbaden11/26/2014 at 02:59 0 comments

    To create more of a finalized installation, a Seeed Studio protoshield was purchased. This was populated with the minimal required circuits/connections. Here is the final proto board populated:

    Analog 0 will read the Current sensor. The current sensor will connect to one of the 3 pin connectors (yellow rectangle). The voltage divider attaches to the second 3 pin connector (red rectangle) and uses the outside two pins for GND and the center pin for 12V. This GND is bonded to the ground of the 5V supply on the Arduino. There is also a 2 pin header that will feed 5V power to the relay board (blue rectangle). This feeds power to the control circuits of the relay board. The control outputs to the relay board will attach via 2 connectors (purple rectangle). Using outpus 2 - 8.

  • V0_06 Test

    willbaden11/21/2014 at 03:36 0 comments

    Testing of the code that references the 1.1V to the supply voltage and calculating the supply voltage appears promising. The voltage differential between a voltmeter and the Arduino was within .5 volts around 11.5V battery voltage. The actual voltage of the USB power supply did vary from 4.7 - 4.9 volts. These values can be seen in the csv file V_06_Test as seen in the test folder of the batterytester github page. The Current calculations code was adjusted to the following:

    BatteryCurrent = analogRead(CurrentSensor);

    BatteryCurrent = map(BatteryCurrent, 0, 1023, 0, ActualVoltage);

    BatteryCurrent = map(BatteryCurrent, 500, 4500, -500, 500);

    This removed one of the remaps. Instead of going to 0-1023, and then to amperage readings, it converted to voltage and then to current readings.

    While doing the testing of the voltage, the current reading appeared to be incorrect. It was measuring low. Instead of 38 - 40 it was measuring around 35. I reloaded the Resistor_Bank_Testing program (after being modified with the actual power supply voltage adjustment) into the Arduino to see what current values were comparing to an ammeter reading. Only banks 4 - 7 could be tested due to being below 10 Amps. Currently I do not have access to a 50A ammeter. The amperage difference was 1.3 Amps. An ammeter was measuring 4.4 amps while the DFRobot 50A ammeter was reading 3.1 amps. Thinking this might be an Arduino issue, I checked the output voltage of the DFRobot sensor. This was within .02V of what the Arduino measured. Which was around 3 amps. There is some error showing up with this meter.

    The most I can attribute to this error, is that it was 38 degrees F in the workspace. Possibly this was causing the error?

  • V_05 Test with Deadband

    willbaden11/19/2014 at 03:32 0 comments

    V_05 of the Arduino program was tested to see if the Deadband would function correctly, so far, it appears that it does. Granted there was not much time to test as I was short on time. To check out the data from this test:

    View V_05_Test_Results.

    This may not be enough test time to verify that it is ok, but it does look promising. Towards the end of the test, I was trying different test spots for the voltage sensor input. Ultimately, I think having a known reference instead of relying on 5V USB voltage is the way to go. I have not tested the voltage of the USB port, but I imagine (seeing the voltage results) it is not very consistent.

    There are analog references that can be used on the UNO and a helpful site from Tinkerit gives a possibility:

    This would allow to check what the supply voltage actually measures when compared to the 1.1V reference. The map function is utilized to massage the values used (ActualVoltage is the return of the actual VCC voltage):

    // The voltage appears to stay higher by another .15V

    BatteryVoltage = analogRead(VoltageSensor);

    //remap to have the actual voltage of the analog input

    BatteryVoltage = map(BatteryVoltage, 0, 1023, 0, ActualVoltage);

    //remap 0-5V range to calculated voltage divider range.

    BatteryVoltage = map(BatteryVoltage, 0, 5000, 0, 2725);

    //Read in Current. Need to rescale this according to actual sensor used

    //Up to 6.5 Amps the current sensed on the RobotShop was consistent

    // with an ammeter

    BatteryCurrent = analogRead(CurrentSensor);

    //remap to have the actual voltage of the analog input

    BatteryCurrent = map(BatteryCurrent, 0, 1023, 0, ActualVoltage);

    //remap current to 0-5V range

    BatteryCurrent = map(BatteryCurrent, 0, 5000, 0, 1023);

    //remap to current values

    BatteryCurrent = map(BatteryCurrent, 101, 922, -500, 500);

    This will need to be tested when I can get another chance.

  • First Battery Drain Test

    willbaden11/14/2014 at 03:12 0 comments

    The first battery test utilized the following program versions:

    Arduino V0.04

    Windows Program V0.02

    Batteries voltage at start of the test (unloaded) 12.1V.

    The logging program functioned correctly and was able to start the test, allow it to run its course until the battery was drained below (what it sensed) 10.5V, and allowed for the data to be saved to a csv file.

    The arduino had a few problems:

    1. The battery voltage is still not reading accurately. When running the test, I checked the voltage of the battery with a voltmeter. The following was observed:

    Program Voltage 11.64V: Actual Voltage 11.53V

    Program Voltage 11.42V: Actual Voltage 11.37V

    Program Voltage 11.21V: Actual Voltage 10.99V

    Program Voltage 11.16V: Actual Voltage 10.91V

    Program Voltage 11.08V: Actual Voltage 10.84V

    Program Voltage 11.00V: Actual Voltage 10.59V

    Program Voltage 10.68V: Actual Voltage 10.27V

    So as the battery drained, the voltage differential increased. The scaling of the voltage will need to be rescaled, or a different measuring device will be needed.

    2. As the battery voltage dropped, there were ranges where the relays would kick in and out the loads causing drastic changes between the samples. Here is a sample of the data within one of these ranges:

    Arduino Status, Time(seconds), Voltage/100, Current/10, Active Resistor Banks

    Program Run,470,1134,401,0010101,

    Program Run,475,1153,409,0000101,

    Program Run,480,1134,401,0010101,

    Program Run,485,1153,411,0000101,

    Program Run,490,1134,401,0010101,

    Program Run,495,1153,409,0000101,

    Program Run,500,1132,400,0010101,

    At first glance it appears that as a load turns on, the voltage drops. When the voltage drops, the calculated loads requires adjusts. Then the voltage rises, causing the calculations to adjust the loads again. This seems to be related to the resolution of the loads. Either the loads can be adjusted for more resolution or the program could be adjusted to allow for a dead zone.

    3. As the battery reaches near the bottom of its voltage test (10.5V), then there is a chance that a load will change and cause the voltage to drop drastically below the 10.5V due to the increased load. This might be linked to internal resistance in the battery. Here is what happened in the first test:

    Program Run,1466,1070,387,0110101,

    Program Run,1471,1070,386,0110101,

    Program Run,1476,1068,385,1110101,

    Program Run,1481,1081,394,0110101,

    Program Run,1486,1065,386,1110101,

    Program Run,1491,1078,392,0110101,

    Program Run,1496,1060,383,0001101,

    Program End,1501,1033,403,0000000,

    In the last few lines, the load increased enough to pull the voltage down below 10.5V. If the program was allowed to continue on, the loads would have increased which would cause the voltage to drop even further. This is tied to number 2 on this list and should be revisited after 2 is smoothed over.

    In the order that these issues are listed should be the order that they are solved.

View all 10 project logs

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates