Чарльз Платт – Электроника для начинающих (2-е издание) (страница 85)
Такое поведение называется
Как мы можем реализовать гистерезис в программе для микроконтроллера? Нам необходим более широкий диапазон значений, чем числа от 469 до 471. Программа могла бы описывать следующее: «Если светодиод включен, пусть он остается в этом состоянии, пока значение температуры не превысит 490. Затем его следует выключить». А также: «Если светодиод выключен, пусть он будет в таком состоянии, пока значение температуры не упадет ниже 460. Затем его надо включить».
Сможем ли мы это сделать? Да, очень легко. Программа, представленная в листинге 5.1, функционирует именно так. Протестировав эту программу, я сделал снимок экрана в среде Arduino IDE, и поэтому у меня есть веские основания полагать, что она работает.
Листинг 5.1
Эта программа содержит также некоторые новые понятия – но для начала введите ее в среду IDE. Не обязательно включать все строки комментариев, которые я добавил только для пояснения.
В более коротком варианте программы (листинг 5.2) строки комментариев опущены.
Листинг 5.2
Выполните проверку/компиляцию вашей программы и при необходимости исправьте опечатки (возможно, вы где-либо пропустили точку с запятой – это самая распространенная ошибка).
Подключите плату Arduino, загрузите программу, и если температура вашего терморезистора ниже 30 °C, должен зажечься желтый светодиод.
Нагрейте терморезистор, зажав его между пальцами, как будто температура в помещении увеличилась. Спустя несколько секунд светодиод погаснет. Теперь отпустите терморезистор, и он остынет, но светодиод еще продолжит гореть некоторое время, потому что гистерезис в данной системе заставляет выждать, пока температура не станет достаточно низкой. В конечном счете, светодиод загорится снова. Получилось!
Но как же работает эта программа?
Строка за строкой
В программе существует такое понятие, как
Строка int digitemp = 0; означает, что объявил переменную с именем digitemp. Она является целочисленной (целым числом) и принимает значения начиная с нуля.
В строке int ledstate = 0; я объявил еще одну целочисленную переменную, чтобы отслеживать состояние светодиода на плате (включен или выключен). Нельзя попросить микроконтроллер посмотреть на светодиод и сказать, в каком он состоянии, поэтому я должен самостоятельно предусмотреть все требуемые действия.
Команда pinMode (13, OUTPUT) в секции setup сообщает микроконтроллеру о том, что следует сконфигурировать контакт 13 как выход. Задавать режим работы контакта А0 в качестве входа нет необходимости, потому что аналоговые выводы являются входами по умолчанию.
Теперь перейдем к основной части программы, К циклу. Сначала я задал команду analogRead, чтобы микроконтроллер прочитал состояние аналогового порта. Какого? Я указал 0, что означает аналоговый порт А0. В него вставлен проводник от моей макетной платы.
Что я собираюсь делать с информацией от АЦП после того, как она будет считана с порта? Есть только одно разумное место ее размещения: в переменной digitemp, которую я создал для этой цели.
Теперь, когда переменная digitemp содержит значение, я могу проверить ее. Если нагреватель включен (светодиод горит) И значение
if (ledstate == 1 && digitemp > 490)
Двойной знак равенства (==) означает «выполнить сравнение и выяснить, одинаковы ли эти два значения». Одиночный знак равенства означает другую операцию: «назначить данное значение переменной».
Двойной символ & – это «логическое И». Да, здесь у нас применяется булева логика, как и в логическом элементе И. Но вместо того чтобы подключать микросхему, мы просто пишем строку кода.
Символ > означает «больше, чем».
Проверка условия «если» помещена в круглые скобки. Если утверждение в круглых скобках истинно, то микроконтроллер выполняет процедуру, расположенную между фигурными скобками. В этой процедуре с помощью команды ledstate = 0 записан тот факт, что светодиод будет выключен. Команда digitalWrite (13, LOW); в действительности выключает светодиод.
Вторая проверка условия «если» очень похожа, за исключением того, что она применяется, если светодиод выключен, а температура сильно снизилась. Тогда мы зажигаем светодиод.
Наконец, введена задержка на десятую долю секунды, поскольку нам не нужно проверять температуру чаще.
Вот и все.
Нюансы программирования
Я объяснил здесь лишь некоторые синтаксические структуры, например, проверку условия «если» и двойной знак равенства, а также логический оператор && без перечисления всего списка конструкций, которые есть в языке С. Необходимые дополнительные сведения вы всегда сможете найти онлайн.
Запомните несколько моментов, относящихся к программе:
• Строки набраны с отступами, чтобы улучшить восприятие логической структуры программы. Компилятор игнорирует дополнительные пробелы, поэтому вы можете спокойно добавлять их в любом количестве.
• Для удобства среда IDE выделяет ошибки в тексте программы цветом.
• Когда вы присваиваете имя переменной, допустимо любое сочетание букв, цифр и символа подчеркивания – при том условии, что эта комбинация не совпадает с зарезервированным словом в языке С. Например, нельзя создать переменную с именем void.
• Кому-то нравится начинать названия с прописной буквы, а кому-то – со строчной. Выбор за вами.
• Каждая переменная должна быть объявлена в начале программы, иначе компилятор выдаст ошибку.
• Целочисленная переменная (объявленная при помощи ключевого слова int) может принимать значение от −32 768 до +32 767. Язык С в этом микроконтроллере разрешает использовать переменные, которые имеют более широкий диапазон значений или которые могут быть дробными. Но до эксперимента 34 большие числа не понадобятся.
Начальные справочные сведения о языке вы можете найти на главном сайте компании Arduino. Выберите вкладку Learning (Обучение), а затем в раскрывающемся меню укажите пункт Reference (Справка). Можно также открыть меню Помощь (Help) в среде Arduino IDE и выбрать пункт Справочник (Reference).
Усовершенствование программы
Предложенная программа решает поставленную задачу, но ее функции очень ограничены. Самое большое ограничение состоит в том, что значения минимальной и максимальной температуры заданы в виде констант. Это похоже на термостат, зафиксированный только в одном положении, которое нельзя настроить. Как улучшить эту программу, чтобы пользователь мог самостоятельно задать пороговые значения температуры для включения и отключения нагревателя?
Думаю, можно было бы добавить потенциометр. Крайние выводы потенциометра следовало бы подключить к клеммам 5 В и 0 В, а движок соединить с другим аналоговым входом микроконтроллера. В результате потенциометр стал бы работать как делитель напряжения и обеспечивал бы полный диапазон напряжения от 0 до 5 В.
Затем я добавил бы еще одну процедуру в цикл, в которой микроконтроллер проверял положение движка потенциометра и переводил его в числовую форму.
В результате получалось бы число в диапазоне от 0 до 1023. Мне потребовалось бы преобразовать его в число, которое соответствует возможному диапазону значений переменной digitemp. Далее я присвоил бы результат новой переменной с именем, скажем, usertemp. Затем мне понадобилось бы выяснить, существенно ли выше или ниже та температура, которую измерил терморезистор, по сравнению с переменной usertemp.
Заметьте, я опустил одну маленькую деталь: каким, собственно, образом я преобразовал бы входной сигнал от потенциометра в диапазон, подходящий для переменной usertemp. Сейчас мы с этим разберемся.
Если диапазон возможных значений терморезистора составлен из чисел от 430 до 512, как я установил ранее, то его можно представить как среднее значение 471 плюс или минус 41. Потенциометр имеет среднее значение 512 плюс или минус 512 до его полного диапазона. Поэтому:
usertemp = 471 + ((potentiometer – 512) * .08)
где potentiometer – это значение со входа потенциометра, а символ «звездочка» (*) используется в языке С как знак умножения. Результат достаточно близкий.
Да, арифметика рано или поздно проявляется в программировании, так или иначе. И нет способа обойтись без нее. Но уровня математики средней школы для наших задач вполне хватит.
В улучшенной версии программы мне по-прежнему необходимо позаботиться о гистерезисе. Первый оператор сравнения следует преобразовать так:
if (ledstate == 1 && digitemp > (usertemp + 10))
после чего светодиод выключается. Но
if (ledstate == 0 && digitemp < (usertemp – 10))
и тогда светодиод загорается. Это дало бы мне диапазон гистерезиса плюс-минус 10, если используются значения от АЦП.
Теперь, когда я описал необходимую модификацию программы, возможно, вы захотите осуществить ее самостоятельно. Не забывайте только объявлять каждую новую переменную, прежде чем вы ее укажете в теле программы.