Software de Control de Dos motores Paso a Paso por el Puerto Paralelo

Intentare dar una breve explicacion del software de control de motores paso a paso mediante el puerto paralelo de un PC.
Si ya hemos leido con atencion el apartado de motores paso a paso de mi pagina, tomamos como conclucion que la cosa solo se limita a enviar una secuencia de señales a un tiempo determinado para que el motor gire en un sentido u otro y a una velocidad u otra.
Pues bien, el programa lo unico que hace es tener almacenada en memoria la codificacion de señales que se indican abajo y enviarlas secuencialmente por el puerto paralelo con un retardo dado. Si tenemos claro los cuadros de abajo:
 
 Relacion entre los Bits de cada Byte enviado y los pins de la clavija del puerto paralelo:
 
PIN
D7
D6
D5
D4
D3
D1
D1
D0
BIT
7
6
5
4
3
2
1
0
 
 
Para controlar un motor PAP Unipolar de Cuatro Fases necesitamos enviar una secuencia de BYTES por el puerto paralelo de la siguiente forma:
 
BIT
7
6
5
4
3
2
1
0
 
BOBINADO
       
2
3
4
1
 
DEC
HEX
Pos0
0
0
0
0
0
0
0
1
1
0x01
Pos1
0
0
0
0
0
0
1
1
3
0x03
Pos2
0
0
0
0
0
0
1
0
2
0x02
Pos3
0
0
0
0
0
1
1
0
6
0x06
Pos4
0
0
0
0
0
1
0
0
4
0x05
Pos5
0
0
0
0
1
1
0
0
12
0x0C
Pos6
0
0
0
0
1
0
0
0
8
0x08
Pos7
0
0
0
0
1
0
0
1
9
0x09
 
