Actividad 1:
Acceso básico al puerto paralelo con QBasic y TurboC

Programación básica de la E/S en Basic

Para realizar el control de dispositivos mediante el puerto paralelo debemos hacer uso de las funciones de QBasic que permiten acceder a los puertos hardware. En lo que sigue se proporcionan unos ejemplos básicos de la programación de la E/S por el puerto paralelo. Estos ejemplos se presentan con un grado de estructuración creciente en el estilo de programación.

En el primer ejemplo se supone que el PC está equipado con un puerto paralelo de tipo estándar localizado en la dirección 0x378, como suele ser habitual, de modo que el registro de datos se localiza en esa misma dirección y el de estado en 0x378+1. En el ejemplo se envía un byte a las líneas de datos y se recibe un byte de las líneas de estado con las funciones OUT e INP utilizando un estilo de programación muy básico:

'    CTRL.BAS
'    Ejemplo básico de E/S digital mediante el puerto paralelo
'       Salidas:  líneas de datos  (bits D0-D7 del registro de datos)
'       Entradas: líneas de estado (bits S3-S7 del registro de estado)
'
'    2002 Víctor R. González
'
'    Suponemos puerto estándar en la dirección H378
'

	' byte para operaciones de E/S
	INPUT "Introduce el byte que se enviará al puerto: ", byte%

	OUT &H378, byte%        ' envía un byte a las líneas de datos

	INPUT "Polariza las líneas de estado y pulsa <INTRO>", tecla

	byte% = INP(&H378 + 1)  ' lee un byte de las líneas de estado

	PRINT "El valor leído es "; byte%

END

En el siguiente ejemplo se supone que el PC está equipado con un puerto paralelo de tipo bidireccional localizado en la dirección 0x378 de modo que el registro de datos se localiza en esa misma dirección y el de control en 0x378+2. El bit C5 del registro de control se utiliza como conmutador del modo salida (escritura en las líneas de datos) al modo entrada (lectura de las líneas de datos). En el ejemplo se envía y se recibe un byte de las líneas de datos del puerto aprovechando su capacidad bidireccional utilizando las funciones OUT e INP  sin mayores complicaciones en la programación:

'    CTRL_0.BAS
'    Ejemplo básico de E/S digital mediante el puerto paralelo
'
'    2002 Víctor R. González
'
'    Suponemos puerto bidireccional (comprobar en BIOS)
'    en la dirección H378
'

	' byte para operaciones de E/S
	INPUT "Introduce el byte que se enviará al puerto: ", byte%

	' pone el puerto en modo salida (bit 5 del reg. CONTROL a 0)
	OUT &H378 + 2, 0

	OUT &H378, byte%        ' envía un byte


	INPUT "Polariza las líneas del puerto y pulsa <INTRO>", tecla

	' pone el puerto en modo entrada (bit 5 del reg. CONTROL a 1)
	OUT &H378 + 2, 32

	byte% = INP(&H378)      ' lee un byte

	PRINT "El valor leído es "; byte%

END

El siguiente ejemplo es funcionalmente idéntico al anterior, aunque se hace uso de las constantes de BASIC para dotar al programa de mayor elegancia y claridad. También, facilita la reprogramación en caso de que, por ejemplo, el puerto no se halle en la dirección supuesta. Obsérvese que la constante 0x378 sólo aparece ahora una vez en el código fuente, frente a las cuatro veces que lo hacía en CTRL_0.BAS.  Se ha hecho uso asimismo de la notación hexadecimal para los valores que activan y desactivan el bit C5 del registro de control.

'    CTRL_1.BAS
'    Ejemplo básico de E/S digital mediante el puerto paralelo
'
'    2002 Víctor R. González
'
'    Suponemos puerto bidireccional (comprobar en BIOS)
'    en la dirección H378
'

	CONST LPTBASE = &H378       ' dirección base del puerto paralelo
	CONST DATOS = LPTBASE       ' dirección de E/S del reg. de datos
	CONST CONTROL = LPTBASE + 2 ' dirección de E/S del reg. de control

	CONST C5ON = &H20           ' bit 5 de control a 1
	CONST C5OFF = &H0           ' bit 5 de control a 0


	' byte para operaciones de E/S
	INPUT "Introduce el byte que se enviará al puerto: ", byte%

	OUT CONTROL, C5OFF      ' pone el puerto en modo salida

	OUT DATOS, byte%        ' envía un byte


	INPUT "Polariza las líneas del puerto y pulsa <INTRO>", tecla

	OUT CONTROL, C5ON       ' pone el puerto en modo entrada

	byte% = INP(DATOS)      ' lee un byte

	PRINT "El valor leído es "; byte%

