# Proyecto: Fotopletismografia -> usb -> c#



## washi_w_z_r (Oct 13, 2009)

Hola a todos, aqui les dejo una parte de mi proyecto de tesis, que trata del estudio de las ondas fotopletismograficas de un oximetro de pulso.

Para el presente proyecto nos enfocaremos en obtener las ondas fotopletismograficas de un oximetro de pulso, pero veamos algo de oximetria:

*El oximetro de pulso monitorea de forma no invasiva la saturación de la hemoglobina arterial,  estos se basan en la absorción diferencial de la luz para determinar el porcentaje de saturación de oxigeno de la hemoglobina en la sangre arterial.*

Para obtener esta absorción diferencial de la luz se utiliza un sensor que transmite dos longitudes de onda: Luz roja de 660nm  y Luz infrarroja de 905nm.

Observemos la siguiente figura 1:


   Lo que haremos es incidir una luz (roja ó infrarroja) sobre el dedo indice de la mano izquierda, como muestra la figura 1,  del cual obtendremos las ondas fotopletismograficas.

La onda fotopletismografica del oximetro de pulso representa el cambio de volumen del flujo sanguíneo 

La onda fotopletismografica del oximetro de pulso  en un órgano o extremidad  se ve afectada por muchas  variables, por ejemplo la luz ambiental, ruido, niveles anormales de hemoglobina, función del ritmo y promedio del pulso cardíaco, tez del paciente, movimiento no controlado del cuerpo, lo cual influye en el monitoreo y diagnostico del estado del paciente.

Estas ondas se muestran en la fig 2:


   Teniendo esta pequeña introducción para el proyecto que a continuación  les presento, nuestros objetivos serán
      -    Diseñar un circuito capaz de recibir una señal através del fotodiodo detector
      -    Realizaremos Adaptación de señal proveniente del fotodiodo
      -    Realizaremos cálculos para diseñar los filtros analógicos
      -    Realizaremos una etapa de amplificación y suma se señal
      -    Realizaremos un programa en el pic18f4550 para adquirir datos analógicos y enviarlos mediante USB
      -    Finalmente realizaremos un programa que adquiera datos provenientes del PIC.
Antes de nada, usaremos :
    - Un sensor para adultos de la empresa DOLPHIN.
    - TL082 para las diferentes etapas( filtrado amplificación y suma)
    - Una fuente ATX del cual obtendremos los voltajes simetricos +-12v para los opams, +5v para el pic 
    - Un Pic18f4550
    - El programa C# 2005
    - Pickit 2, para programar el pic
    - Usaremos el lenguaje C para realizar el soft del pic

Empezeeeeeeemos  :-/ :

*SEÑAL EN EL FOTODIODO RECEPTOR*
La señal proveniente del fotodiodo produce una corriente que es función lineal de la intensidad de la luz, siendo esta corriente medida como densidad de potencia óptica incidente, para ello necesitaremos convertir esta “corriente” a voltaje, conseguiremos ello mediante un conversor de corriente a tensión:   

 Para obtener la resistencia Rf tenemos que definir cuanto deseamos obtener a la salida del OPAM, seria ideal obtener una señal entre 0v a 5v para efectos de la adquisición y conversión con el ADC del PIC,  veamos entonces:
      -    En primera instancia los OPAMS TL082 estarán alimentados con voltaje  de 0v (pìn4) y 5v (pin8).
      -    Esta alimentación produce una salida de 200mV con Rf =20M?.
      -¿Cómo halle esta resistencia?: de la siguiente manera:
Veamos el siguiente cuadro que nos da algunas caracteristicas del sensor:[/SIZE]


como observamos en el esuqema del conversor de corriente a tension se tiene las siguientes ecuaciones:
Se tiene configuracion inversora por ello:


•    Se tiene que VD=0 , por ello:


•    Por otro lado para determinar la corriente que incide en el fotodiodo se tiene:
     o    La potencia producida por el fotodiodo es:


     [size=10pt]o    La corriente producida por el diodo es:


•    Consideramos una tensión de salida de 200mW, por ello se tiene:


•Por ello escogemos una resistencia de 20MO (valor comercial), con lo que nuestro esquema será:



Siendo la alimentacion en los opams TL082 con una fuente simple,  y al ver experimentalmente que se atenua la señal a medida que esta entra en dichos filtros , ademas que si la etapa de filtrado es alta ( me refiero a etapas de mayor a 8vo orden) esta ateunara la señal, por ejm yo obtuve 2v a la salida del conversor V-I y a la salida de los filtros obtuve 200mv o menos en algunos casos.

Por ello se debe tener cuidado en colocar etapas de amplificación ya que estas tambien amplifican tanto la señal DC como la señal AC en este caso.
-     ¿Porque  uso ±12V?, mas adelante veremos  que al usar filtros, estos atenúan la señal.
-    Bien ahora tenemos la señal vista en osciloscopio

De la figura anterior observamos que nuestra onda fotopletismografica esta "MODULADA" con otra frecuencia de 44khz, se ve claramente en la parte inferior es la onda que buscamos.
*FILTROS ANALOGICOS*
Observando la señal del fotodiodo en la cual se encuentra nuestra onda fotopletismografica.

Nuestro objetivo es obtener la onda fotopletismografica, sabemos que el cuerpo Humano produce una frecuencia de 60hz, la red eléctrica en Perú es de 60Hz, además si amplificadoramos la señal de la figura arriba mencionada vemos que nuestra onda esta modulada con otra de 44Khz.

Para eliminar estas frecuencias necesitamos realizar filtraje:

