10.5. Создание регулятора температуры
Давайте теперь заставим дисплей выполнять полезную функцию. Добавим I2C датчик температуры, рассмотренный в главе 8, вентилятор и динамик из главы 5.
Дисплей будет показывать температуру и текущее состояние вентилятора. Когда станет жарко, динамик издаст предупреждающий звук и вентилятор включится.
Когда снова станет прохладно, вентилятор перестанет работать. С помощью двух кнопок и фрагмента кода подавления дребезга из листинга 2.5 вы получите возможность увеличивать или уменьшать требуемую температуру.
- 212 -
10.5.1. Монтаж схемы устройства
Соединение деталей для этого устройства представляет собой комбинацию предыдущих схем. Маломощный вентилятор с двигателем постоянного тока подключается непосредственно к контакту платы Arduino. При желании использовать мощный вентилятор, можно подключить его к внешнему источнику питания через транзистор ( см. главу 4). Для этого подойдет схема, изображенная на рис. 4.1. ЖК-дисплей подключим так же, как в предыдущем примере (см. рис. 10.2).
Один из выводов кнопок подключен к шине питания, а другой - к контакту Arduino и через резистор 10 кОм на землю.
Один вывод динамика подключен к контакту Arduino, а другой - через резистор 150 Ом к земле. Частота звука устанавливается программно.
I2C-датчик температуры подключен так же, как в главе 8. Монтажная схема устройства изображена на рис. 10.3. Изображение датчика температуры сделано частично прозрачным, чтобы можно было увидеть потенциометр позади него.
Рис. 10.3. Схема регулятора температуры с ЖК-дисплеем
- 213 -
10.5.2. Отображение данных на ЖК-дисплее
Для облегчения вывода информации на ЖК-дисплей заранее определим некоторые параметры. Решим, что температуру всегда будем отображать в виде двух цифр.
Надписи "Current:" и "Set:" всегда будут неизменными, их можно вывести на экран один раз. Так как температура представлена в виде двух цифр, местоположение двух надписей " 0 С" тоже будет фиксированным. Текущее значение температуры будет отображаться в позиции (8,0) и обновляться при каждом цикле loop(), значение пороговой температуры размещено в позиции (8, 1) и обновляется при нажатии кнопки. Значок включения вентилятора будет отображаться в нижней правой части дисплея в позиции (15,1) и обновляться, когда изменяется состояние.
При работе программы ЖК-дисплей будет выглядеть примерно так, как показано на рис.10.4.
Рис. 10.4. Отображение данных на ЖК-дисплее
Знак градуса, символы включенного и выключенного вентилятора не входят в стандартный набор символов. Следовательно, в начале программы нужно сформировать соответствующие массивы, как показано в листинге 10.3.
Листинг 10.3. Массивы, опредеяющие пользовательские символы
// Пользовательский символ градуса
byte degree[8] = {
В00110,
В01001,
В01001,
В00110,
B00000, B00000, B00000, B00000,
};
// Символ "вентилятор включен"
byte fan_on[8] = {
В00100,
B10101,
В01110,
B11111,
В01110,
- 214 -
B10101,
B00100,
B00000,
};
// Символ "вентилятор выключен"
byte fan_off[8] = {
B00100,
B00100,
B00100,
B11111,
B00100,
B00100,
B00100,
B00000,
};
Вывод данных на экран ЖК-дисплея будет осуществлен в функции setup(). Размещаем курсор в нужной позиции и с помощью библиотечных функций print() и write() выводим надписи на экран (листинг 10.4).
Листинг 10.4. Вывод иформации на экран ЖК-дисплея
// Создаем пользовательские символы
lcd.createChar(0, degree);
lcd.createChar(1, fan_off);
lcd.createChar(2, fan_on);
// Отображаем статические надписи на экране ЖК-дисплея
lcd.setCursor(0,0);
lcd.print("Current:");
lcd.setCursor(10,0);
lcd.write ( (byte) 0);
lcd.setCursor(11,0);
lcd.print("C");
lcd.setCursor(0,1);
lcd.print("Set:");
lcd.setCursor(10,1);
lcd.write ( (byte) 0);
lcd.setCursor(11,1);
lcd.print("C");
lcd.setCursor(15,1);
lcd.write(1);
В каждом цикле loop() обновляем текущее значение температуры и состояние значка включения вентилятора. Перед этим помещаем в нужное место курсор.
- 215 -
10.5.3. Установка порогового значения температуры с помощью кнопок
В главе 2 мы использовали функцию предотвращения дребезга debounce(). Здесь немного изменим ее, чтобы устранить дребезг нескольких кнопок. Одна кнопка увеличивает пороговое значение температуры, другая уменьшает его. Необходимо определить переменные для хранения текущего и предьщущего состояний кнопок:
// Переменные, используемые при устранении дребезга кнопок
boolean lastDownTempButton = LOW;
boolean currentDownTempButton = LOW;
boolean lastUpTempButton = LOW;
boolean currentUpTempButton = LOW;
Переделаем функцию устранения дребезга debounce() для случая нескольких кнопок. Добавим второй аргумент, задающий кнопку, для которой устраняем дребезг (листинг 10.5).
Листинг 10.5. Функция устранения дребезга двух кнопок
// Функция проверки дребезга для нескольких кнопок
boolean debounce(boolean last, int pin)
{
boolean current = digitalRead(pin);
if (last != current)
{
delay (5);
current = digitalRead(pin);
}
return current;
}
В основном цикле программы loop() проверяем состояние кнопок, устраняем дребезг, изменяем при нажатии кнопки значение переменной пороговой температуры set_temp и обновляем значение на экране ЖК-дисплея (листинг 10.6).
Листинг 10.6. Программа установки пороговой температуры с помощью двух кнопок
// Устранение дребезга нескольких кнопок
currentDownTempButton = debounce(lastDownTempButton, DOWN_BUTTON);
currentUpTempButton = debounce(lastUpTempButton, UP_BUTTON);
// Уменьшить значение set_temp
if (lastDownTempButton == LOW && currentDownTempButton == HIGH)
{
set_temp--;
}
- 216 -
// Увеличить значение set_temp
else if (lastUpTempButton == LOW && currentUpTempButton == HIGH)
{
set_temp++;
}
// Вывести значение set_temp на ЖК-дисплей
lcd.setCursor(8,1);
lcd.print(set_temp);
// Изменить последние значения статуса кнопок
lastDownTempButton = currentDownTempButton;
lastUpTempButton = currentUpTempButton;
В листинге 10.6 запускаем функцию устранения дребезга debounce() для каждой кнопки, а затем изменяем переменную set_temp заданной пороговой температуры при нажатии одной из кнопок. Потом значение температуры обновляется на экране ЖК-дисплея.
10.5.4. Добавляем вентилятор и звуковое оповещение
Теперь добавим фрагмент кода для управления вентилятором и динамиком. Хотя ЖК-дисплей и так информирует нас обо всем, никогда не помешает дополнительное звуковое оповещение о событиях. Например, подача звукового сигнала перед включением вентилятора. В этом примере мы используем команды tone() в паре с задержкой delay() и notone(). Чтобы задать длительность звука, можно указать второй аргумент команды tone(). Добавив переменную состояния, можно устанавливать звуковое оповещение динамиком только один раз при превышении порогового значения температуры.
Фрагмент кода, приведенный в листинге 10.7, проверяет температуру и управляет динамиком, вентилятором и индикатором вентилятора на ЖК-дисплее.
Листинг 10.7. Выдача звукового оповещения при превышении пороговой температуры
// Стало жарко!
if (с>= set_temp)
// Издать звук динамиком
if ( !one_time)
{
tone(SPEAKER, 400);
delay(500);
one time = true;
}
- 217 -
// Выключить динамик
else
{
noTone (SPEAKER);
}
// Включить вентилятор и знак на ЖК-дисплее
digitalWrite(FAN, HIGH);
lcd.setCursor(15,1);
lcd.write(2);
}
// Стало прохладнее
else
{
// Выключить динамик
// Сбросить состояние one time в false
// Выключить вентилятор и значок на ЖК-дисплее
noTone(SPEAKER);
one time = false;
digitalWrite(FAN, LOW);
lcd.setCursor(15,1);
lcd.write(1);
}
Переменная one_time позволяет выдать однократный, а не непрерывный звуковой сигнал. После того как динамик издает звук длительностью 500 мс частотой 400 Гц, переменная устанавливается в true и сбрасывается в false только тогда, когда температура падает обратно ниже заданного порога.
10.5.5. Итог всего: полная программа
Теперь соберем части в единое целое. В начале программы необходимо подключить библиотеки, определить флажки и инициализировать переменные состояния.
Полный текст программы приведен в листинге 10.8. Загрузите ее на плату Arduino и сравните результаты с видеоклипом, демонстрирующим систему в действии.
Листинг 10.8. Программа автоматического регулятора температуры - LCD_thermostat.ino
// Это программа автоматического регулятора температуры
// Для вывода температуры используются 2 знака
// Использует библиотеку Wire с установкой адреса
#include <Wire.h>
#define TEMP ADDR 72
// Подключение и инициализация библиотеки LiquidCrystal:
#include <LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
- 218 -
// Пользовательский символ градуса
byte degree[8] = {
В00110,
В01001,
В01001,
В00110,
B00000, B00000, B00000, B00000,
};
// Пользовательский символ "вентилятор включен"
byte fan_on[8] = {
800100,
810101,
B01110,
B11111,
В01110,
B10101,
B00100,
B00000,
};
// Пользовательский символ "вентилятор выключен"
byte fan_off[8] = {
В00100,
B00100,
B00100,
B11111,
B00100,
B00100,
B00100,
B00000,
};
// Выводы подключения динамика, кнопок, вентилятора
const int SPEAKER=8;
const int DOWN_BUTTON =9;
const int UP_BUTTON =10;
const int FAN =11;
// Переменные для устранения дребезга кнопок
boolean lastDownTempButton = LOW;
boolean currentDownTempButton = LOW;
boolean lastUpTempButton = LOW;
boolean currentUpTempButton = LOW;
int set_temp = 23; // Значение граничной температуры
boolean one time = false; // Флаг звука динамика
- 219 -
void setup()
{
pinMode(FAN, OUTPUT);
// Создание объекта Wire (I2С-датчик температуры)
Wire.begin();
// Настройки дисплея (число столбцов и строк)
lcd.begin(16, 2);
// Определить пользовательские символы
lcd.createChar(0, degree);
lcd.createChar(1, fan_off);
lcd.createChar(2, fan_on);
// Вывод закрепленных сообщений на дисплее
lcd.setCursor(0,0);
lcd.print("Current:");
lcd.setCursor(10,0);
lcd. write ( (byte) 0);
lcd.setCursor(11,0);
lcd.print("C");
lcd.setCursor(0,1);
lcd.print("Set:");
lcd.setCursor(10,1);
lcd.write ( (byte) 0);
lcd.setCursor(11,1);
lcd.print("C");
lcd.setCursor(15,1);
lcd.write(1);
}
// Функция проверки на дребезг для нескольких кнопок
boolean debounce(boolean last, int pin)
{
boolean current = digitalRead(pin);
if (last != current)
{
delay(5);
current = digitalRead(pin);
}
return current;
}
void loop()
{
// Получить значение от датчика температуры
Wire.beginTransmission(TEMP_ADDR);
Wire.write (0);
Wire.endTransmission();
Wire.requestFrom(TEMP_ADDR, 1);
- 220 -
// Ожидаем передачу
// Получить 1 байт
while(Wire.available()==0);
int с = Wire.read();
// Установить курсор
// и вывести текущее значение
lcd.setCursor(8,0);
lcd.print(c);
// Проверка на дребезг для двух кнопок
currentDownTempButton = debounce(lastDownTempButton, DOWN_BUTTON);
currentUpTempButton = debounce(lastUpTempButton, UP_BUTTON);
// Уменьшить пороговое значение температуры
if (lastDownTempButton== LOW && currentDownTempButton == HIGH)
{
set_temp--;
}
// Увеличить пороговое значение температуры
else if (lastUpTempButton == LOW && currentUpTempButton
{
set_temp++;
}
// Вывод порогового значения на экран
lcd.setCursor(8,1);
lcd.print(set_temp);
currentDownTempButton;
lastDownTempButton
lastUpTempButton = currentUpTempButton;
// Очень жарко!
if (с >= set_temp)
{
// Однократный звуковой сигнал на динамик
if ( ! one_time)
{
tone(SPEAKER, 400);
delay ( 500);
one time = true;
}
// Отключить вывод звука
else
{
noTone (SPEAKER);
}
// Включить вентилятор и вывести значок на дисплей
digitalWrite(FAN, HIGH);
lcd.setCursor(15,1);
lcd.write(2);
}
- 221 -
//Не жарко!
else
{
// Выключить динамик
// Сбросить состояние one time в false
// Выключить вентилятор и значок на ЖК-дисплее
noTone(SPEAKER);
one time = false;
digitalWrite(FAN, LOW);
lcd.setCursor(15,1);
lcd.write(1);
}
}
Теперь, чтобы посмотреть температуру, необязательно подключать плату Arduino к компьютеру. Можно питать плату от батарейки или автономного источника питания и поместить ее в любом месте вашей комнаты.
ПРИМЕЧАНИЕ
Посмотреть видеоклип, демонстрирующий действие автономного терморегулятора, можно на странице http://www.exploringarduino.com/content/ch10. Этот видеофайл доступен также на сайте издательства Wiley.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОК