Tabla de contenido:

Enviar datos numéricos de un Arduino a otro: 16 pasos
Enviar datos numéricos de un Arduino a otro: 16 pasos

Video: Enviar datos numéricos de un Arduino a otro: 16 pasos

Video: Enviar datos numéricos de un Arduino a otro: 16 pasos
Video: Tutorial LCD 16 x 2 - Arduino - Programacion Paso a Paso - Parte1 2024, Mes de julio
Anonim
Enviar datos numéricos de un Arduino a otro
Enviar datos numéricos de un Arduino a otro

Introducción

por David Palmer, CDIO Tech. en la Universidad de Aston.

¿Alguna vez necesitó enviar algunos números de un Arduino a otro? Este Instructable muestra cómo.

Puede probar fácilmente que funciona simplemente escribiendo una cadena de números para enviar al terminal Serial Monitor, y ver que los números vuelven a aparecer en un segundo monitor Serial conectado al segundo Arduino. Incluso puede utilizar un enlace Bluetooth.

Que hace

Es necesario desarrollar dos programas Arduino (los bocetos en Arduino hablan), uno, un programa maestro para conectarse a la computadora host que ejecuta el monitor serial Arduino, otro para actuar como esclavo para recibir el mensaje serial del maestro, decodificarlo y enviarlo de vuelta. El esclavo es opcionalmente capaz de mostrar los números con los que está tratando en el monitor serial de un segundo IDE, en caso de que quiera usarlo. Puede ayudar a que las cosas funcionen en primer lugar y ayudarlo si decide realizar cambios en los programas para que se adapten a sus propios requisitos.

Equipo

  • 2 de Arduino
  • 2 cables USB
  • cables de conexión (según sea necesario)
  • 1 PC / portátil cargado con Arduino IDE (disponible como descarga gratuita desde el sitio web Arduino.cc)

Paso 1: Configuración: primero configure su hardware

Configuración: primero configure su hardware
Configuración: primero configure su hardware
Configuración: primero configure su hardware
Configuración: primero configure su hardware

Conecte los 2 Arduinos en 2 puertos USB de su computadora.

Sugerencia, es una buena idea etiquetarlos como M y S (maestro y esclavo) para que no se meta en un lío más adelante (como se muestra en las 2 fotos aquí).

Paso 2: Configuración - Configure su pantalla

Configuración: configure su pantalla
Configuración: configure su pantalla

Lo mejor es configurar tu pantalla para que tengas

  • el IDE cargado con el programa maestro a la izquierda y
  • eso con el esclavo a la derecha.

Mantenga los monitores en serie para Maser y Slave a la izquierda y a la derecha también, como se muestra en la captura de pantalla aquí.

Paso 3: Configure el extremo maestro y luego conéctese juntos - Parte 1

Configure el extremo maestro y luego conéctese juntos - Parte 1
Configure el extremo maestro y luego conéctese juntos - Parte 1

Cuando configura su Monitor de serie final maestro para enviar dos números, siempre debe usar el inicio y el final, los caracteres delimitadores y el carácter separador de coma como se ve aquí.

Ahora necesita conectar los 2 Arduino juntos en serie. Esto se hace con dos latiguillos.

Usé verde y amarillo

  • Tome el amarillo primero, esto debe conectarse a D6 en un Arduino y D7 en el segundo
  • Luego, lo opuesto para el cable verde, D7 en el primero y D6 en el segundo Arduino.

Alternativamente, si tiene algo disponible como un par de módulos Bluetooth, como el HC-05, estos también funcionarán para brindarle exactamente el mismo efecto que los cables anteriores.

Paso 4: Configure el Master End, luego conéctese juntos - Parte 2

Configure el Master End, luego conéctese juntos - Parte 2
Configure el Master End, luego conéctese juntos - Parte 2
Configure el Master End, luego conéctese juntos - Parte 2
Configure el Master End, luego conéctese juntos - Parte 2

Estamos haciendo uso de la biblioteca de serie de software. Más información está disponible en este enlace

Puede verlo en la línea 7 de cualquiera de los programas. Configura los pines digitales 7 y 6 como TX y RX (transmitir y recibir). Así es como los datos viajarán desde el Arduino maestro a través del cable verde hacia el Esclavo y, cuando el programa Esclavo en el segundo Arduino haya terminado su trabajo, volverán a través del cable amarillo. En la parte inferior de la misma ilustración (en la ventana Monitor de serie), puede ver que los datos que transmitimos ahora han recorrido con éxito el ciclo que se describe aquí y regresan a la PC como el par de números enteros bien separados.

