Знаю, тема уже избитая, но все таки. Написал небольшую программку, которая должна выводить через usart символ '1' каждую секунд, но выводит за 10 секунд всего 6 единиц. Вот код: Код (C++): #include<avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> volatile unsigned long a = 0; ISR(TIMER1_COMPA_vect) { a++; } void USART_init(void) // Настраеваем скорость передачи данных { unsigned int bd = (16000000UL / (16UL * 38400UL) - 1); UBRR0L = 103; UBRR0H = 0; UCSR0B = (1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0); UCSR0C = (1<<USBS0)|(3<<UCSZ00); } void USART_TransmitByte( unsigned char data ) { while ( !( UCSR0A & (1<<UDRE0)) ); UDR0 = data; } void T1_init() { TCCR1A = 2; // CTC //TCCR1B |= (1<<CS02)|(1<<CS00); // MK/1024 TCCR1B |= (1<<CS01)|(1<<CS00); // MK/64 TCNT1 = 0; // счетный регистр OCR1A = 250; // 1 милисекунда TIMSK1 |= (1 << OCIE1A); // Разрешаем прерывание по событию совпадение } int main() { sei(); USART_init(); USART_TransmitByte('J'); T1_init(); while(1) { if(a == 1000) { USART_TransmitByte('1'); a = 0; } } } Частота МК 16 000 000; Делитель 64 => что одна секунда это 250 000 => что одна милисекунда это 250. Что я сделал не так?
Ну, понимаешь, МК-то он глупый, он читает то, что ты в коде пишешь, а не в комментариях. А ты пишешь там разные вещи. Вот, смотри, я прокомментировал твою инициализацию таймера Код (C++): /* По поводу использования |= с регистрами. Так делают когда надо сохранить остальные биты "как были". В данном случае ты уверен, что "как были" тебя устраивает? Думаю, нет, лучше использовать просто присваивание */ void T1_init() { TCCR1A = 2; // CTC /* НА САМОМ ДЕЛЕ PWM, Phase Correct, 9-bit */ //TCCR1B |= (1<<CS02)|(1<<CS00); // MK/1024 TCCR1B |= (1<<CS01)|(1<<CS00); // MK/64 /* здесь делают CS от другого таймера ? */ TCNT1 = 0; // счетный регистр OCR1A = 250; // 1 милисекунда /* а чего сразу на секунду не настроить ???? */ TIMSK1 |= (1 << OCIE1A); // Разрешаем прерывание по событию совпадение } Самое критичное, конечно, в первой строке функции (про TCCR1A). С такой настройкой таймера прерывание происходит вдвое реже Если нормально настроить таймер, то все тикает как надо Спойлер: Настройка таймера Код (C++): void T1_init(void) { TCCR1A = 0; // CTC TCCR1B = (1<<CS11) | (1<<CS10) | (1<<WGM12); // MK/64 + CTC TCNT1 = 0; // счетный регистр OCR1A = 250; // 1 милисекунда /* а чего сразу на секунду не настроить ???? */ TIMSK1 = (1 << OCIE1A); // Разрешаем прерывание по событию совпадение } Настройку USART не проверял, но там тоже что-то кривовато. например, хитрая переменная bd вычисляется, а потом нигде ни разу не используется.
Почему TCCR1A = 0? За настройку таймера отвечают два регистра TCCR1A, TCCR1B биты WGM10, 11 (TCCR1A) и WGM12,13 отвечают за выбор режима таймера СТС это 0100 => TCCR1A = 2. Нет?
Лучше писать через определения битов. Глянул даташит - режима CTC у этого МК два и в обоих режимах оба младших бита равны нулю. Откуда 2?
Конечно, нет! СТС (OCR1A) это когда все WGM1x нули, кроме WGM12. А WGM12 в каком регистре? В TCCR1B! Вот и получается, что TCCR1A у нас 0, а WGM12 взводится в TCCR1B