код проверен, отлично работает на моем роботе (3 сервы)
- Код: Выделить всё • Развернуть
// Для компилятора AVR-GCC / WinAVR
// Сервоконтроллер на 8 серво (АТмега8, 11.0592МГц)
// Работает на прерываниях таймера-счетчика 2
#define F_CPU 11059200 //частота проца
#include <avr/io.h>
#include <avr/interrupt.h>
//макросы для установки/сброса/переключения отдельных битов
#define clrs( x,y ) x &= ~(y)
#define sets( x,y ) x |= (y)
#define togs( x,y ) x ^= (y)
#define clr( x,y ) clrs( x,(1<<y) )
#define set( x,y ) sets( x,(1<<y) )
#define tog( x,y ) togs( x,(1<<y) )
//порт сервоконтроллера
#define SERVOPORT PORTD
//маска сервоконтроллера
#define SERVOMASK 0xF0
//частота таймера2 Ft2=400Гц, вычисляется как F_CPU/Ft2/PRSt2
//где PRSt2 - значение предделителя
#define EVERY400 216
#define TCNT2_VAL (255-EVERY400)
//среднее значение для серво, вычисляется как EVERY400*1.5/2.5+TCNT2_VAL
#define SERVO_AVG 169
//массив, с помощью которого устанавливаются значения серв
volatile unsigned char servo[8], servo_i, servo_next;
ISR( TIMER2_OVF_vect )
{
TCNT2 = TCNT2_VAL;
servo_i = servo_next;
servo_next++; if( servo_next>7 ){ servo_next=0; }
OCR2 = servo[ servo_next ];
if( servo[servo_i] < TCNT2_VAL ){ return; }
sets( SERVOPORT, (1<<servo_i)&SERVOMASK );
}
ISR( TIMER2_COMP_vect )
{
clrs( SERVOPORT, (1<<servo_i)&SERVOMASK );
}
int main()
{
//PORT D as SERVO
//4-7 servo
DDRD = (1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
PORTD = 0;
//Инициализация таймера2
TCCR2 = (1<<WGM20)|(1<<WGM21)|(5<<CS20);
TCNT2 = TCNT2_VAL;
TIMSK = (1<<OCIE2)|(1<<TOIE2);
servo_i = 0;
servo_next = 1;
for( unsigned char i=0; i<8; i++ ){ servo[i] = 0; }
sei();
//для примера
servo[4] = SERVO_AVG; //серво4 - T=1500us ( 0*)
servo[5] = SERVO_AVG+86;//серво5 - T=2500us (+90*)
servo[6] = SERVO_AVG-86;//серво6 - T= 500us (-90*)
servo[7] = SERVO_AVG+43;//серво7 - T=2070us (+45*)
//остальные каналы не используются (маскированы SERVO_MASK)
while(1);
return 0;
}