Está en la página 1de 27

TECNM-Instituto Tecnológico de la Laguna Diseño Digital Avanzado

Profesor: Dr. Juan Sifuentes Mijares

Sistema DAQ por FPGA con sensor de gas butano hacia software en
.NET con geolocalización por IP y almacenamiento en la nube

Nombre del Alumno: Jesús Octavio Olivares González


No de control: M2213007

Nombre del Alumno: Linda Patricia Martínez Rodríguez


No de control: M2213001

Abstract – El siguiente reporte explica a detalle el diseño de un Sistema de Adquisición de


Datos, que va desde el ensamble del circuito y programación de un convertidor de señal
analógica-digital ADC0804 para un sensor de gas butano MQ-135; el código VHDL para una
FPGA que recibe dicho dato en 8 bits y lo transforma en una cifra de 4 dígitos, que se transmite
por comunicación UART hacia una computadora; la codificación de una aplicación .NET que se
conecta a los puertos seriales que recolectan la información de la FPGA; el diseño de una base de
datos en MySQL para almacenar las mediciones; y el desarrollo y despliegue de una API REST en
.NET Core consumida por la aplicación .NET y una aplicación web para graficar y generar
reportes con los datos.
Keywords: VHDL, Xilinx, Spartan3, MQ-135, ADC0804, FPGA, UART, RS-232, HyperTerminal,
Proteus, .NET, .NET Core, C#, API REST, MySQL

valores fue orientado hacia la ecuación


característica de la medición de gas butano. Su
I. Introducción
lectura de datos en bruto se desarrolla en unión con
un convertidor de señal analógica-digital ADC0804,
Se aplica la instrumentación electrónica al ensamblado en un circuito en físico y da como
ensamblar un circuito convertidor de señal resultado a un valor digital de 8 bits, pudiendo ser
analógica-digital a partir de un transductor leído sólo a través de una FPGA.
electroquímico; el diseño digital se encuentra en la
codificación en lenguaje VHDL de un circuito El circuito digital desarrollado en la FPGA permite:
digital que permite recibir y procesar la información 1) Recibir un dato de 8 bits de un convertidor
del convertidor en bruto y la transforma en un dato de señal A-D configurado en modo
descifrable para otros aparatos electrónicos. Cuando automático, es decir, sin tomar en cuenta
el dato está listo, éste se transmite por ningún mecanismo de interrupción.
comunicación serial (UART) desde la FPGA hacia 2) Traducir los 8 bits de hexadecimal a BCD
una computadora que recolecta estos valores (Binary-Coded Decimal) hacia un valor
mediante un software desarrollado específicamente decimal codificado en binario, hasta
para este instrumento. conformar una cifra con centenas, decenas
Finalmente, el Cloud Computing se hace presente y unidades.
cuando esta aplicación de escritorio carga los datos 3) Dar salida al dato legible, conservando la
de las mediciones con una API REST, que congruencia determinada por la lógica con
almacena los datos en una base de datos alojada en la que fue programada el convertidor, es
un VPS, para que este recurso sea consumible por decir, que el mismo valor que haya sido
cualquier servicio (ej., una aplicación web, móvil o enviado por el convertidor, sea el mismo
de escritorio), y la información pueda ser utilizada que salga por la FPGA.
con diversos fines (ej., reportes estadísticos,
gráficas en tiempo real, consultas, etc.,). De esta manera, el valor resultante puede ser legible
para cualquier dispositivo compatible con
La instrumentación comienza con un sensor de comunicación serial. Sin embargo, para este
gases MQ-135, cuyo funcionamiento y cálculo de instrumento se desarrolló una aplicación de
escritorio en .NET, específicamente en lenguaje de
programación C#, que pudiera recibir información
por cualquiera de los puertos COM. Debido a que
la FPGA sólo permite conexión por su puerto RS-
232 y las computadoras actuales sólo poseen
puertos USB para transmisión de datos, se
consideró el uso de un cable adaptado con una
punta RS-232 de un extremo y del otro, con punta
USB.

Una vez que el software recoge sólo 3 caracteres


(correspondientes al valor decimal con centenas) de
la línea de datos que envía la FPGA cada segundo,
el valor se registra en la API por una petición HTTP Fig. 1. Configuración en modo automático del C.I.
de tipo POST. Este proceso se automatiza por un ADC0804
componente .NET llamado Timer, programado a
ejecutarse cada 2 segundos (2000 milisegundos)
para propiciar una mayor precisión de
instrumentación e incrementar la claridad y calidad II.2. Paso No.2 Simulación de ADC0804 a lectura
de la posterior interpretación de la información automática
almacenada.

Posteriormente se desarrolla la simulación del


diagrama electrónico propuesto para la conversión
del dato, haciendo uso del software Proteus
II. Desarrollo 8.2.(Fig.2.).

Para el desarrollo del proyecto se utilizó el


software de simulación Proteus 8.2, para la
simulación de la etapa de conversión analógico-
digital de 8 bits; la herramienta virtual
HyperTerminal configurada para emplear como
monitor serial; y el programa Xilinx ISE Design
Suite 8.2, en una máquina virtual con sistema
operativo Windows XP Service Pack 3, teniendo
Windows 11 como sistema operativo anfitrión.

Se redacta a continuación la metodología seguida Fig. 2. Simulación del C.I. ADC0804 en modo
para el desarrollo del proyecto. automático

II.1. Paso No.1 Diagrama Electrónico Se analiza el resultado de la simulación para


determinar que es correcta y se puede implementar
físicamente con éxito.
Se propone un diagrama electrónico para la
conversión del voltaje analógico a un dato digital,
que se obtiene de la señal del sensor de gas. (Fig.
1.).
II.3. Paso No.3 Diseño Básico en Xilinx
Desde el navegador del programa seleccionar
File > New Project.
placa Spartan 3E, con las especificaciones que se
detallan en seguida:

Device Family: Spartan3

Device: XC3S200

Package: FT256

Speed Grade: -5

Synthesis tool: XST (VHDL/Verilog)

Simulator: ISE Simulator (VHDL/Verilog)

Fig. 3. Asistente de Nuevo proyecto

II.4. Paso No. 4 Nombre y propiedades

En el asistente de creación de nuevos


proyectos de Xilinx ISE, se determina el nombre del
proyecto, la ruta de ubicación del mismo y el tipo
de fuente de alto nivel (que por defecto se mantiene
en HDL). Para ello, esta información se completa en Fig. 5. Ventana de propiedades del proyecto
un cuadro de diálogo, como el que se muestra a
continuación en la Fig. 4.: II.5. Paso No. 5 Añadir Ficheros y puertos

El siguiente paso es crear un nuevo recurso, una


vez configuradas las características de trabajo del
proyecto. Entonces se despliega el cuadro de
diálogo “Create a New Source”, donde se
seleccióna el botón “New Source”.
Fig. 4. Nombre del proyecto.

Es recomendable crear una carpeta de trabajo en C:\

Para elegir la carpeta de destino, se debe pulsar el


botón “…” y una vez seleccionado el destino, se
pulsa “OK”.
Se debe asignar un nombre al proyecto, en este
caso se definió como “serstring”.

Tal como se aprecia en la Fig. 5., se establecen


las siguientes características para el diseño del Fig. 6. Seleccionar New Source
circuito, de acuerdo a la FPGA que se programará
en físico. Estas especificaciones deberán seguirse al Al terminar de especificar las características del
pie de la letra, en el cuadro de diálogo que las dispositivo para el cual se diseñará el circuito, se
pregunta. Este proyecto se desarrolla sobre una
deberá crear una nueva fuente, concretamente, un
módulo VHDL.
En el nuevo cuadro de diálogo, se selecciona el II.6. Paso No. 6 Creación de nuevos proyectos y
tipo VHDL Module para la nueva fuente a crear y concatenación con proyecto principal
se nombra igual que al proyecto raíz.
Para esta parte del proceso, se crea nuevos
proyectos repitiendo los pasos anteriores (Paso
No.1 a Paso No. 4), que, posteriormente, se
enlazarán al proyecto principal para reutilizar el
código.

Para vincular otros proyectos al principal, en el


panel izquierdo se da clic derecho sobre el objeto
serstring y se selecciona el submenú Add Copy
of Source para agregar el archivo .vhd del
proyecto que se desea vincular.
Fig. 7. Ventana de selección del tipo de recurso

En el siguiente cuadro de diálogo “Define Module”


se establecen los puertos de entrada y salida que
contemplará el diseño del circuito. Esto puede
modificarse después de forma manual, a través del
archivo .vhd que se genera.

Fig. 10. Adición de una copia de fuente

Por consecuente, se abre el cuadro de diálogo de


selección de archivos, en donde el usuario podrá buscar
la ruta en la que se encuentra el proyecto a vincular, y
Fig. 8. Definición de puertos elegir el archivo con extensión .vhd que requiere.

El código por default que se generó, fue el


siguiente:

Fig. 11. Copia de archivo fuente seleccionado

Fig. 9. Código VHDL por default


Nota: Para este proyecto es necesario agregar todas pueden localizar los componentes externos ya
las copias de los archivos fuente, por lo que se vinculados, pero definidos después de la línea de
repite esta acción, por cada proyecto a enlazar. código "architecture Behavioral of serstring is".

Se visualizan estos archivos fuente agregados El componente bcd, como se mencionó en párrafos
correctamente en el panel izquierdo Sources, anteriores, corresponde al convertidor de datos de 8
debajo de la fuente principal. bits hexadecimales hacia BCD. En tanto, el
componente reg_corr es el proyecto del que
depende la transmisión de datos por comunicación
serial para que ésta se lleve a cabo sin errores, pues
se trata del procedimiento para el corrimiento de
cada dato de envío.

Fig. 12. Proyectos vinculados Después de múltiples pruebas para concluir en este
procedimiento de resolución de este proyecto, se
determinó que este componente no debía dejarse de
Se accede con doble clic sobre la copia del primer lado, muy a pesar de tener las máquinas de estados
archivo fuente para copiar el código de la entidad necesarias para la transmisión de datos.
que le corresponde.
El código mostrado en la Fig. 13., es el del proyecto
de un convertidor de datos hexadecimales a datos
BCD (Binary-Coded Decimal).

Fig. 13. Entidad del proyecto externo bcd

Para poder incluir este bloque de código en el


archivo fuente principal serstring.vhd, se deberán
efectuar unas modificaciones, como sigue:

1) La línea de código entity bcd is, se


establecerá como component bcd
2) Mientras que en la línea de cierre del
bloque end entity bcd; quedará como end
component;.

Fig. 15. (a) Entidad principal serstring y componentes


externos bcd y reg_corr

En los siguientes bloques de código mostrados en la


Fig. 15. (b) se visualiza lo siguiente, tal cual se
Fig. 14. Entidad del proyecto externo bcd listo para indica en la ilustración:
vincularse al proyecto principal
1) Configuración de señales y variables de la
máquina de estados del transmisor.
En la Fig. 15. (a), se observa (en primera instancia)
2) Configuración de señales y variables para la
la definición de la entidad serstring, con sus
máquina de estados utilizada para la
respectivos puertos de entrada y salida. También se
conversión hexadecimal-BCD
Fig. 15. (b) Señales auxiliares y tipos de dato generados
por el usuario para las respectivas máquinas de estados

En la Fig. 15. (c) se observan las últimas señales


Fig. 15. (d) Primeros dos procesos de la máquina de
auxiliares definidas antes de la línea de código estados de la conversión del dato hexadecimal a BCD
begin, y en seguida, el código del circuito diseñado.

Fig. 15.(c) Últimas señales auxiliares antes de begin, y Fig. 15. (e) Tercer proceso de la máquina de estados de
código del circuito diseñado después de begin. conversión hexadecimal a BCD e inicio de la máquina de
estados de transmisión del dato
digit_0 : out std_logic_vector( 3 downto 0);
digit_1 : out std_logic_vector( 3 downto 0);
digit_2 : out std_logic_vector( 3 downto 0);
digit_3 : out std_logic_vector( 3 downto 0)
);
end component;

---------------------------------------------------------------------

--RECORRIMIENTO DE DATO DE ENVIO


component reg_corr
Port ( clk : in STD_LOGIC;
din : in STD_LOGIC_VECTOR (7 downto 0);
load : in STD_LOGIC;
rdy : out std_logic;
txd : out STD_LOGIC);
end component;

---------------------------------------------------------------------

--CONFIGURACION DE SEÑALES Y VARIABLES


DEL TRANSMISOR

--Estados de la Màquina de Estados


type state is (s0,s1,s2,s3,s4);

--Posicion actual o siguiente de la Maquina de Estados


signal edopre, edosig: state;
signal cuenta: integer range 0 to 4;
type memoria is array (0 to 4) of std_logic_vector (7
downto 0);

Fig. 15. (f) Máquina de estados de transmisión de datos --Memoria de almacenamiento del tipo RAM
signal mem:
memoria:=("00000000","00000000","00000000","00000
El diseño final del circuito para este proyecto quedó de la 000","00100000");
siguiente manera: ---------------------------------------------------------------------

entity serstring is --CONFIGURACION DE SEÑALES Y VARIABLES


Port ( clk : in STD_LOGIC; PARA LA MAQUINA DE ESTADOS PARA LA
rst : in STD_LOGIC; CONVERSION HEXADECIMAL-BINARIO
INT : in STD_LOGIC;
DIN : IN STD_LOGIC_VECTOR (7 downto --Declarando Estados de la Maquina de Estados
0); type estado is (EDO0,EDO1,EDO2,EDO3);
DOUT : OUT STD_LOGIC_VECTOR (7
downto 0);
txd : out STD_LOGIC --Posicion actual o siguiente de la Màquina de Estados
); signal edoPres,edoSigs: estado;
end serstring;
--Variables de almacenamiento de la lectura del sensor
architecture Behavioral of serstring is signal unidades, decenas, centenas, millares :
STD_LOGIC_VECTOR (3 downto 0);
--COMPONENTES
--------------------------------------------------------------------- --Variable donde se almacena el dato de entrada
signal entradaBcd: STD_LOGIC_VECTOR (10 downto
--CONVERTIDOR HEXADECIMAL A BINARIO 0);
component bcd
port ( --Variable para almacenar dato a desplegar
in_binary : in std_logic_vector(10 downto 0);
signal resultadoFinal: STD_LOGIC_VECTOR (7 if CONTADOR < 4 and edoPres <= EDO2 THEN
downto 0); CONTADOR <= CONTADOR + 1;
elsif edoPres <= EDO0 THEN
--Señales Auxiliares (Para la interrupciòn y la detecciòn CONTADOR <= 0;
del gas) end if;
signal AUXINT,AUXGAS: std_logic; end if;
end process inicioDesglose;
--Señal de almacenamiento del valor analogico del sensor
con respecto a la posiciòn --Moviendo Màquina de Estados
signal aux_dat: std_logic_vector(7 downto 0);
moverDesglose:process(edoPres)
--Señales Auxiliares (Para la transmision del dato y begin
bandera de finalizado) case edoPres is
signal aux_load, aux_rdy: std_logic; when EDO0 =>
edoSigs <=EDO1;
--Contador when EDO1 =>
signal CONTADOR: INTEGER RANGE 0 to 4 ; edoSigs <= EDO2;
--------------------------------------------------------------------- when EDO2 =>
---------------------------------- edoSigs <= EDO3;
when others =>
--Maquina de Estados para almacenamiento y conversion edoSigs <= EDO0;
de dato hexadecimal a binario end case;
end process moverDesglose;
begin
--Acciones de Màquina de Estados
--Asignacion de interrupcion y señal de deteccion del gas
accionarDesglose:process(edoPres,mem)
AUXINT<= INT and AUXGAS; begin
case edoPres is
--Asignacion del dato de entrada con tres ceros when EDO0 =>
concatenados when EDO1 =>
-- al inicio a la señal que almacena el dato sin convertir resultadoFinal <= mem(CONTADOR);
when EDO2 =>
entradaBcd<="000"&DIN; when EDO3 =>
when others =>
--Conexion entre el componente bcd y el puerto end case;
"serstring" end process accionarDesglose;

A1: bcd port map (entradaBcd, unidades, decenas, -- Guardando el dato convertido en la variable de salida
centenas, millares); del puerto

--Guardando datos en la memoria DOUT <= resultadoFinal;

mem(0) <= "0011" & millares; ---------------------------------------------------------------------


mem(1) <= "0011" & centenas; ----------------------------------
mem(2) <= "0011" & decenas;
mem(3) <= "0011" & unidades;
--Màquina de Estados para el envio del dato convertido
--Iniciando Màquina de Estados

inicioDesglose:process(rst,INT,CONTADOR) --Conexion entre el componente reg_corr y el puerto


"serstring"
begin

if rst = '1' THEN A2: reg_corr port map


edoPres <= EDO0; (clk,aux_dat,aux_load,aux_rdy,txd);
CONTADOR <=0;
elsif INT = '0' and INT'event THEN
edoPres <= edoSigs;
--Señal que almacena el dato en la posicion con respecto A continuación, se procede a revisar la sintaxis de
al conteo presente programación del archivo completo por lo que, en el
panel inferior izquierdo Processes se despliega el
menú Synthesize – XST y se da clic derecho en la
aux_dat <= mem(cuenta);
opción “Check Syntax” para verificar que la sintaxis
--Iniciando la Maquina de estados del código diseñado sea correcta. En caso contrario
process(rst, clk) se procede a revisar en la consola de errores la
begin posible causa de la falla.
if rst = '1' then
edopre <= s0;
elsif clk'event and clk = '1' then
edopre <= edosig;
if edopre = s0 then cuenta <= 0;
elsif edopre = s2 then cuenta <= cuenta+1;
end if;
end if;
end process;

--Moviendo Màquina de Estados

process(edopre)
begin
case edopre is
when s0 => aux_load <= '1';
when s1 => aux_load <= '1'; Fig. 16. Ventana de procesos
when s2 => aux_load <= '0';
when s3 => aux_load <= '0'; Para la visualizar el esquema del proyecto, en la
when s4 => aux_load <= '0'; ventana de procesos y al desplegar synthesize hacer
when others => aux_load <= '0'; clic derecho en “View RTL Schematic” dando clic a
end case; la opción de “Run”.
end process;

--Acciones de cada estado

process(edopre,aux_rdy,cuenta)
begin
case edopre is
when s0 => edosig <= s1;
when s1 => edosig <= s2;
when s2 => edosig <= s3;
when s3 => if aux_rdy = '0' then
edosig <= s3;
else
edosig <= s4;
Fig. 17. Corriendo visualización del esquema
end if;
when s4 =>
if cuenta >= 9 then
edosig <= s0;
else
edosig <= s1;
end if;
when others =>
end case;
end process;
end Behavioral;

Fig. 17. (a) Esquema generado


Fig. 17. (b) Esquema generado Fig. 19. Asignación de pines físicos

Una vez realizada la generación del archivo “. ucf”


se procederá a la programación de la tarjeta.
II.7. Paso No. 7 Terminales de salida

Para asignar los puertos de entrada y salida hacia II.8. Paso No. 8 Modulo iMPACT
pines físicos de la tarjeta se crea una nueva fuente;
en el panel superior izquierdo Sources se da clic
derecho sobre el archivo principal serstring.vhd y Para programar la tarjeta FPGA SPARTAN 3, en el
se selecciona el tipo de nueva fuente como panel inferior izquierdo Processes se acciona la
“Implementations Constraints File”. generación del archivo de programa con doble clic,
en la opción “Generate Programming File”.
Se asigna el nombre a la nueva fuente como pines,
que generará un archivo con extensión .ucf.

Para asignar los pines mediante el asistente


proporcionado por el IDE, en el panel Sources se
selecciona el archivo nuevo pines.ucf y el usuario
deberá posicionarse ahora en el panel inferior de
Processes para desplegar el menú User
Constraints y elegir con doble clic el acceso
directo Assign Package Pins.

Fig. 20. Generación de archivo “. bit”

En este punto, se hace la correcta conexión de la


tarjeta SPARTAN 3 con la computadora por medio
de un cable USB de tipo A macho y B macho; se
Fig. 18. Panel izquierdo de Sources (superior) y conecta un inversor/Convertidor de CA a CC, para
Processes (inferior) poder energizar.
traspasó el archivo de diseño a una máquina virtual
con Windows XP que permitiera el reconocimiento
de estos dispositivos por USB.

En la Fig. 23. se especifica que se haga un escaneo


de los periféricos conectados; en seguida, se da clic
en Finish y se verá la interfaz como en la Fig. 24.

Fig. 21 Conexión entre Tarjeta SPARTAN 3 y Laptop

Si el ícono que se muestra en Generate


Programming File resulta ser un check verde,
entonces el circuito diseñado resultó sin errores en
la programación y ahora puede implementarse en la
tarjeta sin problema. Para esto, debajo del menú de
Generate Programming File se accede con doble
clic a la opción Configure Device (IMPACT)
como se observa en la Fig. 22.

Fig. 23. Configuración de Modulo iMPACT

Para asignar un nuevo archivo de configuración,


debe existir un único archivo con extensión .bit en
el directorio raíz (que tendrá el nombre del proyecto
actual). Entonces se selecciona este único archivo y
luego se da clic en el botón Open para aparecer
después la misma ventana pero sin el archivo
elegido.
Fig. 22 Selección de Modulo iMPACT
Cuando ya no aparezca el archivo con extensión
Cuando se accede a Configure Device (IMPACT), .bit, ahora se proseguirá a dar clic en el botón
se inicializa una de las herramientas que se instalan Bypass.
junto con el IDE de Xilinx: IMPACT es un software
que programa a las tarjetas Spartan con el diseño
que el usuario crea en Xilinx ISE.
Siempre que se inicie IMPACT, el software
consultará qué acción ejecutar, entre esas acciones
se encontrará el inspeccionar los puertos USB en
búsqueda de dispositivos Xilinx conectados a la
computadora.

NOTA: Para poder programar la tarjeta Spartan y


que Xilinx reconozca cualquier dispositivo de su
marca conectado a los puertos USB, no es
compatible con Windows 11 (el sistema operativo
en donde se desarrolló esta práctica), por lo que se
II.9. Paso No. 9 Interfaz RS-232 e Hyperterminal

Para visualizar los resultados, se conecta a la tarjeta


FPGA por medio del puerto serial para la interfaz
RS-232, respetando la configuración proporcionada
por el fabricante.

Fig. 23. (a) Cargando programa a la tarjeta SPARTAN

Para enviarle este diseño creado por el usuario a la


Spartan, se da clic derecho en el chipset izquierdo y
posteriormente, clic en el submenú Program, como
se muestra en la Fig. 23. (b).

Fig. 24. Configuración para comunicación UART usando


protocolo de comunicación RS-232

A continuación, se conecta el extremo restante de


este conjunto de cables de comunicación al
Fig. 23. (b) Programando Tarjeta SPARTAN 3 ordenador a cualquier puerto hembra USB
disponible.

Cuando aparezca la ventana Programming Nota: Se puede conectar a la tarjeta FPGA la


Properties (Fig. 23. (c)) se dará clic directamente interfaz de comunicación RS-232 de manera típica,
en el botón Apply y luego al botón OK, sin a pesar que en este circuito generado, sólo se
modificar ningún otro parámetro de la ventana. habilita el pin de transmisión “R13”.

A continuación, se abre el software


“Hyperterminal”, dando doble clic sobre el icono en
el escritorio de la computadora.

Al momento se despliega una ventana de acciones a


realizar, se dirige el cursor al espacio en blanco
previamente programada para escribir el nombre de
la conexión dando un clic, en ese instante se teclea:
“RS-232” y en la parte inferior de la misma ventana
multiopciones, se coloca el cursor en el símbolo que
represente esta conexión, para continuar con la
siguiente parte del proceso, se da clic sobre el botón
de OK.
Fig. 23. (c) Propiedades de programación para la tarjeta
Para guardar las propiedades de comunicación, se
dirige el cursor al botón de Aceptar dando un clic y
después se redirige el cursor en la opción OK de la
ventana de características del puerto. El monitor
serial del software Hyperterminal despliega la
información emitida por el sensor.

Fig. 25. Nueva conexión de Hyperterminal para


comenzar la visualización de datos

Fig. 28. Monitor serial Hyperterminal haciendo lectura


de datos.

En las siguientes ilustraciones (Fig. 28., y Fig. 29.),


se aprecian las pruebas en físico del circuito
convertidor emitiendo datos hacia la FPGA desde el
sensor de gas y finalmente mostrando este valor
resultante en el Hyperterminal de una computadora.

Fig. 26. Circuito ADC0804 con el sensor MQ-135 y la


FPGA, con el cable RS-232 conectado.

Se abre una ventana nueva en la cual detecta de


manera automática el puerto donde está conectado
la interfaz RS-232; se dirige el cursor a la opción
“Configure” dando un clic, a consecuencia un
submenú de opciones, para verificar las propiedades
de conexión o configuración del puerto:
Fig. 29. Prueba con el sensor, pt. 1.

Fig. 27. Configuración del puerto Fig. 30. Prueba con el sensor, pt. 2.
II.10. Paso No. 10 Base de Datos en MySQL Para almacenar los datos de la instrumentación, se
planteó el siguiente esquema (Fig. 33.), dentro de
una base de datos instrumentacion (Fig. 32).:
A partir de este punto, la parte del Cloud
Computing de este proyecto se basa en el concepto
de la Arquitectura de Microservicios a fin de
evitar los inconvenientes de mantenimiento,
disponibilidad y accesibilidad a la información, que
la Arquitectura Monolítica representaba en el
pasado. De esta manera, con los microservicios se
impulsa el desarrollo y la capacidad de respuesta de
la aplicación.

Tanto la base de datos como la Web API se


encuentran en servidores diferentes y aislados a la
aplicación web y a la aplicación de escritorio que
las consumen.

En cuanto a la base de datos, se eligió a MySQL


como alternativa principal de Sistema Gestor de
Base de Datos, muy a pesar de que la Web API
fuera desarrollada en .NET y su plataforma destino
predeterminada es Windows.
Es así, como, por su ventaja de ser una opción de Fig. 32. Base de datos instrumentacion diseñada con
SGBD de código abierto, baja demanda de una tabla sensadotiemporeal, una vista
rendimiento y alta compatibilidad con la mayoría de vista_graficacion y ocho procedimientos almacenados
sistemas operativos y aplicaciones, que se (Stored Procedures) detallados más adelante.
determinó alojar la base de datos en un Servidor con
una distribución de Linux como sistema operativo
(Debian 9), para albergar la información y liberar de
carga al servidor donde se hospeda la Web API.

Para manipular la base de datos alojada en el


servidor Debian, se utilizó la interfaz visual Fig. 33. Esquema de tabla sensadotiemporeal en
MySQL Workbench, desde un cliente Windows MySQL
11, creando una conexión directa al servidor por el
puerto 3306, empleando las credenciales de un
usuario administrador generado previamente en la Los campos mostrados en la Fig. 32 significan lo
consola de comandos de MySQL en el servidor. siguiente:

1) id_reg, es el id del nuevo registro que se


haga a la tabla. Es de tipo entero con
longitud de 10 caracteres.
2) analogico, es el valor analógico que viene
desde la FPGA, capturado por la aplicación
desarrollada
3) latitud y longitud, son los valores de
latitud y longitud del par de coordenadas
que proporciona la aplicación, en
sustitución de un sensor físico GPS. Se
detallará su mecanismo de funcionamiento
más adelante.
Fig. 31. Interfaz inicial de MySQL Workbench
4) fecha_hr_reg, es la fecha y hora en que se II.11. Paso No. 11 Stored Procedures
realizó el nuevo registro.
Con el propósito de proteger la base de datos contra
El código SQL es el siguiente: inyecciones SQL, puesto que será expuesta a través de la
API a múltiples clientes que consuman su información, y
CREATE TABLE `sensadotiemporeal` ( además, con la finalidad de reutilizar el código para
`id_reg` int(10) NOT NULL ahorrar tiempo de actualización o corrección de errores,
AUTO_INCREMENT, se determinó que la inserción, manipulación o consulta
`analogico` int(7) DEFAULT NULL, de datos, se hiciera a través de procedimientos
almacenados (Stored Procedures).
`latitud` double(8,5) DEFAULT NULL,
`longitud` double(9,5) DEFAULT NULL,
`fecha_hr_reg` datetime NOT NULL,
PRIMARY KEY (`id_reg`)
) ENGINE=InnoDB AUTO_INCREMENT=244
DEFAULT CHARSET=utf8mb4;

Si se ejecuta una consulta general a dicha tabla (Fig.


34. (a)), se arroja lo siguiente, mostrado en la Fig.
34. (b). Los datos mostrados son datos registrados
durante las pruebas previas y durante el desarrollo
de este documento. Fig. 35. Stored procedures de la base de datos
instrumentacion

Cada procedimiento almacenado cumple una


Fig. 34. (a) Consulta a la tabla sensadotiemporeal. función. A continuación se detalla ésta función y su
código SQL:

deleteData – eliminar un registro de la tabla


sensadotiemporeal.

CREATE DEFINER=`root`@`localhost`
PROCEDURE `deleteData`(IN `id` INT(10))
BEGIN
DELETE FROM sensadotiemporeal
WHERE id_reg = id;
END

getAllData – consulta general de todos los registros


Fig. 34. (b) Datos arrojados por la consulta en la Fig. 34. de la tabla sensadotiemporeal.
(a).
CREATE DEFINER=`root`@`localhost`
PROCEDURE `getAllData`()
BEGIN
SELECT * FROM sensadotiemporeal ORDER
BY id_reg DESC;
END
Fig. 34. (c) Consola de MySQL Workbench, indicando la
consulta realizada con éxito y el número de filas
devueltas como resultado.
getDataByCoord – consulta del valor analógico y CREATE DEFINER=`root`@`localhost`
la fecha y hora de registro en tiempo real (60 PROCEDURE `getGasData`()
minutos anteriores y posteriores a la hora y fecha BEGIN
actual), recibiendo como parámetro el par de SELECT * FROM vista_graficacion;
coordenadas latitud y longitud. END

