AVR использование таймеров ( ATMega8 TIMER0)

Timer0 — 8битный таймер.
В ATMega8 и ему подобных, timer0 ну очень простой таймер. Он умеет только считать, только от 0, и только до 255. Считает он с заданной частотой, и это пожалуй единственная настройка, которую можно настроить. Хотя и тут выбор не так велик, как хотелось бы.
Счетный регистр TCNT0 (8-и разрядный, как не сложно догадаться), доступен на чтение и запись, при переполнении (когда значение меняется с 0xFF на 0x00) дергается прерывание по-вектору TIMER0_OVF (если конечно разрешено битом TOIE0 в регистре TIMSK и глобально включено командой sei). Так, вот, благодаря доступу на запись, можно немного мухлевать, или даже много, например если в прерывании таймера в TCNT0 загнать, например 127, то считать он будет порядком (двоичным порядком) веселее. Таким образом даже шимить можно. Если очень нужно.

Параметры таймера задаются регистром TCCR0 , точнее первыми 3-мя битам (Clock Select) этого регистра: CS00,CS01,CS02 – выбор тактового источника

CS02 CS01 CS00  
0 0 0 нет источника, таймер остановлен
0 0 1 без предделителя, на вход таймера подается тактовая частота
0 1 0 F_CPU/8 (предделитель/prescaler)
0 1 1 F_CPU/64 (предделитель/prescaler)
1 0 0 F_CPU/256 (предделитель/prescaler)
1 0 1 F_CPU/1024 (предделитель/prescaler)
1 1 0 внешний источник, по фронту
1 1 1 внешний источник, по спаду

Для работы необходим разрешить соответствующее прерывание в регистре TIMSK установкой бита TOIE0

Сброс предделителя можно осуществить установив соответствующий бит (для ATMega8 это PSR10) регистра SFIOR.

В ATmega8 для timer0 и timer1 регистр предделителя общий, и надо внимательно относиться, т.к. возможны проблемы: если на вход таймер0 подается F_CPU, на таймер1 F_CPU/1024, а в обработчике TIMER0_OVF происходит установка PSR10, то TIMER1 работать перестанет, т.к. каждые 256 тактов счетчик предделителя будет обнуляться, и значения F_CPU/1024 ни разу не достигнет.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
#include <avr/io.h>
#include <avr/interrupt.h>
 
int main(void){
 
    //Порт D.0 как выход
    DDRD=_BV(PD0);
 
    //Устанавливаем источник тактов (F_CPU/1024)
    TCCR0 = _BV(CS00)|_BV(CS02);
    //Вот прям с этого момента TCNT0 начинает тикать
    //И увеличиваться на 1 каждые 1024 тактов процессора
 
    //включаем прерывание
    TIMSK |= _BV(TOIE0);
 
    //разрешаем прерывания
    sei();
 
    //бесконечный цикл
    while(1){;}
}
 
ISR(TIMER0_OVF_vect){
    PORTD ^= _BV(PD0); // мигаем портом D.0
    /* Период срабатывания прерывания легко посчитать, например F_CPU 16MHz,
     * тогда 1/(16000000/1024/256) = 16,384мс
     */
}