# Como usar puerto Serie en VBA (Excel)



## rumboleon

Bueno, llevo dos días loco intentando comunicarme con mi microcontrolador Arduino a través de VBA (en Excel). Y he notado que si bien todo el mundo dice que hay miles de ejemplos en la web, será que el google tenía un mal día porque pocos he encontrado que me fuesen útiles y explicasen realmente como funciona la comunicación en serie a nivel de un absoluto novel en el tema. Así que ahora que por fin he conseguido que funcione voy a intentar explicar paso por paso como se hace.

En primer lugar, el protocolo de comunicaciones es casero y el programa es el primero que hago en VB, así que es muy rudimentario y no está muy depurado, pero hace dos días habría matado por uno así

Bien, el programa sirve para gestionar los datos de un sensor (en mi caso ultrasónico) conectado al micro controlador. Si está encendido, el micro envía H por el puerto serie constantemente, cuando recibe una instrucción valida (en este caso A) envía una B y después el resultado de la medición (el tiempo en el que lo hace es desconocido) y se pone a la espera de otra orden.

He utilizado de obtener un dato, en primer lugar,manual por medio de 3 botones (abrir puerto, medir, cerrar puerto) y otra que directamente abre el puerto, introduce una serie de datos (hora...) y 7 tandas en las que en cada una se coloca la media de 7 mediciones...

