Помогите разобраться с кодом управления 3-мя сервоприводами

Обсуждаем контроллеры компании Atmel.
Ответить
Аватара пользователя
fevcomp
Первый раз сказал Мяу!
Сообщения: 25
Зарегистрирован: Чт окт 24, 2013 21:16:26
Откуда: Волгоград

Помогите разобраться с кодом управления 3-мя сервоприводами

Сообщение fevcomp »

На одном из сайтов нашел код DI HALT по управлению n -количеством сервоприводов но, перебросив код в CVAR и протестировав в Proteus, получил отрицательный результат. Т.е. запустив эмуляцию, сервоприводы смещаются, но на максимально возможный угол. Если пытаться менять показатель отклонения вала сервопривода на другой угол, то ни чего не выходит. Может где - то я ошибся в коде. Подскажите!

Код: Выделить всё

#include <mega16.h>
#include <delay.h>

#define MaxServo 3		// Число сервомашинок

//============== ПЕРЕМЕННЫЕ ==============
char servo_state;		            // Состояние конечного автомата. 
char ServoPortState[MaxServo+1];	// Значение порта которое надо вывести
char ServoNextOCR[MaxServo+1];	    // Время вывода значения
char servo_need_update;

 typedef struct
 {
	char Position;
	char Bit;
 }  SArray_def;
  
SArray_def Servo[MaxServo];
SArray_def *Servo_sorted[MaxServo];

//================== ФУНКЦИИ ==============
void Servo_sort(void);
void Servo_upd(void);
void Servo_Init(void);
//Теперь можно писать из прикладной программы любые произвольные значения (26…76 в данном случае) в поле Position, задавая произвольное положение любой из восьми сервомашинок. 
//После изменения любого из полей, перед отправкой таблиц в конечный автомат, данные надо упорядочить по длительности. Это делает спец функция.

//Простейший алгоритм сортировки вставкой. Недалеко ушел от пузырька, но на столь малых количествах
// данных являетя наиболее эффективным. 
void Servo_sort(void) 
{
char i,k;
SArray_def *tmp;
 
// Сортируем массив указателей.
for(i=1;i<MaxServo;i++)
	{
	   for(k=i;((k>0)&&(Servo_sorted[k]->Position < Servo_sorted[k-1]->Position));k--)
		{	
		   tmp = Servo_sorted[k];					            // Swap [k,k-1] 
		   Servo_sorted[k]=Servo_sorted[k-1];
		   Servo_sorted[k-1]=tmp;
		}
 
	}
}

//Массив отсортирован. Теперь надо его обработать и сформировать таблицы для автомата. 
//Обработка заключается в склейке совпадающих полей. Т.е. если у нас есть, например, 5 каналов с длительностью 20, 
//то их надо склеить в одно значение таблицы, а биты слепить в единую битмаску.
//А потом загрузить все в массивы конечного автомата.
//Обновление идет в функции Servo_upd

void Servo_upd(void)
{
   char i,j,k;
 
   for(i=0,k=0;i<MaxServo;i++,k++)
  {
	if(Servo_sorted[i]->Position!=Servo_sorted[i+1]->Position)	//Если значения уникальные
	{
	   ServoNextOCR[k] = Servo_sorted[i]->Position;			   // Записываем их как есть
	   ServoPortState[k+1] = Servo_sorted[i]->Bit;			   // И битмаску туда же
	}
	else								                       // Но если совпадает со следующим
	{
	   ServoNextOCR[k] = Servo_sorted[i]->Position;			  // Позицию записываем
	   ServoPortState[k+1] = Servo_sorted[i]->Bit;			  // Записываем битмаску

	 // И в цикле ищем все аналогичные позиции, склеивая их битмаски в одну.

	   for(j=1;(Servo_sorted[i]->Position == Servo_sorted[i+j]->Position)&&(i+j<MaxServo);j++)
		{
		   ServoPortState[k+1] |= Servo_sorted[i+j]->Bit;
		}
	   i+=j-1;						               // Перед выходом корректируем индекс
	}						                       // На глубину зарывания в повторы
  }	
  ServoNextOCR[k] = 0xFF;                          // В последний элемент вписываем заглушку FF.
}

