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





ГЛАВА 8
Программирование таймеров
С таймерами, одними из важнейших компонентов микроконтроллеров, мы уже в общих чертах познакомились в главе 3. Из главы 5 мы узнали, как реализовать простые задержки с помощью таймера и без него. В этой главе мы резюмируем полученную информацию и познакомимся с некоторыми более сложными функциями, которые позволяют осуществлять таймеры.

8- и 16-разрядные таймеры
Таймер в МК— это, по сути дела, двоичный счетчик. 8-разрядный таймер может считать от 0 до 255, а 16-разрядный — от 0 до 65 535. Результат счета можно прочесть в любой момент (в том числе, и не прекращая работу таймера) из счетного регистра, носящего общее наименование tcntx, где х -— номер таймера (для 8-разрядных это номера 0 и 2, для 16-разрядных— нечетные 1, 3 и т. д.). В 16-разрядных таймерах счетный регистр состоит из двух 8-разрядных регистров с общим наименованием tcntxh (старший) и tcntxl (младший). В счетные регистры также в любой момент можно записывать любое значение, что позволяет начинать счет не с нуля и регулировать интервалы счета. При чтении регистров 16-разрядных таймеров их содержимое может измениться в промежутке между чтением отдельных 8-разрядных "половинок". Например, если содержимое младшего байта составляет $FF, то мы прочтем именно это значение, но до выполнения команды на чтение старшего байта общее состояние таймера может стать на единицу больше, а младший байт в это время обнулится. В результате при реальном числе, записанном в счетных регистрах, равном $0100, мы прочтем $01FF, что, конечно, далеко от действительности. Аналогичная история может произойти и при записи некоего числа в таймер. Во избежание таких ситуаций в 16-разрядных таймерах AVR предусмотрен специальный механизм, который требует некоторой внимательности от программиста.

Механизм этот следующий. При записи первым загружается значение старшего байта, которое автоматически помещается в некий (недоступный для программиста) буферный регистр. Затем, когда поступает команда на запись младшего байта, оба значения объединяются и запись производится одновременно в обе "половинки" 16-разрядного регистра. Наоборот, при чтении первым должен быть прочитан младший байт, при этом значение старшего автоматически фиксируется помещением в тот же буферный регистр, и при следующей операции чтения старшего байта его значение извлекается оттуда. Таким образом, и при чтении значения байтов соответствуют одному и тому же моменту времени.

Повторим: для того чтобы манипуляции со счетными регистрами были успешными, при чтении необходимо сначала прочесть младший байт TCNTXL, потом старший TCNTXH, при записи сиачача записать старший байт TCNTXH, потом младший TCNTXL. Аналогичное правило справедливо для всех 16-разрядных регистров 16-разрядных таймеров, которые мы будем разбирать далее, с двумя исключениями — во-первых, оно не действует на регистры управления (TCCRXA И TCCRXB, которые по сути есть два раздельных регистра, а не один 16-разрядный), а во-вторых, не работает при операции чтения (но не записи!) из регистров сравнения OCRXBH И OCRXBL, которые можно читать в произвольном порядке (хотя сама по себе такая операция требуется крайне редко).

Неправильный порядок чтения либо записи может привести к непредсказуемым результатам: например, если прочесть младший байт TCNTXL последним, то в этот момент буферизуется старший TCNTXH И так и останется в буфере. И при следующем чтении в том же порядке, когда бы оно не производилось, сначала будет прочитано это значение, которое, естественно, никак не соответствует прочитанному далее значению младшего регистра.

Формально говоря, при чтении содержимого этих регистров также должны быть запрещены прерывания, но на практике, если соблюдается правильный порядок чтения, то "вклинившаяся" процедура прерывания лишь приведет к небольшой отсрочке получения результата. Единственное исключение составляет случай, если в самом прерывании также происходит обращение к любому из 16-разрядных регистров таймера, изменяющее буфер (для всех регистров он один и тот же) — тогда на время, чтения или записи такие прерывания следует запрещать.
При запуске таймеров в работу следует также учитывать, что, несмотря на формальную установку в ноль всех РВВ при включении питания, для получения точного первого отсчета, как показывает практика, регистры TCNTX еле дует принудительно обнулить перед запуском таймера в работу. Например, для 16-разрядного Timerl эта процедура выглядит так:
clr temp
out TCNTlH,temp ;не забываем про порядок записи out TCNT1L,temp

Если далее используется прерывание по переполнению (или с обнулением счетчика по достижении заданного числа), то в принципе каждый раз обнулять таймер необязательно. Но при этом следует учесть, что вовремя не остановленный таймер продолжает считать (в том числе и в течение времени, необходимого для его остановки). Потому при точном измерении интервалов времени между событиями необходимо остановить таймер, очистить его счетные регистры и по наступлению нужного начального события запустить "в работу"заново.
При необходимости следует также очищать предделитель таймеров— иначе может возникать ошибка в пределах одного периода заданной частоты на входе таймера (например, при коэффициенте 1/8 может появиться ошибка в пределах 8 периодов тактовой частоты). Очистка осуществляется записью логической единицы в биты PSRX регистра SFIOR (Х здесь означает используемые таймеры — значение "10" относится к Timerl и TimerO, значение "2" — к Timer2, который может работать отдельно от первых двух и т. д.). Заметим, что останавливать таймеры можно не только очисткой соответствующих бит регистра управления (см. далее), но и остановкой предделителя — при этом прекратят счет все таймеры, которые в данный момент работают от предделителя. Для остановки нужно записать логическую единицу в бит тэмтого же регистра SFIOR, для запуска— в этот бит записывается логический нуль. Таким способом таймеры можно синхронизировать.



     
 

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