-    filtro pasa-altas: con el fin de eliminar la componente DC , la frecuencia de corte se fija en 0.5Hz
-    filtro pasa-bajas: con el fin de eliminar las frecuencias altas , la frecuencia de corte se fija en 3.5Hz
Bien como ya definimos las frecuenciaqs de corte , empezmos a diseñar los filtros analogicos, para ello usaremos la configuracion SALLEN KEY  veamos para un filtro pasa-baja de 2do orden: 

Para un filtro pasa-alta de 2do orden:

Cuyas funciones de transferencia son:


----------



## washi_w_z_r (Oct 13, 2009)

Respectivamente, ahora bien la ventaja de esta configuración SALLEN KEY es que podemos colocar resistencias y capacitores de la  misma magnitud nominal y con ello  nos enfocamos en el denominador con el objetivo de igualarlo a cero obteniendo:


En ambos casos se obtiene una frecuencia de resonancia f0,  para el caso del filtro pasa altos se tiene:



Para las frecuencias anteriormente especificadas los valores de las resistencias son demasiadas altas del orden de los megaohm, ello trae la perdida de la señal.

Los valores que yo use son :
filtro pasa-altas 2do orden de: R= 150k y C=440nf (dos cap de 220nF de poliéster en paralelo),obteniendo  la siguiente señal:


filtro pasa-bajas 2do orden de: R= 360k y C=440nf (dos cap de 220nF de poliéster en paralelo),obteniendo  la siguiente señal:






Filtro pasa.altas de 8vo orden: R= 130k y C=440nf (dos cap de 220nF de poliéster en paralelo),obteniendo la siguiente señal:


Notas Aclaratorias:
- Al sensor se envia una señal para encienda el fotodiodo emisor rojo, con ello obtenemos una señal fotoletismografica AC y 
  otra DC, lo mismo sucede cuando encendemos el fotodiodo emisor infrarrojo.
- La señal AC nos muestra el cambio en flujo sanguineo ( en este caso el dedo indice de la mano izq), esta señal AC es la que vemos en los diferentes figuras arriba mostradas.
- La señal DC si bien para nuestros propositos la eliminamos, esta señal contiene la variacion de la respiracion.
- La señal AC fue obtenida siguiendo las etapas: CONVERSOR I-V ---> FILTRO PASA-ALTAS 2DO ORDEN ---> FILTRO PASABAJA DE SEGUNDO ORDEN ---> ETAP DE PRE-AMPLIFICADO ---> FILTRADO 8VO ORDEN, como observamos en el siguiente esquema:

- Como estamos realizando un tratamiento a esta señal observamos en el osciloscopio que nuestra señal alcanza los 200mV, en este punto lo dejamos con este valor, al cual le añadiremos uan etapa de suma y otra de amplificación, para obtener un voltaje adecuado para la captura en el ADC del pic.

PROGRAMACION EN EL PIC:
Aqui les dejo mi prog en el pic:

