Reading analog values over I2C

So I’m back again with another I2C device made by NXP. My last one did I2C to SPI, but we’re here to do ADC.

Now, if you’re the average Arduino user, then you have 6 ADC ports on your Uno, so why would you need any more? Well, you probably don’t, but if you’re using an ESP8266, then the onboard ADC is kinda garbage as it only tolerates values up to 1V. For some devices, this may not work as they require or output values greater than that.

I’ll be using the NXP PCF8951. A quick search looks like it can be purchased in DIP form, but I’m using a SO-16 (SMD). From the datasheet, we have the following pinouts:

If you’re familiar with any I2C device, then a lot of these pins should look familiar:

  • The A0-A2 lines are to determine the address (it starts at 0x48 – 0x4F for Arduino).
  • Vss goes to GND and Vdd to +5v.
  • SDA goes to the SDA pin on the Arduino, and likewise for SCL.

For this example, we’re going bring all of the address lines to GND. Vref is pulled to Vdd, but this isn’t needed for this example as this will be ADC, but that’d be your max output value when converting a digital value to analog. The same goes for AGND, except this will be the corresponding GND (useful if you’re using this with a separate and unrelated GND).

EXT and OSC relates to using an oscillator. The datasheet says:

8.6 Oscillator
An on-chip oscillator generates the clock signal required for the A/D conversion cycle and for refreshing the auto-zeroed buffer amplifier. When using this oscillator the EXT pin must be connected to VSS. The oscillator frequency is available at the OSC pin. If the EXT pin is connected to VDD, the oscillator output OSC is switched to a high-impedance state allowing to feed an external clock signal to OSC.

For what we’re doing, we’ll just set EXT to low.

We’ll put two pull-up resistors on the SDA and SCL lines (as per usual). We’ll tie our non-used analog lines to GND (A1-A3).

Finally, for our actual device, we’ll connect our Analog Out to A0. In my case I’m using a cheap moisture meter (FC-28, for those playing alone at home), but you can use whatever you want. I’ve left it purposefully ambiguous in the circuit diagram.

Speaking of witch, if you have everything set up correctly, your breadboard should look like this:

Time to code!

I’m going to assume that you have the prerequisite libraries and such and don’t need an explanation on them. I’ll include that stuff in my code, but I won’t go in depth.

If we look at Figure 18 in the datasheet…hold on, I can’t harp on it how much you NEED to read the datasheet! Take my examples and use them to learn how to read the datasheet.

Anyway, if we look at Figure 18, we can figure out what commands we need to read from different values (or write them):

Since we just want to read from A0 on the chip, we’ll write 0x00 to the device from our Arduino. If you want to do A1, then you’d send 0x01, and so on. Now if all four of your analog ports have devices you want to read from, you can use the auto-increment flag and send 0x05 and read multiple times.

Anyway, here is the code as promised. It’s extremely short. As you run this, you’ll notice your max values might seem strange. For the answer why, you can easily find that in the datasheet. 😉

#include "Wire.h"
#define PCF8591 0x48

void setup()

void loop()
int value = 0
Wire.requestFrom(PCF8591, 1);;



This entry was posted in Engineering and tagged , , , , . Bookmark the permalink.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.