Esto es solo para un motor, si queremos controlar dos, solo tenemos que utilizar tambien los bites del 4 al 7 con la misma codificacion que para los bites 0 a 3. como estamos trabajando en hexadecimal, solo tenemos que multiplicar el valor anterior por 16 y asi pasamos la codificacion de los bites 0 a 3 a los bites 4 a 7.
Pues bien, como no pretendo dar un curso de programacion en C, sino, explicar brevemente el algoritmo del programa de control de dos motores pap de forma sencilla, os adjunto el codigo fuente del programa para que podais ver las tripas del mismo...
 
 
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <conio.h>
#include <math.h>
#include <string.h>
/***** Declaracion de variables globales *****/
int           gaiPortInst[3]     = {0,0,0};
int           giPortID           = 0x378;
unsigned char gaucCharCodif[18];
unsigned long gaulPasos[2];                         /*Contador de los pasos del Motor*/
char          gcFileOpen         = '0';
FILE*         gflFileIH;
int           gaiTimeRet[2]      = {1,1};           /*Tiempo de retardo en milisegundos*/
/***** Declaracion de estructuras *****/
/***** Declaracion de Defines *****/
#define DEFMOTOFF ucFunMgMPAP(0,-1000)+ucFunMgMPAP(1,-1000)
/***** Declaracion de funciones *****/
int           iFunFindLPTPort (void);
void          vFunInitGVar    (int iModo);
unsigned char ucFunMgMPAP     (int iMotor, int iDir);
void          vFunError       (char *acMsg);
int           iFunMenu        (void);
void          vFunSetOrigen   (void);
int           fprCsplit       (char *strn, char sep, int pos, char *ret);
void          vLeeFich        (FILE *fin);
int           vMoveCarr       (int iDx, int iDy);
void          vMCKBhit        (void);
/**************************************************************************/
/***** FUNCION MAIN *****/
/**************************************************************************/
int main (int argc, char **argv) {
 int iT;
 printf("\n\nPROGRAMA CNCPAP2M (Francisco Pantano Rubiño 01/2000)");
 printf("\n\tControl de motores PasoAPaso por puerto paralelo\n");
 vFunInitGVar(2);                                        /*Inicializo las variables globales*/
 if (iFunFindLPTPort() == 0) {
  vFunError("No se ha encontrado LPT instalado en el PC");
 }
 iT = 0;
 while (gaiPortInst[iT] == 0) iT++;                      /*Busco el primer puerto LPT disponible*/
 giPortID = gaiPortInst[iT];
 for (iT = 0; iT < 3; iT++) {
  if (gaiPortInst[iT] != 0) {
 outportb(gaiPortInst[iT], DEFMOTOFF);                /*Pongo los motores a cero en todos los LPT's*/
  }
 }
 while (iFunMenu() != -1) {
  if (gcFileOpen == '0') {
 vFunError("No se ha encontrado canal abierto de datos de archivo...");
  }
  outportb(giPortID, DEFMOTOFF);                          /*Pongo los motores a cero*/
  vLeeFich(gflFileIH);                                    /*Lee el fichero y mueve los motores*/
  outportb(giPortID, DEFMOTOFF);                          /*Pongo los motores a cero*/
 }
 if (gcFileOpen == '1') {
  fclose (gflFileIH);
 }
 printf("\n\nSE HA FINALIZADO EL PROGRAMA CNCPAP2M (FPR 01/2000)");
 printf("\n\tPUERTO DE COMUNICACION: 0x%x", giPortID);
 printf("\n\tCONTADOR MOTOR 1: %lu"       , gaulPasos[0]);
 printf("\n\tCONTADOR MOTOR 2: %lu"       , gaulPasos[1]);
 printf("\n\tVELOCIDAD: %d,%d\n"          , gaiTimeRet[0], gaiTimeRet[1]);
 return (0);
}
/**************************************************************************/
/***** ALGORITMO DE FUNCIONES *****/
/**************************************************************************/
/*Busca los puertos paralelos instalados en el PC*/
int iFunFindLPTPort (void) {
 int iT;
 int iTmp = 0;
 unsigned uTmp;
 for (iT=0; iT<3; iT++) {
  uTmp = * (unsigned *) (0x408 + (iT * 2));
  if (uTmp != 0) {
 gaiPortInst[iT] = (int) uTmp;
 iTmp++;
 printf("\n\tEncontrado LPT%d en 0x%x", iTmp, uTmp);
  } else {
 gaiPortInst[iT] = 0;
  }
 }
 return (iTmp);
}
/*Inicializa las variables globales especiales*/
void vFunInitGVar (int iModo) {
 /*Inicializo El Vector de Codificacion de Pasos*/
  gaulPasos[0] = 2e9;                               /*Motor 0*/
  gaulPasos[1] = 2e9;                               /*Motor 1*/
 /*Inicializo El Vector de Codificacion de Pasos*/
 switch (iModo) {
 case 0: { /* SIMPLE activacion */
 /*Motor 0*/
  gaucCharCodif[0] = 0x01;        /*Posicion  1: 0001=0x1 ,invertido: 1110=0xe*/
  gaucCharCodif[1] = 0x02;        /*Posicion  3: 0010=0x2 ,invertido: 1101=0xd*/
  gaucCharCodif[2] = 0x04;        /*Posicion  5: 0100=0x4 ,invertido: 1011=0xb*/
  gaucCharCodif[3] = 0x08;        /*Posicion  7: 1000=0x8 ,invertido: 0111=0x7*/
  gaucCharCodif[4] = 0x01;        /*Posicion  1: 0001=0x1 ,invertido: 1110=0xe*/
  gaucCharCodif[5] = 0x02;        /*Posicion  3: 0010=0x2 ,invertido: 1101=0xd*/
  gaucCharCodif[6] = 0x04;        /*Posicion  5: 0100=0x4 ,invertido: 1011=0xb*/
  gaucCharCodif[7] = 0x08;        /*Posicion  7: 1000=0x8 ,invertido: 0111=0x7*/
  gaucCharCodif[8] = 0x00;        /*Posicion  0: 0000=0x0 ,invertido: 1111=0xf*/
 /*Motor 1*/
  gaucCharCodif[9] = 0x10;        /*Posicion  1: 0001=0x1 ,invertido: 1110=0xe*/
  gaucCharCodif[10]= 0x20;        /*Posicion  3: 0010=0x2 ,invertido: 1101=0xd*/
  gaucCharCodif[11]= 0x40;        /*Posicion  5: 0100=0x4 ,invertido: 1011=0xb*/
  gaucCharCodif[12]= 0x80;        /*Posicion  7: 1000=0x8 ,invertido: 0111=0x7*/
  gaucCharCodif[13]= 0x10;        /*Posicion  1: 0001=0x1 ,invertido: 1110=0xe*/
  gaucCharCodif[14]= 0x20;        /*Posicion  3: 0010=0x2 ,invertido: 1101=0xd*/
  gaucCharCodif[15]= 0x40;        /*Posicion  5: 0100=0x4 ,invertido: 1011=0xb*/
  gaucCharCodif[16]= 0x80;        /*Posicion  7: 1000=0x8 ,invertido: 0111=0x7*/
  gaucCharCodif[17]= 0x00;        /*Posicion  0: 0000=0x0 ,invertido: 1111=0xf*/
  break;
 }
 case 1: { /* DOBLE activacion */
 /*Motor 0*/
  gaucCharCodif[0] = 0x03;        /*Posicion  2: 0011=0x3 ,invertido: 1100=0xc*/
  gaucCharCodif[1] = 0x06;        /*Posicion  4: 0110=0x6 ,invertido: 1001=0x9*/
  gaucCharCodif[2] = 0x0c;        /*Posicion  6: 1100=0xc ,invertido: 0011=0x3*/
  gaucCharCodif[3] = 0x09;        /*Posicion  8: 1001=0x9 ,invertido: 0110=0x6*/
  gaucCharCodif[4] = 0x03;        /*Posicion  2: 0011=0x3 ,invertido: 1100=0xc*/
  gaucCharCodif[5] = 0x06;        /*Posicion  4: 0110=0x6 ,invertido: 1001=0x9*/
  gaucCharCodif[6] = 0x0c;        /*Posicion  6: 1100=0xc ,invertido: 0011=0x3*/
  gaucCharCodif[7] = 0x09;        /*Posicion  8: 1001=0x9 ,invertido: 0110=0x6*/
  gaucCharCodif[8] = 0x00;        /*Posicion  0: 0000=0x0 ,invertido: 1111=0xf*/
 /*Motor 1*/
  gaucCharCodif[9] = 0x30;        /*Posicion  2: 0011=0x3 ,invertido: 1100=0xc*/
  gaucCharCodif[10]= 0x60;        /*Posicion  4: 0110=0x6 ,invertido: 1001=0x9*/
  gaucCharCodif[11]= 0xc0;        /*Posicion  6: 1100=0xc ,invertido: 0011=0x3*/
  gaucCharCodif[12]= 0x90;        /*Posicion  8: 1001=0x9 ,invertido: 0110=0x6*/
  gaucCharCodif[13]= 0x30;        /*Posicion  2: 0011=0x3 ,invertido: 1100=0xc*/
  gaucCharCodif[14]= 0x60;        /*Posicion  4: 0110=0x6 ,invertido: 1001=0x9*/
  gaucCharCodif[15]= 0xc0;        /*Posicion  6: 1100=0xc ,invertido: 0011=0x3*/
  gaucCharCodif[16]= 0x90;        /*Posicion  8: 1001=0x9 ,invertido: 0110=0x6*/
  gaucCharCodif[17]= 0x00;        /*Posicion  0: 0000=0x0 ,invertido: 1111=0xf*/
  break;
 }
 case 2: { /* DOBLE+SIMPLE activacion */
 /*Motor 0*/
  gaucCharCodif[0] = 0x01;        /*Posicion  1: 0001=0x1 ,invertido: 1110=0xe*/
  gaucCharCodif[1] = 0x03;        /*Posicion  2: 0011=0x3 ,invertido: 1100=0xc*/
  gaucCharCodif[2] = 0x02;        /*Posicion  3: 0010=0x2 ,invertido: 1101=0xd*/
  gaucCharCodif[3] = 0x06;        /*Posicion  4: 0110=0x6 ,invertido: 1001=0x9*/
  gaucCharCodif[4] = 0x04;        /*Posicion  5: 0100=0x4 ,invertido: 1011=0xb*/
  gaucCharCodif[5] = 0x0c;        /*Posicion  6: 1100=0xc ,invertido: 0011=0x3*/
  gaucCharCodif[6] = 0x08;        /*Posicion  7: 1000=0x8 ,invertido: 0111=0x7*/
  gaucCharCodif[7] = 0x09;        /*Posicion  8: 1001=0x9 ,invertido: 0110=0x6*/
  gaucCharCodif[8] = 0x00;        /*Posicion  0: 0000=0x0 ,invertido: 1111=0xf*/
 /*Motor 1*/
  gaucCharCodif[9] = 0x10;        /*Posicion  1: 0001=0x1 ,invertido: 1110=0xe*/
  gaucCharCodif[10]= 0x30;        /*Posicion  2: 0011=0x3 ,invertido: 1100=0xc*/
  gaucCharCodif[11]= 0x20;        /*Posicion  3: 0010=0x2 ,invertido: 1101=0xd*/
  gaucCharCodif[12]= 0x60;        /*Posicion  4: 0110=0x6 ,invertido: 1001=0x9*/
  gaucCharCodif[13]= 0x40;        /*Posicion  5: 0100=0x4 ,invertido: 1011=0xb*/
  gaucCharCodif[14]= 0xc0;        /*Posicion  6: 1100=0xc ,invertido: 0011=0x3*/
  gaucCharCodif[15]= 0x80;        /*Posicion  7: 1000=0x8 ,invertido: 0111=0x7*/
  gaucCharCodif[16]= 0x90;        /*Posicion  8: 1001=0x9 ,invertido: 0110=0x6*/
  gaucCharCodif[17]= 0x00;        /*Posicion  0: 0000=0x0 ,invertido: 1111=0xf*/
  break;
 }
 default: {
  break;
 }
  }
}
/**************************************************************************/
/*Devuelve el caracter con la codificacion del paso para el motor iMotor*/
 /*Variable con las codificaciones de los polos -> gaucCharCodif[2,9]*/
 /*Variable con los contadores de los pasos     -> gaulPasos[motores]*/
