roboforum.ru

Технический форум по робототехнике.

Управление Сервами в WinAvr

Ответить

Lirzman » 15 авг 2006, 12:42

avr123.nm.ru писал(а):вы сформулируйте ТЗ для вашего устройства и опубликуйте.

ТЗ?
Боюсь показаться безграмотным, но что сия аббревиатура значит?

avr123.nm.ru » 15 авг 2006, 13:28

ТЗ - техническое задание -  него нужно начинать изготовление чего либо.

упрощенный пример в - avr123.nm.ru/z1.htm

По ТЗ создается схема и определяется алгоритм, далее алгоритм можно записать на псевдокоде - т.е. не на Си не на АСМе а на русском.

После этого написание самой программы становится "делом техники"

Наличие ТЗ позволит и другим людям помочь вам - они должны понимать чего вы добиваетесь.

Lirzman » 15 авг 2006, 13:30

Чего-то я не врубаюсь. :(
Сделал всё как говорил aesok.
Вот чего получилось:

Код: Выделить всёРазвернуть
char gservo;//Номер сервы
long int gangle;//Управляющий импульс
const int period =1000 ; //период в 20 миллисекунд

//****************ИНИЦИАЛИЗАЦИЯ ТАЙМЕРА***************************
void timer1_init()
{
TCCR1B = 0x00; //stop timer
//TCNT1 = gangle; //записать в регистр таймера число 3686400/1024/120(x)
//60056-среднее положение(+0.02)
TIMSK SET_B(TOIE1);//Разрешение прерывания по переполнению таймера 1
SREG SET_B(7);//Бит i в регистре SREG включен(разрешить глобальные прерывания)
TCCR1B =0x01; //Старт таймера при делителе = 1024
//Биты CS10 CS11 CS12
}
//**************ПРОЦЕДУРА ПЕРЕПОЛНЕНИЯ ТАЙМЕРА***********************
SIGNAL(SIG_OVERFLOW1)
{
PORTB CLR_B(gservo);//Выставить 0 на ножку  
static int cur_state;
 if(cur_state == 0) {
    //вывести '1'
    TCNT1=gangle; //настроить таймер на задежку t ms
    cur_state = 1;
   
 } else {
     //вывести '0'
     TCNT1=period;//настроить таймер на задежку (20) ms
     cur_state = 0;
 }

//timer1_init();
}

//************ПРОЦЕДУРА ПОЗИЦИОНИРОВАНИЯ СЕРВЫ********************
void Pos(char servo,long int angle)
{

PORTB SET_B(servo);//Выставить 1 на ножку
gservo=servo;//Номер сервы
gangle=angle;//Управляющий импульс
TCNT1=gangle;//Управляющий импульс
timer1_init();

}


По идее таймер должен зациклистя, но этого не происходит т.к надо вызвать ф-цию timer1_init(); или TCCR1B =0x01; //Старт таймера при делителе = 1024. По понятным причинам вставлять эти ф-ции в подпрограмму прерывания таймера я не могу.

Подаётся только управляющийй импульс :( , без 20мс периода после него.

2aesok:Или ваш вариант нерабочий, или я опять затупил  :)

Lirzman » 15 авг 2006, 13:33

avr писал(а):они должны понимать чего вы добиваетесь.

Пока и без ТЗ думаю всем понятно что я пытаюсь сделать 20мс задержку на 16-ти битном таймере. :D
Тем более я код постоянно выкладываю.

Вот закончу с сервами и напишу ТЗ :D

avr123.nm.ru » 15 авг 2006, 15:04

ну если так просто то сделайте по аналогии как в задачах сделано для 8-ми битного таймера.

Lirzman » 15 авг 2006, 15:12

Как оказалось я затупил :D
Получилось сделать ~20мс задержку, но такое ощущение что она сливается с управляющим импульсом.
В общем смотрите:
Вложения
simul.JPG

aesok » 15 авг 2006, 15:14

Lirzman писал(а):Чего-то я не врубаюсь. :(
Сделал всё как говорил aesok.
Вот чего получилось:

Код: Выделить всёРазвернуть
char gservo;//Номер сервы
long int gangle;//Управляющий импульс
const int period =1000 ; //период в 20 миллисекунд

//****************ИНИЦИАЛИЗАЦИЯ ТАЙМЕРА***************************
void timer1_init()
{
TCCR1B = 0x00; //stop timer
//TCNT1 = gangle; //записать в регистр таймера число 3686400/1024/120(x)
//60056-среднее положение(+0.02)
TIMSK SET_B(TOIE1);//Разрешение прерывания по переполнению таймера 1
SREG SET_B(7);//Бит i в регистре SREG включен(разрешить глобальные прерывания)
TCCR1B =0x01; //Старт таймера при делителе = 1024
//Биты CS10 CS11 CS12
}
//**************ПРОЦЕДУРА ПЕРЕПОЛНЕНИЯ ТАЙМЕРА***********************
SIGNAL(SIG_OVERFLOW1)
{
PORTB CLR_B(gservo);//Выставить 0 на ножку  
static int cur_state;
 if(cur_state == 0) {
    //вывести '1'
    TCNT1=gangle; //настроить таймер на задежку t ms
    cur_state = 1;
   
 } else {
     //вывести '0'
     TCNT1=period;//настроить таймер на задежку (20) ms
     cur_state = 0;
 }

//timer1_init();
}

//************ПРОЦЕДУРА ПОЗИЦИОНИРОВАНИЯ СЕРВЫ********************
void Pos(char servo,long int angle)
{

PORTB SET_B(servo);//Выставить 1 на ножку
gservo=servo;//Номер сервы
gangle=angle;//Управляющий импульс
TCNT1=gangle;//Управляющий импульс
timer1_init();

}


По идее таймер должен зациклистя, но этого не происходит т.к надо вызвать ф-цию timer1_init(); или TCCR1B =0x01; //Старт таймера при делителе = 1024. По понятным причинам вставлять эти ф-ции в подпрограмму прерывания таймера я не могу.

Подаётся только управляющийй импульс :( , без 20мс периода после него.

2aesok:Или ваш вариант нерабочий, или я опять затупил  :)


У меня сейчас мало времени.

1. 2 правило програмирования микроконтроллеров: ВСЕ ПРЕРЕМЕННЫЕ КОТОРЫЕ ИСПОЛЬЗУЮТЬСЯ И В ОСНОВНОЙ ПРОГРАММЕ И ПРЕРЫВАНИЯХ ДОЛЖНЫ БЫТЬ ОБЯВЛЕННЫ С МОДИФИКАТОРОМ volatile.

volatile int gangle;//Управляющий импульс

2. Вызывайте timer1_init(); только один из раз main.

3.   if(cur_state == 0) {
    //вывести '1'
Вместо   //вывести '1' должно быть управление пином к которому подключена серва.

Подробнее вечером.

Анатолий.

Lirzman » 15 авг 2006, 15:18

2 aesok
Спасибо, уже врубился :D

avr123.nm.ru » 15 авг 2006, 15:27

Согласно мастеру начального кода "ICC-AVR application builder" imagecraft.com   : 15.08.2006 15:07:24

для Mega8 при частоте 3.6864Mhz

можно получить 20 мС на таймере 1 при делителе 8.

т.е. нужно включить прерывание по переполнению таймера

TIMSK = 0x04; //timer interrupt sources

затем запустить таймер установкой деления - 8

TCCR1A = 0x00;
TCCR1B = 0x02; //start Timer

затем вписать в таймер число с которого считать.

TCNT1H = 0xDC; //reload counter high value
TCNT1L = 0x01; //reload counter low value

досчитав до FFFF таймер переполнится и возникнет прерывание. Это будет конец 20 мС с момента

загрузки в таймер числа с которого считать.


т.е. все абсолютно аналогично туму как сделано в задаче  http://avr123.nm.ru/z6.htm

================
Вот прога созданая мастером для ICC

#include <iom8v.h>
#include <macros.h>

void port_init(void)
{
PORTB = 0x00;
DDRB  = 0x00;
PORTC = 0x00; //m103 output only
DDRC  = 0x00;
PORTD = 0x00;
DDRD  = 0x00;
}

//TIMER1 initialize - prescale:8
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 50Hz
// actual value: 50,005Hz (0,0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
TCNT1H = 0xDC; //setup
TCNT1L = 0x01;
OCR1AH = 0x23;
OCR1AL = 0xFF;
OCR1BH = 0x23;
OCR1BL = 0xFF;
ICR1H  = 0x23;
ICR1L  = 0xFF;
TCCR1A = 0x00;
TCCR1B = 0x02; //start Timer
}

#pragma interrupt_handler timer1_ovf_isr:9
void timer1_ovf_isr(void)
{
//TIMER1 has overflowed
TCNT1H = 0xDC; //reload counter high value
TCNT1L = 0x01; //reload counter low value
}

//call this routine to initialize all peripherals
void init_devices(void)
{
//stop errant interrupts until set up
CLI(); //disable all interrupts
port_init();
timer1_init();

MCUCR = 0x00;
GICR  = 0x00;
TIMSK = 0x04; //timer interrupt sources
SEI(); //re-enable interrupts
//all peripherals are now initialized
}

==========

такой мастер для WinAVR есть в пакете

AtmanAvr, IDE of C/C++ Compiler AVRGCC

http://www.atmanecl.net/EnglishSite/SoftwareEnglish.htm

РЕКОМЕНДУЮ !

1) ProjectWizard - When you first create a project , you use the Project Wizard to lead you through a series of dialog boxes in which you choose options for the MCU type, modules, functions and etc. of your project. AtmanAvr generates code automatically for you.

2) CodeWizard - The Code Wizard is like a programmer's assistant: it makes it easier for you to do certain routine tasks such as 1) creating new modules, 2) adding or deleting interrupt functions, and 3) seeing which modules or interrupt handlers are already defined and jumping to the handler program code.

