• 1
  • 2

Tlačidlami ovládame Unipolárny Krokový motor - Multitasking

. .

Multitasking - Krokový motor + tlačidlá
 

Doporučené preštudovať: Krokové Motory | Riadenie Unipolárneho Krokového motora #2 | Interrupty | Oživujemé tlačidlá #2

Tento výtvor vychádza z viacerých kapitol ako "Ovládame tlačidlá #1 - #2", kapitoly o krokových motoroch 
a z kapitoly venovanej Interruptom.

U tochto projektu vytvorím interface medzi unipolárnym krokovým motorom a 4 tlačidlami na ovládanie rýchlosti,
smer a celkové zapnutie/vypnutie motora.
Interface bude bežať pod dvomi nezávislými vláknami.

Čo sa týka kódu, upravím kód z predchádzajúcich projektov + sefektívnim logiku tlačidiel.

Návrh schémy:




Návrh kódu:



Navrhnutá štruktúra konfigurácie krokového motoru, tlačidiel, polohovania a ostatných pomocných premenných.

 

stepper.h

struct _unipolar_stepper_motor_ {
       struct __attribute__ ((packed)) {
              float err;
              volatile unsigned int *Port;
              volatile unsigned int *Tris;
              int * Pins;
              int pin_size;
                }Config;

       struct __attribute__ ((packed)) {
             int from;
             int to;
             int routing;
             int left;
             int right;
               struct __attribute__ ((packed)) {
                     struct __attribute__ ((packed)) {
                            bool switches;
                            volatile unsigned int *Port;
                            volatile unsigned int *Tris;
                            int pin_size;
                              }Config;
                       int on_off;
                       int left;
                       int right;
                       int slow;
                       int fast;
                        }Switch;
                }Control;

       struct __attribute__ ((packed)) {
              int i;
              int a;
              int b;
              int set_step;
              int button_ready;
              int max_speed;
              int min_speed;
              int current_speed;
              int tmp_speed;
              int fast_push_count;
              bool is_on;
              bool is_left;
              bool is_right;
              bool is_slow;
              bool is_fast;
                }Tmp;
}Stepper;




Navrhnutá časť riadiaca krokový motor.

stepper.h


void Stepper_Init(void)
{
   int stepper_pins[] = {1,2,3,7};
   int switch_pins[] = {Stepper.Control.Switch.on_off,
                                Stepper.Control.Switch.left,
                                Stepper.Control.Switch.right,
                                Stepper.Control.Switch.slow,
                                Stepper.Control.Switch.fast
                               };

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

   if(Stepper.Control.Switch.Config.switches == true && Stepper.Config.err==0 )
    {
       Stepper.Config.err = 245;
       if (*Stepper.Control.Switch.Config.Port == PORTA && PORTA != __No__Used__ && TRISA != __No__Used__)
         { Stepper.Control.Switch.Config.Tris = uintptr &TRISA; Stepper.Config.err=-1; }
       if (*Stepper.Control.Switch.Config.Port == PORTB && PORTB != __No__Used__ && TRISB != __No__Used__)
         { Stepper.Control.Switch.Config.Tris = uintptr ⧍ Stepper.Config.err=-1; }
       if (*Stepper.Control.Switch.Config.Port == PORTC && PORTC != __No__Used__ && TRISC != __No__Used__)
         { Stepper.Control.Switch.Config.Tris = uintptr &TRISC; Stepper.Config.err=-1; }
       if (*Stepper.Control.Switch.Config.Port == PORTD && PORTD != __No__Used__ && TRISD != __No__Used__)
         { Stepper.Control.Switch.Config.Tris = uintptr &TRISD; Stepper.Config.err=-1; }
    }

   if(Stepper.Config.err==0 || Stepper.Config.err==1)
    {
       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.Config.Port,Stepper.Config.Pins[Stepper.Tmp.i],"digital");
              Config_OUT(*Stepper.Config.Tris,Stepper.Config.Pins[Stepper.Tmp.i]);
              Bit_Clr(*Stepper.Config.Port,Stepper.Config.Pins[Stepper.Tmp.i]);
           }

       if (Stepper.Config.err==-1)
         {
            Stepper.Control.Switch.Config.pin_size = sizeof(switch_pins)/sizeof(int);

            for(Stepper.Tmp.i = 0;Stepper.Tmp.i < Stepper.Control.Switch.Config.pin_size; Stepper.Tmp.i++)
               {
                  Init_Port(*Stepper.Control.Switch.Config.Port,switch_pins[Stepper.Tmp.i],"digital");
                  Config_IN(*Stepper.Control.Switch.Config.Tris,switch_pins[Stepper.Tmp.i]);
                  Bit_Clr(*Stepper.Control.Switch.Config.Port,switch_pins[Stepper.Tmp.i]);
               }

            Stepper.Tmp.is_on = false;
            Stepper.Tmp.is_left = false;
            Stepper.Tmp.is_right = false;
            Stepper.Tmp.button_ready = 0;
         }

       Stepper.Tmp.max_speed = 3000;
       Stepper.Tmp.min_speed = 20;
       Stepper.Tmp.fast_push_count = -1;
   }
}