1. Para empezar, hay que bajarse la librería para las comunicaciones está será MScomm o Netcomm (http://home.comcast.net/~hardandsoftware/NETCommOCX.htm).

2. La instaláis, reemplazáis con la actualización el OCX, REINICIÁIS el ordenador y en el editor de VBA en referencias, activais "MScomm32.Ocx replacement" (en VB le agregáis la referencia)

3. En insertar controles > controles activeX >mas controles..> y buscáis NetcomOCX.Netcom (o en el caso de MScomm creo que es "microsoft comunications control 6.0" o algo así y lo colocáis en un sitio que no moleste (pero que sepáis donde está porque es invisible)

4. Se colocan los botones,colores.... 

5. Para saber como se llama el objeto de comunicaciones (MScomm1, Netcomm2...) la forma mas sencilla es haced doble click sobre el y ver como se llama la rutina.

6.Para abrir el puerto, se debe configurar previamente, como por ejemplo


		Código:
	

NETComm1.CommPort = Sheets("config").Cells(4, 5)
NETComm1.Settings = Sheets("config").Cells(5, 5) & ",N,8,1"
NETComm1.PortOpen = True
NETComm1.RThreshold = 1
NETComm1.InputLen = 1
NETComm1.InBufferSize = 1024
NETComm1.PortOpen = False

importantes

- CommPort, introducimos el NUMERO (sin COM) del puerto, en este caso, una referencia a una celda

- Settings se sigue el formato "velocidad,Paridad,Tamaño,Bits de parada"

- PortOpen abre/cierra el puerto

-NETcomm1.InputLen dice de cuantos bytes, en cuantos bytes lees los datos, (si es 0 es ilimitado). A mi me hizo perder un día entero, puesto que mi programa recoge los bytes de uno en uno y los alitera hasta encontrar el retorno de carro, así que cuidado.

   Para abrirlo basta con un


		Código:
	

If NETComm1.PortOpen = False Then 'Si el puerto está cerrado, lo abre
NETComm1.PortOpen = True
End If

- En donde queramos (en el botón solo para abrir o dentro de otro...)y podemos ponerle mensajes de error con MSgbox si da problemas (con NETComm1.PortOpen nos devuelve su estado)

-A continuación vaciamos en buffer con


		Código:
	

While (NETComm1.InBufferCount <> 0)
    trama = NETComm1.InputData
Wend
trama = ""

y ya tenemos el puerto abierto y listo.

7. Cerrarlo consiste básicamente en NETComm1.Portopen = False (para evitar poblemas, podemos usar un "if Netcomm1.PortOpen= True then Netcomm1.PortOpen=False "

8. Lo importante, para recibir los datos, si queremos estar recibiendo datos continuamente podemos usar el objeto Netcomm como propone http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1230677761. En mi caso, solo quiero recibir un dato cuando lo pida, para eso creo una función que dice lo siguiente:



		Código:
	

Private Function actualiza()

'La siguiente instrucción, actualiza el dato almacenado y lo retorna en cuanto recibe 'un retorno de carro

Dim datosSerie As String
Dim dato As String
    
    actualiza = 0
    datosSerie = "_"
    dato = ""
    
    Rc = Chr(10) 'Caracter de retorno de carro
    NL = Chr(13) 'Carcacter de siguiente linea
    
   If NETComm1.CommEvent = NETComm_EV_RECEIVE Then 'Si recibe información...
        While (datosSerie <> Rc)    'Mientras sea distinta del retorno de carro...
            datosSerie = NETComm1.InputData 'Recibe el byte
            If (datosSerie > NL) Then   'Desprecia todos los caracteres anteriores a NL (incluidos)
                trama = trama + datosSerie  'Alitera los datos
            End If
        Wend
        dato = trama
        trama = ""  'limpia la trama
        Cells(26, 18).Value = dato
        actualiza = dato 'Devuelve el dato
        Else
        MsgBox "Datos no recibidos", vbCritical + vbOKOnly, "Error 3"
    End If


End Function

Creo que con los comentarios debería ser suficiente, resumiendo, la función devuelve cada vez que la llamamos el código recibido (hasta el retorno de carro y despreciando los saltos de linea)

9- Solo tenemos que llamarla cuando queramos recibir un dato. En mi caso el algoritmo sería el siquiente:

Si recibo una H ->  Envío una "A" ->Espero a recibir una "B" -> Si la recibo, espero a que desaparezca y me envíe el dato. En mi caso :



		Código:
	

'Al hacer click, Indica una sola medición
If NETComm1.PortOpen = False Then
MsgBox "El puerto no está abierto", vbCritical + vbOKOnly, "Error 5"
Else
datoS = actualiza()
If datoS = "H" Then
    NETComm1.Output = "A" ' Envia el numero de orden (dato individual)
    espera (10)
    datoS = actualiza()
        If (datoS = "B") Then
            While (datoS = "B")
            datoS = actualiza()
            Wend
        Cells(26, 17) = datoS
        Else
        MsgBox "Arduino no entiende el comando, ha respondido: " & datoS, vbCritial + vbOKOnly, "Error 4"
        End If
Else: MsgBox "No recibida comunicación con Arduino", vbCritical + vbOKOnly, "Error 2"
End If
End If

10 y extra... he incluido la función espera()  que simplemente es una delay() Casera



		Código:
	

Private Function espera(a As Single)
'Esta función simplemente hace un "wait"
Dim m As Integer

 tiempo_inicial = timeGetTime()
   Do
       tiempo_actual = timeGetTime()
       n = DoEvents()
   Loop Until (tiempo_actual >= tiempo_inicial + a)
espera = 1
End Function

Adjunto el XLS para que podáis verlo.

Y debo dar las gracias a Igor R. del foro de Arduino, porque sinceramente, su hilo es el único que me ha sido realmente útil


----------



## Lobato Garcia

Hola rumboleon:

Me parece un trabajo excelente. Por favor si es posible a mí también me gustaría que me enviaras el Excel. Estaba buscando algo así pero no encontraba nada. 

Un saludo y muchas gracias


----------



## KanonOfGeminis

Muy interesante lo que describes, tiene la forma que tengo para implementarlo en una estacion radial.
No soy tan bueno en VBA pero entiendo algunos comandos que describes.

Muchas gracias.


----------



## alejandrow999

Hola rumboleón. Es muy intereresante tu aporte. Solo te quería sugerir que comprimieses el archivo (por ejemplo al formato ZIP) , lo subas a algún almacén de archivos (mediafire, megaupload,...) o simplemente le avises a algún modeador de tu problema para poder subirlo acá. Pasa que no sólo es incomodo que difundas el archivo via mail, sino que contradice la idea de un foro público, realmente. 

Saludos.


----------



## krit

¿Porque mediafire o mega"timo"upload si no no son mas que unos vampiros que ganan un dinero con el trabajo de otros?
Este foro dispone de unos medios muy fáciles de usar para compartir información; y ademas gratis.

Yo tampoco dispongo de una cuenta premium ni estoy registrado en ninguna pagina-timo de estas y me ha costado un "guevo y parte del otro" bajar el archivo. Seguramente eso es asi por que no pago y estos vampiros sólo quieren que subamos archivos para compartir,teoricamente, pero a la hora de bajar no ponen las cosas tan fáciles.

Baje el archivo por curiosear un poco pero no tengo los conocimientos suficientes para abrirlo con el VB de excel.
De todas formas lo dejo en el foro por si a alguien le interesa. Siempre sera mas facil bajarlo desde aqui.
Por cierto rumboleon yo tambien soy de León;de León de España.
Un saludo.


----------



## Citroen 8

Hola rumboleon,
me llamo David y vivo en Valladolid.He leido tu articulo y me parece muy interesante.No obstante estoy bastante pez en esto y necesitaría de tu ayuda en algo que creo que tienes resuelto.Te explico:

Necesito que al ejecutar el proyecto
 State change detection (edge detection) de arduino ,el pushbutton count, es decir el numero de veces que pulso el boton, que me copie este contador a una celda de excel.

Ya me instale el active x Netcomm, por lo que ya tengo comunicacion con el puerto.
M faltaria solo la macro de excel.Agradecería enormemente que pudieras ayudarme.

Sólo necesito copiar el contador en una celda de excel, de forma continua o como muchocqon una tasa de refresco de 1 segundo.
Muchisimas gracias.

David


----------



## 1000tonto

muy buenas foro...

miren eh estado intentando poder recepcionar en excell y la verdad ya no pude.... eh buscado todo lo que hay en internet y bueno para lo que es envio todo ok pero para la recepcion es otro el cuento...

lo que queria era recepcionar un dato del puerto serial cada 500 ms esto que lo haga autonomamente.. pero aun no puedo recepcionar nada y queria que lo que recepcione sea mostrado un textbox o en las celdas de excell si pudiesen ayudarme se los agradeceria ya que he visto que estan al tanto de este tema...

lo que utilizo es:

Private Sub NETComm1_OnComm()
        If NETComm1.CommEvent = NETComm_EV_RECEIVE Then
            TextBox2.Text = NETComm1.InputData  

End Sub


gracias por la ayuda...


----------



## 1000tonto

bueno querido foro.. los saludo..

ya encontre mi problema, era cosa del netcomm1 colocarlo y reiniciar... muchas gracias por compartir vuestras experiencias hasta otra byebye.......


----------



## GONZA911

Buenas, estoy  desarrollando un programa en PIC16F877A el cual  envia datos a excel mediante puerto serie separados por punto y coma ";" para separar estos datos en dos columnas distintas. y bueno, hasta ahi todo bien. utilizo hyperterminal para enviar los datos a un archivo ".csv" y luego graficarlos. 

lo que me gustaria hacer es realizar esta misma recopilacion de datos pero graficando en tiempo real, es decir, graficar a medida que se va desarrolando el proceso y no tener que esperar a que este finalice para ver el grafico. 

e intentado hacer esto mediante VBA pero al parecer es dificil en el sistema que utilizo (Office 2013 x64 en windows 7 x64). estube tratando de instalar las referencias de MScomm y de NETcommX sin resultado alguno. 

existe alguna forma de resolver este insconveniente en mi sistema o algun otro metodo para adquirir estos datos en tiempo real, que porsupuesto no implique instalar Matlab ni lavbiew ni Visual basic? (es la idea de este trabajo). 

agradezco desde ya cualquier ayuda...


----------



## kamk

buenas tardes,

busco concretar la transmisión serie entre excel y un pic para graficar los datos de mi sensor ultrasonico a tiempo real, para ello utilizo proteus para simular el pic y la comunicación serial con EXCEL, (LA CUAL ES EFECTIVA), sin embargo no logro gráficar la información que envio a EXCEL a traves del puerto serial. 


no utilizo ni java, ni visual estudio, ni matlab ni labview, solo excel dado que (es un proyecto economico). 

-adjunto el codigo utilizado de VBA de excel 2010 (implementado en el macro)y  la imagen (donde muestro que efectivamente se establece la comunicación serial) a traves del software  virtual serial port, 

En la otra imagen aparece el contenido de mi macro.



		Código:
	

Private Sub ToggleButton1_Click()
Dim trama As String

If NETComm1.PortOpen = False Then 'Si el puerto está cerrado, lo abre
NETComm1.PortOpen = True

While (NETComm1.InBufferCount <> 0)
    trama = NETComm1.InputData
    Cells(1, 1).Value = trama
Wend

 

ElseIf NETComm1.PortOpen = True Then
NETComm1.PortOpen = False
End If
End Sub




En la esquina inferior se asoma el grafico, el cual esta en blanco.




De ante mano muchas gracias, editare el mensaje.


----------



## RFQP

hola buen dia , soy nuevo en el tema y necesito recibir datos de un equipo por un com , y que esa informacion se reciba en una celda en un ahoja de excel .. ya descargue la libreria y la instale en el pc pero no me comunica


----------



## jaravena

Indique el código.


----------



## RFQP

muchas gracias por responder , mira tengo este código según el cual ya debo recibir información en las celdas en excel pero nada :

Private Sub CommandButton1_Click()
NETComm1.CommPort = Sheets("config").Cells(8, 15)
NETComm1.Settings = Sheets("config").Cells(8, 15) & ",N,8,1"
NETComm1.PortOpen = True
NETComm1.RThreshold = 1
NETComm1.InputLen = 1
NETComm1.InBufferSize = 1024
NETComm1.PortOpen = False

If NETComm1.PortOpen = False Then
NETComm1.PortOpen = True
End If

While (NETComm1.InBufferCount <> 0)
    trama = NETComm1.InputData

    Wend
    trama = ""


End Sub


**************************************

coloque de esta manera la configuracion del netcomm:

agradezco mucho cualquier ayuda ::::


----------



## D@rkbytes

Configura la propiedad Handshaking en "NONE o NINGUNO" según venga en ese control.
Ese control es un wraper del MSCOMM32.OCX, o sea que lo tiene interno, lo cual no tiene mucho sentido, aparte de mostrar una molesta ventana al iniciar y al finalizar la ejecución.

Por otro lado, el control ActiveX MSCOMM32.OCX ya no tiene funcionalidad en Windows 10
Tienes que migrar a .NET o usar las API de Windows.
Transmite pero no recibe, y sin depuración se puede generar un error que cerrará la aplicación.

Si no es tu caso, prueba cambiando lo que te mencioné.

Otra cosa. No he usado esta funcionalidad en Excel, pero no veo que estés asignando lo que recibes a ninguna celda.


----------



## jaravena

Te adjunto una hoja que me funciono con excel 2003 sobre widows7
Hay unas altrenativas interesantes en "Instructables.com"
busca por "excel".
Una solucion novedosa, basada en el chip ESP8266 esta con el titulo "Direct to Excel Measurement" que tambien está en español. No te envio el link pues el foro lo prohibe.
Buena suerte.


----------



## MasterPorcupine

D@rkbytes dijo:


> Por otro lado, el control ActiveX MSCOMM32.OCX ya no tiene funcionalidad en Windows 10
> Tienes que migrar a .NET o usar las API de Windows.
> Transmite pero no recibe, y sin depuración se puede generar un error que cerrará la aplicación.



hola D@rkbytes, perdon por la pregunta de algo de hace tiempo, me podrias aclarar eso por favor, estoy empezando con este proyecto en VBA y cuento con office 13 y windows 10, no sabia eso que no ya no recibia informacion. No se a que te refieras con .Net y las API de Windows, soy novato en esto


----------



## D@rkbytes

En Windows 10 x64, no sé si en x86 también, se presenta un caso muy extraño con el ActiveX MSCOMM32.OCX.
En algunas aplicaciones recibe sin problemas, pero en otras se produce un error en el evento comEvReceive.
No sé a qué se deba y tampoco busqué el motivo, mejor usé las API  de Windows.

.Net es el Framework que incluye las librerías para el nuevo entorno de Visual Studio.
Las API de Windows son las librerías nativas del sistema, a las que se puede tener acceso por medio de llamadas sus funciones.
Sobre esto puedes encontrar más información en Internet, ya que el tema es bastante extenso.

Saludos.


----------



## laurym

Saludos, el enlace esta caído y no se donde descargar el MScomm32.Ocx  para win7 de 64bits.


----------



## D@rkbytes

No existe MSCOMM32.OCX de 64 bits, por eso al final de su nombre lleva el 32. (32 bits)
Sin embargo, el de 32 bits (x86) funciona perfectamente en Windows 7 x64.
Descarga segura de MSCOMM32.OCX: *Interfaz RS232 PIC PC (Proyecto Completo VB6)*


----------

