Informações sobre o curso.
Motor de Passo
Controlando 8 motores de passo
Por: Antônio Rogério Messias
Página 1 de 1     Home  Índice  
CONTROLANDO 8 MOTORES DE PASSO SIMULTANEAMENTE ATRAVÉS DA PORTA PARALELA, USANDO SOMENTE 3 PINOS
Para uso particular ou educacional.
Copyright(c) 1999-2006 ROGERCOM.COM
Todos os direitos reservados.


       L
embra aquele projeto espetacular usando vários motores de passo que você engavetou anos atrás, por não dispor de mais pinos da Porta Paralela para controlá-los. Mesmo que você esteja cansado, desanimado sem motivação, arregace as mangas e vamos brincar com 8 motores de passo conectados à Porta Paralela, com o uso de apenas 3 pinos e o GND, ainda ficam disponíveis 9 pinos de saída e 5 de entrada. Se usar o modo EPP terá disponível 13 entradas e 1 saída. Está motivado agora?
       Com o projeto exposto neste artigo poderemos construir robôs, controlar câmeras ou quaisquer outros dispositivos controlados através de motores de passo.
       O circuito de interface com a Porta Paralela é o mesmo do artigo DSP32es, só que em vez dos 32 LEDs nas saídas iremos usar 4 drivers ULN 2803 para controlar os 8 motores de passo. Toda a lógica de controle será responsabilidade do software. O segredo do software está na manipulação adequada de bits, e para compreender seu funcionamento, é importante lembrarmos dos conceitos de bits, nibbles, bytes, operadores binários AND, OR e de deslocamento.
      Para aqueles que desejam pesquisar e estudar, o código fonte do programa está disponível para download. Para aqueles que só desejam testar o projeto, podem fazer o download do programa EXE.

A fonte de alimentação tem que fornecer corrente elétrica suficiente para alimentar a soma do consumo de corrente de todos os motores de passo, mais os demais componentes do circuito.
       Se cada motor consome 200mA, a fonte tem que suprir no mínimo 8 x 200mA = 1,6A. Nesse caso seria interessante uma fonte de 2A.
       Observe também que cada ULN 2803 pode alimentar um motor que consuma até 500mA ou 2 motores que consumam cada um, 250mA. Motores que consomem mais que 500mA não podem ser ligados ao CI ULN 2803.

Artigos relacionados:

Controle de 32 saídas através da Porta Paralela (DSP32es)
Controle de Motor de passo (LPTMOTOR)

Figura 1 - Mapa dos bytes e nibbles

       Na figura acima temos um valor de 32 bits (FFFFFF) expresso no sistema hexadecimal. Observe que cada dígito no sistema hexadecimal representa 4 bits no sistema binário, ou seja, 1 nibble. Portanto, com um hardware que disponha de 32 saídas, poderemos controlar até 8 motores de passo associando 4 saídas de controle para cada um.
       Veja na figura abaixo a associação dos motores de passo aos seus respectivos nibbles numa variável de 32 bits.

Figura 2 - Associação dos Motores de Passo numa variável de 32 bits sub-dividida em Nibbles

       Cada bit na variável está associado a uma respectiva saída no circuito que irá controlar os motores de passo. Um bit com um nível lógico '1' ativa uma bobina e um bit com nível '0' desativa.
       O segredo para se controlar qualquer um dos oito motores de passo sem que um comando enviado para a Porta Paralela interfira no funcionamento dos outros, está na correta manipulação dos bits da variável de controle de 32 bits, com auxílio dos operadores bit-a-bit AND, OR e de deslocamento, disponíveis em algumas linguagens de programação.

