AVR: настройка таймера счетчика

В микроконтроллерах avr есть такой периферийный модуль как таймер счетчик. В соответствии со своим названием он считает время. У таймер счетчика есть регистр TCNT из которого можно прочитать сколько времени прошло с момента запуска таймера. Значение в этом регистре не в минутах или секундах, а в ‘попугаях’ — ‘тиках’ таймера. Чему равен один тик — зависит от тактовой частоты, на которой работает микроконтроллер avr, и от настроек таймера.

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

Например:
Тактовая частота = 11059200 Гц (  11.0592 МГц  )
Делитель = 1024
Частота таймера счетчика = Тактовая частота/Делитель =  11059200/1024 = 10800 Гц
Длительность периода( тика ) =  1/10800 = 92.593*10^-6 секунды = 92.593 мкс

Для настройки делителя используются биты CS  регистра TCCR.

Например для таймера 1 в atmega8 используются регистр TCCR1B  и биты CS10, CS11, CS12.

Зависимость делителя от состояния бит CS для таймера 1 в atmega8

CS12 CS11 CS10 Делитель
0 0 0 0
0 0 1 1
0 1 0 8
0 1 1 64
1 0 0 256
1 0 1 1024

Пример кода настройки делителя для таймера 1 avr atmega8:

TCCR1B = (1<<CS12)|(0<<CS11)|(1<<CS10); //xtall/1024

В avr таймеры могут быть 8 или 16 разрядными. Разрядность определяет максимальное количество тиков которые может сосчитать таймер. Для 8 разрядного это 256 тиков, для 16 это 65536.

В нашем случае один тик равен 92.593 мкс, соответственно максимальное значение, которое может измерить 16 битный таймер, это 65536*92.593*10^-6 = 6.068 секунды,  8-ми битный —  0.0237 секунды.

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

Пример кода для разрешения прерываний таймера 1 avr atmega8:

TIMSK |= (1<<TOIE1);  // разрешить прерывание по переполнению таймера счетчика
sei();                // выставить бит общего разрешения прерываний

Так же надо определить обработчик данного прерывания — функцию которая будет вызвана при переполнении таймера.

Добавим в эту функцию код изменяющий состояние ножки PB0, к которой подключен светодиод.

Пример кода функции обработчика прерывания для таймера 1 avr atmega8:

ISR( TIMER1_OVF_vect )
{
  if( PINB & ( 1 << PB0 ) ) {
    PORTB &= ~( 1 << PB0 );
  }
  else {
    PORTB |= ( 1 << PB0 );
  }
}

Светодиод будет изменять свое состояние через каждые 6 секунд.

Чтобы светодиод менял свое состояние с частотой 10Гц, надо чтобы таймер отсчитывал не 65536 тиков а меньше. Рассчитаем необходимое число тиков:

10800/10 = 1080

Чтобы таймер считал не с нуля а с некоторого значения, при инициализации  и при каждом срабатывании прерывания  в регистр TCNT1 будем записывать число (65536 — 1080) = 64456.

Листинг итоговой программы для таймера 1 avr atmega8:

#include <avr/io.h>
#include <avr/interrupt.h>
 
ISR( TIMER1_OVF_vect )
{
  TCNT1 = 64456; //выставляем начальное значение TCNT1
  if( PINB & ( 1 << PB0 ) ) {
    PORTB &= ~( 1 << PB0 );
  }
  else {
    PORTB |= ( 1 << PB0 );
  }
}
 
int main()
{
  DDRB = ( 1 << PB0 );  // настраиваем PB0 на выход
  TCCR1B = (1<<CS12)|(0<<CS11)|(1<<CS10); // настраиваем делитель
  TIMSK |= (1<<TOIE1); // разрешаем прерывание по переполнению таймера
  TCNT1 = 64456;        // выставляем начальное значение TCNT1
  sei();                // выставляем бит общего разрешения прерываний
  while(1);             // вечный цикл
  return 0;
}

Так же вы можете прочитать другие статьи из рубрики «Микроконтроллеры avr».