```
/////////////////////////////////////////////////////////////////////////////
//DECLARANDO DISPOSITIVO A USAR
////////////////////////////////////////////////////////////////////////////
#include <18f4458.h>
/////////////////////////////////////////////////////////////////////////////
//DECLARANDO ADC 
////////////////////////////////////////////////////////////////////////////
#device ADC=12   // ADC DE 10 BITS
/////////////////////////////////////////////////////////////////////////////
//DECLARANDO FUSES   :  20MHZ DE OSC  
////////////////////////////////////////////////////////////////////////////
#fuses HSPLL,NOMCLR,NOWDT,NOPROTECT,NOLVP,NODEBUG,USBDIV,PLL5,CPUDIV2,VREGEN,NOPBADEN,NOBROWNOUT
/////////////////////////////////////////////////////////////////////////////
//CONFIGURANDO A 48MHZ NECESARIOS PARA USAR EL USB 2.0
////////////////////////////////////////////////////////////////////////////
#use delay(clock=48000000)

/////////////////////////////////////////////////////////////////////////////
//LIBRERIAS DE CONFIGURACION DEL USB 
/////////////////////////////////////////////////////////////////////////////
#define USB_HID_DEVICE     FALSE             //deshabilitamos el uso de las directivas HID
#define USB_EP1_TX_ENABLE  USB_ENABLE_BULK   //turn on EP1(EndPoint1) for IN bulk/interrupt transfers
#define USB_EP1_RX_ENABLE  USB_ENABLE_BULK   //turn on EP1(EndPoint1) for OUT bulk/interrupt transfers
#define USB_EP1_TX_SIZE    8                 //size to allocate for the tx endpoint 1 buffer
#define USB_EP1_RX_SIZE    3                 //size to allocate for the rx endpoint 1 buffer

///////////////////////////////////////////////////////////////////////////////
#define USB_CON_SENSE_PIN PIN_E3  
/////////////////////////////////////////////////////////////////////////////
//
// If you are using a USB connection sense pin, define it here.  If you are
// not using connection sense, comment out this line.  Without connection
// sense you will not know if the device gets disconnected.
//       (connection sense should look like this:
//                             100k
//            VBUS-----+----/\/\/\/\/\----- (I/O PIN ON PIC)
//                     |
//                     +----/\/\/\/\/\-----GND
//                             100k
//        (where VBUS is pin1 of the USB connector)
//
/////////////////////////////////////////////////////////////////////////////

#include <pic18_usb.h>     //Microchip PIC18Fxx5x Hardware layer for CCS's PIC USB driver
#include <USB_ADC_TESIS.h>         //Configuración del USB y los descriptores para este dispositivo
#include <usb.c>           //handles usb setup tokens and get descriptor reports
/////////////////////////////////////////////////////////////////////////////
//DEFINICION DE VARIABLES PARA EL USO ADC
////////////////////////////////////////////////////////////////////////////
#define DERECHA 0

#byte TRISA = 0xF92
#byte TRISD = 0xF95
#byte ADCON2 = 0xFC0
#byte ADCON0 = 0xFC2
#byte ADCON1 = 0xFC1
#byte ADRESL = 0xFC3
#byte ADRESH = 0xFC4
#byte ValorH = 0x028
#byte ValorL = 0x029
////////////////////////////////////////////////////////////////////////////
// DEFINICION DE VARIABLES PARA CONTROL DE CONEX USB
//////////////////////////////////////////////////////////////////////////
//*** CONTROL DE CONEX USB ***//
#define LEDV    PIN_B6
#define LEDR    PIN_B7

//*** CONTROL LED SENSOR ***//
#define LED_ROJO PIN_C1
#define LED_INFR PIN_C0
//*** CONTROL DE SEÑALES AC-DC***//
#define CONTROL_0 PIN_D0   //SEÑAL ROJO_AC_4
#define CONTROL_1 PIN_D1   //SEÑAL INFR_AC_4
#define CONTROL_2 PIN_D2   //SEÑAL ROJO_DC
#define CONTROL_3 PIN_D3   //SEÑAL INFR_DC

//*** ESTADOS SALIDA DE PINES ***//
#define LED_ON  output_high
#define LED_OFF output_low


///////////////////////////////////////////////////////////////////////////
// PARAMETROS: ENVIO Y RECEPCION DATOS ATRAVES DEL USB
//////////////////////////////////////////////////////////////////////////
#define modo      recibe[0]
#define param1    recibe[1]
#define param2    recibe[2]

/////////////////////////////////////////////////////////
void main(void) {
   ///////////////////////
   //VARIABLES PARA EL ADC
   ///////////////////////
   int recibe[3];                  //declaramos variables
   long value;
   int i;
   int8 Buffer_ADC[8];
   int SPO_1[3]=
   {
   255,254,20
   };
  
    LED_OFF(LEDV);                   //encendemos led rojo
    LED_ON(LEDR);
   // CONFIGURANDO CANALES ANALOGICOS
   setup_adc_ports(AN0_TO_AN1_ANALOG);
   // CONFIGURANDO RELOJ DE CONVERSION
   setup_adc(ADC_CLOCK_DIV_64 );  
   //CONFIGURANDO TIPO DE JUSTIFICACION
    #asm
     bcf 0xFC0,7   // ADFM <- 0 justificacion derecha
    #endasm
    //CONFIGURANDO TIEMPO DE ADQUISICION
    #asm          // configura Tacq = 2Tad
     bsf 0xFC0,3
     bsf 0xFC0,4
     bsf 0xFC0,5
    #endasm
  
     
   usb_init_cs();  // inciamos y apagamos el modulo USB , ahora depende de usb_task();
    
   while (TRUE)
   {
      usb_task();   //habilita periferico usb e interrupciones

      if(usb_enumerated())          //si el PicUSB está configurado
      {
        if (usb_kbhit(1))          //si el endpoint de salida contiene datos del host
         {
            usb_get_packet(1, recibe, 3); //cojemos el paquete de tamaño 3bytes del EP1 y almacenamos en recibe
            switch (modo)
            {   
               
               case 0:
               {
                  if (param1 == 0) {LED_OFF(LEDV); LED_OFF(LEDR);} //apagamos los leds
                  if (param1 == 1) {LED_ON(LEDV); LED_OFF(LEDR);} //encendemos led verde
                  if (param1 == 2) {LED_OFF(LEDV); LED_ON(LEDR);} //encendemos led rojo
                  break;
               }
               
               case 1:
               {
                  usb_put_packet(1,SPO_1,3,USB_DTS_TOGGLE);  //probar si envia un paquete 
                  break;
               }
               
               case 2:
               {
               //LED_ON(LEDV);
                /////////////////////////////////////////////////////////
                /// CONTROL DE MUX ROJO                               ///
                /////////////////////////////////////////////////////////
                ///   ENCENDIDO LED ROJO - ACTIVAR MUX ROJO_AC_4      ///
                /////////////////////////////////////////////////////////
                LED_ON(LED_ROJO);   // ENCIENDO LED ROJO
                LED_OFF(LED_INFR);  // APAGO LED INFRARROJO
                /////////////////////////////////////////////
                LED_OFF(CONTROL_0);   // ACTIVO MUX_ROJO_AC_4
                LED_ON(CONTROL_1);   //  DESACTIVO MUX_INFR_AC_4
                LED_ON(CONTROL_2);   // DESACTIVO MUX_ROJO_DC
                LED_ON(CONTROL_3);   //DESACTIVO MUX_INFR_DC
                ///////////////////////////////
                /// configurar canal AN0     //
                ///////////////////////////////
               set_adc_channel(0);   // elegimos canal a convertir
                delay_us(50);
                value=read_adc();         // LEEMOS LA CONVERISION DEL ADC
                Buffer_ADC[0]=ValorH;      //ALMACENAMOS BITS MSB
                Buffer_ADC[1]=ValorL;      //ALMACENAMOS BITS LSB
                delay_us(50);
                set_adc_channel(0);   // elegimos canal a convertir
                delay_us(50);
                value=read_adc();         // LEEMOS LA CONVERISION DEL ADC
                Buffer_ADC[2]=ValorH;      //ALMACENAMOS BITS MSB
                Buffer_ADC[3]=ValorL;      //ALMACENAMOS BITS LSB
                delay_us(50);
                set_adc_channel(0);   // elegimos canal a convertir
                delay_us(50);
                value=read_adc();         // LEEMOS LA CONVERISION DEL ADC
                Buffer_ADC[4]=ValorH;      //ALMACENAMOS BITS MSB
                Buffer_ADC[5]=ValorL;      //ALMACENAMOS BITS LSB
                delay_us(50);
                set_adc_channel(0);   // elegimos canal a convertir
                delay_us(50);
                value=read_adc();         // LEEMOS LA CONVERISION DEL ADC
                Buffer_ADC[6]=ValorH;      //ALMACENAMOS BITS MSB
                Buffer_ADC[7]=ValorL;      //ALMACENAMOS BITS LSB
                set_adc_channel(0);   // elegimos canal a convertir
                delay_us(50);
                usb_put_packet(1,Buffer_ADC,8,USB_DTS_TOGGLE);
                //LED_OFF(LEDV);
                break;
              }

                           
            }
         }
      }
   }
}
```
Bien explicando en lineeas generales:
-  Yo uso el pic 18f4458 que tiene 12 bits de ADC , pero pòdemos usar el pic 18f4550 con el mismo codigo sin ningun problema.
-  Lo que hace el codigo es que cada vez que el PC le pida valores del ADC este leera 4 valores y lo enviara a la PC.
-  Algunas de la directivas , por ejemplo #define CONTROL_0 PIN_D0   //SEÑAL ROJO_AC_4
#define CONTROL_1 PIN_D1   //SEÑAL INFR_AC_4, es debido a que en mi proyecto yo requiero visualizar las cuatro ondas es decir : del fotoemisor rojo las ondas AC y DC , del fotoemisor infrarrojo las ondas AC y DC , para ello uso un multiplexor analogico ADG411 con el cual selecciono la onda deseada.
- Para el presente proyecto en este foro solo visualizaremos la señal Rojo_AC.
- Antes de seguir les dejo imagenes de mis placas tanto las que diseñe en EAGLE 5.40 y las reales asi como los respectivos archivos.

