2

First post here and I have very little Arduino/c programming knowledge so forgive me my ignorance.

I am processing 18650 cells for a little powerwall project. I am using an Arduino pro mini atmega328p(5v) to read battery slot voltages and to turn on/off the tp4506 when the voltage reaches 3.85 volts for long term storage.

I am getting good voltage readings and after some trouble having a common ground with the tp4506 I think I have isolated it with a couple diodes.

I am using a 30N06L n channel mosfet to switch the tp4506's on and off, shutting them off to get the reading then back on till next voltage reading. I am learning a lot and having fun with it.

My problem stems from me not really having firm grasp of terminology or Arduino C. I cannot find my solution from search engine results after a few hours searching on and off.

I am using a for loop over 3(for now) analogue pins to get my voltage readings. What I can't figure out is how to map those pins to the digital pins controlling the mosfets from the loop. I have a few different versions of this project just trying to get a feel for what is the most efficient way to do it(I like the loop). How do I map or correlate AO with D2 and so forth. It's very frustrating not being able to type what I want out in a way that get's me some code I can learn from so I hope another human can understand my issue.

const int aRefVoltage = 5.00;
float voltage         = 0;  

void setup() {
  // put your setup code here, to run once:
  pinMode(2, OUTPUT);
  Serial.begin(9600);
}

void loop() {
// put your main code here, to run repeatedly:
// read the input on analog pin 0-2

  for (int i = 0; i < 3; i++) {
    int sensorValue = analogRead(i);
    delay(700);

// float voltage = sensorValue * (aRefVoltage / 1024.0);
    voltage = sensorValue*aRefVoltage/1024.0;
// print out the value you read:
    Serial.print( F("  Slot-") );
    Serial.print(i + 1); // +1 to match slot number
    Serial.print( F(" = ") );
    Serial.print(voltage);
    Serial.print( F(" Volts") );

    if (i == 2) Serial.println("     ");
    Serial.println( F("") );
  }

}

What is the smartest way to map analogue "i[0]" to the digital pin 2 to turn on that slots mosfet while using the for loop? Switch case? I hope I was clear enough in my question.

Thank you

edit: inb4 I get chewed out.

I am not looking for the answer to be handed to me. I would like a link to a tutorial that will show me how to use i[1] either in or out of the loop so I can use it....or how to use it. An explanation from my would be hero would be nice too.

My searches all got me very rudimentary for loop examples and endless tutorials on how to turn analogue pins into digital pins. Surprising amount of tutorials on how to do that out there.


edit 2

A ce pin? That sounds handy I will have to look into that. I am sure my use of diodes would make an engineer shake his head. I have limited supplies on hand and this is really my first project where I have a use for my tinkering.

On each analogue pin I have two 10k resistors. One to pull down and the other to prevent the batteries from sending juice back through the analogue pin.

I spent several hours trying to use the 1.1 volt internal reference but even after calculating what my 1.1 actually was my results were not as accurate and it just seemed like slapping a dmm across the rail and dialing the knob on the buck converter was practical.

https://provideyourown.com/2012/secret-arduino-voltmeter-measure-battery-voltage/ and internal1.1Ref = 1.1 * Vcc1 (per voltmeter) / Vcc2 (per readVcc() function)

For diodes I have a 1N4001 between the battery negative on tp4506 chip and ground. If I did not have it there power was flowing back through the chip. I was also playing with a 3v zener on the positive side to block .5 volts to my analogue reading when no battery present in slot.

I have no doubt I am doing it incorrectly I wasn't expecting those issues and was just trying to hack a solution together, luckily my aim is not charging to 4.2 or I would be up a creek.

Thank you again for taking the time to show me the code I needed. I should be able to figure it out from here. As long as I am moving forward I am content. I had been at it for ten hours by the time I broke down and made this post. I was pretty burnt out and knew if I could just see an example I would be good to go.


edit 3

const int aRefVoltage        = 5.00;
const int readVoltagePins[3] = { A0, A1, A2 };
const int chargePin[3]       = { 2, 3, 4 };
const int hysteresis         = 0.10;
float voltage                = 0;

void setup() {
  // put your setup code here, to run once:
  for (int i = 0; i < 3; i++) {
    pinMode(chargePin[i], OUTPUT);
  }
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  // read the input on analog pin 0-2

  for (int i = 0; i < 3; i++) {
    digitalWrite(chargePin[i], LOW);
    delay(1500);
    int sensorValue = analogRead(readVoltagePins[i]);
    float voltage = (float) sensorValue * (5.0 / 1024.0);

    // Write here code to turn on the digital pin on (once) if the voltage
    // is too low and off (once) with hysteresis.
    // The digital pin is: chargePin[i]

    if (voltage <= 1.50) {
      digitalWrite(chargePin[i], LOW); 
      Serial.print( F("  Slot-") );
      Serial.print(i + 1); // +1 to match slot number
      Serial.println( F(" = NFG || Empty ") );
      break;
    }

    else if (voltage <= (3.85 - hysteresis)) {
      digitalWrite(chargePin[i], HIGH);
      Serial.print( F("  Slot-") );
      Serial.print(i + 1); // +1 to match slot number
      Serial.print( F(" = ") );
      Serial.print(voltage);
      Serial.println( F(" Volts & Charging") );
    }

    else if (voltage >= (3.85 + hysteresis)) {
      digitalWrite(chargePin[i], LOW);
      Serial.print( F("  Slot-") );
      Serial.print(i + 1); // +1 to match slot number
      Serial.print( F(" = ") );
      Serial.print(voltage);
      Serial.println( F(" Volts & !Charging") );
    }

  }
  delay(5000); // increase later
  for (int i = 0; i < 3; i++) {
      if (i == 2)
      Serial.println("     ");
  }
}