Архив с исходниками под avr-gcc (WinAvr) можно скачать тут.

P.S. Если Вам понравилась эта статья, или же наоборот, Вы считаете ее бесполезной, если у Вас есть какие-то вопросы или пожелания, пожалуйста, напишите комментарий.

Запись опубликована в рубрике Микроконтроллеры avr с метками , . Добавьте в закладки постоянную ссылку.

49 комментариев: AVR: настройка таймера счетчика

  1. Андрій говорит:

    Норма, все зрозуміло.

  2. Артём Двинин говорит:

    Андрій, радий, що допоміг =)

  3. Тагир говорит:

    Все понятно, полезная статья. Самое главное все работает сразу.

  4. Артём Двинин говорит:

    Тагир, пожалуйста!

  5. serge говорит:

    Полезная статья. Спасибо

  6. Артём Двинин говорит:

    Serge, спасибо за отзыв!

  7. Michael7 говорит:

    Есть неточность в настройке таймера счетчика, нужно еще настроить биты WGM в одном из регистров, плохо что тут это не расписано. Ищу информ-ию по этим битам. =\

  8. Артём Двинин говорит:

    биты WGM в основном используются для настройки ШИМ (PWM), а если надо таймер настроить на срабатывание через заданный промежуток времени, то эти биты не нужны, они по умолчанию выставлены в 0, что обеспечивает требуемый режим работы таймера.

  9. Игорь говорит:

    Очень хорошо описано!
    Большое спасибо — стало понятнее.

  10. Артём Двинин говорит:

    Игорь, пожалуйста! :)

  11. Артем Колесников говорит:

    Неплохая статья, но можно было бы (и скорее всего, необходимо) добавить про тактирование таймера, что он может тактироваться не только от микроконтроллера, но и из вне. Со всеми вытекающими обстоятельствами.
    То есть предложение:
    «Так же у таймера счетчика есть настраиваемый делитель частоты, который определяет на сколько будет поделена тактовая частота микроконтроллера перед тем как будет подана на таймер счетчик. » рассматривает только лишь частный случай работы таймера.

  12. Артём Двинин говорит:

    Спасибо за отзыв. Да Вы правы, надо будет дополнить статью, или может отдельную заметку написать.

  13. Александр говорит:

    Спасибо. Толково. Есть вопрос. Таймер стартует при включении МК. А как можно запускать и останавливать его вручную(при помощи кнопки например).

  14. Артём Двинин говорит:

    Пожалуйста :)
    Таймер стартует когда делитель частоты не равен нулю, соответственно, что бы остановить таймер надо выставить делитель частоты равным нулю, например, для таймера 1 atmega8 надо обнулить биты CS12, CS11, CS10

  15. Atabek говорит:

    здравствуйте. как получить сигнал от ИК приемника(38 КГц) его data подключен в PB0 у.
    не знаю как настроит таймеры .
    помогите пожалуйста.
    за ранние спасибо.

  16. Артём Двинин говорит:

    Доброго времени суток! А какой у Вас микроконтроллер?

  17. Dima говорит:

    Помогите пожалуйста . Сейчас разбираюсь с UART на avr studio4 (mega8)
    Хочу сделать программу , в которой через терминал мы вводим число , и светодиод мигает , ну например написал 10, значит мигать будет 10 раз в сек и тд.
    Помогите советом пожалуйста
    Заранее благодарен
    Вот мой код

     
    volatile static unsigned long timer;   //10ms
     
     
    volatile static unsigned long DeltaTik10ms=0;
    unsigned char c;
    volatile unsigned long tik10ms;
    volatile unsigned long tikalarm;   
    volatile unsigned long tikkey;  
    volatile unsigned long tikcycle;
    volatile unsigned long tik10ms;
    volatile unsigned long tikalarm;
    volatile unsigned char d=50;
    volatile unsigned char dd;
    unsigned long p=0;
     
    ISR( TIMER1_OVF_vect  )
    {
    TCNT1 = 65496;
    timer+=10;
    }
     
     
    ISR(USART_RXC_vect)
    {
    d=UDR;
     
    uart_putc(d);
     
    }
     
    inline void StartTime()
    {
      TCCR1B = (1<<CS12)|(0<<CS11)|(1<<CS10);   //1024
      TIMSK |= (1<<TOIE1); 
      TCNT1 = 65496;  
     
    }
    /*inline unsigned long GetDelta()
    {
    unsigned long l;
    cli();
    l = d;     
    sei();    
    return l;
    } */
    inline unsigned long GetTimeMS()
    {
    unsigned long p;
    cli();
    p = timer;     
    sei();    
    return p;
    } 
    inline void diod()
    {
    PORTB ^=( 1 << PB0 );
    }
     
    void uart_init( void )
    {
      //настройка скорости обмена
      UBRRH = 0;
      UBRRL = 1;
      //8 бит данных, 1 стоп бит, без контроля четности
      UCSRC = ( 1 << URSEL ) | ( 1 << UCSZ1 ) | ( 1 << UCSZ0 );
      //разрешить прием и передачу данных
      UCSRB = ( 1 << TXEN ) | ( 1 <<RXEN ) | (1<<RXCIE);
    }
     
    unsigned char uart_getc( void )
    {
     
       //ждем приема байта
       while( ( UCSRA & ( 1 << RXC ) ) == 0  );
       //считываем принятый байт
       return UDR;
    }
     
    void uart_putc( char c )
    {
      /*ждем окончания передачи предыдущего байта(для того чтобы 
      отправить следующий байи нужно проверить , был ли потправлен байт)*/
     
      while( ( UCSRA & ( 1 <=tikalarm)
    {
    tikalarm=tik10ms+d;
    diod();
    }
     
    }
     
      return 0;
    }
  18. Артём Двинин говорит:

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

  19. Константин говорит:

    Может кто-нибудь на ассемблере выложить настройку таймера и мигалку на светодиоде?

  20. Назар говорит:

    Добрый день!
    Нужна ваша помощь! Я не программист, начинаю с простого — с Ардуино (знаю, плохое начало, но так сложилось). Вот код

    LiquidCrystal lcd(14,15,16,17,18,19);
    unsigned long t_1 = 0; // переменная для хранения времении работы программы в мкс
    unsigned long t_2 = 0; // переменная для хранения времении работы программы в мкс
    unsigned int R = 4274; // сопротивление резистора заряда конденсатора в kОмах
    unsigned long T = 0.0; // время заряда конд. плюс входная емкость плюс время виполнения команд
    volatile float C = 0.0; // вычесленное значение емкости
     
    void setup() 
    {
    lcd.begin(16,2);    
    }
     
    void loop() 
    {  
           D8_Out; // назначаем D8 на выход 
           D8_Low; // на D8 устанавливаем 0  (минус конденсатора)
           D9_Out; // назначаем D9 на выход
           D9_Low;  // на D9 устанавливаем 0 (разряд конд. через резистор 100 Ом)
           delay(2000); // ждем пока розрядится конд.
           D9_In; // делаем D9 входом, что б не мишать измерениям
           delayMicroseconds(100); // небольшея пауза
           t_1 = micros(); // засекаем время t_1 
           if (analogComparator.waitComp(0)) // если на компараторе напражение више установленого...
            {
             t_2 = micros(); // засекаем время t_2
            }
          T = (t_2 - t_1); // время заряда конденсатора
          C = ((T - 24.0)/R*1000); // вычисление емкости в пф.
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("Capacitance: ");
       if (C = 1000) && (C = 1000000)
       {
          lcd.setCursor(0,1);
          lcd.print (C/1000000); // вывод значения емкости на экран
          lcd.print (" uF "); 
       }
    }

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

  21. Артём Двинин говорит:

    Назар, день добрый!
    Извините, что не сразу отвечаю, лето, отпуск… отдыхаю от компьютера :)
    Ардуино — нормальное начало, пока его возможностей хватает, почему-бы и не использовать, тем более что это проще чем писать на голом Си.
    Могу подсказать, как решить вашу задачу без библиотек от arduino, используя только ардуиновску плату.
    В качестве компилятора будет avr-gcc или WinAvr.
    Если Вам интересно — пишите, продолжим общение :)

    Кстати, а что это за устройство, которое Вы разрабатываете?

  22. Назар говорит:

    Здравствуйте, Артем! Спасибо за ответ!
    Я свою проблему решил, прибор — это измеритель емкости от 1пФ+-0,25 пФ до 1,5 мкФ+-2,5нФ. Все работает, но интересно было бы сделать все не на Arduino IDE.
    Вот мой код :

    //#include   // библиотека для работы с компаратором
    //#include    // библиотека для ускореной работы с портами
    //#include  // библиотека для LCD
    LiquidCrystal lcd(14,15,16,17,18,19); // инициализация LCD
    volatile unsigned int R = 1995; // резистор заряда конд. первого предела
    volatile unsigned int T = 0; // время заряда конд. плюс входная емкость плюс время виполнения команд
    volatile double C = 0.0; // вычесленное значение емкости
      void Timer1_Init( void )  // Timer/Counter 1 initialization
       {
        TCNT1 = 0;
        TCCR1A = 0; // Bits: COM1A1 COM1A0 COM1B1 COM1B0 - - WGM11 WGM10
        TCCR1B = 0; // Bits: ICNC1 ICES1 - WGM13 WGM12 CS12 CS11 CS10
        TCCR1C = 0; // Bits: FOC1A FOC1B - - - - - -
        TIMSK1 = 0; // Bits: - - ICIE1 - - OCIE1B OCIE1A TOIE1
        TIFR1 = 0;  // Bits: – – ICF1 – - OCF1B OCF1A TOV1
       }
    volatile double calib = 122.0; // значение Т без конденсатора (калибрация)
    void setup() 
    {
     lcd.begin(16,2); // вкл. LCD
     D8_Out; // назначаем D8 на выход 
     D8_Low; // на D8 устанавливаем 0  (минус конденсатора)
     D12_Out; // назначаем D12 на выход
     D12_High; // на D12 устанавливаем 1  (заряд конд. резистором первого предела)
     D1_Out; // назначаем D1 на выход
     D1_High; // на D1 устанавливаем 1  (заряд конд. резистором второго предела)
     cli(); // Global disable interrupts
     Timer1_Init(); // Timer/Counter 1 initialization
     TIMSK0 &= ~(1 << TOIE0);   //  Disable Timer 0.
     TIMSK2 &= ~(1 << TOIE2);   //  Disable Timer 2.
     sei(); // Global anable interrupts
     ADCSRA = 0; // Disable ADC
     PRR = B10010111; // Disable USART0, TWI, SPI
    }
     
    void loop() 
    {  
           D9_Out; // назначаем D9 на выход
           D9_Low;  // на D9 устанавливаем 0 (разряд конд. через резистор 100 Ом)
        for (int i=0; i<250; i++) // ждем пока разрядится конд. 1 cек
         {
           TCCR1B = (1<<CS10); // запускаем таймер Fxtal/1
           while( TCNT1 < 64000 ){}
           TCCR1B = 0; //останавливаем таймер
           TCNT1 = 0; // сброс счетчика
         }     
           D9_In; // делаем D9 входом, что б не мишать измерениям
           analogComparator.setOn(AIN0, AIN1); // компаратор вкл.
           TCCR1B = (1<<CS11); // запускаем таймер Fxtal/8
           while((((ACSR && (1<<ACO)) == 0))&&(TCNT1= 14001) // выбираем придел измерений
            {
              D1_Low;
              R = 20.0;
              calib = 6.0;
              lcd.print("Range 700nF");
              lcd.setCursor(0,1);
              lcd.print(C/1000);
              lcd.print("nF ");
             // lcd.print(T); 
            }
     
           if ( C <= 14000) // выбираем придел измерений
           {
              D1_High;
              R = 1995.0;
              calib = 122.0;
              lcd.print("Range 7nF");
              lcd.setCursor(0,1);
              lcd.print(C);
              lcd.print("pF ");
             // lcd.print(T);
            }      
    }

    Еще вопрос: как сделать что-бы значение таймера при переполнении продолжало увеличиваться, а не обнулялось и начиналось сначала? То есть, я хочу сделать таймер 32-х битным. Это для того, что-бы не делать отдельные пределы измерений, а просто увеличить время заряда конденсатора.
    Заранее спасибо!

    П.С. могу скинуть схемку, если интересно.

  23. Артём Двинин говорит:

    Доброго времени суток, Назар!
    Таймер в avr 16 битный, что бы получить 32 разряда можно настроить прерывание по переполнению, и в этом прерывании увеличивать программный счетчик, назовём его cnt.
    Тогда измеренное значение будет (cnt << 16) + TCNT1;

    Если есть желание работать без Arduino IDE, поставьте WinAvr. И двигайтесь по пути от простого к сложному, сначала помигайте светодиодом, потом подключите LCD, http://mainloop.ru/avr-atmega/lcd.html.
    затем освойте работу с компаратором.
    Будут вопросы — обращайтесь, постараюсь помочь.

    А схема конечно интересна, пришлите, пожалуйста!

    PS кстати, мне кажется, в этой строке ошибка:

    while((((ACSR &amp;&amp; (1&lt;&lt;ACO)) == 0))&amp;&amp;(TCNT1=14001)

    В этом цикле TCNT1 приравнивается 14001.
    А должно быть, скорее всего, сравнение (TCNT1==14001)

  24. Никита говорит:

    Здравствуйте, очень интересная и полезная статься, а можете подсказать как это сделать в microPascal for AVR?

  25. Антон говорит:

    Пытаюсь играться с таймером в меге8. Обнаружил что строчка TCNT0=128; в обработчике прерывания влияет на частоту, замедляет ее и она не соответствует расчетной. Без этой строчки фактическая частота замеренная тестером соответствует расчетной а со строчкой уже нет, даже если прописано TCNT0=0;. Собственно нужно чтобы тикало меньше чем 256 раз. В чем нюанс?

    interrupt [TIM0_OVF] void timer0_ovf_isr(void)
    { 
        TCNT0=128;
    ... 
    }
     
    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: 8000,000 kHz
    TCCR0=0x01;
    TCNT0=0x00;
  26. Артём говорит:

    Дело может быть в том, что у вас делитель = 1, т.е. таймер работает с частотой 8МГц. С этой же частотой выполняются и команды микроконтроллера (1 — 3 такта на команду). Получается, что если код обработчика прерываний выполняется более чем за 256 тактов, то частота будет уменьшаться. Попробуйте дизасемблировать прошивку и посмотреть какой код генерируется для обработчика прерывания.
    Чтобы получить частоту больше чем 8МГц/256 можно попробовать переписать обработчик на ассемблере или использовать таймер1 в режиме CTC (Clear Timer on Compare).

  27. Александр говорит:

    подскажите а обязательно значение в регистр OCR1A записывать в 16ричном формате? и обязательно ли записывать значение сначала в старший а потом младший, т.е. вот так:

    OCR1AH=0x03;//записываем в регистр OCR1A 1000
    OCR1AL=0xE8;

    или можно просто

    OCR1A=0x03E8;
  28. Артём Двинин говорит:

    Александр,
    Значение можно записывать в любом формате.
    Если записывать значения отдельно в старший и младший байт, то сначала обязательно надо записать старший байт.
    Но можно записывать и сразу два байта: OCR1A=0x03E8, в этом случае компилятор сам произведет запись в нужной последовательности.

  29. роман говорит:

    как настроить три таймера?

    TCCR0=(1&lt;&lt;0)|(1&lt;&lt;1); //Настраиваем предделитель
    TIMSK|=(1&lt;&lt;TOIE0);    // 
    //___________________________________________________TIMER1
    TCCR1B=(1&lt;&lt;CS12)|(0&lt;&lt;CS11)|(0&lt;&lt;CS10); //Настраиваем предделитель 256
    TIMSK|=(1&lt;&lt;TOIE1);    // 
    TCNT1 =0;
    //___________________________________________________TIMER2
    //TCCR2 =(1&lt;&lt;CS12)|(0&lt;&lt;CS11)|(1&lt;&lt;CS10); //Настраиваем предделитель 1024
    //TIMSK|=(1&lt;&lt;TOIE2);    //

    с таемером 2 всё как то неработает

  30. Артём Двинин говорит:

    Роман, здравствуйте.
    A что значит не работает?

    P.S.
    строку

     TCCR2 =(1<<CS12)|(0<<CS11)|(1<<CS10)

    лучше заменить на

    TCCR2 =(1<<CS22)|(0<<CS21)|(1<<CS20)
  31. Александр говорит:

    подскажите пожалуйста. В ATtiny2313a в настройках 16 битного таймера в регистре TCCR1A есть такие биты: COMnA1:0 , COMnB1:0, COMnC1:0. Из даташита вычитал, что при совпадении с регистром сравнения (в соответствии с записанными значениями в эти регистры) будут меняться уровень напряжения на противоположный, подтягиваться к+5 или 0. Но вот не могу понять, при активации данной функции можно ли менять значения этих ножек в программе?

  32. Артём Двинин говорит:

    Александр, здравствуйте.
    Выставляя биты COMnA1:0 , COMnB1:0, COMnC1:0 Вы включаете альтернативную функцию вывода, и запрещаете его работу как обычного порта ввода-вывода (т.е. выставить значение из программы не получиться). При этом надо не забыть настроить соответствующий вывод на выход.

  33. Александр М. говорит:

    Попытался прошить программу под AtMega 128 с внешним кварцем на 16МГц, программа почему-то не заработала. Наверно надо исправить значения битов?

  34. Артём Двинин говорит:

    Доброго времени суток, Александр.
    Может попробовать сначала простую программу?
    Если будет мигать, то дело в настройках таймера, если нет, то не работает светодиод.

    #include <avr/io.h>
    #include <util/delay.h>
     
    int main( void )
    {
      DDRB |= PB0;
      while(1) {
       _delay_ms(1000);
       if( PINB & ( 1 << PB0 ) ) {
          PORTB &= ~( 1 << PB0 );
        }
        else {
          PORTB |= ( 1 << PB0 );
        }
      }
      return 0;
    }
  35. нурик говорит:

    добрый вечер! помогите пожалуйста как записать программу на аттини 2313 чтобы
    одно лампа сразу загоралась а вторая через 5 сек
    заранее спасибо!!!!!

  36. Артём Двинин говорит:

    Нурик, доброго времени суток :)
    Попробую помочь, но мне не известна схема вашего устройства.
    По этому есть вопросы, микроконтроллер работает на какой частоте? Какие выводы используете для управления «лампами»? А «лампы» — это что?

  37. Олег говорит:

    Артём, спасибо за статью. Но я никак не могу разобраться с расчетом задержки. Правильно ли я понимаю: attiny2313, выставлено во фьюзах 8МГц (8000000Гц), делитель 1024. Частота таймера: 8000000 / 1024 = 7812,5. Мигание светодиода с частотой 10Гц: 7812,5 / 10 = 781,25, 65536 — 781 = 64754

    ISR( TIMER1_OVF_vect )
    {
    	TCNT1 = 64754;	
    	if( PIND &amp; ( 1 &lt;&lt; PD1 )) {
    		PORTD &amp;= ~( 1 &lt;&lt; PD1 );
    	}
    	else {
    		PORTD |= ( 1 &lt;&lt; PD1 );
    	}
    }
     
    int main(void)
    {
    	DDRD = ( 1 &lt;&lt; PD1 );  
    	TCCR1B = (1&lt;&lt;CS12)|(0&lt;&lt;CS11)|(1&lt;&lt;CS10); 
    	TIMSK |= (1&lt;&lt;TOIE1); 
    	TCNT1 = 64754;       
    	sei();               
     
    	while(1);            
    	return 0;
    }

    Но светодиод мигает раз в 2, сек, а 10Гц это 10 раз в секунду.
    Может я, что-то не так понял?

  38. Артём Двинин говорит:

    Доброго времени суток, Олег.
    Вы все рассчитываете правильно. Cветодиод должен менять своё состояние с частотой 10Гц, но мигать он будет с частотой 5 Гц.
    А 0.5 Гц получается скорее всего из за того, что выставлен fuse — CKDIV8.

  39. Олег говорит:

    Артём, большое спасибо. Так и есть, CKDIV8 был выставлен.

  40. Сергей говорит:

    Спасибо за статью и примеры.
    Я ардуину изучаю и наткнулся на пример инициализации и чтения таймера для
    CodeVisionAVR и там TCNT1H и TCNT1L регистры отдельно надо грузить и я так и сделал, и компилятор ардуины это проглотил но TCNT1H при раьоте программы всегда был ноль что бы я в него не грузил. А исправил на TCNT1 = xxxxx; и всё стало правильно работать

  41. xorkrus говорит:

    А нет ли кода как в статье, только на ассемблере?

  42. Сергей говорит:

    Вот спасибо большое! Все доходчиво, хоть пользуюст CVAVR, а не тем на чем вы пишете.

  43. Артём Двинин говорит:

    Пожалуйста, заходите ещё =)

  44. Алексей говорит:

    Помогите начинающему!
    Не запускается таймер на Attiny44

    /////
    #define F_CPU 8000000UL
    #include

    void init(void)
    {
    TCCR0B |= (1<<CS02); //настройка делителя нулевого таймера 256
    TIMSK0 |= (1<<TOIE0); //разрешение прерывания по переполнению
    }

    ISR (TIM0_OVF_vect) //прерывание
    {

    }

    int main(void)
    {
    init(); //инициализация
    sei(); //разрешение всех прерываний
    while(1)
    {
    asm("nop");
    }
    }

    /////////////////////////
    В данном случае таймер даже не начинает считать!
    Подскажите в чём проблема??
    Заранее благодарен!!!

  45. Сергей говорит:

    Объясните, пож.

    1. Из IDE загружаю скетч в ардуино Леонардо, где информация по USB каждую секунду направляется на выход. В консоли вижу ежесекундное обновление.
    2. Подключаю вместо консоли TeraTerm\ttermpro.exe». В окне вижу ежесекундное обновление.
    3. Все закрываю, отключаю ардуино от USB.
    4. Подключаю ардуино к USB. Подключаю TeraTerm\ttermpro.exe». В окне вижу обновление через 8 секуунд.

    Почему?

  46. Игорь говорит:

    А не проще в счётный регистр занести сразу ноль TCNT1 = 0;
    А в регистр сравнения столько тактов, сколько надо сосчитать, например 500 OCR1A = 500;
    И настроить таймер на прерывание по совпадению. Вот весь код настройки:

    TCCR1A |= (0 << WGM11) | (0 << WGM10);
    TCCR1 |= (0 << WGM13) | (1 << WGM12); // Режим 4, CTC "Clear Timer on Compare" значение счётного регистра TCNT1 будет сравниваться со значением в регистре OCR1A
    TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10); // Настраиваем предделитель = 8
    TIMSK |= (1 << OCIE1A); // Устанавливаем прерывания по совпадению
    OCR1A = 461; // Число для сравнения (когда TCNT1 = OCR1A наступит прерывание по совпадению)
    TCNT1 = 0; // Обнуляем значение счётного регистра таймера/счётчика1

  47. Игорь говорит:

    Ах да и вот собственно обработка этого прерывания:

    ISR(TIMER1_COMPA_vect)
    {
    // Тут код обработчик прерывания
    }

  48. Андрей говорит:

    Я скопировал данных код в atmel studio 4. И записал код в atmega32a.
    У меня диод на ноге PB0 в макетной плате стоит, он так и не замигал

  49. Андрей говорит:

    Здравствуйте!
    Пишу код в Atmel Studio 4 все работает, но записываю в контроллер (макетная плата на atmega32a) диод на PB0 не мигает. Что-то не могу разобраться с таймерами…

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

Ваш e-mail не будет опубликован.

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