void Stepper_Go(void)
{
   if(Stepper.Tmp.is_left==true && Stepper.Tmp.is_right==false)
    {
       Stepper_Controll(BACKWARD,30,1);
    } else { Stepper_Controll(FORWARD,30,1); }
}

void Stepper_Controll(int way,int timer_ms,int rount)
{
   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;
                }
   if(Stepper.Tmp.fast_push_count == -1)
    {
       Stepper.Tmp.current_speed = timer_ms;
       Stepper.Tmp.fast_push_count=0;
    }

   for (Stepper.Tmp.b=0;Stepper.Tmp.b < rount && Stepper.Tmp.is_on == true;Stepper.Tmp.b++)
       {
          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.Config.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                             } else
                                  {
                                     Bit_Clr(*Stepper.Config.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.Config.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                             } else
                                  {
                                     Bit_Clr(*Stepper.Config.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.Config.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                             } else
                                  {
                                     Bit_Clr(*Stepper.Config.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.Config.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                              }else
                                  {
                                     Bit_Clr(*Stepper.Config.Port,Stepper.Config.Pins[Stepper.Tmp.a]);
                                  }
                         }
                        if(Stepper.Control.routing == Stepper.Control.left)
                         { Stepper.Tmp.a++; } else { Stepper.Tmp.a--; }

                     }
                 Delay_ms(Stepper.Tmp.current_speed);
                 if(Stepper.Control.routing == Stepper.Control.left)
                  { Stepper.Tmp.i++; } else { Stepper.Tmp.i--; }
              }
       }
}


Táto časť modulu pozostáva z troch funkcií Stepper_Init, Stepper_Go, Stepper_Controll.

Funkcia Stepper_Init ako z predošlých projektov inicializovanie rozhranie motoru a tláčidiel, definuje maximálnu/minimálnu rýchlosť motora, atď. .
Premennou Stepper.Config.err sa identifikuje stav správnosti definície premennej - pri chybnej alebo žiadnej definícií sa inicializácia nevykoná.
Príznak tejto premennej môžme používať globálne ako podmienený blok. Ak sa inicializovanie nevykoná kôli chybe, tak sa jednotlivé obsahy ostatných funkcií nevykonajú a ušetrí sa ďalší čas.

Funkcia Stepper_Controll je funkcia, ktorá mala v minulých projektov názov Stepper_Go.
Riadi krokový motor - rieši logiku smeru, rýchlosť otáčiek, pristupuje priamo do globálnej štruktúry.

Funkcia Stepper_Go je funkcia, ktorá je volaná priamo z vlákna. Táto funkcia nemá žiaden parameter a volá funkciu Stepper_Controll s defaultnými parametrami - smer, rýchlosť, počet otáčok. Defaultné hodnoty určujú parametre motora pri prvotnom spustení.
Pri ovládaní tláčidlami, sa o riadenie motora stará vnútorná logika funkcie Stepper_Controll.



Návrh modulu ovládania tláčidiel.

stepper.h

