Ovládání analogového serva

Dobrý den,
Rozhodl jsem se, že se naučím pracovat se servem, našel jsem kód pochopil princip ovládání, a dokonce se mi podařilo servo rozchodit.
Problém je v tom, že se chová celkem nepředvídatelně :slight_smile:
klidně mi 10x provede bez problému cyklus 0°, 90°, 180°, a potom se začně kousat, vrčet, ale následně třeba znovu naběhne zpátky, jindy se procesor zastaví, nebo jen přepíná LED.
Zde je kód:

#define _XTAL_FREQ 20000000

#include <xc.h>

#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF

void servoRotate0()
{
  unsigned int i;
  for(i=0;i<50;i++)
  {
    RA0 = 1;
     __delay_us(500);
    RA0 = 0;
    __delay_us(19500);
  }
}

void servoRotate90()
{
  unsigned int i;
  for(i=0;i<50;i++)
  {
    RA0 = 1;
    __delay_us(1500);
    RA0 = 0;
    __delay_us(18500);
  }
}

void servoRotate180()
{
  unsigned int i;
  for(i=0;i<50;i++)
  {
    RA0 = 1;
    __delay_us(2100);
    RA0 = 0;
    __delay_us(17900);
  }
}

void main()
{
  TRISA = 0;
  TRISD = 0;
  PORTD = 0;
  while(1)
  {
    PORTD = 0xFE;
    servoRotate0();
    __delay_ms(2000);
    PORTD = 0xFD;
    servoRotate90();
    __delay_ms(2000);
    PORTD = 0xFB;
    servoRotate180();
    __delay_ms(2000);
  }
}

Mohl by jste mi někdo poradit?
Děkuji mnohokát!

zkus zo treba vyhladit filtrem…mozna pomuze

  1. Máš blokovací kondenzátory u procesoru ?
  2. Mám takový vtíravý pocit, že do serva by měl jít ten signál trvale a ne, že mu pošleš 50 pulzů a pak to celé 2 vteřiny stojí. Ono je totiž docela pravděpodobný, že servo během těch 50 pulzů nestihne přestavit pozici…

A mimochodem, snaž se vyhnout příkazům delay o délce kolem 1 ms a výše. Procesor pak má soustu práce s delayema a nemá čas na nic jínýho. Na testování je to samozřejmě jedno. Jinak místo toho použij nějaké časovače a přerušení a procesoru zbyde spoustu času na nějakou rozumnější práci, než čekání.

servo se ovlada impulzama o delce cca 1-2ms, co servo to samozrekme odchylka , sou ale serva co zvladnou i vic,
ten pulz: 1ms je sinchronizace a zbytek natoceni, frekvence cca 50Hz, takze kazdejch 20ms by mel bejt impulz o nastaveni , nektery zvladaj i rychlejsi posilani ,
pokud neni zadnej pulz servo stoji,musi ale bejt log 0 na vstupu
pokud nastavis log 1 a pretahnes to pres 2 ms tak to dela bordel,servo jede za roh na dorazy a pak samozrejme klesa napeti (pokud nemas tvrdej zdroj) a muze se resetovat procesor atd
kondiky…

RA0 = 1; __delay_us(500); tohle je co ??
co tohle…

while(true) { unsigned int i,j; unsigned int16 pulz=1200; for(j=0;j<5;j++) { for(i=0;i<25;i++) { RA0 = 1; __delay_us(pulz); RA0 = 0; __delay_us(20000); } pulz+=100; } for(j=0;j<5;j++) { for(i=0;i<25;i++) { RA0 = 1; __delay_us(pulz); RA0 = 0; __delay_us(20000); } pulz-=100; } }

Děkuji za Vaše reakce.
Reaguji na MiloPS3:
Kód jsem musel upravit tak, aby mi to kompilátor vzal následovně;

[code]#define _XTAL_FREQ 20000000

#include <xc.h>

#pragma config FOSC = HS
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config BOREN = OFF
#pragma config LVP = OFF
#pragma config CPD = OFF
#pragma config WRT = OFF
#pragma config CP = OFF

