Когда запрашиваете помощь на форуме, то постить код с инициализацией регистров числовыми значениями это совершенно дурная практика. Вы полагаете, что все дружно должны полезть в мануалы, раскапывая, что значит 0х07 для TCCR1 attiny45 ? Зачем вы подчистили всю побитовую разблюдовку кодвижена? Вы совершили совершенно бессмысленную работу, чтобы запутать себя и практически лишились возможности получить помощь извне. По степени интеллектуальной мощи это ни с чем не сравнимое действие.
Это хорошо, что у меня кодвижен был запущен и я как раз разбирался с таймером меги328, прежде чем зайти сюда. Восстановив по комментариями режим инициализации таймера для тини45 (хорошо еще комментарии почистить у вас ума не хватило), кодвижен у меня сгенирировал несколько отличный от вашего код. Маска прерываний для разрешения прерывания по переполнению должна выглядеть так:
Код: Выделить всё
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(0<<OCIE1A) | (0<<OCIE1B) | (0<<OCIE0A) | (0<<OCIE0B) | (1<<TOIE1) | (0<<TOIE0);
сравните это со своим умопомрачительно лаконичным TIMSK=0x04, которое изначально должно было выглядеть так:
Код: Выделить всё
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(0<<OCIE1A) | (0<<OCIE1B) | (0<<OCIE0A) | (1<<OCIE0B) | (0<<TOIE1) | (0<<TOIE0);
Вы видите, что 0x04 это бит OCIE0B, который разрешает не прерывание по переполнению (на который у вас стоит обработчик), а другое прерывание -- по совпадению счетчика со значением регистра OCR1B. В итоге вы ждете прерывание, которое никогда не может случиться.
Я же сюда зашел совсем по другому поводу. Ситуация несколько двусмысленная и я не знаю, считать это багом или нет. Есть шестнадцатибитный таймер TIMER1 атмеги 328p. Инициализируется он в режиме CTC:
Код: Выделить всё
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 16000,000 kHz
// Mode: CTC top=OCR1A
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer Period: 1 ms
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: On
// Compare B Match Interrupt: On
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10);
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x3E;
OCR1AL=0x7F;
OCR1BH=0x01;
OCR1BL=0x00;
Кодвижен генерирует код, где несколько операций присваивания устанавливают нулевые значения регистрам, которые, если верить атмеловскому букварю, и так находятся при включении в нуле. По сути это лишний код, который не делает осмысленных действий. Но не тут то было. Попытки закомментировать нулевые присвоения приводят к тому, что таймер впадает в некое странное состояние, когда он вроде бы работает, но прерывания начинают выдаваться не периодически и с большей частотой, чем было задумано.
Путем последовательного перебора было вычислено, что виновна во всем строчка инициализации TCCR1A. Если записать туда ноль, то все работает нормально. Если туда ничего не записывать, то получается ерунда. Если бы это была половинка 16-битного регистра, то еще можно было бы подозревать, что должны соблюдаться некие правила обращения к шестнадцатибитным регистрам и они где-то нарушаются. Но этот регистр восьмибитный и ни с каким другим регистром более не связан. Смотрю в букварь и вижу, что регистр после сброса всегда в нуле:
Какое таинство должно совершаться по замыслу атмелов, после записи туда еще одного нуля? Может, конечно, это компилятор где-то самовольничает, но шерстить ассемблерный код всех библиотек мне как-то совсем не хочется.