Вот скриншоты
http://www.atmanecl.net/EnglishSite/snapshot.htm

==============

вот картинка мастера ICC по настройке таймера 1.
Вложения
avr123.nm.ru_icc_timer1.jpg

Lirzman » 15 авг 2006, 15:49

2 avr123.nm.ru
Спасибо.

Нет ли у вас картинки иллюстрирующей импульсы на оссцилографе в момент управления сервой.
Просто с задержками я уже справился.

Насколько я помню:
1.5мс высокий уровень
20мс низкий
1.5мс высокий уровень
20мс низкий

и так далее...

Так ведь?

avr123.nm.ru » 15 авг 2006, 15:55

да. я ж давал линк на "генеральский" фак по серво.

http://www.hitecrcd.com/Support/Faqs/Faq_Genservo_.htm

Возможно в ветке Сергея. Он тоже с сервами "бился".

Lirzman » 15 авг 2006, 15:57

Урррррааааааа!!!!
У меня получилось!!!!

Правда есть одно но, серву немного колбасит в пределах +-0.2гр,
но это не проблема т.к период в 20мс я ставил "на глазок" по оссциллографу :D
Вложения
simul_success.JPG

Lirzman » 15 авг 2006, 16:31

Спасибо за пример, теперь трясет только первую серву :D ,остальные стоят ровно. С чем это может быть связано?