Figura 3 - Desligando os bits de um único Nibble numa variável de 32 bits

       Imaginem que desejássemos desligar somente os bits do nibble 4 associado ao Motor 4, numa variável de 32 bits sem que os outros bits fossem alterados. Uma solução bastante prática seria criar uma máscara de 32 bits, todos com níveis lógico '1', exceto os 4 bits do nibble 4, que ficarão todos em nível '0'. Usando um operador bit-a-bit AND entre o valor original e a máscara de bits, teremos um resultado onde somente o nibble 4 será alterado. Para entendermos porque somente o nibble 4 no resultado foi alterado, façam uma multiplicação de cada bit da máscara pelos respectivos bits do valor original e compare-o com o resultado. Observará que somente o nibble 4 foi modificado. Portanto, o operador bit-a-bit AND numa primeira etapa, operando com uma máscara de bits pré-determinados e uma variável, terá a finalidade de desligar bits.

Figura 4 - Ligando um único bit em um Nibble numa variável de 32 bits

       Agora que temos o resultado da operação AND, com o nibble 4 zerado, poderemos ligar qualquer um dos 4 bits do nibble 4 usando o operador bit-a-bit OR operando um dos valores: 1, 2, 4 e 8 relacionados aos controles dos passos do motor.

Tabela 1 - Passo Completo 1 (Full-step)
Nº do
passo
B3
B2
B1
B0
Decimal
1-->
1
0
0
0
8
2-->
0
1
0
0
4
3-->
0
0
1
0
2
4-->
0
0
0
1
1


       Para ligarmos a primeira bobina do motor 4, deveremos adicionar o número 1 (00000001)bin., na posição do nibble 4 da variável de 32 bits; para a segunda bobina, o valor 2 (00000010)bin.; para a terceira, o valor 4 (00000100)bin.; e para a quarta e última, o valor 8 (00001000)bin. Como esses valores estão posicionados no primeiro nibble de cada byte de controle de passo, e desejamos manipular somente o quarto nibble associado ao motor 4, teremos que fazer um deslocamento de 12 bits à esquerda para colocarmos o valor do primeiro passo no quarto nibble da máscara, conforme mostra a Figura 4.

       A animação abaixo mostra os 4 bits associados com as bobinas do motor 4.

Figura 5 - Alternando os bits do Nibble 4 associado ao Motor 4

       Na animação acima vemos a seqüência de passos para girar o motor 4. Em um determinado instante o valor do nibble 4 é 1 (0001)bin., depois 2 (0010)bin.,... 4 (0100)bin. e 8 (1000)bin. Depois a seqüência se repete e o motor gira continuamente. Observe que os outros bits não são modificados.
       Para manipular nibbles simultaneamente é só criar as máscaras associadas aos bits que deseja manipular.

       Na listagem do Fonte 1 está disponível o código fonte da função RotacionaMotor() que fará o controle dos 8 motores de passo. Esse código é somente um fragmento do programa, o código fonte completo do projeto poderá ser apreciado fazendo download no final desse artigo.

Fonte 1 - Função escrita em C/C++ para controle 8 motores de passo

//Função para controlar 8 Motores de passo através da Porta Paralela.
//Autor: Antonio Rogério Messias
//www.rogercom.com

//rogercom@rogercom.com

//Copyright(c) 1999-2004 ROGERCOM
//Todos os direitos reservados.

//-------------------------------------------------------------------------------------------------------------------------------------------------------

#define LPT1 0x378
//Mascaras para manipular somente os Nibbles de uma palavra de 32 bits.
#define MASK_NIBBLE_M1     0xFFFFFFF0
#define MASK_NIBBLE_M2     0xFFFFFF0F
#define MASK_NIBBLE_M3     0xFFFFF0FF
#define MASK_NIBBLE_M4     0xFFFF0FFF
#define MASK_NIBBLE_M5     0xFFF0FFFF
#define MASK_NIBBLE_M6     0xFF0FFFFF
#define MASK_NIBBLE_M7     0xF0FFFFFF
#define MASK_NIBBLE_M8     0x0FFFFFFF


//Variáveis globais.
unsigned __int32 Dados;
char Passos[] = {1, 2, 4, 8}; //Passos simples.
unsigned char MAXPASSO = 3; //Máximo de passos: 0 a 3.
//-------------------------------------------------------------------------------------------------------------------------------------------------------