END

Todavía alguna sofisticación más: esta vez no es sólo maquillaje. Cuando en los ejemplos anteriores hemos activado y desactivado el bit C5, hemos podido también modificar el estado del resto de los bits del registro de control. Normalmente, es de buen gusto respetar el estado original del puerto cuando uno finaliza la ejecución de su programa. Así pues, en el siguiente ejemplo se lee en primer lugar el estado del registro de control y se almacena en un byte (que llamamos ctrl%). Cuando utilizamos OUT, lo hacemos de modo que únicamente modificamos individualmente el bit deseado, y no todos. Finalmente escribimos el byte ctrl% al registro de control para recuperar el estado original. Obsérvese que se usa el operador ~ para realizar el complemento a 1 de C5ON, de modo que nos ahorramos el definir otra constante simbólica para la condición de bit apagado.

'    CTRL_2.BAS
'    Ejemplo básico de E/S digital mediante el puerto paralelo
'
'    2002 Víctor R. González
'
'    Suponemos puerto bidireccional (comprobar en BIOS)
'    en la dirección H378
'

	CONST LPTBASE = &H378       ' dirección base del puerto paralelo
	CONST DATOS = LPTBASE       ' dirección de E/S del reg. de datos
	CONST CONTROL = LPTBASE + 2 ' dirección de E/S del reg. de control

	CONST C5ON = &H20           ' bit 5 de control a 1


	ctrl% = INP(CONTROL)    ' guarda el valor actual del reg. de control

	' byte para operaciones de E/S
	INPUT "Introduce el byte que se enviará al puerto: ", byte%

	OUT CONTROL, ctrl% AND NOT (C5ON)   ' pone el puerto en modo salida

	OUT DATOS, byte%        ' envía un byte


	INPUT "Polariza las líneas del puerto y pulsa <INTRO>", tecla

	OUT CONTROL, ctrl% OR C5ON          ' pone el puerto en modo entrada

	byte% = INP(DATOS)      ' lee un byte

	PRINT "El valor leído es "; byte%

	OUT CONTROL, ctrl%      ' restaura el valor original del reg. de control

END

Ahora un cambio significativo: vamos a determinar, y no a suponer, dónde se halla situado el puerto paralelo (consúltese la sección correspondiente  de El Puerto Paralelo del PC para conocer los detalles acerca de cómo determinar cuántos puertos se hallan instalados y qué direcciones de E/S ocupan). Para ello accedemos a la zona de memoria donde se registran las direcciones de los puertos paralelos presentes en el PC (en la zona de las variables de la BIOS), por mediación de la función PEEK . Una vez detectados los puertos presentes, nos quedamos con el primero y programamos la entrada-salida exactamente igual que en CTRL_2.BAS.

'    CTRL_3.BAS
'    Ejemplo básico de E/S digital mediante el puerto paralelo
'
'    2002 Víctor R. González
'

	CONST C5ON = &H20		' bit 5 de control a 1

	' determina los puertos instalados y sus direcciones
	DEF SEG = 0			' selecciona el segmento de memoria 0

	FOR puerto% = 2 TO 0 STEP -1	' número de puerto paralelo
					' 0 (LPT1), 1 (LPT2), 2 (LPT3)
		' dirección del puerto
		LPTBASE% = PEEK(&H408 + puerto% * 2) + 256 * PEEK(&H408 + puerto% * 2 + 1)
		IF LPTBASE% = 0 THEN
			PRINT "No hay puerto asignado a LPT"; puerto% + 1
		ELSE
			PRINT "La dirección de LPT"; puerto% + 1; " es "; LPTBASE%
		END IF
	NEXT puerto%

	DATOS% = LPTBASE%       ' dirección de E/S del reg. de datos
	CONTROL% = LPTBASE% + 2 ' dirección de E/S del reg. de control


	IF LPTBASE% > 0 THEN
		' suponemos puerto bidireccional (comprobar en BIOS)

		ctrl% = INP(CONTROL%)    ' guarda el valor actual del reg. de control

		' byte para operaciones de E/S
		INPUT "Introduce el byte que se enviará al puerto: ", byte%

		OUT CONTROL%, ctrl% AND NOT (C5ON)   ' pone el puerto en modo salida

		OUT DATOS%, byte%        ' envía un byte
									 

		INPUT "Polariza las líneas del puerto y pulsa <INTRO>", tecla

		OUT CONTROL%, ctrl% OR C5ON          ' pone el puerto en modo entrada

		byte% = INP(DATOS%)      ' lee un byte

		PRINT "El valor leído es "; byte%

		OUT CONTROL%, ctrl%      ' restaura el valor original del reg. de control

	END IF