http://img203.imageshack.us/img203/7240/placafiltrossealreal.jpg
http://img527.imageshack.us/img527/2018/placafiltrossealeagle.jpg
http://img131.imageshack.us/img131/6790/placamultiplexacionampl.jpg
http://img162.imageshack.us/img162/6790/placamultiplexacionampl.jpg
http://img101.imageshack.us/img101/1251/placafuentereal.jpg
http://img202.imageshack.us/img202/8489/placafuenteeagle.jpg
http://img397.imageshack.us/img397/9671/placapicreal.jpg
http://img202.imageshack.us/img202/6085/placapiceagle.jpg

PROGRAMACION C#
Lo primero sera crear un nuevo proyecto, esto lo c#
http://img440.imageshack.us/img440/2555/cpaso1.jpg

Colocamos el nombre del proyecto y  la ubicación en este caso el nombre del proyecto es “ONDAS_PLETISMOGRAFICAS” y esta localizado en la unidad “D “con el nombre de ONDAS, aclarando que el mismo C# dará el nombre a “Solution Name”, por ello no lo cambiamos.

http://img440.imageshack.us/img440/6893/cpaso2.jpg

Damos OK y esperamos a que el soft cree los objetos, métodos y el diseño del proyecto.

Quedara así:

http://img440.imageshack.us/img440/3711/cpaso3.jpg

Hacemos click en esta herramienta la cual desplegara:

http://img440.imageshack.us/img440/4205/cpaso4.jpg

Buscamos el componente “button” “groupbox”, deslizamos estos componentes al objeto “Form1”, apretamos F4 para desplegar las propiedades  de los componentes y empezamos a diseñar nuestro programa, el cual quedara en primera instancia así:

http://img440.imageshack.us/img440/9308/cpaso5.jpg

http://img440.imageshack.us/img440/2471/cpaso6.jpg

Dentro de la carpeta de nuestro proyecto copiamos el DLL Graph components, este lo podrán encontrar en la pagina CODEPROJECT, cuyo autor nos autoriza a usar su maravilloso graficador.

Bien una vez obtenido este DLL, procedemos a colocarlo en nuestro toolbox para ello realizamos la siguiente operación:

Nos dirigimos a la herramienta ToolBox, hacemos anticlik y escogemos “choose item”
http://img440.imageshack.us/img440/2551/cpaso7.jpg

Después elegimos NET components y buscamos la ubicación del DLL que nos hemos bajado algo así:
http://img440.imageshack.us/img440/650/cpaso8.jpg

Apretamos “open”, después aceptamos en la ventana choose toolbox ítems, y desplegamos en la pestaña toolbox ---? All Windows forms:
http://img440.imageshack.us/img440/4774/cpaso9.jpg

Como observamos ya contamos con el componente ploter que es esencial para nuestro proyecto.

Ahora nuestra ventana queda así

http://img440.imageshack.us/img440/2032/cpaso10.jpg


Si bien hasta ahora solo hemos diseñado es hora de programar, para ello haremos anticlik en el “Form1” y nos iremos  a “view code”

http://img440.imageshack.us/img440/21/cpaso11.jpg

Automáticamente el programa nos traslada al código principal ósea:

http://img440.imageshack.us/img440/6127/cpaso12.jpg

OK detengámonos un rato y pesemos algo, tenemos el prog C#, tenemos el prog en el PIC, tenemos el driver del PIC,  además el mpusbapi.dll, pero nos falta los, OK vayamos por partes.

-    Primero el mpusbapi.dll es un DLL que nos permite realizar  tareas en el PIC, entonces ¿Cómo lo enlazo para que este haga las funciones en el PIC? , para ello crearemos una clase denominada PICUSBAPI
-    Volvamos al C#, dentro de esta ultima figura nos dirigimos ala derecha a la pestaña “Solution Explorer” es decir:


http://img440.imageshack.us/img440/5066/cpaso13.jpg

-    Hacemos anticlik en :
http://img70.imageshack.us/img70/1079/cpaso14.jpg

-    Escogemos Add-? New Item, haciendo esto se desplegara:
http://img70.imageshack.us/img70/5694/cpaso15.jpg