This is what I have for code for now. I am just leaving the b- disconnected on the cloned charging boards. Let me know what you think @Jot

2 Answers 2

2

Is the programming code for A0 to D2 the same as for the other pins ? Then you could put the pin numbers in an array and run them in a for loop.

The TP4056 has a CE pin, why don't you use that to turn then on and off ?

The accuracy of reading a voltage with an Arduino depends on the accuracy of the voltage reference. You use the VCC 5V as reference. Is your 5V a stable and accurate 5.00V ? Did you measure the 5V pin of the Arduino board ?

Did you protect the analog inputs with a resistor ?

What did you do with the diodes ? Can you show a schematic (it can be a photo of a drawing) ?

An array with analog pins and digital pins:

const int readVoltagePins[3] = { A0, A1, A2 };
const int chargePins[3] = { 2, 3, 4 };

In the setup, set the digital pins as outputs:

for (int i=0; i<3; i++) 
{
  pinMode (chargePins[i], OUTPUT);
}

In the loop, use a similar for-loop. I declare the locally used variables locally.

for (int i=0; i<3; i++)
{
  int sensorValue = analogRead(readVoltagePins[i]);
  float voltage = (float) sensorValue * (5.0 / 1024.0);

  // Write here code to turn on the digital pin on (once) if the voltage
  // is too low and off (once) with hysteresis.
  // The digital pin is: chargePins[i]
}

Reaction to edit 3

The idea of StackExchange is to have a question with an answer. Both the question and the answer can be polished along the way to create something that is helpful for others.
Developing a Arduino sketch is something else. I don't know either what the best way is to reply.

What about taking the average value of about 30 (5 to 1000) samples ? If the voltages are not steady, then averaging will help a lot.

The internal voltage reference of 1.1V is not bad, but the actual voltage can be between 1.0 and 1.2V. It is different for each Arduino board. You can measure the AREF pin with a multimeter after setting the 1.1V reference and put the measured voltage in the sketch in the calculation.
If the power to the Arduino board is a good 5.0V and the Arduino is always at the same room temperature, then the internal voltage of 1.1V can be used to measure a battery with 20mV accuracy, and perhaps 5mV with a lot averaging.

You use a delay to slow down the sketch. It is okay to do a digitalWrite over and over again during charging or during idle. In the comment I wrote to do that once, because I was anticipating to use millis instead of delays.

Because of the delay, the if_else_if_else_if is nice and straightforward code.

An integer can not be 5.0 or 0.10. Please check your whole sketch for 'float' versus 'int'. If floating point is needed, then use floating point. The voltage is a 'float', therefor it is best to use 'float' everywhere the voltage is used, for example the hysteresis.

I still don't understand the diodes. Can you make a schematic ?
Using a mosfet is probably okay, but I have to see the schematic.

10
  • I am not sure the correct way to reply to you so I edited my question.
    – ether
    Commented Nov 12, 2017 at 4:42
  • While looking into the ce pin I realize that I have clones of the tp4056. I have a tc4056 and a 4056e. Talk about rabbit holes. The data sheet on the tc doesn't show a ce pin for 8 but a chrg. Is there anything wrong with using the mosfet to supply/cut power to these clones? jimlaurwilliams.org/wordpress/?p=4731
    – ether
    Commented Nov 12, 2017 at 6:35
  • @ether Added a section: Reaction to edit 3
    – Jot
    Commented Nov 12, 2017 at 14:32
  • I can't thank you enough for your input. I have 3 slots working well, I will fix the float/int issue, easy enough. I also have to work out the hysteresis a bit better, maybe save the last read and compare. I installed fritzing this morning but then got sidetracked. I will try and get to it but the weekend is almost over so don't hold your breath. The diodes aren't being used. Solved by just leaving the bat - unattached. Not sure how cool that is but it is working just fine as is.
    – ether
    Commented Nov 12, 2017 at 17:28
  • Also as for the voltage readings. They are consistently .01 volt off of my meter. Since the initial function is to get to 3.85 for storage I am not too concerned about the accuracy just yet. I have noticed that all the batteries I have brought up to 3.85 sag back down after a few loops also. I am assuming it is saturation of sorts. Until the next phase I would be content with less accuracy.
    – ether
    Commented Nov 12, 2017 at 17:36
0

What I can't figure out is how to map those pins to the digital pins controlling the mosfets from the loop.

you probably will have to do a better job articulating what "mapping" an analog pin to digital pins means.

If the issue is "associating" an analog pin with a digital pin, a struct would do, like this:

typedef struct {
  uint8_t apin; //analog pin
  uint8_t dpin; //digital pin associated with the analog pin
} PIN_TYPE;

PIN_TYPE pins1, pins2; //two sets of pins

 ...
 if (analogRead(pins1.apin) < BAT_THRESLOW) turn_on(pins1.dpin); //if voltage is too low, start charging it
 if (analogRead(pins2.apin) > BAT_THRESHIGH) turn_off(pins2.dpin); //if voltage is too high, stop charging.

Obviously, the logic should be more comprehensive to avoid oscillation.

1
  • Dear @dannyf, due to a mistake my "Reaction to edit 3" got somehow into your answer. Please ignore or remove it.
    – Jot
    Commented Nov 12, 2017 at 14:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.