По просьбам трудящихся, сделаем попытку разобраться с режимом захвата таймера.
ICP_logo
Довольно часто возникают вопросы, которые можно объединить в одну группу, ибо суть задачи сводится к необходимости измерения длительности импульса. Для решения подобных задач можно воспользоваться режимом захвата таймера. Для этого у микроконтроллера есть ножка с названием ICPn. Например, у atmega8 это ножка PB0.
ICP1_mega

Настраиваем таймер1 для использования прерывания, по захвату таймера
ICP1_mega2

Теперь пару слов, о том как работает эта функция. Помните как работает внешнее прерывание? Здесь нечто похожее. Включили микроконтроллер, настроили таймер, запустили его, таймер тикает. При изменении состояния ножки (при нарастании сигнала), текущее значение таймера (то сколько он оттикал), копируется в регистр ICR1. Это значение хранится до возникновения следующего изменения на ножке ICPn.

Особенно удобно, при этом использовать прерывание. Допустим, при первом прерывании, считываем сколько таймер оттикал, при втором прерывании записываем второе значение. Разница между первым и вторым значениями будет длительностью импульса.

Попробуем проверить, как это будет работать в протеусе. Используем настройки, как указанные выше, таймер1 работающий на частоте 125кГц, т.е. один тик длится 1/125 000 = 0,000008 сек.

#include <mega8.h>
long x=0,y=0,z=0;
 
interrupt [TIM1_CAPT] void timer1_capt_isr(void)
{
  if(x==0) //в первый заход считываем таймер в переменную х
  {
     x=ICR1;
  }
  else   //во второй заход считываем в y, находим разницу
  {
     y=ICR1;   
     z=y-x;
     #asm("cli")
  }
}
 
void main(void)
{
PORTB=0x01;
DDRB=0x00;
 
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Normal top=0xFFFF
// Input Capture on Rising Edge
// Input Capture Interrupt: On
TCCR1A=0x00;
TCCR1B=0x43;
TCNT1=0x00;
ICR1=0x00;
 
TIMSK=0x20;
#asm("sei")
 
while (1)
      {
      }
}

Для проверки подключим к ножке генератор на 1кГц, т.е. время одного периода 1/1000 = 0,001с. Первый заход, не считаем, а вот второй произошел, когда таймер сделал 27 тиков.
ICP1_mega3

Следующий заход в прерывание произошел, когда таймер натикал 152.
ICP1_mega4

Разница между прерываниями составила 125 тиков. Как выше уже было сказано, на 125кГц один тик длится 0,000008с. Таким образом, период сигнала составляет 125*0,000008=0,001с, что вполне соответствует 1кГц.

Для желающих лично ознакомиться схема в протеусе и прошивка

