Понадобилось управлять одной сервой с помощью 8-битного таймера. Аппаратный ШИМ дает слишком маленькое разрешение, два таймера использовать жирно.
Поэтому я применил способ (основанный на методе 3, описанном тут в местной wike), использующий переконфигурирование таймера в каждом прерывании. В этом случае надо всего два прерывания на период управления - одно начинает управляющий импульс, другое его заканчивает. При кварце 14.7456Мгц разрешение получилось примерно 8,68мкс, диапазон ширины управляющего импульса - чуть шире 800-2200мкс. Среднее положение соответствует числу 172 в регистре OCR2, изменение на 1 соответствует примерно изменению ширины импульса на 8,68мкс.
Привожу код для ATMega16a, может кому пригодится.
Управление сервоприводом с помощью 8-битного таймера. Только нужная часть кода.
- Код: Выделить всё • Развернуть
...
//global variables
uint8_t servo_position;//содержит текущее положение сервопривода, просто запишите в него нужное значение
...
//начальная инициализация
void init(){
...
sei();
servo_position=172; //сервопривод в среднее положение
DDRD|=1<<servo_pwm; //пин OC2 на выход
OCR2=0xFF; //пин OC2 Timer2 автоматически установится, когда таймер досчитает до OCR2=255
TIMSK|=1<<TOIE2; // активируем прерывание Timer2 overflow
TCCR2=0b00110111; // ck/1024, normal mode, set OC2 on compare
/*первым наступит прерывание Timer2 overflow, при этом пин OC2 автоматически установится потому что
в настройках таймера задана "установка OC2 при равенстве TCNT2=OCR2=255", вручную устанавливать не надо.*/
...
}
...
//ПРЕРЫВАНИЯ
//=================Timer2 overwlow interrupt================
ISR(TIMER2_OVF_vect){
TCCR2=0b00100101; // предделитель ck/128, normal mode, clear OC2 on compare
// при F_CPU=14.7456Мгц один тик таймера 8,6784мкс
OCR2=servo_position; //задаем ширину управляющего импульса
TCNT2=0;
TIFR|=1<<OCF2; //сбрасываем флаг OCF2, флаг TOV2 сбросится при выходе из прерывания
TIMSK|=1<<OCIE2; // активируем прерывание Timer2 compare
TIMSK&=~(1<<TOIE2); // дизактивируем прерывание Timer2 overflow
}
//=================Timer2 compare match interrupt================
ISR(TIMER2_COMP_vect){
TCCR2=0b00110111; // предделитель ck/1024, normal mode, set OC2 on compare
OCR2=0xFF; //счет до 255 даст задержку ~17мс
TCNT2=0;
TIFR|=1<<TOV2; //сбрасываем флаг TOV2, флаг OCF2 сбросится при выходе из прерывания
TIMSK|=1<<TOIE2; // активируем прерывание Timer2 overflow
TIMSK&=~(1<<OCIE2); // дизактивируем прерывание Timer2 compare
}
...