Lembra 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:
Programa
executável (LPT8M.exe).
Código
fonte do programa Projeto-LPT8M escrito em C/C++.
(para análises, estudos e pesquisas).
|