END

Por último, integraremos el código que localiza la dirección del puerto en una función que devuelve dicha dirección. Para ello definimos la función PuertoDir%, sin argumentos y de tipo entero. Si dicha función no localiza ningún puerto devuelve un 0, lo que brinda al programa una posibilidad de terminar la ejecución cuando en un PC no existe puerto paralelo disponible.

DECLARE FUNCTION PuertoDir% ()	' determina la dirección del primer puerto
'
'    CTRL_5.BAS
'    Ejemplo básico de E/S digital mediante el puerto paralelo
'
'    2002 Víctor R. González
'

	CONST C5ON = &H20       ' bit 5 de control a 1

	LPTBASE% = PuertoDir    ' dirección base del primer puerto paralelo
	DATOS% = LPTBASE%       ' dirección de E/S del reg. de datos
	CONTROL% = LPTBASE% + 2 ' dirección de E/S del reg. de control


	IF LPTBASE% > 0 THEN
		' suponemos puerto bidireccional (comprobar en BIOS)

		ctrl% = INP(CONTROL%)    ' guarda el valor actual del reg. de control

		' byte para operaciones de E/S
		INPUT "Introduce el byte que se enviará al puerto: ", byte%

		OUT CONTROL%, ctrl% AND NOT (C5ON)   ' pone el puerto en modo salida

		OUT DATOS%, byte%        ' envía un byte
									 

		INPUT "Polariza las líneas del puerto y pulsa <INTRO>", tecla

		OUT CONTROL%, ctrl% OR C5ON          ' pone el puerto en modo entrada

		byte% = INP(DATOS%)      ' lee un byte

		PRINT "El valor leído es "; byte%

		OUT CONTROL%, ctrl%      ' restaura el valor original del reg. de control

	END IF

END


' Determina la dirección del primer puerto paralelo
FUNCTION PuertoDir%

	' determina los puertos instalados y sus direcciones
	DEF SEG = 0                ' selecciona el segmento de memoria 0

	FOR puerto% = 2 TO 0 STEP -1 ' número de puerto paralelo
				     ' 0 (LPT1), 1 (LPT2), 2 (LPT3)
		' dirección del puerto
		dir% = PEEK(&H408 + puerto% * 2) + 256 * PEEK(&H408 + puerto% * 2 + 1)
		IF dir% = 0 THEN
			PRINT "No hay puerto asignado a LPT"; puerto% + 1
		ELSE
			PRINT "La dirección de LPT"; puerto% + 1; " es "; dir%
		END IF
	NEXT puerto%

	PuertoDir% = dir%

END FUNCTION

Volver al principio de página

 

Programación básica de la E/S en TurboC

Todo lo anterior se puede realizar igualmente utilizando lenguaje TurboC. A continuación se ofrece el código fuente correspondiente a los programas BASIC anteriores en este lenguaje C. Obsérvense las acusadas similitudes, al menos a este nivel de programación, entre los códigos en C y en BASIC.

Para realizar el control de dispositivos mediante el puerto paralelo debemos hacer uso de las funciones de TurboC que permiten acceder a los puertos hardware. En lo que sigue se proporcionan unos ejemplos básicos de la programación de la E/S por el puerto paralelo. Estos ejemplos se presentan con un grado de estructuración creciente en el estilo de programación.

En el primer ejemplo se supone que el PC está equipado con un puerto paralelo de tipo estándar localizado en la dirección 0x378, como suele ser habitual, de modo que el registro de datos se localiza en esa misma dirección y el de estado en 0x378+1. En el ejemplo se envía un byte a las líneas de datos y se recibe un byte de las líneas de estado con las funciones outportb e inportb utilizando un estilo de programación muy básico (código equivalente a CRTL.BAS):

