Работа с таймерами на Attiny45 и Attiny84

van1
Offline
Зарегистрирован: 17.03.2014

Доброе время суток.

Есть такая проблема. Сделал ПИД-регулятор на ардуино Уно: светодиод на ШИМ плюс фоторезистор. Управление таймером. Все ок, работает. Решил перейти на 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));
}

 

 

MaksMS
Offline
Зарегистрирован: 11.03.2013

Может проблема  в том,что используется внутренний генератор ? Может перейти на кварц ?

van1
Offline
Зарегистрирован: 17.03.2014

Тоже об этом подумал. Частота в два раза больше, шуметь ШИМ будет меньше.

Шью с ArduinoISP, соответственно, нужно поменять фьюзы для  Tiny45 для 16 МГц кварца. На какие?

C compa вроде понял проблему, с ovf нет Все равно не на той частоте работает.