Для подключения термопар используется несколько типов конвертеров доступных на Aliexpress. Термопары позволяют измерять очень низкие и очень высокие тепературы.
Недорогой модуль MAX6675 транслирует данные снятые с термопары по шине SPI. АЦП 12-ти битный. Позволяет измерять только положительные температуры от 0 до +700 оС. Детектирует обрыв термопары. Цена в районе 1,5 USD.
Более современный и дорогой модуль MAX31855, заменивший MAX6675 также передает данные по шине SPI. Плата посерьезнее, чем MAX6675:
- 14-ти битный АЦП,
- Помимо определения обрыва дополнительно определяет закорачивание выхода термопары на Vcc или GND.
- Диапазон измеряемых температур от -270 до +1768 оС (крайние диапазоны).
- Цена около 1,9 USD с доставкой в Россию.
С этой платкой есть одна проблема. Винтовой разъем не позволяет закреплять клеммы термопары как это задумано разработчиками. Приходится зажимать винтами одну из половинок клеммы, но держится нормально.
На Aliexpress есть три варианта плат с MAX31855. Самая дорогая идет с обширной обвязкой. Стоит около 8 USD. Не разбирался, в чем отличие от недорогого варианта. Разве что есть отдельный вход 3V и Vin. Я использовал плату за 1,9 USD и запитывал от 3,3 V БП. В описании у китайцев сравнения дорогой платы с бюджетной не нашел.
- https://datasheets.maximintegrated.com/en/ds/MAX6675.pdf
- https://datasheets.maximintegrated.com/en/ds/MAX31855.pdf
В одной из статей я писал о схемотехнике для автоматической сыроварни. Для замера температуры молока и температуры жидкости в паровой бане как раз использовалась термопара.
Wemos D1 min и MAX6675K
MAX6675K | Wemos D1 Mini |
Vcc | 3.3v (я использовал БП) |
SO | D6 (GPIO12) |
SS/CS | D7 (GPIO13) |
CSK | D8 (GPIO15) |
Земля (GND) MAX6675 и (GND) Wemos D1 Mini должны быть соединена, если MAX6675 запитывается от отдельного источника питания.
Интерфейс SPI использует 4 линии для обмена данными:
- SCLK — Serial Clock: тактовый сигнал (от ведущего)
Другие обозначения: SCK, CLK - MOSI — Master Output, Slave Input: данные от ведущего к ведомому
Другие обозначения: SDI, DI, SI - MISO — Master Input, Slave Output: данные от ведомого к ведущему
Другие обозначения: SDO, DO, SO - SS — Slave Select: выбор ведомого; устанавливается ведущим
Другие обозначения: nCS, CS, CSB, CSN, nSS, STE
Для снятия данных с термопары платой MAX6675 используется библиотека https://github.com/YuriiSalimov/MAX6675_Thermocouple. Она основана на более старой библиотекеAdafruit Max6675 Library
#include "MAX6675_Thermocouple.h" //https://github.com/YuriiSalimov/MAX6675_Thermocouple #define SCK_PIN 15 //D8 #define CS_PIN 13 //D7 #define SO_PIN 12 //D6 /** How many readings are taken to determine a mean temperature. The more values, the longer a calibration is performed, but the readings will be more accurate. */ #define READINGS_NUMBER 20 /** Delay time between a temperature readings from the temperature sensor (ms). */ #define DELAY_TIME 20 MAX6675_Thermocouple* thermocouple = NULL; void setup() { Serial.begin(9600); thermocouple = new MAX6675_Thermocouple(SCK_PIN, CS_PIN, SO_PIN, READINGS_NUMBER, DELAY_TIME); } void loop() { const double celsius = thermocouple->readCelsius(); const double kelvin = thermocouple->readKelvin(); const double fahrenheit = thermocouple->readFahrenheit(); Serial.print("Temperature: "); Serial.print(String(celsius) + " C, "); Serial.print(String(kelvin) + " K, "); Serial.println(String(fahrenheit) + " F"); delay(500); }
Результат работы программы:
19:14:01.820 -> Temperature: 28.50 C, 301.65 K, 83.30 F 19:14:05.538 -> Temperature: 28.75 C, 301.90 K, 83.75 F 19:14:09.278 -> Temperature: 28.50 C, 301.65 K, 83.30 F 19:14:13.025 -> Temperature: 28.50 C, 301.65 K, 83.30 F 19:14:16.730 -> Temperature: 28.75 C, 301.90 K, 83.75 F
Сенсоры надо калибровать, поскольку температура в комнате была не 28,5 оС, а ниже.
ESP32 DevKit и MAX6675K
В качестве ESP32 платы используется эта плата.
MAX6675K | ESP32 DevKit |
Vcc | 3.3v (я использовал БП) |
SO | 12 (IO12) |
SS/CS | 13 (IO13) |
CSK | 15 (IO15) |
Код без изменений работает и на ESP32.
#include "MAX6675_Thermocouple.h" //https://github.com/YuriiSalimov/MAX6675_Thermocouple #define SCK_PIN 15 #define CS_PIN 13 #define SO_PIN 12 /** How many readings are taken to determine a mean temperature. The more values, the longer a calibration is performed, but the readings will be more accurate. */ #define READINGS_NUMBER 20 /** Delay time between a temperature readings from the temperature sensor (ms). */ #define DELAY_TIME 20 MAX6675_Thermocouple* thermocouple = NULL; void setup() { Serial.begin(9600); thermocouple = new MAX6675_Thermocouple(SCK_PIN, CS_PIN, SO_PIN, READINGS_NUMBER, DELAY_TIME); } void loop() { const double celsius = thermocouple->readCelsius(); const double kelvin = thermocouple->readKelvin(); const double fahrenheit = thermocouple->readFahrenheit(); Serial.print("Temperature: "); Serial.print(String(celsius) + " C, "); Serial.print(String(kelvin) + " K, "); Serial.println(String(fahrenheit) + " F"); delay(500); }
Результат:
21:16:42.882 -> Temperature: 26.25 C, 299.40 K, 79.25 F 21:16:46.554 -> Temperature: 26.75 C, 299.90 K, 80.15 F 21:16:50.256 -> Temperature: 26.50 C, 299.65 K, 79.70 F 21:16:53.926 -> Temperature: 26.25 C, 299.40 K, 79.25 F 21:17:30.707 -> Temperature: 26.50 C, 299.65 K, 79.70 F
Странно, но ESP32 считывает более корректную температуру, чем ESP8266. Температура в комнате как раз где-то в районе 26,5 оС.
ESP32 и MAX31855
Без проблем на ESP32 заработала библиотка от Adafruit c программной эмуляцией. GPIO использовал те-же, что и для примера с MAX6675.
#include <SPI.h> #include "Adafruit_MAX31855.h" //https://github.com/adafruit/Adafruit-MAX31855-library/ // Default connection is using software SPI, but comment and uncomment one of // the two examples below to switch between software SPI and hardware SPI: // Example creating a thermocouple instance with software SPI on any three // digital IO pins. #define MAXDO 12 #define MAXCS 13 #define MAXCLK 15 // initialize the Thermocouple Adafruit_MAX31855 thermocouple(MAXCLK, MAXCS, MAXDO); // Example creating a thermocouple instance with hardware SPI // on a given CS pin. //#define MAXCS 10 //Adafruit_MAX31855 thermocouple(MAXCS); void setup() { Serial.begin(115200); Serial.println("MAX31855 test"); // wait for MAX chip to stabilize delay(500); } void loop() { // basic readout test, just print the current temp Serial.print("Temperature: "); double c = thermocouple.readCelsius(); if (isnan(c)) { Serial.println("Something wrong with thermocouple!"); } else { Serial.print(String(c) + " C, "); Serial.print(String(thermocouple.readFarenheit()) + " F, "); Serial.println(String(thermocouple.readInternal()) + " C (internal)"); } delay(1000); }
Результат:
15:39:44.805 -> Temperature: 24.25 C, 77.90 F, 25.94 C (internal) 15:39:45.977 -> Temperature: 24.25 C, 77.45 F, 25.88 C (internal) 15:39:47.190 -> Temperature: 25.50 C, 77.90 F, 25.94 C (internal) 15:39:48.396 -> Temperature: 25.25 C, 77.90 F, 25.94 C (internal) 15:39:49.618 -> Temperature: 25.00 C, 78.35 F, 25.94 C (internal)
Попробуем запустить библиотеку с аппаратным SPI:
- SPI MOSI — GPIO23
- SPI MISO — GPIO19
- SPI SCK — GPIO18
- SPI SS (CS) — GPIO5
Код существенно упростился, но все работает отлично.
#include <SPI.h> #include "Adafruit_MAX31855.h" //https://github.com/adafruit/Adafruit-MAX31855-library/ #define MAXCS 5 Adafruit_MAX31855 thermocouple(MAXCS); void setup() { Serial.begin(115200); Serial.println("MAX31855 test"); // wait for MAX chip to stabilize delay(500); } void loop() { // basic readout test, just print the current temp Serial.print("Temperature: "); double c = thermocouple.readCelsius(); if (isnan(c)) { Serial.println("Something wrong with thermocouple!"); } else { Serial.print(String(c) + " C, "); Serial.print(String(thermocouple.readFarenheit()) + " F, "); Serial.println(String(thermocouple.readInternal()) + " C (internal)"); } delay(1000); }
Библиотека https://github.com/SV-Zanshin/MAX31855/ нормально работает с аппаратным SPI.
#include <MAX31855.h> // https://github.com/SV-Zanshin/MAX31855/ /******************************************************************************************************************* ** Declare all program constants ** *******************************************************************************************************************/ const uint32_t SERIAL_SPEED = 115200; ///< Set the baud rate for Serial I/O const uint8_t SPI_CHIP_SELECT = 5; //< Chip-Select PIN for SPI const uint8_t SPI_MISO = MISO; //< Master-In, Slave-Out PIN for SPI const uint8_t SPI_SYSTEM_CLOCK = SCK; //< System Clock PIN for SPI /******************************************************************************************************************* ** Declare global variables and instantiate classes ** *******************************************************************************************************************/ MAX31855_Class MAX31855; ///< Create an instance of MAX31855 /***************************************************************************************************************//*! * @brief Arduino method called once at startup to initialize the system * @details This is an Arduino IDE method which is called first upon boot or restart. It is only called one time * and then control goes to the main "loop()" method, from which control never returns * @return void *******************************************************************************************************************/ void setup() { Serial.begin(SERIAL_SPEED); #ifdef __AVR_ATmega32U4__ // If this is a 32U4 processor, then wait 3 seconds for the interface to initialize delay(3000); #endif Serial.println(F("Starting software SPI demo program for MAX31855")); Serial.print(F("Initializing MAX31855 sensor\n")); /******************************************************************************************** ** Uncomment out either the hardware or software SPI call, depending upon which is in use ** ********************************************************************************************/ while (!MAX31855.begin(SPI_CHIP_SELECT)) // Hardware SPI for MAX31855 //while (!MAX31855.begin(SPI_CHIP_SELECT,SPI_MISO,SPI_SYSTSEM_CLOCK)) // Software SPI for MAX31855 { Serial.println(F("Unable to start MAX31855. Waiting 3 seconds.")); delay(3000); } // of loop until device is located Serial.println(); } // of method setup() /***************************************************************************************************************//*! * @brief Arduino method for the main program loop * @details This is the main program for the Arduino IDE, it is an infinite loop and keeps on repeating. * @return void *******************************************************************************************************************/ void loop() { int32_t ambientTemperature = MAX31855.readAmbient(); // retrieve MAX31855 die ambient temperature int32_t probeTemperature = MAX31855.readProbe(); // retrieve thermocouple probe temp uint8_t faultCode = MAX31855.fault(); // retrieve any error codes if ( faultCode ) // Display error code if present { Serial.print("Fault code "); Serial.print(faultCode); Serial.println(" returned."); } else { Serial.print("Ambient Temperature is "); Serial.print((float)ambientTemperature/1000,3); Serial.println("\xC2\xB0""C"); Serial.print("Probe Temperature is "); Serial.print((float)probeTemperature/1000,3); Serial.println("\xC2\xB0""C\n"); } // of if-then-else an error occurred delay(5000); } // of method loop()
Полезные ссылки
- Библиотка для работы с MAX6675K. Основна на коде более старой билиотеки от Adafruit.
- Библиотека Adafruit для работы с MAX6675K.
- Библиотека Adafruit для работы с MAX31855.
- Библиотека для работы с MAX31855 поновее, чем Adafruit.
- https://www.instructables.com/id/Power-and-Temperature-Data-Logger-With-ESP32-and-A/
- http://www.esp8266learning.com/wemos-max6675-example.php
- http://www.esp32learning.com/code/esp32-and-max6675-example.php
- http://henrysbench.capnfatz.com/henrys-bench/arduino-temperature-measurements/max6675-temp-module-arduino-manual-and-tutorial/
- http://www.electronoobs.com/eng_arduino_tut24.php
- https://protosupplies.com/product/max6675-thermocouple-temperature-module/