unsigned char ucFunMgMPAP (int iMotor, int iDir) {
 if ((gaulPasos[iMotor]+iDir) < (unsigned long) 5000 ||
   (gaulPasos[iMotor]+iDir) > (unsigned long) 4e9) {
  printf("\n\tAVISO: Contador %d proximo a limite de rango", iMotor + 1);
  getchar();
 }
 if (iDir == -1000) {
  return (gaucCharCodif[iMotor * 9 + 8]);
 }
 gaulPasos[iMotor] += iDir;
 return (gaucCharCodif[iMotor * 9 + (int) (gaulPasos[iMotor] % 8)]);
}
/**************************************************************************/
/*Funcion de control de errores*/
void vFunError (char *acMsg) {
 printf("\n\nSE HA FINALIZADO EL PROGRAMA CNCPAP2M (FPR 01/2000)");
 printf("\n\tMENSAJE: %s", acMsg);
 if (gcFileOpen == '1') {
  fclose (gflFileIH);
 }
 outportb(giPortID, DEFMOTOFF);                          /*Pongo los motores a cero*/
 printf("\n\tPUERTO DE COMUNICACION: 0x%x", giPortID);
 printf("\n\tCONTADOR MOTOR 1: %lu"        , gaulPasos[0]);
 printf("\n\tCONTADOR MOTOR 2: %lu"        , gaulPasos[1]);
 printf("\n\tVELOCIDAD: %d,%d\n"          , gaiTimeRet[0], gaiTimeRet[1]);
 exit(0);
}
/**************************************************************************/
/*Configura las propiedades del ploter*/
int iFunMenu(void) {
 int  iT, iTT    = 0;
 int  iRet       = 0;
 char cT;
 char acTmp[80];
 char acTmp1[80];
 acTmp[0]='\0';
 for (iT = 0; iT < 3;iT++) {
  if (gaiPortInst[iT] != 0) {
 iTT++;
 if (iTT > 1) strcat(acTmp, ", ");
 itoa(iT + 1, acTmp1, 10);
 strcat(acTmp, acTmp1);
 strcat(acTmp, "->");
 sprintf(acTmp1,"0x%x", gaiPortInst[iT]);
 strcat(acTmp, acTmp1);
  }
 }
 while (iRet == 0) {
  printf ("\n\n\nMENU DE CONTROL DEL GESTOR DE MOTORES CNCPAP-2motores");
  printf ("\n\tEstablecer Puerto  (%s)", acTmp);
  printf ("\n\tModo de activacion (m)");
  printf ("\n\tFichero de datos   (f)");
  printf ("\n\tEstablecer Origen  (o)");
  printf ("\n\tVelocidad          (v)");
  printf ("\n\tEjecutar programa  (e)");
  printf ("\n\tSalir del programa (s)");
  printf ("\n\nEntrar Opcion: ");
  switch (getche()) {
 case '1': {
  if (gaiPortInst[0] != 0) {
   giPortID = gaiPortInst[0];
   printf("\n\nConfigurando Puerto de comunicacion LPT1");
  } else {
   printf("\n\nERROR: El puerto LPT1 no esta instalado en el PC");
  }
  break;
 }
 case '2': {
  if (gaiPortInst[1] != 0) {
   giPortID = gaiPortInst[1];
   printf("\n\nConfigurando Puerto de comunicacion LPT2");
  } else {
   printf("\n\nERROR: El puerto LPT2 no esta instalado en el PC");
  }
  break;
 }
 case '3': {
  if (gaiPortInst[2] != 0) {
   giPortID = gaiPortInst[2];
   printf("\n\nConfigurando Puerto de comunicacion LPT3");
  } else {
   printf("\n\nERROR: El puerto LPT3 no esta instalado en el PC");
  }
  break;
 }
 case 'm': {
  cT = 'f';
  while (cT != '0' && cT != '1' && cT != '2') {
   printf("\n\t\tEstableciendo Modo de activacion (0->S, 1->D, 2->S+D): ");
   cT = getche();
  }
  acTmp[0] = cT;
  acTmp[1] = '\0';
  iT = (int) atoi(acTmp);
  vFunInitGVar(iT);                                    /*Inicializo las variables globales*/
  break;
 }
 case 'f': {
  printf ("\nEspecificar Nombre del fichero: ");
  if (gcFileOpen == '1') {
   fclose (gflFileIH);
   gcFileOpen = '0';
  }
  scanf("%s",acTmp1);
  while ((gflFileIH = fopen(acTmp1, "r")) == NULL) {
   printf ("\nEspecificar Nombre del fichero: ");
   scanf("%s",acTmp1);
  }
  gcFileOpen = '1';
  break;
 }
 case 'o': {
  vFunSetOrigen();
  break;
 }
 case 'v': {
  printf("\n\t\tEstableciendo Velocidad (Ton ->RETURN): ");
  scanf("%s", acTmp);
  gaiTimeRet[0] = atoi(acTmp);
  printf("\n\t\tEstableciendo Velocidad (Toff ->RETURN): ");
  scanf("%s", acTmp);
  gaiTimeRet[1] = atoi(acTmp);
  if (gaiTimeRet[0] < 1) gaiTimeRet[0] = 1;                    /*Tiempo de Retardo de los Motores*/
  if (gaiTimeRet[1] < 1) gaiTimeRet[1] = 1;                    /*Tiempo de Retardo de los Motores*/
  break;
 }
 case 'e': {
  printf("\n\t\tEjecucion Normal del Programa...");
  iRet = 1;
  getchar();
  break;
 }
 case 's': {
  printf("\n\nESTA SEGURO QUE DESEA ABANDONAR EL PROGRAMA ? (s->si): ");
  if (getche() == 's') iRet = -1;
  break;
 }
 default: {
 }
  }
 }
 return (iRet);
}
/**************************************************************************/
/*Sincroniza el contador de pasos con el origen de coordenadas*/
void vFunSetOrigen(void) {
 char cTecla;
 int iDx;
 int iDy;
 char acTmp[80];
 gaulPasos[0] = 2e9 + gaulPasos[0] % 8;                   /*Motor 0*/
 gaulPasos[1] = 2e9 + gaulPasos[1] % 8;                   /*Motor 1*/
 printf("\n\n\tESTABLECIENDO ORIGEN DEL CNCPAP2M");
 printf("\n\tPulsar una de las teclas siguientes y luego + o -");
 printf("\n\t\tDesplazamiento Carro (d)");
 printf("\n\t\tAvance               (a)");
 printf("\n\t\tCoordenadas          (c)");
 printf("\n\t\tFin                  (f)");
 cTecla = getch();
 while (cTecla != 'f') {
  switch (cTecla) {
 case 'd': {
  printf("\n\t\tEstableciendo Desplazamiento de Carro...");
  cTecla = getch();
  while (cTecla == '-' || cTecla == '+') {
   if (cTecla == '+') vMoveCarr( 1, 0);
   if (cTecla == '-') vMoveCarr(-1, 0);
   cTecla = getch();
  }
  break;
 }
 case 'a': {
  printf("\n\t\tEstableciendo Avance...");
  cTecla = getch();
  while (cTecla == '-' || cTecla == '+') {
   if (cTecla == '+') vMoveCarr(0, 1);
   if (cTecla == '-') vMoveCarr(0,-1);
   cTecla = getch();
  }
  break;
 }
 case 'c': {
  printf("\n\tIntroducir coordenadas de desplazamiento X: ");
  scanf("%s", acTmp);
  iDx = atoi(acTmp);
  printf("\n\tIntroducir coordenadas de desplazamiento Y: ");
  scanf("%s", acTmp);
  iDy = atoi(acTmp);
  vMoveCarr(iDx, iDy);
  cTecla = 'f';
  break;
 }
 default: {
  cTecla = getch();
  break;
 }
  }
 }
 printf("\n\tCONTADOR MOTOR 1: %lu"      , gaulPasos[0]);
 printf("\n\tCONTADOR MOTOR 2: %lu"      , gaulPasos[1]);
 printf("\n\tCONTADOR 1 y 2 RESETEADOS");
 gaulPasos[0] = 10000 + gaulPasos[0] % 8;           /*Motor 0*/
 gaulPasos[1] = 10000 + gaulPasos[1] % 8;           /*Motor 1*/
 outportb(giPortID, DEFMOTOFF);                     /*Pongo los motores a cero*/
}
/**************************************************************************/
/*Extrae las cadenas internas entre el separador sep en la posicion pos*/
int fprCsplit (char *strn, char sep, int pos, char *ret) {
 int it;
 int ij;
 int istrl;
 int ailisep[10] = {-1,-2,-2,-2,-2,-2,-2,-2,-2,-2};
 istrl = strlen(strn);
 ij = 1;
 for (it = 0 ; it < istrl ; it++) {
  if (strn[it] == sep) {
 ailisep[ij] = it;
 ij++;
  }
 }
 ailisep[ij] = istrl;
 if (ailisep[pos] == -2) {
  ret[0] = '\0';
  return (-1);
 }
 if (ailisep[pos+1] - ailisep[pos] < 2) {
  ret[0] = '\0';
  return (pos);
 }
 ij = 0;
 for (it = ailisep[pos]+1 ; it < ailisep[pos+1] ; it++) {
  ret[ij] = strn[it];
  ij++;
 }
 ret[ij] = '\0';
 return (pos);
}
/**************************************************************************/
/*Lee el fichero de datos y mueve los motores*/
void vLeeFich(FILE *fin) {
 int iCline = 0;
 int iCmd;
 char aTmp[80];
 char acD1[80];
 char acD2[80];
 int iD1;
 int iD2;
 int iEx = 1;
 int iEy = 1;
 printf("\n\nEjecutando Fichero de Comandos");
 fscanf (fin,"%s\n", aTmp);
 if (fprCsplit (aTmp, ',', 0, acD1) == -1) {
  printf("\n\t(%5d)ComandoFichero: No se ha encontrado comando en linea %s", iCline, aTmp);
  getchar();
 }
 iCmd = atoi(acD1);
 while (iCmd != -1 && feof(fin) != 1) {
  if (kbhit() != 0) {
 if (iFunMenu() == -1) {
  vFunError("Cancelacion desde el Teclado...");
 }
  }
  if (fprCsplit (aTmp, ',', 1, acD1) == -1) { /*ERROR*/ };
  if (fprCsplit (aTmp, ',', 2, acD2) == -1) { /*ERROR*/ };
  iD1 = atoi(acD1);
  iD2 = atoi(acD2);
  switch (iCmd) {
 case 0: {                                         /*Establece el factor de escala*/
  iEx = iD1;
  iEy = iD2;
   printf("\n\t(%5d)ComandoFichero: Configurando Factor de EscalaX %d", iCline, iEx);
   printf("\n\t(%5d)ComandoFichero: Configurando Factor de EscalaY %d", iCline, iEy);
  break;
 }
 case 1: {                                         /*Establece la Velocidad*/
  if (iD1 < 1) {
   gaiTimeRet[0]=1;
   printf("\n\t(%5d)ComandoFichero: ERROR: Configurando Tiempo ON  %dms. negativa", iCline, iD1);
   if (iFunMenu() == -1) {
  vFunError("Cancelacion desde el Teclado...");
   }
  } else {
   gaiTimeRet[0]=iD1;
   printf("\n\t(%5d)ComandoFichero: Configurando Tiempo ON  a %dms.", iCline, iD1);
  }
  if (iD2 < 1) {
   gaiTimeRet[1]=1;
   printf("\n\t(%5d)ComandoFichero: ERROR: Configurando Tiempo OFF %dms. negativa", iCline, iD2);
   if (iFunMenu() == -1) {
  vFunError("Cancelacion desde el Teclado...");
   }
  } else {
   gaiTimeRet[1]=iD2;
   printf("\n\t(%5d)ComandoFichero: Configurando Tiempo OFF a %dms.", iCline, iD2);
  }
  break;
 }
 case 2: {                                         /*Establece el Puerto de Comunicacion*/
  if (iD1 > 0 && iD1 < 4 && gaiPortInst[iD1-1] != 0) {
   giPortID = gaiPortInst[iD1-1];
   printf("\n\t(%5d)ComandoFichero: Configurando Puerto de comunicacion LPT%d", iCline, iD1);
  } else {
   printf("\n\t(%5d)ComandoFichero: ERROR: Puerto de comunicacion LPT%d no Valido", iCline, iD1);
   if (iFunMenu() == -1) {
  vFunError("Cancelacion desde el Teclado...");
   }
  }
  break;
 }
 case 3: {                                         /*Muestra un mensaje en la pantalla*/
  printf("\n\t(%5d)ComandoFichero: MENSAJE=> %s - %s", iCline, acD1, acD2);
  break;
 }
 case 4: {                                         /*Hace una pausa*/
  if (iD1 > 0 ) {
   printf("\n\t(%5d)ComandoFichero: PAUSA de %ds.", iCline, iD1);
   delay(iD1 * 1000);
  } else {
  printf("\n\t(%5d)ComandoFichero: PAUSA INDEFINIDA, pulse RETURN para continuar.", iCline);
   getchar();
  }
  break;
 }
 case 5: {                                         /*Establece el modo de activacion de los motores*/
  if (iD1 > -1 && iD1 < 3) {
   vFunInitGVar(iD1);
   printf("\n\t(%5d)ComandoFichero: Modo Activacion seleccionado: %d", iCline, iD1);
  } else {
   printf("\n\t(%5d)ComandoFichero: ERROR en Modo Activacion seleccionado.", iCline);
   if (iFunMenu() == -1) {
  vFunError("Cancelacion desde el Teclado...");
   }
  }
  break;
 }
 case 10: {                                         /*Mueve el Carro*/
  printf("\n\t(%5d)ComandoFichero: Enviando Pasos a motores: %d - %d", iCline, iEx*iD1, iEy*iD2);
  vMoveCarr(iEx*iD1, iEy*iD2);
  break;
 }
 default: {
  printf("\n\t(%5d)ComandoFichero: Orden %d Desconocida", iCline, iCmd);
 }
  }
  fscanf (fin,"%s\n", aTmp);
  if (fprCsplit (aTmp, ',', 0, acD1) == -1) {
 printf("\n\t(%5d)ComandoFichero: No se ha encontrado comando en linea %s", iCline, aTmp);
 getchar();
  }
  iCmd = atoi(acD1);
  iCline++;
 }
 printf("\n\t(%5d)ComandoFichero: FIN DE EJECUCION DEL FICHERO", iCline);
}
/**************************************************************************/
/*Operacion de presionar tecla en funcion vMoveCarr*/
void vMCKBhit (void) {
 char cT;
 cT = getche();
 switch (cT) {
  case '-': {
 gaiTimeRet[0] --;
 gaiTimeRet[1] --;
 if (gaiTimeRet[0] < 1) gaiTimeRet[0] = 1;        /*Tiempo de Retardo de los Motores*/
 if (gaiTimeRet[1] < 1) gaiTimeRet[1] = 1;        /*Tiempo de Retardo de los Motores*/
 break;
  }
  case '+': {
 gaiTimeRet[0] ++;
 break;
  }
  default: {
 if (iFunMenu() == -1) {
  vFunError("Cancelacion desde el Teclado...");
 }
  }
 }
}
/**************************************************************************/
/*Mueve el carro la cantidad que se le especifique*/
int vMoveCarr(int iDx, int iDy) {
 int iT;
 int iI;
 int iJ;
 int iYPaso;
 int iSentx;                                         /*sentido de avance*/
 int iSenty;                                         /*sentido de avance*/
 double dProp;
 double dTmp1;
 unsigned char cCod;
 if (iDx == 0 && iDy == 0) {
  return(0);
 }
 if (iDy == 0) {
  iSentx = iDx / abs(iDx);
  iDx = abs(iDx);
  for (iT = 0; iT < iDx; iT++) {
 if (kbhit() != 0) {
  vMCKBhit ();
 }
 outportb(giPortID, ucFunMgMPAP (0, iSentx) + ucFunMgMPAP (1, -1000));
 delay (gaiTimeRet[0]);
 if (gaiTimeRet[1] > 0) {
  outportb(giPortID, DEFMOTOFF);
  delay (gaiTimeRet[1]);
 }
 /*printf("\nMovX");*/
  }
  return(0);
 }
 if (iDx == 0) {
  iSenty = iDy / abs(iDy);
  iDy = abs(iDy);
  for (iT = 0; iT < iDy; iT++) {
 if (kbhit() != 0) {
  vMCKBhit ();
 }
 outportb(giPortID, ucFunMgMPAP (1, iSenty) + ucFunMgMPAP (0, -1000));
 delay (gaiTimeRet[0]);
 if (gaiTimeRet[1] > 0) {
  outportb(giPortID, DEFMOTOFF);
  delay (gaiTimeRet[1]);
 }
 /*printf("\nMovY");*/
  }
  return(0);
 }
 iSentx = iDx / abs(iDx);
 iSenty = iDy / abs(iDy);
 iDx = abs(iDx);
 iDy = abs(iDy);
 dProp = (double) iDy / (double) iDx;
 iI = 0;
 for (iT = 0; iT < iDx; iT++) {
  iJ = 0;
  cCod = ucFunMgMPAP (0, iSentx);
  /*printf("\nMovX");*/
  dTmp1 = floor ((double) (iT + 1) * dProp);
  if ((double) (iT + 1) * dProp - dTmp1 < 0.5) {
 iYPaso = (int) dTmp1;
  } else {
 iYPaso = (int) dTmp1 + 1;
  }
  for (; iI < iYPaso; iI++) {
 iJ++;
 outportb(giPortID, cCod + ucFunMgMPAP (1, iSenty));
 delay (gaiTimeRet[0]);
 if (gaiTimeRet[1] > 0) {
  outportb(giPortID, DEFMOTOFF);
  delay (gaiTimeRet[1]);
 }
 if (iJ < 10) {
  cCod = ucFunMgMPAP (0, 0);
 } else {
  cCod = ucFunMgMPAP (0, -1000);      /*Paro el motor 0*/
 }
 /*printf("-MovY");*/
  }
  if (iJ == 0) {
 /*printf("-MX");*/
 outportb(giPortID, cCod + ucFunMgMPAP (1,-1000));
 delay (gaiTimeRet[0]);
 if (gaiTimeRet[1] > 0) {
  outportb(giPortID, DEFMOTOFF);
  delay (gaiTimeRet[1]);
 }
  }
 if (kbhit() != 0) {
  vMCKBhit ();
 }
 }
 return (0);
}
 
 
 
