Форум по микроконтроллерам: Программные таймеры - Форум по микроконтроллерам

Перейти к содержимому

Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

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

#1 Пользователь офлайн   Alex 

  • Убиватель МК
  • PipPipPipPip
  • Группа: Пользователи
  • Сообщений: 1 891
  • Регистрация: 15 Февраль 11

Отправлено 23 Сентябрь 2011 - 10:20

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

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

Далее, нам необходимо создать обработчик прерываний от любого, имеющегося на "борту" МК, таймера.
Возьмём за основу 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Гц :)
Прикрепленный файл  timers_1.rar (49,56К)
Количество загрузок:: 259

Естественно, для мигания светодиода зацикливать программу, в ожидании окончания отсчёта таймера, глупо. Но мы можем не зацикливать программу, а просто проверять флаг состояния и мигать светодиодом. А программа, после проверки флага будет продолжать работат дальше.
Например, установим таймер, будем его проверять и продолжать выполнять программу дальше. Если проверка прошла, перезапустим таймер заного и проинвертируем ПИН светодиода.
cnt = -500;     // Предустановка таймера на 500 тиков
while(1){       // Безконечный цикл

    if(cnt>=0){     // Если таймер отсчитал, т.е. значение счётчика не отрицательное
        cnt = -500;     // Устанавливаем таймер заного на 500 тиков
        RB0=!RB0;       // и проинвертируем RB0
    }

/*** Тут программа продолжает работу ****/
NOP();
NOP();
NOP();
/****************************************/
}
В итоге, результат получился как и в предыдущем примере, но программа не зациклина, она продолжает свою работу. А LED инвертируется только когда отсчитает таймер. В том и прелесть программных таймеров, что они считают "в фоне", а проверяем их и работаем с ними только по необходимости.
Прикрепленный файл  timers_2.rar (48,97К)
Количество загрузок:: 275

Для справочки, кусочек дизасма
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
43:                    }
Заметьте, компилятор не делает никаких ужасных вычислений, он просто проверяет старший бит переменной.

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

Не говорите что мне делать, и я не скажу куда Вам идти !
0

#2 Пользователь офлайн   golowa70 

  • Новичок
  • Pip
  • Группа: Пользователи
  • Сообщений: 41
  • Регистрация: 03 Январь 12

Отправлено 23 Декабрь 2013 - 18:12

Извините,не допонял на какое состояние счетчика должен указывать бит-флаг?
Почему нельзя просто увеличивать переменную в обработчке прерыванй,и там же сравнивать с нужным числом?

cnt++;
if (cnt >500){
cnt=0;
PORTB=!PORTB;
}
0

#3 Пользователь офлайн   Alex 

  • Убиватель МК
  • PipPipPipPip
  • Группа: Пользователи
  • Сообщений: 1 891
  • Регистрация: 15 Февраль 11

Отправлено 23 Декабрь 2013 - 19:01

Цитата

Почему нельзя просто увеличивать переменную в обработчке прерыванй,и там же сравнивать с нужным числом?
Кто сказал что нельзя ? Делайте как Вам удобно :)
Только таймер уже жёстко будет привязан к порту. Точнее, наверное, наоборот - порт к таймеру. И уже этот таймер Вы не сможете использовать для других целей.
Не говорите что мне делать, и я не скажу куда Вам идти !
0

#4 Пользователь офлайн   dosikus 

  • Завсегдатай
  • PipPipPip
  • Группа: Пользователи
  • Сообщений: 439
  • Регистрация: 15 Январь 13

Отправлено 04 Февраль 2015 - 18:26

Без заморочек со знаковыми :

В прерывании
  if(Timer){Timer--};


Установка и использование
Блокирующие
 Timer=500;
   While(Timer);

Не блокирующие
 If(!Timer)
    {
      Led=~Led;
      Timer=500;
    }

0

#5 Пользователь офлайн   Alex 

  • Убиватель МК
  • PipPipPipPip
  • Группа: Пользователи
  • Сообщений: 1 891
  • Регистрация: 15 Февраль 11

Отправлено 04 Февраль 2015 - 22:40

Неатомарно, при размерности таймера больше 1 байта.
Не говорите что мне делать, и я не скажу куда Вам идти !
0

#6 Пользователь офлайн   dosikus 

  • Завсегдатай
  • PipPipPip
  • Группа: Пользователи
  • Сообщений: 439
  • Регистрация: 15 Январь 13

Отправлено 05 Февраль 2015 - 12:03

О какой атомарности речь в твоем примере ? :crazy:
41:                        cnt = -500;     // Устанавливаем таймер заного на 500 тиков
   035    300C     MOVLW 0xc
   036    00A0     MOVWF 0x20
   037    30FE     MOVLW 0xfe
   038    00A1     MOVWF 0x21

0

#7 Пользователь офлайн   Alex 

  • Убиватель МК
  • PipPipPipPip
  • Группа: Пользователи
  • Сообщений: 1 891
  • Регистрация: 15 Февраль 11

Отправлено 05 Февраль 2015 - 15:03

А ты повнимательнее посмотри :)
1. Таймер запустится только если в старшем бите старшего байта появится 1-чка. Она появится вместе с установкой.
2. Проверка таймера в случае с 1 битом - тоже атомарна.

А теперь прикинь это всё к твоему примеру. В особенности проверку переменной на ноль :)
Не говорите что мне делать, и я не скажу куда Вам идти !
0

Поделиться темой:


Страница 1 из 1
  • Вы не можете создать новую тему
  • Вы не можете ответить в тему

1 человек читают эту тему
0 пользователей, 1 гостей, 0 скрытых пользователей