|
|
|
![]() |
Lezione 5
Comandare un motore passo passo (progetto di David Facta)
|
|
|
|
|
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)
|
|
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)
|