El ejecutable lo teneis en la zona de descarga...
 
Basicamente, el programa lo que hace es tener almacenado la codificacion de señales dependiendo del tipo de activacion en la que queramos hacer trabajar el motor y con un contador llevamos la cuenta de la señal que se ha enviado para asi seguir la secuencia correcta. Para variar la velocidad, lo que se hace es controlar el tiempo que tardamos en enviar una señal desde que se envio la anterior (en milisegundos). Y basicamente eso es todo el programa.
Pero esto asi no es muy practico, por lo que el programa acepta un fichero de comandos que permite hacer que el programa vaya ejecutando una secuencia de ordenes que en su conjunto hagan del programa algo util. Por ejemplo: podemos hacer que el programa vaya moviendo los motores de tal forma que si estan conectados a un ploter 2D conseguimos un dibujo a base de segmentos de lineas mas o menos cortas...
El fichero debe ser de texto y sui sintaxis es muy simple; Comando, dato1,dato2
Los comandos que acepta son:
 
 
Descripcion Comando
Comando
Dato1
Dato2
Factor de escala
0
Escala Motor 1
Escala Motor 2
Velocidad
1
Tiempo Encendido (ms)
Tiempo Apagado (ms)
Puerto Lpt
2
Numero Puerto (1, 2, 3)
0
Mensaje en pantalla
3
Mensaje 1
Mensaje 2
Tiempo Pausa
4
Tiempo Segundos
0
Modo Activacion
5
Modo (0, 1 , 2)
0
Movimiento motores
10
Pasos Motor 1
Pasos Motor 2
Fin fichero
-1
0
0
 
 
Un ejemplo de fichero seria:
 
 
0,1,1
1,10,0
2,1,0
3,Fichero,Ejemplo
5,0,0
4,5,0
10,100,200
10,15,365
10,-58,+487
-1,0,0
Factor de escala
Velocidad
Puerto Lpt
Mensaje
Activacion Simple
Pausa de 5 segundos
Movimiento de motores
Movimiento de motores
Movimiento de motores
Fin fichero
 
