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
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
- 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
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:
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 :
10 y extra... he incluido la función espera() que simplemente es una delay() Casera
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
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
- 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
-A continuación vaciamos en buffer con
Código:
While (NETComm1.InBufferCount <> 0)
trama = NETComm1.InputData
Wend
trama = ""
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
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
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
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