Skip to content

Commit ef69944

Browse files
author
FischerMoseley
committed
Added the ability to configure ADC resolution
1 parent 81d0019 commit ef69944

File tree

5 files changed

+223
-44
lines changed

5 files changed

+223
-44
lines changed

examples/Example2_SetThermocoupleType/Example2_SetThermocoupleType.ino

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,23 @@
88
This example outputs the ambient and thermocouple temperatures from the MCP9600 sensor, but allows for a non
99
K-type thermocouple to be used.
1010
11+
The Qwiic MCP9600 supports K/J/T/N/S/E/B/R type thermocouples, and the type can be configured below!
12+
1113
Hardware Connections:
1214
Attach the Qwiic Shield to your Arduino/Photon/ESP32 or other
1315
Plug the sensor onto the shield
1416
Serial.print it out at 115200 baud to serial monitor.
1517
*/
1618

19+
1720
#include <SparkFun_MCP9600.h>
1821
MCP9600 tempSensor;
22+
thermocoupleType type = S_type; //the type of thermocouple to change to!
1923

2024
void setup(){
2125
Serial.begin(115200);
2226

23-
//check if the sensor is connected
27+
//check that the sensor is connected
2428
if(tempSensor.isConnected()){
2529
Serial.println("Device will acknowledge!");
2630
}
@@ -29,7 +33,7 @@ void setup(){
2933
while(1); //hang forever
3034
}
3135

32-
//check if the Device ID is correct
36+
//check that the Device ID is correct
3337
if(tempSensor.checkDeviceID()){
3438
Serial.println("Device ID is correct!");
3539
}
@@ -38,9 +42,12 @@ void setup(){
3842
while(1);
3943
}
4044

45+
//change the thermocouple type being used
4146
Serial.println("Setting Thermocouple Type!");
42-
43-
if(tempSensor.setThermocoupleType(Stype) == 0){
47+
tempSensor.setThermocoupleType(type);
48+
49+
//make sure the type was set correctly!
50+
if(tempSensor.getThermocoupleType() == type){
4451
Serial.println("Thermocouple Type set sucessfully!");
4552
}
4653

examples/Example3_SetFilterCoeffecients/Example3_SetFilterCoeffecients.ino

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
#include <SparkFun_MCP9600.h>
2121
MCP9600 tempSensor;
22+
uint8_t coeffecient = 5;
2223

2324
void setup(){
2425
Serial.begin(115200);
@@ -38,17 +39,16 @@ void setup(){
3839
}
3940
else {
4041
Serial.println("Device ID is not correct! Freezing.");
41-
while(1);
42+
while(1); //hang forever
4243
}
4344

4445
//print the filter coeffecient that's about to be set
45-
uint8_t coeffecient = 4;
4646
Serial.print("Setting Filter Coeffecient to ");
4747
Serial.print(coeffecient);
4848
Serial.println("!");
4949

5050
//tell us if the coeffecient was set sucessfully
51-
if(tempSensor.setFilterCoeffecients(coeffecient) == 0){
51+
if(tempSensor.getFilterCoeffecients() == coeffecient){
5252
Serial.println("Filter Coeffecients set sucessfully!");
5353
}
5454

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
Setting ADC resolution with the MCP9600 Thermocouple Amplifier
3+
By: Fischer Moseley
4+
SparkFun Electronics
5+
Date: July 10, 2019
6+
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware License).
7+
8+
This example allows you to change the ADC resolution on the thermocouple (hot) and ambient (cold) junctions. Why
9+
do this, you ask? Well, setting the resolution lower decreases the sampling time, meaning that you can measure
10+
high-speed thermal transients! (at the expense of lower resolution, of course).
11+
12+
Before we start adjusting ADC resolution, a quick word on how this all works. All thermocouple systems have a hot
13+
and cold junction, and the MCP9600 is no different. Thanks to physics, thermocouples only measure the difference
14+
in hot and cold junction temperatures, meaning that in order to know the temperature of the hot junction, the
15+
amplifier needs to know the temperature of cold junction. From there, it will add the cold junction temperature
16+
to the temperature difference measured by the thermocouple, giving the absolute temperature rather than just the
17+
relative one.
18+
19+
This means that the MCP9600 has to take two temperature measurements! Thankfully, the MCP9600 will let us set the
20+
resolution on each one independently. SetAmbientResolution and SetThermocoupleResolution configure these measurements
21+
with a desired resolution for the cold and hot junctions respectively.
22+
23+
Cold Junction Possible Resolutions:
24+
RES_ZERO_POINT_0625 -> Configures the ambient (cold) junction to measure in increments of 0.0625ºC
25+
RES_ZERO_POINT_25 -> Configures the ambient (cold) junction to measure in increments of 0.25ºC
26+
27+
28+
Hot Junction Possible Resolutions:
29+
RES_18_BIT -> Reads the hot junction ADC to 18 bits, or 2µV
30+
RES_16_BIT -> Reads the hot junction ADC to 16 bits, or 8µV
31+
RES_14_BIT -> Reads the hot junction ADC to 14 bits, or 32µV
32+
RES_12_BIT -> Reads the hot junction ADC to 12 bits, or 128µV
33+
34+
It's worth noting that since the thermocouple that serves as the hot junction is arbitrary, we can't provide a
35+
specification on how many degrees Celcius precision you will get for a given ADC resolution.
36+
37+
Hardware Connections:
38+
Attach the Qwiic Shield to your Arduino/Photon/ESP32 or other
39+
Plug the sensor onto the shield
40+
Serial.print it out at 115200 baud to serial monitor.
41+
*/
42+
43+
#include <SparkFun_MCP9600.h>
44+
MCP9600 tempSensor;
45+
46+
ambientResolution ambientRes = RES_ZERO_POINT_0625;
47+
thermocoupleResolution thermocoupleRes = RES_14_BIT;
48+
49+
void setup(){
50+
Serial.begin(115200);
51+
//check if the sensor is connected
52+
if(tempSensor.isConnected()){
53+
Serial.println("Device will acknowledge!");
54+
}
55+
else {
56+
Serial.println("Device did not acknowledge! Freezing.");
57+
while(1); //hang forever
58+
}
59+
60+
//check if the Device ID is correct
61+
if(tempSensor.checkDeviceID()){
62+
Serial.println("Device ID is correct!");
63+
}
64+
else {
65+
Serial.println("Device ID is not correct! Freezing.");
66+
while(1); //hang forever
67+
}
68+
69+
//set the resolution on the ambient (cold) junction
70+
tempSensor.setAmbientResolution(ambientRes);
71+
tempSensor.setThermocoupleResolution(thermocoupleRes);
72+
73+
//this is just debug, remove it if you're reading this
74+
Serial.print("Ambient Resolution Config successful?: ");
75+
Serial.println(tempSensor.getAmbientResolution() == ambientRes);
76+
Serial.print("Thermocouple Resolution Config successful?: ");
77+
Serial.println(tempSensor.getThermocoupleResolution() == thermocoupleRes);
78+
}
79+
80+
void loop(){ //print the thermocouple, ambient and delta temperatures every 200ms
81+
Serial.print("Thermocouple: ");
82+
Serial.print(tempSensor.thermocoupleTemp());
83+
Serial.print(" °C Ambient: ");
84+
Serial.print(tempSensor.ambientTemp());
85+
Serial.print(" °C Temperature Delta: ");
86+
Serial.print(tempSensor.tempDelta());
87+
Serial.print(" °C");
88+
Serial.println();
89+
delay(200);
90+
}

src/SparkFun_MCP9600.cpp

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,17 @@ Distributed as-is; no warranty is given.
2626
#include "WProgram.h"
2727
#endif
2828

29+
//Class constructor
2930
MCP9600::MCP9600(uint8_t address, TwoWire &wirePort){
3031
_deviceAddress = address; //grab the address that the sensor is on
3132
_i2cPort = &wirePort; //grab the port that the user wants to use
3233
_i2cPort->begin();
3334
_i2cPort->setClock(10000);
3435
}
3536

37+
38+
/*-------------------------------- Device Status ------------------------*/
39+
3640
bool MCP9600::isConnected(){
3741
_i2cPort->beginTransmission(_deviceAddress);
3842
return (_i2cPort->endTransmission() == 0);
@@ -46,6 +50,9 @@ bool MCP9600::checkDeviceID(){
4650
return (highByte(deviceID()) == DEV_ID_UPPER);
4751
}
4852

53+
54+
/*----------------------------- Sensor Measurements ---------------------*/
55+
4956
float MCP9600::thermocoupleTemp(){
5057
int16_t raw = readDoubleRegister(HOT_JUNC_TEMP);
5158
return ((float)raw * DEV_RESOLUTION);
@@ -61,18 +68,62 @@ float MCP9600::tempDelta(){
6168
return ((float)raw * DEV_RESOLUTION);
6269
}
6370

71+
72+
/*--------------------------- Measurement Configuration --------------- */
73+
74+
bool MCP9600::setAmbientResolution(ambientResolution res){
75+
uint8_t config = readSingleRegister(DEVICE_CONFIG); //get current device configuration so we don't wipe everything else
76+
bitWrite(config, 7, res); //set the bit that controls the ambient (cold) junction resolution
77+
78+
bool failed = writeSingleRegister(DEVICE_CONFIG, config); //write new config register to MCP9600
79+
failed &= (readSingleRegister(DEVICE_CONFIG) != config); //double check that it was set properly
80+
return failed; //return 1 if the write failed or the register wasn't properly set, 0 otherwise
81+
}
82+
83+
ambientResolution MCP9600::getAmbientResolution(){
84+
uint8_t config = readSingleRegister(DEVICE_CONFIG); //grab current device configuration
85+
return bitRead(config, 7); //return 7th bit from config register
86+
}
87+
88+
bool MCP9600::setThermocoupleResolution(thermocoupleResolution res){
89+
uint8_t config = readSingleRegister(DEVICE_CONFIG); //grab current device configuration so we don't wipe everything else
90+
bool highResolutionBit = bitRead(res, 1);
91+
bool lowResolutionBit = bitRead(res, 0);
92+
bitWrite(config, 6, highResolutionBit); //set 6th bit of config register to 1st bit of the resolution
93+
bitWrite(config, 5, lowResolutionBit); //set 5th bit of config register to 0th bit of the resolution
94+
95+
bool failed = writeSingleRegister(DEVICE_CONFIG, config); //write new config register to MCP9600
96+
failed &= (readSingleRegister(DEVICE_CONFIG) != config); //double check that it was written properly
97+
return failed; //return 1 if the write failed or the register wasn't properly set, 0 otherwise
98+
}
99+
100+
thermocoupleResolution MCP9600::getThermocoupleResolution(){
101+
uint8_t config = readSingleRegister(DEVICE_CONFIG); //grab current device configuration
102+
thermocoupleResolution res; //define new thermocoupleResolution enum to return
103+
bool highResolutionBit = bitRead(config, 6);
104+
bool lowResolutionBit = bitRead(config, 5);
105+
bitWrite(res, 1, highResolutionBit); //set 1st bit of the enum to the 6th bit of the config register
106+
bitWrite(res, 0, lowResolutionBit); //set 0th bit of the enum to the 5th bit of the config register
107+
return res;
108+
}
109+
64110
uint8_t MCP9600::setThermocoupleType(thermocoupleType type){
65-
uint8_t config = readSingleRegister(THERMO_SENSOR_CONFIG);
111+
uint8_t config = readSingleRegister(THERMO_SENSOR_CONFIG); //grab current device configuration so we don't wipe everything else
66112
bitClear(config, 4); //clear the necessary bits so that they can be set
67113
bitClear(config, 5);
68114
bitClear(config, 6);
69115
config |= (type << 4); //set the necessary bits in the config register
70-
if(writeSingleRegister(THERMO_SENSOR_CONFIG, config) != 0) return 1; //if write fails, return 1
116+
if(writeSingleRegister(THERMO_SENSOR_CONFIG, config)) return 1; //if write fails, return 1
71117
if(readSingleRegister(THERMO_SENSOR_CONFIG) != config) return 2; //if the register didn't take the new value, return 2
72118

73119
return 0; //otherwise return 0
74120
}
75121

122+
thermocoupleType MCP9600::getThermocoupleType(){
123+
uint8_t config = readSingleRegister(THERMO_SENSOR_CONFIG);
124+
return (config >> 4); //clear the non-thermocouple-type bits in the config registe
125+
}
126+
76127
uint8_t MCP9600::setFilterCoeffecients(uint8_t coeffecient){
77128
if(coeffecient > 7) return 3; //return immediately if the value is too big
78129

@@ -82,14 +133,17 @@ uint8_t MCP9600::setFilterCoeffecients(uint8_t coeffecient){
82133
config |= coeffecient; //set the necessary bits in the config register
83134

84135
writeSingleRegister(THERMO_SENSOR_CONFIG, config);
85-
for(uint8_t attempts = 0; attempts <= retryAttempts; attempts++){
86-
uint8_t readBack = readSingleRegister(THERMO_SENSOR_CONFIG);
87-
Serial.println(readBack, BIN);
88-
if(readBack == config) return 0;
89-
}
90-
return 1;
136+
return;
137+
}
138+
139+
uint8_t MCP9600::getFilterCoeffecients(){
140+
uint8_t config = readSingleRegister(THERMO_SENSOR_CONFIG);
141+
return ((config << 5) >> 5); //clear the non-filter-coeffecients data in the config register
91142
}
92143

144+
145+
/*------------------------- Internal I2C Abstraction ---------------- */
146+
93147
uint8_t MCP9600::readSingleRegister(MCP9600_Register reg){
94148
for(uint8_t attempts; attempts <= retryAttempts; attempts++){
95149
_i2cPort->beginTransmission(DEV_ADDR);
@@ -117,9 +171,9 @@ uint16_t MCP9600::readDoubleRegister(MCP9600_Register reg){
117171
return;
118172
}
119173

120-
uint8_t MCP9600::writeSingleRegister(MCP9600_Register reg, uint8_t data){
174+
bool MCP9600::writeSingleRegister(MCP9600_Register reg, uint8_t data){
121175
_i2cPort->beginTransmission(_deviceAddress);
122176
_i2cPort->write(reg);
123177
_i2cPort->write(data);
124-
return _i2cPort->endTransmission();
178+
return (_i2cPort->endTransmission() != 0);
125179
}

src/SparkFun_MCP9600.h

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -41,35 +41,63 @@ enum MCP9600_Register {
4141
};
4242

4343
enum thermocoupleType {
44-
Ktype = 0b000,
45-
Jtype = 0b001,
46-
Ttype = 0b010,
47-
Ntype = 0b011,
48-
Stype = 0b100,
49-
Etype = 0b101,
50-
Btype = 0b110,
51-
Rtype = 0b111,
44+
K_type = 0b000,
45+
J_type = 0b001,
46+
T_type = 0b010,
47+
N_type = 0b011,
48+
S_type = 0b100,
49+
E_type = 0b101,
50+
B_type = 0b110,
51+
R_type = 0b111,
52+
};
53+
54+
enum ambientResolution {
55+
RES_ZERO_POINT_0625 = 0b0,
56+
RES_ZERO_POINT_25 = 0b1,
57+
};
58+
59+
enum thermocoupleResolution {
60+
RES_18_BIT = 0b00,
61+
RES_16_BIT = 0b01,
62+
RES_14_BIT = 0b10,
63+
RES_12_BIT = 0b11,
5264
};
5365

5466
class MCP9600{
55-
public:
56-
MCP9600(uint8_t address = DEV_ADDR, TwoWire &wirePort = Wire); //Class constructor
57-
bool isConnected(); //Returns true if the thermocouple will acknowledge over I2C, and false otherwise
58-
uint16_t deviceID(); //Returns the contents of the device ID register. The upper 8 bits are constant, but the lower contain revision data.
59-
bool checkDeviceID(); //Returns true if the constant upper 8 bits in the device ID register are what they should be according to the datasheet.
60-
61-
float thermocoupleTemp(); //Returns the thermocouple temperature in degrees Celcius
62-
float ambientTemp(); //Returns the ambient (IC die) temperature in degrees Celcius
63-
float tempDelta(); //Returns the difference in temperature between the thermocouple and ambient junctions, in degrees Celcius
64-
65-
uint8_t setThermocoupleType(thermocoupleType type); //Sets the type of thermocouple connected to the MCP9600. Supported types are KJTNSEBR.
66-
uint8_t setFilterCoeffecients(uint8_t coeffecient); //Sets how heavy of an exponential moving average filter to use. Set this to 0 for no filter, 1 for minimum filter, and 7 for maximum filter.
67-
68-
private:
69-
TwoWire *_i2cPort; //Generic connection to user's chosen I2C port
70-
uint8_t _deviceAddress; //I2C address of the MCP9600
71-
uint8_t readSingleRegister(MCP9600_Register reg); //Attempts to read a single register, will keep trying for retryAttempts amount of times
72-
uint16_t readDoubleRegister(MCP9600_Register reg); //Attempts to read two registers, will keep trying for retryAttempts amount of times
73-
uint8_t writeSingleRegister(MCP9600_Register reg, uint8_t data); //Attempts to write data into a single 8-bit register. Does not check to make sure it was written successfully.
67+
public:
68+
69+
//Class constructor
70+
MCP9600(uint8_t address = DEV_ADDR, TwoWire &wirePort = Wire);
71+
72+
//Device status
73+
bool isConnected(); //Returns true if the thermocouple will acknowledge over I2C, and false otherwise
74+
uint16_t deviceID(); //Returns the contents of the device ID register. The upper 8 bits are constant, but the lower contain revision data.
75+
bool checkDeviceID(); //Returns true if the constant upper 8 bits in the device ID register are what they should be according to the datasheet.
76+
bool resetToDefaults(); //Resets all device parameters to their default values. Returns 1 if there was an error, zero otherwise.
77+
78+
//Sensor measurements
79+
float thermocoupleTemp(); //Returns the thermocouple temperature in degrees Celcius
80+
float ambientTemp(); //Returns the ambient (IC die) temperature in degrees Celcius
81+
float tempDelta(); //Returns the difference in temperature between the thermocouple and ambient junctions, in degrees Celcius
82+
83+
//Measurement configuration
84+
bool setAmbientResolution(ambientResolution res); //Changes the resolution on the cold (ambient) junction, for either 0.0625 or 0.25 degree C resolution. Lower resolution reduces conversion time.
85+
ambientResolution getAmbientResolution(); //Returns the resolution on the cold (ambient) junction, for either 0.0625 or 0.25 degree C resolution. Lower resolution reduces conversion time.
86+
bool setThermocoupleResolution(thermocoupleResolution res); //Changes the resolution on the hot (thermocouple) junction, for either 18, 16, 14, or 12-bit resolution. Lower resolution reduces conversion time.
87+
thermocoupleResolution getThermocoupleResolution(); //Returns the resolution on the hot (thermocouple) junction, for either 18, 16, 14, or 12-bit resolution. Lower resolution reduces conversion time.
88+
89+
uint8_t setThermocoupleType(thermocoupleType type); //Changes the type of thermocouple connected to the MCP9600. Supported types are KJTNSEBR.
90+
thermocoupleType getThermocoupleType(); //Returns the type of thermocouple connected to the MCP9600 as found in its configuration register. Supported types are KJTNSEBR.
91+
uint8_t setFilterCoeffecients(uint8_t coeffecient); //Changes the weight of the on-chip exponential moving average filter. Set this to 0 for no filter, 1 for minimum filter, and 7 for maximum filter.
92+
uint8_t getFilterCoeffecients(); //Returns the weight of the on-chip exponential moving average filter.
93+
94+
95+
//Internal I2C Abstraction
96+
private:
97+
TwoWire *_i2cPort; //Generic connection to user's chosen I2C port
98+
uint8_t _deviceAddress; //I2C address of the MCP9600
99+
uint8_t readSingleRegister(MCP9600_Register reg); //Attempts to read a single register, will keep trying for retryAttempts amount of times
100+
uint16_t readDoubleRegister(MCP9600_Register reg); //Attempts to read two registers, will keep trying for retryAttempts amount of times
101+
bool writeSingleRegister(MCP9600_Register reg, uint8_t data); //Attempts to write data into a single 8-bit register. Does not check to make sure it was written successfully.
74102
};
75103
#endif

0 commit comments

Comments
 (0)