I'm using an MPC73831 - a LiPo charging IC - in my Arduino project. It has a status
pin to allow interface to a microcontroller, which uses a tri-state operation to convey three possible states of charging. I don't have the IC and battery yet, but I wanted to write a quick program to test a generic tri-state pin for HI, LO, and HiZ while I'm waiting for it to arrive.
The algorithm I wrote is very simple:
Set pinTest to input, no pullup.
Is pinTest high?
Yes - pinTriState is HIGH, done.
Set pinTest to input with pullup.
Is pinTest high?
Yes - pinTriState is HiZ, internal pullup causes high reading.
No - pinTriState is LOW, 'cancelling out' internal pullup.
However, I'm not getting the expected results when using the internal pullup resistor - my board is showing correct analysis for HI and LO, but HiZ returns a mixture of HiZ and HIGH. I have tried this on an Uno, a Pro-Micro (32u4) and Uno->Micro and Micro->Uno. All give the same spurious results. I am baffled, therefore some advice would be appreciated. The full code is as below. I have left in code which randomises the time pinTriState
stays at in a given state to keep pinTest
guessing, but it's ultimately only an elaborate way of cycling through the three states.
#define pinTest 2
#define pinTriState 3
int state = 0;
char stateCh = '?';
int sect1;
int sect2;
int sectMax;
void setup()
{
Serial.begin(9600);
randomSeed(analogRead(A0));
sect1 = random(1, 20);
sect2 = random(sect1 + 1, random(sect1 + 2, sect1 + 20));
sectMax = random(sect2 + 1, random(sect2 + 2, sect2 + 20));
}
void loop()
{
// PART (1) Code to toggle three states of a tri-state pin
if (state == 0)
{
pinMode(pinTriState, OUTPUT);
digitalWrite(pinTriState, HIGH);
stateCh = 'H';
}
if (state == sect1)
{
pinMode(pinTriState, OUTPUT);
digitalWrite(pinTriState, LOW);
stateCh = 'L'
}
if (state == sect2)
{
pinMode(pinTriState, INPUT);
stateCh = 'Z';
}
// PART (2) Code to determine state of tri-state pin
Serial.print(stateCh); // Shows what it *should* be
pinMode(pinTest, INPUT);
if (digitalRead(pinTest))
Serial.println(" - HIGH");
else
{
pinMode(pinTest, INPUT_PULLUP);
if (digitalRead(pinTest))
Serial.println(" - HiZ");
else
Serial.println(" - LOW");
}
(state == sectMax ? state = 0 : state++);
}
The necessary pins are connected with a single wire. If I upload the code to two boards I remove PART (2) on the 'triState' board and PART (1) on the 'testing' board. In this case, stateCh
has no function.
For a single-board setup, I get the following output:
H - HIGH
H - HIGH
...
L - LOW
L - LOW
...
Z - HiZ <-- the first Z is correct 95% of the time
Z - HIGH
Z - HIGH <-- the remaining Zs are a mixture, biased heavily towards HIGH.
Z - HiZ
...
H - HIGH <-- H always gives HIGH
...
It makes no difference if I change the operating order of pinState
. I've thrown in delay(100);
between almost every other line, again to no avail.
I tried with a 22k, a 33k, and a 47k external pullup resistor. The results are perfect. However, this requires an extra Arduino pin to make sure that the pullup is only active when necessary. Part (2) becomes:
// PART (2) Code to determine state of tri-state pin
Serial.print(stateCh); // Shows what it *should* be
pinMode(pinTest, INPUT);
pinMode(pinPullup, INPUT); // connected to pinTest via resistor
if (digitalRead(pinTest))
Serial.println(" - HIGH");
else
{
//pinMode(pinTest, INPUT_PULLUP); <-- not anymore
pinMode(pinPullup, OUTPUT);
digitalWrite(pinPullup, HIGH); // pulls pinTest to Vdd
if (digitalRead(pinTest))
Serial.println(" - HiZ");
else
Serial.println(" - LOW");
}
Using the extra pin to provide the pullup is a real pain in the ar...duino. I'm cripplingly short of spare pins and I don't see why this is not resolvable with internal pullups. Help?!
pinMode(pinTest, INPUT_PULLUP)
is the first line in theelse
block. And that doesn't answer why it works with an external pull-up resistor that's turned on at the right time in leiu of the internal pull-up. – CharlieHanson Jun 28 '15 at 1:27pinPullup
happens to be biased towards Vcc, keeping the resistor slightly pulled up at all times? Why never pulled down by a leakage? – CharlieHanson Jun 28 '15 at 8:21