Como el generar el fichero manualmente no es algo practico, yo me he basado en el programa Autocad de diseño asistido por PC para generar la figura a tratar y luego exportar sus coordenadas en el formato del fichero que yo utilizo.
Para hacer la orden que genere el fichero desde autocad, yo me he basado en el lenguaje de programacion AUTOLISP (propio de Autocad) para generar las ordenes que necesito y que no vienen en Autocad. Para mas informacion, os remito a la ayuda del propio Autocad sobre el lenguaje AUTOLISP.
Como no pretendo dar una clase de Autolisp, aqui adjunto una orden que obtiene los puntos desde una polilinea de autocad y los guarda en un fichero con el formato de mi programa. Estas ordenes se graban en un fichero ASCII de texto con la extension .lsp y luego se las carga desde Autocad.
Para cargar un fichero LSP con autocad debeis seguir los siguientes pasos:
 
Ir al menu Herramientas:
 
 
Entrar en Cargar Aplicacion: pulsar el boton Archivo y seleccionar el fichero .lsp
 
 
Seleccionando el fichero en la lista de ficheros a cargar, pulsamos el boton CARGAR
 
 
Veremos como nos indica en la linea de comandos que ha cargado el fichero .lsp
 
 
Esto lo debemos hacer cada vez que se carga un dibujo nuevo ya que Autocad resetea la lista de ordenes cada vez que se abre un dibujo...
 
 
 
