Изначально термостат делался просто как термометр, для контроля температуры за окном. Затем во время морозов, стала подмерзать картошка в подполье и был добавлен функционал для контроля за микроклиматом. Паспортные данные коммутационного реле – 250В и 10А( 2,5кВт). Т.к жара в подполье не нужна, тэна на киловатт вполне хватит.
Необходимые материалы и инструменты:-коробка от средство ухода за обувью
-USB-зарядка для для телефона(любая,не менее 0,7А)
-Arduino-Pro-Mini
-2-х строчный 8 символьный дисплей(WH0802A-NGA-CT он более компактный)
-энкодер с кнопкой (можно приобрести в любом радиомаг, кнопку можно и не встроенную)
-шильд с 5В реле (я приобрел в свое время кучу китайских реле без опторазвязки, поэтому мне понадобился еще Оптрон PC817 и резистор на 470 Ом. Если у вас на шильде собрана опторазвязка, то вы можете подключить шильд непосредственно к порту arduino)
-USB-разъем
-2 USB-удлинителя 3 метровых (один для шнура питания, ко второму подпаяем DS1820)
- DS1820 (с любой буквой)
-паяльник
-клеевой пиcтолет
-шильд FTDI232
Шаг 1: Первым делом нам надо прошить ардуинку, т.к у меня Pro Mini (она идет без преобразователя USB-RS232) мне необходимо впаять линейку с пинами на ардуинку. С той стороны где выведены DTR, TXD, RXD, VCC, GND, GND. Теперь соединяем FTDI232 DTR к DTR, VCC к VCC, GND к GND, TXD к RXD, RXD к TXD. Запускаем arduino IDE загружаем скетч и прошиваем(скетч в конце).
Шаг 2: Теперь займемся корпусом. Отрываем губку у "ФУКС", все хорошо обезжириваем, глубокую часть коробочки можно пройти наждачкой (что-бы крепче приклеилось). Размечаем отверстие под энкодер, USB-разъем(маму) и сам дисплейчик. На крышку коробки приклеиваем реле. Надо постараться расположить реле подальше от процессора и расположить компоненты так, что-бы потом крышка закрылась (место предостаточно).
Шаг 3: Теперь берем USB-удлинитель отрезаем разъем гнездо (мама). Разделываем отрезанный конец, сверлим в корпусе отверстие под кабель, просовываем его и проклеиваем кл.пистолетом. Плюс у кабеля красный, минус черный(я на всякий проверяю), плюс на плюс разъема, минус на минус (распиновку разъема я не привожу – в инете есть). Между плюсом разъема и 2 средними(у меня они соединены) надо распаять резистор 4.7кОм.
![]()
Шаг 4: Берем 2 USB удлинитель, отрезаем разъем(маму), разделываем кабель. На всякий случай проверим все ли мы правильно распаяли. Кабель питания соединяем с USB-зарядкой и в сеть, разделанный кабель втыкаем в USB-разъем, тестером смотрим + на красном – на черном. Выдергиваем кабель и распаиваем DS1820: - к 1, + к 3 оставшиеся 2 провода ко 2. Я потом эпоксидным составом(для ремонта бачков, радиаторов) обмазываю, оставляя немного корпуса датчика наружу, что-бы была более быстрая реакция на изменения температуры. Ну и делаем монтаж согласно принципиальной схемы(питание и землю релейного шильда соединяем с общим + и – схемы соответственно).
![]()
![]()
Шаг 5: Все компоненты схемы соединены. Подключаем наш датчик(без него дисплей останется черным),подаем питание. В первой строке – значение температуры, во 2 если горит “*” – реле вкл, нет – выкл. Теперь попробуем выставить пределы переключения реле. Нажимаем вал энкодера(или вашу кнопку) появится значение предела при котором реле будет включаться, вращая вал – значение увеличивается или уменьшается. Нажав на вал еще раз – получим верхний предел(реле будет выключаться),выставляем значение и нажимаем еще раз. Прибор будет контролировать температуру, значение пределов сохраняется при отключении питания. Все.
#include <OneWire.h>
#include <LiquidCrystal.h>
#include <EEPROM.h>
#define BUTTON_1_PIN 10 // номер вывода кнопки 1 равен 12
OneWire ds(12); // on pin 10 (a 4.7K resistor is necessary)
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(3, 2, 4, 5, 6, 7);
unsigned long currentTime;
const int pin_A = 8; // pin 12
const int pin_B = 9; // pin 11
unsigned char enc_A;
unsigned char enc_B;
unsigned char enc_A_prev=0;
float n_pr = 24.1;
float b_pr = 26.2;
boolean priz = false;
class Button {
public:
Button(byte pin, byte timeButton); // описание конструктора
boolean flagPress; // признак кнопка сейчас нажата
boolean flagClick; // признак кнопка была нажата (клик)
void scanState(); // метод проверки состояние сигнала
void setPinTime(byte pin, byte timeButton); // метод установки номера вывода и времени (числа) подтверждения
private:
byte _buttonCount; // счетчик подтверждений стабильного состояния
byte _timeButton; // время подтверждения состояния кнопки
byte _pin; // номер вывода
};
Button button1(BUTTON_1_PIN,30);
void knopka(){
lcd.clear();
lcd.setCursor(1,0);
lcd.print(n_pr);
// button1.scanState();
while (button1.flagClick==false){
enc_A = digitalRead(pin_A);
enc_B = digitalRead(pin_B);
if ((!enc_A)&&(enc_A_prev)){
if (enc_B){
n_pr = n_pr-0.1;
}else{
n_pr = n_pr+0.1;
}
lcd.clear();
lcd.setCursor(1,0);
lcd.print(n_pr);
}
enc_A_prev = enc_A;
button1.scanState();
}
button1.flagClick=false;
lcd.clear();
lcd.setCursor(1,0);
lcd.print(b_pr);
while (button1.flagClick==false){
enc_A = digitalRead(pin_A);
enc_B = digitalRead(pin_B);
if ((!enc_A)&&(enc_A_prev)){
if (enc_B){
b_pr = b_pr-0.1;
}else{
b_pr = b_pr+0.1;
}
lcd.clear();
lcd.setCursor(1,0);
lcd.print(b_pr);
}
enc_A_prev = enc_A;
button1.scanState();
}
button1.flagClick=false;
if (n_pr > b_pr){
float wr = n_pr;
n_pr = b_pr;
b_pr = wr;
}
int addr = 0;
EEPROM.write(addr,'y');
addr = 1;
EEPROM.put(addr,n_pr);
addr +=sizeof(float);
EEPROM.put(addr,b_pr);
delay(300);
}
void setup(void) {
pinMode(11,OUTPUT);
pinMode(pin_A,INPUT_PULLUP);
pinMode(pin_B,INPUT_PULLUP);
lcd.begin(8,2);
int addr = 0;
char c = EEPROM.read(addr);
addr = addr+1;
if (c == 'y'){
EEPROM.get(addr,n_pr);
addr += sizeof(float);
EEPROM.get(addr,b_pr);
}
// Serial.begin(9600);
}
void loop(void) {
byte i;
byte present = 0;
byte type_s;
byte data[12];
byte addr[8];
float celsius;
if ( !ds.search(addr)) {
ds.reset_search();
delay(250);
return;
}
if (OneWire::crc8(addr, 7) != addr[7]) {
return;
}
// the first ROM byte indicates which chip
switch (addr[0]) {
case 0x10:
type_s = 1;
break;
case 0x28:
type_s = 0;
break;
case 0x22:
type_s = 0;
break;
default:
return;
}
ds.reset();
ds.select(addr);
ds.write(0x44, 1); // start conversion, with parasite power on at the end
enc_A = digitalRead(pin_A);
enc_A_prev = enc_A;
currentTime = millis();
while ((millis()-currentTime)<2000){
button1.scanState();
if ( button1.flagClick == true ) {
// было нажатие кнопки
button1.flagClick= false; // сброс признака клика
knopka();
}
}
// delay(1000); // maybe 750ms is enough, maybe not
// we might do a ds.depower() here, but the reset will take care of it.
present = ds.reset();
ds.select(addr);
ds.write(0xBE); // Read Scratchpad
for ( i = 0; i < 9; i++) { // we need 9 bytes
data[i] = ds.read();
}
// Convert the data to actual temperature
// because the result is a 16 bit signed integer, it should
// be stored to an "int16_t" type, which is always 16 bits
// even when compiled on a 32 bit processor.
int16_t raw = (data[1] << 8) | data[0];
if (type_s) {
raw = raw << 3; // 9 bit resolution default
if (data[7] == 0x10) {
// "count remain" gives full 12 bit resolution
raw = (raw & 0xFFF0) + 12 - data[6];
}
} else {
byte cfg = (data[4] & 0x60);
// at lower res, the low bits are undefined, so let's zero them
if (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 ms
else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
//// default is 12 bit resolution, 750 ms conversion time
}
celsius = (float)raw / 16.0;
lcd.clear();
lcd.setCursor(1,0);
lcd.print(celsius);
if (priz){
lcd.setCursor(0,1);
lcd.print('*');
}
if (n_pr != b_pr){
if (celsius < n_pr){
digitalWrite(11,HIGH);
priz = true;
}
if (celsius > b_pr){
digitalWrite(11,LOW);
priz = false;
}
}
}
// метод проверки состояния кнопки
// flagPress= true - нажата
// flagPress= false - отжата
// flagClick= true - была нажата (клик)
void Button::scanState() {
if ( flagPress == (! digitalRead(_pin)) ) {
// состояние сигнала осталось прежним
_buttonCount= 0; // сброс счетчика состояния сигнала
}
else {
// состояние сигнала изменилось
_buttonCount++; // +1 к счетчику состояния сигнала
if ( _buttonCount >= _timeButton ) {
// состояние сигнала не менялось заданное время
// состояние сигнала стало устойчивым
flagPress= ! flagPress; // инверсия признака состояния
_buttonCount= 0; // сброс счетчика состояния сигнала
if ( flagPress == true ) flagClick= true; // признак клика на нажатие
}
}
}
// метод установки номера вывода и времени подтверждения
void Button::setPinTime(byte pin, byte timeButton) {
_pin= pin;
_timeButton= timeButton;
pinMode(_pin, INPUT_PULLUP); // определяем вывод как вход
}
// описание конструктора класса Button
Button::Button(byte pin, byte timeButton) {
_pin= pin;
_timeButton= timeButton;
pinMode(_pin, INPUT_PULLUP); // определяем вывод как вход
}
Становитесь автором сайта, публикуйте собственные статьи, описания самоделок с оплатой за текст.
Подробнее здесь.