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мс */ } |