-    Escogemos “Class” y le damos un nombre en este caso “PicUsbApi”, dentro de esta clase definiremos, el tamaño de bytes que enviamos y recibimos 

-    Demos una mirada solo a las funciones del mpusbapi.dll que usaremos

Abrir Pipe: nos permite abrir la conexión con el PIC, acotando algo cuando observamos DWORD seleccion = 0; significa que si estamos usando un solo pic , este pic sera seleccionado con “DWORD seleccion = 0” , en mi caso llege a usar en un determinado momento dos pic , con ello el segundo pic sera seleccionado con “DWORD seleccion = 1”, pero atentos a algo, para usar el mpusbapi con dos pic tendremos que:

“Crear dos clases, una que contenga el PID&VID del primer pic con el DWORD selección=0; y otra clase que contenga el otro PID&VID del segundo pic con el DWORD selección =1”.

Para terminar con esta  parte, las clases que yo implemente los denomine PicUSBApi y PIC_18usbapi, cada una de ellas maneja un dispositivo PIC.

Cerrar Pipe: cierra la conexión entre la PC y el Pic18f4550

Envio Paquete y Recibo: Paquete nos permite enviar y recibir bytes desde la PC al PIC y viceversa.

LedPic: con esta método enviaremos ordenes al PIC, en este caso enviaremos 3bytes, el primer byte que pide al PIC realizar lo que este en el “case 1”, en este caso apagar o prendera cierto Led.

PideDatos_ADC_ROJO_4_PIC1: como recordaran en mi placa de filtros yo tengo varias etapas, esta se refiere a la etapa de cuarto orden del filtro de octavo orden (espero se entienda) , del cual yo visualizare la onda, para ello pido al pic que ejecute el “case 2” 

public float[] RecibeDatos_ADC_ROJO_4_PIC1: para ejecutar este metodo nosotros no solo lo llamaremos, sino tendremos que pasar  un valor para que esta funcion nos devuelva los bytes que queremos, traduciendo si no le enviamos algo esta funcion no devolvera nada, por ello lo declaramos como “public float[] “ , dento del argumento de este metodo se encuentra (uint velo) , que desde nuestro codigo principal le enviaremos un valor del tipo uint, seguidamente creamos un arreglo de 8 posiciones, al cual llamamos recibe_adc_rojo_4_pic1, dentro del cual almacenamos los valores recibidos desde el pic, y lo devolvemos con la instrucción return recibe_adc_rojo_4_pic1;

-    Muy bien ya implementamos nuestra clase PicUSBApi , el cual queda así:

