/*
* ПРАКТИЧЕСКАЯ РАБОТА 5 - Датчики температуры
* =============================================
* Изучение трёх датчиков температуры:
* 1. DS18B20 - Полупроводниковый датчик (One-Wire, pin 2)
* 2. NTC - Резистивный датчик (A0, с делителем 10kΩ)
* 3. OLED - Дисплей SSD1306 (I2C: SDA=20, SCL=21)
*
* Arduino Mega 2560
* Работает в Wokwi:
* Установить через Library Manager:
* - OneWire
* - DallasTemperature
* - Adafruit SSD1306
* - Adafruit GFX Library
*/
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ======== НАСТРОЙКИ ПИНОВ ========
#define DS18B20_PIN 2 // DS18B20 One-Wire пин
#define NTC_PIN A0 // NTC аналоговый пин
#define LED_PIN 13 // Статусный LED
// Параметры NTC (10kΩ NTC + 10kΩ последовательно)
#define SERIES_R 10000.0
#define NTC_NOMINAL 10000.0
#define TEMP_NOMINAL 25.0
#define B_COEFF 3950.0
// OLED экран
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
// ======== ОБЪЕКТЫ ========
OneWire oneWire(DS18B20_PIN);
DallasTemperature ds18b20(&oneWire);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// ======== ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ========
float tempDS = 0;
float tempNTC = 0;
int measNum = 0;
// Для статистики (5 измерений)
float ds_arr[5] = {0};
float ntc_arr[5] = {0};
// ======== ВЫЧИСЛЕНИЕ ТЕМПЕРАТУРЫ NTC ========
float readNTC() {
int raw = analogRead(NTC_PIN);
if (raw <= 0) raw = 1;
// Формула Стейнхарта-Харта
float resistance = SERIES_R * (1023.0 / (float)raw - 1.0);
float steinhart = log(resistance / NTC_NOMINAL) / B_COEFF;
steinhart += 1.0 / (TEMP_NOMINAL + 273.15);
float tempK = 1.0 / steinhart;
return tempK - 273.15;
}
// ======== СТАТИСТИЧЕСКИЕ ФУНКЦИИ ========
float calcMean(float arr[], int n) {
float s = 0;
for (int i = 0; i < n; i++) s += arr[i];
return s / n;
}
float calcSigma(float arr[], int n, float mean) {
float s = 0;
for (int i = 0; i < n; i++) s += pow(arr[i] - mean, 2);
return sqrt(s / (n - 1));
}
void printStats(const char* name, float arr[], int n) {
float mean = calcMean(arr, n);
float sigma = calcSigma(arr, n, mean);
float sigmaM = sigma / sqrt((float)n);
float absErr = 1.97 * sigmaM;
float relErr = fabs(absErr / mean) * 100.0;
Serial.print(F("--- ")); Serial.println(name);
Serial.print(F(" Среднее (x) : ")); Serial.print(mean, 3); Serial.println(F(" C"));
Serial.print(F(" Станд. отклонение s: ")); Serial.print(sigma, 4); Serial.println(F(" C"));
Serial.print(F(" Абсолютная погр. Dx : ")); Serial.print(absErr, 4); Serial.println(F(" C"));
Serial.print(F(" Относит. погр. e : +-")); Serial.print(relErr, 2); Serial.println(F(" %"));
}
// ======== ИНИЦИАЛИЗАЦИЯ ========
void setup() {
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
Serial.println(F("============================================"));
Serial.println(F(" ПРАКТИЧЕСКАЯ РАБОТА 5: Датчики температуры"));
Serial.println(F(" Arduino Mega 2560"));
Serial.println(F("============================================"));
Serial.println(F(" Pin 2 -> DS18B20 (One-Wire)"));
Serial.println(F(" A0 -> NTC термистор"));
Serial.println(F(" 20,21 -> OLED I2C (SDA, SCL)"));
Serial.println(F("============================================"));
Serial.println(F("Время(мс)\tDS18B20(C)\tNTC(C)"));
ds18b20.begin();
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("OLED не найден!"));
} else {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 10);
display.println(F("Практ. работа 5"));
display.setCursor(5, 25);
display.println(F("Датчики температуры"));
display.setCursor(20, 45);
display.println(F("DS18B20 + NTC"));
display.display();
delay(2000);
}
}
// ======== ОСНОВНОЙ ЦИКЛ ========
void loop() {
// 1. Чтение DS18B20
ds18b20.requestTemperatures();
tempDS = ds18b20.getTempCByIndex(0);
// 2. Чтение NTC
tempNTC = readNTC();
measNum++;
// Вывод в Serial Monitor
Serial.print(millis());
Serial.print(F("\t"));
Serial.print(tempDS, 2);
Serial.print(F("\t\t"));
Serial.println(tempNTC, 2);
// Обновление OLED
display.clearDisplay();
// Заголовок
display.setTextSize(1);
display.setCursor(0, 0);
display.println(F("== Практ. работа 5 =="));
// DS18B20
display.setCursor(0, 16);
display.print(F("DS18B20: "));
display.setTextSize(2);
display.setCursor(0, 24);
display.print(tempDS, 1);
display.print(F(" C"));
// NTC
display.setTextSize(1);
display.setCursor(0, 44);
display.print(F("NTC: "));
display.print(tempNTC, 1);
display.print(F(" C"));
// Номер измерения
display.setCursor(0, 56);
display.print(F("#"));
display.print(measNum);
display.display();
// Мигание LED
digitalWrite(LED_PIN, measNum % 2);
// Сохранение первых 5 измерений
if (measNum <= 5) {
ds_arr[measNum - 1] = tempDS;
ntc_arr[measNum - 1] = tempNTC;
}
// После 5 измерений — вывод статистики
if (measNum == 5) {
Serial.println(F("\n====== СТАТИСТИЧЕСКАЯ ОБРАБОТКА (N=5) ======"));
Serial.println(F("Формулы: (16) - среднее, (17) - сигма,"));
Serial.println(F(" (18) - сигма_mean, (19) - delta_x"));
printStats("DS18B20 (Полупроводниковый, pin 2)", ds_arr, 5);
printStats("NTC термистор (Резистивный, A0)", ntc_arr, 5);
// Разрешающая способность (формула 21)
float Ta_ds = 180.0 / (pow(2.0, 12) - 1); // DS18B20: 12-бит, -55~+125
float Ta_ntc = 5.0 / (pow(2.0, 10) - 1); // NTC: Arduino 10-бит АЦП
Serial.println(F("\n--- Разрешающая способность (формула 21) ---"));
Serial.print(F(" DS18B20 (12-бит): Ta = "));
Serial.print(Ta_ds * 1000.0, 3); Serial.println(F(" мC"));
Serial.print(F(" NTC (10-бит): Ta = "));
Serial.print(Ta_ntc * 1000.0, 3); Serial.println(F(" мВ"));
// Чувствительность (формула 22): S = (x2-x1)/(T2-T1)
float s_ds = fabs(ds_arr[4] - ds_arr[0]) / 4.0;
float s_ntc = fabs(ntc_arr[4] - ntc_arr[0]) / 4.0;
Serial.println(F("\n--- Чувствительность (формула 22) ---"));
Serial.print(F(" DS18B20 : S = ")); Serial.print(s_ds, 4); Serial.println(F(" C/изм"));
Serial.print(F(" NTC : S = ")); Serial.print(s_ntc, 4); Serial.println(F(" C/изм"));
Serial.println(F("=====================================\n"));
}
delay(1000); // Пауза 1 секунда
}