Описание работы таймера/счётчика 1.
Прерывания от TC1
Таймер/счётчик 1 (TC1) представляет из себя 16-битный модуль, содержащий 10 8-битных регистров. Эти регистры фактически являются набором из 5 16-битных регистров. Счёт происходит в регистрах TCNT1H (Timer counter 1 High byte) и TCNT1L (Low byte), вместе составляющих 16-битный регистр TCNT1. ВНИМАНИЕ! Если использовать прямое чтение 8-битных регистров TCNT1H и TCNT1L, то нельзя быть уверенным, что эти регистры прочитались одновременно. Может произойти следующая ситуация: Счётчик содержал значение $01FF, Вы считали TCNT1H (содержащий значение 01 в какую-то переменную). За это время произошёл счётный импульс, и содержимое TCNT1L стало равно $00, а в TCNT1H записалось значение $02. Теперь Вы читаете значение TCNT1L в другую переменную, получаете в этой переменной значение $00 (ведь таймер-счётчик уже произвёл счёт). 16-битное значение этих переменных получилось $0100, но на момент считывания старшего байта содержимое счётчика было $01FF, и младший байт у Вас должен был прочитаться как FF. Для предотвращения такой ситуации служит временный регистр, содержащийся в блоке таймера-счётчика. Этот регистр прозрачный, т.е. действует автоматически. При считывании значения регистра TCNT1L в переменную, содержимое TCNT1H попадает в этот регистр. Затем при чтении старшего байта в переменную, считывается значение временного регистра. Временный регистр абсолютно прозрачен для пользователя, но для его корректной работы необходимо соблюдать такую последовательность действий:
Для 16-битной операции записи, старший байт должен быть записан первым. Младший - вторым.
Для операции 16-битного чтения, младший байт должен быть прочитан первым, а содержимое старшего байта считывается вторым.
Регистр TCCR1A служит для задания режимов работы таймера/счётчика 1:
Биты COM1A1,COM1A0, COM1B1 и COM1B0 - контролируют поведение выводов OC1A и OC1B.
Биты FOC1A, FOC1B, WGM11 и WGM10 служат для задания работы ТС1 как широтно-импульсного модулятора.
Скорость счёта ТС1 можно установить в регистре TCCR1B:
Где биты ICNC1, ICES1, WGM13 и WGM12 также служат для PWM, а CS12, CS11 и CS10 настраивают скорость счёта следующим образом:
В случае, если в эти биты записаны значения 000, ТС0 остановлен. Если записано 001, то тактовая частота процессора подаётся через схему делителя без изменений, и на каждый такт процессора ТС1 увеличивает значение в регистре TCNT1. Соответственно, если в CSxx Записано 101, то увеличение значения в TCNT1 происходит на каждый 1024-ый такт процессора.
16-битные регистры OCR1A и OCR1Bслужат для задания значения, при достижении которого в режиме счёта, ТС1 генерирует соответствующие прерывания.
Обработка прерываний от TC1
ТС1 при переполнении значения TCNT1 посылает процессору сигнал Timer/Counter 1 Overflow. Также процессору посылается сигнал Timer/Counter 1 A или B Compare Match при совпадении значений в регистрах TCNT1 и OCR1A и OCR1B соответственно. Реакция процессора на эти сигналы (вызов соответствующих прерываний) зависит от значения регистров TIMSK и флага I в Status регистре процессора.
Для задания реакции на события TC1 в регистре TIMSK служат четыре бита:
Бит 2 - TOIE1 - Когда этот бит установлен в 1 и разрешены прерывания, процессор реагирует на сигнал переполнения ТС1 и вызывает прерывание по вектору $010 (OVF1addr).
Бит 3 - OCIE1B - Когда этот бит установлен в 1 и разрешены прерывания, процессор реагирует вызовом прерывания по вектору $00E (OC1Baddr) на событие совпадения счёта с константой в регистре OCR1B. Бит 4 - OCIE1A - Когда этот бит установлен в 1 и разрешены прерывания, процессор реагирует вызовом прерывания по вектору $00C (OC1Aaddr) на событие совпадения счёта с константой в регистре OCR1A. Бит 5 - TICIE1 - Если установлен этот бит и разрешены прерывания, разрешено прерывание захвата ТС1, расположенного по вектору $00A (ICP1addr).
http://sotvorimvmeste.ru/viewtopic.php?f=38&t=78
Работа выполняется с таймером T0 микроконтроллера ATtiny2313 (D1), используя несколько изменённую схему второго задания. По ходу работы исследуются режимы работы таймера, его регистров, выхода и прерываний. Схема для работы :
R1-10 - 1 кОм; R11 - 10 кОм.
К выводам PORTВ подключёна светодиодная шкала (VD1), на которую постоянно выводится состояние счётного регистра TCNT0 таймера (см. код программы). Крайние светодиоды шкалы показывают состояние выхода таймера OC0B (вывод PD5) и состояние вывода PD6, который является индикатором работы в прерывании. Для тактирования таймера к входу T0 (вывод PD4) подключается тактовый генератор. Возможно, индикацию выводов OC0B (PD5) и PD6 будет удобней (для наглядности) выполнять не через светодиоды шкалы, а через отдельные светодиоды.
Например, режим работы таймера Normal, прерывание по сравнению.
//ATtiny2313
//f_cpu=8000000
#include <avr/io.h>
#include <avr/interrupt.h>
SIGNAL(SIG_OUTPUT_COMPARE0B)
{
TCNT0 = 0;
PORTD ^= 0b01000000; //инверсия на PD6
}
int main(void)
{
// порты ввода/вывода
PORTA = 0b11111111;
DDRA = 0b00000000;
// PD6 - выход на светодиод для индикации прерывания; D5 - выход OC0B; PD4 - вход T0
PORTD = 0b10011111;
DDRD = 0b01100000;
PORTB = 0b00000000;
DDRB = 0b11111111; // PB0-PB7 - аноды индикатора
//таймер T0
TCCR0A = 0b00010000; // Normal; состояние вывода OC0B меняется на противоположное
TCCR0B = 0b00000111; //подключение вывода T0, счёт по нарастающему фронту
TIMSK = 0b00000100; //прерывание по сравнению OCR0B
OCR0B = 8;
sei();
while (1) {
PORTB = TCNT0;
};
}
Пример 2. Normal. Overflow.
Режим работы таймера - Normal. Прерывание по переполнению.
В обработчике сигнала необходимо сбросить значение счетного регистра таймера до выбранного значения.
А.В. Евстифеев, стр 241.
//мк ATtiny2313
#include <avr/io.h>
#include <avr/interrupt.h>
//Режим Normal, прерывание по переполнению
#define TCNT TCNT0 = 256 - 15 //Число тактов до прерывания
SIGNAL(SIG_OVERFLOW0) //прерывание по переполнению
{
TCNT; //сброс счетчик
PORTD ^= 0b01000000;
}
int main(void)
{
PORTA = 0b11111111;
DDRA = 0b00000000;
// PD6 - выход на светодиод для индикации прерывания; D5 - выход OC0B; PD4 - вход T0
PORTB = 0b00000000;
DDRB = 0b11111111;
PORTD = 0b10011111;
DDRD = 0b01100000; //D5 - выход OCR0B
//Режим Normal
TCCR0A = 0;
TCCR0B = 0x07; //источник тактового сигнала
TIMSK = 0b00000010; //прерывание по переполнению
TCNT;
sei();
while(1)
{
PORTB = TCNT0; //вывод счетчика таймера на индикатор
}
}
Пример 3. CTC.
Режим работы таймера - СТС(сброс при совпадении).
Максимальное значение счетного регистра таймера определяется регистром сравнения OCR0A.
А.В. Евстифеев, стр 242.
//мк ATtiny2313
#include <avr/io.h>
#include <avr/interrupt.h>
//Режим СТС(сброс при совпадении)
//Состояние выхода меняется на противоположенное
int main(void)
{
PORTA = 0b11111111;
DDRA = 0b00000000;
PORTB = 0b00000000;
DDRB = 0b11111111;
PORTD = 0b10011111;
DDRD = 0b01100000; //D5 - выход OCR0B
//Режим СТС
TCCR0A = 0b00010010;
TCCR0B = 0x07;
OCR0A = 20; //Задаем максимум счетчика таймера
while(1)
{
PORTB = TCNT0;
}
}
Пример 4. СТС. Overflow.
Режим работы таймера - СТС. Прерывание по переполнению.
Прерывание по переполнению в режиме СТС генерируется только, если регистра сравнения(OCR0A) равен 255(0xFF).
А.В. Евстифеев, стр 242.
//мк ATtiny2313
#include <avr/io.h>
#include <avr/interrupt.h>
//Режим СТС(сброс при совпадении), прерывание по переполнению
//Состояние выхода меняется на противоположенное
SIGNAL(SIG_OVERFLOW0) //прерывание по переполнению
{
PORTD ^= 0b01000000;
}
int main(void)
{
PORTA = 0b11111111;
DDRA = 0b00000000;
PORTB = 0b00000000;
DDRB = 0b11111111;
PORTD = 0b10011111;
DDRD = 0b01100000; //D5 - выход OCR0B
//Режим СТС
TCCR0A = 0b00010010;
TCCR0B = 0x07;
TIMSK = 0b00000010;
OCR0A = 0xFF; //Для прерывания по переполнению только 0xFF
sei();
while(1)
{
PORTB = TCNT0;
}
}
Пример 5. CTC. Compare.
Режим работы таймера - СТС. Прерывание по сравнению.
Прерывание по сравнению в режиме СТС генерируется при равенстве счетного регистра таймера регистру сравнения OCR0A.
А.В. Евстифеев, стр 242.
//мк ATtiny2313
#include <avr/io.h>
#include <avr/interrupt.h>
//Режим СТС(сброс при совпадении), прерывание по сравнению.
//Состояние выхода меняется на противоположенное
SIGNAL (SIG_OUTPUT_COMPARE0A) //прерывание по сравнению c OCR0A
{
PORTD ^= 0b01000000;
}
SIGNAL (SIG_OUTPUT_COMPARE0B) //прерывание по сравнению с OCR0B
{
}
int main(void)
{
PORTA = 0b11111111;
DDRA = 0b00000000;
PORTB = 0b00000000;
DDRB = 0b11111111;
PORTD = 0b10011111;
DDRD = 0b01100000; //D5 - выход OCR0B
//Режим СТС
TCCR0A = 0b00010010;
TCCR0B = 0x07;
TIMSK = 0b00000101;
OCR0A = 20; //Для прерывания по сравнению любое значение
//OCR0B = 10;
sei();
while(1)
{
PORTB = TCNT0;
}
}
Пример 6. Phase Correct PWM.
Режим работы таймера - (ШИМ)Phase Correct PWM.
Счетный регистр таймера инкрементирует свое значение до значения OCR0A(или 0xFF - в зависимости от WGM02). Затем дикрементирует до минимума(0x00). Затем опять меняется направление счета.
Значение OCR0B определяет "скважность" сигнала т.е. отношения полезного сигнала к периоду.
А.В. Евстифеев, стр 245.
//мк ATtiny2313
#include <avr/io.h>
#include <avr/interrupt.h>
//Режим ШИМ (Phase Correct PWM)
int main(void)
{
PORTA = 0b11111111;
DDRA = 0b00000000;
PORTB = 0b00000000;
DDRB = 0b11111111;
PORTD = 0b10011111;
DDRD = 0b01100000; //D5 - выход OCR0B
//Режим ШИМ (Phase Correct PWM)
TCCR0A = 0b00110001; //7,6 и 5,4 биты отвечают за выходы OC0A и OC0B
//01 влияет только на OC0A
//10 неинвертированный ШИМ сигнал
//11 инвертированный ШИМ сигнал
//TCCR0B = 0b00000111;//Максимальное значение счетчика = 0xFF
TCCR0B = 0b00001111; //Максимально значение счетчика = OCR0A
OCR0A = 40; //Задаем максимальное значение
OCR0B = 10; //Изменение значения OCR0B определяет "скважность"
//Т.е. отношения полезного сигнала к периоду
sei();
while(1)
{
PORTB = TCNT0;
}
}
Пример 7. Phase Correct PWM. Устойчивые состояния.
Режим работы таймера - (ШИМ)Phase Correct PWM.
Если в регистр сравнения записать максимальное или минимальное(0x00) значение, то при совпадении значения счетчика таймера и содержания регистра сравнения, выход переключится в одно из устойчивых состояний. В соответствии с таблицей 7.16(стр. 247)
А.В. Евстифеев, стр 247.
//мк ATtiny2313
#include <avr/io.h>
#include <avr/interrupt.h>
//Режим ШИМ (Phase Correct PWM)
int main(void)
{
PORTA = 0b11111111;
DDRA = 0b00000000;
PORTB = 0b00000000;
DDRB = 0b11111111;
PORTD = 0b10011111;
DDRD = 0b01100000; //D5 - выход OCR0B
//Режим ШИМ (Phase Correct PWM)
TCCR0A = 0b00110001;
//TCCR0B = 0b00000111;//Максимальное значение счетчика = 0xFF
TCCR0B = 0b00001111; //Максимально значение счетчика = OCR0A
OCR0A = 40; //Задаем максимальное значение
OCR0B = 0; //Если задать 0 или максимум в зависимости от TCCROA
//(COMOx0:COMOx1) выход переходит в одно из устойчивых состояний
sei();
while(1)
{
PORTB = TCNT0;
}
}
Пример 8. Phase Correct PWM. Overflow.
Режим работы таймера - ШИМ(Phase Correct PWM). Прерывание по переполнению.
Прерывание генерируется когда счетный регистр таймера достигает нуля.
А.В. Евстифеев, стр 245.
//мк ATtiny2313
#include <avr/io.h>
#include <avr/interrupt.h>
//Режим ШИМ (Phase Correct PWM), прерывание по переполнению
SIGNAL(SIG_OVERFLOW0) //прерывание по переполнению, только при достижении 0
{
PORTD ^= 0b01000000;
}
int main(void)
{
PORTA = 0b11111111;
DDRA = 0b00000000;
PORTB = 0b00000000;
DDRB = 0b11111111;
PORTD = 0b10011111;
DDRD = 0b01100000; //D5 - выход OCR0B
//Режим ШИМ (Phase Correct PWM)
TCCR0A = 0b00110001;
//TCCR0B = 0b00000111;
TCCR0B = 0b00001111;
OCR0A = 40;
OCR0B = 20;
TIMSK = 0b00000010;
sei();
while(1)
{
PORTB = TCNT0;
}
}
Пример 9. Phase Correct PWM. Compare.
Режим работы таймера - ШИМ(Phase Correct PWM). Прерывание по сравнению.
Прерывание генерируется когда содержание счетного регистра таймера становится равно содержанию регистра сравнения.
А.В. Евстифеев, стр 245.
//мк ATtiny2313
#include <avr/io.h>
#include <avr/interrupt.h>
//Режим ШИМ (Phase Correct PWM), прерывание по сравнению
SIGNAL (SIG_OUTPUT_COMPARE0B)
{
PORTD ^= 0b01000000;
}
SIGNAL (SIG_OUTPUT_COMPARE0A)
{
}
int main(void)
{
PORTA = 0b11111111;
DDRA = 0b00000000;
PORTB = 0b00000000;
DDRB = 0b11111111;
PORTD = 0b10011111;
DDRD = 0b01100000; //D5 - выход OCR0B
//Режим ШИМ (Phase Correct PWM)
TCCR0A = 0b00110001;
//TCCR0B = 0b00000111;
TCCR0B = 0b00001111;
OCR0A = 80;
OCR0B = 40;
TIMSK = 0b00000101;
sei();
while(1)
{
PORTB = TCNT0;
}
}
Пример 10. Fast PWM. Compare/Overflow.
Режим работы таймера - (Fast PWM)ШИМ. Прерывание по сравнению/переполнению.
В этом режиме инкреметирования счетного регистра идет до OCR0A (или 0xFF - в зависимости от WGM02). Затем происходит сброс до минимума(0x00). Затем инкрементация повторяется.
Прерывание по сравнению генерируется при достижении счетчиком значения OCR0B, по переполнению - при достижении максимального значения. Так же присутствуют устойчивые состояния.
А.В. Евстифеев, стр 243.
//мк ATtiny2313
#include <avr/io.h>
#include <avr/interrupt.h>
//Быстрый ШИМ (Fast PWM)
SIGNAL(SIG_OVERFLOW0) //прерывание по переполнению
{
PORTA ^= 0x01;
}
SIGNAL (SIG_OUTPUT_COMPARE0B) //сравнение
{
PORTD ^= 0b01000000;
}
SIGNAL (SIG_OUTPUT_COMPARE0A) //сравнение
{
}
int main(void)
{
PORTA = 0b11111111;
DDRA = 0b00000000;
PORTB = 0b00000000;
DDRB = 0b11111111;
PORTD = 0b10011111;
DDRD = 0b01100000; //D5 - выход OCR0B
//Быстрый ШИМ (Fast PWM)
TCCR0A = 0b00110011; //7,6 и 5,4 биты отвечают за выходы OC0A и OC0B
//01 влияет только на OC0A
//10 неинвертированный ШИМ сигнал
//11 инвертированный ШИМ сигнал
//TCCR0B = 0b00000111;
TCCR0B = 0b00001111;
OCR0A = 80; //Прерывание по переполнению при достижении OCR0A
OCR0B = 40;
//TIMSK = 0b00000010;//Переполнение
//TIMSK = 0b00000101;//Сравнение
sei();
while(1)
{
PORTB = TCNT0;
}
}