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