```
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Runtime.InteropServices;

using PVOID = System.IntPtr;
using DWORD = System.UInt32;

namespace ONDAS_PLETISMOGRAFICAS
{
     unsafe public class PICUSBAPI
        {
            #region DEFINICION DE STRINGS ENDPOINT , VID_PID
            string vid_pid_norm = "vid_04d8&pid_0052";
            string out_pipe = "\\MCHP_EP1";
            string in_pipe = "\\MCHP_EP1";
            #endregion

            #region FUNCIONES IMPORTADAS DE LA DLL: mpusbapi.dll
            [DllImport("mpusbapi.dll")]
            private static extern DWORD _MPUSBGetDLLVersion();
            [DllImport("mpusbapi.dll")]
            private static extern DWORD _MPUSBGetDeviceCount(string pVID_PID);
            [DllImport("mpusbapi.dll")]
            private static extern void* _MPUSBOpen(DWORD instance, string pVID_PID, string pEP, DWORD dwDir, DWORD dwReserved);
            [DllImport("mpusbapi.dll")]
            private static extern DWORD _MPUSBRead(void* handle, void* pData, DWORD dwLen, DWORD* pLength, DWORD dwMilliseconds);
            [DllImport("mpusbapi.dll")]
            private static extern DWORD _MPUSBWrite(void* handle, void* pData, DWORD dwLen, DWORD* pLength, DWORD dwMilliseconds);
            [DllImport("mpusbapi.dll")]
            private static extern DWORD _MPUSBReadInt(void* handle, DWORD* pData, DWORD dwLen, DWORD* pLength, DWORD dwMilliseconds);
            [DllImport("mpusbapi.dll")]
            private static extern bool _MPUSBClose(void* handle);
            #endregion
           
            void* myOutPipe;
            void* myInPipe;

            #region ABRIR CERRAR PUERTO
            // METODO ABRIR PIPE//

            public void AbrirPipe()
            {
                DWORD seleccion = 0;
                myOutPipe = _MPUSBOpen(seleccion, vid_pid_norm, out_pipe, 0, 0);
                myInPipe = _MPUSBOpen(seleccion, vid_pid_norm, in_pipe, 1, 0);
            }
            public void CerrarPipe()
            {
                _MPUSBClose(myOutPipe);
                _MPUSBClose(myInPipe);
            }
            //METODOS ENVIO RECEPCION PAQUETES 
            private void EnvioPaquetes(byte* SendPacket, DWORD SendLength)
            {
                uint sendelay = 4000000000;
                DWORD SendDataLength;
                _MPUSBWrite(myOutPipe, (void*)SendPacket, SendLength, &SendDataLength, sendelay);
            }

            private void ReciboPaquete(byte* ReceiveData, DWORD* ReceiveLentgh)
            {
                uint ReceiveDelay = 4000000000;
                DWORD ExpectReceiveLength = *ReceiveLentgh;
                _MPUSBRead(myInPipe, (void*)ReceiveData, ExpectReceiveLength, ReceiveLentgh, ReceiveDelay);
            }
            //METODO PRENDER APAGAR LEDS //
            public void LedPic(uint Led)
            {
                byte* send_buf = stackalloc byte[2];
                send_buf[0] = 0x00;
                send_buf[1] = (byte)Led;
                EnvioPaquetes(send_buf, 2);
            }
            #endregion
         
            #region ENVIO-RECIBO SEÑALES INDIVIDUALES
            //METODO RECIBE ENVIA DATOS ADC PIC 1 
            //SEÑAL ROJO_AC_4
            public void PideDatos_ADC_ROJO_4_PIC1()
            {
                byte* Envio_Buff = stackalloc byte[2];
                Envio_Buff[0] = 0x02;
                Envio_Buff[1] = 0; //No implementado
                EnvioPaquetes(Envio_Buff, 2);
            }
            public float[] RecibeDatos_ADC_ROJO_4_PIC1(uint velo)
            {
                uint veloH;
                veloH = velo / 2;
                DWORD RecvLength = 8;
                float[] recibe_adc_rojo_4_pic1 = new float[8];
                byte* recibir_buff = stackalloc byte[8];
         
                ReciboPaquete(recibir_buff, &RecvLength);
                
                recibe_adc_rojo_4_pic1[0] = recibir_buff[0];
                recibe_adc_rojo_4_pic1[1] = recibir_buff[1];
                recibe_adc_rojo_4_pic1[2] = recibir_buff[2];
                recibe_adc_rojo_4_pic1[3] = recibir_buff[3];
                recibe_adc_rojo_4_pic1[4] = recibir_buff[4];
                recibe_adc_rojo_4_pic1[5] = recibir_buff[5];
                recibe_adc_rojo_4_pic1[6] = recibir_buff[6];
                recibe_adc_rojo_4_pic1[7] = recibir_buff[7];
              
                
                return recibe_adc_rojo_4_pic1;
            }
            //METODO RECIBE ENVIA DATOS ADC PIC 1 
            //SEÑAL ROJO_AC_8
            public void PideDatos_ADC_ROJO_8_PIC1()
            {
                byte* Envio_Buff = stackalloc byte[2];
                Envio_Buff[0] = 0x03;
                Envio_Buff[1] = 0; //No implementado
                EnvioPaquetes(Envio_Buff, 2);
            }
            public float[] RecibeDatos_ADC_ROJO_8_PIC1(uint velo)
            {
             
                uint veloH;
                veloH = velo / 2;
                DWORD RecvLength = 8;
                float[] recibe_adc_rojo_8_pic1 = new float[8];
                byte* recibir_buff = stackalloc byte[8];
                ReciboPaquete(recibir_buff, &RecvLength);
                recibe_adc_rojo_8_pic1[0] = recibir_buff[0];
                recibe_adc_rojo_8_pic1[1] = recibir_buff[1];
                recibe_adc_rojo_8_pic1[2] = recibir_buff[2];
                recibe_adc_rojo_8_pic1[3] = recibir_buff[3];
                recibe_adc_rojo_8_pic1[4] = recibir_buff[4];
                recibe_adc_rojo_8_pic1[5] = recibir_buff[5];
                recibe_adc_rojo_8_pic1[6] = recibir_buff[6];
                recibe_adc_rojo_8_pic1[7] = recibir_buff[7];
                return recibe_adc_rojo_8_pic1;
            }
            //METODO ENVIA-RECIBE DATOS ADC PIC1 
            // SEÑAL: INFR_AC_4
            public void PideDatos_ADC_INFR_AC_4_PIC1()
            {
                byte* Envio_Buff = stackalloc byte[2];
                Envio_Buff[0] = 0x04;
                Envio_Buff[1] = 0;
                EnvioPaquetes(Envio_Buff, 2);
            }
            public float[] RecibeDatos_ADC_INFR_AC_4_PIC1(uint velo)
            {
                uint veloH;
                veloH = velo / 2;
                DWORD RecvLength = 8;
                float[] recibe_adc_infr_ac_4_pic1 = new float[8];
                byte* recibir_buff = stackalloc byte[8];
                ReciboPaquete(recibir_buff, &RecvLength);
                recibe_adc_infr_ac_4_pic1[0] = recibir_buff[0];
                recibe_adc_infr_ac_4_pic1[1] = recibir_buff[1];
                recibe_adc_infr_ac_4_pic1[2] = recibir_buff[2];
                recibe_adc_infr_ac_4_pic1[3] = recibir_buff[3];
                recibe_adc_infr_ac_4_pic1[4] = recibir_buff[4];
                recibe_adc_infr_ac_4_pic1[5] = recibir_buff[5];
                recibe_adc_infr_ac_4_pic1[6] = recibir_buff[6];
                recibe_adc_infr_ac_4_pic1[7] = recibir_buff[7];
                return recibe_adc_infr_ac_4_pic1;
            }
            //METODO ENVIA RECIBE DATOS ADC PIC1 
            // SEÑAL: INFR_AC_8
            public void PideDatos_ADC_Infr_AC_8_PIC1()
            {
                byte* Envio_Buff = stackalloc byte[2];
                Envio_Buff[0] = 0x05;
                Envio_Buff[1] = 0;
                EnvioPaquetes(Envio_Buff, 2);
            }
            public float[] RecibeDatos_ADC_Infr_AC_8_PIC1(uint velo)
            {
                uint veloH;
                veloH = velo / 2;
                DWORD RecvLength = 8;
                float[] recibe_adc_infr_ac_8_pic1 = new float[8];
                byte* recibir_buff = stackalloc byte[8];
                ReciboPaquete(recibir_buff, &RecvLength);
                recibe_adc_infr_ac_8_pic1[0] = recibir_buff[0];
                recibe_adc_infr_ac_8_pic1[1] = recibir_buff[1];
                recibe_adc_infr_ac_8_pic1[2] = recibir_buff[2];
                recibe_adc_infr_ac_8_pic1[3] = recibir_buff[3];
                recibe_adc_infr_ac_8_pic1[4] = recibir_buff[4];
                recibe_adc_infr_ac_8_pic1[5] = recibir_buff[5];
                recibe_adc_infr_ac_8_pic1[6] = recibir_buff[6];
                recibe_adc_infr_ac_8_pic1[7] = recibir_buff[7];
                return recibe_adc_infr_ac_8_pic1;
            }
            //METODO ENVIA-RECIBE DATOS
            // SEÑAL ROJO_DC
            public void PideDatos_ADC_Rojo_DC_PIC1()
            {
                byte* Envio_Buff = stackalloc byte[2];
                Envio_Buff[0] = 0x06;
                Envio_Buff[1] = 0;
                EnvioPaquetes(Envio_Buff, 2);
            }
             public float[] RecibeDatos_ADC_Rojo_DC_PIC1(uint velo)
             {
                 uint veloH;
                 veloH = velo / 2;
                 DWORD RecvLength = 8;
                 float[] recibe_adc_rojo_dc_pic1 = new float[8];
                 byte* recibir_buff = stackalloc byte[8];
                 ReciboPaquete(recibir_buff, &RecvLength);
                 recibe_adc_rojo_dc_pic1[0] = recibir_buff[0];
                 recibe_adc_rojo_dc_pic1[1] = recibir_buff[1];
                 recibe_adc_rojo_dc_pic1[2] = recibir_buff[2];
                 recibe_adc_rojo_dc_pic1[3] = recibir_buff[3];
                 recibe_adc_rojo_dc_pic1[4] = recibir_buff[4];
                 recibe_adc_rojo_dc_pic1[5] = recibir_buff[5];
                 recibe_adc_rojo_dc_pic1[6] = recibir_buff[6];
                 recibe_adc_rojo_dc_pic1[7] = recibir_buff[7];
                 return recibe_adc_rojo_dc_pic1;
             }
             //METODO ENVIA-RECIBE DATOS
             // SEÑAL INFR_DC
             public void PideDatos_ADC_Infr_DC_PIC1()
             {
                 byte* Envio_Buff = stackalloc byte[2];
                 Envio_Buff[0] = 0x07;
                 Envio_Buff[1] = 0;
                 EnvioPaquetes(Envio_Buff, 2);
             }
             public float[] RecibeDatos_ADC_Infr_DC_PIC1(uint velo)
             {
                 uint veloH;
                 veloH = velo / 2;
                 DWORD RecvLength = 8;
                 float[] recibe_adc_infr_dc_pic1 = new float[8];
                 byte* recibir_buff = stackalloc byte[8];
                 ReciboPaquete(recibir_buff, &RecvLength);
                 recibe_adc_infr_dc_pic1[0] = recibir_buff[0];
                 recibe_adc_infr_dc_pic1[1] = recibir_buff[1];
                 recibe_adc_infr_dc_pic1[2] = recibir_buff[2];
                 recibe_adc_infr_dc_pic1[3] = recibir_buff[3];
                 recibe_adc_infr_dc_pic1[4] = recibir_buff[4];
                 recibe_adc_infr_dc_pic1[5] = recibir_buff[5];
                 recibe_adc_infr_dc_pic1[6] = recibir_buff[6];
                 recibe_adc_infr_dc_pic1[7] = recibir_buff[7];
                 return recibe_adc_infr_dc_pic1;
             }
             //METODO ENVIA-RECIBE DATOS
             // SEÑAL LUZ_DC
             public void PideDatos_ADC_Luz_DC_PIC1()
             {
                 byte* Envio_Buff = stackalloc byte[2];
                 Envio_Buff[0] = 0x08;
                 Envio_Buff[1] = 0;
                 EnvioPaquetes(Envio_Buff, 2);
             }
             public float[] RecibeDatos_ADC_Luz_DC_PIC1(uint velo)
             {
                 uint veloH;
                 veloH = velo / 2;
                 DWORD RecvLength = 8;
                 float[] recibe_adc_luz_dc_pic1 = new float[8];
                 byte* recibir_buff = stackalloc byte[8];
                 ReciboPaquete(recibir_buff, &RecvLength);
                 recibe_adc_luz_dc_pic1[0] = recibir_buff[0];
                 recibe_adc_luz_dc_pic1[1] = recibir_buff[1];
                 recibe_adc_luz_dc_pic1[2] = recibir_buff[2];
                 recibe_adc_luz_dc_pic1[3] = recibir_buff[3];
                 recibe_adc_luz_dc_pic1[4] = recibir_buff[4];
                 recibe_adc_luz_dc_pic1[5] = recibir_buff[5];
                 recibe_adc_luz_dc_pic1[6] = recibir_buff[6];
                 recibe_adc_luz_dc_pic1[7] = recibir_buff[7];
                 return recibe_adc_luz_dc_pic1;
             }
            #endregion
         }
}
```
-    Es hora de volver al código principal, para usar la clase que hemos creado haremos los siguiente:
PICUSBAPI usbapi = new PICUSBAPI();
         PicUSB_18API usb_18api = new PicUSB_18API();