/*	CTRL.C
	Ejemplo básico de E/S digital mediante el puerto paralelo
		Salidas:  líneas de datos  (bits D0-D7 del registro de datos)
		Entradas: líneas de estado (bits S3-S7 del registro de estado)

	2002 Víctor R. González

	Suponemos puerto estándar en la dirección 0x378
*/


#include <stdio.h>
#include <dos.h>


main ()
{
	unsigned char byte;	/* byte para operaciones de E/S */

	printf ("Introduce el byte que se enviará al puerto: ");
	scanf("%u", &byte); getchar();

	outportb (0x378, byte);	/* envía un byte a las líneas de datos */


	printf ("Polariza las líneas de estado y pulsa una tecla\n");
	getchar();

	byte = inportb (0x378+1); /* lee un byte de las líneas de estado */
	printf ("El valor leído es %i", byte);

	return 0;
}

En el siguiente ejemplo se supone que el PC está equipado con un puerto paralelo de tipo bidireccional localizado en la dirección 0x378 de modo que el registro de datos se localiza en esa misma dirección y el de control en 0x378+2. El bit C5 del registro de control se utiliza como conmutador del modo salida (escritura en las líneas de datos) al modo entrada (lectura de las líneas de datos). En el ejemplo se envía y se recibe un byte de las líneas de datos del puerto aprovechando su capacidad bidireccional utilizando las funciones outportb e inportb sin mayores complicaciones en la programación (código equivalente a CRTL_O.BAS):

/*	CTRL_0.C
	Ejemplo básico de E/S digital mediante el puerto paralelo

	2002 Víctor R. González

	Suponemos puerto bidireccional (comprobar en BIOS)
	en la dirección 0x378
*/

#include <stdio.h>
#include <dos.h>

main ()
{
	unsigned char byte;		/* byte para operaciones de E/S */

	printf ("Introduce el byte que se enviará al puerto: ");
	scanf("%u", &byte); getchar();

	/* pone el puerto en modo salida (bit 5 del reg. CONTROL a 0) */
	outportb (0x378+2, 0);

	outportb (0x378, byte);		/* envía un byte */

	printf ("Polariza las líneas del puerto y pulsa una tecla\n"); getchar();

	/* pone el puerto en modo entrada (bit 5 del reg. CONTROL a 1: 00100000) */
	outportb (0x378+2, 32);

	byte = inportb (0x378);		/* lee un byte */

	printf ("El valor leído es %i", byte);

	return 0;
}

El siguiente ejemplo es funcionalmente idéntico al anterior, aunque se hace uso de las constantes simbólicas de C para dotar el programa de mayor elegancia y claridad. También, facilita la reprogramación en caso de que, por ejemplo, el puerto no se halle en la dirección supuesta. Obsérvese que la constante 0x378 sólo aparece ahora una vez en el código fuente, frente a las cuatro veces que lo hacía en CTRL_0.C.  Se ha hecho uso asimismo de la notación hexadecimal para los valores que activan y desactivan el bit C5 del registro de control (código equivalente a CRTL_1.BAS):

/*	CTRL_1.C
	Ejemplo básico de E/S digital mediante el puerto paralelo

	2002 Víctor R. González

	Suponemos puerto bidireccional (comprobar en BIOS)
	en la dirección 0x378
*/

#include <stdio.h>
#include <dos.h>

#define LPT_BASE	0x378		/* dirección base del puerto paralelo   */
#define DATOS		LPT_BASE	/* dirección de E/S del reg. de datos   */
#define CONTROL		LPT_BASE+2	/* dirección de E/S del reg. de control */

#define C5_ON		0x20		/* bit 5 de CONTROL a 1 */
#define C5_OFF		0x00		/* bit 5 de CONTROL a 0 */

main ()
{
	unsigned char byte;		/* byte para operaciones de E/S */

	printf ("Introduce el byte que se enviará al puerto: ");
	scanf("%u", &byte); getchar();

	outportb (CONTROL, C5_OFF );	/* pone el puerto en modo salida */

	outportb (DATOS, byte);		/* envía un byte */

	printf ("Polariza las líneas del puerto y pulsa una tecla\n"); getchar();

	outportb (CONTROL, C5_ON );	/* pone el puerto en modo entrada */

	byte = inportb (DATOS);		/* lee un byte */

	printf ("El valor leído es %i", byte);

	return 0;
}

