Работа с таймерами на Attiny45 и Attiny84
- Войдите на сайт для отправки комментариев
Доброе время суток.
Есть такая проблема. Сделал ПИД-регулятор на ардуино Уно: светодиод на ШИМ плюс фоторезистор. Управление таймером. Все ок, работает. Решил перейти на Attiny45. Всё перенес, и вижу, что работать-то работает, но сигнал нестабилен. Путем проб выяснил, что контроллер выдает плохую (нестабильную) ШИМ. Написал свою ШИМ по известному алгоритму (таймер плюс прямое управлени портами). И все бы хорошо, да все равно ШИМ плохая. Предположил, что я как-то не так программирую таймер - не выдает он у меня 256-8000000/1/8000000 = 255 на Timer1, а выдает гораздо меньше.
Перешел на Attiny 84. А там еще хуже. Как ни бился, мне не удалось получить от таймеров (обоих) высокочастотное тактирование. И OVF и СOMPA пробовал. Вероятно, я что-то делаю не так.
Само собой, даташиты курил. имена регистров пишу без ошибок. Но, походу, глобально что-то забываю/не понимаю, т.к. опыт имею не шибко большой. Возможно, какие-то биты не пишу из нужных, возможно, вообще задаю непрвильный режим работы таймера. Повторюсь, основная проблема в ом, что таймеры тактирубтся на более низких частотах. чем мне надо, т.е. светодиодик мигает не достаточно быстро для полноценной ШИМ.
Может быть кто-то программировал таймеры на Attiny45/84 и поделится добрым советом или кусочком кода?
И второй вопрос: как еще можно получить качественную ШИМ, без мелких биений вокруг level (аналог функции analogWrite(pin, level))?
Пример для Attiny45 (OVF или COMPA на выбор): //Если можете ответить на вопросы выше без прочтения кода, то не забивайте им голову:)
void initTimer0() {
noInterrupts();
DDRB = (1 << PB4);
TCCR0A = 0;
TCCR0B = 0;
timer0_counter = 255;//256-(int)(8000000/8/1000000); //Должен мигать на 1000000 Гц
TCNT0 = timer0_counter; //OVF
// TCNT0 = 0; //COMPA
// OCR0A = timer0_counter; //COMPA
TCCR0B |= (1<<CS01); // 8 prescaler
// TCCR0B |= (1 << CS02);//256
//TCCR0B |= (1 << CS02) | (1 << CS00); //1024
TIMSK |= (1 << TOIE0); //OVF
// TIMSK |= (1<< OCIE0A); //COMPA
interrupts();
}
ISR(TIMER0_OVF_vect)
//ISR(TIMER0_COMPA_vect)
{
TCNT0 = timer0_counter; // OVF preload timer
//digitalWrite(4, !digitalRead(4));
}
void initTimer1() {
timer1_counter = 255; //256-(int)(8000000/1024/7812); // Должен мигать на 7812 Гц
noInterrupts(); // disable all interrupts
DDRB = (1 << PB4);
TCCR1 = 0;
TCNT1=0;
/// OCR1A=timer1_counter;
OCR1A=timer1_counter; //timer_counter
//TCCR1 |= (1 << CS13) | (1 << CS10); // 256
// TCCR1 |= (1 << CS12); //8
TCCR1 |= (1 << CS10); //1
// TCCR1 |= (1 << CS13) | (1 << CS11) | (1 << CS10); //1024
TIMSK |= (1 << OCIE1A);
// TIMSK |= (1 << OCIE1B);
interrupts();
}
ISR(TIMER1_COMPA_vect)
{
if (counter == 0) {
buf_lev_ch1 = lev_ch1;
PORTB |=(1<<PB4);
}
if (counter == buf_lev_ch1) PORTB&=~(1<<PB4);
counter++;
if (counter == 10) counter = 0;
}
Для Attiny84:
void initTimer1() {
//sreg = SREG;
noInterrupts();
DDRB = (1 << PB2);
TCCR0A = 0;
TCCR0B = 0;
// TCCR1B |= (1<<WGM12);//COMPA
timer1_counter = 65536-(int)(8000000/1/8000000);
TCNT1 = timer1_counter; //OVF
// TCNT1 = 0; //COMPA
// OCR1A = timer1_counter; //COMPA
TCCR1B |= (1 << CS02) ; //256
// TCCR1B |= (1<<CS10); // 1 prescaler
TIMSK1 |= (1 << TOIE0); //OVF
// TIMSK1 |= (1<< OCIE1A); //COMPA
//SREG = sreg;
interrupts();
}
ISR(TIM1_OVF_vect)
//ISR(TIM1_COMPA_vect)
{
TCNT1 = timer1_counter; // OVF preload timer
digitalWrite(2, !digitalRead(2));
}
Может проблема в том,что используется внутренний генератор ? Может перейти на кварц ?
Тоже об этом подумал. Частота в два раза больше, шуметь ШИМ будет меньше.
Шью с ArduinoISP, соответственно, нужно поменять фьюзы для Tiny45 для 16 МГц кварца. На какие?
C compa вроде понял проблему, с ovf нет Все равно не на той частоте работает.