/* CS_113_D.c CONTROL DEL ROBOT CS-113 2002 V¡ctor R. Gonz lez */ #include #include #include #include #include "paralelo.h" #define TRUE 1 #define FALSE 0 #define PASO_M1 0.12 /* paso angular de la cintura (motor 1)*/ #define PASO_M2 0.12 /* paso angular del hombro */ #define PASO_M3 0.08 /* paso angular del codo */ #define PASO_M4 0.05 /* paso angular de la mu¤eca (rotaci¢n) */ #define PASO_M5 0.05 /* paso angular de la mu¤eca (inclinaci¢n) */ #define PASO_M6 0.10 /* paso angular de la pinza */ #define LIM_M1 1000 /* +/- l¡mite (en pasos) de la cintura */ #define LIM_M2 600 /* +/- l¡mite (en pasos) del hombro */ #define LIM_M3 600 /* +/- l¡mite (en pasos) del codo */ #define LIM_M4 3600 /* +/- l¡mite (en pasos) de la mu¤eca (rotaci¢n) */ #define LIM_M5 1992 /* +/- l¡mite (en pasos) de la mu¤eca (inclinaci¢n) */ #define LIM_M6 1800 /* +/- l¡mite (en pasos) de la pinza */ #define VELOCIDAD_MIN 1 /* Velocidad m¡nima */ #define VELOCIDAD_MAX 5 /* Velocidad m xima */ #define VELOCIDAD_INI VELOCIDAD_MAX /* Velocidad inicial */ #define MEM_MIN 1 /* Posiciones de memoria disponibles */ #define MEM_MAX 100 #define MOV_ABSOLUTO 0 /* Movimiento absoluto o relativo */ #define MOV_RELATIVO 1 #define MENU_LIN1 8 #define MENU_COL1 33 #define MENU_COL2 38 #define INTRO 13 #define TAB 9 #define origen orden("Z") /* ZERO: Establece la posici¢n actual como referencia */ #define ir_origen orden("N") /* HOME: Ir a la posici¢n de referencia indicada por ZERO */ #define cierra_mano_todo orden("C") /* GRIP CLOSE: cierra al m ximo la pinza */ #define abre_mano_todo orden("O") /* GRIP OPEN: abre al m ximo la pinza */ #define para(seg) orden1("D", seg) /* DELAY: detiene el robot segundos (1-9)*/ #define velocidad(veloc) orden1("S", veloc) /* SPEED: establece la velocidad de los motores (1-5) */ #define limites(no_si) orden1("L", no_si) /* LIMIT: activa la vigilancia de los l¡mites de los motores (0-1) */ #define pos_mem(n_pos) orden1("H", n_pos) /* HERE: memoriza las posiciones de cada motor (1-100)*/ #define ir_mem(n_pos) orden1("G", n_pos) /* GOTO: va a posici¢n memorizada (1-100) */ #define cintura_izqda(grad) orden6("M", -grad, 0, 0, 0, 0, 0) #define cintura_dcha(grad) orden6("M", +grad, 0, 0, 0, 0, 0) #define hombro_sube(grad) orden6("M", 0, -grad, 0, 0, 0, 0) #define hombro_baja(grad) orden6("M", 0, +grad, 0, 0, 0, 0) #define codo_sube(grad) orden6("M", 0, 0, -grad, 0, 0, 0) #define codo_baja(grad) orden6("M", 0, 0, +grad, 0, 0, 0) #define muneca_sube(grad) orden6("M", 0, 0, 0, -grad, +grad, 0) #define muneca_baja(grad) orden6("M", 0, 0, 0, +grad, -grad, 0) #define muneca_izqda(grad) orden6("M", 0, 0, 0, -grad, -grad, 0) #define muneca_dcha(grad) orden6("M", 0, 0, 0, +grad, +grad, 0) #define cierra_mano(grad) orden6("M", 0, 0, 0, 0, 0, +grad) #define abre_mano(grad) orden6("M", 0, 0, 0, 0, 0, -grad) #define motores(cint, hom, cod, mun_ele, mun_gir, mano) orden6("M", cint, hom, cod, mun_ele, mun_gir, mano) int ParaleloIni (void); /* Inicia el puerto paralelo */ void enviab (unsigned char caracter); void orden (char* id); void orden1 (char* id, int arg); void orden6 (char* id, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6); void msg_orden(char* orden); void msg_error(char* mens); unsigned selector(int* valor, int inf, int sup, float factor, char* form); void espera_fin_mov(int p1, int p2, int p3, int p4, int p5, int p6, int velocidad); void lote ( void); void main() { unsigned tecla = 0, tecla_ant = 0; unsigned modo_mov = MOV_ABSOLUTO; unsigned limites = TRUE; int velocidad = VELOCIDAD_INI; int pos_mem = MEM_MIN, ir_mem = MEM_MIN; int p1, p2, p3, p4, p5, p6; int cintura=0, hombro=0, codo=0, muneca_giro=0, muneca_elev=0, mano=0; int cintura_abs=0, hombro_abs=0, codo_abs=0, muneca_giro_abs=0, muneca_elev_abs=0, mano_abs=0; /* Detecci¢n del puerto paralelo */ if ( ParaleloIni() == LPT_NINGUNO ) exit(1); printf(" *** Control directo del ROBOT CS-113 en el puerto 0x%X ***\n\n", LPT_BASE); printf(" Pos. actual: cintura - hombro - codo - mu¤eca - pinza\n"); printf(" absoluta eleva. - giro\n"); printf(" (pasos):\n"); printf(" (§):\n\n"); printf(" Ir a la posici¢n de origen (0)\n"); printf(" Fijar la posici¢n de origen (o)\n\n"); printf(" Girar la cintura (c)\n"); printf(" Girar el hombro (h)\n"); printf(" Girar el codo (k)\n"); printf(" Girar la mu¤eca (g)\n"); printf(" Elevar la mu¤eca (e)\n"); printf(" Mover la pinza (p)\n\n"); printf(" Velocidad: (v)\n\n"); printf(" Almacenar esta posici¢n (a)\n"); printf(" Ir a una posici¢n guardada (i)\n\n"); printf(" Mover a pos. seleccionada (m)\n"); printf(" Fichero de instrucciones (f)\n"); printf(" Salir (s)"); /* Muestra posiciones iniciales */ gotoxy (29, MENU_LIN1-3); printf (" %7i %7i %7i %7i %7i %7i", cintura_abs, hombro_abs, codo_abs, muneca_elev_abs, muneca_giro_abs, mano_abs); gotoxy (29, MENU_LIN1-2); printf (" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f", cintura_abs*PASO_M1, hombro_abs*PASO_M2, codo_abs*PASO_M3, muneca_elev_abs*PASO_M4, muneca_giro_abs*PASO_M5, mano_abs*PASO_M6); gotoxy (15, MENU_LIN1+10); printf ("%1u", velocidad); gotoxy (MENU_COL2+5, MENU_LIN1+2); printf ("Modo (r,l): %s , %s", (modo_mov == MOV_ABSOLUTO) ? "absoluto" : "relativo", (limites == TRUE) ? "limitado " : "no limitado"); while (tecla != 's' && tecla != 'S') { switch (tecla) { case '0': gotoxy(MENU_COL1, MENU_LIN1); ir_origen; tecla = getch(); tecla_ant = 0; break; case 'o': case 'O': gotoxy(MENU_COL1, MENU_LIN1+1); origen; tecla = getch(); tecla_ant = 0; break; case 'c': case 'C': /* Giro de cintura */ gotoxy(MENU_COL2, MENU_LIN1+3); printf("Pos.: "); tecla = selector (&cintura, -LIM_M1, LIM_M1, PASO_M1, "%5i pasos , %7.2f §"); tecla_ant = 'c'; break; case 'h': case 'H': /* Giro de hombro */ gotoxy(MENU_COL2, MENU_LIN1+4); printf("Pos.: "); tecla = selector (&hombro, -LIM_M2, LIM_M2, PASO_M2, "%5i pasos , %7.2f §"); tecla_ant = 'h'; break; case 'k': case 'K': /* Giro de codo */ gotoxy(MENU_COL2, MENU_LIN1+5); printf("Pos.: "); tecla = selector (&codo, -LIM_M3, LIM_M3, PASO_M3, "%5i pasos , %7.2f §"); tecla_ant = 'k'; break; case 'g': case 'G': /* Giro de mu¤eca */ gotoxy(MENU_COL2, MENU_LIN1+6); printf("Pos.: "); tecla = selector (&muneca_giro, -LIM_M4, LIM_M4, PASO_M4, "%5i pasos , %7.2f §"); tecla_ant = 'g'; break; case 'e': case 'E': /* Elevaci¢n de mu¤eca */ gotoxy(MENU_COL2, MENU_LIN1+7); printf("Pos.: "); tecla = selector (&muneca_elev, -LIM_M5, LIM_M5, PASO_M5, "%5i pasos , %7.2f §"); tecla_ant = 'e'; break; case 'p': case 'P': /* Abrir y cerrar pinza */ gotoxy(MENU_COL2, MENU_LIN1+8); printf("Pos.: "); tecla = selector (&mano, -LIM_M6, LIM_M6, PASO_M6, "%5i pasos , %7.2f §"); tecla_ant = 'p'; break; case 'v': case 'V': /* Fijar velocidad de los motores */ gotoxy(15, MENU_LIN1+10); tecla = selector (&velocidad, 1, 5, 1, "%1u"); velocidad (velocidad); tecla_ant = 'v'; break; case 'a': case 'A': /* Almacenar posici¢n en memoria */ gotoxy(MENU_COL2, MENU_LIN1+12); printf("Memoria: "); tecla = selector (&pos_mem, 1, 100, 1, "%3u"); pos_mem (pos_mem); tecla_ant = 'a'; break; case 'i': case 'I': /* Ir a posici¢n de memoria */ gotoxy(MENU_COL2, MENU_LIN1+13); printf("Memoria: "); tecla = selector (&ir_mem, 1, 100, 1, "%3u"); ir_mem (ir_mem); tecla_ant = 'i'; break; case 'm': case 'M': /* Mover motores */ gotoxy(MENU_COL1, MENU_LIN1+12); if (modo_mov == MOV_ABSOLUTO) { /* Se mueve a nuevas posiciones absolutas */ p1 = cintura - cintura_abs; p2 = hombro - hombro_abs; p3 = codo - codo_abs; p4 = muneca_giro - muneca_giro_abs; p5 = muneca_elev - muneca_elev_abs; p6 = mano - mano_abs; motores (p1, p2, p3, p4, p5, p6); espera_fin_mov(p1, p2, p3, p4, p5, p6, velocidad); /* Guarda nuevas posiciones absolutas */ cintura_abs = cintura; hombro_abs = hombro; codo_abs = codo; muneca_giro_abs = muneca_giro; muneca_elev_abs = muneca_elev; mano_abs = mano; } else { /* Comprueba l¡mites */ p1 = cintura; p2 = hombro; p3 = codo; p4 = muneca_giro; p5 = muneca_elev; p6 = mano; if (cintura_abs + p1 <= LIM_M1 && cintura_abs + p1 >= -LIM_M1 && hombro_abs + p2 <= LIM_M2 && hombro_abs + p2 >= -LIM_M2 && codo_abs + p3 <= LIM_M3 && codo_abs + p3 >= -LIM_M3 && muneca_giro_abs + p4 <= LIM_M4 && muneca_giro_abs + p4 >= -LIM_M4 && muneca_elev_abs + p5 <= LIM_M5 && muneca_elev_abs + p5 >= -LIM_M5 && mano_abs + p6 <= LIM_M6 && mano_abs + p6 >= -LIM_M6 ) { motores (p1, p2, p3, p4, p5, p6); espera_fin_mov(p1, p2, p3, p4, p5, p6, velocidad); /* Guarda nuevas posiciones absolutas */ cintura_abs += cintura; hombro_abs += hombro; codo_abs += codo; muneca_giro_abs += muneca_giro; muneca_elev_abs += muneca_elev; mano_abs += mano; } else msg_error ("... fuera de l¡mites ..."); } gotoxy(29, MENU_LIN1-3); printf(" %7i %7i %7i %7i %7i %7i", cintura_abs, hombro_abs, codo_abs, muneca_elev_abs, muneca_giro_abs, mano_abs); gotoxy(29, MENU_LIN1-2); printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f", cintura_abs*PASO_M1, hombro_abs*PASO_M2, codo_abs*PASO_M3, muneca_elev_abs*PASO_M4, muneca_giro_abs*PASO_M5, mano_abs*PASO_M6); tecla = getch(); tecla_ant = 0; break; case 'f': case 'F': lote (); tecla = getch(); tecla_ant = 0; break; case 'l': case 'L': /* Activar o desactivar l¡mite de motores */ limites = !limites; limites (limites); gotoxy (MENU_COL2+5, MENU_LIN1+2); printf ("Modo (r,l): %s , %s", (modo_mov == MOV_ABSOLUTO) ? "absoluto" : "relativo", (limites == TRUE) ? "limitado " : "no limitado"); tecla = getch(); break; case 'r': case 'R': /* Modo de pos.: absoluto o relativo */ if (modo_mov == MOV_ABSOLUTO) /* Cambia a relativo */ modo_mov = MOV_RELATIVO; else { /* Cambia a absoluto */ modo_mov = MOV_ABSOLUTO; cintura = cintura_abs; hombro = hombro_abs; codo = codo_abs; muneca_giro = muneca_giro_abs; muneca_elev = muneca_elev_abs; mano = mano_abs; } gotoxy (MENU_COL2+5, MENU_LIN1+2); printf ("Modo (r,l): %s , %s", (modo_mov == MOV_ABSOLUTO) ? "absoluto" : "relativo", (limites == TRUE) ? "limitado " : "no limitado"); tecla = getch(); break; case INTRO: case TAB: /* Pasa al siguientre campo */ switch (tecla_ant) { case 0: tecla = 'c'; break; case 'c': case 'C': tecla = 'h'; break; case 'h': case 'H': tecla = 'k'; break; case 'k': case 'K': tecla = 'g'; break; case 'g': case 'G': tecla = 'e'; break; case 'e': case 'E': tecla = 'p'; break; case 'p': case 'P': tecla = 'v'; break; case 'v': case 'V': tecla = 'a'; break; case 'a': case 'A': tecla = 'i'; break; case 'i': case 'I': tecla = 'c'; break; } break; default: tecla = getch(); break; } /* switch (tecla) */ } /* while (tecla != f) */ } /* Env¡a un car cter al puerto utilizando un protocolo similar a las impresoras */ void enviab (unsigned char caracter) { outportb (DATOS, caracter); /* Espera a que el dispositivo esté libre: BUSY bajo (S7# = 1)*/ while ( ! (inportb(ESTADO) & 0x80) ); /* Solicita aceptaci¢n del byte: STB# bajo (C0# = 1) */ outportb (CONTROL, inportb(CONTROL) | 1); /* Espera confirmaci¢n de dato recibido: ACK# bajo (S6=0)*/ /* while ( inportb(ESTADO) & 0x40 ); */ /* No se utiliza en el robot */ delay(1); outportb (CONTROL, inportb(CONTROL) & ~1); /* Repone STB# alto (C0# = 0) */ delay(1); /* Espera entre env¡os para no bloquear el robot */ } /* Env¡a una orden de s¢lo texto */ void orden(char* id) { char orden[64]; char *ptr = orden; /* A¤ade un salto de l¡nea al identificador */ sprintf ( orden, "%s\n", id); /* Env¡a la orden al puerto */ while (*ptr != '\0') enviab( *ptr++ ); msg_orden (orden); } /* Env¡a una orden con un argumento entero */ void orden1(char* id, int arg) { char orden[64]; char *ptr = orden; /* Concatena el argumento entero con el identificador y a¤ade un salto de l¡nea */ sprintf ( orden, "%s%i\n", id, arg); /* Env¡a la orden al puerto */ while (*ptr != '\0') enviab( *ptr++ ); msg_orden (orden); } /* Env¡a una orden con 6 argumentos */ void orden6(char* id, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6) { char orden[64]; char *ptr = orden; /* Convierte los argumentos de grados a pasos, los concatena con el identificador y a¤ade un salto de l¡nea */ sprintf ( orden, "%s%i,%i,%i,%i,%i,%i\n", id, arg1, arg2, arg3, arg4, arg5, arg6); /* Env¡a la orden al puerto */ while (*ptr != '\0') enviab( *ptr++ ); msg_orden (orden); } void msg_orden(char* orden) { unsigned pos_x = wherex(), pos_y = wherey(); gotoxy (37,24); printf (" "); gotoxy (37,24); printf ("orden: %s", orden); gotoxy (pos_x, pos_y); } void msg_error(char* mens) { unsigned pos_x = wherex(), pos_y = wherey(); unsigned i; for (i=1; i<=5; i++) { gotoxy(40,25); printf (mens); delay(500); gotoxy(40,25); printf (" "); } gotoxy (pos_x, pos_y); } /* Establece el valor de un par metro entero entre unos l¡mites */ unsigned selector(int* valor, int inf, int sup, float factor, char* form) { unsigned tecla; unsigned pos_x, pos_y; int paso = 1; int paso_pag = 50; /* Paso de p gina */ int num = *valor; char salir = FALSE; pos_x = wherex(); pos_y = wherey(); while (!salir) { /* Muestra el nuevo valor */ gotoxy(pos_x, pos_y); printf(form, num, num*factor); switch (tecla = getch()) { case '+': /* Avanza un paso */ if (num <= sup-paso) num += paso; break; case '-': /* Retrocede un paso */ if (num >= inf+paso) num -= paso; break; case '>': /* Avanza una p gina de pasos */ if (num <= sup-paso_pag) num += paso_pag; break; case '<': /* Retrocede una p gina de pasos */ if (num >= inf+paso_pag) num -= paso_pag; break; case 'z': case 'Z': /* Retrocede al l¡mite inferior */ num = inf; break; case 'x': case 'X': /* Avanza al l¡mite superior */ num = sup; break; case ' ': /* Se sitúa en el punto medio */ num = .5*(inf+sup); break; case '0': /* Sale del selector entregando la pulsaci¢n */ case 'o': case 'O': case 'c': case 'C': case 'h': case 'H': case 'k': case 'K': case 'g': case 'G': case 'e': case 'E': case 'p': case 'P': case 'v': case 'V': case 'a': case 'A': case 'i': case 'I': case 'm': case 'M': case 'f': case 'F': case 'r': case 'R': case 's': case 'S': case INTRO: salir = TRUE; break; } /* switch (tecla) */ } /* while (!salir) */ *valor = num; return tecla; } /* Espera fin de movimiento A velocidad 1 se recorre un paso cada 5 ms A velocidad 5 se recorre un paso cada 15 ms */ void espera_fin_mov(int p1, int p2, int p3, int p4, int p5, int p6, int velocidad) { int pasos = 0; pasos = max(abs(p1),pasos); pasos = max(abs(p2),pasos); pasos = max(abs(p3),pasos); pasos = max(abs(p4),pasos); pasos = max(abs(p5),pasos); pasos = max(abs(p6),pasos); gotoxy(40,25); printf ("... realizando el desplazamiento ..."); delay ( pasos * (5 + 2.5*(velocidad-1)) ); gotoxy(40,25); printf (" "); } /* Ejecuta un lote de instrucciones desde archivo */ void lote () { FILE *lote; char byte, txt_ord[64]; char *ptr_ord = txt_ord; if ((lote = fopen("cs113.txt", "rt")) != NULL) { while ( !feof (lote) ) { byte = fgetc (lote); if ((byte > 42 && byte < 91) || byte == '\n' ) { if (byte == ';') /* Descarta comentarios entre ; y \n */ while (!feof (lote) && (byte=fgetc (lote)) != '\n'); if (byte != '\n') *ptr_ord++ = byte; /* Almacena la orden */ else { *ptr_ord = '\0'; /* Se ha llegado a fin de orden */ orden (txt_ord); /* Env¡a la orden */ ptr_ord = txt_ord; /* Comienza otra */ } } } } else msg_error("No se encuentra el archivo de lotes"); fclose(lote); } /* Identifica los puertos paralelos instalados en el PC Devuelve: LPT_NINGUNO: si no hay puertos instalados LPT_OTROS : si el primer puerto es de tipo desconocido LPT_SPP : si el primer puerto es SPP LPT_BIDIR : si el primer puerto es bidireccional LPT_EPP : si el primer puerto es EPP LPT_ECP : si el primer puerto es ECP */ int ParaleloIni (void) { unsigned int PuertoNum, Puerto, NumPuertos; unsigned int Byte, tmp; char PuertoEPP; int PuertoTipo; char *PuertoNombre[]={"", "Estandar (SPP)", "Bidireccional", "EPP", "ECP"}; /* Busca la direcci¢n de E/S de los puertos instalados */ NumPuertos = 0; PuertoTipo = LPT_NINGUNO; for (PuertoNum=1; PuertoNum<=3; PuertoNum++) { _lpt_dir[PuertoNum] = peek(0x0040,0x0008 + (PuertoNum-1)*2); if (_lpt_dir[PuertoNum] == 0) printf ("No se encuentra puerto asignado a LPT%d \n", PuertoNum); else { printf ("La direcci¢n asignada a LPT%d es 0x%X\n", PuertoNum, _lpt_dir[PuertoNum]); NumPuertos++; } } if (NumPuertos > 0 ) { /* Detecta el tipo de puerto del primero hallado */ printf ("\nPuerto seleccionado: LPT%d en 0x%X. ", LPT_NUM, LPT_BASE); /* Prueba puerto ECP */ Byte = inportb (CONTROL_EXT) & 0x03; /* toma bits 0 y 1 de CONTROL_EXT */ if (Byte == 1) { Byte = inportb (CONTROL); tmp = Byte; outportb (CONTROL, Byte ^ 0x03); /* pone a 0 los bits 0 y 1 de CONTROL */ Byte = inportb(CONTROL_EXT) & 0x03; if (Byte == 1) PuertoTipo = LPT_ECP; outportb (CONTROL, tmp); /* restaura CONTROL */ } /* Prueba puerto EPP */ if (!PuertoTipo) { PuertoEPP = FALSE; if (LPT_BASE != 0x03BC) { Byte = inportb (ESTADO); tmp = Byte; outportb (ESTADO, Byte & (~0x01) ); /* Pone a 0 el bit 0 de ESTADO */ for (Puerto=REG_EPP_PRI; Puerto<=REG_EPP_ULT; Puerto++) { outportb (Puerto, 0x55); Byte = inportb (Puerto); if (Byte == 0x55) { outportb (Puerto, 0xAA); Byte = inportb (Puerto); PuertoEPP = (Byte == 0xAA); if (!PuertoEPP) break; } } outportb (ESTADO, tmp); /* restaura bit 1 de ESTADO */ } if (PuertoEPP) PuertoTipo = LPT_EPP; } /* Prueba puerto SPP */ if (!PuertoTipo) { Byte = inportb (CONTROL); tmp = Byte; outportb (CONTROL, Byte | 0x20 ); /* Pone a 1 el bit 5 de CONTROL (entrada de DATOS) */ outportb (DATOS, 0x55); Byte = inportb (DATOS); if (Byte == 0x55) { outportb (CONTROL, Byte | 0x20 ); /* Pone a 1 el bit 5 de CONTROL (entrada de DATOS) */ outportb (DATOS, 0xAA); Byte = inportb (DATOS); if (Byte == 0xAA) PuertoTipo = LPT_SPP; } outportb (CONTROL, tmp); /* Restaura el bit 5 de CONTROL */ } /* Prueba puerto bidireccional */ if (!PuertoTipo) { Byte = inportb (CONTROL); tmp = Byte; outportb (CONTROL, Byte | 0x20 ); /* Pone a el 1 bit 5 de CONTROL (entrada de DATOS)*/ outportb (DATOS, 0x55); Byte = inportb (DATOS); if (Byte != 0x55) { outportb (CONTROL, Byte | 0x20 ); /* Pone a el 1 bit 5 de CONTROL (entrada de DATOS) */ outportb (DATOS, 0xAA); Byte = inportb (DATOS); if (Byte != 0xAA) PuertoTipo = LPT_BIDIR; } outportb (CONTROL, tmp); /* Restaura el bit 5 de CONTROL */ } if (PuertoTipo) { printf("Puerto tipo: %s (%i)\n", PuertoNombre[PuertoTipo], PuertoTipo); /* Pone DATOS en modo salida */ DATOS_out(); /* Pone las salidas en bajo */ outportb (DATOS, 0x00); /* reg. de DATOS */ outportb (CONTROL, inportb (CONTROL) & 0xFB); /* nibble bajo del reg. de CONTROL */ } else { PuertoTipo= LPT_OTROS; /* Puerto de tipo desconocido */ printf("Puerto de tipo desconocido\n"); } } /* NumPuertos > 0 */ return( LPT_TIPO = PuertoTipo ); }