fisertek_300
 
Lezione 5 
 
Comandare un motore passo passo (progetto di David Facta)
 
 
barra rossa2 
 
Dal momento che David, mi ha detto subito che il programma sviluppato da lui è, a dir poco, impresentabile, mi sono preso la briga di tirarne giù uno molto semplice ma, che introducesse qualche elemento nuovo nella tecnica di programmazione del linguaggio C (nuovo per noi)
 
barra rossa2 
 
motore_passo_600 
 
Foto di David Facta 
 
Il software 
I motori passo passo che si trovano in commercio e nelle nostre stampanti che andremo a cannibalizzare, possono essere di tipo bipolare (4 fili) e unipolari (5-6 fili).Il modulo presentato da David è pensato per gestire motori unipolari (5-6 fili), e la sua gestione, dal punto di vista del software, è praticamente identica alla gestione dei led. 
Quindi, per sviluppare il programma, partiremo proprio da quello usato per accendere led in sequenza, nella lezione n. 2 di questo sito.  
Ne riprendo uno scorcio che riporto qui sotto per comodità: 
 
/****************************\ 
* led in sequenza * 
\****************************/ 
 
#include<pic.h>     // compila per il PIC generico 
#include"delay.c" // richiama la routine di ritardo per poter usare le pause 
#define asp 120     //definisce che asp è uguale a 120 
 
main(void)              //l'inizio del programma 
 
