Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: lib_MAX31856_example
lib_MAX31856.cpp
00001 /******************************************************************//** 00002 * @file lib_MAX31856.cpp 00003 * 00004 * @author Devin Alexander 00005 * 00006 * @version 1.0 00007 * 00008 * Started: SEPTEMBER 14th 2017 00009 * 00010 * Updated: Jully 2021 By Yannic Simon 00011 * 00012 * @brief Source file for MAX3185 class 00013 * 00014 *********************************************************************** 00015 * 00016 * @copyright 00017 * Copyright (C) 2015 Maxim Integrated Products, Inc., All Rights Reserved. 00018 * 00019 * Permission is hereby granted, free of charge, to any person obtaining a 00020 * copy of this software and associated documentation files (the "Software"), 00021 * to deal in the Software without restriction, including without limitation 00022 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 00023 * and/or sell copies of the Software, and to permit persons to whom the 00024 * Software is furnished to do so, subject to the following conditions: 00025 * 00026 * The above copyright notice and this permission notice shall be included 00027 * in all copies or substantial portions of the Software. 00028 * 00029 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00030 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00031 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00032 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES 00033 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 00034 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 00035 * OTHER DEALINGS IN THE SOFTWARE. 00036 * 00037 * Except as contained in this notice, the name of Maxim Integrated 00038 * Products, Inc. shall not be used except as stated in the Maxim Integrated 00039 * Products, Inc. Branding Policy. 00040 * 00041 * The mere transfer of this software does not imply any licenses 00042 * of trade secrets, proprietary technology, copyrights, patents, 00043 * trademarks, maskwork rights, or any other form of intellectual 00044 * property whatsoever. Maxim Integrated Products, Inc. retains all 00045 * ownership rights. 00046 **********************************************************************/ 00047 #include "lib_MAX31856.h" 00048 00049 #define LOG(args...) printf(args) 00050 00051 //***************************************************************************** 00052 MAX31856::MAX31856(SPI& _spi, PinName _ncs, uint8_t _type, uint8_t _fltr, uint8_t _samples, uint8_t _conversion_mode) : spi(_spi), ncs(_ncs), samples(_samples) 00053 { 00054 spi.format(8,3); //configure the correct SPI mode to beable to program the registers intially correctly 00055 init_MAX31856 &= setThermocoupleType(_type); 00056 init_MAX31856 &= setEmiFilterFreq(_fltr); 00057 init_MAX31856 &= setNumSamplesAvg(_samples); 00058 init_MAX31856 &= setConversionMode(_conversion_mode); 00059 lastReadTime = time(NULL); 00060 wait_us(1000000); 00061 } 00062 00063 00064 //***************************************************************************** 00065 float MAX31856::readTC() 00066 { 00067 //Check and see if the MAX31856 is set to conversion mode ALWAYS ON 00068 if (conversion_mode==0) { //means that the conversion mode is normally off 00069 init_MAX31856 &= setOneShotMode(CR0_1_SHOT_MODE_ONE_CONVERSION); // turn on the one shot mode for singular conversion 00070 thermocouple_conversion_count=0; //reset the conversion count back to zero to make sure minimum conversion time reflects one shot mode requirements 00071 } 00072 if(!init_MAX31856) return NAN; 00073 //calculate minimum wait time for conversions 00074 calculateDelayTime(); 00075 //initialize other info for the read functionality 00076 uint32_t buf_read[3] = {0}, buf_write[3] = {ADDRESS_LTCBH_READ, ADDRESS_LTCBM_READ, ADDRESS_LTCBL_READ}; 00077 if(checkFaultsThermocoupleConnection()) //no faults with connection are present so continue on with normal read of temperature 00078 { 00079 uint32_t tm = time(NULL)*1000000; 00080 uint32_t duration = tm - lastReadTime; 00081 lastReadTime = tm; 00082 if (duration > conversion_time) 00083 { 00084 for(int i=0; i<3; i++) buf_read[i] = registerReadByte(buf_write[i]); 00085 //Convert the registers contents into the correct value 00086 int32_t temp = ((buf_read[0] & 0xFF) << 0x18) + ((buf_read[1] & 0xFF) << 0x10) + ((buf_read[2] & 0xFF) << 0x08); // LTCBH + LTCBM + LTCBL 00087 return prev_TC = (temp >> 0x0D) * 0.0078125; 00088 } 00089 } 00090 thermocouple_conversion_count++; //iterate the conversion count to speed up time in between future converions in always on mode 00091 checkFaultsThermocoupleThresholds(); //print any faults to the terminal 00092 return prev_TC; 00093 } 00094 00095 00096 //***************************************************************************** 00097 float MAX31856::readCJ() 00098 { 00099 if(!init_MAX31856) return NAN; 00100 uint32_t buf_read[2] = {0}, buf_write[2] = {ADDRESS_CJTH_READ, ADDRESS_CJTL_READ}; 00101 for(int i=0; i<2; i++) buf_read[i] = registerReadByte(buf_write[i]); 00102 int16_t temp = ((buf_read[0] & 0xFF) << 8) + (buf_read[1] & 0xFF); // CJTH + CJTL 00103 return temp/256.0; 00104 } 00105 00106 //***************************************************************************** 00107 uint8_t MAX31856::checkFaultsThermocoupleThresholds() 00108 { 00109 uint8_t fault_byte=registerReadByte(ADDRESS_SR_READ); //Read contents of fault status register 00110 uint8_t temp[2], return_int; 00111 for(int i=0; i<2; i++) 00112 temp[i]=fault_byte; 00113 00114 //Check if any of the faults for thermocouple connection are triggered 00115 if ((fault_byte&0x4C)==0) //means no fault is detected for thermocouple thresholds 00116 return_int=0; 00117 else { 00118 if ((fault_byte&0x40)==0) { //check if normal operation of thermocouple is true 00119 if (temp[0]&0x08) { 00120 LOG("FAULT! Thermocouple temp is higher than the threshold that is set!\r\n"); 00121 return_int=1; 00122 } 00123 else if (temp[1]&0x04) { 00124 LOG("FAULT! Thermocouple temp is lower than the threshold that is set!\r\n"); 00125 return_int=2; 00126 } 00127 } 00128 else { //Thermocouples is operating outside of normal range 00129 LOG("FAULT! Thermocouple temperature is out of range for specific type of thermocouple!\r\n"); 00130 if (temp[0]&0x08) { 00131 LOG("FAULT! Thermocouple temp is higher than the threshold that is set!\r\n"); 00132 return_int=4; 00133 } 00134 else if (temp[1]&0x04) { 00135 LOG("FAULT! Thermocouple temp is lower than the threshold that is set!\r\n"); 00136 return_int=5; 00137 } 00138 else //no other faults are flagged besides unnatural operation 00139 return_int=3; 00140 } 00141 } 00142 return return_int; 00143 } 00144 00145 //***************************************************************************** 00146 uint8_t MAX31856::checkFaultsColdJunctionThresholds() 00147 { 00148 uint8_t fault_byte=registerReadByte(ADDRESS_SR_READ); //Read contents of fault status register 00149 uint8_t temp[2], return_int; 00150 for(int i=0; i<2; i++) 00151 temp[i]=fault_byte; 00152 00153 //Check if any of the faults for thermocouple connection are triggered 00154 if ((fault_byte&0xB0)==0) //means no fault is detected for cold junction thresholds 00155 return_int=0; 00156 else { 00157 if ((fault_byte&0x80)==0) { //check if normal operation of cold junction is true 00158 if (temp[0]&0x20) { 00159 LOG("FAULT! Cold Junction temp is higher than the threshold that is set!\r\n"); 00160 return_int=1; 00161 } 00162 else if (temp[1]&0x10) { 00163 LOG("FAULT! Cold Junction temp is lower than the threshold that is set!\r\n"); 00164 return_int=2; 00165 } 00166 } 00167 else { //Cold Junction is operating outside of normal range 00168 LOG("FAULT! Cold Junction temperature is out of range for specific type of thermocouple!\r\n"); 00169 if (temp[0]&0x20) { 00170 LOG("FAULT! Cold Junction temp is higher than the threshold that is set!\r\n"); 00171 return_int=4; 00172 } 00173 else if (temp[1]&0x10) { 00174 LOG("FAULT! Cold Junction temp is lower than the threshold that is set!\r\n"); 00175 return_int=5; 00176 } 00177 else //no other faults are flagged besides unnatural operation 00178 return_int=3; 00179 } 00180 } 00181 return return_int; 00182 } 00183 00184 //***************************************************************************** 00185 bool MAX31856::checkFaultsThermocoupleConnection() 00186 { 00187 return !registerReadByte(ADDRESS_SR_READ); //Read contents of fault status register 00188 } 00189 00190 00191 //Register:CR0 Bits: 7 00192 //***************************************************************************** 00193 bool MAX31856::setConversionMode(uint8_t val) 00194 { 00195 switch(val) 00196 { 00197 case CR0_CONV_MODE_NORMALLY_OFF: case CR0_CONV_MODE_NORMALLY_ON: 00198 conversion_mode = (val == CR0_CONV_MODE_NORMALLY_ON)?1:0; 00199 return registerReadWriteByte(ADDRESS_CR0_READ, ADDRESS_CR0_WRITE, CR0_CLEAR_BITS_7, val); 00200 break; 00201 default: 00202 //LOG("Incorrect parameter selected for Control Register 0 (CR0) bit 7. Default value not changed.\r\nPlease see MAX31856.h for list of valid parameters. \r\n"); 00203 return false; 00204 break; 00205 } 00206 } 00207 00208 00209 //Register:CR0 Bits: 6 00210 //***************************************************************************** 00211 bool MAX31856::setOneShotMode(uint8_t val) 00212 { 00213 switch(val) 00214 { 00215 case CR0_1_SHOT_MODE_NO_CONVERSION: case CR0_1_SHOT_MODE_ONE_CONVERSION: 00216 return registerReadWriteByte(ADDRESS_CR0_READ, ADDRESS_CR0_WRITE, CR0_CLEAR_BITS_6, val); 00217 break; 00218 default: 00219 //LOG("Incorrect parameter selected for Control Register 0 (CR0) bit 6. Default value not changed.\r\nPlease see MAX31856.h for list of valid parameters. \r\n"); 00220 return false; 00221 break; 00222 } 00223 } 00224 00225 00226 //Register:CR0 Bits: 5:4 00227 //***************************************************************************** 00228 bool MAX31856::setOpenCircuitFaultDetection(uint8_t val) 00229 { 00230 switch(val) 00231 { 00232 case CR0_OC_DETECT_DISABLED: case CR0_OC_DETECT_ENABLED_R_LESS_5k: case CR0_OC_DETECT_ENABLED_TC_LESS_2ms: case CR0_OC_DETECT_ENABLED_TC_MORE_2ms: 00233 return registerReadWriteByte(ADDRESS_CR0_READ, ADDRESS_CR0_WRITE, CR0_CLEAR_BITS_5_4, val); 00234 break; 00235 default: 00236 //LOG("Incorrect parameter selected for Control Register 0 (CR0) bits 5:4. Default value not changed.\r\nPlease see MAX31856.h for list of valid parameters. \r\n"); 00237 return false; 00238 break; 00239 } 00240 } 00241 00242 00243 //Register:CR0 Bits: 3 00244 //***************************************************************************** 00245 bool MAX31856::setColdJunctionDisable(uint8_t val) 00246 { 00247 switch(val) 00248 { 00249 case CR0_COLD_JUNC_ENABLE: case CR0_COLD_JUNC_DISABLE: 00250 cold_junction_enabled = (val==CR0_COLD_JUNC_ENABLE)?1:0; 00251 return registerReadWriteByte(ADDRESS_CR0_READ, ADDRESS_CR0_WRITE, CR0_CLEAR_BITS_3, val); 00252 break; 00253 default: 00254 //LOG("Incorrect parameter selected for Control Register 0 (CR0) bit 3. Default value not changed.\r\nPlease see MAX31856.h for list of valid parameters. \r\n"); 00255 return false; 00256 break; 00257 } 00258 } 00259 00260 00261 //Register:CR0 Bits: 2 00262 //***************************************************************************** 00263 bool MAX31856::setFaultMode(uint8_t val) 00264 { 00265 switch(val) 00266 { 00267 case CR0_FAULT_MODE_COMPARATOR: case CR0_FAULT_MODE_INTERUPT: 00268 return registerReadWriteByte(ADDRESS_CR0_READ, ADDRESS_CR0_WRITE, CR0_CLEAR_BITS_2, val); 00269 break; 00270 default: 00271 //LOG("Incorrect parameter selected for Control Register 0 (CR0) bit 2. Default value not changed.\r\nPlease see MAX31856.h for list of valid parameters. \r\n"); 00272 return false; 00273 break; 00274 } 00275 } 00276 00277 00278 //Register:CR0 Bits: 1 00279 //***************************************************************************** 00280 bool MAX31856::setFaultStatusClear(uint8_t val) 00281 { 00282 switch(val) 00283 { 00284 case CR0_FAULTCLR_DEFAULT_VAL: case CR0_FAULTCLR_RETURN_FAULTS_TO_ZERO: 00285 return registerReadWriteByte(ADDRESS_CR0_READ, ADDRESS_CR0_WRITE, CR0_CLEAR_BITS_1, val); 00286 break; 00287 default: 00288 //LOG("Incorrect parameter selected for Control Register 0 (CR0) bit 1. Default value not changed.\r\nPlease see MAX31856.h for list of valid parameters. \r\n"); 00289 return false; 00290 break; 00291 } 00292 } 00293 00294 00295 //Register:CR0 Bits: 0 00296 //***************************************************************************** 00297 bool MAX31856::setEmiFilterFreq(uint8_t val) 00298 { 00299 switch(val) 00300 { 00301 case CR0_FILTER_OUT_60Hz: case CR0_FILTER_OUT_50Hz: 00302 filter_mode = val; 00303 return registerReadWriteByte(ADDRESS_CR0_READ, ADDRESS_CR0_WRITE, CR0_CLEAR_BITS_0, val); 00304 break; 00305 default: 00306 //LOG("Incorrect parameter selected for Control Register 0 (CR0) bit 0. Default value not changed.\r\nPlease see MAX31856.h for list of valid parameters. \r\n"); 00307 return false; 00308 break; 00309 } 00310 } 00311 00312 00313 //Register:CR1 Bits: 6:4 00314 //***************************************************************************** 00315 bool MAX31856::setNumSamplesAvg(uint8_t val) 00316 { 00317 switch(val) 00318 { 00319 case CR1_AVG_TC_SAMPLES_1: case CR1_AVG_TC_SAMPLES_2: case CR1_AVG_TC_SAMPLES_4: case CR1_AVG_TC_SAMPLES_8: case CR1_AVG_TC_SAMPLES_16: 00320 samples = 1 << (val >> 4); 00321 return registerReadWriteByte(ADDRESS_CR1_READ, ADDRESS_CR1_WRITE, CR1_CLEAR_BITS_6_4, val); 00322 break; 00323 default: 00324 //LOG("Incorrect parameter selected for Control Register 1 (CR1) bits 6:4. Default value not changed.\r\nPlease see MAX31856.h for list of valid parameters. \r\n"); 00325 return false; 00326 break; 00327 } 00328 } 00329 00330 00331 //Register:CR1 Bits: 3:0 00332 //***************************************************************************** 00333 bool MAX31856::setThermocoupleType(uint8_t val) 00334 { 00335 switch(val) 00336 { 00337 case CR1_TC_TYPE_B: case CR1_TC_TYPE_E: case CR1_TC_TYPE_J: case CR1_TC_TYPE_K: case CR1_TC_TYPE_N: case CR1_TC_TYPE_R: case CR1_TC_TYPE_S: case CR1_TC_TYPE_T: case CR1_TC_TYPE_VOLT_MODE_GAIN_8: case CR1_TC_TYPE_VOLT_MODE_GAIN_32: 00338 voltage_mode = ((val == CR1_TC_TYPE_VOLT_MODE_GAIN_8) || (val == CR1_TC_TYPE_VOLT_MODE_GAIN_32)); 00339 return registerReadWriteByte(ADDRESS_CR1_READ, ADDRESS_CR1_WRITE, CR1_CLEAR_BITS_3_0, val); 00340 break; 00341 default: 00342 //LOG("Incorrect parameter selected for Control Register 1 (CR1) bits 3:0. Default value not changed.\r\nPlease see MAX31856.h for list of valid parameters. \r\n"); 00343 return false; 00344 break; 00345 } 00346 } 00347 00348 00349 //Register:MASK Bits: 5:0 00350 //***************************************************************************** 00351 bool MAX31856::setFaultMasks(uint8_t val, bool enable) 00352 { 00353 if(enable) val = 0; 00354 switch(val) 00355 { 00356 case MASK_CJ_FAULT_THRESHOLD_HIGH: 00357 return registerReadWriteByte(ADDRESS_MASK_READ, ADDRESS_MASK_WRITE, MASK_CLEAR_BITS_5, val); 00358 break; 00359 case MASK_CJ_FAULT_THRESHOLD_LOW: 00360 return registerReadWriteByte(ADDRESS_MASK_READ, ADDRESS_MASK_WRITE, MASK_CLEAR_BITS_4, val); 00361 break; 00362 case MASK_TC_FAULT_THRESHOLD_HIGH: 00363 return registerReadWriteByte(ADDRESS_MASK_READ, ADDRESS_MASK_WRITE, MASK_CLEAR_BITS_3, val); 00364 break; 00365 case MASK_TC_FAULT_THRESHOLD_LOW: 00366 return registerReadWriteByte(ADDRESS_MASK_READ, ADDRESS_MASK_WRITE, MASK_CLEAR_BITS_2, val); 00367 break; 00368 case MASK_OVER_UNDER_VOLT_FAULT: 00369 return registerReadWriteByte(ADDRESS_MASK_READ, ADDRESS_MASK_WRITE, MASK_CLEAR_BITS_1, val); 00370 break; 00371 case MASK_OPEN_CIRCUIT_FAULT: 00372 return registerReadWriteByte(ADDRESS_MASK_READ, ADDRESS_MASK_WRITE, MASK_CLEAR_BITS_0, val); 00373 break; 00374 default: 00375 //LOG("Incorrect parameter selected for Mask Register bits 5:0. Default value not changed.\r\nPlease see MAX31856.h for list of valid parameters. \r\n"); 00376 return false; 00377 break; 00378 } 00379 } 00380 00381 00382 //Register:MASK Bits: 5:0 00383 //****************************************************************************** 00384 bool MAX31856::setFaultThresholds(uint8_t val, float temperature) 00385 { 00386 switch(val) 00387 { 00388 case MASK_CJ_FAULT_THRESHOLD_HIGH: 00389 return registerWriteByte(ADDRESS_CJHF_WRITE, temperature); 00390 break; 00391 case MASK_CJ_FAULT_THRESHOLD_LOW: 00392 return registerWriteByte(ADDRESS_CJLF_WRITE, temperature); 00393 break; 00394 case MASK_TC_FAULT_THRESHOLD_HIGH:{ 00395 int8_t temperature_byte[2]; 00396 int16_t temperature_multi_byte =temperature*4.0; 00397 temperature_byte[0]=((uint8_t)((temperature_multi_byte)&(0xFF00) >> 8)); 00398 temperature_byte[1]=((uint8_t)((temperature_multi_byte)&(0x00FF))); 00399 return registerWriteByte(ADDRESS_LTHFTH_WRITE, temperature_byte[0]) && registerWriteByte(ADDRESS_LTHFTL_WRITE, temperature_byte[1]);} 00400 break; 00401 case MASK_TC_FAULT_THRESHOLD_LOW:{ 00402 int8_t temperature_byte[2]; 00403 int16_t temperature_multi_byte =temperature*4.0; 00404 temperature_byte[0]=((uint8_t)((temperature_multi_byte)&(0xFF00) >> 8)); 00405 temperature_byte[1]=((uint8_t)((temperature_multi_byte)&(0x00FF))); 00406 return registerWriteByte(ADDRESS_LTLFTH_WRITE, temperature_byte[0]) && registerWriteByte(ADDRESS_LTLFTL_WRITE, temperature_byte[1]);} 00407 break; 00408 default: 00409 return false; 00410 //LOG("Please select correct threshold register to program with the correct value!\r\n"); 00411 break; 00412 } 00413 } 00414 00415 //****************************************************************************** 00416 bool MAX31856::coldJunctionOffset(float temperature) 00417 { 00418 if (temperature > 7.9375 || temperature < -8.0) 00419 { 00420 //LOG("Input value to offest the cold junction point is non valid. enter in value in range -8 to +7.9375\r\n"); 00421 return false; 00422 } 00423 int8_t temp_val=temperature*16.0f; //normalize the value to get rid of decimal and shorten it to size of register 00424 return registerWriteByte(ADDRESS_CJTO_WRITE, temp_val); //write the byte to cold junction offset register 00425 } 00426 00427 00428 //The following functions are for internal library use only 00429 //****************************************************************************** 00430 void MAX31856::spiEnable() 00431 { 00432 ncs=0; //Set CS low to start transmission (interrupts conversion) 00433 return; 00434 } 00435 00436 00437 //****************************************************************************** 00438 void MAX31856::spiDisable() 00439 { 00440 ncs=1; //Set CS high to stop transmission (restarts conversion) 00441 return; 00442 } 00443 00444 00445 //****************************************************************************** 00446 bool MAX31856::registerReadWriteByte(uint8_t read_address, uint8_t write_address, int clear_bits, uint8_t val) 00447 { 00448 //Read the current contents of a register 00449 uint8_t buf_read = registerReadByte(read_address); 00450 00451 //Modify contents pulled from the register 00452 buf_read &= clear_bits; //Clear the contents of bits of parameter you are trying to clear for later or equal operation 00453 buf_read |= val; //Bitwise OR the input parameter with cleaned buf_read[1] to create new byte 00454 val = buf_read; 00455 00456 //Write the updated byte to the register 00457 registerWriteByte(write_address, val); 00458 00459 //Read the current contents of a register 00460 buf_read = registerReadByte(read_address); 00461 00462 return buf_read == val; 00463 } 00464 00465 00466 //****************************************************************************** 00467 bool MAX31856::registerWriteByte(uint8_t write_address, uint8_t val) 00468 { 00469 //Write the updated byte to the register 00470 spiEnable(); 00471 spi.write(write_address); 00472 spi.write(val); 00473 spiDisable(); 00474 return true; 00475 } 00476 00477 //****************************************************************************** 00478 uint8_t MAX31856::registerReadByte(uint8_t read_address) 00479 { 00480 spiEnable(); 00481 spi.write(read_address); 00482 uint8_t buf_read = spi.write(0); 00483 spiDisable(); 00484 return buf_read; 00485 } 00486 00487 //****************************************************************************** 00488 void MAX31856::calculateDelayTime() { 00489 uint32_t temp_int; 00490 00491 if (conversion_mode==0 || thermocouple_conversion_count==0) { 00492 if (filter_mode==0) //60Hz 00493 temp_int=82+(samples-1)*33.33f; 00494 else //50Hz 00495 temp_int=98+(samples-1)*40.00f; 00496 } 00497 else { 00498 if (filter_mode==0) //60Hz 00499 temp_int=82+(samples-1)*16.67f; 00500 else //50Hz 00501 temp_int=98+(samples-1)*20.00f; 00502 } 00503 00504 if (cold_junction_enabled==0) //cold junction is disabled enabling 25 millisecond faster conversion times 00505 temp_int=temp_int-25; 00506 conversion_time=1000*temp_int; //set private member conversion time to calculated minimum wait time in microseconds 00507 return; 00508 } 00509 00510 //***************************************************************************** 00511 MAX31856::~MAX31856(void) 00512 { 00513 //empty block 00514 }
Generated on Thu Jul 14 2022 06:27:04 by
1.7.2