• 1
  • 2

Riadenie Unipolárneho Krokového motora #1

. .

Rotácia v konštantnom smere a s konštantnou rýchlosťou.

 

Doporučené preštudovať: Krokové Motory



Ako krokový motor použijem motor z faxu.

Parametre:
Napájanie............. 24V
Krokovanie............ 48 krokov/Otáčka



Pri zvolení napájania je dobré si uvedomiť, že väčšina krokových motorov funguje aj na podstatne nižšom napätí.
Tento krokový motor v pohode funguje pri 12V, 300mA.
Napájanie nižším napätím má za následok omnoho menšie prehrievanie než pri doporučovanom alebo maximálnom napätí.

Je nutné však dodať, že menším napätím sa zmenšuje magnetické pole vinutí a tým dochádza k prešmykovaniu rotora pri určitej záťaži - vedie k desynchronizácií krokového systému.

Schéma zapojenia:




Krokové riadenie budením vinutí - sekvencie

V článku o krokových motoroch sme si už niečo povedali.
Po návrhu schémy a pred samotným návrhom kódu si musíme uvedomiť akým spôsobom chceme motor ovládať.

Krokovacie sekvencie nám reprezentújú postupné zopínanie vinutí, ktorého výsledkom je pootočenie sa rotora naproti statoru o určitý odstupňovaný krok.

Pri tvorbe zapojení je nutné vedieť konštrukčné vlastnosti krokového motora.
Máme krokový motor, ktorého celá otočka pozostáva zo 48 krokov.
Jeden celý krok (Full-Step) je odstupňovaný o 1.8 stupňa.
Pri Half-Stepe (pol kroku) to teda musí byť 0.9 stupňa.

Vidíme, že krokový motor umožňuje posun rotora o jeden celý alebo polovičný krok.
Polovičné kroky nám umožňujú dosiahnúť jemnejšieho polohovania rotora. Toto využívame, ak u zariadenia neberieme v úvahe otáčanie ako také, ale polohovanie na základe stupňov.
Stupne sa vypočítajú, či doladia pri polovičných krokoch - ak by celé kroky boli mimo požadovanú stupňovú hodnotu.

Krokové motory sú tvorené dvomi vinutiami. Môžeme budiť každé vinutie samostatne, alebo obe vinutia naraz. Z toho vyplýva jednofázové alebo dvojfázové riadenie.
Budenie fáz nám určuje krútiaci moment.
Pri dvojfázovom budení bude mať krokový motor väčší krútiaci moment než pri jednofázovom.
Krútiaci moment je sila rotoru otočiť sa synchrónne so záťažov.

Tabuľky budenia:

 

 



Prvé dve (Full-Steps) sú 4-taktné, po štvrtom takte sa sekvencie opakujú.
Pri Half-Steps sa sekvencie opakujú až od ôsmeho taktu.


Pri návrhu teda budeme pracovať s dvojfázovým budením pre čo najväčší krútiaci moment a rotor motora
budeme posúvať o celý krok - režim: 2-Fázový, Full-Step.



Návrh programu:

stepper_diall.h


struct _unipolar_stepper_motor_ {
      struct __attribute__ ((packed)) {
             volatile unsigned int *Port;
             volatile unsigned int *Tris;
                }Direct;

      struct __attribute__ ((packed)) {
             int * Pins;
             int pin_size;
                }Config;

      struct __attribute__ ((packed)) {
             int from;
             int to;
             int routing;
             int left;
             int right;
                }Control;

     struct __attribute__ ((packed)) {
             int i;
             int a;
                }Tmp;
}Stepper;

void Stepper_Init()
{
   int stepper_pins[] = {1,2,3,7};
   int err=1;

   if(*Stepper.Direct.Port == PORTA && PORTA != __No__Used__ && TRISA != __No__Used__)
    { Stepper.Direct.Tris = uintptr &TRISA; err=0; }
   if(*Stepper.Direct.Port == PORTB && PORTB != __No__Used__ && TRISB != __No__Used__)
    { Stepper.Direct.Tris = uintptr ⧍ err=0; }
   if(*Stepper.Direct.Port == PORTC && PORTC != __No__Used__ && TRISC != __No__Used__)
    { Stepper.Direct.Tris = uintptr &TRISC; err=0; }
   if(*Stepper.Direct.Port == PORTD && PORTD != __No__Used__ && TRISD != __No__Used__)
    { Stepper.Direct.Tris = uintptr &TRISD; err=0; }

   if(err==0)
    {
       Stepper.Config.pin_size = sizeof(stepper_pins)/sizeof(int);
       Stepper.Config.Pins = malloc(Stepper.Config.pin_size);
       Stepper.Control.left = 0;
       Stepper.Control.right = 1;

       for(Stepper.Tmp.i = 0; Stepper.Tmp.i < Stepper.Config.pin_size; Stepper.Tmp.i++)
          {
             Stepper.Config.Pins[Stepper.Tmp.i] = stepper_pins[Stepper.Tmp.i];
          }

       for(Stepper.Tmp.i = 0; Stepper.Tmp.i < Stepper.Config.pin_size; Stepper.Tmp.i++)
          {
             Init_Port(*Stepper.Direct.Port,Stepper.Config.Pins[Stepper.Tmp.i],"digital");
             Config_OUT(*Stepper.Direct.Tris,Stepper.Config.Pins[Stepper.Tmp.i]);
             Bit_Clr(*Stepper.Direct.Port,Stepper.Config.Pins[Stepper.Tmp.i]);
          }
     }
}

