Подключение термопары (K-Type) к ESP8266/ESP32/Arduino

Для подключения термопар используется несколько типов конвертеров доступных на Aliexpress. Термопары позволяют измерять очень низкие и очень высокие тепературы.

Модуль MAX6675 для подключения термопары K-Type к 
микроконтроллеру по шине SPI

Модуль MAX6675 для подключения термопары K-Type к
микроконтроллеру по шине SPI

Недорогой модуль MAX6675 транслирует данные снятые с термопары по шине SPI. АЦП 12-ти битный. Позволяет измерять только положительные температуры от 0 до +700 оС. Детектирует обрыв термопары. Цена в районе 1,5 USD.

Модуль MAX31855 для подключения термопары K-Type к микроконтроллеру по шине SPI

Модуль MAX31855 для подключения термопары K-Type к микроконтроллеру по шине SPI

Более современный и дорогой модуль MAX31855, заменивший MAX6675 также передает данные по шине SPI. Плата посерьезнее, чем MAX6675:

  • 14-ти битный АЦП,
  • Помимо определения обрыва дополнительно определяет закорачивание выхода термопары на Vcc или GND.
  • Диапазон измеряемых температур от -270 до +1768 оС (крайние диапазоны).
  • Цена около 1,9 USD с доставкой в Россию.
Подключение MAX31855 к термопаре
Подключение MAX31855 к термопаре

С этой платкой есть одна проблема. Винтовой разъем не позволяет закреплять клеммы термопары как это задумано разработчиками. Приходится зажимать винтами одну из половинок клеммы, но держится нормально.

На Aliexpress есть три варианта плат с MAX31855. Самая дорогая идет с обширной обвязкой. Стоит около 8 USD. Не разбирался, в чем отличие от недорогого варианта. Разве что есть отдельный вход 3V и Vin. Я использовал плату за 1,9 USD и запитывал от 3,3 V БП. В описании у китайцев сравнения дорогой платы с бюджетной не нашел.

В одной из статей я писал о схемотехнике для автоматической сыроварни. Для замера температуры молока и температуры жидкости в паровой бане как раз использовалась термопара.

Wemos D1 min и MAX6675K

MAX6675KWemos D1 Mini
Vcc 3.3v (я использовал БП)
Gnd Gnd (от БП и Wemos D1 mini)
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 (я использовал БП)
Gnd Gnd (от БП и Wemos D1 mini)
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()

Полезные ссылки

Spread the love
Запись опубликована в рубрике IT рецепты с метками , . Добавьте в закладки постоянную ссылку.

Добавить комментарий