CREATE DEFINER=`root`@`localhost` Código SQL de la vista_graficacion:


PROCEDURE `getDataByCoord`(IN `lat`
DOUBLE(8,5), IN `lon` DOUBLE(9,5)) CREATE
BEGIN ALGORITHM = UNDEFINED
SELECT analogico, fecha_hr_reg FROM DEFINER = `root`@`localhost`
sensadotiemporeal SQL SECURITY DEFINER
WHERE latitud LIKE lat AND longitud VIEW `instrumentacion`.`vista_graficacion` AS
LIKE lon AND fecha_hr_reg BETWEEN SELECT
DATE_SUB(NOW(), INTERVAL 60 MINUTE) `instrumentacion`.`sensadotiemporeal`.`analogico`
AND DATE_ADD(NOW(), INTERVAL 60 AS `analogico`,
MINUTE); `instrumentacion`.`sensadotiemporeal`.`fecha_hr_re
END g` AS `fecha_hr_reg`
FROM
getDataByDate – consulta el valor analógico y la `instrumentacion`.`sensadotiemporeal`
fecha y hora de registro, según una fecha en ORDER BY
específico. Mostrará todos los registros de cualquier `instrumentacion`.`sensadotiemporeal`.`id_reg`
hora sólo en ésa fecha. Recibe una fecha como DESC
parámetro, en formato ‘AAAA-MM-DD’.
insertData – inserción de un nuevo registro en la
CREATE DEFINER=`root`@`localhost` tabla sensadotiemporeal. En este procedimiento, se
PROCEDURE `getDataByDate`(IN `fecha` quita el espacio que viene como separador de los
VARCHAR(255)) datos que se envían desde la FPGA.
BEGIN
SET @FechaIngresada = (SELECT CREATE DEFINER=`root`@`localhost`
CONCAT(fecha,'%')); PROCEDURE `insertData`(IN `analogico` INT(7),
SELECT analogico, latitud, longitud, IN `latitud` double(8,6), IN `longitud` double(9,6))
fecha_hr_reg FROM sensadotiemporeal WHERE BEGIN
fecha_hr_reg LIKE @FechaIngresada; SET @trimmedString = (SELECT
END TRIM(analogico) AS TrimmedString);
SET @fechaHrActual = (SELECT
getDataById – consulta toda la información de un DATE_SUB(CURRENT_TIMESTAMP(),
registro, sabiendo su ID. Recibe el ID como INTERVAL 5 HOUR));
parámetro. INSERT INTO sensadotiemporeal(analogico,
latitud, longitud, fecha_hr_reg)
CREATE DEFINER=`root`@`localhost` VALUES(@trimmedString, latitud, longitud,
PROCEDURE `getDataById`(IN `id` INT(10)) @fechaHrActual);
BEGIN
SELECT id, analogico, latitud, longitud, END
fecha_hr_reg FROM sensadotiemporeal WHERE
id_reg = id; updateData – modificación de un registro existente
END en la tabla sensadotiemporeal, según su id.

getGasData – consulta, de la vista_graficacion, CREATE DEFINER=`root`@`localhost`


todos los registros con su valor analógico y la fecha PROCEDURE `updateData`(IN `id` INT(10), IN
y hora de registro, ordenados del registro más nuevo `analogico` INT(7), IN `latitud` double(8,6), IN
al más viejo, según la fecha. No recibe ningún `longitud` double(9,6))
parámetro. BEGIN
SET @trimmedString = (SELECT La plantilla elegida fue Web Forms y se definió que
TRIM(analogico) AS TrimmedString); se agregaran carpetas y referencias principales
UPDATE sensadotiemporeal como proyecto MVC y Web API.
SET analogico = @trimmedString,
latitud = latitud,
longitud = longitud
WHERE id_reg = id;
END

II.12. Paso No. 12 API REST

Para el desarrollo de esta API REST se empleó el


IDE Visual Studio 2019, sobre una Aplicación
Web ASP.NET (.NET Framework), como se indica Fig. 38. API REST desarrollada con una plantilla Web
en la Fig. 36. Forms con características adicionales de MVC y Web
API

Lo primero que se configura en la API es la cadena


de conexión con el servidor en donde se encuentra
la base de datos. Estos parámetros se ubican en el
archivo Web.config, localizable en el panel
Explorador de Soluciones.

Fig. 36. API REST desarrollada a partir de un proyecto


de tipo Aplicación Web ASP.NET (.NET Framework)

La nueva aplicación se desarrolló sobre la versión