void Stepper_Go(int way, int timer_ms)
{
   if(way == Stepper.Control.left)
    {
       Stepper.Control.from = 0;
       Stepper.Control.to = Stepper.Config.pin_size;
       Stepper.Control.routing = BACKWARD;

    } else if(way == Stepper.Control.right)
               {
                  Stepper.Control.from = Stepper.Config.pin_size-1;
                  Stepper.Control.to = -1;
                  Stepper.Control.routing = FORWARD;
               }
   for(Stepper.Tmp.i = Stepper.Control.from; Stepper.Tmp.i!=Stepper.Control.to;)
       {
          for(Stepper.Tmp.a=Stepper.Control.from; Stepper.Tmp.a!=Stepper.Control.to;)
              {
                 if(Stepper.Tmp.i==0) //1.takt - start
                   {
                      if(Stepper.Tmp.a==0 || Stepper.Tmp.a==1)
                        {
                           Bit_Set(*Stepper.Direct.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                         } else
                              {
                                 Bit_Clr(*Stepper.Direct.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                              }
                   }

                 if(Stepper.Tmp.i==1) //2.takt - start
                   {
                      if(Stepper.Tmp.a==1 || Stepper.Tmp.a==2)
                       {
                          Bit_Set(*Stepper.Direct.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                       } else
                            {
                               Bit_Clr(*Stepper.Direct.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                            }
                   }

                 if(Stepper.Tmp.i==2) //3.takt - start
                  {
                     if(Stepper.Tmp.a==2 || Stepper.Tmp.a==3)
                      {
                         Bit_Set(*Stepper.Direct.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                      } else
                           {
                              Bit_Clr(*Stepper.Direct.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                            }
                  }

                 if(Stepper.Tmp.i==3) //4.takt - start
                  {
                     if(Stepper.Tmp.a==3 || Stepper.Tmp.a==0)
                      {
                         Bit_Set(*Stepper.Direct.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                       } else
                            {
                               Bit_Clr(*Stepper.Direct.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                            }
                  }

                if(Stepper.Control.routing == Stepper.Control.left) //prechadzanie pola pinov /urcenie smeru/
                 { Stepper.Tmp.a++; } else { Stepper.Tmp.a--; }
              }

            Delay_ms(timer_ms);

            if(Stepper.Control.routing == Stepper.Control.left)
             { //prechadzanie taktov /urcenie smeru/
                Stepper.Tmp.i++;
             } else {
                         Stepper.Tmp.i--;
                       }
       }
}




Ako u predošlých zapojeniach, nastavíme riadiace piny MCU. Dynamickou alokáciou sa nám uložia do globálneho, štruktuálneho poľa odkiaľ sa funkciou Stepper_Init() inicializujú.
Funkcia má navyše overenie nastavenia pracovného registra.
Pokiaľ je definovaný nepodporovaný pracovný register, init sa nevykoná. Register na nastavuje zo súboru main nižšie.
Premennú err je možné vložiť do štruktúry pre globálny prístup a pri chybe sa nevykonajú ani ďalšie funkcie modulu.

Funkcia Stepper_Go má dva vstupné parametre. Prvý udáva smer, v ktorom sa má motor točiť a druhý udáva oneskorenie. Oneskorením nastavujeme rýchlosť otáčania.
Čím je hodnota menšia, tým sa motor točí rýchlejšie. Prvý cyklus "for" sa vykoná 4-krát (zistí počet riadiacích portov z poľa), čo je 4. Je možné hodnotu manuálne nastaviť pri uprave kódu.
Duhý cyklus "for" prechádza riadiace porty a nastavuje im dané riadiace sekvencie krokov.

Logika zmeny smeru - zmena poradia prechádzania prvkov, je nanajvýš jasná.

main.c


  #define __NoTypeDefh__

#include "config_diall.h"
#include "stepper_diall.h"
#include "config_words.h"

char *PageSys(void)
{
   return "0x21";
}


int main(void)
{
   Stepper.Direct.Port = uintptr &PORTB;
   Stepper_Init();

   while(1)
    {
       Stepper_Go(FORWARD,100);
    }
}




Do premennej Stepper.Direct.Port nastavíme názov pracovného registra.
Globálnou premennou, konfiguračného súboru config_diall.h, FORWARD nastavujeme funkcií Stepper_Go smer otáčania dopredu - doprava. Pre smer doľava - vzad, použijeme premennú BACKWARD.
Konštantou "100" definujeme zbrzdenie motora na dobu 100ms. Čím je konštanta väčšia, motor sa točí pomalšie.