I bet this is going to come up as more and more folk are transitioning to 32-microprocessors like the Due... libraries will need to be updated to reflect the different lengths of bytes, etc. since an int on a Due can hold a greater range of numbers than on a Uno. Anyhow, I wonder if someone could look over this code for a MCP3421 ADC
, which offers multiple resolutions, ranging from 12-18 bits that I am trying to use on a 32-bit micro with the Arduino IDE (Teensy 3.0)
The ADC uses a I2C connection, if 18-bits are used, three data bytes are sent, otherwise, only two. The databytes then have to be re-assembled into the signed numbers they represent. My code is an attempt to be flexible, hence I declared a int32_t as the ADC value being computed. As best as I can tell, the code below is OK for the positive portion of the range. However, negative numbers appear to be coming out incorrectly. Could someone more knowledgable see if I got the code right?
int32_t Read_Thermistor_Value (byte Bits)
uint8_t Hi=0, Med=0, Lo=0;
uint8_t reads=2; // default number of bytes that have to be read for every conversion
int32_t ADC_Value=0; // return value
if (Bits==18) reads+=1; // add another round of reads if 18 bit mode is used.
Wire.requestFrom((int)MCP3421_address, (int) reads);
if (reads ==3) Hi = Wire.read(); //only read top byte if 18 bit conversion is used
Med = Wire.read(); //Otherwise, just read two bits
Lo = Wire.read();
//here use signed int32_t and right + left shifts to carry the sign and append the value as needed
//for 18-bit operations, only the last bit of the Hi byte is relevant. The remaining bits are sign bits
if (Bits == 18) ADC_Value = (((Hi << 30) | (Med << 22)) | (Lo << 14)) >> 14;
//for all other resolutions, the returned value is left shifted based on the resolution to preserve the sign,
//then right shifted back, i.e. if 16 bit resolution is needed, left shift Med 24 bits, while 12-byte values
//would require a 28-bit left shift.
else ADC_Value = ((Med << (40-Bits)) | (Lo << (32-Bits))) >> (32-Bits);