Go Down

Topic: How to programatically determine if my Arduino is running from USB power or VIN? (Read 3095 times) previous topic - next topic

tfabris

Please forgive me if I'm asking a Frequently Asked Question here. I've been googling and forum-searching for a while and I can't find the answer. If this is in a FAQ somewhere, I'd be grateful if someone could give me a link with the answer.

Background:
I am writing code for the Arduino Uno. It is driving a daughterboard of my own design, and the daughterboard contains some relays which require an external power voltage, so I must power the system using a 12v wall-wart with enough juice to drive the relays (the arduino itself is not strong enough to drive them). I am also using the USB connector on the arduino as a serial communication command/control line, connected to host pc at the same time. So the interesting thing about this project is that it will be connected to two different power sources at the same time to operate correctly. It is connected to the wall wart, and it is also connected to the host PC via USB.

The problem:
The end-user might plug in the USB cable without plugging in the external wall wart power supply. If they do that, the Arduino code will run fine, the LEDs will light up, but the relays will not switch. In other words, it will look like the device is only partially working.

My question:
Using the Arduino programming language running on the Arduino itself, how can I make my code behave differently depending on whether the arduino is getting its power from the USB cable, or getting its power from the power jack?

I want the code to do something like this:
Code: [Select]

if (ExternalPower == TRUE)
   {
    Serial.println("Arduino is correctly powered by an external power source.");
    TurnOnTheGreenLED();
    RunMainProgramCode();
   }
else
    {
      While (1)
          {
             Serial.println("ERROR: Arduino is not plugged into an external power source.");
             TurnOnTheRedLED();
             DoNothing();
          }
   }


If this can be done entirely in code without any special circuitry, then what is the technique?

If this requires some sort of special trick, such as connecting the VIN pin back to an analog input pin, and then reading that pin, then that would be an acceptable solution. However, I don't know just how to do that without blowing the Arduino. The external power supply is 12v 500ma, and I don't want to overload the Arduino. What would be the correct circuit to accomplish this? And what would the resulting code look like?

majenko

You can measure the current chip supply voltage using the internal ADC and 1.1v voltage reference.

I have found that when connected to the USB of my laptop I get 5.12v.  When running on the wall wart through the internal voltage regulator I get 5.04v

The actual USB voltage may vary from computer to computer.

You can get the Vcc monitoring code here:  http://code.google.com/p/tinkerit/wiki/SecretVoltmeter

Nick Gammon


The external power supply is 12v 500ma, and I don't want to overload the Arduino. What would be the correct circuit to accomplish this? And what would the resulting code look like?


Run the Vin through two resistors as a voltage divider, that can bring the voltage down to an acceptable level. Then measure that through an analog pin.

eg.




That circuit would cut 12V down to 4V. Thus an analogRead would return (around) 819 (being 4/5 * 1024). But with only USB input it would be much lower.

Code: [Select]
void setup ()
{
  Serial.begin (115200);
}

void loop ()
{
  if (analogRead (A2) > 400)
    Serial.println ("12V connected");
  else
    Serial.println ("USB only");
   
   delay (1000);
}


(Actually Vin would be a bit less than 12V because of the protection diode but you would be able to easily tell the difference between the two).
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Nick Gammon

Quote
Code: [Select]
      While (1)


Change that to "while (test if power not connected)" so they can plug in the wall-wart and have it recover without having to reboot.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

majenko

That would require hardware changes - the OP wants software only.  The on-board regulator will give the same reading whatever the input voltage.  Compare it to the 1.1v Vref, and if it is the voltage that the voltage regulator gives you then you are running on wall wart.  If it's anything else, then you're on USB.

tfabris

Thanks for the replies, Majenko and Nick! They are enlightening.

Quote
That would require hardware changes - the OP wants software only.


Actually, I'm fine with hardware changes, if there isn't a software-only method, or if the software-only method isn't 100 percent reliable.

Quote
The on-board regulator will give the same reading whatever the input voltage.  Compare it to the 1.1v Vref, and if it is the voltage that the voltage regulator gives you then you are running on wall wart.  If it's anything else, then you're on USB.


This is the technique you linked to higher up on the thread, correct?  That's software-only, right? Is that technique reliable? For example, it will work no matter what the voltage of the adapter I have plugged in?

Quote
Change that to "while (test if power not connected)" so they can plug in the wall-wart and have it recover without having to reboot.


Ah yes, of course. :)

I'm going to experiment with Majenko's software-only method first, since it requires the least amount of work. However, the voltage divider diagram you provided, Nick, is extremely useful and looks like it would be very likely to be of high reliability! So if I run into trouble with the software method, I'll try that instead. Thanks so much!

majenko

Quote
it will work no matter what the voltage of the adapter I have plugged in?

The on-board voltage regulator will always regulate to the same voltage - that is the point of it.

There is a chance the USB could give the same reading as the on-board regulator, so it's not 100% reliable, but close.

Nick Gammon

I think the resistors will be more reliable, the other method relies on the USB and the voltage regulator having different voltages.

Quote
I have found that when connected to the USB of my laptop I get 5.12v.  When running on the wall wart through the internal voltage regulator I get 5.04v


Considering the analogRead maxes out at 5V you may have a problem with that. Those are both over 5V. It may work, but it might be marginal.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

tfabris

Quote
The on-board voltage regulator will always regulate to the same voltage - that is the point of it.


What about different Arduino units? I intend to build multiple copies of this thing once I get it debugged. Would the results be different from one Arduino board to the next?

majenko

Quote
Would the results be different from one Arduino board to the next?


Possibly - it's hard to tell.  We could do with running a survey - get people to test their board's regulator voltage (using a sketch) and post the results - see how they vary.

Nick Gammon

One one Uno:

USB:

Code: [Select]
5096
5096
5120
5120
5096
5096
5096
5096


9V in:

Code: [Select]
5073
5073
5073
5073
5073
5073
5073
5073


On another one:

USB:

Code: [Select]
5028
5028
5028
5028
5028
5028
5028
5028


9V in:

Code: [Select]

5006
4984
4984
5006
4984
4984
4984
4984
4984


I don't think you will be able to get the "magic number" using this method. Not for a series of boards.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

majenko

Pants - Ah well, worth a try.

Looks like you'll have to have a voltage divider from Vin to an analogue input pin.


JimG

Run a flywire from pin 1 of the LMV358 dual op amp to any unused ATmega pin. If HIGH you are running on Vin. If LOW then Vcc is provided by USB or another source.

Just another option.

Jim

PS There is already a voltage divider on the Uno that splits Vin in half.  Look on the Uno schematic at the inputs to LMV358-1.
TC4 Open Source Digital Thermometer and Temperature Controller
http://code.google.com/p/tc4-shield

Nick Gammon

Quote
PS There is already a voltage divider on the Uno that splits Vin in half.  Look on the Uno schematic at the inputs to LMV358-1.


However half of 12V is still too high for an analog pin.
Please post technical questions on the forum, not by personal message. Thanks!

More info:
http://www.gammon.com.au/electronics

Go Up