{                              // graffa di apertura del programma 
TRISA = 15           // setta le prime 4 porte A del PIC come entrate 
TRISB = 0;            // setta le porte B del PIC come uscite 
 
       while(1)                              //ripete il ciclo all'infinito 
      {                                           //graffa di apertura di while 
             switch (PORTA)          //lettura PORTA 
                      {                           //graffa di apertura di switch 
               case 1:                        //se PORTA è 1 (0001) esegue la sequenza sotto, altrimenti salta 
                          PORTB = 0b00000001;DelayMs(asp); //sequenza da 0 a 7 
                          PORTB = 0b00000010;DelayMs(asp); 
                          PORTB = 0b00000100;DelayMs(asp); 
                          PORTB = 0b00001000;DelayMs(asp); 
                          PORTB = 0b00010000;DelayMs(asp); 
                          PORTB = 0b00100000;DelayMs(asp); 
                          PORTB = 0b01000000;DelayMs(asp); 
                          PORTB = 0b10000000;DelayMs(asp); 
              break;                           //interrompe il programma switch e torna a while 
 
benchè funzionante, è piuttosto rudimentale e approfittiamo con l'occasione a renderlo più efficiente con una o due stringhe e vorrei usare il costrutto IF invece di usare lo SWITH, così avete modo di osservarne le similitudini. 
Per iniziare prendiamo in esame soltanto il blocco che accendeva i led con le pause inframmentate.Per comandare un motore passo passo, dovremo soltanto sostituire le sequenze binarie con quelle opportune affinchè il modulo motore possa attivare i transistor nella giusta sequenza e, per fare questo dovremo riferirci alle caratteristiche del motore utilizzato. 
Prima di tutto dovremo limitare a 4 il numero delle righe nel caso il motore debba essere comandato a passi interi, mentre dovremo lasciare 8 linee per i mezzi passi.Dal momento che il modulo, per essere comandato, richiede solo 4 pin del pic, dovremo concentrare la sequenza solo alle prime 4 cifre del codice binario (ricordatevi che partono da destra). 
Prendiamo il caso dei passi interi del motore, modifichiamo il codice appena preso e ne viene fuori questo: 
 
PORTB = 0b00000001;DelayMs(asp); //sequenza da 0 a 3 
PORTB = 0b00000010;DelayMs(asp); 
PORTB = 0b00000100;DelayMs(asp); 
PORTB = 0b00001000;DelayMs(asp); 
 
Questa sequenza può già essere utilizzata per far girare il motore in un verso con passi interi.Se volessimo far girare il motore al rovescio, basterà invertire l'ordine della sequenza così: 
 
PORTB = 0b00001000;DelayMs(asp); //sequenza da 0 a 3 
PORTB = 0b00000100;DelayMs(asp); 
PORTB = 0b00000010;DelayMs(asp); 
PORTB = 0b00000001;DelayMs(asp); 
 
Le pause messe in ogni linea, ritardano l'esecuzione del programma rallentando la rotazione del motore.Quindi minore sarà il valore di asp, maggiore sarà la velocità del motore.I numeri in binario possono benissimo essere sostituiti con numeri in formato decimale, proviamo a farlo subito e ci ritroviamo con questo: 
 
PORTB = 1;DelayMs(asp); //sequenza da 0 a 3 
PORTB = 2;DelayMs(asp); 
PORTB = 4;DelayMs(asp); 
PORTB = 8;DelayMs(asp); 
 
Rimane il problema della poca efficienza di quanto appena descritto, è poco pratico scrivere per ogni parametro una linea di programma con la relativa pausa.Per rendere più efficiente il codice, introduco l'uso di una stringa di variabili che saranno puntati da una variabile (che chiameremo puntatore).In pratica la sequenza dei numeri decimali che abbiamo messo (1, 2, 4, 8 ) protremmo raccoglierla in una stringa e dichiararla all'inizio del programma in questo modo: 
 
int step[] = {1, 2, 4, 8}; 
 
Cosa vuol dire???Facciamo una descrizione punto per punto, altrimento rischiamo di perderci: 
 
Int:---->dichiaro una variabile di valore intero 
 
Step[]--->nome che ho dato io alla variabile e le parentesi quadre specificano che si tratta di una stringa di valori, tra le parentesi ci và il numero delle variabili presenti nella stringa ma nel linguaggio C non è obbligatorio, ci penserà il compilatore a farlo per me (sarebbe step[4] ). 
Segue il valore delle 4 variabili raccolte nelle parentesi graffe e separate dalla virgola.  
Le parentesi demarcano l'inizio e la fine della stringa, le virgole separano i valori delle variabili.Naturalmente bisogna ricordarsi il punto e virgola alla fine dell'istruzione. 
Ora che abbiamo definito la stringa, dobbiamo creare il puntatore che punterà le variabili all'interno di essa e ne restituirà il relativo valore, in modo da poterlo usare. Per raggiungere lo scopo, basterà impostare un'altra variabile che chiameremo i 
Per non farvi stare troppo sulle spine, riporto ora il listato completo con i relativi commenti.Ho fatto il programma in modo che il motore possa girare solo quando si preme uno dei 4 tasti del modulo tasti collegato alle porte A del pic, due tasti per i passi interi e l'altri due per i mezzi passi. 
 
/*************************** 
*** stepper unipolare *** 
************************** 
* motore collegato alla porta B 
* tasti collegati alla porta A* 
* (C)Sergio 29-03-2003* 
*************************/ 
 
#include <pic.h> 
#include "delay.c" 
#define asp 50           //definisce che asp è uguale a 50 
                                  //diminuire questo valore per aumentare la velocità 
int step[8] = {1, 3, 2, 6,4,12,8,9};  //stringa per i mezzi passi 
int step2[] = {1, 2, 4, 8};               //stringa per i passi interi 
main()
short i,e;                                        //dichiara due variabili con segno 
i=0;                                                //pongo a 0 la variabile 
e=0; 
 
PORTA =0;                                   //setta a 0 le porte A 
TRISA = 1;                                   //porte A come entrate 
PORTB = 0;                                 //setta a 0 le porte B 
TRISB = 0;                                   //setta le porte B come uscite 
for(;;) {                                          //inizio ciclo 
if(PORTA==0b00010)                 //verifica la pressione del tasto (RA1) 
  { 
   i++;                                           //incrementa la variabile di 1 
   if(i == 8)                                    //se la variabile è al massimo 
   i = 0;                                          //lo riporta a 0 
   PORTB=(step[i]);                    //pone a PORTB il valore puntato dalla variabile  
   DelayMs(asp);                         //pausa per settare la velocità del motore 
   while(PORTA==0b00010)       //attende il rilascio del tasto premuto 
   continue;                                   //continua se il tasto è stato rilasciato 
   } 
if(PORTA==0b00100)                 //altro tasto per il reverse (RA2) 
  { 
  PORTB=(step[i]); 
  i--; 
  if(i == -1)i = 7; 
 DelayMs(50); 
  while(PORTA==0b00100) 
  continue; 
  } 
if(PORTA==0b00001)               //verifica la pressione del tasto (RA0) 
 { 
 e++;                                          //incrementa la variabile di 1 
 if(e == 4)                                  //se la variabile è al massimo 
 e = 0;                                        //lo riporta a 0 
 PORTB=(step2[e]);                 //pone a PORTB il valore puntato dalla variabile  
 DelayMs(asp);                         //pausa per settare la velocità del motore 
 while(PORTA==0b00001)       //attende il rilascio del tasto premuto 
 continue; //continua se il tasto è stato rilasciato 
 } 
if(PORTA==0b01000) //altro tasto per il reverse (RA3) 
  { 
  PORTB=(step2[e]); 
  e--; 
  if(e == -1)e = 3; 
 DelayMs(50); 
 while(PORTA==0b01000) 
 continue; 
 } 
 
Cosa aggiungere oltre a questo???Ho passato il programma a Nicola per vedere se era ancora migliorabile. (ricordatevi che sono alle prime armi anche io).Da buon programmatore evoluto (e pignolo) lui mi rimanda il listato debitamente corretto e stravolto.Nella pagina successiva riporto il listato. 
 
/*************************** 
*** stepper unipolare ***  
*************************** 
* motore collegato alla porta B 
* tasti collegati alla porta A 
* (C)Sergio 29-03-2003 
**************************/ 
 
#include <pic.h> 
#include "delay.c" 
#define asp 50         //tempo di attesa in millisecondi 
                                //diminuire questo valore per aumentare la velocità 
int step[8] = {1, 3, 2, 6,4,12,8,9};    //array per i mezzi passiint  
step2[] = {1, 2, 4, 8};        //array per i passi interi 
 
main() 
signed char i, e;       // variabili indice 
 
PORTA = 0x00;     // azzera linee porta A 
PORTB = 0x00;     // azzera linee porta B 
TRISA = 0x0F;      // imposta linee porte A come ingressi 
TRISB = 0x000;    // imposta linee porte B come uscite 
 
i=0;                         // indice al primo elemento di step 
e=0;                        // indice al primo elemento di step2 
while (1) {              // ciclo infinito 
 while(PORTA == 0x01) {      // ciclo fin quando RA0 è down 
    e = (e+1) % 4;                    // modulo 4, ritorna un valore compreso tra 0 e 3 
    PORTB = step2[e]; // pone PORTB con valore i-mo di step2 
    DelayMs(asp); // aspetta timeout 
    } 
    while(PORTA == 0x02) {     // ciclo fin quando RA1 è down 
       i = (i+1) % 8;                     // modulo 8, ritorna un valore compreso tra 0 e 7 
       PORTB = step[i];              // pone PORTB con valore i-mo di step 
       DelayMs(asp);                  // aspetta timeout 
       } 
       while(PORTA == 0x04) {  // ciclo fin quando RA2 è down 
        i = (i-1) % 8;                     // modulo 8, ritorna un valore compreso tra 0 e 7 
        PORTB = step[i];             // pone PORTB con valore i-mo di step 
        DelayMs(asp);                 // aspetta timeout 
        
       while(PORTA == 0x08) {  // ciclo fin quando RA3 è down  
       e = (e-1) % 4; // modulo 4, ritorna un valore compreso tra 0 e 3 
       PORTB = step2[e]; // pone PORTB con valore i-mo di step2 
       DelayMs(asp); // aspetta timeout 
       } 
   } 
 
Cosa ha combinato Nicola???? Semplice, invece di utilizzare l'incremento per puntare l'array (la stringa dei valori), ha utilizzato un modulo. Andatevi a vedere sui vostri libri come si usa e capirete come Nicola ha reso più efficiente il programma (e anche più corto)
 
 
barra rossa2 
 
b_home2_baloon 
 
© 2002-2006 by Sergio Fiocco -Tutti i diritti riservati- Vietata la riproduzione, anche parziale del presente sito