Arduino Library For MCP342X

Last time, I discussed how to interface TI’s ADS1112 16-bit delta-sigma A/D converter with Arduino. Today I am going to introduce you to a set of easy-to-program A/D chips from Microchip. MCP3246/7/8 are a family of 16-bit Delta-Sigma A/D converters with an I2C interface. MCP3426 and MCP3427 both have two differential input channels, while MCP3429 has four differential input channels. The programming for all three devices are essentially the same, except for the number of available channels.

Compared to the ADS1112 library we discussed previously, you will find that the programming for MCP342X are strikingly similar — the layout of the configuration register is bit-wise identical compared to that of ADS1112 except for the default value of the A/D conversion resolution and the sample rate. ADS1112 defaults to 16 bit and 15 SPS, whereas MCP342X defaults to 14 bit and 240 SPS.

One key deference between ADS1112 and MCP342X is how the single-ended inputs are handled. In ADS1112, switching between single-ended and differential measurements changes the analog input pin reference. Under single-ended mode, AIN3 becomes the common input pin and AIN0 to AIN2 become the single-ended inputs. For MCP342X, single-ended operation is achieved by grounding the negative differential input of the channel. So ADS1112 has two differential channels and three single-ended channels and MCP342X has four differential and four single-ended channels. Due to this difference, the programming for MCP342X is actually easier as we do not need to distinguish single-ended and differential operations in code.

MCP3428 Reference Circuit (Courtesy  http://ww1.microchip.com/downloads/en/ DeviceDoc/22226a.pdf))

MCP3428 Reference Circuit (Courtesy http://ww1.microchip.com/downloads/en/ DeviceDoc/22226a.pdf))

The Arduino library can be downloaded at the end. As for the ADS1112 library, I only included 16-bit mode. For other resolution and sampling rate, you can change the S0 and S1 bits in the communication register in the selectChannel function. Since differential and single-ended input are handled essentially the same way (except for where the negative differential input is referenced), we do not need to distinguish these two modes in code and thus the mode parameter was dropped on purpose.

#include <MCP342X.h>
#include <Wire.h>

MCP342X mcp3428;

void setup()
{
  Wire.begin();
  Serial.begin(9600);

  mcp3428.init(MCP342X::L, MCP342X::L);
  mcp3428.selectChannel(MCP342X::CHANNEL_0, MCP342X::GAIN_1);
}

void loop()
{
    Serial.println(mcp3428.readADC(), 3);
    delay(100);
}

Here is a list of the available library functions and parameters:

init(byte A0, byte A1)
A0 and A1 are used in conjunction with the corresponding pin wiring to set the device I2C address. (MCP3426 does not have user selectable addresses)

selectChannel(byte channel, byte gain, byte mode)
channel: CHANNEL_0, CHANNEL_1, CHANNEL; in bi-polar mode, it is either CHANNEL_0 or CHANNEL_1 _2 or CHANNEL_3 (CHANNEL_2 and CHANNEL_3 only available for MCP3428)
gain: GAIN_1, GAIN_2, GAIN_4 or GAIN_8

readADC()
get the AD conversion result based on the parameters selected using selectChannel

MCP3428 on Breadboard

MCP3428 on Breadboard


Download: MCP342X Library

Be Sociable, Share!

27 Comments

  1. Vaibhav Jain says:

    Dear sir

    Can we get results in 8.5 digit mode using MCP3426
    (e.g. 0.00000000)?
    if yes where will the changes in code.
    Thanks!

  2. Abishai says:

    Very informative article sir. Can you please tell me what is the maximum voltage that mcp 3428 can measure. In my application, I have to measure maximum voltage upto 130 volts DC. Can you please provide me some information? Thank you.

  3. EMMY says:

    Hi Kerry,
    i’d like to use yr library MCP342x on window 7
    but i din#t manage to download it!!!it has an Endig .tar and i don’t now how i can#t get it on my
    Arduino application!
    is the programm able to be unpacked? if so which program have i to use to unpack this Library
    and install it in Arduino IDE?

    thanks in Advance for yr answer.

  4. Adnc says:

    Hi Kerry,

    if I’m not wrong your library could also be used for for the MCP3422 althogh your referencing it to the 6/7/8.

    Regards

    • kwong says:

      MCP3422/3/4 are 18 bits converters. I don’t have any but just by looking at the clock diagram (page 21) I see that the data has 4 bytes where as for MCP3426/7/8 the data has 3 bytes. So you will need to change MCP342X::readADC() and assemble the extra data byte if you are using MCP3422/3/4.

  5. EmmY says:

    Hi Kerry, can you tell if it’s possible to use only one of the 4 Channel of this chip(MCP3428)?
    What about other 3 remaining?
    have i to let them floating or connect them on GND or VDD( i mean chn+ and chn- on the same voltage level with n = channel Nummber).
    Anothe question ist which GND have i to use?the digital one or analog?
    On Arduino are both present and i don’t know which one is to be used?

    N.B: i ask you this cause i got the chip no work!wenn i connect the supply voltage(5V), the chip get hot and i don’t know whats the matter.
    thanks in advance!!
    EMMY

    • kwong says:

      When using just one of the available channels, you can simply leave other input pins unconnected or connected to ground.

      The analog ground and digital ground are both connected to ground potentials (e.g. the GND pin on your Arduino). There are some subtle differences between these two grounds. To reduce noise, the AGND pin should be connected directly to the ground plane of the analog portion of the circuit and the digital GND pin should be connected to ground plane of the digital portion.

      But for simple circuits where noise is not a big concern, both pins can be connected together to your circuit ground reference point.

      I am not sure if you have already damaged your chip as during normal operation it should not get warm.

  6. EmmY says:

    Hi Kerry, it works, the chip was arleady dead. i replaced it and i got it working.
    sometimes i use this library and works perfectly.
    Today i do’t manage to run it! everytime i compile, it comes out the following error message:
    sketch_mar04a.ino: In function ‘void setup()’:
    sketch_mar04a:15: error: ‘class MCP342X’ has no member named ‘init’
    sketch_mar04a:15: error: ‘L’ is not a member of ‘MCP342X’
    sketch_mar04a:15: error: ‘L’ is not a member of ‘MCP342X’
    sketch_mar04a:16: error: ‘class MCP342X’ has no member named ‘selectChannel’
    sketch_mar04a:16: error: ‘CHANNEL_0’ is not a member of ‘MCP342X’
    sketch_mar04a:16: error: ‘GAIN_1’ is not a member of ‘MCP342X’
    sketch_mar04a.ino: In function ‘void loop()’:
    sketch_mar04a:21: error: ‘class MCP342X’ has no member named ‘readADC’

    Do you know how to remove this error and get the sketsch in yr example working again?
    I’m using the arduino IDE version 1.05 -r2

    thank you very much for supporting me!!

    • kwong says:

      Assuming that the library source files were in under your arduino program folder (libraries\MCP342X\MCP342X.h & MCP342X.cpp) I’d check if you get an error with just the following code, just to ensure that the header file can be included properly:

      #include
      #include

      MCP342X mcp3428;

      void setup()
      {
      }

      void loop()
      {
      }

      It’s hard to tell what caused this error but by the look of it it seems that it didn’t find the library. But you can easily figure out whether or not the library was located correctly by using the snippet above.

  7. EmmY says:

    Hi Kerry, how are you?
    first of all thank you for yr help!!
    Now it works! there was the Problem with my IDE, i’ve reinstalled it and run it again.

    But i’m still having a problem concerning the maximaum Voltage that could be measured.
    Someone have asked you above but no answer and i’ve the same problem.
    ist it possible to measure the voltage between 5 mV and 20 V with this Library?

    thank you in Advance!!1
    EMMY

  8. EmmY says:

    HAllo Kerry, thanks for all!
    Now i’m using yr library in my project. I tried to read the voltage fallingacross the shunt-Resistor.
    For small voltage mearures the MCP3428 very well, but as the voltage increases the error too.
    For example:
    Measuring 5 mV i got 4,98mv that okay.
    measuring 20mV i got 17,68 mV
    and bei 60mv i got 54,6 mV only.
    I don’t know how i can avoid this.
    Do you know what may be the cause. i tried my best but in vain.
    thanks
    EMMY

    • kwong says:

      It sounds like that the internal Vref for MCP3428 is not spot on… In the library I had coded:

      static const double VRef = 2.048;

      and try changing that to compensate your measurements. (I will add a method later so it can be changed within user code).

  9. Ollie says:

    Hi Kerry, cheers for the library! Found it to be very useful. I was just wondering if you could recommend the best way to read multiple channels in a single loop?

    I have attached 4 inputs to my MCP3428 and am trying to read both of their values within a single loop of the arduino code. When I try to do this (using the code I’ve pasted below), the values that it reads seem to be random and non-changing and do not respond to the change in input (coming from a potentiometer).

    Note that when I run your example code posted above with only a single channel being read at a time it responds to a change in the potentiometer. Additionally, if I leave a 100ms gap between when I read the first channel and when I read the second, it manages to read both channels. If I reduce that time however, it resorts back to invalid data.

    #include
    #include

    MCP342X mcp3428_1;
    MCP342X mcp3428_2;

    void setup(){
    Wire.begin();
    Serial.begin(9600);

    mcp3428_1.init(MCP342X::L, MCP342X::L);
    mcp3428_1.selectChannel(MCP342X::CHANNEL_0, MCP342X::GAIN_1);

    mcp3428_2.init(MCP342X::L, MCP342X::L);
    mcp3428_2.selectChannel(MCP342X::CHANNEL_1, MCP342X::GAIN_1);
    }

    void loop(){
    Serial.println(mcp3428_1.readADC(), 3);
    Serial.println(mcp3428_2.readADC(), 3);
    delay(100);
    }

    • kwong says:

      Thanks Ollie,

      The code you attached seems to suggest that both chips have the same address, which is incorrect, you need to use different address for each chip connected.

      • Ollie says:

        Ah apologies. It’s probably just ignorance on my part, but I’m using a single MCP3428 chip. In the code I was trying to reference two of the chip’s channels.

        I was under the impression that I began transmission with the chip using your init function and then I tried to select each of the channels to be read within your selectChannel function. Do I need to use a different address for the one chip when reading different channels?

        Thanks again,
        Ollie…

  10. David says:

    Hi.
    Really new to the concept of programming and I have read through the .h and .cpp files again and again to figure out how to change the data rate between 12, 14 & 16bit and where to choose continuous or one-shot mode, at first I set out to enable those two parameters.
    I’ve created in .h:
    static const byte MODE_cont = 0;
    static const byte MODE_shot = 1;

    static const byte RES_12 = 0;
    static const byte RES_14 = 1;
    static const byte RES_16 = 2;
    and added to
    void selectChannel(byte channel, byte mode, byte gain = GAIN_1, byte res);

    and in .cpp
    void MCP342W::selectChannel(byte channel, byte mode, byte gain, byte res)

    I am designing a power supply but have not yet produced any real circuit so I can’t find out by trial and error, but I assume that in the .cpp file the line
    byte reg = 1 << BIT_RDY | channel << BIT_C0 | 1 << BIT_OC | 1 << BIT_S1 | gain;
    controls individual bits of the reg byte, am I right in thinking that the declared byte's CHANNEL_1,2,3&4 relates to "channel << BIT_C0" and that I can add something like
    "| mode << BIT_OC | res << BIT_S0"?

    Or am I way of?

    I am simply guessing how the library works but if I'm wrong in my deduction I simply need to know how to set(in the library files) BIT_OC, BIT_S0 & BIT_S1, it would help me out a lot.

    I have more than once found really golden information at your site, thank you very much for your explanations.

    • kwong says:

      Hi David,

      You probably want to refer to p18 of the datasheet. The BIT_* constants (e.g. BIT_S1, BIT_S0) defined in the header file are the bit locations within the communication register and if you want to set that bit you would left shift 1 by the number of bits. So if you want to set the S1 bit, you will do a 1 << BIT_S1.

  11. Kevin says:

    Hi,
    I have read from the datasheet that the vref can be changed from 2.048 v to 4.096 v,but am not sure of how to do that.I am using it in single ended mode.

  12. Juan Gutierrez says:

    Hallo Kerry,
    I am facing a problem.
    I have 6 measurement boards. Each board has 2 temperature sensors and 1 current sensor. All of them have a analog output and I am using a MCP3428 to receive the values over a I2C bus. I am using only 3 channels of each MCP3428. At the beggining I tried to request all the values from the first ADC, then the second and so on but lately I discovered that for some reason any value was updated, that means, the values can be read but neither the temperature sensors nor the current sensor was changing over the time (even when the temperature and current were changing). Then I decided to request the first channel of the first ADC, then the first channel of the second ADC and so on, and it works but partially because now it only updates the first channels that I am addresing. Lets say that I have the following code

    measureArray[0] = I2Cmeasure(0x68, 0x98, measureArray[0]); //first channel of the first ADC
    measureArray[1] = I2Cmeasure(0x6D, 0x98, measureArray[1]); ´//first channel of the second ADC
    measureArray[2] = I2Cmeasure(0x69, 0x98, measureArray[2]); // first channel of the third ADC and so on
    measureArray[3] = I2Cmeasure(0x6C, 0x98, measureArray[3]);
    measureArray[4] = I2Cmeasure(0x6A, 0x98, measureArray[4]);
    measureArray[5] = I2Cmeasure(0x6F, 0x98, measureArray[5]);
    measureArray[6] = I2Cmeasure(0x68, 0xB8, measureArray[6]); //second channel of the first ADC
    measureArray[7] = I2Cmeasure(0x6D, 0xB8, measureArray[7]); //second channel of the second ADC
    measureArray[8] = I2Cmeasure(0x69, 0xB8, measureArray[8]);
    measureArray[9] = I2Cmeasure(0x6C, 0xB8, measureArray[9]);
    measureArray[10] = I2Cmeasure(0x6A, 0xB8, measureArray[10]);
    measureArray[11] = I2Cmeasure(0x6F, 0xB8, measureArray[11]);
    measureArray[12] = I2Cmeasure(0x68, 0xD8, measureArray[12]); //third channel of the first ADC
    measureArray[13] = I2Cmeasure(0x6D, 0xD8, measureArray[13]); //thrid channel of the second ADC
    measureArray[14] = I2Cmeasure(0x69, 0xD8, measureArray[14]);
    measureArray[15] = I2Cmeasure(0x6C, 0xD8, measureArray[15]);
    measureArray[16] = I2Cmeasure(0x6A, 0xD8, measureArray[16]);
    measureArray[17] = I2Cmeasure(0x6F, 0xD8, measureArray[17]);

    and the function I2Cmeasure looks like this:

    int I2Cmeasure(byte p, byte mode, int measure_output)
    {
    Wire.beginTransmission(p);
    Wire.write(mode);
    Wire.endTransmission();
    Wire.requestFrom(p, 2);
    int temp = Wire.read();
    measure_output = temp << 8;
    measure_output |= Wire.read();
    temp = Wire.read(); //TODO:check if this line is required
    return measure_output;
    }

    For some reason this code receives all the values but like I said only the first six values change over the time, the other ones remain static the whole time.

    I was trying to use your library to solve this problem but to be honest I couldn't figure out how to make the instances of all my 6 MCP3428, and also I couldn't undestand very well how the following line works?

    MCP342x::Config status;

    Do you have any idea why is this happening? and do you have some suggestion to solve my problem using your library?

    Thank you very much in advance for your help.

    Regards

    Juan Gutierrez

  13. Martin Jaeger says:

    Hi Kerry, thanks for providing this library, it isvery helpfull.
    in your MCP342X.cpp file calculating the Vin-value, you code:
    ” if (t >= 32768) {t = 655361 – t; } ” obviously ckecking the sign-bit,
    but “655361 – t ” ? I don’t understand
    could you please explain ?
    Thank You
    Regards
    Martin

Leave a Reply