21 комментарий: Режим захвата таймера

  • Не, не пойдет такое измерение. Так мы только измерим ПЕРИОД (время импульса + время паузы) Там какой-то другой смысл заложен. Измерить именно время импульса или паузы. У Вас в протеусе выставлено 50% заполнение. Должны получить число в два раза меньше. Вот если при первом импульсе перенастроить срабатывание по спадающему фронту тогда да.

  • Здравствуйте. Подскажите пожалуйста как решить проблему: пишу под мегу64, нужно измерить период импульсов с помощью захвата таймера3 и столкнулся с проблемой что у третьего счетчика нет суммарного ICR3, а только ICR3L и ICR3H отсюда проблема как их объединить в одно целое.
    Ps таймер1 уже занят.

  • К ICR3 можно обращаться как к 16 битному

  • Ну кодвижн на вот это:

    interrupt [TIM3_CAPT] void timer3_capt_isr(void)
    {
    // Place your code here
    if (b=0) {
    b = ICR3;
    }
    else {
    Tv = ICR3 — b;
    v = 6/10*Tv;
    };

    }

    заявил это:

    Error: dash1mega.c(152): undefined symbol ‘ICR3′
    Error: dash1mega.c(155): undefined symbol ‘ICR3′

    Я почитал файл header там действительно нет ICR3, я попробовал в header дописать ICR3 по аналогии с ICR1

    sfrb ICR1L=0x26;
    sfrb ICR1H=0x27;
    sfrw ICR1=0x26; // 16 bit access
    sfrb ICR3L=0x80;
    sfrb ICR3H=0x81;
    sfrw ICR3=0x80; // 16 bit access

    на что код вижн выдал что SFR может быть от 0х00 до 0x3f.

    В итоге либо я чет не допонимаю либо надо ICR3H и ICR3L собрать в одну переменную что потом работать с ней

  • Лучше всего посмотреть в даташите про ICR3. Есть такой вариант записи 16 битного числа в регистры:
    OCR1AH = (char)(Bit>>8); //старший байт
    OCR1AL = (char)Bit; //младший байт

  • В общем изучение даташита дало вот что … это статья ровно тоже самое что и в даташите, но на русском, только как это реализовать в конкретно моем случаем у меня не хватает знаний.

  • Я вам привел решение на Си, чем оно не нравится?

  • Ну как я понял вы привели пример ЗАПИСИ числа В регистр, а мне нужно 2 числа ИЗ регистров H и L СЧИТАТЬ, объединить вместе и записать в переменную и далее с помощью этой переменной вычислить период импульсов как в вашей статье. Если я что то понял не так из вашего сообщения или не понятно описал свою проблему извините.

  • int result;
    char y = ICR3H;
    char x = ICR3L;
    result = (y << 8) + x;

  • Спасибо огромнейшее))) еще раз извините что сразу точно не описал задачу

  • Доброго времени суток.Подскажите пожалуйста как измерить разность фаз(частота низкая всего 50 Гц хочу померить косинус фи в сети) на атмеге или может направте на какую нибудь статью(лучше чтобы она была ваша, вы очень доступно объясняете)….заранее спасибо

  • начните с этого http://avr-start.ru/?p=4500

  • Спасибо за урок.
    Но значение «125» вычислялось только при ПЕРВОМ проходе программы.
    Я добавил в код ОДНУ строчку и теперь «125» вычисляется ПОСТОЯННО.
    Вот код:

    // Timer1 input capture interrupt service routine
    interrupt [TIM1_CAPT] void timer1_capt_isr(void)
    {
    if(x==0)
    {
    x=ICR1;
    }
    else
    {
    y=ICR1;
    z=y-x;
    x=y;
    #asm(«cli»)
    }
    }

  • Намекните, пожалуйста костяк для решения такой задачи:
    Мы даём запрос некому устройству (это я умею сделать) и слушаем ответ.
    Если ответ верный, то зажигаем зелёный светодиод. Если ответ не верный, то зажигаем красный светодиод.
    А ответ — примитивный. Это, к примеру пять единичных импульсов длительностью по 2 милисекунды каждый и паузами между этими импульсами от 4 до 8 милисекунд. Таких единичных импульсов должно поступить пять штук. Если пришло меньше или не пришло — то красный светодиод.
    Получить и оценить длительность одного импульса Вы уже меня научили, спасибо.
    Теперь прошу научить видеть «1» или «0» и складывать их в КОД, для сопоставления еталонного и полученного кода. Спасибо.

  • Конкретно в данном случае, если все как вы описали, лучше захват не использовать, можно просто по прерываниям на ноге смотреть, сколько оттикал таймер. Идею посмотреть тут http://avr-start.ru/?p=3516

  • Добрый вечер!Помогите пожалуйста если таймер настроен на захват как он будет относится к прерыванию INTO? Когда сработало прерывание на ножке INT0 ножка захвата не работает ?
    Я думал что таймер сам по себе тикает.

  • Не понятен вопрос, в статье вроде написано, время считается от прерывания до прерывания

  • Делаю ДУ на ИФК на ножке захвата стоит TSOP при срабатывании прерывания INT1 контроллер уже не видит пульт.Как совместить грамотно два внешних прерывания?

  • если вы хотите считать длительность импульса, то так не получится, т.к. прерывание срабатывает по восходящему фронту, т.е. это годится только для подсчета периода. точно знаю что у стм32 можно настроить срабатывание по обоим фронтам.

  • Добрый день.По отдельности у меня всё работает прерывание и захват таймера ,а вот вместе не хотят.Можно код выложить здесь.

  • честно так и не понял, как вы их хотите совместить, возьмите код из статьи про инфракрасник и не мучайтесь.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Свежие записи
Последние комментарии
  • Загрузка...
Счетчик
Яндекс.Метрика