Перейти к содержанию
    

Программирование таймеров Attiny45 и 84 - есть проблема

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

 

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

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!!!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всё же Вы не дочитали даташит. Например (timer 0, tiny45), устанавливаете режим Phase Correct PWM Mode (WGM[2:0] = 1), настраиваете поведение нужного Вам вывода (COM0A[1:0] или COM0B[1:0]), задаёте заполнение в соответствующем регистре OCR0A или OCR0B и включаете предделитель (CS0[2:0] = 1). Частота ШИМ будет = 8000000 / 510. И для "ручного" переключения состояния вывода достаточно записать 1 в соответствующий бит регистра PIN, а не заморачиваться с проверками, чтением и прочей фигнёй :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

 

А тогда вопрос: почему analogWrite для Attiny шумит, а для UNO гораздо меньше? Не в тактовой частоте ли дело?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Всё же Вы не дочитали даташит. Например (timer 0, tiny45), устанавливаете режим Phase Correct PWM Mode (WGM[2:0] = 1), настраиваете поведение нужного Вам вывода (COM0A[1:0] или COM0B[1:0]), задаёте заполнение в соответствующем регистре OCR0A или OCR0B и включаете предделитель (CS0[2:0] = 1). Частота ШИМ будет = 8000000 / 510. И для "ручного" переключения состояния вывода достаточно записать 1 в соответствующий бит регистра PIN, а не заморачиваться с проверками, чтением и прочей фигнёй :)

 

 

Кстати, спасибо, ШИМ действительно ровная получается. но это, к сожалению, все равно не ответ на вопрос, почему программная ШИМ не ровная. пока грешу на тактовую частоту.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Значит какие-то прерывания перебивают прерывания по таймеру. У вас два вектора прерываний по таймерам (пробежался по исходникам 45й). Выберите тот, что важнее, и запрещайте прерывания в обработчике, потом разрешайте. И неизвестно еще что компилятор на компилировал, может есть какой вектор на изменения состояния вывода, а по воздуху летают наводки.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Выберите тот, что важнее, и запрещайте прерывания в обработчике, потом разрешайте.
Нет, это не поможет. В AVR при входе в обработчик прерывания запрещаются автоматически. AVR не имеет вложенных прерываний, поэтому если прерывание ШИМ возникнет во время обработки другого прерывания - оно будет задержано до выхода из первого обработчика. Хочется получать одно прерывание без задержек - другие прерывания не должны использоваться вообще. Можно организовать некое подобие вложенных прерываний, но это не поможет избавиться от дрожания полностью, лишь частично его уменьшит.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...