Todavía alguna sofisticación más: esta vez no es sólo maquillaje. Cuando en los ejemplos anteriores hemos activado y desactivado el bit C5, hemos podido también modificar el estado del resto de los bits del registro de control. Normalmente, es de buen gusto respetar el estado original del puerto cuando uno finaliza la ejecución de su programa. Así pues, en el siguiente ejemplo se lee en primer lugar el estado del registro de control y se almacena en un byte (que llamamos ctrl). Cuando utilizamos outportb, lo hacemos de modo que únicamente modificamos individualmente el bit deseado, y no todos. Finalmente escribimos el byte ctrl al registro de control para recuperar el estado original. Obsérvese que se usa el operador ~ para realizar el complemento a 1 de C5_ON, de modo que nos ahorramos el definir otra constante simbólica para la condición de bit apagado (código equivalente a CRTL_2.BAS):

/*	CTRL_2.C
	Ejemplo básico de E/S digital mediante el puerto paralelo

	2002 Víctor R. González

	Suponemos puerto bidireccional (comprobar en BIOS)
	en la dirección 0x378
*/

#include <stdio.h>
#include <dos.h>

#define LPT_BASE	0x378		/* dirección base del puerto paralelo   */
#define DATOS		LPT_BASE	/* dirección de E/S del reg. de datos   */
#define CONTROL		LPT_BASE+2	/* dirección de E/S del reg. de control */

#define C5_ON		0x20		/* bit 5 de CONTROL a 1 */

main ()
{
	unsigned char byte;		/* byte para operaciones de E/S */
	unsigned char ctrl;		/* byte para estado de CONTROL  */

	ctrl = inportb(CONTROL);	/* guarda el valor actual del reg. de CONTROL */

	printf ("Introduce el byte que se enviará al puerto: ");
	scanf("%u", &byte); getchar();

	outportb (CONTROL, ctrl & ~C5_ON ); /* pone el puerto en modo salida */

	outportb (DATOS, byte);		/* envía un byte */

	printf ("Polariza las líneas del puerto y pulsa una tecla\n"); getchar();

	outportb (CONTROL, ctrl | C5_ON ); /* pone el puerto en modo entrada */

	byte = inportb (DATOS);		/* lee un byte */

	printf ("El valor leído es %i", byte);

	outportb (CONTROL, ctrl);	/* restaura el valor original del reg. de CONTROL */

	return 0;
}

Ahora un cambio significativo: vamos a determinar, y no a suponer, dónde se halla situado el puerto paralelo (consúltese la sección correspondiente  de El Puerto Paralelo del PC para conocer los detalles acerca de cómo determinar cuántos puertos se hallan instalados y qué direcciones de E/S ocupan). Para ello accedemos a la zona de memoria donde se registran las direcciones de los puertos paralelos presentes en el PC (en la zona de las variables de la BIOS), por mediación de la función peek . Una vez detectados los puertos presentes, nos quedamos con el primero y programamos la entrada-salida exactamente igual que en CTRL_2.C (código equivalente a CRTL_3.BAS):

/*	CTRL_3.C
	Ejemplo básico de E/S digital mediante el puerto paralelo

	2002 Víctor R. González

*/

#include <stdio.h>
#include <dos.h>

#define LPT_BASE	puerto_dir	/* dirección base del puerto paralelo   */
#define DATOS		LPT_BASE	/* dirección de E/S del reg. de datos   */
#define CONTROL		LPT_BASE+2	/* dirección de E/S del reg. de control */

#define C5_ON		0x20		/* bit 5 de CONTROL a 1 */

main ()
{
	unsigned char byte;		/* byte para operaciones de E/S */
	unsigned char ctrl;		/* byte para estado de CONTROL  */
	int puerto;			/* número de puerto paralelo:
					0 (LPT1), 1 (LPT2), 2 (LPT3) */
	unsigned int puerto_dir;	/* dirección del puerto */

	/* Determina los puertos instalados y sus direcciones */
	for (puerto=2; puerto>=0; puerto--) {
		LPT_BASE = peek(0x0040,0x0008 + puerto*2);
		if (LPT_BASE == 0)
			printf("No hay puerto asignado a LPT%d \n", puerto+1);
		else
			printf("La dirección de LPT%d es 0x%X\n", puerto+1, LPT_BASE);
	}

	if (LPT_BASE > 0) {
		/* Suponemos puerto bidireccional (comprobar en BIOS) */
		ctrl = inportb(CONTROL);	/* guarda el valor actual del reg. de CONTROL */
		printf ("Introduce el byte que se enviará al puerto: ");
		scanf("%u", &byte); getchar();
		outportb (CONTROL, ctrl & ~C5_ON ); /* pone el puerto en modo salida */

		outportb (DATOS, byte);		/* envía un byte */

		printf ("Polariza las líneas del puerto y pulsa una tecla\n"); getchar();
		/* pone el puerto en modo entrada */
		outportb (CONTROL, ctrl | C5_ON );
		byte = inportb (DATOS);		/* lee un byte */

		printf ("El valor leído es %i", byte);

		outportb (CONTROL, ctrl);	/* restaura el valor original del reg. de CONTROL */
	}

	return 0;
}

