Para disminuir el riesgo de daños al puerto de control y mejorar la capacidad de manejo de corriente que necesita el motor se puede utilizar una etapa de desacoplo.
![]() |
Mediante relés |
Se podría pensar en utilizar directamente relés conectados al puerto tal como se sugiere en la figura siguiente; en ella se utilizan las dos primeras líneas de datos con la intención de activarlos, y hacer girar el motor en sentido horario o antihorario dependiendo de los valores alto o bajo de las líneas 2 y 3 (es decir, valores 0 o 1 de los bits D0 y D1 del registro de datos).
Desafortunadamente, la corriente que proporcionan las líneas del puerto no es suficiente para permitir la conmutación de los relés mecánicos habituales. Así pues, es preciso poner alguna etapa intermedia de transistores entre la salida del puerto y el relé correspondiente, que sea capaz de excitar a éste. Por ejemplo, como se muestra en la figura siguiente:
![]() |
Mediante módulos optoacoplados con salidas a relé |
Una solución que se encuentra disponible comercialmente, consiste en utilizar una interfaz de módulos optoacoplados de salidas a relé. A través de optoacopladores, un módulo como el T-1 (de 4 E/S, aunque también existen de 1,2 y 8 E/S) aísla eléctricamente las señales de control de cada entrada.
Módulo optoacoplado T-1 con salidas a relé
Esquema del optoacoplador situado entre las entradas y los relés
Al inyectar sobre cualquier entrada una señal entre 3 y 24 V c.c., la correspondiente salida se activa, permaneciendo en ese estado hasta que la tensión de entrada baja a 0. El módulo incorpora LEDs señalizadores.
Las entradas se pueden conectar a las líneas de datos del puerto paralelo para gobernar un motor c.c.
![]() |
Mediante transistores |
Una alternativa simple a la interfase anterior consiste en utilizar un circuito como el de la figura siguiente.
En éste se utilizan transistores para la etapa de potencia del motor. Cuando el bit D0 se pone a 0 y el D1 a 1, el borne izquierdo del motor se encuentra a +6V y el derecho a tierra, con lo que el motor gira en un sentido. Cuando el bit D0 vale 1 y el D1 0, es el borne derecho el que está alimentado mientras que el izquierdo se halla conectado a tierra, de modo que el motor gira en sentido opuesto.
Una de las ventajas de esta interfaz frente a las precedentes (con relés y optoacopladores) radica en que si las señales de control conmutan a frecuencia elevada, los transistores son capaces de seguirlas, mientras que los relés ya no lo hacen cuando el período de la conmutación se halla en torno a los milisegundos.
Los principios básicos de funcionamiento de motores P-P se detallan en la sección Motores paso a paso. A continuación se ofrecen algunas nociones prácticas sobre identificación y control de este tipo de motores.
![]() |
Identificación del motor P-P |
Cuando se trabaja con motores P-P usados o bien nuevos, pero de los cuales no tenemos hojas de datos es posible averiguar la distribución de los cables a los bobinados y el cable común en un motor de pasos unipolar de 5 o 6 cables siguiendo las instrucciones que se detallan a continuación:
1. Aislando el(los) cable(s) común(es) a la fuente de alimentación: Como se aprecia en las figuras anteriores, en el caso de motores con 6 cables, estos poseen dos cables comunes, pero generalmente tienen el mismo color, de modo que lo mejor es unirlos antes de comenzar las pruebas.
Usando un multímetro para chequear la resistencia entre pares de cables, el cable común será el único que tenga la mitad del valor de la resistencia entre ella y el resto de los cables. Esto es debido a que el cable común tiene una bobina entre él y cualquier otro cable, mientras que cada uno de los otros cables tienen dos bobinas entre ellos. De ahí la mitad de la resistencia medida en el mismo.
2. Identificando los cables de las bobinas (A, B, C y D): aplicar un voltaje al cable común (generalmente 12 V, pero puede ser más o menos) y manteniendo uno de los otros cables a masa (GND) mientras vamos poniendo a masa cada uno de los demás cables de forma alternada y observando los resultados. El proceso se puede apreciar en el siguiente cuadro:
Seleccionar un cable y conectarlo a masa. Ese será llamado cable A. |
|
Manteniendo el cable A conectado a masa, probar cuál de los tres cables restantes provoca un paso en sentido antihorario al ser conectado también a masa. Ese será el cable B. |
|
Manteniendo el cable A conectado a masa, probar cuál de los dos cables restantes provoca un paso en sentido horario al ser conectado a masa. Ese será el cable D. |
|
El último cable debería ser el cable C. Para comprobarlo, basta con conectarlo a masa, lo que no debería generar movimiento alguno debido a que es la bobina opuesta a la A. |
|
Nota: La nomenclatura de los cables (A, B, C, D) es totalmente arbitraria.
Observaciones:
![]() |
Interfase de conexión del motor P-P |
En la figura siguiente podemos observar un ejemplo de conexionado para controlar un motor paso a paso unipolar mediante el uso de cuatro transistores que actúan como etapa de potencia:
Si las bases de los cuatro transistores se conectan a cuatro de las líneas de datos del puerto paralelo, el motor puede ser controlado desde el PC.
Sin embargo, nos centraremos en un circuito de control más compacto. Vamos a controlar un pequeño motor P-P unipolar de cuatro fases RS351-4574 (similar, por ejemplo, al motor KP4M4-001 que llevan algunas de las disqueteras antiguas de 5¼). Tiene seis cables externos, dos de común y cuatro de fases. Su consumo está en torno a los 180 mA, con un par de retención máximo de 2.5 Ncm, y utiliza una tensión de trabajo de 12V.
Cableado externo del motor RS351-4574
El puerto paralelo trabaja a 5V y, como máximo, a 20mA, por lo que no podemos conectar el motor directamente directamente. Para ello utilizaremos un circuito interfase entre el motor y el puerto que será el encargado de aumentar la potencia de nuestro puerto paralelo. Está basado en el integrado ULN2003, un driver Darlington de 7-bit, 500mA, entrada TTL npn, y su conexión es tan sencilla como indica el siguiente esquema:
El diodo Zener se utiliza como medida de protección contra las inducciones que se producen en los bobinados, evitando así las fuertes corriente inversas generadas. El zener es de 12V, 0.5W. El integrado acepta un consumo máximo de 500mA por lo que no será capaz de controlar nada que supere dicho consumo. Para un entendimiento más global, el integrado se comporta como una serie de 7 relés electrónicos.
Por el puerto paralelo del PC podemos enviar 1 Byte cada vez a una velocidad de aproximadamente a 30 kBytes por segundo, mucho más de lo que es capaz de girar un motor de estas características, por lo que deberemos frenar el envío de datos. La filosofía de control no es más compleja que la de tener que encender y apagar diodos LED mediante software.
Para controlar un servomotor es preciso contar con la circuitería que lleve cabo la modulación de anchura de pulso que éste precisa. Un ejemplo de interfaz de puerto paralelo que realiza esta función figura en el esquema siguiente:
Sin embargo en nuestro caso, con objeto de realizar un control programado directo a través del puerto paralelo, prescindiremos de dicha circuitería y generaremos por software los pulsos de anchura requerida. Esto simplifica notablemente el hardware pero requiere la ocupación del microprocesador del PC. Planteado de esta manera, el problema se puede resolver utilizando para controlar al servo una interfaz muy similar a la interfaz de transistores utilizada para el control de un motor c.c. Ahora se conecta el cable V+ del servo a los colectores de los transistores (activados mediante el bit D0 -pin 2-) y la línea de control al bit D1 (pin 3). Es en esta última línea donde se aplicarán los pulsos modulados en anchura para posicionar al servo.
Interfaz simple para controlar el servomotor desde el puerto paralelo
Servo Hitec HS-300
![]() |
Par |
3 kg-cm a 4.8 V / 3.5 kg-cm a 6 V |
Intervalo angular de operación | 0º-210º | |
Velocidad |
0.19 s / 60° a 4.8 V / 0.16 s/60º a 6 V |
|
Voltaje |
4.8 - 6 VDC |
|
Corriente |
140 mA (operación) / 20 mA (stand by) |
|
Pulso posición neutra |
1500 µs |
|
Pulso ángulo máx. |
2500 µs |
|
Pulso ángulo mín. |
500 µs |
|
Tamaño | 40 x 20 x 36 mm | |
Peso | 44.5 g | |
Cableado | +V (rojo), GND (negro), Control (amarillo) |
Ejemplo: supongamos que queremos mover el servo Hitec HS-300 a 30º desde la posición neutra.
Calculemos la anchura del pulso necesaria:
0º → 0.5 ms
180º → 2.5 ms
=> según una relación lineal, para 30º → 0.5 ms +30 ·(2.5-0.5)/180 ms = 0.833 ms.
Así, si seguimos enviándole pulsos de 0.833 ms, lo posicionaremos en 30º. Si hay una fuerza externa que intenta bloqueado, el servo intentará resistir activamente (es decir, sí el brazo se mueve externamente, el servo dará entradas al motor para corregir el error).También es posible dejar de enviar pulsos después que el servo se ha movido a su posición. Si dejamos de enviar pulsos por más de 50 ms (dependiendo del servo), este podría caerse. Esto significa, que este no estaría aplicando ninguna entrada al motor, o activamente resistiendo fuerzas externas; solamente la fricción sostendrá el brazo (del servo) en su lugar.
Servo Futaba FP-S148
|
Par |
42 Oz-in / 3024 g-cm |
Velocidad |
0.22 s / 60° |
|
Voltaje |
4.8 - 6 VDC |
|
Corriente |
8mA @ 6V (idle) |
|
Pulso posición neutra |
1250 µs* |
|
Pulso ángulo máx. |
2200 µs* |
|
Pulso ángulo mín. |
220 µs* |
|
Peso |
1.5 Oz (44.4 g) |
|
Cableado |
+V (rojo), GND (negro), Control (blanco) |
* Números deducidos empíricamente. Cámbiense si se detecta un zumbido.
Una versión muy popular de un circuito conversor D/A (digital-analógico) para ser usado con el puerto paralelo es la representada en el siguiente esquema:
Móntese la interfaz de transistores para conectar un motor c.c al puerto paralelo. Realícese un programa que ordene al motor desplazarse en sentidos horario y antihorario.
Solución:
QBasic:
' MOTOR_CC.BAS ' ' CONTROL DE ACTUADORES Y SENSORES MEDIANTE PUERTO PARALELO ' ' Control de un motor de c.c. ' Motor conectado a los 2 primeros pines de datos mediante una ' etapa de potencia (transistores TIP125-120) ' + - ' D0 --- (etapa) --- M --- (etapa) --- D1 ' 2002 Víctor R. González DECLARE SUB Activa (valor%) ' Direcciones del puerto paralelo CONST LPTBASE = &H378 CONST DATOS = LPTBASE CONST ESTADO = LPTBASE + 1 CONST CONTROL = LPTBASE + 2 ' Valores que activan el giro y la parada del motor CONST APAGA.MOTOR = &H3 ' D0=1 (pin2), D1=1 (pin 3) CONST GIRO.HORARIO = &H2 ' D0=0 (pin2), D1=1 (pin 3) CONST GIRO.ANTIHORARIO = &H1 ' D0=1 (pin2), D1=0 (pin 3) DIM tecla$ DIM pos.x AS INTEGER, pos.y AS INTEGER Activa APAGA.MOTOR CLS PRINT "Control de un motor c.c.:" PRINT " - = giro en sentido horario" PRINT " + = giro en sentido antihorario" PRINT " p = parada" PRINT " s = salir" PRINT pos.x = POS(0): pos.y = CSRLIN DO LOCATE pos.y, pos.x tecla$ = INKEY$ SELECT CASE tecla$ CASE "+" ' Giro en sentido antihorario PRINT "... giro antihorario ..." Activa GIRO.ANTIHORARIO CASE "-" ' Giro en sentido horario PRINT "... giro horario ... " Activa GIRO.HORARIO CASE "p" ' Parada PRINT "... detenido ... " Activa APAGA.MOTOR CASE "s" ' Salir END SELECT LOOP UNTIL tecla$ = "s" Activa APAGA.MOTOR END ' Envía un valor al puerto de datos SUB Activa (valor%) OUT DATOS, valor% END SUB
TurboC:
/* MOTOR_CC.C CONTROL DE ACTUADORES Y SENSORES MEDIANTE PUERTO PARALELO Control de un MOTOR de C.C. Motor conectado a los 2 primeros pines de datos mediante una etapa de potencia (transistores TIP125-120) + - D0 --- (etapa) --- M --- (etapa) --- D1 2002 Víctor R. González */ #include <stdio.h> #include <dos.h> #include <conio.h> /* Direcciones del puerto paralelo */ #define LPT_BASE 0x378 #define DATOS LPT_BASE #define ESTADO LPT_BASE+1 #define CONTROL LPT_BASE+2 /* Valores que activan el giro y la parada del motor */ #define APAGA_MOTOR 0x03 /* D0=1 (pin2), D1=1 (pin 3) */ #define GIRO_HORARIO 0x02 /* D0=0 (pin2), D1=1 (pin 3) */ #define GIRO_ANTIHORARIO 0x01 /* D0=1 (pin2), D1=0 (pin 3) */ /* Macro que envía un valor al puerto de DATOS */ #define Activa(valor) outportb (DATOS, valor) main () { unsigned tecla, pos_x, pos_y; Activa(APAGA_MOTOR); /* Comienza con el motor detenido */ printf("Control de un motor c.c.:\n"); printf("\t - = giro en sentido horario\n"); printf("\t + = giro en sentido antihorario\n"); printf("\t p = parada\n"); printf("\t s = salir\n\n"); pos_x = wherex(); pos_y = wherey(); tecla = 0; do { if ( kbhit() ) tecla = getch(); gotoxy(pos_x, pos_y); switch (tecla) { case '+': /* Giro en sentido antihorario */ printf("\t... giro antihorario ..."); Activa(GIRO_ANTIHORARIO); break; case '-': /* Giro en sentido horario */ printf("\t... giro horario ... "); Activa(GIRO_HORARIO); break; case 'p': /* Parada */ printf("\t... detenido ... "); Activa(APAGA_MOTOR); break; } } while (tecla != 's'); printf("\n"); Activa(APAGA_MOTOR); /* Detiene el motor si no lo estaba ya */ return 0; } |
Móntese la interfaz de control de un motor paso a paso unipolar de 4 fases mediante puerto paralelo. Realícese un programa en TurboC que ordene al motor girar un número de pasos elegido mediante teclado según una secuencia de paso completo doble.
Solución:
/* MOTOR_PP.C CONTROL DE ACTUADORES Y SENSORES MEDIANTE PUERTO PARALELO Control de un MOTOR PASO A PASO. Bobinas del motor conectadas a los cuatro primeros pines de datos mediante una etapa de potencia (ULN2003). D0 ----- (3 -ULN2003- 14) ------------- MOTOR (BOB. A) D1 ----- (4 -ULN2003- 13) ------------- MOTOR (BOB. B) D2 ----- (5 -ULN2003- 12) ------------- MOTOR (BOB. C) D3 ----- (6 -ULN2003- 11) ------------- MOTOR (BOB. D) GND ---- (8 -ULN2003- 9) --- Zener --- MOTOR COMÚN --- +12 V 2002 Víctor R. González */ #include <stdio.h> #include <dos.h> /* Direcciones del puerto paralelo */ #define LPT_BASE 0x378 #define DATOS LPT_BASE #define ESTADO LPT_BASE+1 #define CONTROL LPT_BASE+2 /* Activación bobinas motor paso a paso */ #define BOBINA_A 0x01 /* Activa bobina A (amarillo-RS351-4574 / negro-RS440-290) */ #define BOBINA_B 0x02 /* Activa bobina B (marrón -RS351-4574 / azul -RS440-290) */ #define BOBINA_C 0x04 /* Activa bobina C (naranja -RS351-4574 / verde-RS440-290) */ #define BOBINA_D 0x08 /* Activa bobina D (negro -RS351-4574 / rojo -RS440-290) */ #define BOBINA_COM /* Común bobinas (rojo+verde-RS351-4574 / blanco+blanco-RS440-290 */ #define APAGA_MOTOR 0x00 /* Bobinas desactivadas */ #define PAUSA_PASO 10 /* Espera (en ms) entre pasos */ #define HORARIO 0 /* Sentidos de giro */ #define ANTIHORARIO 1 /* Macro que envía un valor al puerto de DATOS */ #define Activa(valor) outportb (DATOS, valor) void motor_pasos (unsigned num_pasos, unsigned sentido); main () { unsigned num_pasos; printf("Control de motor paso a paso:\n"); Activa (APAGA_MOTOR); /* Comienza con el motor detenido */ do { printf("\tIntroduce número de pasos (0=salir): "); scanf("%u", &num_pasos); if (num_pasos > 0) { /* Secuencia de paso completo doble */ printf("\tSecuencia de paso completo doble:\n"); printf("\t\t... sentido horario ...\n"); motor_pasos(num_pasos, HORARIO); Activa(APAGA_MOTOR); delay (1000); printf("\t\t... sentido antihorario ...\n"); motor_pasos(num_pasos, ANTIHORARIO); Activa(APAGA_MOTOR); } } while (num_pasos > 0); return 0; } /* Hace girar un motor paso a paso según una secuencia de paso completo doble */ void motor_pasos (unsigned num_pasos, unsigned sentido) { unsigned bobinas[][4] = { { /* secuencia para giro horario */ BOBINA_A | BOBINA_B, BOBINA_B | BOBINA_C, BOBINA_C | BOBINA_D, BOBINA_D | BOBINA_A }, { /* secuencia para giro antihorario */ BOBINA_D | BOBINA_A, BOBINA_C | BOBINA_D, BOBINA_B | BOBINA_C, BOBINA_A | BOBINA_B } }; unsigned paso; for (paso=0; paso<num_pasos; paso++) { Activa ( bobinas[sentido][paso % 4] ); delay(PAUSA_PASO); } } |
Realícese un programa en Turbo C que ordene al motor realizar una revolución completa en sentido horario y otra en sentido antihorario según una secuencia de paso completo básica y según una secuencia de medio paso.
Móntese la interfaz para conectar un servomotor al puerto paralelo. Realícese un programa en Turbo C que ordene al servo desplazarse a cualquier posición angular entre sus posiciones extremas.
Solución:
/* SERVO.C CONTROL DE ACTUADORES Y SENSORES MEDIANTE PUERTO PARALELO Control de un SERVOMOTOR. Alimentación del servo conectada al primer pin de datos mediante una etapa de potencia (transistores npn). Línea de control del servo conectada directamente al segundo pin de datos + D0 --- (etapa) ---- SERVO ------- D1 | ctrl GND ------------------| - 2002 Víctor R. González */ #include <stdio.h> #include <dos.h> /* Direcciones del puerto paralelo */ #define LPT_BASE 0x378 #define DATOS LPT_BASE #define ESTADO LPT_BASE+1 #define CONTROL LPT_BASE+2 /* Posiciones angulares del servo (Hitec HS-300) */ #define ANG_MIN 0. /* posición angular mínima (º) */ #define ANG_NEUTRO 90. /* posición angular neutra (º) */ #define ANG_MAX 180. /* posición angular máxima (º) */ #define PULSO_MIN 500. /* tiempo (en us) de pulso de control para 0 º */ #define PULSO_NEUTRO 1500. /* tiempo (en us) de pulso de control para 90 º */ #define PULSO_MAX 2500. /* tiempo (en us) de pulso de control para 180 º */ #define PULSO_OFF 20000. /* tiempo (en us) de pulso de control en OFF */ #define APAGA_SERVO 0x01 /* D0 alto (pin 2) alimentación del servo */ #define ENCIENDE_SERVO 0x00 /* D0 bajo (pin 2) alimentación del servo */ #define CONTROL_SERVO 0x04 /* D2 alto (pin 4) control del servo */ /* Para retardos de precisión */ #define us_CUENTA 15.086 /* nº de microsegundos por cuenta */ /* Macro que envía un valor al puerto de DATOS */ #define Activa(valor) outportb (DATOS, valor) /* Envía pulsos PWM al servo */ void servo_pulsos (float angulo, unsigned num_pulsos); /* Retardo de precisión */ void pausa (unsigned long); void main (void) { float angulo; unsigned num_pulsos; printf("Control de un servomotor:\n"); Activa (ENCIENDE_SERVO); /* Alimenta el servo */ do { printf ("\tIntroduce la posición angular final del servo: "); scanf ("%f", &angulo); printf ("\tIntroduce el número de pulsos de control (0=salir): "); scanf ("%u", &num_pulsos); if (num_pulsos >0) servo_pulsos (angulo, num_pulsos); } while (num_pulsos > 0); Activa (APAGA_SERVO); /* Apaga la alimentación del servo */ } /* Posiciona un servomotor en el ángulo requerido */ void servo_pulsos (float angulo, unsigned num_pulsos) { int pulso; float tiempo_pulso; unsigned long cuentas_pulso, cuentas_off; /* Duración del pulso */ tiempo_pulso = PULSO_MIN + angulo * (PULSO_MAX-PULSO_MIN) / (ANG_MAX-ANG_MIN); cuentas_pulso = tiempo_pulso / us_CUENTA; printf ("\t\t(Duración del pulso: %6.1f us, %u cuentas)\n", tiempo_pulso, cuentas_pulso); /* Duración (en cuentas) de pulso apagado */ cuentas_off = PULSO_OFF/us_CUENTA; for (pulso=1; pulso<num_pulsos; pulso++) { /* Activa la línea de control */ Activa (CONTROL_SERVO | ENCIENDE_SERVO); pausa (cuentas_pulso); /* Desactiva la línea de control */ Activa (ENCIENDE_SERVO); pausa (cuentas_off); } Activa (APAGA_SERVO); /* Apaga la alimentación del servo */ } /* Retardo de precisión El tiempo se mide en cuentas. Un segundo equivale a 66288 cuentas. Una cuenta equivale a 1/66287.78 s = 15.086 microsegundos. Ésta es la resolución temporal que se consigue con este método. */ void pausa (unsigned long cuenta) { register a = NULL, b; unsigned cuenta_h, cuenta_l; cuenta_h=cuenta >> 16; cuenta_l=cuenta & 0xFFFF; do do { while (a==(b=inportb(0x61) & 0x10)); a=b; } while (cuenta_l--); while (cuenta_h--); } |