-    Recordemos nuestro “form” y sus componentes en la siguiente imagen


http://img70.imageshack.us/img70/3162/cpaso16.jpg

-    Damos doble click en el botón “Abrir” y escribimos lo siguiente:

```
private void btnAbrir_Click(object sender, EventArgs e)
        {
            usbapi.AbrirPipe();
            usbapi.LedPic(0x00);
        }
```
http://img70.imageshack.us/img70/2180/cpaso17.jpg
-    Hacemos lo propio en los demás botones y el código queda así:

```
private void btnCerrar_Click(object sender, EventArgs e)
        {
            usbapi.CerrarPipe();
        }

        private void btnRojo_Click(object sender, EventArgs e)
        {
            usbapi.LedPic(0x02);
        }

        private void btnVerde_Click(object sender, EventArgs e)
        {
            usbapi.LedPic(0x01);
        }
```
-    OK, empecemos a recibir y plotear los datos, primero declaramos en la parte public Form1(), lo siguiente:

```
plotter1.Channels[0].MaximumValue = 2;
            plotter1.Channels[0].MinimumValue = -1;
            plotter1.PlotRate = 15;
            plotter1.Start();
```
-    Con ello decimos que usamos un solo canal del ploter, pero podemos inicializar hasta ocho canales, en la Pág. de codeprojet conde sacamos este ploteador les dirá mas detalles del mismo.
-    Bien para poder plotear necesitamos la ayuda de un timer, este lo encontramos en las herramientas del “TOOLBOX”, arrastrando el mismo queda así en nuestro panel :
http://img70.imageshack.us/img70/1828/cpaso18.jpg