//Função para enviar sinais para girar os motores
através da Porta Paralela.
unsigned __int32 RotacionaMotor(unsigned __int32 BitsDados, int NumMotor, char Direcao)
{
   static short int IndexM1,IndexM2,IndexM3,IndexM4;
   static short int IndexM5,IndexM6,IndexM7,IndexM8;
   String StBin; //Para armazenar a conversção da string binária.

   if( Direcao == 'D' ) //Direita - Hórário.
   {
      switch( NumMotor ) //Escolhe qual o motor será girado.
      {
         case 1: if(IndexM1 > 0)
                        IndexM1--;
                     else
                        IndexM1 =
MAXPASSO;

                     AnimaMotor1(IndexM1);
                     BitsDados = ( Passos[IndexM1] ) | (BitsDados & MASK_NIBBLE_M1);
                     break;

         case 2: if(IndexM2 > 0)
                        IndexM2--;
                     else
                        IndexM2 =
MAXPASSO;

                     AnimaMotor2(IndexM2);
                     BitsDados = ( Passos[IndexM2]<<4 ) | (BitsDados & MASK_NIBBLE_M2);
                     break;
         case 3: if(IndexM3 > 0)
                        IndexM3--;
                     else
                        IndexM3 =
MAXPASSO;
  
                     AnimaMotor3(IndexM3);
                     BitsDados = ( Passos[IndexM3]<<8 ) | (BitsDados & MASK_NIBBLE_M3);
                     break;
         case 4: if(IndexM4 > 0)
                        IndexM4--;
                     else
                        IndexM4 =
MAXPASSO;

                     AnimaMotor4(IndexM4);
                     BitsDados = ( Passos[IndexM4]<<12 ) | (BitsDados & MASK_NIBBLE_M4);
                     break;

         case 5: if(IndexM5 > 0)
                        IndexM5--;
                     else
                        IndexM5 =
MAXPASSO;

                     AnimaMotor5(IndexM5);
                     BitsDados = ( Passos[IndexM5]<<16 ) | (BitsDados & MASK_NIBBLE_M5);
                     break;
         case 6: if(IndexM6 > 0)
                        IndexM6--;
                     else
                        IndexM6 =
MAXPASSO;

                     AnimaMotor6(IndexM6);
                     BitsDados = ( Passos[IndexM6]<<20 ) | (BitsDados & MASK_NIBBLE_M6);
                     break;
         case 7: if(IndexM7 > 0)
                        IndexM7--;
                     else
                        IndexM7 =
MAXPASSO;

                     AnimaMotor7(IndexM7);
                     BitsDados = ( Passos[IndexM7]<<24 ) | (BitsDados & MASK_NIBBLE_M7);
                     break;
         case 8: if(IndexM8 > 0)
                        IndexM8--;
                     else
                        IndexM8 =
MAXPASSO;

                     AnimaMotor8(IndexM8);
                     BitsDados = ( Passos[IndexM8]<<28 ) | (BitsDados & MASK_NIBBLE_M8);
                     break;
      }

   }else if( Direcao == 'E' ) //Esquerda - Anti-horário.
   {
      switch( NumMotor )
      {
         case 1: if(IndexM1 <
MAXPASSO)
                        IndexM1++;
                     else
                        IndexM1 = 0;

                     AnimaMotor1(IndexM1);
                     BitsDados = ( Passos[IndexM1] ) | (BitsDados & MASK_NIBBLE_M1);
                     break;
         case 2: if(IndexM2 <
MAXPASSO)
                        IndexM2++;
                     else
                        IndexM2 = 0;

                     AnimaMotor2(IndexM2);
                     BitsDados = ( Passos[IndexM2]<<4 ) | (BitsDados & MASK_NIBBLE_M2);
                     break;
         case 3: if(IndexM3 <
MAXPASSO)
                        IndexM3++;
                     else
                        IndexM3 = 0;

                     AnimaMotor3(IndexM3);
                     BitsDados = ( Passos[IndexM3]<<8 ) | (BitsDados & MASK_NIBBLE_M3);
                     break;
         case 4: if(IndexM4 <
MAXPASSO)
                         IndexM4++;
                     else
                         IndexM4 = 0;

                     AnimaMotor4(IndexM4);
                     BitsDados = ( Passos[IndexM4]<<12 ) | (BitsDados & MASK_NIBBLE_M4);
                     break;
         case 5: if(IndexM5 <
MAXPASSO)
                        IndexM5++;
                     else
                        IndexM5 = 0;

                     AnimaMotor5(IndexM5);
                     BitsDados = ( Passos[IndexM5]<<16 ) | (BitsDados & MASK_NIBBLE_M5);
                     break;
         case 6: if(IndexM6 <
MAXPASSO)
                        IndexM6++;
                     else
                        IndexM6 = 0;

                     AnimaMotor6(IndexM6);
                     BitsDados = ( Passos[IndexM6]<<20 ) | (BitsDados & MASK_NIBBLE_M6);
                     break;
         case 7: if(IndexM7 <
MAXPASSO)
                        IndexM7++;
                     else
                        IndexM7 = 0;      

                     AnimaMotor7(IndexM7);
                     BitsDados = ( Passos[IndexM7]<<24 ) | (BitsDados & MASK_NIBBLE_M7);
                     break;
         case 8: if(IndexM8 <
MAXPASSO)
                        IndexM8++;
                     else
                        IndexM8 = 0;

                     AnimaMotor8(IndexM8);
                     BitsDados = ( Passos[IndexM8]<<28 ) | (BitsDados & MASK_NIBBLE_M8);
                     break;
      }
   }

   Outport32(LPT1, BitsDados); //Envia os bits de controle para a porta paralela.

   StBin = StrBin32(BitsDados); //Converte inteiro em string binario.
   //Extrai cada Nibble e mostra na tela em binário.
   Form1->LabelNibbleM8->Caption = StBin.SubString(1, 4);
   Form1->LabelNibbleM7->Caption = StBin.SubString(5, 4);
   Form1->LabelNibbleM6->Caption = StBin.SubString(9, 4);
   Form1->LabelNibbleM5->Caption = StBin.SubString(13, 4);
   Form1->LabelNibbleM4->Caption = StBin.SubString(17, 4);
   Form1->LabelNibbleM3->Caption = StBin.SubString(21, 4);
   Form1->LabelNibbleM2->Caption = StBin.SubString(25, 4);
   Form1->LabelNibbleM1->Caption = StBin.SubString(29, 4);

   return(BitsDados);
}


      Na figura abaixo temos o esquema do driver que controlará os 8 motores de passo. As entradas (S1 a S32) desse dirver deverão ser conectadas as respectivas saídas do circuito 5 disponível no artigo DSP32es sem a utilização dos LEDs.

Figura 6 - Driver usando 4 CI ULN 2803 para controlar os 8 Motores de Passo

       Os CI ULN 2803 só pode fornecer 500mA nas suas 8 saídas, portanto, para que o circuito funcione sem dificuldades é necessário que o consumo de cada motor seja igual ou inferior a 250mA Para alimentar todo o circuito utilize uma fonte de alimentação de 12v/2A.

Figura 7 - Tela do programa LPT8M para controlar os 8 Motores de Passo

       Com o programa mostrado na figura acima, poderemos controlar cada motor de passo independentemente, de forma manual ou automática.
       O controle da velocidade é geral para todos os motores.

Downloads dos arquivos fonte e programas apresentados neste artigo:

Download do LPT8M.exe Programa executável (LPT8M.exe).

Download do projeto LPT8M. Código fonte do programa Projeto-LPT8M escrito em C/C++. (para análises, estudos e pesquisas).

 


Volta à página principal. 
 

Índice dos artigos.

http://www.rogercom.com
© Copyright, 1999-2006 ROGERCOM - Antonio Rogério Messias - rogercom@rogercom.com
Todos os Direitos Reservados - All Rights Reserved.