реклама на сайте
подробности

 
 
> Программирование таймеров Attiny45 и 84 - есть проблема
van1
сообщение Jun 3 2014, 17:29
Сообщение #1





Группа: Новичок
Сообщений: 3
Регистрация: 3-06-14
Пользователь №: 81 860



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

Есть такая проблема. Сделал ПИД-регулятор на ардуино Уно: светодиод на ШИМ плюс фоторезистор. Управление таймером. Все ок, работает. Решил перейти на Attiny45. Всё перенес, и вижу, что работать-то работает, но сигнал нестабилен. Путем проб выяснил, что контроллер выдает плохую (нестабильную) ШИМ. Написал свою ШИМ по известному алгоритму (таймер плюс прямое управлени портами). И все бы хорошо, да все равно ШИМ плохая. Предположил, что я как-то не так программирую таймер - не выдает он у меня 256-8000000/1/8000000 = 255 на Timer1, а выдает гораздо меньше.

Перешел на Attiny 84. А там еще хуже. Как ни бился, мне не удалось получить от таймеров (обоих) высокочастотное тактирование. И OVF и СOMPA пробовал. Вероятно, я что-то делаю не так.

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

Может быть кто-то программировал таймеры на Attiny45/84 и поделится добрым советом или кусочком кода?

И второй вопрос: как еще можно получить качественную ШИМ, без мелких биений вокруг level (аналог функции analogWrite(pin, level))?

Пример для Attiny45 (OVF или COMPA на выбор): //Если можете ответить на вопросы выше без прочтения кода, то не забивайте им головуsm.gif

CODE
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:

CODE
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 - Jun 3 2014, 19:20
Причина редактирования: [codebox] для длинного кода, [code] - для короткого!!!
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов (1 - 5)
RabidRabbit
сообщение Jun 4 2014, 02:20
Сообщение #2


Местный
***

Группа: Свой
Сообщений: 397
Регистрация: 3-12-09
Из: Россия, Москва
Пользователь №: 54 040



Всё же Вы не дочитали даташит. Например (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, а не заморачиваться с проверками, чтением и прочей фигнёй sm.gif
Go to the top of the page
 
+Quote Post
van1
сообщение Jun 4 2014, 08:00
Сообщение #3





Группа: Новичок
Сообщений: 3
Регистрация: 3-06-14
Пользователь №: 81 860



Цитата(RabidRabbit @ Jun 4 2014, 07:30) *


А тогда вопрос: почему analogWrite для Attiny шумит, а для UNO гораздо меньше? Не в тактовой частоте ли дело?
Go to the top of the page
 
+Quote Post
van1
сообщение Jun 4 2014, 09:44
Сообщение #4





Группа: Новичок
Сообщений: 3
Регистрация: 3-06-14
Пользователь №: 81 860



Цитата(RabidRabbit @ Jun 4 2014, 07:30) *
Всё же Вы не дочитали даташит. Например (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, а не заморачиваться с проверками, чтением и прочей фигнёй sm.gif



Кстати, спасибо, ШИМ действительно ровная получается. но это, к сожалению, все равно не ответ на вопрос, почему программная ШИМ не ровная. пока грешу на тактовую частоту.
Go to the top of the page
 
+Quote Post
gena_p1
сообщение Jun 19 2014, 08:51
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 11-05-10
Пользователь №: 57 193



Значит какие-то прерывания перебивают прерывания по таймеру. У вас два вектора прерываний по таймерам (пробежался по исходникам 45й). Выберите тот, что важнее, и запрещайте прерывания в обработчике, потом разрешайте. И неизвестно еще что компилятор на компилировал, может есть какой вектор на изменения состояния вывода, а по воздуху летают наводки.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jun 19 2014, 09:49
Сообщение #6


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(gena_p1 @ Jun 19 2014, 11:51) *
Выберите тот, что важнее, и запрещайте прерывания в обработчике, потом разрешайте.
Нет, это не поможет. В AVR при входе в обработчик прерывания запрещаются автоматически. AVR не имеет вложенных прерываний, поэтому если прерывание ШИМ возникнет во время обработки другого прерывания - оно будет задержано до выхода из первого обработчика. Хочется получать одно прерывание без задержек - другие прерывания не должны использоваться вообще. Можно организовать некое подобие вложенных прерываний, но это не поможет избавиться от дрожания полностью, лишь частично его уменьшит.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 14:16
Рейтинг@Mail.ru


Страница сгенерированна за 0.01389 секунд с 7
ELECTRONIX ©2004-2016