void main()
{
TRISA0 = 0;
while(1)
{
unsigned int i,j;
unsigned int pulz = 1200;
for(j=0;j<5;j++)
{
for(i=0;i<25;i++)
{
RA0 = 1;
__delay_us(pulz);
RA0 = 0;
__delay_us(20000);
}
pulz+=100;
}
for(j=0;j<5;j++)
{
for(i=0;i<25;i++)
{
RA0 = 1;
__delay_us(pulz);
RA0 = 0;
__delay_us(20000);
}
pulz-=100;
}
}
}
[/code]
Ovšem kompilátor mi vyhazuje chybu u __delay_us(pulz);
main.c:26: error: (1387) inline delay argument must be constant
Zřejmě mu tam vadí proměnná.
Ještě mi nešlo int16 a while(true).
Používám kompiler XC8

co tohle ?[code]usdelay(int a)
{
int r;
for (r=0;r<a;r++)
__delay_us(1);
}

while(1)
{
unsigned int i,j;
unsigned int16 pulz=1200;
for(j=0;j<5;j++)
{
for(i=0;i<25;i++)
{
RA0 = 1;
usdelay(pulz);
RA0 = 0;
usdelay(20000);
}
pulz+=100;
}
for(j=0;j<5;j++)
{
for(i=0;i<25;i++)
{
RA0 = 1;
usdelay(pulz);
RA0 = 0;
usdelay(20000);
}
pulz-=100;
}
}[/code]
nevim jak je definovanej “int” v tom xc8 , mel by bejt 16bit pro pulz

Servo dělá krůčky po zhruba 5°, dojede na konec, ale nezastaví se.
Je možné, že se každé servo ovládá jinak?

ne(nevim o tom ze by se ovladalo jinak), co je to za servo ? odkaz, foto stitku

Jedná se o servo ROBBE 8544 (8 g).

Zdravím, než takhle složitě laborovat, udělal bych si malý přípravek s 555, který bude posílat puls 1.5 ms s periodou 20 ms. Přidat malý poti, abych mohl puls měnit o ca 0.3 ms. To vše pro napětí ca 4 až 5V. Servo s tím musí naprosto spolehlivě fungovat. Nešetřil bych blokovací kondy a elyty v napájení, rovněž zdroj musí bez poklesu pod 0.2V zvládnout 2A proudu. Jinak osciloskop zkontrolovat napájení, pulsy, zkrátka vše možné. Bez možnosti změřit sám nebo u někoho je vše časově a psychycky hodně náročné.

Dobrý den,
Na začátku Balů napsal

Četl jsem, že příkazy __delay vytěžují procesor.
Proto jsem se snažil najít nějaký příklad s použitím některého ze tří timerů.
Jeden z nejjednodušších kódů pro začátek jsem našel zde:
microcontrollerboard.com/pic-timer0-tutorial.html
Pro začátek bych chtěl jen blikat s LED diodou, jenže nevím, na jaké místo do kódu na výš uvedené adrese zařadit RD0 = 1 popř. 0
Nemohli by jste mi poradit, nebo mě odkázat na nejjednodušší program s použitím timeru?
Děkuji!

za Count=0;
pokud prekladac umi prikaz toggle tak staci ten jinak toglovat podle nastavenyho lath popripade priznakovy bit

Používám kompiler XC8.
Toggle se zapisuje takto: RD0.Toggle(); ?

nevim, ja ho nepouzivam, se koukni do helpu…

Aha, tak toggle se v XC8 dělá takto:

RD0 = ~ RD0;

Kód jsem upravil následovně:

[code]#include <xc.h>
#include <pic16f877a.h>

#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)

int Count=0;

void main()
{
TRISD0 = 0;

TMR0=0;
T0CS=0;
T0SE=0;
PSA=0;
PS0=1;
PS1=1;
PS2=1;

while(1)
{
    while(!T0IF);
    T0IF=0;
    if(Count == 8)
    {
        Count=0;
        RD0 = ~ RD0;
    }
}

}[/code]
Bohužel, nefunguje to, ale nejsem si zde jist pár věcmi:

T0CS = 0; //pro práci s interním oscilátorem

Tam bych asi měl nastavit něco jiného, když používám 20MHz externí krystal, že? Navíc, PIC16F877A podle mně dostupných informací interním oscilátorem nedisponuje.
Prescaleru rozumím, o tom jsem se dočetl v příručce microchip, ale nevím, co přesně nastavuje bit T0SE.
Toto je v tutoriálu Microchip:

Mám všechna nastavení správně? Musí být povolen Watchdog timer?
Děkuji!