void StepperSwitch (void)
{
   if((Get_Switch(*Stepper.Control.Switch.Config.Port,Stepper.Control.Switch.on_off)) !=0 &&
                    Stepper.Tmp.button_ready==0)
    {
       Stepper.Tmp.button_ready=1;
       ReSwitching(Stepper.Tmp.is_on);

       if(Stepper.Tmp.is_on==false)
        {
           Stepper.Tmp.is_on = true;
           Bit_Set(PORTB,0);
        } else
             {
                Stepper.Tmp.is_on = false;
                Bit_Clr(PORTB,0);
             }
    }

   if(Stepper.Tmp.is_on == true)
    {
       if((Get_Switch(*Stepper.Control.Switch.Config.Port,Stepper.Control.Switch.left)) !=0 &&
                        Stepper.Tmp.button_ready==0)
        {
           Stepper.Tmp.button_ready=2;
           ReSwitching(Stepper.Tmp.is_left);
           if(Stepper.Tmp.is_left==false)
            {
               Stepper.Tmp.is_left = true;
               Stepper.Tmp.is_right = false;
            } else
                 {
                    Stepper.Tmp.is_left = false;
                    Stepper.Tmp.is_right = true;
                 }
        }

   if((Get_Switch(*Stepper.Control.Switch.Config.Port,Stepper.Control.Switch.fast)) !=0)
    {
       if(Stepper.Tmp.current_speed > Stepper.Tmp.min_speed)
         {
            Stepper.Tmp.current_speed = (Stepper.Tmp.current_speed-(10*2));
         }
    }

   if((Get_Switch(*Stepper.Control.Switch.Config.Port,Stepper.Control.Switch.slow)) !=0)
    {
       if(Stepper.Tmp.current_speed < Stepper.Tmp.max_speed)
        {
           Stepper.Tmp.current_speed = (Stepper.Tmp.current_speed+10)*2;
        }
    }
   }

   if(Stepper.Tmp.button_ready==1 &&
        (Get_Switch(*Stepper.Control.Switch.Config.Port,Stepper.Control.Switch.on_off))==0)
    {
       Stepper.Tmp.button_ready=0; return;
    }

   if(Stepper.Tmp.button_ready==2 &&
        (Get_Switch(*Stepper.Control.Switch.Config.Port,Stepper.Control.Switch.left))==0)
    {
        Stepper.Tmp.button_ready=0; return;
    }

}



Z predošlých príkladoch o tlačidlách vidíme, že som vynechal všetky bloky spomalenia Delay_ms() a cyklus while
podmienený stlačeným tlačidlom som nahradil príznakmi.

Riešenie je bezpečné a predchádza zacykleniam či spomaleniu.

Tlačidlá pre zrýchlenie/spomalenie motoru sú aktívne pri ich držaní. Motor sa zrýchľuje/spomaľuje nie len pri mačkaní,
ale aj pri stálom držaní.


Konfigurácia modulu v súbore main.c:

main.c

#define __enable__threading_mode__ AND
#define _disable_Thread_C                 AND
#define _disable_Thread_D                 AND
#define _disable_Thread_E                 END


#include "config_diall.h"
#include "stepper.h"
#include "config_words.h"

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

void ThreadA(void)
{
   Stepper_Go();
}

void ThreadB(void)
{
   StepperSwitch();
}


int main_diall(void)
{
   Init_Port(PORTB,0,"digital");
   Config_OUT(TRISB,0);
   Bit_Clr(PORTB,0);

   Stepper.Config.Port = uintptr &PORTB;
   Stepper.Control.Switch.Config.Port = uintptr &PORTB;
   Stepper.Control.Switch.on_off = 8;
   Stepper.Control.Switch.left= 9;
   Stepper.Control.Switch.slow = 10;
   Stepper.Control.Switch.fast = 11;

   Stepper_Init();

   while(1)
     {
     }
   return 0;
}
 



Ako prvé v metóde main_diall nastavujeme rýchlu konfiguráciu pre LED.

Ako druhé, nastavujeme názvy pracovných registrov pre krokový motor a tlačidlá.
Pri tlačidlách do premenných nastavujeme čísla pinov. Keďze pri univerzálnosti nebudeme v budúcnu možno požadovať všetky tlačidlá, nie je nutné alokovať pamäť pre dynamické pole. S jednotlivými spínačmi musíme pracovať "natvrdo", čo by nebolo efektívne pri poli.

Nasleduje inicializácia modulu a zacyklená podmienka while.

Jednotlivé metody modulu bežia pod vlastným vláknom.



Celý projekt v akcií: