Arduino:Примеры/TemperatureControl
Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску
Содержание | Знакомство с Arduino | Продукты | Основы | Справочник языка Arduino | Примеры | Библиотеки | Хакинг | Изменения | Сравнение языков Arduino и Processing |
Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.
Управление температурой[1]
Этот пример является расширенной версией примера «Контроллер Arduino» и показывает, как измерять и управлять температурой в бойлере, а также выводить эту температуру на график.
Код
// *** Управление температурой ***
// Это расширенная версия примера «Контроллер Arduino». Теперь PC
// отсылает на Arduino стартовую команду, а Arduino начинает измерять
// температуру и управлять нагревателем. Контроллер также начинает
// отсылать на PC данные о температуре и управлении нагревателем, а PC
// переводит их в график. Управление нагревателем осуществляется при
// помощи ползунка и библиотеки PID – с их помощью можно задать
// целевую температуру.
// Если у вас нет термопары или нагревающего элемента, в этот скетч
// встроена симуляция бойлера. Чтобы воспользоваться ею,
// отключите #define REAL_HEATER
// ПРИМЕЧАНИЕ: Если вы для загрузки библиотеки CmdMessenger
// использовали диспетчер пакетов, убедитесь, что у вас также
// подключены эти библиотеки:
// * PID
// * Adafruit_MAX31855 (в режиме симуляции не обязательна)
//
// Пакет, содержащий все эти библиотеки, можно найти тут:
https://github.com/thijse/Zipballs/blob/master/CmdMessenger/CmdMessenger.zip?raw=true
#include <utility\HeaterSim.h>
//#define REAL_HEATER;
#ifdef REAL_HEATER
#include <Adafruit_MAX31855.h>
#else
#include <utility\HeaterSim.h>
#endif
#include <CmdMessenger.h>
#include <PID_v1.h>
#include <utility\\DoEvery.h>
// привязываем экземпляр класса CmdMessenger к последовательному порту:
CmdMessenger cmdMessenger(Serial);
const int heaterPwmInterval = 300; // продолжительность ШИМ-цикла
const int measureInterval = 100; // интервал между измерениями
DoEvery tempTimer(measureInterval);
DoEvery pidTimer(heaterPwmInterval);
// настройки PID:
double pidP = 1500;
double pidI = 25;
double pidD = 0;
// контакты термопары:
int thermoDO = 3;
int thermoCS = 4;
int thermoCLK = 5;
// контакт для реле:
const int switchPin = 4;
bool acquireData = false; // флаг для запуска/остановки записи логов
bool controlHeater = false; // флаг для запуска/остановки управления нагревателем
long startAcqMillis = 0;
double CurrentTemperature = 20; // измеренная температура
double goalTemperature = 20; // целевая температура
bool heaterOn = false; // начальное состояние нагревателя
double heaterSteerValue = 0; // начальное нормализированное значение для управления нагревателем
// инициализируем библиотеку для термопары:
#ifdef REAL_HEATER
Adafruit_MAX31855 thermocouple(thermoCLK, thermoCS, thermoDO);
#else
HeaterSim heaterSim(20); // нагреватель находится в месте, где окружающая температура составляет 20 градусов Цельсия
#endif
// инициализируем библиотеку PID:
PID pid(&CurrentTemperature, &heaterSteerValue, &goalTemperature,pidP,pidI,pidD,DIRECT);
// Это список распознаваемых команд, и эти команды могут быть
// либо получены, либо отправлены. Чтобы получить команду, к этому
// событию нужно привязать функцию внешнего вызова.
enum
{
// команды:
kWatchdog , // команда, запрашивающая ID устройства
kAcknowledge , // команда, подтверждающая получение команды
kError , // команда, сообщающая об ошибках
kStartLogging , // команда, запрашивающая начать запись логов
kStopLogging , // команда, запрашивающая остановить запись логов
kPlotDataPoint , // команда, запрашивающая отображение на графике точек данных
kSetGoalTemperature , // команда, задающая целевую температуру
KSetStartTime , // команда, задающая новое начальное время для записи логов
};
// команды, отсылаемые от PC и получаемые на Arduino; в скетче Arduino
// нужно задать функцию внешнего вызова для каждой записи из списка ниже:
void attachCommandCallbacks()
{
// подключаем функции внешнего вызова:
cmdMessenger.attach(OnUnknownCommand);
cmdMessenger.attach(kWatchdog, OnWatchdogRequest);
cmdMessenger.attach(kStartLogging, OnStartLogging);
cmdMessenger.attach(kStopLogging, OnStopLogging);
cmdMessenger.attach(kSetGoalTemperature, OnSetGoalTemperature);
cmdMessenger.attach(KSetStartTime, OnSetStartTime);
}
// ------------------ ФУНКЦИИ ВНЕШНЕГО ВЫЗОВА ----------------------
// эта функция вызывается, когда к присланной команде не привязано никакой функции:
void OnUnknownCommand()
{
cmdMessenger.sendCmd(kError,"Command without attached callback"); // "Команда без функции внешнего вызова"
}
void OnWatchdogRequest()
{
// по запросу отсылаем на компьютер эти команду и идентификатор:
cmdMessenger.sendCmd(kWatchdog, "77FAEDD5-FAC8-46BD-875E-5E9B6D44F85C");
}
// функция внешнего вызова, сообщающая о готовности Arduino (т.е. о ее загрузке):
void OnArduinoReady()
{
cmdMessenger.sendCmd(kAcknowledge,"Arduino ready"); // "Arduino готова"
}
// функция для сбора данных:
void OnStartLogging()
{
// начинаем сбор данных:
acquireData = true;
cmdMessenger.sendCmd(kAcknowledge,"Start Logging"); // "Начинаем запись логов"
}
// функция для остановки сбора данных:
void OnStopLogging()
{
acquireData = false;
cmdMessenger.sendCmd(kAcknowledge,"Stop Logging"); // "Останавливаем запись логов"
}
// функция внешнего вызова, задающая целевую температуру:
void OnSetGoalTemperature()
{
// считываем аргумент о состоянии светодиода, интерпретируем строку как float:
float newTemperature = cmdMessenger.readBinArg<float>();
// перед изменением целевой температуры убеждаемся, что аргумент корректен:
if (cmdMessenger.isArgOk()) {
goalTemperature = newTemperature;
// включаем управление нагревателем (вначале оно отключено)
controlHeater = true;
// отправляем на PC сообщение с подтверждением:
cmdMessenger.sendBinCmd(kAcknowledge,goalTemperature);
} else {
// в присланной целевой температуре ошибка! Значит, шлем на PC сообщение об этой ошибке:
cmdMessenger.sendCmd(kError,"Error in received new goal temperature"); // "В новой целевой температуре обнаружена ошибка"
}
}
// функция внешнего вызова, задающая начальное время:
void OnSetStartTime()
{
// считываем аргумент о состоянии светодиода, интерпретируем строку как float:
float startTime = cmdMessenger.readBinArg<float>();
// перед изменением убеждаемся, что аргумент корректен:
if (cmdMessenger.isArgOk()) {
unsigned long milis = millis();
// транслируем секунды в миллисекунды для внутренних часов: startAcqMillis = (unsigned long)((float)startTime*1000.0f);
if (startAcqMillis > milis) { startAcqMillis = milis; }
startAcqMillis = milis- startAcqMillis;
}
}
// ------------------ ГЛАВНАЯ ЧАСТЬ СКЕТЧА ----------------------
// блок исходных операций:
void setup()
{
// прослушиваем последовательное соединение на предмет сообщений
// от PC (115200 – это, как правило, максимальная скорость для
// последовательной коммуникации через USB):
Serial.begin(115200);
// многие макетные платы с bluetooth (вроде HC-05/HC-06) по
// умолчанию работают на скорости 9600. Настройки, указанные ниже,
// должны этому соответствовать:
//Serial.begin(9600);
// в конце команды не пишем символ новой строки, чтобы сократить
// размер отправляемых данных:
cmdMessenger.printLfCr(false);
// инициализируем таймеры:
tempTimer.reset();
pidTimer.reset();
// инициализируем переменные PID:
pid.SetOutputLimits(0,heaterPwmInterval);
// считываем текущую температуру:
#ifdef REAL_HEATER
CurrentTemperature= thermocouple.readCelsius();
#else
CurrentTemperature = heaterSim.GetTemp();
#endif
// подготавливаем PID-порт для записи:
pinMode(switchPin, OUTPUT);
// включаем PID и выставляем на автомат:
pid.SetMode(AUTOMATIC);
// выставляем время замера:
pid.SetSampleTime(measureInterval);
// подключаем функции внешнего вызова, заданные пользователем:
attachCommandCallbacks();
// отсылаем на PC сообщение о загрузке Arduino:
cmdMessenger.sendCmd(kAcknowledge,"Arduino has started!"); // "Arduino запущена!"
}
// блок повторяющихся операций:
void loop()
{
// обрабатываем данные, пришедшие по последовательному соединению,
// и выполняем функции внешнего вызова:
cmdMessenger.feedinSerialData();
// каждые 100 миллисекунд обновляем температуру:
if(tempTimer.check()) measure();
// обновляем таймер PID:
pidTimer.check();
// проверяем, управляем ли мы нагревателем:
if (controlHeater) {
// вычисляем новые параметры PID:
pid.Compute();
// управляем нагревателем при помощи широтно-импульсной модуляции:
heaterPWM();
}
}
// меряем температуру в бойлере:
void measure() {
if (acquireData) {
// рассчитываем время:
float seconds = (float) (millis()-startAcqMillis) /1000.0 ;
// измеряем температуру:
#ifdef REAL_HEATER
CurrentTemperature= thermocouple.readCelsius(); // измеряем при помощи термопары
#else
CurrentTemperature = heaterSim.GetTemp(); // измеряем температуру в симулированном бойлере
#endif
// отправляем данные на PC:
cmdMessenger.sendCmdStart(kPlotDataPoint);
cmdMessenger.sendCmdBinArg((float)seconds); // время
cmdMessenger.sendCmdBinArg((float)CurrentTemperature); // измеренная температура
cmdMessenger.sendCmdBinArg((float)goalTemperature); // целевая температура
cmdMessenger.sendCmdBinArg((float)((double)heaterSteerValue/(double)heaterPwmInterval)); // нормализированное значения для управления нагревателем
cmdMessenger.sendCmdBinArg((bool)heaterOn); // состояние вкл/выкл во время ШИМ-цикла
cmdMessenger.sendCmdEnd();
}
}
void SetHeaterState(bool heaterOn)
{
// включаем нагреватель, подключенный к реле на контакте switchPin:
digitalWrite(switchPin,heaterOn?HIGH:LOW);
}
// задаем состояние нагревателя:
void heaterPWM()
{
// включаем/выключаем нагреватель – в зависимости от фазы ШИМ-цикла:
heaterOn = pidTimer.before(heaterSteerValue);
#ifdef REAL_HEATER
SetHeaterState(heaterOn); // включаем нагреватель бойлера
#else
heaterSim.SetHeaterState(heaterOn); // включаем нагреватель симулированного бойлера
#endif
}
См.также
Внешние ссылки
Arduino продукты | |
---|---|
Начальный уровень | Arduino Uno • Arduino Leonardo • Arduino 101 • Arduino Robot • Arduino Esplora • Arduino Micro • Arduino Nano • Arduino Mini • Arduino Starter Kit • Arduino Basic Kit • MKR2UNO • TFT-дисплей Arduino |
Продвинутые функции | Arduino Mega 2560 • Arduino Zero • Arduino Due • Arduino Mega ADK • Arduino Pro • Arduino Motor Shield • Arduino USB Host Shield • Arduino Proto Shield • MKR Proto Shield • MKR Proto Large Shield • Arduino ISP • Arduino USB 2 Serial Micro • Arduino Mini USB Serial Adapter |
Интернет вещей | Arduino Yun • Arduino Ethernet • Arduino MKR1000 • Arduino WiFi 101 Shield • Arduino GSM Shield V2 • Arduino WiFi Shield • Arduino Wireless SD Shield • Arduino Wireless Proto Shield • Arduino Ethernet Shield V2 • Arduino Yun Shield • Arduino MKR1000 Bundle |
Носимые устройства | Arduino Gemma • Lilypad Arduino Simple • Lilypad Arduino Main Board • Lilypad Arduino USB • LilyPad Arduino SimpleSnap |
3D-печать | Arduino Materia 101 |
Устаревшие устройства | - |
Примеры Arduino | |
---|---|
Стандартные функции | |
Основы |
|
Цифровой сигнал |
|
Аналоговый сигнал |
|
Связь |
|
Управляющие структуры |
|
Датчики |
|
Дисплей |
Примеры, объясняющие основы управления дисплеем:
|
Строки |
|
USB (для Leonardo, Micro и Due плат) |
В этой секции имеют место примеры, которые демонстрируют использование библиотек, уникальных для плат Leonardo, Micro и Due.
|
Клавиатура |
|
Мышь |
|
Разное |
Категории:
- Страницы, использующие повторяющиеся аргументы в вызовах шаблонов
- Справочник языка Arduino
- Arduino
- Перевод от Сubewriter
- Проверка:myagkij
- Оформление:myagkij
- Редактирование:myagkij
- Страницы, где используется шаблон "Навигационная таблица/Телепорт"
- Страницы с телепортом
- Пример
- Примеры
- Пример программирования Arduino
- Примеры программирования Arduino