Paso 5: Descripción general de los bocetos / programas: estructura del programa

Resumen de los bocetos / programas: estructura del programa
Resumen de los bocetos / programas: estructura del programa
Resumen de los bocetos / programas: estructura del programa
Resumen de los bocetos / programas: estructura del programa

Diseño Como en todos los bocetos de Arduino, hay 3 partes básicas:

  • Las declaraciones
  • La puesta en marcha
  • El bucle principal

Como ocurre a menudo, hemos hecho uso aquí de una cuarta sección que es la adición de 'Funciones'. Si no está familiarizado con el uso de Funciones, puede buscar en Google "Funciones de Arduino" y encontrará sitios de explicación como el ejemplo en este enlace: www.tutorialspoint.com/arduino/arduino_functions…..

También hemos hecho uso de pestañas para separar el programa en bloques más manejables.

Los tres bloques que hemos utilizado se pueden ver en la parte superior de cada ilustración de las ventanas IDE de arriba:

  • simpleRxTx0330Master
  • común
  • notas

En realidad, estos son archivos separados dentro de la carpeta del programa, como puede ver en esta vista del Explorador de Windows de los archivos del programa esclavo.

Hay una muy buena razón por la que hemos hecho esto.

  • A medida que estábamos construyendo el programa, nos dimos cuenta de que la mayor parte del programa para el Maestro era el mismo que para el Esclavo.
  • Terminamos colocando todas las partes comunes en una pestaña, que por lo tanto llamamos "común", y luego, cada vez que depuramos una parte (la probamos y estábamos satisfechos de que funcionaba bien), simplemente copiamos y pegamos toda la pestaña. a través de Master a Slave, o viceversa.
  • Las pestañas de notas también resultan ser idénticas, ya que el diseño es genérico.

Ninguna de las funciones se llama desde la configuración, todas se llaman desde el ciclo, por lo que las hemos creado después de la configuración pero antes del ciclo.

Paso 6: Diseño de arriba hacia abajo

Es una buena idea diseñar su boceto comenzando con una definición de lo que desea hacer.

Una vez que tenga esto, puede comenzar a hacer que el boceto haga esas cosas. Generalmente, si hay un detalle que aún no sabe cómo hacer, simplemente conviértalo en una función y deje la creación de la función para más adelante.

Esto sigue la buena filosofía de diseño, que se enseña en muchas universidades, llamada CDIO (si aún no conoces esta, puedes buscarla en Google y encontrar sitios para explicarla como: https://www.cdio.org/s). Esto básicamente dice: No inicie el diseño antes de tener claro el concepto. No inicie la implementación hasta que tenga claro el diseño. No espere que funcione antes de tener clara la implementación. C primero, luego D, I y O. En cada etapa subsiguiente, itera (retroceda por los bucles, por lo que una vez que esté satisfecho con su bucle de diseño inicial, verifique que aún cumple con el Concepto y actualice la C si es necesario. Y así sucesivamente, así que incluso cuando haya llegado a Operación, vaya hasta la parte superior y vuelva a ver cómo se ve la C ahora, luego la D y la I, y haga y verifique todos cambia según sea necesario. Con los bocetos de programación, esto funciona de la misma manera si se diseña de arriba hacia abajo.

Paso 7: Concepto y diseño - Parte 1

Concepto y diseño - Parte 1
Concepto y diseño - Parte 1
Concepto y diseño - Parte 1
Concepto y diseño - Parte 1

El concepto aquí se parece a los requisitos del esquema establecidos en la pestaña 'notas'.

El diseño podría verse como una versión anterior del bucle, que coincide con la pestaña de notas y podría parecerse a lo que se ve en esta figura.

Vea cómo me gusta comenzar realmente copiando CTRL-C primero los comentarios en el encabezado del ciclo, y luego comenzar a llenar los espacios en blanco con comandos que harán esas cosas.

Esto en realidad se compila bien, como puede ver en la parte inferior de la pantalla en la figura. Eso va desde la etapa D de CDIO hasta la I, y a medida que desarrollamos el código, es una buena idea seguir dando vueltas en este bucle D-I.

Ahora es el momento de pasar a la siguiente etapa, hay un comentario allí que dice que vamos a: // recibir algo del hardware USB, luego lo transmitiremos al canal serial del software. Escribimos este código para que eso suceda: las líneas 133 a 138 se muestran aquí en resaltador amarillo

Paso 8: Concepto y diseño - Parte 2

Concepto y diseño - Parte 2
Concepto y diseño - Parte 2
Concepto y diseño - Parte 2
Concepto y diseño - Parte 2

Las dos primeras funciones que presentamos aquí son (recv () y tran () para realizar la recepción desde el puerto de hardware y la transmisión al puerto de software, por lo tanto, llamarlas con los parámetros 'hw' o 'sw' que se muestran.

Además de ellos, hemos agregado una prueba en una variable global llamada newData. Esta es una bandera que colocaremos dentro de la función "void recv ();". Cuando se recibe un mensaje, esta variable se marca de falso a verdadero. Hacemos esto para que solo transmitamos un mensaje si se ha recibido uno (bandera == verdadero) en la línea 134. Y una vez que hemos transmitido nuestro mensaje, eso es 'trabajo hecho', así que borramos la bandera de nuevo a falso en la línea 137.

Nuevamente podemos verificar la compilación (D a I), y esta vez tenemos un mensaje de error 'no declarado' (mostrado). Esto nos dice que no hemos declarado recv (); función. Planeamos hacer esto más adelante, así que solo por ahora para permitirnos obtener una compilación limpia, necesitamos crear una función ficticia o de marcador de posición, como se muestra a continuación.

Nuevamente podemos verificar compilar (D a I), y esta vez tenemos otro mensaje de error 'no declarado' para el tran (); función. Esto necesita una creación de código auxiliar similar. Nuevamente podemos verificar compilar (D a I), y esta vez encontraremos que esto funciona perfectamente; Hasta ahora, todo bien.

Paso 9: Termine el bucle principal: A) Recibiendo desde USB, B) Recibiendo desde Slave Arduino

Termine el bucle principal: A) Recibiendo desde USB, B) Recibiendo desde Slave Arduino
Termine el bucle principal: A) Recibiendo desde USB, B) Recibiendo desde Slave Arduino
Termine el bucle principal: A) Recibiendo desde USB, B) Recibiendo desde Slave Arduino
Termine el bucle principal: A) Recibiendo desde USB, B) Recibiendo desde Slave Arduino

Hay una pieza final que hemos agregado para terminar esta parte, que es agregar un código de depuración.

Hay otro Instructable sobre la depuración de bocetos al que se puede hacer referencia para comprender lo que hemos hecho aquí y por qué. Consulte el Instructable "Cómo construir y probar bocetos de Arduino hasta que funcionen"

Entonces, estas líneas de depuración [136-139 mostradas] se agregan a continuación en el ciclo principal y, he aquí, puede probarlas en el extremo maestro haciendo que la variable de depuración sea verdadera, y compilando (I), entonces si conectas un Arduino, puedes cargarlo, abrir el monitor en serie y ver si lo que vuelve al monitor en serie es como se muestra aquí (¿ves que se agrega el mensaje "MODO DE DEPURACIÓN"?)

Paso 10: recibir y manejar los datos en el Arduino esclavo

Recepción y manejo de datos en el Arduino esclavo
Recepción y manejo de datos en el Arduino esclavo
Recepción y manejo de datos en el Arduino esclavo
Recepción y manejo de datos en el Arduino esclavo

Recepción de esclavo Arduino

Agregue el código necesario para el segundo canal al bucle principal, el receptor en serie del software como se muestra: líneas 149 a 155.

¿Puede ver que la estructura se basa libremente en lo que escribimos anteriormente para el caso Master?

También verá que obtenemos un error del compilador, otra función no declarada - esta vez parseData (); - por lo que también necesitamos hacer un código auxiliar para esto, antes de que podamos ejecutar una compilación de prueba sin errores.

Manejo de los datos en el Arduino esclavo

Agregue el código de bucle principal requerido para Arduino si está configurado como un dispositivo esclavo como se muestra - líneas 163 a 174. ¿Puede ver que la estructura del mismo es muy similar a la del primer canal?

Y deberías encontrar que esta vez se compila absolutamente bien.

Paso 11: escriba la función de recepción

Escribir la función de recepción
Escribir la función de recepción

La función Recibir - void recv (char from) {} - tiene dos trabajos principales.

1 para recibir una cadena de caracteres del canal USB, y

2 para recibir uno del canal Arduino a Arduino.

Para el primero, necesitaremos usar porque usa el hardware UART integrado de Arduino, y para el segundo, usa la biblioteca Arduino estándar: software UART.

Cuando comenzamos a agregar código a una función, para crear una función que haga algo, en lugar de solo un código auxiliar, debemos recordar eliminar o comentar el código auxiliar que está reemplazando. De lo contrario, obtenemos un error de compilación: refinación de 'void lrec (char)'.

Intente obtener el error y luego pruebe cualquiera de las formas sugeridas anteriormente para deshacerse de él.

Comience con una función que se parezca a la que mostramos aquí de las líneas 75 a 88 en amarillo.

A estas alturas ya sabe que, al tener código, deberá probar la operación Compilar. Obtiene un error, como los que teníamos anteriormente, del tipo: nombre de función no declarado en este ámbito. Inicialmente, necesitaremos otro código auxiliar que nos permita compilar después de este error, así que agregue uno como antes y asegúrese de que ahora puede obtener una compilación sin errores.

Ahora echemos un vistazo al código que hemos escrito para la función recv ().

Es bastante limpio, puede ver el uso de la condición 'si' para producir las dos partes de la función mencionada anteriormente.

El código dentro de la parte 'sw' y la parte 'hw' tiene la misma forma, y lo describiré aquí.

La primera del par de líneas en cada caso es el comienzo de un ciclo while. Si no está familiarizado con while, puede buscarlo en el sitio Arduino.cc/Reference para obtener una explicación y ejemplos. Aquí esperamos 'mientras' la función 'Serial' incorporada no ha recibido ningún carácter y porque la variable newData se ha desactivado (es decir, la condición newData == false es verdadera). Tan pronto como se reciba un carácter, o más de un carácter, el while pasará a la segunda línea de este par. Eso luego llamará a recAstringChar (char); función para manejar el carácter actual. Este par de líneas se alternarán mientras (o mientras) haya caracteres que aún requieran ser recibidos. Una vez que están todos terminados, el estado while finaliza, permitiendo que el if o el siguiente nivel hasta el final, y a su vez permitiendo el rec (char); función para terminar. Por lo tanto, ahora se ha recibido un mensaje completo.

Paso 12: Escriba la subfunción de recepción - Parte 1

Escribir la subfunción de recepción - Parte 1
Escribir la subfunción de recepción - Parte 1
Escribir la subfunción de recepción - Parte 1
Escribir la subfunción de recepción - Parte 1

Ahora necesitamos escribir la función llamada recAstringChar (char);. Puede ver en el comentario de la línea 50 aquí en la parte superior, que su trabajo es actualizar dos búferes con copias del mensaje serial entrante. [Resultó que mientras intentaba hacer que todo esto funcionara, una cosa que aprendí fue que necesitaba dos búferes diferentes, o al menos esa era la forma más fácil de solucionar algunos problemas, por lo que evolucionó hasta necesitar 2 búferes, así que Los acabo de hacer.] He llamado a un búfer: selectedData y al otro: selectedChars.

Los búferes son variables globales, por lo que se declaran a nivel de módulo, consulte las líneas 9 y 10 de la pestaña común. Hay otras variables declaradas dentro de esta función que, por lo tanto, tienen alcance local, como se muestra en las líneas 51-54 aquí. Este no es el lugar para explicar las diferencias entre globales y locales, pero hay más información sobre esto en https://www.arduino.cc/glossary/en/ en Local y Global.

También puede averiguar todo sobre los tipos de datos y modificadores de tipo: estático, booleano, byte, const, char en https://www.arduino.cc/reference/en/#variables, que se muestra aquí.

El flujo del programa principal en esta función está controlado por el if en la línea 56 aquí, y su correspondiente else en la línea 74. Se trata de dos escenarios

a) [de la línea 74 en adelante] cuando comienza el mensaje recibido. Esto sucede cuando se detecta el marcador de inicio; esto se ha definido como el carácter '<', por lo que siempre que probamos el boceto siempre comenzamos nuestra cadena con ese carácter. Si no lo hacemos, no se procesará nada como recibido, todo se ignorará como si estuviéramos escribiendo tonterías en el indicador del teclado 'Monitor en serie'.

b) [líneas 56 a 73] que recibe todos los demás caracteres, sean los que sean, pero solo tratan con caracteres después de que ha ocurrido un inicio válido (se ha recibido un '>' como en a) anterior).

En estas líneas (de 74 a 78) colocamos que recibió <en uno de los búferes (recibióData [0]) pero no en el otro. Ajustamos el puntero del búfer (variable: char ndx) para que apunte a la siguiente posición del búfer de reserva (datos recibidos [1]) usando el comando post-incremento (++) en la línea ndx ++; y establecemos el indicador en progreso en verdadero.

El flujo del programa en esta parte de la función está controlado por el if en la línea 57 aquí, y su correspondiente else en la línea 65. Se trata de dos escenarios

a) [de la línea 65 en adelante] cuando finaliza el mensaje recibido. Esto sucede cuando se detecta el endMarker, definido como>, por lo que cada vez que probamos nuestro boceto, siempre terminamos nuestra cadena con ese carácter. Una de las cosas que sucede cuando se recibe el carácter final es que la bandera global (técnicamente variable) newData se establece como verdadera justo cuando la función termina, de modo que la función que llamó a nuestra subfunción (la función de llamada: recv (char);) puede 'saber' que se han recibido nuevos datos válidos completos.

b) [líneas 57 a 64] que recibe todos los demás caracteres, sean los que sean. Simplemente los estaciona cuidadosamente en filas en ambos búferes.

Paso 13: Escriba la subfunción de recepción - Parte 2

Escribir la subfunción de recepción - Parte 2
Escribir la subfunción de recepción - Parte 2
Escribir la subfunción de recepción - Parte 2
Escribir la subfunción de recepción - Parte 2

Podría ser útil dar un ejemplo de cómo se ven los 2 búferes cuando se han llenado. Si tuviéramos que teclear enter, los búferes tendrían los caracteres que se muestran en ellos:

Así que ahora puede ver que tenemos un búfer que tiene exactamente los mismos caracteres que escribimos por primera vez, y un búfer que solo tiene los dos valores y una coma de separación. Ahora tenemos un código que puede recibir los caracteres que escribimos en el teclado del Monitor Serial, podemos pasar de la fase I de CDIO a la O, escribiendo algunas cadenas y viendo qué sucede. Sube el código al Master Arduino, abre el Serial Monitor e intenta escribir algo válido, como enter. ¿Recibe un eco en la pantalla del Monitor serial como el que se muestra aquí?

Paso 14: Escriba las funciones de transmisión y análisis

Escribir las funciones de transmisión y análisis
Escribir las funciones de transmisión y análisis
Escribir las funciones de transmisión y análisis
Escribir las funciones de transmisión y análisis

Primero para la transmisión

Entonces, ahora que hemos recibido una cadena, podemos escribir la función de transmisión: tran (char); para reemplazar su talón. Esto nos permitirá enviar una cadena desde el maestro al esclavo Arduino, así que asegúrese de que ambos dispositivos estén enchufados y conectados juntos para probar esta nueva funcionalidad.

Ingrese esta función como se muestra aquí en las líneas 117 a 133. Como reconocerá, tiene dos partes, una para transmitir al canal USB (hardware UART) y otra para transmitir al otro Arduino (software UART). Esto debería compilar el error -gratis, y puede cargar inmediatamente el boceto y ver qué sucede. Esta vez lo enviaré. ¿Obtienes el resultado que se muestra?

La captura de pantalla es interesante porque la cadena Recibida … debería verse correcta como antes, y la cadena Transmitida … ahora debería verse correcta. Sin embargo, tenga en cuenta que la conversión de números enteros no ha funcionado. Todavía hay un poco más de código para agregar para que funcione.

Paso 15: Escriba las funciones de transmisión y análisis

Escribir las funciones de transmisión y análisis
Escribir las funciones de transmisión y análisis
Escribir las funciones de transmisión y análisis
Escribir las funciones de transmisión y análisis

Entonces para el Parse

Este es un fragmento de código que analiza la cadena recibida para obtener las cadenas parciales numéricas y las convierte en valores enteros. Es el vacío parseData (); función del bucle principal

Reemplace el stub de análisis con el código que se muestra en las líneas 98 - 113. Súbelo y veamos si el problema que teníamos con los 2 valores enteros ahora está solucionado. Intentemos.

Sí, funciona, como se muestra, los números enteros encontrados son 49 y 98.

Paso 16: ¡Final

¡Final!
¡Final!

Estos datos han recorrido todo el ciclo desde la PC a través del Maestro a través del esclavo y de vuelta a través del Maestro nuevamente a la PC. Con la versión final de common cargada en los extremos maestro y esclavo, y con el modo de depuración desactivado ahora, podemos ver los datos recibidos correctamente en ambos extremos como se muestra aquí.

Recomendado: