Code modify on modified MCP3428 4-Channel 4-20mA from NCD


I purchased a modified 4 Chanel 4-20mA board from NCD and had them modify it to measure voltage at 48Volts.

When they shipped it they emailed me this line of the code, that I can not get to work, can someone help me with the Voltage = (Raw_ADC[i-1]*0.00155); line to add into the code? full code shared below.

Hi Brandon,

Your order is shipping out today.

The board can read a max 48V DC. The Max input voltage could be upto 55V.

Please use this equation to convert raw ADC value into voltage

Voltage = (Raw_ADC[i-1]*0.00155);

any help would be appreciated

  • Brandon
#include <application.h>
#include <spark_wiring_i2c.h>

// MCP3428 I2C address is 0x68(104)
#define Addr 0x68

int raw_adc = 0;
void setup() 
  // Set variable
  Particle.variable("i2cdevice", "MCP3428");
  Particle.variable("rawADC", raw_adc);

  // Initialise I2C communication as MASTER
  // Start serial communication and set baud rate = 9600

  // Start I2C Transmission
  // Select configuration command
  // Continuous conversion mode, Channel-1, 12-bit resolution
  // Stop I2C Transmission

void loop()
  unsigned int data[2];

  // Start I2C Transmission
  // Select data register
  // Stop I2C Transmission

  // Request 2 bytes of data

  // Read 2 bytes of data
  // raw_adc msb, raw_adc lsb
  if(Wire.available() == 2)
    data[0] =;
    data[1] =;

  // Convert the data to 12-bits
  int raw_adc = (data[0] & 0x0F) * 256 + data[1];
  if(raw_adc > 2047)
    raw_adc -= 4095;

  // Output data to dashboard
  Particle.publish("Digital value of Analog Input : ", String(raw_adc));

Is there a question to this post? Or are you only letting us know?

Sorry yes there is a question, I edited my post… thank you.

Granted, that statement in the email is somewhat confusing as the original code doesn’t appear to feature a Raw_ADC[] array nor a variable called Voltage.
However, there is a variable raw_adc and with that the logical conclusion would be to reword that in some way that can resolve the “discrepancy”.

A wild guess from my side would look something like this

  double Voltage = raw_adc * 0.00155;

Not sure whether the result will fit your expectations but that’s the best I could come up with based on the original post and the lack of a similarly modified MCP3428 board.

If the result won’t fit your expectations I’d think it’d be best to contact NCD again (or maybe @IOTrav is still active in this forum to chime in).

@bbarr7iot, that ridiculously context-less email, I suspect, assumed there was a for() loop scanning the four channels of the unit, hence the reference to Raw_ADC[i-1] where `has values of 1 to 4. Perhaps it makes sense in context of sample code they provide for the unmodified unit?

1 Like

Thank you for the tag @ScruffR

Try this modified code:
I unfortunately do not have one of these boards at my desk so I cannot verify it. It should print the voltage readings from all 4 channels over the USB connection on the module. If there is an issue communicating with the MCP3428 via I2C it will print an error. Let me know what you find.


@IOTrav thanks for this info, can you add a particle.publish to it?

Why don’t you try it yourself?

ok buddy…

Try this: not tested !!! @ScruffR its gonna hate me now :shushing_face: sorry I couldn’t stop myself :see_no_evil:


Nah, not hate - but I can’t stop the disapproving frown over the use of String :speak_no_evil: :wink:

1 Like

I agree with you about String 100% but… they are here for years and I use them to build my JSON format variable (with absolutely any JSON library) for years and my home dashboard panel refreshing them every seconds for years and I don’t have any problems with them no disconnects no SOS completely working just perfect for my needs :crazy_face:

String status_extender = "{}";
String template_extender = "{\"Q1\":<Q1>,\"Q2\":<Q2>,\"Q3\":<Q3>,\"Q4\":<Q4>,\"Q5\":<Q5>,\"Q6\":<Q6>}";

String status = "{}" ; 
String status_template = "{\"MQ2\":<MQ2>,\"humidity\":<humidity>,\"pressure_hPa\":<pressure_pKa>,\"temperature_c\":<temperature_c>,\"altitude_ft\":<altitude_ft>,\"altitude_m\":<altitude_m>}" ;

    status = String(status_template); // copying ;
    status.replace("<pressure_hPa>" ,String(pressure_finall));
    status.replace("<temperature_c>" ,String(temperature_c));
    status.replace("<altitude_ft>" ,String(altitude_ft));
    status.replace("<altitude_m>" ,String(altitude_m));
    status_extender = String(template_extender);

Sorry for going out of topic !!!

Without String this could look like this (taken from another post - but you get the idea)

const char jsonTemplate[] =           // string template for creating the JSON string
  char msg[sizeof(jsonTemplate)+64];  // allow for up to 64 characters to be inserted into the template
  snprintf(msg, sizeof(msg), jsonTemplate
          , ts
          , (const char*)id
          , temp
          , total
          , accum 
          , vbat
          , status);

This is only one active instruction and it’s just as flexible and much better performancewise as it doesn’t create and destroy tons of temporary objects. Each String(...) and replace() call creates its own temporary entity just for the action - not considering the need for extending and relocating the original object.

If you want to make the above even more flexible without the need for the template to “know” about the data type in advance, you can do a two pass string build where you use %s everywhere and then inject the format placeholder in a first pass and then inject the data during the second.

However, for JSON building there is now also this


Thank you @ScruffR very much, I really appreciate your advice and I’m going to update all of my code on all devices, where I use String, right away !
I will try with JSONWriter.
Thanks again !

1 Like

ScruffR all works like charm !!! with JSONWriter.
Thanks again !
Just one more question, i’m curious if this will be good approach for my function publishChannelVoltage for mcp3428 to get rid of String ?

Updated regarding to ScruffR suggestion

void publishChannelVoltage(int channelno){
      char publishMsg[128];
      snprintf(publishMsg, sizeof(publishMsg),"Channel nr: %d,  voltage %ld", channelno, Raw_ADC[channelno-1]*0.00155); 
      //publishMsg =  String("Channel ") + String(channelno) + String(" Voltage") + String(Raw_ADC[channelno-1]*0.00155);
      Particle.publish("publishChannelsVoltage", publishMsg, 60, PRIVATE);   

This should work, but why would you arbitrary break your format string?
It makes sense to break a very long format string over multiple lines, but in a single line???

BTW, I’d rather have publishMsg[] to be a local variable - unless you need the “last” contents accessible somewhere else too.

This is perfect. Thank You!!