4.7.2. de .NET Framework.

Fig. 39. Archivo Web.config

Después de la línea <configuration>, se agregaron


etiquetas
<connectionStrings></connectionStrings>, y
entre ellas se colocó una variable dbConn en una
Fig. 37. Especificación de versión de .NET Framework etiqueta <add>, tal como se muestra en la Fig. 40.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id =
RouteParameter.Optional }
);
}
Fig. 40. Cadena de conexión en archivo Web.config }
}
La configuración siguiente es en el archivo
WebApiConfig.cs de la carpeta App_Start ubicada También, con la línea de código
dentro de la solución. config.EnableCors(); se evitan errores de acceso a
la API desde otros servidores externos al que aloja
al servicio; esto es una medida de seguridad por
defecto de todas las APIs, precisamente para evadir
a los intrusos. NOTA: este método EnableCors() es
propio de la clase System.Web.Http, que se instala
con el paquete NuGet
Microsoft.AspNet.WebApi.Cors. Ver más
información: https://docs.microsoft.com/en-
us/aspnet/web-api/overview/security/enabling-
cross-origin-requests-in-web-api

Fig. 41. Configuración de archivo WebApiConfig

El código debe establecer las rutas de la API como


api/{controlador}/{id}, es decir, como en el
siguiente link:
http://77.68.25.150/ConsultarInstrumentacion,
donde la IP 77.68.25.150 es donde se aloja la api, y
el primer parámetro después de la diagonal al
finalizar la dirección IP, es el nombre del
controlador al que direcciona.

Código C#:

using System; Fig. 41. Código de archivo WebApiConfig


using System.Collections.Generic;
using System.Linq;
using System.Web.Http; En la carpeta Controllers se creó el controlador para
la instrumentación, llamado SensorController.cs.
namespace devWebApiRest
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration
config)
{
// Configuración y servicios de API web
config.EnableCors();
// Rutas de API web
config.MapHttpAttributeRoutes();
using System.Web.Http.Cors;

namespace devWebApiRest.Controllers
{
[EnableCors(origins: "*", headers: "*", methods:
"*")]
public class SensorController : ApiController
{
string connDb =
ConfigurationManager.ConnectionStrings["dbConn
"].ConnectionString;
Fig. 42. SensorController.cs
//Consultar solo valor analogico con fecha y hr
En la Fig. 43. se muestra una vista previa al código
[HttpGet]
del archivo SensorController.cs, el cual es el que
[Route("ConsultarInstrumentacion")]
albergará todas las solicitudes HttpGet que
public IHttpActionResult
consultarán, insertarán o manipularán datos
ConsultarInstrumentacion()
directamente con la base de datos.
{
ServicePointManager.SecurityProtocol =
Para que este código funcione correctamente, se
SecurityProtocolType.Tls12;
instalaron los paquetes NuGet que se enlistan a
continuación:
using (MySqlConnection db = new
MySql.Data
MySqlConnection(connDb))
Dapper
{
System.Web.Http
var datos =
System.Net
db.Query<GraficarDatos>("CALL `getGasData`()",
new { }).ToList();
return Ok(datos);
}
}

//Consultar informacion
[HttpGet]
[Route("ConsultarTodo")]
public IHttpActionResult ConsultarTodo()
{
ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls12;

using (MySqlConnection db = new


MySqlConnection(connDb))
Fig. 43. Código SensorController.cs {
var datos =
using Dapper; db.Query<SensadoTiempoReal>("CALL
using devWebApiRest.Models; `getAllData`()", new { }).ToList();
using MySql.Data.MySqlClient; return Ok(datos);
using System; }
using System.Collections.Generic; }
using System.Configuration;
using System.Linq; //Consultar 1 registro segun id
using System.Net; [HttpGet]
using System.Net.Http; [Route("ConsultarRegistro")]
using System.Web.Http;
public IHttpActionResult var datos =
ConsultarRegistro(string Id) db.Query<GraficarDatos>("CALL
{ `getDataByCoord`(@lat, @lon)", new { lat, lon
ServicePointManager.SecurityProtocol = }).ToList();
SecurityProtocolType.Tls12; return Ok(datos);
}
using (MySqlConnection db = new }
MySqlConnection(connDb))
{ //Insercion de Datos
var datos = [HttpGet]
db.Query<SensadoTiempoReal>("CALL [Route("AgregarDato")]
`getDataById`(@Id)", new { Id }).ToList(); public IHttpActionResult AgregarDato(int
return Ok(datos); analogico, double latitud, double longitud)
} {
} ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls12;
//Consultar TODOS los registros por una fecha
específica using (MySqlConnection db = new
[HttpGet] MySqlConnection(connDb))
[Route("ConsultarDatoPorFecha")] {
public IHttpActionResult var datos =
ConsultarDatoPorFecha(string fecha_hr) db.Query<SensadoTiempoReal>("CALL
{ `insertData`(@analogico, @latitud, @longitud)",
ServicePointManager.SecurityProtocol = new { analogico, latitud, longitud }).ToList();
SecurityProtocolType.Tls12; return Ok(datos);
}
using (MySqlConnection db = new }
MySqlConnection(connDb))
{ //Actualizacion de un dato
var datos = [HttpGet]
db.Query<DatosPorFecha>("CALL [Route("ModificarDato")]
`getDataByDate`(@fecha_hr)", new { fecha_hr public IHttpActionResult ModificarDato(string
}).ToList(); id, int analogico, double latitud, double longitud)
return Ok(datos); {
} ServicePointManager.SecurityProtocol =
} SecurityProtocolType.Tls12;

//Consultar TODOS los registros con fecha y using (MySqlConnection db = new


hora con actualizacion MySqlConnection(connDb))
/// a los 60 min anteriores y durante los 60 {
min posteriores var datos =
/// segun ubicacion (par de coordenadas db.Query<SensadoTiempoReal>("CALL
lat y lon). `updateData`(@id, @analogico, @latitud,
[HttpGet] @longitud)", new { id, analogico, latitud, longitud
[Route("ConsultarDatoPorUbicacion")] }).ToList();
public IHttpActionResult return Ok(datos);
ConsultarDatoPorUbicacion(double lat, double lon) }
{ }
ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls12; //Eliminar un Dato
[HttpGet]
using (MySqlConnection db = new [Route("EliminarDato")]
MySqlConnection(connDb)) public IHttpActionResult EliminarDato(string
{ id)
{ ConsultarInstrumentacion,
ServicePointManager.SecurityProtocol = ConsultarDatoPorUbicacion.
SecurityProtocolType.Tls12;
using System;
using (MySqlConnection db = new using System.Collections.Generic;
MySqlConnection(connDb)) using System.Linq;
{ using System.Web;
var datos =
db.Query<SensadoTiempoReal>("CALL namespace devWebApiRest.Models
`deleteData`(@id)", new { id }).ToList(); {
return Ok(datos); public class GraficarDatos
} {
} public int analogico { get; set; }
public string fecha_Hr_Reg { get; set; }
}
}

} Código C# del modelo SensadoTiempoReal.cs,


} utilizado en todos los demás métodos del
controlador SensorController.cs.
Para la correcta visualización de los datos
consultados por cada controlador en la API, se using System;
generaron 3 modelos en la carpeta Models: using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace devWebApiRest.Models
{
public class SensadoTiempoReal
Fig. 44. Modelos {
public int id { get; set; }
Código C# del modelo DatosPorFecha.cs, utilizado public int analogico { get; set; }
en el controlador SensorController, en el método public Double latitud { get; set; }
ConsultarDatosPorFecha public Double longitud { get; set; }
public string fecha_Hr_Reg { get; set; }
using System; }
using System.Collections.Generic; }
using System.Linq;
using System.Web; Los modelos sirven para organizar los datos de
consulta, como se observa en el link
namespace devWebApiRest.Models http://77.68.25.150/ConsultarInstrumentacion
{
public class DatosPorFecha
{
public int analogico { get; set; }
public Double latitud { get; set; }
public Double longitud { get; set; }
public string fecha_Hr_Reg { get; set; }
}
}