Pues Bien, la orden que obtiene datos desde una polilinea y los guarda en un fichero es:
 
(DEFUN C:POL2TRAZ ( / glpx glpy prx pry vel ent fid p0 dx dy p1)
 (SETVAR "cmdecho" 0)
 (SETQ glpx 0)
 (SETQ glpy 0)
 (SETQ prx  (GETREAL "\nIntroduzca Factor de Proporcion X: "))
 (SETQ pry  (GETREAL "\nIntroduzca Factor de Proporcion Y: "))
 (SETQ vel  (GETINT  "\nIntroduzca Velocidad en MiliSegundos: "))
 (SETQ fid  (OPEN (GETFILED "DEME NOMBRE DEL FICHERO..." "" "fpt" 1) "w"))
 (PRINC "0,1,1" fid)
 (PRINC (STRCAT "\n1," (ITOA vel) ",0") fid)
 (SETQ p1  (GETPOINT  "\nIndicar Punto de Referencia de Trazado: "))
 (PRINC "\nSELECCIONAR LA POLILINEA A EXPORTAR:")
 (SETQ ent (ENTSEL))
 (WHILE (/= nil ent)
  (SETQ ent (NTH 0 ent))
  (IF (= "POLYLINE" (CDR (ASSOC 0 (entget ent))))
   (PROGN
    (SETQ ent (ENTNEXT ent))
    (WHILE (= "VERTEX" (CDR (ASSOC 0 (ENTGET ent))))
     (SETQ p0 (CDR (ASSOC 10 (ENTGET ent))))
     (SETQ dx (- (ATOI (RTOS (/ (- (NTH 0 p0) (NTH 0 p1)) prx) 2 0)) glpx))
     (SETQ dy (- (ATOI (RTOS (/ (- (NTH 1 p0) (NTH 1 p1)) pry) 2 0)) glpy))
     (PRINC (STRCAT "\n10," (ITOA dx) "," (ITOA dy)) fid)
     (SETQ glpx (+ glpx dx))
     (SETQ glpy (+ glpy dy))
     (SETQ ent (ENTNEXT ent))
    )
   )
   (PRINC (STRCAT "\n\nERROR: La entidad seleccionada es: " (CDR (ASSOC 0 (ENTGET ent)))))
  )
  (PRINC "\nSELECCIONAR SIGUIENTE POLILINEA A EXPORTAR:")
  (SETQ ent (ENTSEL))
 )
 (PRINC "\n-1,0,0\n" fid)
 (CLOSE fid)
 (SETVAR "cmdecho" 1)
)