.
Беседа шестая.
Прерывания и создание функции.
Я обещал без теории, ну извините, мы так высоко забрались, что без этого уже никак. Но постараюсь что бы вам не было совсем уж скучно.
Еще меня тут просили не обижать прораба. Но куда же без него?! Все дело встанет!
Итак, что же такое прерывание.
Ситуация:
Все та же стройка, идет мучительный процесс возведения элитного жилого дома. Все занимаются своим делом. Вы копаете траншею от забора и до обеда. Прораб по обычаю мечется по этажам. И вот в этот момент, ваш приятель подает вам условный сигнал. (Помните, как в приключениях Шурика – «Третьим будешь?») Этот сигнал вам хорошо известен. Сигнал этот, так же как и место свершения таинства, гвоздем процарапаны на подкорке вашего мозга. Поэтому, ничуть не мешкая вы
прерываетесь и мухой летите в кандейку, там раскатываете 0,5 на троих и так же мухой возвращаетесь к своей траншее. Общий процесс от этого не пострадал, прораб ничего не заметил, ну разве что завершение стройки отодвинулось на очень короткий промежуток времени. На столько короткий что им можно пренебречь.
Вот и весь принцип работы прерывания.
В Ардуино прерывания бывают: Аппаратные, Программные и Внутренние (синхронные).
Рассмотрим аппаратные. К ним можно отнести нажатие на кнопку, подключенную к ножке контроллера. Так вот по этому сигналу, контроллер останавливает выполнение основного кода и выполняет отдельный кусочек программы, находящийся вне этого кода (кандейке). После чего возвращается в основной код, четко в то место на котором прервался. Основной код выполняется дальше.
Сразу оговорюсь. Не все ножки контроллера поддерживают прерывания. К примеру, у Arduino UNO их две – пин2 и пин3. Прерывания тоже пронумерованы 0 и 1.
Пин2 – прерывание 0
Пин3 – прерывание 1
Большее количество аппаратных прерываний задействовать в данном контроллере простым способом не удастся.
В коде функция аппаратного прерывания выглядит так:
attachInterrupt(№прерывания, действие, условие);
№прерывания – это номер кандейки.
Действие – условное название того, что будем делать (в кандейке)
Условие – это тот тайный знак, при котором надо все бросать и бежать.
Условий всего 4
LOW – когда на пине 1
CHANGE – когда сигнал меняется с 0 на 1 и наоборот.
RISING – когда сигнал изменяется строго с 0 на 1.
FALLING – когда сигнал изменяется строго с 1 на 0.
Я специально использовал 0 и 1, так как искренне считаю, что многим, здесь присутствующим, это будет понятней.
Замените 0 на LOW , а 1 на HIGH и получите классическое описание.
Займемся усовершенствованием нашего прорабского калькулятора и прикрутим к нему клавиатуру. Состоять она будет из двух кнопок, которыми мы будем выставлять актуальный этаж.
Условно представим, что наша программа ну очень большая и полетные вычисления — это только маленькая ее часть. Поэтому на выполнение цикла уходит значительное время, а нажатие на кнопку ну очень короткое. Этажей то у нас 50, а время на ввод значения одной кнопкой гораздо меньше секунды. В наших супер возможностях я не сомневаюсь, а вот контроллер может и пропустить какое ни будь нажатие, т.к. за время 1-го цикла их штуки три может произойти. Вот тут-то нам без прерываний не обойтись.
Приступим.
Открываем для редактирования наш блок «Прораб V1», переименовываем его и удаляем вход Etazh, а вместо входа декларируем переменную Etazh и присваиваем ей значение по умолчанию 0. В принципе ноль то можно и не присваивать. При старте он и так там будет, но если стартовое значение должно отличаться от ноля, то это можно сделать подобным образом.
Int Etazh = 0;
.
- 1.jpg (59.15 КБ) 2751 просмотр
.
Еще нам потребуется визуальный контроль набранного с клавиатуры значения этажа.
Для этого добавим выход Е и приравняем его значение к переменной Etazh
Вот так:
E = Etazh;
Теперь нам не придется считать в уме количество нажатий. Мы сможем видеть результат нажатий на дисплее.
Основной код теперь выглядит так:
if(Etazh == 0) {h = 0;}
if(Etazh == 1) {h = h0;}
if((Etazh > 1) && (Etazh < 3)) {h = h0 + h1;}
if(Etazh >= 3) {h = h0 + h1 + ((Etazh - 2) * h2);}
if(Etazh < 0) {t = 10800;} else {t = sqrt(2 * h / 9.8);}
E = Etazh;
Как видите, к исходному варианту добавилась всего одна, маленькая строчка. Больше ничего мы здесь изменять не будем.
Теперь создаем наши прерывания. Кнопку «+» мы прикрутим ко второй, а «-» к третьей ноге нашего бешеного, считающего таракана с гордым именем Atmega328. А ноги эти привяжем подтяжкой к плюсу (VCC), дабы он ими не дрыгал. И если кнопки, подключенные к земле, не нажаты, то на входах будем иметь «1», а при нажатии «0». Это и есть условие FALLING.
Подтяжку к питанию можно сделать как внешним сопротивлением (физически), так и внутренним (программно).
Давайте сделаем это программно. Для этого в SetupSection пропишем режимы работы пинов:
pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
Сразу оговорюсь, внутренняя подтяжка в некоторых схемах не всегда адекватно работает, особенно на прерываниях.
При конфигурации входа как pinMode(2, INPUT); пин будет условно подтянут к земле.
Возвращаясь к функциям, вспомним что они что-то возвращают, но так не всегда. Некоторые функции сами по себе ничего не возвращают. Шурупят там у себя, совершают какие-то вычисления, за чем-то следят, отдают команды, имеют внутри себя другие функции. К таким функциям относится и attachInterrupt();
Записывается эта функция в SetupSection:
attachInterrupt(0, FunсtionPLUS, FALLING);
attachInterrupt(1, FunсtionMINUS, FALLING);
Где FunсtionPLUS – имя действия которое свершится в кандейке по команде FALLING от товарища №0 (пин 2).
Аналогично и с FunсtionMINUS
.
.
Остается только найти эту кандейку. Все просто, методом исключения, находим в редакторе блоков ту единственную вкладку, которую мы еще не рассмотрели под названием FunсtionSection.
В ней то мы и создадим наши личные функции с именами FunсtionPLUS и FunсtionMINUS.
Кликаем в секции FunсtionSection на плюсик и в открывшемся окне вводим:
void FunсtionPLUS()
Почему так?
Про вильку и тарельку помните? Ну вот…
Лингвистические особенности языка разбирать не будем.
Хотя для меня самого до сих пор загадка почему разделы скетча назвали пустотой – void.
Может МЭТРЫ нам подскажут или у кого версии есть. Высказывайтесь. Лишнее потом модераторы подчистят. Думаю, им самим будет интересно. Только без пошлости господа.
Так, теперь в окне тела функции пишем то, что должна делать наша функция.
А должна она инкрементировать (увеличивать на единицу) нашу переменную.
Etazh++;
Подобным образом поступаем с FunсtionMINUS. Только в ней нашу переменную мы будем декрементировать (уменьшать на единицу):
Etazh--;
.
.
С функциями разобрались, со входами выходами тоже. Вроде бы все.
Остался один малюсенький, но очень важный момент. Дело в том, что переменные используемые основным кодом программы, как крепостные в поместье основного кода. И подчиняются они только основному коду и смогут изменить свое значение только по команде этого кода и никакая сила на стороне (вне основного кода) не изменит их значение. Что же делать? На этот случай помещики и придумали вольную для крестьян. Вот и мы давайте дадим вольную нашей переменной Etazh.
А в паспорте ей практически так и запишем:
volatile int Etazh = 0;
Теперь ее сущность смогут изменить даже в кандейке. (Ну о чем я говорю, вы и сами все прекрасно понимаете
)
Следовало сразу это учесть при создании переменной, но я умышленно не сделал этого, дабы обратить ваше внимание на сей факт.
На этом все. Наш блок готов. Не забываем сохранить. И можно пользоваться.
.
- 4.jpg (12.94 КБ) 2751 просмотр
.
Dryundel©
Кто увидит прораба. передавайте привет, и долгих лет жизни ему.
.