-    Bien hacemos doble click en el timer y colocamos el siguiente cod:

```
//PEDIMOS AL PIC 1 INICIALIZAR EL MODULO ADC ROJO AC_4TO
            usbapi.PideDatos_ADC_ROJO_4_PIC1();
            //-----  CREAMOS UN ARREGLO PARA ALMACENAR DATOS
            float[] Resultado = new float[8];
            //-----  ALMACENAMOS LOS DATOS PROVENIENTES DEL ADC DEL PIC 1
            Resultado = usbapi.RecibeDatos_ADC_ROJO_4_PIC1(4);
            
            //-----  CREAMOS UN BUFFER AUXILIAR PARA GRAFICAR DATOS
            
            float[] Buff_Aux = new float[4];
            Buff_Aux[0] = ((Resultado[0] + Resultado[1] * 256) * 5 / 4096);
            Buff_Aux[1] = ((Resultado[2] + Resultado[3] * 256) * 5 / 4096);
            Buff_Aux[2] = ((Resultado[4] + Resultado[5] * 256) * 5 / 4096);
            Buff_Aux[3] = ((Resultado[6] + Resultado[7] * 256) * 5 / 4096);
           
            plotter1.Channels[0].CurrentValue = Buff_Aux[0] / 25;
            plotter1.UpdateDisplay();
            plotter1.Channels[0].CurrentValue = Buff_Aux[1] / 25;
            plotter1.UpdateDisplay();
            plotter1.Channels[0].CurrentValue = Buff_Aux[2] / 25;
            plotter1.UpdateDisplay();
            plotter1.Channels[0].CurrentValue = Buff_Aux[3] / 25;
            plotter1.UpdateDisplay();
```
-    Describiendo un poco el cod anterior :
o    primero pedimos datos  al PIC , nótese las funciones que desarrollamos en la clase usbapi estarán presentes, un vistazo a ello
o    segundo creamos un arreglo donde almacenaremos nuestros bytes provenientes del pic al cual llamamos “Resultado”
o    En este arreglo “Resultado “ almacenamos los bytes provenientes del pic, pero solo hemos recibido los bytes ADRESH y ADRESL , entonces lo convertiremos a voltaje mediante la siguiente conversión:
Buff_Aux[0] = ((Resultado[0] + Resultado[1] * 256) * 5 / 4096);

En las posiciones Buff_Aux[0], Buff_Aux[0] ,Buff_Aux[0], haremos similar tarea
o    Es hora de plotear, lo haremos con un bucle for de la siguiente manera:
for (i = 0; i < 4; i++)
            {
                plotter1.Channels[0].CurrentValue = Buff_Aux[0] / 25;
                plotter1.UpdateDisplay();
   }

Un detalle, colocamos plotter1.UpdateDisplay con el cual mostraremos los datos, de no colocar esta instrucción nuestro ploter no hara nada.

o    Para llamar al timer deberemos hacer doble click en el botón Plotter y colocamos :

timer1.Start();

o    Bien ya ploteamos y observamos el siguiente video:
prueba de leds:YouTube - Probar Conex USB
prueba de onda: http:YouTube - prueba onda
prueba fototipos: YouTube - MUESTRA DE ONDAS FOTOPLETISMOGRAFICAS


----------



## Chico3001 (Oct 14, 2009)

Buenisimo tu proyecto.....  me tome la libertad de ponerlo entre los temas destacados....


----------



## Moyano Jonathan (Oct 14, 2009)

Un excelente proyecto felicitaciones !!!!!


----------



## Meliklos (Dic 14, 2010)

washi que buen proyecto! 
y que buena presentacion del mismo tambien!

se merece el destacado


----------



## Pelelalo (Dic 14, 2010)

Juer macho, me has quedado de piedra. 

Acabe el DEA y para la Tesis no tengo ni flaguer de que hacer. Pero si tengo que hacer algo a tu altura, lo llevo mal.

Enhorabuena DOCTOR.


----------



## jklemus (Abr 14, 2011)

washi_w_z_r, esta muy bueno tu proyecto ^^

me preguntaba si en el codigo del pic, el archivo que agregas en 

#include <USB_ADC_TESIS.h>

me lo puedes facilitar o si me puedes colaborar pues mejor.

saludos desde colombia


----------



## rascueso (Abr 14, 2011)

washi_w_z_r muy buen proyecto loco y la explicacion 10 puntos. exitos


----------



## Tom sawyer JCHL (Nov 19, 2011)

La señal que obtienes se parece bastante a la fotopletismografia , pero parece que le falta una componente.


----------



## marcjsm1 (Abr 13, 2012)

hola, estoy interesado en realizar un proyecto con un sensor oximetro con el fin de contar pulsos por minuto.. que señal debo adquirir?..la del sensor infrarojo o la del led rojo?..gracias


----------

