На этой странице публикую скетч моего модуля термометра-регулятора (МТР-1.2). Для реализации вначале использовал Arduino UNO, а потом, когда пришла посылка с Arduino Nano, то переделал на него. Вообще можно использовать любой вариант, хоть бы и Arduino Pro Mini, если есть интерес уменьшить габариты.
Сам модуль задумывался как устройство измерения температуры со световой и звуковой индикацией, с возможностью работы по управлению либо нагревателем, либо охладителем. Поэтому реализованы три режима работы модуля:
Схема была собрана на Arduino UNO (можно Arduino Nano), а когда стал её отрисовывать, то оказалось, что слишком всё запутано. Поэтому сделал оптимизацию, для лучшей графической наглядности. Окончательный вариант вы можете видеть ниже на картинке.
В качестве индикатора, использую 3-х разрядный 7-сегментный светодиодный индикатор. У меня это 3632AS – с общим анодом. На катоды установлены ограничивающие резисторы 2,2 кОм, чтобы минимизировать ток на сегменты.
В схеме добавлены два индикаторных светодиода: красный – HL2 – показывает, что включено исполнительное реле К1 на нагрев, а когда модуль работает в режиме охладителя, то индикацию включения реле К1 указывает уже синий светодиод HL3. Сделал это для интуитивного воспринятия режима работы модуля термометра-регулятора. Начальный момент включения регулировки дополнительно сопровождается звуковой индикацией с помощью Buzzer-а (BZ1), для привлечения внимания к моменту включения управляющего сигнала.
На диодах VD1, VD2 реализовано логическое устройство ИЛИ. Поэтому любой сигнал на нагрев или на охлаждение будет управлять реле К1.
Датчик температуры использован DS18B20 – очень точный, надёжный и вообще хороший датчик. Никогда у меня с ним не было никаких проблем. Подключается по протоколу одного провода (OneWire). У меня он в качестве микросхемы в типовом корпусе ТО-92, а к нему припаян небольшой трёхжильный кабель. Продаются и влагозащищённые типы, удобны для измерения температуры воды или другой жидкой среды.
Модуль К1 – самодельный. Вначале купил на алиэкспрессе модуль реле, но не обратил внимания, что у него управляющий сигнал низкого уровня (ноль). В моей же конструкции программа была написана под управляющий сигнал высокого уровня (единица), поэтому пришлось по-быстрому изготовить себе свой модуль реле. Габариты у него 42 * 16,5 * 16,5 мм, что чуть меньше, чем у покупного. А покупной модуль реле мне ещё пригодится в новых проектах, где будет учтена его особенность по управлению.
Этот модуль реле самодельный, но его легко можно заменить и покупным, учитывая лишь, чтобы управляющий сигнал был высоким уровнем напряжения (единица).
Реализован скеч на макетных панельках. Несколько штук соединены в общую конструкцию. Подумываю со временем изготовить плату, на которой будет всё размещено и в оконцовке упрятано в копрус. Как будет сделано, то дополню фотографиями.
Звуковой излучатель пока – обычная ЗП. Подключен к порту Ардуино и управляется функцией tone(), потом хочу его заменить активным излучателем и управлять уровнем напряжения.
При работе МТР-1.2 в режиме охладителя, видно как включился модуль реле К1 (индикация светодиода на плате модуля реле) и включился синий светодиод – режим охлаждения.
Далее переходим к скетчу (программе).
Скетч модуля МТР-1.2
Опубликованный скетч модуля можно скопировать в Приложении:
/***********************************************************
* 2018-03-24 Mr.ALB Тренировка в программировании Ардуино
*
* Модуль Термометр-Регулятор - 1.x (МТР-1.x)
* на датчике DS18B20.
* Значение выводим на индикатор 3631AS (3 разряда)
********************************************************
* 2018-03-24 Mr.ALB MTR-1.0
* 2018-05-10 Mr.ALB использование библиотеки Led4Digits
* http://mypractic.ru/ Урок 20
*
* 2018-05-11 Mr.ALB MTR-1.1
* 2018-05-11 Mr.ALB сигнализация
* при выходе за пределы min и max t°C
* 2018-05-12 Mr.ALB 1) добавлен гистерезис для min и max
* 2) добавлены кнопки:
* а) выбор режима индикации
* б) минус 0.1 к значению
* в) плюс 0.1 к значению
* 2018-05-15 Mr.ALB добавлена запись уставок в EEPROM...
*
* 2018-05-18 Mr.ALB MTR-1.2
* 2018-05-18 Mr.ALB одна температура уставки +
* дельта +
* режим регулирования температуры
*
* Режим регулирования температуры:
* 0 - без регулирования,
* 1 - нагреватель,
* 2 - охладитель
*
* 2018-06-15 Mr.ALB добавлен модуль реле
* 2018-06-23 Mr.ALB добавлен зуммер
*
* Вывод на 3-х разрядный 7 сегментный индикатор 3631AS
*
* Соответствие контактов:
* Ардуино - 3631AS
* 10 - DIG.0 pin12
* 11 - DIG.1 pin9
* 17(А3)- DIG.2 pin8
*
* 9 - A pin11
* 8 - B pin7
* 7 - C pin4
* 6 - D pin2
* 5 - E pin1
* 4 - F pin10
* 3 - G pin5
* 2 - DP pin3
*
***********************************************************/
/* Подключение библиотек */#include<EEPROM.h>// для EEPROM#include<MsTimer2.h>// для прерывания по таймеру 2#include<Led4Digits.h>// для семисегментного индикатора#include<Button.h>// для кнопок#include<OneWire.h>// для OneWire#include<DallasTemperature.h>// для Dallas Temperature/***********************************************************
* Led4Digits
(
byte typeLed,
byte digitPin0,
byte digitPin1,
byte digitPin2,
byte digitPin3,
byte segPinA,
byte segPinB,
byte segPinC,
byte segPinD,
byte segPinE,
byte segPinF,
byte segPinG,
byte segPinH
);
digitPin0 ... digitPin3 - выводы выбора разрядов,
= 255 - разряд отключен
typeLed:
0 - Общий анод с ключами выбора разряда
1 - Общий анод
2 - Общий катод
3 - Общий катод с ключами выбора разряда
* Тип индикатора 1 - общий анод
* Выводы разрядов:
* 17, 11, 10 => DIG.2, DIG.1, DIG.0,
noDIG (255) => (3631AS: 8,9,12,noDIG)
* Выводы сегментов 9,8,7,6,5,4,3,2 => A,B,C,D,E,F,DP
*
***********************************************************/// Создаём объект индикатора
Led4Digits disp(1, 17,11,10,255, 9,8,7,6,5,4,3,2);
// Создаём объект oneWire// Номер пина 14(A0) к которому подключен DS18B20#define ONE_WIRE_BUS 14
OneWire oneWire(ONE_WIRE_BUS);
// Создаём объект sensors типа DallasTemperature
DallasTemperature sensors(&oneWire);
// Переменные для DS18x20
// Температура с датчикаfloat temperature,
set_temp=21.,// Уставка температуры
delta_t=1.; // Гистерезис для температурыbyte addr[8], type_s;
boolean flag_alarm;
// ЗП на вывод 15(А1)#define pinBUZZER 15
// Светодиод для индикации нагревателя#define pinLedT1 13
// Светодиод для индикации охладителя на вывод 16(А2)#define pinLedT2 16
// номер вывода кнопки меню 18(А4)#define BUTTON_MENU_PIN 18
// номер вывода кнопки уменьшить 19(A5)#define BUTTON_MINUS_PIN 19
// номер вывода кнопки увеличить#define BUTTON_PLUS_PIN 12
/********************************************************
* Button(byte pin, byte timeButton)
* pin - контакт
* timeButton - время (число) подтверждения
*
********************************************************/// Создание объектов для кнопкок
Button buttonMenu(BUTTON_MENU_PIN,18); // для кнопки menu
Button buttonMinus(BUTTON_MINUS_PIN,18);// для кнопки Минус
Button buttonPlus(BUTTON_PLUS_PIN,18); // для кнопки Плюс// Переменные для времени (обновление значения)unsignedlong tm, next_sec;
// Обновление температуры через 1 секундуconstunsignedint to_sec = 1000;
byte menu=0; // Переменная для менюbyte menu_last;// Переменная предыдущего п. менюint mode_t; // Режим регулирования температуры:// 0 - без регулирования,// 1 - нагреватель,// 2 - охладитель// Адреса для сохранения уставок в EEPROMbyte addrT=0;
byte addrDeltaT=addrT+4;
byte addrModeT=addrDeltaT+4;
boolean flag_eeprom=false;
float temp;// Переменная для временного значения/*******************************************************
* Настроечная функция, выполняется один раз вначале
*******************************************************/voidsetup()
{
pinMode(pinBUZZER,OUTPUT);
pinMode(pinLedT1,OUTPUT);
pinMode(pinLedT2,OUTPUT);
// прерывание по таймеру 2 мс
MsTimer2::set(2, timerInterrupt);
// разрешение прерывания
MsTimer2::start();
// зажечь точку второго разряда
disp.digit[1] |= 0x80;
// Старт датчика DS18x20
sensors.begin();
// Считывание адреса датчика
sensors.getAddress(addr, 0);
// Установка значений из EEPROM
set_temp = EEPROM_float_read(addrT);
delta_t = EEPROM_float_read(addrDeltaT);
mode_t = EEPROM_int_read(addrModeT);
}
/*******************************************************
* Функция loop() выполняется постоянно
*******************************************************/voidloop()
{
/* Сканирование кнопок */
buttonMenu.scanState();
buttonMinus.scanState();
buttonPlus.scanState();
// Было нажатие кнопки "menu"if(buttonMenu.flagClick ==true)
{
buttonMenu.flagClick =false;// Сброс признака клика
menu++;// Переходим на следующий пунктif(menu > 3) menu=0;
/*******************************************************
* Всего 4-е пункта меню:
* 0 - индикация текущей температуры
* 1 - T°C - уставка температуры
* 2 - delta T°C - дельта температуры
* 3 - режим регулирования температуры:
* 0 - без регулирования,
* 1 - нагреватель,
* 2 - охладитель
*******************************************************/
}
// Получаем кол-во мс от начала работы программы
tm =millis();
// Индикация текущей температурыif((tm > next_sec) && menu == 0)
{
disp.digit[1] |= 0x80; // зажечь точку второго разряда
next_sec = tm + to_sec;// Добавляем 1 секунду/* Чтение температуры */
// Обновление значения датчика
sensors.requestTemperatures();
temperature = sensors.getTempC(addr);// Получение t°C/* Режим регулирования = НАГРЕВАТЕЛЬ */if((temperature < (set_temp - delta_t)) && mode_t == 1)
{
if(flag_alarm ==false)
{
// Звуковой сигналtone(pinBUZZER,1000,50);
// Включение сигнализации нагрева REDdigitalWrite(pinLedT1,HIGH);
}
flag_alarm =true;// Подъём флага сигнализации
}
elseif(flag_alarm && (temperature > set_temp) && mode_t==1)
{
flag_alarm =false;// Сброс флага сигнализацииdigitalWrite(pinLedT1,LOW);// Отключение сигнализации
}
/* Режим регулирования = ОХЛАДИТЕЛЬ */if((temperature > (set_temp + delta_t)) && mode_t == 2)
{
if(flag_alarm ==false)
{
// Звуковой сигналtone(pinBUZZER,1000,50);
// Включение сигнализации охлаждения BLUEdigitalWrite(pinLedT2,HIGH);
}
flag_alarm =true;// Подъём флага сигнализации
}
elseif(flag_alarm && (temperature < set_temp) && mode_t == 2)
{
flag_alarm =false;// Сброс флага сигнализацииdigitalWrite(pinLedT2,LOW);// Отключение сигнализации
}
/*********************************************************
* Выводим на индикатор текущую температуру:
* Делаем умножение на 10
* преобразуем в целое
* и выводим на индикатор как целое значение
* точку ставим во втором разряде =>
* получается на индикаторе число с точкой
* и десятичным значением после неё
*
*********************************************************/
disp.print(int(temperature * 10.), 3, 1);
}
/* Режимы установки параметров */if(menu == 1)// Уставка температуры
{
if(buttonMinus.flagClick ==true)
{
buttonMinus.flagClick =false;// Сброс признака клика
set_temp -= 0.1;
flag_eeprom =true;// Взводим флаг записи в EEPROM
}
if(buttonPlus.flagClick ==true)
{
buttonPlus.flagClick =false;// Сброс признака клика
set_temp += 0.1;
flag_eeprom =true;// Взводим флаг записи в EEPROM
}
disp.print(int(temperature * 10.), 3, 1);
}
if(menu == 2)// Уставка дельты
{
if(buttonMinus.flagClick ==true)
{
buttonMinus.flagClick =false;// Сброс признака клика
delta_t -= 0.1;
flag_eeprom =true;// Взводим флаг записи в EEPROM
}
if(buttonPlus.flagClick ==true)
{
buttonPlus.flagClick =false;// Сброс признака клика
delta_t += 0.1;
flag_eeprom =true;// Взводим флаг записи в EEPROM
}
// Выводим на индикатор дельту
disp.print(int(delta_t * 10.), 3, 1);
}
if(menu == 3)// Уставка режима регулирования температуры
{
if(buttonMinus.flagClick ==true)
{
buttonMinus.flagClick =false;// Сброс признака клика
mode_t --;
if(mode_t < 0) mode_t=2;
flag_eeprom =true;// Взводим флаг записи в EEPROM
}
if(buttonPlus.flagClick ==true)
{
buttonPlus.flagClick =false;// Сброс признака клика
mode_t ++;
if(mode_t > 2) mode_t=0;
flag_eeprom =true;// Взводим флаг записи в EEPROM
}
// потушить точку второго разряда B01111111
disp.digit[1] &= 0x7f;
disp.print(mode_t, 3, 1);// Выводим на индикатор
}
/* Запись изменённых значений в EEPROM */if(flag_eeprom && menu_last != menu)
{
switch(menu_last)
{
case 1:// Чтение значения Т°C из памяти
temp = EEPROM_float_read(addrT);
if(set_temp != temp)
EEPROM_float_write(addrT, set_temp);
break;
case 2:// Чтение значения delta_t из памяти
temp = EEPROM_float_read(addrDeltaT);
if(delta_t != temp)
EEPROM_float_write(addrDeltaT, delta_t);
break;
case 3:// Чтение значения mode_t из памяти
temp = EEPROM_int_read(addrModeT);
if(mode_t !=int(temp))
EEPROM_int_write(addrModeT, mode_t);
/* При смене mode_t отключаем бывшие оповещения */digitalWrite(pinLedT1,LOW);
digitalWrite(pinLedT2,LOW);
}
flag_eeprom =false;// Сбрасываем флаг записи в EEPROM
}
menu_last = menu;// Перезаписываем режим
}// Конец loop()/* Обработчик прерывания 2 мс */void timerInterrupt()
{
disp.regen();// регенерация индикатора
}
/********************************************************
* Функции для работы с EEPROM
********************************************************//* Чтение float из EEPROM */float EEPROM_float_read(int addr)
{
byte raw[4];
for(byte i = 0; i < 4; i++)
{
raw[i] =EEPROM.read(addr+i);
}
float&num = (float&)raw;
return num;
}
/* Запись float в EEPROM */void EEPROM_float_write(int addr,float num)
{
byte raw[4];
(float&)raw = num;
for(byte i = 0; i < 4; i++)
{
EEPROM.write(addr+i, raw[i]);
}
}
/* Чтение int из EEPROM */int EEPROM_int_read(int addr)
{
byte raw[2];
for(byte i = 0; i < 2; i++)
{
raw[i] =EEPROM.read(addr+i);
}
int&num = (int&)raw;
return num;
}
/* Запись int в EEPROM */void EEPROM_int_write(int addr,int num)
{
byte raw[2];
(int&)raw = num;
for(byte i = 0; i < 2; i++)
{
EEPROM.write(addr+i, raw[i]);
}
}
Код закоментирован достаточно подробно и понятно.
Можно немного ещё дополнить, что код записи в EEPROM нашёл в интернете, покопавшись на разных сайтах и форумах и потом опробовал его работоспособность у себя.
Для управления семисегментным индикатором используется скачанная библиотека Led4Digits.h. В общем мне эта библиотека очень понравилась, с большими возможностями и легко применять. Однако, при такой конструкции, у Ардуино все порты вывода заняты, и в основном этим 3-х разрядным семисегментным индикатором. Подумываю использовать сдвиговые регистры SN74HC595 для управления индикатором и тем самым освободить порты от индикатора... возможно код управления индикатором опубликую на следующих страницах и проектах, а пока так как есть.
Скетч использует 7298 байт, что избыточно для ARDUINO Nano и имеет смысл использовать ARDUINO Pro mini с микроконтроллером ATMEGA168P (16k флэш памяти), или ATTiny88 (8k флэш памяти).