Пятница, 23 сентября 2011 04:44

Программные таймеры Featured

Written by
Rate this item
(0 votes)

 

Программные таймеры. Что это, и с чем их "едят"

Что такое программный таймер? Это таймер-счётчик, основой которого является системный таймер. Т.е., другими словами, это обычная переменная, считающая переполнения системного таймера. Программному таймеру, как минимум, нужен ещё один бит-флаг, управляющий(указывающий) состоянием(на состояние) таймера.

 

 


Давайте разберём это на примере.
Что нам нужно ? Нам нужно создать переменную, которая будет счётчиком ,и флаг состояния таймера.
Можно объявить 2 переменных. Одна будет счётчик(например unsigned int), другая - типа bit. Но мы пойдём немного другим путём. Мы будем использовать старший бит переменной как бит состояния. Т.е. знак переменной у нас будет состоянием таймера. Но, тут есть один минус. Разрешение нашего таймера сократиться ровно в 2 раза, т.к. один бит будет занят. Т.е., если переменная = 2 байтам, то считать мы сможем только до 32767.

Создаём 2-х байтную знаковую переменную. Именно знаковую, т.к. знак у нас - состояние таймера.

 

  signed int volatile cnt;

Далее, нам необходимо создать обработчик прерываний от любого, имеющегося на "борту" МК, таймера.
Возьмём за основу 1-й таймер. Тактовая частота МК = 20Мгц. Таймер настраиваем на 1 мс.

Возьмём за основу 1-й таймер. Тактовая частота МК = 20Мгц. Таймер настраиваем на 1 мс.

  void interrupt _isr(void){
if(TMR1IF){      // Если событие от таймера
TMR1IF=0;           // Сбрасываем флаг события
TMR1-=5000;       // Переустанавливаем таймер на 5000 тактов (при 20Мгц - 1мс.).
}
}

Системные тики имеем. Теперь нам нужно их считать, т.е. сделать обработчик нашего программного таймера.
Сделаем проверку флага состояния, и, если таймер запущен, уменьшим счётчик на единицу.
Добавляем в ОП системного таймера такой код

  if(cnt < 0)     // Если таймер запущен
cnt++;             // Уменьшаем его счётчик на единицу.

Проверяем переменную на отрицательность (старший бит переменной). Тем самым, мы проверяем состояние таймера, и, если переменная отрицательна(<0) - уменьшаем счётчик таймера на еденицу.
Увеличение, как Вы заметили, переменной cnt - не ошибка. Счётчик у нас будет считать от -n до 0. Где n-это устанавливаемое значение таймера. Поэтому мы делаем инкремент переменной(это и есть уменьшение счётчика таймера на единицу).
Программный таймер и его обработка созданы. Осталось всё это применить на деле.
В процедуре main() инициализируем системный таймер(TMR1) и разрешаем прерывания.

  TMR1ON=1;         // Включить TMR1
TMR1IF=0;          // Сбросить флаг от TMR1
TMR1IE=1;          // Разрешить прерывания от TMR1
TMR1=-5000;      // Установить TMR1 на 5000 тактов/

PEIE=1;                // Разрешаем прерывания от перефирии
GIE=1;                 // и глобально

Далее зацикливаем программу

  while(1){              // Бесконечный цикл

}

В этом цикле установим программный таймер на 500 тиков и будем ждать окончания его счёта. По окончанию счёта, проинвертируем один из ПИНов порта.

  while(1){              // Бесконечный цикл
cnt = -500;          // Установка таймера на 500 тиков
while(cnt< 0)        // Ждём отсчёта таймера, т.б. когда он не будет < 0
continue;              //
RB0=!RB0;           // Инверсия RB0
}

И у нас получится мигалка с частотой в 1Гц
Скачать пример (49,56К)

Естественно, для мигания светодиода зацикливать программу, в ожидании окончания отсчёта таймера, глупо. Но мы можем не зацикливать программу, а просто проверять флаг состояния и мигать светодиодом. А программа, после проверки флага будет продолжать работать дальше.
Например, установим таймер, будем его проверять и продолжать выполнять программу дальше. Если проверка прошла, перезапустим таймер заново и проинвертируем пин светодиода.

  cnt = -500;                // Предустановка таймера на 500 тиков
while(1){                    // Бесконечный цикл
if(cnt >= 0){          // Если таймер отсчитал, т.е. значение счётчика не отрицательное
cnt = -500;       // Устанавливаем таймер заново на 500 тиков
RB0 = !RB0;      // и проинвертируем RB0
}
/*** Тут программа продолжает работу ****/
NOP();
NOP();
NOP();

/****************************************/
}


В итоге, результат получился как и в предыдущем примере, но программа не зациклена, она продолжает свою работу. А LED инвертируется, только когда отсчитает таймер. В том и прелесть программных таймеров, что они считают "в фоне", а проверяем их только по необходимости.
Скачать пример (48,97К)

Для справочки, кусочек дизасма:

  40: if(cnt>=0){          // Если таймер отсчитал, т.е. значение счётчика не отрицательное
033    1BA1 BTFSC  0x21, 0x7
034    283B GOTO  0x3b
41: cnt = -500;         // Устанавливаем таймер заново на 500 тиков
035    300C MOVLW 0xc
036    00A0 MOVWF 0x20
037    30FE MOVLW 0xfe
038    00A1 MOVWF 0x21
42: RB0=!RB0;       // и проинвертируем RB0
039    3001 MOVLW 0x1
03A    0686 XORWF 0x6, F

Заметьте, компилятор не делает никаких ужасных вычислений, он просто проверяет старший бит переменной.

 

  Используемый софт для примеров:
Компилятор HI-TECH PICC
Среда разработки MPlab
Отладчик Proteus

Обсуждение статьи тут

Read 3261 times Last modified on Среда, 03 сентября 2014 14:46

Все права принадлежат ChipMK.ru. При копировании материала ссылка обязательна. 2011-2017 © ChipMK.ru

ChipMk.ru Яндекс.Метрика
PRCY.ru