De nuevo, una sofisticación más que hace ganar claridad al código fuente y le proporciona mayor estructuración. Las constantes simbólicas que hemos definido hasta ahora para manejo del puerto pueden formar parte de un conjunto de definiciones que usaremos permanentemente cuando realicemos control con el puerto paralelo y que, con seguridad, ampliaremos con el uso. Así, podemos reunirlas en un archivo de cabecera (header) que incluiremos en todos nuestros programas de control. Llamaremos, por ejemplo, ctrl.h a este archivo de cabecera.

/*	CTRL_4.C
	Ejemplo básico de E/S digital mediante el puerto paralelo

	2002 Víctor R. González

*/

#include <stdio.h>
#include <dos.h>
#include "ctrl.h"

main ()
{
	unsigned char byte;		/* byte para operaciones de E/S */
	unsigned char ctrl;		/* byte para estado de CONTROL  */
	int puerto;			/* número de puerto paralelo:
					0 (LPT1), 1 (LPT2), 2 (LPT3) */

	/* Determina los puertos instalados y sus direcciones */
	for (puerto=2; puerto>=0; puerto--) {
		LPT_BASE = peek(0x0040,0x0008 + puerto*2);
		if (LPT_BASE == 0)
			printf("No hay puerto asignado a LPT%d \n", puerto+1);
		else
			printf("La dirección de LPT%d es 0x%X\n", puerto+1, LPT_BASE);
	}

	if (LPT_BASE > 0) {
		/* Suponemos puerto bidireccional (comprobar en BIOS) */
		lee_control (ctrl);	/* guarda el valor actual del reg. de CONTROL */
		printf ("Introduce el byte que se enviará al puerto: ");
		scanf("%u", &byte); getchar();
		control ( ctrl & ~C5_ON ); /* pone el puerto en modo salida */

		escribe (byte);		/* envía un byte */

		printf ("Polariza las líneas del puerto y pulsa una tecla\n"); getchar();
		/* pone el puerto en modo entrada */
		control ( ctrl | C5_ON );
		lee (byte);		/* lee un byte */

		printf ("El valor leído es %i", byte);

		control (ctrl);		/* restaura el valor original del reg. de CONTROL */
	}

	return 0;
}

Vemos que en el programa anterior han desaparecido misteriosamente todas las referencias a las funciones inportb y outportb, para dejar paso a otras como escribe, lee, lee_control y control. Ello es porque, además, en ctrl.h hemos definido unas macros con dichos nombres, de forma que la notación del programa resulta más breve y cómoda. Con una ventaja adicional muy interesante: si en algún momento queremos utilizar nuestros programas usando otro compilador diferente, seguramente las funciones de E/S no se llamarán exactamente inportb y outportb (aunque los nombres serán parecidos). Si esto sucede, un ligero retoque en nuestro archivo de cabecera permitirá dejar intactos el resto de los programas que hayamos realizado. De lo contrario, habría que seguir todas las línea de código de todos los programas para modificar la sintaxis de la referencia a dichas funciones. Véase a continuación cómo queda el mencionado archivo de cabecera.

/*	CTRL.H
	Declaraciones. constantes y macros para ejemplo básico de E/S digital
	mediante el puerto paralelo

	2002 Víctor R. González

*/
unsigned int puerto_dir;		/* dirección del puerto */

#define LPT_BASE	puerto_dir	/* dirección base del puerto paralelo   */
#define DATOS		LPT_BASE	/* dirección de E/S del reg. de datos   */
#define CONTROL		LPT_BASE+2	/* dirección de E/S del reg. de control */

#define C5_ON		0x20		/* Bit 5 de CONTROL a 1 */

