Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





Использование прерываний
Теперь давайте попробуем сделать ту же самую программу "по-человечески", а именно с использованием прерываний. Обычно контроллер не только следит за кнопками, а еще делает разные другие полезные операции, поэтому нехорошо будет занимать все его время пустыми циклами в ожидании, когда, наконец, кто-то соизволит нажать на кнопку.
Хотя, отметим, пустые циклы, в которых МК больше ничего не делает, кроме отслеживания подобных крайне редких, с его точки зрения, событий (даже за время ожидания пересылки байта через UART, занимающее при скорости 9600 бит/с около одной миллисекунды, контроллер успеет выполнить несколько тысяч команд), как раз представляют собой наименьшее зло, т. к. легко могут быть прерваны на время выполнения других процедур без опасности что-то потерять. Но в общем случае лучше, если мы будем стараться по возможности освободить контроллер от бесцельного зацикливания в ожидании событий: например, иначе невозможно задействовать режимы энергосбережения, о которых пойдет речь в главе 14.

Итак, вернемся к схеме и обратим внимание, что кнопка Кн1 у нас подсоединена к контакту PD2, который, если вы взглянете в описание модели 2313, одновременно служит входом внешнего прерывания INTO. Таким образом, у нас вырисовывается следующая схема действий: сначала мы инициируем прерывание INTO по спаду на этом уровне и, определив таким образом, что кнопка была нажата, временно запрещаем вообще всякие прерывания по выводу INTO, чтобы отфильтровать дребезг при нажатии. Затем опять разрешаем прерывание INTO, но уже по фронту, определяем момент отпускания, производим нужные манипуляции со счетчиком и снова запрещаем прерывания на некоторое время, после чего вновь разрешаем прерывания по спаду, и все повторяется сначала.

Задержка по таймеру
Как и ранее, начнем с того, как нам грамотно организовать задержку. Конечно, можно, как и ранее, запускать пустой цикл в процедуре обработки прерывания. Но некрасиво занимать "машинное время" пустыми задержками: если в течение этого интервала времени прерывания запрещены, то контроллер вообще на время "умрет" для внешнего мира, а если их разрешить, то длительность задержки может оказаться неопределенной. Потому давайте попробуем сделать все, как надо, для чего используем прерывание таймера.
В модели 2313 два таймера: 8- и 16-разрядный, второй удобнее для отсчета длительных интервалов времени. Но мы для простоты выберем 8-разрядный TimerO, что будет универсальным решением абсолютно для всех моделей, даже тех (как Tiny 12), которые 16-разрядного таймера не имеют. Интервал времени мы будем отсчитывать по переполнению этого таймера, которое наступает каждые 256 импульсов счета. Если мы станем считать эти события с помощью одного регистра, то таких событий можем также насчитать максимум 256. Тогда максимальный интервал времени, который мы сможем получить, определится по формуле: 256-256/Гс, где Тс— частота импульсов на входе таймера в герцах, определяемая предделителем в долях от тактовой. Если мы хотим задавать интервалы порядка 1 с, то эта частота должна быть около 65 кГц; таким образом, при тактовой частоте МК 4 МГц коэффициент деления может составить 64 (точная частота на входе таймера — 62 500, максимальный отмеряемый интервал при указанных условиях составит 1,05 с). Задавать интервал мы сможем долями по 1/256 от указанного максимального (задавая значение счетного регистра), т. е. приращениями приблизительно по 4 мс (сами прерывания будут происходить с частотой около 244 Гц).

Опустим пока все необходимые установки для таймера и прерываний и посмотрим, как будет выглядеть такая процедура отсчета интервала времени по-прерыванию переполнения TimerO. Регистр для отсчета прерываний назовем counttime и допустим, что нам требуется отмерить примерно 0,5 с (т. е. интервал должен включать 128 циклов переполнения таймера). Сначала где-то в счетный регистр загружаем нужное число командой ldi counttime, 128 и там же запускаем таймер. Обработчик прерывания таймера может выглядеть так, как показано в листинге 5.12.

Листинг 5.12
TIMO: ;TimerO overflow
dec Count_time ;
в каждом прерывании уменьшаем на 1 breq end_timer ;если ноль, то на конец отсчета reti ;иначе выход из прерывания
end_timer:
<производим необходимые действия и останавливаем таймер>
reti

Заметим, что если и в самом первом цикле требуется очень точно отмерить интервал времени, то предварительно необходимо обнулить счетный регистр таймера (TCNTO). При еще более точных отсчетах обнулять счетный регистр следует всегда, непосредственно перед его запуском, т. к. остановка таймера требует определенного количества операций, за время которых таймер продолжает считать. Если точных интервалов не требуется, то выполнять такие действия необязательно— так, в данном случае неопределенность единственный раз в начале работы может привести к ошибке максимум в 1/128 часть от интервала 0,5 с.



     
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru