Цель проекта достичь задачи:
Энкодер (KY-040) :
Используется для выбора целевой температуры.
Дисплеи TM1637 (x2) :
Первый дисплей показывает целевую температуру, выбранную с помощью энкодера.
Второй дисплей отображает текущую температуру, полученную с АЦП ADS1115.
АЦП ADS1115 :
Измеряет напряжение, соответствующее текущей температуре.
Arduino Nano :
Обрабатывает данные с энкодера, АЦП и передает информацию на дисплеи.
Сравнивает целевую температуру с текущей температурой и управляет реле для управления нагревом печки.
Реле :
Переключается для управления питанием печки.
#include <Wire.h>
#include <Arduino.h>
#include <Adafruit_ADS1X15.h>
#include <RotaryEncoder.h>
#include <TM1637Display.h>
#define ENCODER_DT_PIN 3
#define ENCODER_CLK_PIN 2
#define CLK_1 8
#define DIO_1 9
#define CLK_2 7
#define DIO_2 6
#define RELAY_PIN 7
RotaryEncoder myEnc(ENCODER_DT_PIN, ENCODER_CLK_PIN);
Adafruit_ADS1X15 ads;
TM1637Display display1(CLK_1, DIO_1);
TM1637Display display2(CLK_2, DIO_2);
float multiplier = 0.0078125F;
float coldJunctionTemp = 0; // Температура холодного спая
int encoderValue = 0;
int targetTemperature = 20;
const int step = 5;
const float calibrationTableExtended[25][11] = {
{0.000, 0.198, 0.397, 0.597, 0.798, 1.000, 1.203, 1.407, 1.612, 1.817, 2.023}, // 0-50
{2.230, 2.436, 2.644, 2.851, 3.059, 3.267, 3.474, 3.682, 3.889, 4.096, 4.303}, // 55-105
{4.509, 4.715, 4.920, 5.124, 5.328, 5.532, 5.735, 5.937, 6.138, 6.339, 6.540}, // 110-160
{6.741, 6.941, 7.140, 7.340, 7.540, 7.739, 7.939, 8.138, 8.338, 8.539, 8.739}, // 165-215
{8.940, 9.141, 9.343, 9.545, 9.747, 9.950, 10.153, 10.357, 10.561, 10.766, 10.971}, // 220-270
{11.176, 11.382, 11.588, 11.795, 12.001, 12.209, 12.416, 12.624, 12.831, 13.040, 13.248}, // 275-325
{13.457, 13.665, 13.874, 14.084, 14.293, 14.503, 14.713, 14.923, 15.133, 15.343, 15.554}, // 330-380
{15.764, 15.975, 16.186, 16.397, 16.608, 16.820, 17.031, 17.243, 17.455, 17.667, 17.879}, // 385-435
{18.091, 18.303, 18.516, 18.728, 18.941, 19.154, 19.366, 19.579, 19.792, 20.005, 20.218}, // 440-490
{20.431, 20.644, 20.857, 21.071, 21.284, 21.497, 21.710, 21.924, 22.137, 22.350, 22.563}, // 495-545
{22.776, 22.990, 23.203, 23.416, 23.629, 23.842, 24.055, 24.267, 24.480, 24.693, 24.905}, // 550-600
{25.118, 25.330, 25.543, 25.755, 25.967, 26.179, 26.390, 26.602, 26.814, 27.025, 27.236}, // 605-655
{27.447, 27.658, 27.869, 28.079, 28.289, 28.500, 28.710, 28.919, 29.129, 29.338, 29.548}, // 660-710
{29.757, 29.965, 30.174, 30.382, 30.590, 30.798, 31.006, 31.213, 31.421, 31.628, 31.834}, // 715-765
{32.041, 32.247, 32.453, 32.659, 32.865, 33.070, 33.275, 33.480, 33.685, 33.889, 34.093}, // 770-820
{34.297, 34.501, 34.704, 34.908, 35.110, 35.313, 35.516, 35.718, 35.920, 36.121, 36.323}, // 825-875
{36.524, 36.725, 36.925, 37.126, 37.326, 37.526, 37.725, 37.925, 38.124, 38.323, 38.522}, // 880-930
{38.720, 38.918, 39.116, 39.314, 39.511, 39.708, 39.905, 40.101, 40.298, 40.494, 40.690}, // 935-985
{40.885, 41.081, 41.276, 41.470, 41.665, 41.859, 42.053, 42.247, 42.440, 42.633, 42.826}, // 990-1040
{43.019, 43.211, 43.403, 43.595, 43.787, 43.978, 44.169, 44.359, 44.550, 44.740, 44.929}, // 1045-1095
{45.119, 45.308, 45.497, 45.685, 45.873, 46.061, 46.249, 46.436, 46.623, 46.809, 46.995}, // 1100-1150
{47.181, 47.367, 47.552, 47.737, 47.921, 48.105, 48.289, 48.473, 48.656, 48.838, 49.021}, // 1155-1205
{49.202, 49.384, 49.565, 49.746, 49.926, 50.106, 50.286, 50.465, 50.644, 50.822, 51.000}, // 1210-1260
{51.178, 51.355, 51.532, 51.708, 51.885, 52.060, 52.235, 52.410, 52.585, 52.759, 52.932}, // 1265-1315
{53.106, 53.279, 53.451, 53.623, 53.795, 53.967, 54.138, 54.308, 53.479, 54.649, 54.819} // 1320-1370
};
float getTemperatureFromTable(float voltage) {
for (int row = 0; row < 25; row++) {
for (int col = 0; col < 10; col++) {
float v1 = calibrationTableExtended[row][col];
float v2 = calibrationTableExtended[row][col + 1];
// Проверяем, попадает ли напряжение между v1 и v2
if (voltage >= v1 && voltage <= v2) {
// Линейная интерполяция
float temp1 = row * 10 + col;
float temp2 = row * 10 + col + 1;
return temp1 + (voltage - v1) * (temp2 - temp1) / (v2 - v1);
}
}
}
return -1; // Выход за границы таблицы
}
void setup() {
Serial.begin(9600);
display1.setBrightness(0x0f);
display2.setBrightness(0x0f);
pinMode(RELAY_PIN, OUTPUT);
digitalWrite(RELAY_PIN, LOW);
ads.setGain(GAIN_SIXTEEN);
ads.begin();
}
void loop() {
long newPosition = myEnc.read();
if (newPosition != encoderValue) {
encoderValue = newPosition;
targetTemperature = 20 + encoderValue * step;
targetTemperature = constrain(targetTemperature, 20, 1370);
}
int16_t adc0 = ads.readADC_Differential_0_1();
thermocoupleVoltage = adc0 * multiplier;
float thermocoupleTemp = getTemperatureFromTable(thermocoupleVoltage);
Ttp1 = thermocoupleTemp + coldJunctionTemp;
Serial.print("Напряжение: ");
Serial.print(thermocoupleVoltage);
Serial.print("Target Temperature: ");
Serial.println(targetTemperature);
Serial.print("Current Temperature: ");
Serial.println(Ttp1);
display1.showNumberDec(targetTemperature);
display2.showNumberDec(Ttp1);
if (Ttp1 < Ttgt) {
digitalWrite(RELAY_PIN, HIGH);
}
if (Ttp1 > Ttgt) {
digitalWrite(RELAY_PIN, LOW);
}
if (temperature < targetTemperature) {
digitalWrite(RELAY_PIN, HIGH);
} else {
digitalWrite(RELAY_PIN, LOW);
}
delay(1000);
}