#define escribe(byte)	  outportb (DATOS, byte)     /* escribe un byte en el puerto */
#define lee(byte)	  (byte = inportb (DATOS))   /* lee un byte del puerto */
#define control(byte)	  outportb (CONTROL, byte)   /* escribe un byte en las líneas de control */
#define lee_control(byte) (byte = inportb (CONTROL)) /* lee un byte de las líneas de control */

Por último, integraremos el código que localiza la dirección del puerto en una función que devuelve dicha dirección. Para ello definimos la función PuertoDir(), sin argumentos y de tipo unsigned int. Si dicha función no localiza ningún puerto devuelve un 0, lo que brinda al programa una posibilidad de terminar la ejecución cuando en un PC no existe puerto paralelo disponible (código equivalente a CRTL_5.BAS):

/*	CTRL_5.C
	Ejemplo básico de E/S digital mediante el puerto paralelo

	2002 Víctor R. González

*/

#include <stdio.h>
#include <dos.h>
#include "ctrl.h"

unsigned int PuertoDir();	/* Determina la dirección del primer puerto */

main ()
{
	unsigned char byte;		/* byte para operaciones de E/S */
	unsigned char ctrl;		/* byte para estado de CONTROL  */

	if (PuertoDir > 0) {
		/* Suponemos puerto bidireccional (comprobar en BIOS) */
		lee_control (ctrl);	/* guarda el valor actual del reg. de CONTROL */
		printf ("Introduce el byte que se enviará al puerto: ");
		scanf("%u", &byte); getchar();
		control ( ctrl & ~C5_ON ); /* pone el puerto en modo salida */

		escribe (byte);		/* envía un byte */

		printf ("Polariza las líneas del puerto y pulsa una tecla\n"); getchar();
		/* pone el puerto en modo entrada */
		control ( ctrl | C5_ON );
		lee (byte);		/* lee un byte */

		printf ("El valor leído es %i", byte);

		control (ctrl);		/* restaura el valor original del reg. de CONTROL */
	}

	return 0;
}

unsigned int PuertoDir ()
{
	int puerto;			/* número de puerto paralelo:
					0 (LPT1), 1 (LPT2), 2 (LPT3) */
	/* Determina los puertos instalados y sus direcciones */
	for (puerto=2; puerto>=0; puerto--) {
		LPT_BASE = peek(0x0040,0x0008 + puerto*2);
		if (LPT_BASE == 0)
			printf("No hay puerto asignado a LPT%d \n", puerto+1);
		else
			printf("La dirección de LPT%d es 0x%X\n", puerto+1, LPT_BASE);
	}

	return LPT_BASE;
}

Volver al principio de página

 

Actividades

Puesto que se trata de un montaje inicial, en el que se es posible sacrificar el orden respecto de la sencillez, se puede llevar a cabo uniendo directamente con regletas los componentes a los cables, e introduciendo estos en en las hembrillas del conector del PC. Por supuesto, es preferible realizar montajes más estables del estilo de los que se exponen en la actividad 2: Interfaces básicos de E/S con el p. paralelo: salidas-entradas digitales.
Nota: no es preciso puentear exteriormente entre sí las líneas 18-25 puesto que cada una de ellas es ya la tierra del puerto.

En éste montaje se ha conectado un LED (salida digital)  en el pin  2 del puerto (bit D0 del registro de datos) y un interruptor (entrada digital) en el pin 15 (bit S3 del registro de estado).
- Realícese un programa en QBasic para la iluminación del LED y para la detección del estado del interruptor (véase el programa CTRL.BAS de la sección Programación básica de la E/S en QBasic).
- Realícese un programa en TurboC para la iluminación del LED y para la detección del estado del interruptor (véase el programa CTRL.C de la sección Programación básica de la E/S en TurboC).

Ahora se supone que el puerto paralelo tiene capacidad bidireccional y se ha conectado el interruptor (entrada digital) en el pin 3 del puerto (bit D1 del registro de datos).
- Realícese un programa en QBasic para la iluminación del LED y para la detección del estado del interruptor (véase el programa CTRL_0.BAS de la sección Programación básica de la E/S en QBasic).
- Realícese un programa en TurboC para la iluminación del LED y para la detección del estado del interruptor (véase el programa CTRL_0.C de la sección Programación básica de la E/S en TurboC).

Volver al principio de página

volver a Inicio