Предлагаю Вашему вниманию свою схему термостата. Данное устройство мне понадобилось для моего 3D принтера, а точнее для нагрева стола (у меня самодельная PRUSA I3, когда я поставил на неё подогреваемый столик, возникла проблема, из-за открытого корпуса принтера стол не может удержать температуру, и контролёр принтера кидает ошибку, а потом останавливает печать). Я решил собрать отдельный контроллер нагрева (из имевшихся у меня компонентов, да и просто ради развлечения). В наличии у меня были безымянные терморезисторы, дисплеи на tm1637 контроллеры, полумостовые драйверы ULN2803 и, естественно, микроконтроллеры.
Первое, что нужно было сделать — это понять, как работает терморезистор. Оказалось — очень просто. Надпись NTC — означает, что чем больше температура, тем меньше сопротивление. Здесь всё понятно. Теперь надо решить, как его подключить к контроллеру. Есть несколько вариантов, но основные из них — это делитель напряжения из 2-х резисторов с подтяжкой к земле или с подтяжкой к питанию. Я выбрал вариант номер два (так сделано в 3D принтере), подключил с подтяжкой к питанию резистором 10 килоом (смотрите на схеме).
С подключением определились. Вопрос номер два: как узнать какие значения АЦП будут соответствовать определённым значениям температуры? Здесь есть несколько путей. Можно взять термистор с известными параметрами и таблицами сопротивлений, или воспользоваться сложными формулами расчёта. Мне эти варианты не подошли (резистор неизвестный, а в высшей математике я не силён). Я выбрал другой и, наверное, самый простой путь. Так как я делал не термометр, а термореле, мне не нужно было знать, какому значению температуры соответствует каждое значение АЦП. Мне нужно знать значение АЦП для конкретных (нужных мне) температур в небольшом диапазоне. Потому я решил построить график зависимости АЦП от температуры по нескольким точкам, а потом по этому графику определить приблизительные значения АЦП для нужных мне температур. Для этого я собрал всю схему и написал простой код в arduino, который выводил к значения АЦП через uart в терминал.
const int termo_up = A2; //Вход терморезистора с подтяжкой на плюс
void setup() {
Serial.begin(9600);
}
void loop() {
int adc_value=analogRead(termo_up);
Serial.print(«ADC = «);
Serial.println(adc_value);
delay(500);
}
Затем я просто брал воду разной температуры, измерял её термометром, погружал в неё термистор и записывал значения АЦП. Потом по этим значениям строил график. Получилось примерно так: (это не окончательный вариант, лишь для наглядности, но форма графика приблизительно такая же. Полученные точки, которые сильно отдалялись от линии я корректировал (так сказать к общей тенденции).
График я строил онлайн, что очень удобно, можно в любой точке графика посмотреть значения x и y.
В итоге я составил массив значений АЦП с шагом в один градус Цельсия в диапазоне от 0 до 80 градусов:
//Массив значений АЦП (по возрастанию от 0 до 80 градусов по Цельсию)
int termo[] = {976,975,974,973,972,971,970,969,968,967,966,965,964,963,962,961,960,959,958,
956,954,952,949,946,943,940,937,934,930,928,925,921,917,913,910,906,902,897,
893,888,884,878,874,870,865,861,856,852,847,843,837,834,830,825,820,815,810,
805,800,795,790,785,780,776,771,766,761,755,748,741,733,727,720,712,703,693,
685,674,663,654,643};
Теперь немного электроники. Схема довольно простая, atmega8, обвязка, драйвер реле в виде ULN2803, дисплей, кренка и терморезистор.
Несколько пояснений. На ножках атмеги отмечены названия выходов как портов контролёра, так и выводов arduino (в качестве контролёра можно использовать любой arduino совместимый). Выводов для релюшек четыре штуки лишь потому, что жалко свободных выводов атмеги (можно программно что-нибудь будет прикрутить к ним). Выводы драйвера спарены для надёжности и из-за их избытка тоже. Вместо ULN2803 можно использовать ULN2003 и подобные, они представляют из себя сборку транзисторов Дарлингтона, при желании можно просто сделать ключи на n-канальных мосфетах. Стабилизатор на 5 вольт — любой, входное питание 12 вольт позволяют ставить LM7805, у меня использовано low-drop ams1117-5,0, лишь не жалейте фильтрующих конденсаторов, можно также вывод AVCC атмеги запитать через дроссель для уменьшения помех АЦП. Кварц при желании можно поставить и на 8 MHz, лишь для этого в ардуино нужно скомпилировать свой hex или просто прошить через uart с правильным загрузчиком.
И, собственно, программа. Написана, естественно, в среде arduino, потому что это очень быстро и удобно для такого простого устройства (не надо морочиться с драйверами для дисплея, АЦП, uart и т.д.).
#include <TM1637.h>
#define CLK 3//pins definitions for TM1637 and can be changed to other ports
#define DIO 4
TM1637 tm1637(CLK,DIO);
//Массив значений АЦП (по возрастанию от 0 до 80 градусов по цельсию)
int termo[] = {976,975,974,973,972,971,970,969,968,967,966,965,964,963,962,961,960,959,958,
956,954,952,949,946,943,940,937,934,930,928,925,921,917,913,910,906,902,897,
893,888,884,878,874,870,865,861,856,852,847,843,837,834,830,825,820,815,810,
805,800,795,790,785,780,776,771,766,761,755,748,741,733,727,720,712,703,693,
685,674,663,654,643};
int warm = 20; // Переменная, в которой хранится значение уровня температуры
const int button1 = 13; //Пин первой кнопки («нагрев вкл/выкл»)
const int button2 = 12; //Пин второй кнопки «+»
const int button3 = 11; //Пин третьей кнопки «-»
const int relay1 = 5; //Пины реле 1-4
const int relay2 = 6; //Просто жалко свободных ног МК и ULN2803
const int relay3 = 7;
const int relay4 = 8;
const int termo_up = A2; //Вход терморезистора с подтяжкой на плюс
const int termo_down = A3; ////Вход терморезистора с подтяжкой на землю
void setup() {
pinMode(19, INPUT_PULLUP); //Настраиваем ноги на входы/выходы
pinMode(18, INPUT_PULLUP); //Кнопки с подтяжкой к питанию
pinMode(17, INPUT_PULLUP); //Можно и без, в схеме всёравно есть резисторы
pinMode(relay1, OUTPUT);
pinMode(relay2, OUTPUT);
pinMode(relay3, OUTPUT);
pinMode(relay4, OUTPUT);
tm1637.set(BRIGHT_TYPICAL); //Настраиваем наш экранчик
tm1637.init();
tm1637.point(false);
digitalWrite(relay1,LOW); //Отключаем на всякий случай все реле
digitalWrite(relay2,LOW);
digitalWrite(relay3,LOW);
digitalWrite(relay4,LOW);
tm1637_disp(); //Выводим на экран значение переменной «warm»
}
void loop() {
if(digitalRead(button1)==LOW){ //Если нажата кнопка 1
while(digitalRead(button1)==LOW); //Ждём, пока она нажата
delay(20);
nagrev(); //Переходим в функцию нагрева
}
if(digitalRead(button2)==LOW){ //Если нажата кнопка 2
while(digitalRead(button2)==LOW); //Ждём, пока она нажата
delay(20);
warm=warm+1; //Добавляем 1 к переменной warm
if(warm>80){warm=80;} //Проверяем, чтобы не выходила за пределы наших значений
tm1637.clearDisplay(); //Очищаем дисплей
tm1637_disp(); //И выводим на него новое значение warm
}
if(digitalRead(button3)==LOW){ //Аналогично с кнопкой 2
while(digitalRead(button3)==LOW);
delay(20);
warm=warm-1;
if(warm<0){warm=0;}
tm1637.clearDisplay();
tm1637_disp();
}
}
void tm1637_disp(){ //Функция выводит на дисплей значение переменной warm
if((warm/100)>0){ //Если warm больше или равно 100
tm1637.display(1,(warm/100)); //пишем во 2 разряд сотни
tm1637.display(2,((warm%100)/10)); //пишем в 3 разряд десятки
tm1637.display(3,((warm%100)%10)); //пишем в 4 разряд единицы
}
if((warm/100)==0){
if(((warm%100)/10)>0){ //если warm меньше ста
tm1637.display(2,((warm%100)/10)); //десятки
tm1637.display(3,((warm%100)%10));} //единицы
else{tm1637.display(3,((warm%100)%10));} //если меньше десяти — лишь единицы
}
}
void nagrev(){ //Функция нагрева
tm1637.display(0,0xc); //Выводим букву «С» в первый разряд индикатора
uint16_t adc; //Переменная для чтения значений АЦП
//Цикл нагрева
do{
adc = analogRead(termo_up); //Читаем значение АЦП
if((adc>termo[warm]) ){ //Если значение температуры меньше заданного
digitalWrite(relay3,HIGH); //Включаем реле
} else if((adc<termo[warm])||(adc<termo[warm])){digitalWrite(relay3,LOW);} //Если больше — выключаем
delay(500);
} while((digitalRead(button1))==HIGH);
while(digitalRead(button1)==LOW); //Проверяем, отпущена ли кнопка 1
digitalWrite(relay3,LOW); //Выключаем реле нагрева
tm1637.clearDisplay();
tm1637_disp(); //Выводим на экран значение температуры без буквы «С» в первом разряде
}
Как видите, код с подробными описаниями. В нём ничего сложного, в основном цикле идёт опрос кнопок, а в функции нагрева идёт опрос АЦП и сравнение, в зависимости от результатов которого включается или выключается реле нагрева. И отдельно вынесена функция вывода информации на экран. Так как код написан на ардуино, его легко адаптировать для любого дисплея (для которого хватит оставшихся ножек), можно даже выводить информацию через uart компьютера (что я обычно делаю при отладке устройств).
А вот и фото готового устройства (реле и термистор выносные на проводах):
В конце статьи я прикреплю скетч arduino, HEX для atmega8 (16 MHz, FUSE: high — DC, low — BF) , библиотеку для tm1637 и плату в layout (всё в архиве).
Список радиоэлементовОбозначение
Тип
Номинал
Количество
ПримечаниеМагазинМой блокнот
МК AVR 8-битATmega81
tqfp32
Составной транзисторULN28031
можно uln2003 с переделкой платыCr1
Кварц16 MHz1
NTC1
ТермисторNTC 100K1
Можно любойR1-R5
Резистор10 кОм5
С1,С5
Конденсатор10 мкФ2
smd 0805C3, C4
Конденсатор22p2
smd 0805С2
Конденсатор100n1
smd 0805Rel1-Rel4
Релеавтомобильное или любое на 12В4
VR1
Линейный регуляторAMS1117-5.01
или LM7805 и др.Добавить все
Скачать список элементов (PDF)
Прикрепленные файлы:
- Термореле.rar (149 Кб)