Código C# del modelo GraficarDatos.cs, utilizado en


el controlador SensorController, en el método
Fig. 45. Utilización de modelos para consulta de datos
Esta API fue publicada en un servidor virtual con
sistema operativo Windows Server 2022.

Fig. 48. Diseño del único formulario de la aplicación

Fig. 46. Conexión al servidor por Escritorio Remoto


Código de programación del Form1.cs

using System;
II.13. Paso No. 13 Aplicación de escritorio .NET using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
Se trata de una aplicación de escritorio desarrollada using System.Drawing;
como proyecto de tipo Aplicación de Windows using System.Linq;
Forms (.NET Framework). using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Device.Location;
using System.Net.Http;
using System.Net.Http.Headers;
using Newtonsoft.Json;
using System.IO.Ports;
Fig. 47. Aplicación de escritorio desarrollada sobre un
proyecto de tipo Aplicación de Windows Forms (.NET namespace devMonitorSerial
Framework) {
public partial class Form1 : Form
El diseño del formulario (Form1) quedó de la {
siguiente manera, englobando cada conjunto de Double latitud, longitud, lat, lon;
etiquetas y campos de texto respecto al valor que se static SerialPort _serialPort;
mostrará, con paneles. private void timer1_Tick(object sender, EventArgs
e)
{
//Mensaje predeterminado cuando no se ha
enviado informacion
label8.ForeColor = Color.FromArgb(0, 0, 0);
label8.Text = "Esperando enviar...";

//Obtencion de las coordenadas latitud y longitud


por la IP
GeoCoordinateWatcher oWatcher = new
GeoCoordinateWatcher();
oWatcher.PositionChanged += (S, E) =>
{
var oCoordinate = E.Position.Location;
latitud = oCoordinate.Latitude;
longitud = oCoordinate.Longitude;
string param =
//formato a 5 decimales despues del punto (a la $"analogico={valVolts}&latitud={latVal}&longitud={lo
derecha) nVal}";
lat = try
Convert.ToDouble(String.Format("{0:0.00000}", {
latitud)); //latitud + 0.0702; //diferencia var response = client.GetAsync(url +
lon = param);
Convert.ToDouble(String.Format("{0:0.00000}", string responseBody =
longitud)); //longitud - 0.020820; response.Result.Content.ReadAsStringAsync().Result.To
String();
//Mostrar valores de Latitud y Longitud en los
campos de texto //si el registro fue exitoso, entonces cambiar
textBox1.Text = lat.ToString(); el valor de la etiqueta label8
textBox2.Text = lon.ToString(); //con el mensaje Informacion enviada y
}; cambiarle el color negro a color verde.
oWatcher.Stop(); if (responseBody.Equals("true"))
oWatcher.Start(); {
label8.ForeColor = Color.FromArgb(8,
//-----TRATAMIENTO DE LOS DATOS QUE 226, 0);
VIENEN DE LA FPGA label8.Text = "Información enviada";
int voltaje; }
double aux, ppm, voltResult; }
string valor2dec; catch
voltaje = int.Parse(textBox3.Text); {
//label8.Text="Message :{0} "+ e.Message;
//-----Conversion del Valor Analogico hacia }
Voltaje }
aux = voltaje * (5.0 / 255.0);
ppm = ((5.92 * voltaje) - 995.00); }
voltResult =
Convert.ToDouble(String.Format("{0:0.0000}", aux)); private void label1_Click(object sender, EventArgs
try e){}
{ private void timer2_Tick(object sender, EventArgs
//-----Formato del valor decimal del voltaje a 4 e){}
decimales private void timer2_Tick_1(object sender,
valor2dec = String.Format("{0:0.0000}", aux); EventArgs e){}
//-----Salida al dato resultante por un campo de private void label4_Click(object sender, EventArgs
texto e){}
textBox4.Text = valor2dec + " Volts"; public Form1()
if (voltaje >= 170) {
{ InitializeComponent();
textBox5.Text = String.Format("{0:0.00}", _serialPort = new
ppm) + " p.p.m"; SerialPort("COM7");//VERIFICAR PRIMERO EL
} ADMIN DE DISPOSITIVOS Y CAMBIAR ESTE
else VALOR
{ //POR EL PUERTO COM
textBox5.Text = "No calculable"; EN EL QUE ESTE HABILITADO EL CABLE SERIAL
} CONECTADO
} //A LA
catch{} COMPUTADORA.
_serialPort.BaudRate = 9600; //VELOCIDAD DE
//Registro del dato en la API TRANSMISION DE DATOS
using (var client = new HttpClient()) _serialPort.Open(); //ABRIR EL PUERTO
{ SERIAL
string url = _serialPort.DataReceived +=
"http://77.68.25.150/AgregarDato?"; _serialPort_DataReceived;
string valVolts = textBox3.Text; }
string latVal = textBox1.Text;
string lonVal = textBox2.Text;
private void _serialPort_DataReceived(object }
sender, System.IO.Ports.SerialDataReceivedEventArgs }
e)
{
string POT = _serialPort.ReadExisting(); Pruebas con la aplicación ejecutándose y registro del dato
//_serialPort.ReadLine(); en la API
this.BeginInvoke(new
LineReceivedEvent(LineReceived), POT);
}

private delegate void LineReceivedEvent(string


POT);

private void LineReceived(string POT)


{
textBox3.Text = POT[4].ToString() +
POT[5].ToString() + POT[6].ToString();
}

private void Form1_Load(object sender, EventArgs Fig. 49. Captura de pantalla de la aplicación en ejecución
e) (panel derecho) y consulta de los datos registrados en la
{ API.
//cargar par de coordenadas de geolocalizacion
del dispositivo
GeoCoordinateWatcher oWatcher = new
GeoCoordinateWatcher();
oWatcher.PositionChanged += (S, E) =>
{
var oCoordinate = E.Position.Location;
latitud = oCoordinate.Latitude;
longitud = oCoordinate.Longitude;

//formato a 5 decimales despues del punto (a la


derecha)
lat =
Convert.ToDouble(String.Format("{0:0.00000}",
latitud)); //latitud + 0.0702; //diferencia
lon =
Convert.ToDouble(String.Format("{0:0.00000}",
longitud)); //longitud - 0.020820;
Fig. 50. Fotografía a la computadora ejecutando la
//Mostrar valores de Latitud y Longitud en los aplicación durante las pruebas de lectura del dato desde
campos de texto la FPGA
textBox1.Text = lat.ToString();
textBox2.Text = lon.ToString();
};
oWatcher.Start();

//inicializacion del timer que se ejecutará cada 2


segundos para registrar el dato
//y verificar el cambio de estado en las
coordenadas, por si se ha cambiado de ubicacion el
dispositivo
timer1.Start();
}
Fig. 53. Index del sitio web para despliegue de datos
almacenados en la API; gráfica en tiempo real

En las siguientes ilustraciones se muestran tablas


con registros específicos. Algunos datos incluyen
Fig. 51. Lectura de datos por el software desarrollado, de valores de pruebas dummies (Figuras 54 y 55).
los datos provenientes de la FPGA

Fig. 54. Tabla de registros que ingresaron a la base de


Fig. 52. Graficación de los datos analógicos obtenidos datos durante las últimas 24 horas. Se muestran los
por el sensor, enviados por la aplicación de escritorio a la últimos 20 nuevos.
API (versión anterior)

II.14. Paso No. 14 Aplicación Web para graficación de


datos
La aplicación web consta de 3 páginas .html, donde
la principal (index.html) muestra una gráfica
alimentada en tiempo real por los valores que se van
ingresando desde la aplicación del monitor serial.

La línea azul corresponde al valor analógico


capturado, mientras que la línea roja son las partes
por millón calculadas a partir del valor analógico.
Estos valores son calculados y registrados desde el
monitor serial, en tanto que este sitio web sólo está Fig. 55. Tabla con los históricos de las mediciones
mostrando la información almacenada en la API registradas en la base de datos, mostrando los 100
(Fig. 53). registros m
configuración de este proyecto a modo de poder
visualizar su comportamiento por medio de la
III. Conclusiones simulación y su estructura esquemática que
proporcionan los programas, incluyendo su correcta
ejecución en la tarjeta SPARTAN 3, en tiempo real.
Con esta proyecto se observan las nuevas
aplicaciones de la Electrónica Digital y Sistemas Limitantes encontradas durante la realización
Computacionales como el Cloud Computing en del proyecto:
cada una de las correspondientes etapas del proceso
para diseñar, implementar y desarrollar la Durante el desarrollo de las pruebas unitarias e
Instrumentación Electrónica que detecte el nivel de integrales con todos los componentes físicos, se
concentración de un gas nocivo en un área utilizaron al menos 3 sensores MQ-135 y se
específica, incluyendo las ventajas técnicas y comprobó que en espacios abiertos con temperatura
prácticas que conlleva el emplear una tarjeta FPGA ambiente mayor a 30°C, el funcionamiento del
con respecto algún microcontrolador convencional, sensor es óptimo y más preciso, que cuando se
dado que es una herramienta que tiene múltiples utiliza en un lugar cerrado, donde además se
opciones para recibir, procesar y enviar cualquier encuentre presencia de algún aire acondicionado,
dato al mismo tiempo por medio de cualquier puesto que afecta a las mediciones y al sensor en sí,
protocolo de comunicación para observar de impidiendo que éste tome la temperatura necesaria
manera local o inalámbrica la información obtenida, para poder capturar su valor analógico
esto es posible debido a los softwares correctamente.
especializados configurados que despliegan los
valores resultantes en la pantalla de algún ordenador De esta manera se veía mermado el hacer constantes
común. lecturas durante un determinado período de tiempo,
porque entonces el precalentamiento del sensor
Este tipo de tecnología tiene como ventaja, eliminar demoraba más, que si se hiciesen mediciones en
el espacio físico para monitorear la variable temperaturas superiores a 30°C.
deseada, eficientizar el proceso de detección,
conversión y transmisión de dato, a consecuencia de También se encontró que las cadenas enviadas por
tarjetas FPGA que tienen la capacidad de la FPGA y que son leídas por el monitor serial
desarrollar múltiples tareas al mismo tiempo, con diseñado en la aplicación .NET, continuamente
una velocidad muy alta además de tener una ventaja están recorriendo los caracteres, o aún no se ha
económica a largo plazo, ya que reemplaza detectado el patrón de corrimiento de los caracteres
cualquier circuito integrado convencional para que llegan por el puerto serial, es decir, que para
desarrollar estas etapas, mitigando la posibilidad de poder capturar sólo los caracteres correspondientes
generar gastos continuos debido a la falla de a centenas, decenas y unidades, de una cifra
cualquier elemento electrónico convencional, arrojada por la FPGA, se tenía que tomar un
además de aportar un amplio conocimiento para carácter de la cadena entrante y la posición de éstos
operar cualquier tipo de tarjeta diferente a las cambiaba cada vez que se iniciaba una nueva sesión
encontradas en el mercado. de mediciones de pruebas.

De manera específica, un sensor electroquímico,


convierte un evento físico en una señal de voltaje de
salida, transmitiendo esta información a una etapa Fig. 56. Línea de código del método LineReceived de la
de conversión a través de un convertidor analógico- aplicación .NET
digital (8 bits), emitiendo el resultado a una FPGA
de manera paralela (Operando en una parte del Para corregir o tratar de ‘atrapar’ esta excepción
proceso como Tarjeta de Adquisición de datos), lanzada que interrumpía la lectura por la aplicación,
para procesar y transmitir de manera serial a un el código se modificó de la siguiente manera, en el
ordenador, la situación actual del ambiente que se método private void LineReceived(string POT):
encuentra el elemento transductor.
private void LineReceived(string POT)
El uso de softwares como ISE 8.2, Proteus 8.2 e {
Hyperterminal facilitó la comprensión y //codigo actual
try
{
textBox3.Text = POT[1].ToString() +
POT[2].ToString() + POT[3].ToString(); //linea
actual
}
catch { }
}

Mejoras propuestas:

A pesar de que hay un sensor GPS que puede


utilizarse para sustituir a la geolocalización por
dirección IP, si se aplicaba en este proyecto, debía
incluirse un microcontrolador como nodo esclavo
de la FPGA y se incrementaba el nivel de
complejidad del desarrollo porque había que
desmenuzar los caracteres que llegaban por el
bloque de cadenas que emite el sensor (Fig. 54).

Fig. 57. Mensajes en formato NMEA emitidos por el


sensor GPS NEO-6M

De cualquier forma se cumplió el objetivo de la


inclusión del Cloud Computing para el
almacenamiento en la nube de los datos de un
sensor electroquímico y el par de coordenadas de la
ubicación en donde realice una medición, como una
alternativa para no comprometer las características
físicas de memoria y disco duro de una
computadora doméstica con las capturas de 1 dato
por segundo que este proyecto actualmente
satisface.

También podría gustarte