Conversión Digital/Analógico

Anuncio
Conversión Digital / Analógico
PRECAUCION: Conectar dispositivos al puerto paralelo implica el riesgo de daños
permanentes a la tarjeta madre de la PC, tenga siempre presente que aún los
profesionales cometen errores, por lo tanto no está de más recomendarle extremo
cuidado al trabajar en el puerto paralelo. Lea el contenido total de éste artículo y
asegúrese de comprenderlo cabalmente. Se recomiendan conocimientos sólidos en
electrónica y programación para manipular el puerto paralelo. Éste artículo tiene el
carácter de informar exclusivamente, si bien el material presentado refleja
fielmente las prácticas y resultados obtenidos en un computador
Las computadoras son dispositivos digitales. En una computadora toda la
información se maneja en términos de bits que toman uno de dos valores. El
mundo real, sin embargo, es analógico. Por analógico entendemos la serie de
cambios lineales que se manifiestan en el orden natural de las cosas, por ejemplo,
la temperatura del medio ambiente cambia gradualmente, el agua fluye
suavemente, etc. Todas las entradas sensoriales en un ser humano reciben datos
en forma analógica. Cuando las personas empezaron a diseñar máquinas
"pensantes" rápidamente descubrieron que los dispositivos que operan bajo
principios analógicos eran complicados, sensibles y poco confiables. El problema
necesitaba simplificarse, ¿Qué mejor que permitir no más que dos estados
posibles? ¿Cómo puede una computadora, es decir un dispositivo binario, trabajar
con fenómenos del mundo real?
Existen dos mecanismos principales con los cuales una computadora puede
interactuar con el mundo real, uno llamado conversión Digital / Analógico abreviado
D/A, y el otro denominado conversión Analógico / Digital por lo general abreviado
A/D. El proceso más simple de los dos es el que trataremos en primer lugar en
éste artículo, la conversión D/A.
Teoría del convertidor D/A
El convertidor D/A puede ser considerado como un potenciómetro digital
programable controlado digitalmente para producir una salida analógica, éste valor
de salida (VSALIDA) es el producto de una señal digital (D) y un voltaje analógico de
referencia (VREF) expresado en la siguiente ecuación:
VSALIDA = DVREF
En términos generales, ningún convertidor D/A o A/D es de gran utilidad sin la
especificación del tipo de código usado para representar la magnitud digital. Los
convertidores trabajan con códigos digitales monopolares o bipolares. El monopolar
incluye el binario puro y el decimal codificado en binario (BCD). El binario
desplazado, código Gray y complemento a uno o complemento a dos se suelen
reservar para la operación bipolar. De acuerdo con la fórmula de arriba, la cantidad
binaria presentada por la computadora es un valor fraccionario que se multiplica
por una tensión de referencia. En fracciones binarias, el bit más significativo (MSB)
tiene un valor de 2-1, el siguiente bit tiene un valor igual a 2-2 y el bit menos
significativo (LSB) es 2-n (en donde n es el número de lugares a la derecha del
punto binario). La suma de todos los bits produce un valor cuyo límite tiende a 1. A
la diferencia algebraica entre el valor binario próximo a 1 y el valor 1 se le
denomina error de cuantización del sistema digital.
La conversión de valores digitales en valores analógicos proporcionales es
realizada por una u otra de dos técnicas básicas de conversión: el convertidor D/A
de
resistencias
ponderadas
(equilibradas)
y
el
convertidor
D/A R-2R. El
convertidor
D/A
de
resistencias
ponderadas
es,
hasta
ahora,
el
circuito más
simple
y
más directo,
requiere
solamente
una
resistencia
por bit y
trabaja como
sigue:
los
conmutadores
son
controlados directamente por
las señales que representan
el número digital D, corrientes
con magnitudes de 2-1, 2-2,
...2-n son generadas por
resistencias de magnitudes
R, 2R, ...2nR que están
conectadas por medio de
interruptores
entre
una
tensión de referencia VREF y
el punto sumador de un
amplificador
operacional.
Las diversas
corrientes se
suman y son
convertidas
en
tensión
por
el
amplificador
operacional.
La exactitud
del
convertidor
de
resistencias
ponderadas
está
en
función
directa de las
respectivas
tolerancias de
las
resistencias
utilizadas, la
resistencia de
los
interruptores
y
el
desempeño
del
amplificador utilizado, cuando la resolución es mayor que 10 bits, los valores de las
resistencias son demasiado grandes y por tanto la magnitud de la corriente
demasiado pequeña de tal forma que la señal se pierde a causa del ruido térmico
en la etapa amplificadora.
Para resolver el problema planteado por el convertidor D/A de resistencias
ponderadas se utiliza un circuito conocido como convertidor D/A R-2R, también
llamado convertidor de escalera, éste circuito también contiene un voltaje de
referencia, un amplificador, un conjunto de interruptores y una red de resistencias
cuyos dos únicos valores son de magnitud igual a R y 2R. Una resistencia de
magnitud 2R está en serie con el interruptor de bit, mientras que la otra resistencia
de magnitud R está en la línea sumadora, de tal manera que se forma una red en
"pi". Esto implica que las impedancias en las tres ramas de cualquier nodo son
iguales y que la corriente I que llega a un nodo a través de una rama sale como
I/2 a través de las otras dos ramas. En palabras simples, la posición de un
interruptor, con respecto al punto donde la corriente es medida, determina el
significado binario del cierre del interruptor en particular. Este tipo de convertidor
es fácil de construir puesto que sólo son necesarios dos valores de resistencia, de
hecho, un solo valor para R será suficiente si se utilizan tres componentes por cada
bit, el mantener adaptados los valores de las resistencias con el mismo coeficiente
de temperatura contribuye a un diseño muy estable.
Volver al principio
El convertidor D/A MC1408-8
Es posible construir una red de escalera R-2R para simular la conversión D/A,
pero definitivamente es más práctico utilizar un circuito integrado construido en
base a una red R-2R, me refiero al MC1408-8 fabricado por Motorola, éste
componente tiene un diseño estable, es ampliamente conocido, barato y disponible
prácticamente en cualquier lugar. Se trata de un convertidor D/A de 8 bits, es
decir, ideal para manejarlo con el puerto paralelo de la PC.
En el diagrama de la izquierda podemos apreciar los puntos importantes a
considerar para trabajar con el convertidor D/A
MC1408-8. Las entradas digitales aceptan
niveles TTL por lo que es posible conectarlo
directamente a la salida del puerto paralelo, sin
embargo es conveniente manejar una etapa
separadora como se explica en el artículo
referente al puerto paralelo. La corriente en la
patita 14 es típicamente de 2 mA, los valores
de R1 y R2 son por lo general iguales a 2.0 ~
3.3 KOhms, el voltaje de referencia se situa en
el orden de 4.0 ~ 6.9 Voltios y se requieren
voltajes de alimentación de +5 V. para VCC, -12
V. para VEE y de +12 V. para derivar el voltaje
de referencia VREF. Cuando se aplica un valor
binario a la entrada igual a 11111111 existe
una corriente remanente igual al bit menos
significativo, ésta corriente se deriva a tierra
dando como resultado una corriente de salida
máxima igual a 255/256 de la corriente de referencia proporcionada, en el caso
típico, para una corriente de referencia en la patita 14 igual a 2 mA. la máxima
corriente de salida sería igual a 1.992 mA. Con éstos datos en mente, hagamos el
diseño de un convertidor D/A basado en el MC1408-8 manejado por software a
través del puerto paralelo de la PC.
Hardware para el convertidor D/A
En la figura de la derecha podemos apreciar el diagrama completo de un
convertidor D/A basado en el circuito integrado MC1408-8 controlado por el puerto
paralelo de la PC. Utilizo un CI 74LS244 como etapa separadora para protección del
puerto, las ocho salidas de datos se conectan directamente a las ocho entradas del
MC1408-8. Un diodo zener de 6.8 V. y 1/2 W. establece el nivel de voltaje de
referencia en tanto que un resistor variable de 10,000 Ohms se utiliza para ajustar
el nivel de la corriente de referencia en la patita 14. Para operar éste circuito,
además del software que discutiremos en la siguiente sección, se requiere hacer un
pequeño proceso de calibración, para ésto insertamos un miliamperímetro en la
línea de entrada de la patita 14 del MC1408-8 y ajustamos el potenciómetro de
10,000 Ohms para una lectura de exactamente 2 mA. El otro ajuste necesario tiene
que ver con el nivel de salida del amplificador, pero éste valor lo determinamos una
vez que el circuito esté en operación bajo control del puerto paralelo de la PC. El
amplificador operacional puede ser cualquier unidad de propósito general.
Software para el convertidor D/A
El objetivo general de éste artículo es demostrar la conversión D/A utilizando el
puerto paralelo de la PC. Con 8 bits de resolución podemos obtener 255 valores
diferentes, con una aplicación así de sencilla un programa para Windows 9x. resulta
ideal para demostrar el funcionamiento del convertidor D/A además que
aprovechamos la conveniencia que proporciona una interfaz gráfica de usuario.
Desafortunadamente, en Windows 9x. no es igual de sencillo trabajar con el puerto
paralelo de la PC pues ésto implica programar directamente el hardware lo que
viola el principio de independencia de dispositivos propio de Windows 9x. Sin
embargo no es imposible, tenemos básicamente dos caminos por seguir, uno
implica programar el spooler de impresión para enviar los datos al puerto paralelo,
cosa poco práctica pues en éste caso no nos interesa ejecutar un procedimiento de
impresión. Recuerde que Windows 9x supone que el puerto paralelo sirve
exclusivamente para conectar impresoras. El otro camino a seguir es lo que
personalmente llamo "la solución a la Mexicana".
Si deseamos operar nuestro convertidor D/A en un ambiente Windows debemos
tomar en cuenta que éste sistema operativo se apropia de todos los recursos de la
máquina y como consecuencia del manejo virtual de memoria que hace Windows
nos resulta imposible leer el contenido de la ubicación de memoria 0x00000408h
para determinar las direcciones de los puertos paralelo instalados en la PC. La
solución que propongo en éste artículo es crear un programa para DOS que nos
aporte la información necesaria de las direcciones de los puertos y la almacene en
un archivo temporal. Una vez que contamos con la información necesaria de las
direcciones de puerto paralelo todo se reduce a utilizar la ya conocida función
outp( ) para escribir los datos necesarios al puerto seleccionado. El código es el
siguiente:
/**********************************************************
* det.c
*
* Genera un archivo de información de puertos
* (c)1999, Virgilio Gómez Negrete
*
*
**********************************************************/
#include <stdio.h>
int main()
{
unsigned int __far *direccion;
int i;
FILE *puertos;
direccion = (unsigned int __far *) 0x00000408;
puertos = fopen("Puertos.ini", "w");
for (i=0; i<3; i++)
{
fprintf(puertos, "%d ", *direccion);
direccion++;
}
fclose(puertos);
return 0;
}
Como se puede apreciar, el programa det.c genera un archivo llamado
Puertos.ini en donde se almacena la información del(los) puerto(s) disponibles en
la PC, cada dato separado por un espacio, si no se encuentra un puerto disponible
se almacena el valor de 0, en caso de encontrar un puerto paralelo se almacena la
dirección del mismo en formato decimal. Para operar la interfaz gráfica de usuario
para nuestro convertidor D/A es indispensable compilar el código llamado det.c
para producir el ejecutable det.exe, éste programa será llamado vía software por
el programa principal llamado dacwin.exe que es en sí nuestro programa principal
para el convertidor D/A. El código del programa principal es el siguiente:
//*********************************************************
// dacwin.c
// Controlador para el convertidor D/A
// (c)1999, Virgilio Gómez Negrete
//*********************************************************
#include <windows.h>
#include <stdio.h>
#include <dos.h>
#include <string.h>
#define IDM_ACERCADE 1
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
HWND hwndScroll, hwndEdit, hwndBoton1, hwndBoton2, hwndStatic1,
hwndStatic2, hwndStatic3, hwndRadio1, hwndRadio2, hwndRadio3;
int posicion;
char szAppName[] = "dacwin";
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HMENU
hMenu;
HWND
hwnd;
MSG
msg;
WNDCLASSEX wndclass;
wndclass.cbSize
wndclass.style
= sizeof (wndclass);
= CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra
= 0;
wndclass.cbWndExtra
wndclass.hInstance
wndclass.hIcon
wndclass.hCursor
= 0;
= hInstance;
= LoadIcon (hInstance, szAppName);
= LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE +1);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
wndclass.hIconSm
= LoadIcon (hInstance, szAppName);
RegisterClassEx (&wndclass);
hwnd = CreateWindow (szAppName, "Controlador para el convertidor D/A",
WS_OVERLAPPED | WS_SYSMENU |WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, 355, 305,
NULL, NULL, hInstance, NULL);
hwndStatic1 = CreateWindow("button", "Indicador binario de salida",
WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
0, 0, 0, 0, hwnd, (HMENU)0, hInstance, NULL);
hwndStatic2 = CreateWindow("button", "Puerto paralelo",
WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
0, 0, 0, 0, hwnd, (HMENU)1, hInstance, NULL);
hwndRadio1 = CreateWindow("button", "LPT 1",
WS_CHILD | WS_VISIBLE | WS_DISABLED | BS_RADIOBUTTON,
0, 0, 0, 0, hwnd, (HMENU)2, hInstance, NULL);
hwndRadio2 = CreateWindow("button", "LPT 2",
WS_CHILD | WS_VISIBLE | WS_DISABLED | BS_RADIOBUTTON,
0, 0, 0, 0, hwnd, (HMENU)3, hInstance, NULL);
hwndRadio3 = CreateWindow("button", "LPT 3",
WS_CHILD | WS_VISIBLE | WS_DISABLED | BS_RADIOBUTTON,
0, 0, 0, 0, hwnd, (HMENU)4, hInstance, NULL);
hwndBoton1 = CreateWindow("button", "Detectar puerto",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0, 0, 0, 0, hwnd, (HMENU)5, hInstance, NULL);
hwndStatic3 = CreateWindow("button", "Datos de salida",
WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
0, 0, 0, 0, hwnd, (HMENU)6, hInstance, NULL);
hwndScroll = CreateWindow("scrollbar", NULL,
WS_CHILD | WS_VISIBLE | WS_DISABLED | SBS_HORZ,
0, 0, 0, 0, hwnd, (HMENU)7, hInstance, NULL);
hwndEdit = CreateWindow("edit", NULL,
WS_CHILD|WS_VISIBLE|WS_BORDER|ES_CENTER|ES_MULTILINE|ES_READONLY,
0, 0, 0, 0, hwnd, (HMENU)8, hInstance, NULL);
hwndBoton2 = CreateWindow("button", "Cerrar",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
0, 0, 0, 0, hwnd, (HMENU)9, hInstance, NULL);
SetScrollRange(hwndScroll, SB_CTL, 0, 255, FALSE);
SetScrollPos(hwndScroll, SB_CTL, 0, FALSE);
hMenu = GetSystemMenu (hwnd, FALSE);
AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
AppendMenu(hMenu, MF_STRING, IDM_ACERCADE, "Acerca de...");
ShowWindow (hwnd, iCmdShow);
UpdateWindow (hwnd);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg,
WPARAM wParam, LPARAM lParam)
{
char
szBuffer[48];
static int direccion, puerto1, puerto2, puerto3;
HDC
hdc;
PAINTSTRUCT ps;
RECT
rect;
HBRUSH
FILE
hBrush;
*ini;
switch (iMsg)
{
case WM_CREATE:
WinExec("det.exe", SW_SHOWMINNOACTIVE);
return 0;
case WM_SIZE:
MoveWindow(hwndStatic1, 10, 5, 330, 75, TRUE);
MoveWindow(hwndStatic2, 10, 85, 330, 60, TRUE);
MoveWindow(hwndStatic3, 10, 150, 330, 80, TRUE);
MoveWindow(hwndRadio1, 20, 110, 60, 20, TRUE);
MoveWindow(hwndRadio2, 85, 110, 60, 20, TRUE);
MoveWindow(hwndRadio3, 150, 110, 60, 20, TRUE);
MoveWindow(hwndBoton1, 220, 105, 110, 30, TRUE);
MoveWindow(hwndBoton2, 125, 240, 100, 30, TRUE);
MoveWindow(hwndScroll, 20, 200, 310, 20, TRUE);
MoveWindow(hwndEdit, 20, 170, 310, 20, TRUE);
return 0;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case 2:// Boton "LPT1"
SendMessage (hwndRadio1, BM_SETCHECK, 1, 0);
SendMessage (hwndRadio2, BM_SETCHECK, 0, 0);
SendMessage (hwndRadio3, BM_SETCHECK, 0, 0);
direccion = puerto1;
EnableWindow(hwndScroll, TRUE);
SetFocus(hwndScroll);
break;
case 3:// Boton "LPT2"
SendMessage (hwndRadio1, BM_SETCHECK, 0, 0);
SendMessage (hwndRadio2, BM_SETCHECK, 1, 0);
SendMessage (hwndRadio3, BM_SETCHECK, 0, 0);
direccion = puerto2;
EnableWindow(hwndScroll, TRUE);
SetFocus(hwndScroll);
break;
case 4:// Boton "LPT3"
SendMessage (hwndRadio1, BM_SETCHECK, 0, 0);
SendMessage (hwndRadio2, BM_SETCHECK, 0, 0);
SendMessage (hwndRadio3, BM_SETCHECK, 1, 0);
direccion = puerto3;
EnableWindow(hwndScroll, TRUE);
SetFocus(hwndScroll);
break;
case 5:// Boton "Detectar puerto"
ini = fopen("Puertos.ini", "r");
fscanf(ini, "%d", &puerto1, &puerto2, &puerto3);
fclose(ini);
if(puerto1 != 0)
EnableWindow(hwndRadio1, TRUE);
if(puerto2 != 0)
EnableWindow(hwndRadio2, TRUE);
if(puerto3 != 0)
EnableWindow(hwndRadio3, TRUE);
EnableWindow(hwndBoton1, FALSE);
if((puerto1==0)&&(puerto2==0)&&(puerto3==0))
{
MessageBox(hwnd, "No existe puerto paralelo",
"dacwin.exe", MB_OK|MB_ICONSTOP);
SendMessage(hwnd, WM_CLOSE, 0, 0);
}
break;
case 9:// Boton "Cerrar"
outp(direccion, 0);
SendMessage(hwnd, WM_CLOSE, 0, 0);
break;
default:
break;
}
return 0;
case WM_HSCROLL:
switch(LOWORD(wParam))
{
case SB_PAGEDOWN:
posicion += 15;
case SB_LINEDOWN:
posicion = min(255, posicion + 1);
break;
case SB_PAGEUP:
posicion -= 15;
case SB_LINEUP:
posicion = max(0, posicion - 1);
break;
case SB_TOP:
posicion = 0;
break;
case SB_BOTTOM:
posicion = 255;
break;
case SB_THUMBPOSITION:
case SB_THUMBTRACK:
posicion = HIWORD(wParam);
break;
default:
break;
}
SetScrollPos(hwndScroll, SB_CTL, posicion, TRUE);
sprintf(szBuffer, "Valor binario escrito al puerto: %08b ",
posicion);
SetWindowText(hwndEdit, szBuffer);
InvalidateRect(hwnd, NULL, FALSE); // FALSE para evitar parapadeo
outp(direccion, posicion);
return 0;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
SetBkColor(hdc, GetSysColor (COLOR_BTNFACE));
SetTextColor(hdc, GetSysColor (COLOR_WINDOWTEXT));
TextOut(hdc, 25, 60, "D7", 2);
TextOut(hdc, 65, 60, "D6", 2);
TextOut(hdc, 105, 60, "D5", 2);
TextOut(hdc, 145, 60, "D4", 2);
TextOut(hdc, 185, 60, "D3", 2);
TextOut(hdc, 225, 60, "D2", 2);
TextOut(hdc, 265, 60, "D1", 2);
TextOut(hdc, 305, 60, "D0", 2);
if(posicion&128)
{
SetRect(&rect, 20, 25, 50, 55);
hBrush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
else
{
SetRect(&rect, 20, 25, 50, 55);
hBrush = CreateSolidBrush(RGB(0, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
if(posicion&64)
{
SetRect(&rect, 60, 25, 90, 55);
hBrush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
else
{
SetRect(&rect, 60, 25, 90, 55);
hBrush = CreateSolidBrush(RGB(0, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
if(posicion&32)
{
SetRect(&rect, 100, 25, 130, 55);
hBrush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
else
{
SetRect(&rect, 100, 25, 130, 55);
hBrush = CreateSolidBrush(RGB(0, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
if(posicion&16)
{
SetRect(&rect, 140, 25, 170, 55);
hBrush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
else
{
SetRect(&rect, 140, 25, 170, 55);
hBrush = CreateSolidBrush(RGB(0, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
if(posicion&8)
{
SetRect(&rect, 180, 25, 210, 55);
hBrush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
else
{
SetRect(&rect, 180, 25, 210, 55);
hBrush = CreateSolidBrush(RGB(0, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
if(posicion&4)
{
SetRect(&rect, 220, 25, 250, 55);
hBrush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
else
{
SetRect(&rect, 220, 25, 250, 55);
hBrush = CreateSolidBrush(RGB(0, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
if(posicion&2)
{
SetRect(&rect, 260, 25, 290, 55);
hBrush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
else
{
SetRect(&rect, 260, 25, 290, 55);
hBrush = CreateSolidBrush(RGB(0, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
if(posicion&1)
{
SetRect(&rect, 300, 25, 330, 55);
hBrush = CreateSolidBrush(RGB(255, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
else
{
SetRect(&rect, 300, 25, 330, 55);
hBrush = CreateSolidBrush(RGB(0, 0, 0));
FillRect(hdc, &rect, hBrush);
DeleteObject(hBrush);
}
EndPaint (hwnd, &ps);
return 0;
case WM_SYSCOMMAND:
switch(LOWORD(wParam))
{
case IDM_ACERCADE:
MessageBox(hwnd,
"Convertidor D/A\n©1999, Virgilio Gómez Negrete",
szAppName, MB_OK | MB_ICONINFORMATION);
return 0;
}
break;
case WM_DESTROY:
PostQuitMessage (0);
DeleteFile("Puertos.ini");
return 0;
}
return DefWindowProc (hwnd, iMsg, wParam, lParam);
}
No se impresione por la longitud del código, en realidad es sencillo aunque
redundante como todo programa para Windows 9x. Prácticamente todo el programa
consiste en crear y colocar en posiciones específicas una serie de controles
comunes propios de Windows. El programa empieza rellenando los espacios de una
estructura WNDCLASSEX y luego crea tanto la ventana principal como los controles
que utilizamos para manipular nuestro convertidor D/A utilizando repetidas veces la
función CreateWindow( ). Posteriormente se llama al procedimiento de ventana que
es donde se ejecuta toda la acción del programa, en primer lugar y como respuesta
a un mensaje WM_CREATE utilizamos la función WinExec( ) para ejecutar el
programa llamado det.exe, como ya sabemos, éste genera un archivo llamado
Puertos.ini. Después que se ejecuta el mensaje WM_SIZE nuestro programa está
completamente visible en pantalla y listo para trabajar. Compilado correctamente
debe verse así:
Inicialmente, el botón marcado con el texto "Detectar puerto" se encuentra
activado, al hacer clic en éste botón el programa recupera la información
almacenada en el archivo Puertos.ini, si existe una dirección válida, es decir, un
valor diferente de cero, activa el botón de radio correspondiente (LPT1 en la
figura); para valores iguales a cero, lo que implica la ausencia de un puerto
paralelo, el respectivo botón de radio queda inhabilitado. Lo que sigue es hacer clic
en la(s) opción(es) presentada(s) por el programa para decidir en que puerto
vamos a manejar nuestro convertidor D/A. Al hacer clic en una opción se activa la
barra de desplazamiento horizontal, que es la que nos permite escribir datos en un
rango comprendido entre 0 y 255 en el puerto paralelo seleccionado. Conforme
avanzamos el cuadro de desplazamiento podemos ver una representación gráfica
de los datos a la vez que una pantalla nos muestra textualmente el valor binario
escrito al puerto. En efecto, nuestro indicador visual sustituye en software a los
diodos emisores de luz que utilizamos en el artículo referente al puerto paralelo de
la PC comprobandose así lo dicho en el artículo referente al álgebra booleana, es
decir cualquier algoritmo que podamos implementar en software, lo podemos a su
vez implementar directamente en hardware, y visceversa. Éste programa nos
muestra en forma visual la relación existente entre un 1 binario y una señal positiva
presente en el puerto. Para una explicación más amplia del funcionamiento de un
código para Windows 9x. consulte la sección de Programando Windows 9x. Cuando
termine de utilizar el programa haga clic en el botón "Cerrar", ésta acción escribe
un valor de cero en el puerto y a su vez envía un mensaje WM_CLOSE a la ventana
principal para cerrar definitivamente el programa. Antes de destruir la ventana de
la aplicación, el programa borra el archivo llamado Puertos.ini.
Ajuste final al hardware del convertidor
Contando yá con el controlador para el convertidor D/A es tiempo de hacer el
último ajuste en hardware, escribiendo un valor de 255 al puerto ajustamos el
potenciómetro de 5K. para que la salida de voltaje del amplificador tenga el nivel
conveniente al uso que le daremos al convertidor. Suponiendo que necesitamos
obtener un valor de voltaje máximo de 5 Voltios a la salida del convertidor, cada
etapa del convertidor puede representar un nivel de voltaje igual a 5/255 = 0.019
Voltios, incrementos de voltaje prácticamente imposibles de obtener por medios
análogos económicos.
Descargas
El código fuente de los programas descritos en éste artículo, así como los
programas compilados los puede Usted obtener en el archivo llamado dacwin.zip
archivo comprimido de 24.3 Kb.
© 1999 Virgilio Gómez Negrete, Derechos Reservados
Descargar