interrupt [TIM0_COMP] void timer0_comp_isr(void)   //совпадение по прерыванию
{
  if (servo_state)                                // Если не нулевое состояние то
    {
       OCR0 = ServoNextOCR[servo_state];          // В регистр сравнения кладем следующий интервал
       PORTA &= ~ServoPortState[servo_state];	  // Сбрасываем биты в порту, в соответствии с маской в массиве масок.
	   servo_state++;				              // Увеличиваем состояние автомата
       
	  if (OCR0 == 0xFF)				              // Если значение сравнения равно FF значит это заглушка
		{				                          // И мы достигли конца таблицы. И пора обнулить автомат
		   servo_state = 0;			              // Выставляем нулевое состояние.
		   TCNT0 = 105;			                  // Программируем задержку в 20мс (на предделителе 1024)
		   TCCR0 = 0x00;                   // Сбрасываем предделитель таймера
		   TCCR0 |= 0x05;                         // Устанавливаем предделитель на 1024

		if (servo_need_update)		             // Если поступил приказ обновить таблицы автомата
			{
			   Servo_upd();		                 // Обновляем таблицы.
			   servo_need_update = 0;	         // Сбрасываем сигнал обновления.
			}
		}  
	} 
     else						                  // Нулевое состояние автомата. Новый цикл
	     {  
	        OCR0 = ServoNextOCR[servo_state];	  // Берем первую выдержку.   
	        TCCR0 = 0x00;			      // Сбрасываем предделитель 
	        TCCR0 |= 0x04;				          // Предделитель на 256
	        PORTA = 0b00000111;				      // Выставялем все сервоканалы в 1 - начало импульса   4
	        servo_state++;				          // Увеличиваем состояние конечного автомата. 
	     }
}

void Servo_Init(void)
{

Servo_sorted[0] = &Servo[0];
Servo_sorted[1] = &Servo[1];
Servo_sorted[2] = &Servo[2];

Servo[0].Bit = 0b00000001;
Servo[1].Bit = 0b00000010;
Servo[2].Bit = 0b00000100;

Servo[0].Position = 50;
Servo[1].Position = 50;
Servo[2].Position = 50;

}

void main(void)
{
 DDRB &=~(1<<PORTB2);
 PORTB |= (1<<PORTB2);
 PORTA = 0b00000111;
 DDRA = 0b00000111; 
 Servo_Init();
 TIMSK |= (1<<OCIE0);   
TCCR0 |= 0x04;    //предделитель 256 
#asm("sei")
Servo_sort();
while (1)
      {  

        Servo[0].Position =76;
        Servo_upd();
        servo_need_update = 1;
      }
}
"Жизнь человека - это короткое мгновение во вселенной, и не стоит её тратить на обиды, оскорбления и выяснение отношений."
Реклама
Аватара пользователя
Engineer_Keen
Друг Кота
Сообщения: 3872
Зарегистрирован: Пт янв 29, 2010 10:27:40
Откуда: Москва

Re: Помогите разобраться с кодом управления 3-мя сервопривод

Сообщение Engineer_Keen »

Код смотреть некогда и лень, но я бы проверил скорость работы контроллера, возможно в настройках симулятора и\или прошивке стоит неверная частота. Нужно подключить на выходы осциллограф и измерить длины импульсов, они должны быть в пределах 1-2мс (смотря какие настройки у сервоприводов). Если есть отличие (более чем в 2 раза), ищите проблему в настройках, если нет, то действительно ошибка в коде.
Неправильно собранная из неисправных деталей схема нуждается в отладке и сразу не работает... (С)
Реклама
Ответить

Вернуться в «AVR»