Кроме этого при управлении другими 7-ю сервами, к каждой последующей прибавляется ~0.25гр :shock:
Чтоб было понятней приведу пример:

1.Подаю команду на первую серву.
2.Первая серва встаёт в положение +2.27, её дёргает в промежутке (+2.27..+2.48)

3.Подаю команду на вторую серву.
4.Вторая серва встаёт в положение +2.51, и там остаётся до следующей команды

5.Подаю команду на третью серву.
6.Третья серва встаёт в положение +2.75, и там остаётся до следующей команды

2AVR123.nm.ru: Задержку я переделал по вашему образцу(TCCR1B =0x02;TCNT1 =2201;)

Из-за чего это может быть?
Если импульс 20мс точный, то почему накапливается ошибка в 0.25гр
от серве к серве?

PS:Сервами я управляю ПОКА по ОДНОЙ(при подаче команды на следующую серву, предидущая ОСТАНАВЛИВАЕТСЯ)

Lirzman » 15 авг 2006, 17:04

Так, первую серву дергает потому что при запуске МК, таймер СРАЗУ выводит в PB0 единичку и начинает считать 20мс :shock:
Почему именно PB0???

Интересно то, что делает он это параллельно с управлением остальными сервами, никак на них не влияя :D  :D
Логичный вывод---на одном таймере можно управлять несколькими сервами одновременно :D

На осциллографе сигнал такой формы(PB0):
______  _____   _____
|         |  |        |  |         |
|20мс |_|20мс |_|20мс |

Держите исходник:
Вложения
demo.c
(4.58 КиБ) Скачиваний: 286

avr123.nm.ru » 15 авг 2006, 18:04

Lirzman писал(а):период в 20мс я ставил "на глазок" по оссциллографу :D


точно померить сигналы можно при выводе их с помощью инструментов "ГРАФ" в PROTEUS

и в VMLAB есть средства измерения времен. между событиями в окне SCOPE.   avr123.nm.ru/z2.htm


Rambler\'s Top100 Mail.ru counter