# How can I read a tristate output with microcontroller?

I'd like to interface the STAT line of an MCP73831 lithium ion charge manager IC to a microcontroller to read the current charging status of it.

The datasheet explains, in the section 5.2.1, that the STAT line is tristate output and have the following status:

• High
• Low
• High-Impedance

and a table is provided that explains how each level represents each charging states of the battery.

How can I connect this pin to a microcontroller I/O and read these three distinct states?

Reading High and Low is quite straightforward, but detecting a input is high impedance I've not done before.

-

You could tie it to ground and Vcc with two 10k resistors, and use an A/D input to read the level.

If you don't have an A/D to spare connect it to another pin of your uC with a 10k resistor. If the pin is either high or low it will of course read as high resp. low (assuming it can drive a 10k load). If it is high impedance it will read equal to what you output on the other pin.

-
+I like the 2nd idea. Read with output high and output low, four possibilities, of which only three are sensible. –  Spehro Pefhany Jul 14 at 23:09
Nice idea using the other pin. In this case though, the input can/will exceed the processors Vcc. Added a post instead of an extended comment. –  carveone Jul 25 at 15:44

Many microcontrollers allow you to select between either weak pullup and weak pulldown resistor on a GPIO input - in the order of about 50k-100k Ohm. If the input is high-z, a read with weak pulldown enabled will read low and a following read with weak pullup will be a high.

Remember to wait a few µs between the resistor toggle and the GPIO read to allow the voltage on the pin to settle.

Note that older AVR and 8051's may only have weak pullup but no weak pulldown resistors.

-
+1 ... For MPUs that do not have weak pullup & weak pulldown capability, you could add a single external resistor to another GPIO pin and use it to drive the resistor high or low. –  Tut Jul 14 at 20:17

If you read the document - section 3.3 you see that it is intended to be used with a pull up resistor.

In fact with any open-drain or tri-state signal you're not meant to be reading it when it is in tri-state mode, it is designed that way so that the signal can be shared across multiple devices. Where it gets confusing is that if you are reading the signal and it is in tri-state mode (and you don't know it) you can get spurious readings. the best way is to then apply a weak pull up so that if the signal is in a ambiguous state, then the the signal is read appropriately. Since this signal is meant to be driving a LED to indicate a charge status (i.e. low is charging) then with a pull-up and it reads high, means that it is not charging.

-
The table in section 5.2.1 indicates that (for the MCP73831) that a "HIGH Z" output indicates "Shutdown" or "No Battery Present", while a "H" (high) output indicates "Charge Complete - Standby". A pull-up resistor alone will not allow the MCU to tell the difference. –  Tut Jul 14 at 20:47
With a pull up then the modes of "shutdown", "no battery present" and "Charge-complete - standby" all map to the same reading of High. This all maps to the action of "don't do anything" looks like the datasheet is consistent. –  placeholder Jul 14 at 20:56

If I may add a warning to this post. The MCP73831 is a battery charger chip and thus its Vdd is higher than its Vbat.

Assuming your microcontroller is connected to Vbat and Vdd is supplied from USB, then Vdd could be at least 1.5V higher than Vucontroller.

The catch is that, on the 73831 which has totem pole outputs, STAT is referred to Vdd. So don't connect STAT directly to an uC input. Use something like a 10k resistor in between. For a PIC micro, the input diode clamps will clamp to its Vcc (check the datasheet for max current before latchup)

As an addendum - last year I came across a hack to read hi/low/z inputs that was for a PIC but might (or might not) work for you. Something like (pseudo code):

STAT ----[10k]------ PIC
PIN starts as input

set PIN low
set PIN to output
set PIN to input
set PIN high
value = read PIN  (assuming 1 for high, 0 for low)
value = value << 1
set PIN to output
set PIN to input