Library for MAX31850 thermocouple temperature sensor
Revision 0:5530bf2d0e94, committed 2019-01-23
- Comitter:
- croberts21
- Date:
- Wed Jan 23 23:44:57 2019 +0000
- Commit message:
- All files added
Changed in this revision
diff -r 000000000000 -r 5530bf2d0e94 LinkedList.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LinkedList.cpp Wed Jan 23 23:44:57 2019 +0000 @@ -0,0 +1,194 @@ +/** + * @file LinkedList.cpp + * @brief Core Utility - Templated Linked List class + * @author sam grove + * @version 1.0 + * @see + * + * Copyright (c) 2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "LinkedList.h" // api wrapper + +template<class retT> +LinkedList<retT>::LinkedList() +{ + // clear the member + _head = 0; + + return; +} + +template<class retT> +LinkedList<retT>::~LinkedList() +{ + // free any memory that is on the heap + while(remove(1) != NULL); + + return; +} + +template<class retT> +retT *LinkedList<retT>::push(void *data) +{ + retT *new_node = new retT [1]; + // make sure the new object was allocated + if (0 == new_node) + { + error("Memory allocation failed\n"); + } + // update the next item in the list to the current head + new_node->next = _head; + // store the address to the linked datatype + new_node->data = data; + _head = new_node; + + return _head; +} + +//template<class retT> +//retT *LinkedList<retT>::insert(void *data, uint32_t loc) +//{ +// retT *new_node = new retT [1]; +// // make sure the new object was allocated +// if (0 == new_node) +// { +// error("Memory allocation failed\n"); +// } +// retT *current = _head->next; +// retT *prev = _head; +// // move to the item we want to insert +// for (uint32_t i=1; i!=(loc-1); i++) +// { +// prev = current; +// current = current->next; +// } +// // store the address to the linked datatype +// new_node->data = data; +// // clear the next pointer +// new_node->next = 0; +// // update the list and store the new stuff +// prev->next = new_node; +// new_node->next = current; +// // store the address to the linked datatype +// _head->data = data; +// +// return prev->next; +//} + +template<class retT> +retT *LinkedList<retT>::append(void *data) +{ + retT *current = _head; + retT *new_node = new retT [1]; + // make sure the new object was allocated + if (0 == new_node) + { + error("Memory allocation failed\n"); + } + // store the address to the linked datatype + new_node->data = data; + // clear the next pointer + new_node->next = 0; + // check for an empty list + if (0 == current) + { + _head = new_node; + return _head; + } + else + { + // look for the end of the list + while (current->next != 0) + { + current = current->next; + } + // and then add the new item to the list + current->next = new_node; + } + + return current->next; +} + +template<class retT> +retT *LinkedList<retT>::remove(uint32_t loc) +{ + retT *current = _head; + retT *prev = 0; + // make sure we have an item to remove + if ((loc <= length()) && (loc > 0)) + { + // move to the item we want to delete + if (1 == loc) + { + _head = current->next; + delete [] current; + } + else + { + for (uint32_t i=2; i<=loc; ++i) + { + prev = current; + current = current->next; + } + // store the item + 1 to replace what we are deleting + prev->next = current->next; + delete [] current; + } + } + + return _head; +} + +template<class retT> +retT *LinkedList<retT>::pop(uint32_t loc) +{ + retT *current = _head; + // make sure we have something in the location + if ((loc > length()) || (loc == 0)) + { + return 0; + } + // and if so jump down the list + for (uint32_t i=2; i<=loc; ++i) + { + current = current->next; + } + + return current; +} + +template<class retT> +uint32_t LinkedList<retT>::length(void) +{ + int32_t count = 0; + retT *current = _head; + //loop until the end of the list is found + while (current != 0) + { + ++count; + current = current->next; + } + + return count; +} + +// pre-define the type for the linker +template class LinkedList<node>; + + + + +
diff -r 000000000000 -r 5530bf2d0e94 LinkedList.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LinkedList.h Wed Jan 23 23:44:57 2019 +0000 @@ -0,0 +1,124 @@ +/** + * @file LinkedList.h + * @brief Core Utility - Templated Linked List class + * @author sam grove + * @version 1.0 + * @see + * + * Copyright (c) 2013 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef LINKEDLIST_H_ +#define LINKEDLIST_H_ + +#include <stdint.h> +#include "mbed.h" + +/** + * @struct node + * @brief The Linked List structure + */ +struct node +{ + void *data; /*!< pointer to list member data */ + struct node *next; /*!< pointer to the next list member */ +}; + +/** Example using the LinkedList Class + * @code + * #include "mbed.h" + * #include "LinkedList.h" + * + * LinkedList<node>list; + * + * int main() + * { + * node *tmp; + * + * list.push((char *)"Two\n"); + * list.append((char *)"Three\n"); + * list.append((char *)"Four\n"); + * list.push((char*)"One\n"); + * list.append((char*)"Five\n"); + * + * for(int i=1; i<=list.length(); i++) + * { + * tmp = list.pop(i); + * printf("%s", (char *)tmp->data); + * } + * + * error("done\n"); + * } + * @endcode + */ + +/** + * @class LinkedList + * @brief API abstraction for a Linked List + */ +template<class retT> +class LinkedList +{ +protected: + retT *_head; + +public: + /** Create the LinkedList object + */ + LinkedList(); + + /** Deconstructor for the LinkedList object + * Removes any members + */ + ~LinkedList(); + + /** Add a member to the begining of the list + * @param data - Some data type that is added to the list + * @return The member that was just inserted (NULL if empty) + */ + retT *push(void *data); + +// /** Add a member to some position in the list +// * @param data - Some data type that is added to the list +// * @param loc - Place in the list to put the data +// * @return The member that was just inserted (NULL if empty) +// */ +// retT *insert(void *data, uint32_t loc); + + /** Add a member to the end of the list + * @param data - Some data type that is added to the list + * @return The member that was just inserted (NULL if empty) + */ + retT *append(void *data); + + /** Remove a member from the list + * @param loc - The location of the member to remove + * @return The head of the list + */ + retT *remove(uint32_t loc); + + /** Get access to a member from the list + * @param loc - The location of the member to access + * @return The member that was just requested (NULL if empty or out of bounds) + */ + retT *pop(uint32_t loc); + + /** Get the length of the list + * @return The number of members in the list + */ + uint32_t length(void); +}; + +#endif /* LINKEDLIST_H_ */
diff -r 000000000000 -r 5530bf2d0e94 MAX31850.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MAX31850.cpp Wed Jan 23 23:44:57 2019 +0000 @@ -0,0 +1,364 @@ +#include "MAX31850.h" + +Serial pc(USBTX, USBRX); + +#define ONEWIRE_INPUT(pin) pin->input() +#define ONEWIRE_OUTPUT(pin) pin->output() +#define ONEWIRE_INIT(pin) + +LinkedList<node> MAX31850::probes; + + +MAX31850::MAX31850 (PinName data_pin, PinName power_pin, bool power_polarity) : _datapin(data_pin), _parasitepin(power_pin) { + int byte_counter; + _power_polarity = power_polarity; + + _power_mosfet = power_pin != NC; + + for(byte_counter=0;byte_counter<9;byte_counter++) + scratchpad[byte_counter] = 0x00; + + ONEWIRE_INIT((&_datapin)); + + if (!unassignedProbe(&_datapin, _ROM)) + error("No unassigned MAX31850 found!\n"); + else { + _datapin.input(); + probes.append(this); + _parasite_power = false; //only set up to use external power right now + } +} + +MAX31850::~MAX31850 (void) { + node *tmp; + for(int i=1; i<=probes.length(); i++) + { + tmp = probes.pop(i); + if (tmp->data == this) + probes.remove(i); + } +} + + +bool MAX31850::onewire_reset(DigitalInOut *pin) { +// This will return false if no devices are present on the data bus + bool presence=false; + ONEWIRE_OUTPUT(pin); + pin->write(0); // bring low for 500 us + wait_us(500); + ONEWIRE_INPUT(pin); // let the data line float high + wait_us(90); // wait 90us + if (pin->read()==0) // see if any devices are pulling the data line low + presence=true; + wait_us(410); + return presence; +} + +void MAX31850::onewire_bit_out (DigitalInOut *pin, bool bit_data) { + ONEWIRE_OUTPUT(pin); + pin->write(0); + wait_us(3); // DXP modified from 5 + if (bit_data) { + pin->write(1); // bring data line high + wait_us(55); + } else { + wait_us(55); // keep data line low + pin->write(1); + wait_us(10); // DXP added to allow bus to float high before next bit_out + } +} + +void MAX31850::onewire_byte_out(char data) { // output data character (least sig bit first). + int n; + for (n=0; n<8; n++) { + onewire_bit_out(&this->_datapin, data & 0x01); + data = data >> 1; // now the next bit is in the least sig bit position. + } +} + +bool MAX31850::onewire_bit_in(DigitalInOut *pin) { + bool answer; + ONEWIRE_OUTPUT(pin); + pin->write(0); + wait_us(3); // DXP modified from 5 + ONEWIRE_INPUT(pin); + wait_us(10); // DXP modified from 5 + answer = pin->read(); + wait_us(45); // DXP modified from 50 + return answer; +} + +char MAX31850::onewire_byte_in() { // read byte, least sig byte first + char answer = 0x00; + int i; + for (i=0; i<8; i++) { + answer = answer >> 1; // shift over to make room for the next bit + if (onewire_bit_in(&this->_datapin)) + answer = answer | 0x80; // if the data port is high, make this bit a 1 + } + return answer; +} + +bool MAX31850::unassignedProbe(PinName pin) { + DigitalInOut _pin(pin); + ONEWIRE_INIT((&_pin)); + char ROM_address[8]; + return search_ROM_routine(&_pin, 0xF0, ROM_address); +} + +bool MAX31850::unassignedProbe(DigitalInOut *pin, char *ROM_address) { + return search_ROM_routine(pin, 0xF0, ROM_address); +} + +bool MAX31850::search_ROM_routine(DigitalInOut *pin, char command, char *ROM_address) { + bool DS1820_done_flag = false; + int DS1820_last_discrepancy = 0; + char DS1820_search_ROM[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + + int discrepancy_marker, ROM_bit_index; + bool return_value, Bit_A, Bit_B; + char byte_counter, bit_mask; + + return_value=false; + while (!DS1820_done_flag) { + if (!onewire_reset(pin)) { + return false; + } else { + ROM_bit_index=1; + discrepancy_marker=0; + char command_shift = command; + for (int n=0; n<8; n++) { // Search ROM command + onewire_bit_out(pin, command_shift & 0x01); + command_shift = command_shift >> 1; // now the next bit is in the least sig bit position. + } + byte_counter = 0; + bit_mask = 0x01; + while (ROM_bit_index<=64) { + Bit_A = onewire_bit_in(pin); + Bit_B = onewire_bit_in(pin); + if (Bit_A & Bit_B) { + discrepancy_marker = 0; // data read error, this should never happen + ROM_bit_index = 0xFF; + } else { + if (Bit_A | Bit_B) { + // Set ROM bit to Bit_A + if (Bit_A) { + DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] | bit_mask; // Set ROM bit to one + } else { + DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] & ~bit_mask; // Set ROM bit to zero + } + } else { + // both bits A and B are low, so there are two or more devices present + if ( ROM_bit_index == DS1820_last_discrepancy ) { + DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] | bit_mask; // Set ROM bit to one + } else { + if ( ROM_bit_index > DS1820_last_discrepancy ) { + DS1820_search_ROM[byte_counter] = DS1820_search_ROM[byte_counter] & ~bit_mask; // Set ROM bit to zero + discrepancy_marker = ROM_bit_index; + } else { + if (( DS1820_search_ROM[byte_counter] & bit_mask) == 0x00 ) + discrepancy_marker = ROM_bit_index; + } + } + } + onewire_bit_out (pin, DS1820_search_ROM[byte_counter] & bit_mask); + ROM_bit_index++; + if (bit_mask & 0x80) { + byte_counter++; + bit_mask = 0x01; + } else { + bit_mask = bit_mask << 1; + } + } + } + DS1820_last_discrepancy = discrepancy_marker; + if (ROM_bit_index != 0xFF) { + int i = 1; + node *list_container; + while(1) { + list_container = probes.pop(i); + if (list_container == NULL) { //End of list, or empty list + if (ROM_checksum_error(DS1820_search_ROM)) { // Check the CRC + return false; + } + for(byte_counter=0;byte_counter<8;byte_counter++) + ROM_address[byte_counter] = DS1820_search_ROM[byte_counter]; + return true; + } else { //Otherwise, check if ROM is already known + bool equal = true; + MAX31850 + *pointer = (MAX31850 + *) list_container->data; + char *ROM_compare = pointer->_ROM; + + for(byte_counter=0;byte_counter<8;byte_counter++) { + if ( ROM_compare[byte_counter] != DS1820_search_ROM[byte_counter]) + equal = false; + } + if (equal) + break; + else + i++; + } + } + } + } + if (DS1820_last_discrepancy == 0) + DS1820_done_flag = true; + } + return return_value; +} + +void MAX31850::match_ROM() { +// Used to select a specific device + int i; + onewire_reset(&this->_datapin); + onewire_byte_out( 0x55); //Match ROM command + for (i=0;i<8;i++) { + onewire_byte_out(_ROM[i]); + } +} + +void MAX31850::skip_ROM() { + onewire_reset(&this->_datapin); + onewire_byte_out(0xCC); // Skip ROM command +} + +bool MAX31850::ROM_checksum_error(char *_ROM_address) { + char _CRC=0x00; + int i; + for(i=0;i<7;i++) // Only going to shift the lower 7 bytes + _CRC = CRC_byte(_CRC, _ROM_address[i]); + // After 7 bytes CRC should equal the 8th byte (ROM CRC) + return (_CRC!=_ROM_address[7]); // will return true if there is a CRC checksum mis-match +} + +bool MAX31850::scratchpad_checksum_error() { + char _CRC=0x00; + int i; + for(i=0;i<8;i++) // Only going to shift the lower 8 bytes + _CRC = CRC_byte(_CRC, scratchpad[i]); + // After 8 bytes CRC should equal the 9th byte (scratchpad CRC) + return (_CRC!=scratchpad[8]); // will return true if there is a CRC checksum mis-match +} + +char MAX31850::CRC_byte (char _CRC, char byte ) { + int j; + for(j=0;j<8;j++) { + if ((byte & 0x01 ) ^ (_CRC & 0x01)) { + // DATA ^ LSB CRC = 1 + _CRC = _CRC>>1; + // Set the MSB to 1 + _CRC = _CRC | 0x80; + // Check bit 3 + if (_CRC & 0x04) { + _CRC = _CRC & 0xFB; // Bit 3 is set, so clear it + } else { + _CRC = _CRC | 0x04; // Bit 3 is clear, so set it + } + // Check bit 4 + if (_CRC & 0x08) { + _CRC = _CRC & 0xF7; // Bit 4 is set, so clear it + } else { + _CRC = _CRC | 0x08; // Bit 4 is clear, so set it + } + } else { + // DATA ^ LSB CRC = 0 + _CRC = _CRC>>1; + // clear MSB + _CRC = _CRC & 0x7F; + // No need to check bits, with DATA ^ LSB CRC = 0, they will remain unchanged + } + byte = byte>>1; + } +return _CRC; +} + +void MAX31850::readAll() { + // Convert temperature into scratchpad for all devices at once + int delay_time = 75; //default delay time + + skip_ROM(); //Skip ROM command, will convert for all devices + + onewire_byte_out( 0x44); //perform temperature conversion + + wait_ms(delay_time); +} + +void MAX31850::read_scratchpad() { + // This will copy the MAX31850's 9 bytes of scratchpad data + // into the objects scratchpad array. Functions that use + // scratchpad values will automaticaly call this procedure. + int i; + match_ROM(); // Select this device + onewire_byte_out( 0xBE); //Read Scratchpad command + for(i=0;i<9;i++) { + scratchpad[i] = onewire_byte_in(); + } +} + + +float MAX31850::getTemp(int scale) { + float answer; + int reading; + read_scratchpad(); + if (scratchpad_checksum_error()) { + //indicate we got a CRC error + answer = invalid_conversion; + pc.printf("CRC Error\r\n"); + } + else { + reading = (scratchpad[1] << 8) + scratchpad[0]; //combine first two bytes of scratchpad + reading = reading >> 2; //shift right two to drop unused bits + if (reading & 0x2000) { //check MSB to determin sign + reading = 0-((reading ^ 0x3fff) + 1); //use 2's compliment to convert back to positive number and make it a signed int + } + answer = reading +0.0; //convert to floating point + answer = answer / 4.0; //shift decimal place over two places + + //unit convertion + //checks for passed in value first and if there is none it sets the units baced on class units variable + switch(scale) { + case C: + break; + case K: + answer = answer + 273.15f; + break; + case F: + answer = answer * 1.8f + 32.0f; + break; + case R: + answer = answer * 1.8f + 491.67f; + break; + default: + switch(_units) { + case C: + break; + case K: + answer = answer + 273.15f; + break; + case F: + answer = answer * 1.8f + 32.0f; + break; + case R: + answer = answer * 1.8f + 491.67f; + break; + } + } + } + return answer; +} + +// Contributed by John M. Larkin (jlarkin@whitworth.edu) +unsigned long long MAX31850::getId() { +// This will return the 64 bit address of the connected MAX31850 + unsigned long long myName = 0; + for (int i = 0; i<8; i++) { + myName = (myName<<8) | _ROM[i]; + } + return myName; +} + +void MAX31850::setUnits(int units) { + _units = units; +} \ No newline at end of file
diff -r 000000000000 -r 5530bf2d0e94 MAX31850.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MAX31850.h Wed Jan 23 23:44:57 2019 +0000 @@ -0,0 +1,165 @@ +/* mbed MAX31850 + Library, for the Dallas (Maxim) 1-Wire Digital Thermometer + * Copyright (c) 2010, Michael Hagberg Michael@RedBoxCode.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * + * This library has been adapted from the DS1820 library to work with MAX31850 thermocouple sensor + * Chris Roberts (croberts21@my.whitworth.edu) + * Craig Russell (crussell21@my.whitworth.edu) + * + * For our application, we modified readAll() (previously convertTemperature) to force a small + * wait rather than it being optional, and removed the ability to select a single sensor. + * + * getTemp() (previously temperature) has been updated to deal with the correct number of bits that + * the temperature is stored in as well as updated convertions to all four units + * + * as well as adding a setUnits() function to set the + * units that the sensor will return. + * + * We removed some functionality that dealt with parasite power. + * + * + */ + +#ifndef MBED_MAX31850_H +#define MBED_MAX31850_H + +#include "mbed.h" +#include "LinkedList.h" + +#define C 0 //celsius +#define K 1 //Kelvin +#define F 2 //fahrenheit +#define R 3 //Rankin + +extern Serial pc; + +/** MAX31850 + * + * Example: + * @code + * #include "mbed.h" + * #include "MAX31850.h" + * + * MAX31850 probe(DATA_PIN); + * + * int main() { + * while(true) { + * probe.convertTemperature(true, MAX31850::all_devices); //Start temperature conversion, wait until ready + * printf("It is %3.1foC\r\n", probe.temperature()); + * wait(1); + * } + * } + * @endcode + */ +class MAX31850 + { +public: + enum devices{ + this_device, // command applies to only this device + all_devices }; // command applies to all devices + + enum { + invalid_conversion = -1000 + }; + + /** Create a probe object connected to the specified pins + * + * The probe might either by regular powered or parasite powered. If it is parasite + * powered and power_pin is set, that pin will be used to switch an external mosfet connecting + * data to Vdd. If it is parasite powered and the pin is not set, the regular data pin + * is used to supply extra power when required. This will be sufficient as long as the + * number of probes is limitted. + * + * For our application, we have the functions set up to only use external power. The constructor still supports + * parasite power but the functions to not support it. + */ + MAX31850 (PinName data_pin, PinName power_pin = NC, bool power_polarity = 0); // Constructor with parasite power pin + + ~MAX31850(); + + /** Function to see if there are MAX31850 + * devices left on a pin which do not have a corresponding MAX31850 + * object + * + * @return - true if there are one or more unassigned devices, otherwise false + */ + static bool unassignedProbe(PinName pin); + + /** This routine will initiate the temperature conversion within + * all MAX31850 + * probes. + */ + void readAll(); + + /** This function will return the probe temperature. Approximately 10ms per + * probe to read its scratchpad, do CRC check and convert temperature on the LPC1768. + * + * @scratchpad scale, may be either 'c', 'f', 'k', and 'r' + * @returns temperature for that scale, or MAX31850::invalid_conversion (-1000) if CRC error detected. + */ + float getTemp(int scale = 4); + + /** This function returns the 64 bit address associated with a + * particular DS18B20. + * + * Contributed by John M. Larkin (jlarkin@whitworth.edu) + * + * @returns unsigned long long + */ + unsigned long long getId(); + + + /** This function sets the _units variable to the + * users desired temperature units + */ + void setUnits(int); + + +private: + bool _parasite_power; + bool _power_mosfet; + bool _power_polarity; + + static char CRC_byte(char _CRC, char byte ); + static bool onewire_reset(DigitalInOut *pin); + void match_ROM(); + void skip_ROM(); + static bool search_ROM_routine(DigitalInOut *pin, char command, char *ROM_address); + static void onewire_bit_out (DigitalInOut *pin, bool bit_data); + void onewire_byte_out(char data); + static bool onewire_bit_in(DigitalInOut *pin); + char onewire_byte_in(); + static bool ROM_checksum_error(char *_ROM_address); + bool scratchpad_checksum_error(); + void read_scratchpad(); + static bool unassignedProbe(DigitalInOut *pin, char *ROM_address); + + DigitalInOut _datapin; + DigitalOut _parasitepin; + + char _ROM[8]; + char scratchpad[9]; + int _units; + + static LinkedList<node> probes; +}; +#endif \ No newline at end of file