Archivo de la categoría: Diseños

¿Qué es la comunicación serie?

La electrónica integrada se conforma con circuitos interconectados (procesadores u otros circuitos integrados) para crear un sistema en el que están repartidas las funciones. Para que esos circuitos individuales intercambien su información, deben compartir un protocolo de comunicación común. Se han definido muchos protocolos de comunicación para lograr este intercambio de datos y, esencialmente, cada uno puede ubicarse en una de dos categorías: 1. Paralelo o 2. Serie.

Paralelo versus serie

Las interfaces paralelas transfieren múltiples bits simultáneamente. Por lo general, requieren barras (buses) de datos, que se transmiten a través de ocho, dieciséis o más cables. Los datos se transfieren en amplios oleajes de 1s y 0s.

Un bus de datos de 8 bits, controlado por un reloj,
que transmite un byte por cada pulso de reloj. Se utilizan 9 líneas


En cambio, las interfaces serie transmiten sus datos un bit a la vez. Estas interfaces pueden operar con tan solo un cable, por lo general nunca más de cuatro.

Ejemplo de una interfaz serie, transmitiendo un bit cada pulso de reloj. Solo se requieren 2 cables


Piense en las dos interfaces como una fila de automóviles: una interfaz paralela sería una autopista de 8 carriles o más, mientras que una interfaz en serie es más parecida a una carretera de dos carriles. Durante un lapso determinado, la autopista tiene el potencial de llevar a más personas a destino, pero en muchos casos ese sistema sencillo de dos carriles responde a su propósito, y construirlo cuesta una fracción de los fondos.

La comunicación paralela ciertamente tiene sus beneficios. Es rápida, directa y relativamente fácil de implementar. Pero requiere muchas más líneas de entrada/salida (E/S). Si alguna vez ha tenido que traspasar un proyecto de un Arduino Mega a un Arduino UNO básico, sabe que las líneas de E/S en un microprocesador pueden ser preciosas por lo limitadas. Por lo tanto, cada vez más optamos por la comunicación en serie, sacrificando una velocidad potencial para ahorrar pines.

Serie asíncrono (asincrónico)

A lo largo de los años, se han creado docenas de protocolos en serie para satisfacer las necesidades particulares de los sistemas integrados. USB (Universal Serial Bus = Bus Serie Universal) y Ethernet son dos de las interfaces serie de computación más conocidas en la actualidad. Otras interfaces serie muy comunes son SPI (del inglés Serial Peripheral Interface), I²C (del inglés Inter-Integrated Circuit) y el interfaz serie estándar TX/RX, del que hablaremos aquí. Estas interfaces serie pueden clasificarse en uno de dos grupos: sincrónico o asincrónico.

Una interfaz serie sincrónica siempre necesita tener una señal de reloj junto a las líneas de datos, por lo que todos los dispositivos en un bus serie sincrónico comparten un pulso común de reloj. Esto hace que en una transferencia en serie más directa, a menudo más rápida, también se requiera al menos un cable adicional entre los dispositivos de comunicación. Entre los ejemplos de interfaces sincrónicas están SPI e I²C.

Asincrónico significa que los datos se transfieren sin el respaldo de una señal de reloj conectada entre sistemas. Este método de transmisión es ideal para minimizar los cables necesarios, y en consecuencia la cantidad de pines de E/S utilizados, pero implica que debemos poner un poco de esfuerzo adicional en transferir y recibir datos de manera confiable. El protocolo en serie que analizaremos es la forma más común para las transferencias asincrónicas. De hecho, es tan común que cuando la mayoría de la gente dice «en serie», “o serial”, están hablando sobre este protocolo.

El protocolo serie sin reloj que analizaremos se usa ampliamente en electrónica integrada. Si está buscando agregar un módulo serie GPS, Bluetooth, XBee, LCD, o muchos otros dispositivos externos a su proyecto, es probable que necesite un interfaz serie.

Reglas de la comunicación serie

El protocolo serie asincrónico tiene una serie de reglas integradas: mecanismos que ayudan a garantizar transferencias de datos sólidas y sin errores. Estos mecanismos, que obtenemos para evitar la señal del reloj externo, son:

   ■ Bits de datos
   ■ Bits de sincronización
   ■ Bits de paridad
   ■ Velocidad en baudios

Teniendo en cuenta la variedad de estos mecanismos de señalización, vemos que no hay una sola manera de enviar datos en serie. El protocolo es altamente configurable. La parte crítica es asegurarse de que ambos dispositivos en una línea serie estén configurados para usar exactamente los mismos protocolos.

Velocidad en baudios

La especificación de velocidad de transmisión indica qué tan rápido se envían los datos a través de una línea serie. Normalmente se expresa en unidades de bits por segundo (bps). Si se invierte la velocidad en baudios, se puede averiguar cuánto tiempo se tarda en transmitir cada bit. Este valor determina durante cuánto tiempo el transmisor mantiene en alto/bajo una línea serie, o a qué velocidad muestrea su línea el dispositivo receptor.

Las velocidades en baudios pueden ser casi cualquier valor dentro de lo que permite el hardware. El único requisito es que ambos dispositivos funcionen a la misma velocidad. Una de las velocidades en baudios más comunes, especialmente para cosas simples donde la velocidad no es crítica, es de 9600 bps. Otras velocidades en baudios «estándar» son 1200, 2400, 4800, 19200, 38400, 57600 y 115200.

Cuanto mayor sea la velocidad en baudios, más rápido se envían/reciben los datos, pero existen límites para la velocidad a la que se pueden transferir los datos. Por lo general, no verá velocidades superiores a 115200, lo que es suficientemente rápido para la mayoría de los microcontroladores. Aumente demasiado y comenzará a ver errores en el extremo receptor, ya que los pulsos de reloj y los períodos de muestreo no pueden mantenerse.

Estructurando los datos

Cada bloque de datos (generalmente un byte) que se transmite se envía en realidad en un paquete de bits. Los paquetes se crean agregando bits de sincronización y paridad a nuestros datos.

Algunos símbolos en la estructura del paquete tienen tamaños de bits que son configurables.

Vamos a entrar en los detalles de cada una de estas partes de la estructura del paquete, o bloque.

Bloque de datos

La verdadera sustancia de cada paquete serie es la información que lleva. Ambiguamente llamamos a este bloque de datos un “bloque”, porque su tamaño no está específicamente establecido. En este estándar, la cantidad de datos en cada paquete se puede establecer en valores de 5 a 9 bits. Ciertamente, el tamaño de datos clásico es un byte de 8 bits, pero se usan otros tamaños. Un bloque de datos de 7 bits puede ser más eficiente que 8 si solo está transfiriendo caracteres ASCII de 7 bits.

Después de acordar la longitud para un caracter, ambos dispositivos serie también tienen que acordar el formato de sus datos. ¿Se envían los datos desde el bit más significativo (most significative bit = msb) al menos significativo, o viceversa? Si no se indica lo contrario, generalmente se puede asumir que los datos se transfieren enviando primero el bit menos significativo (least significative bit = lsb).

Bits de sincronización

Los bits de sincronización son dos o tres bits especiales transferidos con cada porción de datos. Son el bit de inicio y el(los) bit(s) de parada. Tal como indica su nombre, estos bits marcan el principio y el final de un paquete. Siempre hay un único bit de inicio, pero la cantidad de bits de parada se puede configurar en uno o dos (aunque normalmente se deja en uno).

El bit de inicio siempre se indica mediante una línea de datos inactiva que pasa de 1 a 0 (ALTO a BAJO). Los bits de parada volverán al estado inactivo manteniendo la línea en 1 (ALTO).

Bits de paridad

La paridad es una forma de comprobación de errores muy simple y de bajo nivel. Se presenta en dos variantes: impar o par. Para generar el bit de paridad, se suman todos los bits del byte de datos (5 a 9), y el resultado de la suma define si el bit es 1 o 0. Por ejemplo, suponiendo que la paridad se establece en par y se agrega a un byte de datos como 0b01011101, que tiene una cantidad impar de 1s (5), el bit de paridad quedaría en 1. Por el contrario, si el modo de paridad se configuró en impar, el bit de paridad sería 0.

La paridad es opcional, y no se usa mucho. Puede ser útil para transmitir a través de medios ruidosos, pero también ralentizará un poco la transferencia de datos y requiere que tanto el transmisor como el receptor implementen el manejo de errores (generalmente, si se detecta error, los datos recibidos con falla deben reenviarse).

Un ejemplo

9600 8N1 – 9600 baudios, 8 bits de datos, sin paridad y 1 bit de parada: es uno de los protocolos serie más utilizados. Entonces, ¿cómo se vería un paquete o dos de datos de 9600 8N1?

Un dispositivo que transmita los caracteres ASCII ‘O’ y ‘K’ tendría que crear dos paquetes de datos. El valor ASCII de O (en mayúsculas) es 79, que se divide en un valor binario de 8 bits de 01001111, mientras que el valor binario de K es 01001011. Todo lo que queda es agregar bits de sincronización.

No se establece específicamente, pero la norma más aceptada es que los datos se transfieren enviando primero el bit menos significativo. Observe cómo se envía cada uno de los dos bytes a medida que se lee de derecha (bit 0) a izquierda (bit 7).

Dado que estamos transfiriendo a 9600 bps, el tiempo empleado en mantener cada uno de esos bits alto o bajo es 1/9600 (bps) o 104 µs por bit.

Por cada byte de datos transmitidos, en realidad como mínimo se envían 10 bits: un bit de inicio, 8 bits de datos y un bit de parada. Entonces, a 9600 bps, en realidad estamos enviando 9600 bits por segundo o 960 (9600/10) bytes por segundo.

Ahora que sabemos cómo construir paquetes serie, podemos pasar a la sección de hardware. Allí veremos cómo esos 1s y 0s, y la velocidad de transmisión, se implementan a un nivel de señal.

Cableado y Hardware

Un bus serie consta de solo dos cables, uno para enviar datos y otro para recibir. Entonces, los dispositivos serie deben tener dos pines serie: el receptor: RX y el transmisor: TX.

Cableado en serie

Es importante tener en cuenta que esas etiquetas RX y TX son con respecto al dispositivo en sí. Entonces, el RX de un dispositivo debe ir al TX del otro y viceversa. Es extraño si uno está acostumbrado a conectar Vcc con Vcc, GND con GND, MOSI con MOSI, etc., pero —pensándolo— tiene sentido. El transmisor debe estar comunicándose con un receptor, no con otro transmisor.

Una interfaz en serie en la que ambos dispositivos pueden enviar y recibir datos es dúplex completo (full-duplex) o semidúplex. Full-duplex significa que ambos dispositivos pueden enviar y recibir simultáneamente. La comunicación semidúplex significa que los dispositivos serie deben turnarse para enviar y recibir.

Algunas conexiones serie pueden implementarse con una sola línea entre un dispositivo de transmisión y un dispositivo de recepción. Por ejemplo, los LCD que tienen conexión serie son solo receptores, y realmente no tienen ningún tipo de información para devolver al dispositivo de control. Esto es lo que se conoce como comunicación serie simplex. Todo lo que necesita es un solo cable desde la transmisión del dispositivo maestro a la línea RX del que recibe.





Implementación de hardware

Hasta ahora fue una cobertura de la comunicación serie asíncrona desde un lado conceptual. Sabemos qué cables necesitamos, pero, ¿cómo se implementa realmente la comunicación en serie a nivel de señal? En una variedad de formas, en realidad. Hay todo tipo de estándares para la comunicación en serie. Veamos algunas de las implementaciones de hardware más populares de serie: nivel lógico o TTL, y RS-232.

Cuando los microcontroladores y otros circuitos integrados de bajo nivel se comunican en serie, generalmente lo hacen a un nivel TTL (Transistor Transistor Logic = Lógica Transistor-Transistor). Las señales serie TTL están en el rango del voltaje que alimenta a un microcontrolador, generalmente de 0V a 3,3V, 0V o 5V. Una señal en el nivel VCC (3,3V, 5V, etc.) indica una línea inactiva, un bit de valor 1 o un bit de parada. Una señal de 0V (GND) representa un bit de inicio o un bit de datos de valor 0.

El protocolo RS-232, que se puede encontrar en algunas de las computadoras y periféricos más antiguos, es como una interfaz serie TTL puesta cabeza abajo. Las señales RS-232 generalmente oscilan entre -13V y 13V, aunque la especificación permite cualquier cosa desde +/- 3V a +/- 25V. En estas señales, un voltaje bajo (-5V, -13V, etc.) indica la línea inactiva, un bit de parada o un bit de datos de valor 1. Una señal RS-232 alta significa un bit de inicio o un bit de datos de valor 0. Eso es lo contrario del protocolo TTL.

Entre los dos estándares de señal en serie, el TTL es mucho más fácil de implementar en circuitos integrados. Sin embargo, los niveles de baja tensión son más susceptibles a sufrir pérdidas en las líneas de transmisión largas. El RS-232 o estándares más complejos —como RS-485— son más adecuados para transmisiones en serie de largo alcance.

Cuando conecte dos dispositivos serie juntos, es importante asegurarse de que coincidan los voltajes de su señal. No se puede conectar directamente un dispositivo serie TTL con una línea RS-232. Se deben adaptar esas señales.

Continuando, exploraremos la herramienta que usan los microcontroladores para convertir sus datos que se encuentran presentes en un bus paralelo desde y hacia una interfaz serial: se llama UART.

UARTs

La última pieza de este armado en serie es encontrar algo para crear los paquetes en serie y controlar las líneas de hardware físico. Esto se concreta con un módulo llamado UART (Universal Asynchronous Receiver/Transmiter = Receptor/Transmisor Asíncrono Universal).

Un receptor/transmisor asíncrono universal es un bloque de circuitos responsable de implementar la comunicación en serie. En esencia, este UART actúa como un intermediario entre las interfaces paralelas y seriales. En un extremo del UART hay un bus de ocho o más líneas de datos (más algunos pines de control), en el otro lado están los dos cables serie: RX y TX.

UART simplificado
UART
Los UART existen como circuitos integrados independientes, pero en la actualidad es más común que se encuentren dentro de los microcontroladores. Debemos consultar la hoja de datos de un microcontrolador para ver si tiene algún UART. Algunos no tienen, otros tienen uno, otros tienen varios. Por ejemplo, el Arduino UNO, basado en el «antiguo y fiel» ATmega328, tiene un solo UART, mientras que el Arduino Mega, construido sobre un ATmega2560, tiene cuatro UART.

Como lo indican las letras R y T en el acrónimo, los UART son responsables de enviar y recibir datos en serie. En el lado de transmisión, un UART debe crear el paquete de datos —agregando la sincronización y los bits de paridad— y enviar ese paquete por la línea TX con una sincronización precisa (de acuerdo con la velocidad de transmisión establecida). En el extremo de recepción, el UART tiene que muestrear la línea de RX a velocidades acordes con la velocidad de transmisión que se espera, seleccionar los bits de sincronización y entregar como resultado los datos.

UART interno

Los UART más avanzados pueden enviar los datos que reciben a un archivo de memoria de respaldo, llamado búfer, donde pueden permanecer hasta que el microcontrolador vaya a buscarlos. Los UART generalmente publicarán sus datos almacenados en un búfer con un sistema de “el primero que entra es el primero que sale” (First In First Out = FIFO). Los búfer pueden tener apenas unos pocos bits, o pueden ser de gran tamaño, como miles de bytes.

Diagrama de bloques de un UART con FIFO


UARTs de software

Si un microcontrolador no tiene un UART, o no tiene suficientes, se puede implementar la interfaz en serie en bits que son controlados directamente por el procesador. Este es el enfoque que tienen las bibliotecas de Arduino como SoftwareSerial. El uso de bits es intensivo en el procesador, y no suele ser tan preciso como un UART, pero funciona en caso de necesidad.

Errores comunes

Eso fue todo lo básico sobre la comunicación en serie. Podemos dejar señalados algunos errores comunes que un ingeniero, de cualquier nivel de experiencia, puede llegar a cometer:

RX a TX, / TX a RX

Parece bastante simple, pero es un error que algunos cometen un par de veces. Por mucho que desee que sus etiquetas coincidan, siempre asegúrese de cruzar las líneas RX y TX entre los dispositivos serie.

FTDI Basic programando un Pro Mini. Note que RX y TX están cruzados


Discrepancia en la velocidad de transmisión

Los valores de baudios son como claves en lenguajes de la comunicación en serie. Si dos dispositivos no están hablando a la misma velocidad, los datos pueden ser mal interpretados o completamente perdidos. Si todo lo que el dispositivo receptor ve en su línea de recepción está compuesta de caracteres extraños, llamados “basura” en el ambiente, verifique que coincidan las velocidades en baudios definidas en ambos extremos.

Datos transmitidos a 9600 bps, pero recibidos a 19200 bps. Desajuste de baudios = basura


Contención de transferencia en la línea

La comunicación en serie está diseñada para permitir que solo dos dispositivos se comuniquen a través de un bus en serie. Si más de un dispositivo está intentando transmitir en la misma línea serie, podría encontrarse con una contención de bus.

Por ejemplo, si está conectando un módulo GPS a su Arduino, puede conectar la línea de transmisión de ese módulo a la línea RX de Arduino. Pero ese pin Arduino RX ya está conectado al pin TX del convertidor de USB a serie (por ejemplo un chip FTDI) que se usa cada vez que se programa el Arduino, o se usa el Monitor Serie. Esto establece la situación potencial en la que tanto el módulo GPS como el chip FTDI intentan transmitir en la misma línea al mismo tiempo.

Ejemplo de contención de línea (o bus)

No es bueno que dos dispositivos intenten transmitir datos al mismo tiempo en la misma línea. En el mejor de los casos, ninguno de los dispositivos podrá enviar sus datos. En el peor de los casos, las líneas de transmisión de ambos dispositivos se volverán locas (aunque eso es raro y generalmente están protegidos contra esta situación).

Puede ser seguro conectar varios dispositivos receptores a un solo dispositivo de transmisión. Realmente no cabe dentro de las especificaciones, y probablemente esté mal visto por un ingeniero experimentado, pero funcionará. Por ejemplo, si conectamos un LCD serie a un Arduino, el método más sencillo puede ser conectar la línea RX del módulo LCD a la línea TX del Arduino. El TX de Arduino ya está conectado a la línea RX del programador USB, pero eso deja solo un dispositivo controlando la línea de transmisión.

Implementación segura pero dudosa de un transmisor y dos receptores

La distribución de una línea de transmisión de este tipo puede ser peligrosa desde la perspectiva del firmware, ya que no puede elegir qué dispositivo recibe cual transmisión. La pantalla LCD terminará recibiendo datos que no están destinados a ella, lo que podría ordenarle que pase a un estado desconocido.

Hay formas de implementarlo, usando un poco de hardware adicional, pero esto es tema para otro artículo.



Diseños de bases y accesorios para robots con impresora 3D

Soporte de motores, por zi3d
https://www.thingiverse.com/thing:750963
Enlaces para archivos de impresión
https://www.thingiverse.com/thing:750963/zip

Este soporte permite fijar los motores estándar de los kits más comunes con más firmeza, sin fijaciones que se rompen con facilidad, y sobre cualquier placa base del material que usted desee, sin necesidad de comprar las cortadas con láser.






DotBot por Dotbot-io
https://www.thingiverse.com/thing:1441937
Enlaces para archivos de impresión
https://www.thingiverse.com/thing:1441937/zip






Chassis para robot por metshein
https://www.thingiverse.com/thing:1011890
Enlaces para archivos de impresión
https://www.thingiverse.com/thing:1011890/zip






Chassis compacto por makerhacks
https://www.thingiverse.com/thing:2320298
Enlaces para los archivos (distintos modelos)
https://www.thingiverse.com/thing:2320298/zip


Montaje para motor con tacómetro por b2vn
https://www.thingiverse.com/thing:1473508
Archivos para impresión 3D
https://www.thingiverse.com/thing:1473508/zip


Montaje para motor, ruedas y orugas por edwardchew
https://www.thingiverse.com/thing:3228395
https://www.thingiverse.com/thing:3228359
Descargar todos los archivos para chassis y ruedas https://www.thingiverse.com/thing:3228395/zip
Descargar todos los archivos para orugas https://www.thingiverse.com/thing:3228359/zip






Chassis para robot por Malathar
https://www.thingiverse.com/thing:1316755
Enlaces de los archivos para impresión 3D
https://www.thingiverse.com/thing:1316755/zip


Seguidor de línea JJ1 por AndrewLinden
https://www.thingiverse.com/thing:2831729
Enlace para los archivos de impresión 3D
https://www.thingiverse.com/thing:2831729/zip

Es un chasis de robot para construir un robot seguidor de línea utilizando los motores amarillos de engranajes y un Arduino.

En lugar de los tres módulos de sensor de línea, también puede usar un conjunto de sensores de 8 canales.

El chasis tiene agujeros para esta placa de sensores también. Esta matriz tiene salida analógica y necesitas un Arduino Nano que posee pines adicionales A6 y A7 usar los 8 canales del sensor, que tiene salida analógica. También puede optar por agregar al Arduino uno un CD74HC4067, multiplexador de 16 canales.

Cuando use paquetes de batería LiPo sin protección, también debe usar un sensor de bateria Lipo con beeper como el de la imagen que sigue, o una protección similar.

Utilice un tornillo de cabeza redonda en uno de los orificios frontales. La parte frontal del robot se deslizará sobre ese tornillo.


Por supuesto, se pueden encontrar varios diseños más en el repositorio de diseños 3D https://www.thingiverse.com/



Sistema para estacionamiento de un auto y para evitar acercarse demasiado a otro vehículo

Utilizando sensores ultrasónicos, los autos modernos nos dan una útil ayuda en el momento de maniobrar, especialmente al estacionarlos en espacios limitado. Podemos hacer nuestro sistema detector con un Arduino UNO y unos pocos componentes de bajo costo


Cómo funciona el sensor ultrasónico HC-SR04

El sensor ultrasónico HC-SR04 nos permite medir distancias por medio de emisión y rebote de ultrasonidos. Para medir distancias con Arduino podemos hacerlo de diferentes maneras.

Por orden de costo, hay un sensor que mide con el rebote de un láser; luego un sensor de infrarrojos que utiliza el paralaje del regreso de un haz de luz para calcular la distancia; y por último el más barato, el sensor ultrasónico HC-SR04, muy utilizado con Arduino, que utiliza la velocidad de propagación del sonido para medir distancia.

Para que no sea molesto al oído humano, utiliza ultrasonido a una frecuencia de 40 kHz. Estas ondas sonoras tienen una frecuencia muy por encima del espectro audible por los seres humanos.
El sensor funciona como un sonar, por rebote de la onda. El emisor del HC-SR04 envía un tren de ondas ultrasónicas cuando se activa la señal de disparo (trigger). Este sonido se refleja contra el objeto y retorna. El receptor detecta el momento en que retorna la onda y lo indica en la salida eco (echo).

Midiendo el tiempo de viaje podemos calcular la distancia.

La velocidad del sonido en la atmósfera terrestre es de 343,2 m/s a 20° C de temperatura, con 50% de humedad y a nivel del mar. Si necesitamos una gran exactitud, podemos agregar al diseño sensores BMP180 o BMP280, que nos aportan datos de altitud y temperatura, e incluso agregar un medidor de humedad, y por supuesto aplicar una fórmula más compleja. Pero para este diseño no necesitamos tanta precisión.

La fórmula de la velocidad es:

velocidad = espacio/tiempo

De donde despejamos la variable espacio, que necesitamos conocer:

espacio = velocidad x tiempo

La velocidad es conocida: la del sonido. El tiempo lo obtenemos con el sensor ultrasónico. Con ambos datos, podemos calcular la incógnita: a qué distancia se encuentra un objeto.

El zumbador o buzzer

Para simular correctamente un medidor de distancia de un automóvil utilizamos un buzzer (zumbador) pasivo. No hay que confundirlo con el zumbador activo, que tiene un oscilador interno, y por lo tanto una frecuencia fija y polaridad en sus pines de conexión.

Este reproductor no tiene un rango tan amplio de emisión de sonido como el del oído humano, ni mucho menos, pero es suficiente para diferenciar la distancia con frecuencias diferentes dentro de lo que es capaz de emitir. Además de los pequeños (como el de la foto), que vienen incluidos en los kits de Arduino, hay otros con mayor diámetro de diafragma (por ejemplo en el desarme de viejos modems), que ofrecen más volumen y un rango de frecuencias más amplio.

Sistema de alerta con leds y zumbador

Si bien al maniobrar no estaremos mirando hacia un indicador, sino atentos a los tonos de aviso, agregaremos al diseño un sistema de alerta visual. Nos dará una indicación aún más efectiva de si estamos cerca o lejos de un obstáculo. Con tres leds (verde, amarillo y rojo) conseguimos determinar si estamos a distancia sin riesgo, acercándonos, o en zona de peligro. Pero se podría ampliar la indicación con más leds y más comparaciones en el programa.

Componentes:

Arduino UNO, protoboard, cables para conexiones, resistores de 330 Ω, led verde, led amarillo, led rojo, sensor ultrasónico Arduino (HC-SR04), buzzer




Circuito:

Los resistores son de 330 Ω y van en serie con los LEDs. El sensor ultrasónico se conecta a dos pines digitales, uno para el trigger o disparador y otro para el echo, o receptor. El buzzer se conecta a una salida PWM y a GND. La salida PWM entregará distintas frecuencias según la indicación del programa, por medio de la función tone().

Programando el detector de distancia

Diagrama del programa

Los umbrales para la decisión se fijan como constantes, uno para cada situación. Podemos medir la distancia con una regla y determinarlos.

■ UmbralAlejado: está en zona verde desde 50 cm a 30 cm.
■ UmbralMedio: está en zona amarilla, desde 30 cm a 10 cm.
■ UmbralCerca: está en zona roja, menos de 10 cm.

Estos umbrales no son definitivos: se pueden cambiar a gusto del usuario.

El programa debe analizar la medición dividida en 4 zonas: fuera de rango (más de 50 cm, ninguna indicación), entre 50 cm y 30 cm (zona verde), entre 30 cm y 10 cm (zona amarilla), entre 10 cm e impacto (zona roja).

■ Luego de medir la distancia se la compara con el umbral que indica fuera de rango (50 cm).
■ Si la distancia es menor a ese valor está en zona verde: se enciende el led verde y emite el tono de 2000 c/s.
■ Si la distancia es menor a 30 cm y mayor a 10 cm está en zona amarilla: enciende el led amarillo y emite el tono de 2500 c/s.
■ Si la distancia es menor a 10 cm está en zona roja: enciende el led rojo y emite el tono de 3000 c/s.

Programa

Para esta determinación de rangos, es importante buscar en la hoja de especificaciones técnicas el rango de funcionamiento del sensor de ultrasonidos que disponemos. Para este artículo se usó uno que puede medir de 2 cm a 400 cm.

Artículos relacionados:

VL53L0X: Sensor de distancia que mide por la velocidad de la luz (Time-of-Fly)

Dando a los vehículos autónomos una “visión eléctrica” más aguda

Módulo de emisor piezoeléctrico pasivo KY-006 (Kit de sensores Keyes 6)

RCWL-0516: Módulo sensor de movimiento de microondas con radar Doppler



Ampliar la cantidad de entradas de Arduino

Para expandir la capacidad de entradas digitales se utilizan registros de desplazamiento (Shift Register en inglés) con entradas en paralelo y salida serie.

Para este ejemplo, utilizamos tres pines digitales de la placa Arduino en conjunto con el circuito integrado 74HC165 (puede ser, también, 74LS165), que nos aportará 8 entradas.

Diagrama de pines:

Se pueden conectar varios de estos chips en cadena, lo que le nos aporta 16, 24, 32 o más entradas, sin usar ningún pin digital adicional de Arduino, simplemente conectando la salida QH de un registro a la entrada de datos serie SER del otro.

En el diagrama que sigue se ve cómo es la conexión completa de dos 74HC165. Los conjuntos de llaves de corredera, llamados DIP Switch en inglés, representan a las diversas entradas que se podrían ingresar. Si son llaves que se cierran (pulsadores, microswitches, relés, salidas de colector abierto), corresponde el circuito tal como se lo ve, con un resistor de polarización (pull-up) conectado a +5V. Si se trata de salidas digitales de otros chips y placas con salidas compatible con lógica TTL, no es necesario colocar el resistor.

Con línea de puntos se indica la conexión para continuar la cadena indefinidamente. La señal CLK (pata 2) va unida entre chips, e igual la señal SH/LD (pata 1), con la única salvedad de que hay que leer la hoja de datos del microcontrolador (según cuál sea) para saber cuántas entradas de este tipo de chip TTL HC se le pueden conectar a una salida digital de Arduino.

La tabla que sigue, y el diagrama interno del chip, los agrego para ofrecer más información y mejor comprensión del funcionamiento. Se pueden encontrar más detalles en su hoja de datos.

Diagrama de tiempo

La señal SH/LD se mantiene en ALTO durante las operaciones de desplazamiento. Un pulso a BAJO en este pin ingresa nuevos datos desde las entradas al registro de desplazamiento. Cuando el pulso vuelve a ALTO, queda todo dispuesto para aplicar pulsos de CLK y desplazar uno a uno los bits del registro hacia la salida serie QH. Si hemos usado un solo chip 74HC165, con 8 pulsos se habrán leído todas las entradas a través de QH (luego de haberlo conectado a una entrada digital del Arduino). Cada chip adicional requiere 8 pulsos más. En los programas se puede entender claramente cómo se ingresan los datos a variables dentro de nuestro microcontrolador.

Leer una de las entradas del 74HC165 – Diseño del programa:

■ Se aplica un pulso de alto a bajo y luego de regreso a alto en SH/LD, y así las entradas ingresan al registro de desplazamiento (condición “LOAD”, o de carga).

■ Aplicar a la salida CLK la cantidad de pulsos necesarios, desplazando los datos, para que el bit que deseamos leer quede ubicado en la línea de salida QH.

■ Leer el valor del pin digital de entrada del Arduino.

Primer programa de prueba

Este programa lee de a un pin e indica su estado en el LED incluido en el Arduino UNO, pin 13 = LED_BUILTIN. Para determinar qué entrada queremos leer para conocer su estado, se lo indicamos tipeando los números 1 a 8 desde el teclado de la computadora a la que esté conectado el Arduino por USB.

Incluso, usando comparaciones con IF se podría elegir como comando cualquier caracter. Puede ser “a”, “b”, “c”, o “A”, “B”, “C”, o lo que usted elija. Si la entrada proviene de sensores de puertas o ventanas abiertas, o de luces encendidas, se puede usar, por ejemplo, “C” para cocina, “B” para baño, “P” para pasillo, “p” para patio, “E” para entrada, “H” para una habitación y “h” para otra habitación. Y así. Además, estas letras de comando se pueden enviar a través de un módulo Bluetooth HC-06 o HC-05 y controlar desde el teléfono celular, recibiendo la respuesta por el mismo medio.

En este programa —para simplificar— se eligió tipear un número desde el teclado para leer cada entrada. Lo más interesante es la función que lee las entradas y las desplaza hacia la salida. Se le envía como parámetro un valor numérico y entero de 1 a 8, y devuelve un 1 o un 0 según el estado de la entrada. No es difícil ampliar el código hasta la cantidad de entradas que desee.

Agregando esta función a su programa, puede usarla del modo que usted quiera.

Utilizamos este circuito, que es el mismo que servirá para todos los programas excepto el de manejo por SPI, que requiere conectar dos señales del circuito a las entradas MOSI y SCLK de esta interfaz, como luego veremos.

Disculpen si tiene un aspecto un poco antiestético, pero ocurre que es difícil cablear un conjunto de llavecitas DIP al chip 74HC165 con el programa de dibujo sin hacer cruces de cables, y que sea todo visible. Ya verán en la foto que el circuito real, en la protoboard, quedó más prolijo.

Programa para leer de a una entrada

 


 
Segundo ejemplo: ingresar todas las entradas a variables

El siguiente programa permite listar en el Monitor Serie el estado de los pines de entrada del circuito del ejemplo, o de una cadena de chips para ampliar 16, 24, 32 o más entradas. Tampoco necesita biblioteca. El listado se actualiza cada vez que cambia una entrada. Los comentarios explican en detalle su funcionamiento.

El Monitor Serie mostrará este mensaje, y se renovará cada vez que se cambie el valor de una entrada.


 


 
Biblioteca ShiftIn

Esta es una biblioteca que permite leer 8 o más entradas. Y también, si bien la biblioteca tiene una función que define 4 pines, se pueden usar sólo 3 pines al Arduino. Además, se puede conectar en cadena varios registros de desplazamiento utilizando la misma cantidad de pines digitales, o sea 3. El cableado es con la misma configuración que en el diagrama de protoboard mostrado arriba.

Instalación fácil (importar zip)

La forma más fácil de instalar esta biblioteca es descargar la última versión y luego importarla. No tiene que descomprimirlo. Simplemente abra su IDE de Arduino y navegue a Programa > Incluir Librería > Añadir Biblioteca .ZIP… y luego seleccione el archivo zip, que puede bajar desde aquí.

Instalación manual

Por supuesto también se puede instalar esta biblioteca manualmente. Para hacerlo, descargue la versión más reciente y descomprímala. Luego tiene que copiar la carpeta ShiftIn (NO la carpeta ShiftIn-x.y.z) y colocarla en la carpeta de la biblioteca Arduino:

Windows: Documentos\Arduino\libraries\
Mac and Linux: Documents/Arduino/libraries/

Después de esto solo hay que reiniciar el IDE de Arduino.

Uso de ShiftIn

Si ha instalado esta biblioteca, puede incluirla navegando a Programa > Incluir Librería > ShiftIn. Esto agregará la línea #include <ShiftIn.h> a su programa (por supuesto, también puede escribir esta línea manualmente).

Ahora se puede usar esta biblioteca:

Los datos en el Monitor Serie se verán así:

Si usted necesita usar dos shift registers, sólo tiene que cambiar la declaración de ShiftIn<1> shift; a ShiftIn<2> shift;, y así sucesivamente.

El diagrama para 2 chips – 16 entradas es este:

Detalle de las funciones de la biblioteca ShiftIn

Dependiendo de la cantidad de chips, esta biblioteca utilizará diferentes tipos de datos. Si solo está utilizando un chip, el tipo ShiftType será un unsigned byte (uint8_t). Para dos chips será un unsigned int (uint16_t). Para tres o cuatro chips será un unsigned long (uint32_t) y para 5 a 8 chips será un unsigned long long (uint64_t). La biblioteca todavía no maneja más de ocho chips.

Esta función debe ser llamada en la función de configuración. Se utiliza para indicar a la biblioteca los pines que debe usar.

void begin(int ploadPin, int clockEnablePin, int dataPin, int clockPin)

GetPulseWidth() define el retardo para el pin de clock en microsegundos. Este valor está fijado en 5 us y en general no habrá necesidad de cambiarlo, aunque teniendo en cuenta el tiempo de programa transcurrido entre la ejecución de el inicio del pulso y de su final, puede ser tan pequeño como 1 us, incluso 0.

uint8_t getPulseWidth()
void setPulseWidth(uint8_t value)

Retorna la cantidad de entradas (bits en el estado)
uint16_t getDataWidth()

Retornan VERDADERO si ha cambiado alguna entrada durante la última lectura.
boolean hasChanged()
boolean hasChanged(int i) // lo mismo de arriba, pero solo para la entrada i

Retornan el estado completo del actual y el último grupo de bits
ShiftType getCurrent()
ShiftType getLast()

Retornan el estado de una sola entrada en el grupo actual de bits y el último grupo de bits
boolean state(int i)
boolean last(int i)

Indica cuando una entrada ha cambiado. En el ejemplo de los esquemas, se ha presionado o se ha soltado un pulsador
boolean pressed(int id) // no estaba presionado en la última lectura, pero ahora sí
boolean released(int id) // estaba presionado en la última lectura, pero ahora fue liberado

Esta función (la función para actualizar) debe ser llamada una vez por cada grupo de bits. Leerá todos los valores de los shift registers y retornará el nuevo estado.
ShiftType read()

Esta función es básicamente la misma que la función read, pero retorna VERDADERO si ha cambiado de estado alguna entrada, y FALSO en el caso contrario
boolean update()
 


 
Ingresando datos por SPI

Conectando el 74HC165 a la interfaz SPI se puede leer rápidamente 8 entradas digitales, ingresando los 8 bits en una sola instrucción de SPI. Se los puede encadenar para leer 16, 24, 32 o más entradas a la vez.

Podría usarse, por ejemplo, para examinar la configuración de un interruptor DIP de 8 interruptores (donde se fijaría la configuración del dispositivo).

En el 74HC165 se tiene que pulsar el pin de «cargar» (pin 1 del chip) para que el registro ingrese las entradas externas en sus registros internos.

La habilitación del chip, en esta prueba, es fija. El pin de activación de chip (/CLK INH) está a tierra, ya que el chip también puede funcionar estando siempre habilitado. Tenga en cuenta que la línea MISO siempre está activa, por lo que no es posible compartir este chip con otros dispositivos SPI utilizando el hardware SPI. Se puede solucionar agregando un circuito selector, pero no lo describiré en este artículo ya que si necesita usar otro dispositivo SPI, puede utilizar los otros ejemplos de programa, sin necesidad de SPI.

Código de programa

Es fácil de leer desde el registro. La biblioteca SPI se ocupará de todo.

Los pasos importantes son (dentro de la función de bucle):

1. Aplique un pulse al pin de carga paralela para cargar el registro desde las entradas.
2. Haga una transferencia SPI para leer el registro del chip.

Si desea leer más de 8 interruptores, simplemente use más registros, conecte en paralelo los pines 1, 2 y 15 de los chips, y la salida de cada chip «anterior» en la secuencia (QH) a la entrada del siguiente (SER).

Para leer cuatro bancos de interruptores, se cambia la sección de lectura del programa:

digitalWrite(LATCH, LOW);
digitalWrite(LATCH, HIGH);
bancoEntradas1 = SPI.transfer(0);
bancoEntradas2 = SPI.transfer(0);
bancoEntradas3 = SPI.transfer(0);
bancoEntradas4 = SPI.transfer(0);

NOTA: OBSERVE QUE HAY QUE CAMBIAR, EN EL DIAGRAMA DEL PROTOBOARD DE ARRIBA, LOS PINES QUE IBAN A SALIDA DIGITAL 11 Y SALIDA DIGITAL 12 DEL ARDUINO. LA CONEXIÓN QUE ESTABA EN 12 SE DEBE PASAR A 13, Y LA QUE ESTABA EN 11 SE DEBE PASAR A 12.

Resultados en Monitor Serie. Muestra una indicación del estado al inicio, y luego lista cada cambio que se produce en las entradas:


 


 
Otras opciones

Por último, existen dos librerías relacionadas, llamadas bitBangedSPI y bitBangedSPIfast, que permiten operar las múltiples entradas desde 74HC165 con un SPI implementado por software, y dejar libre el módulo SPI de hardware para otros dispositivos. Entiendo que es lo que hicimos con los programas de ejemplo anteriores, pero les dejo la inquietud de investigarlos y probarlos.


Arduino: ampliar cantidad de salidas digitales con 74HC595

A veces un Arduino queda corto de pines, y se nos presenta la necesidad de ampliar la cantidad de salidas digitales. La manera más usual es con un registro de desplazamiento (Shift Register, en inglés), que convierte los datos en serie en salidas paralelas. Esto será de utilidad en aquellas placas como Arduino UNO, Nano, Micro, etc, que a veces resultan un poco limitados en este sentido.

El chip 74HC595 —para algunos un misterioso integrado de 16 patas que viene incluido en muchos kits de inicio para Arduino— tiene una ventaja esencial ante otros chips del mismo tipo: tiene un registro que mantiene el dato en los pines de salida sin variación mientras se desplazan los datos dentro del chip.

Adicionalmente, tiene la posibilidad de desconectar las salidas de este registro de los pines de salida del chip, por medio de la entrada de control OE (Ouput Enable = Habilitación de Salidas), dejándolos en un estado de alta impedancia, o tercer estado. No usaremos esta opción aquí, pero en futuros artículos veremos la importancia de esta posibilidad.

Otro chip opcional para este uso, aunque de 16 bits y también con registro de salida, es el circuito integrado 74LS673, pero es más difícil de encontrar en el mercado.

Al utilizar el circuito integrado 74HC595, ocupamos solamente 3 salidas digitales en la placa Arduino, pero obtenemos 8 salidas digitales adicionales. Este 3 x 8 en pines no parece una gran mejora (ganamos 5 salidas), pero si se agregan más chips, la ampliación puede llegar a ser importante.

Poniendo más chips conectados en serie se pueden obtener otras 8 salidas más por cada chip agregado, y la cantidad de pines ocupados en el Arduino sigue igual: solamente tres. Con tres chips tendremos 24 salidas, con 8 chips tendremos 64, y con 32 chips tendremos una ampliación de 256 nuevas salidas.

Para calcular la cantidad de salidas que obtendremos, hay que multiplicar la cantidad de chips por 8.

En teoría, se puede poner una cantidad indefinida de chips en serie y obtener centenares de salidas adicionales. Sólo se debe tener en cuenta que los datos no se desplazan instantáneamente, debido a los tiempos de programa. Supongamos una cantidad de 32 bytes a poner en las salidas de 32 chips —256 bits—. Colocar todos esos datos en los registros de salida de 32 chips 74HC595 implica un tiempo que puede ser sustancial y prohibitivo para algunas aplicaciones que requieren salidas con variaciones rápidas, sin que importe si se cambia un único bit en las salidas, o los 256 bits juntos. Para aplicaciones sin tiempos críticos, como encendido de leds, artefactos a través de relés, displays de segmentos o control de motores, no existe ningún problema de tiempos.

La mayoría de los chips de registro de desplazamiento pueden manejarse elevadas frecuencias en MHz para el desplazamiento, todos superan la máxima velocidad de envío de datos en serie de un Atmega328P, ya que para hacerlo debemos usar una secuencia de instrucciones de programa. Algunas hojas de datos nos muestran frecuencias de desplazamiento de 100 MHz, 36 MHz, y similares. Un Arduino estándar, con cristal de 16 MHz, y aún más teniendo que usar una secuencia de instrucciones para enviar cada bit, no superará nunca esas frecuencias para el desplazamiento de los datos. De modo que no se nos presentarán problemas de límite de velocidad al usar estos chips.




Registro de desplazamiento 74HC595


Descripción de pines:

Las salidas son Q0 a Q7 (pata 15, y de 1 a 7), y las tres entradas que van conectadas a las salidas de la placa Arduino son DS = entrada de datos (14), SCTP, para ingresar un pulso que deja fijos los datos en el registro de salida (12), y SHCP, que es el pulso de reloj, o clock, que hace desplazar los datos en el registro de desplazamiento (11).

Estas son las señales más importantes de comprender y profundizar.

Luego está la entrada de voltaje de 5V (16), la conexión a tierra (8), y Q7S (9), la salida que se utiliza para continuar la conexión de más chips en serie.

La hoja de datos (datasheet) permite ver con más detalle los datos del chip.

Por la entrada de reloj SHCP se ingresan pulsos que indican el tiempo preciso en que debe ocurrir el ingreso de bits por la entrada DS, y el desplazamiento en el registro.

La entrada de datos es DS.

Y la señal SCTP es un pulso que traspasa los datos del registro de desplazamiento al de salida, y de allí a las salidas digitales.

Las línea SHCP es la señal de reloj. La segunda línea, DS, es la secuencia de datos que queremos hacer llegar a las salidas Q1-Q7.

Con el pulso de reloj el registro de desplazamiento del 74HC595 desplaza los que entraron anteriormente hacia el interior del registro e ingresa el valor que hayamos puesto en el pin de Arduino que está conectado a su entrada DS. Este bit es parte de la secuencia de datos de 8 bits (o sea que este suceso ocurrirá 8 veces).

Para el primer pulso el bit 0, para el segundo pulso el bit 1, y así sucesivamente hasta completar los 8 bits de un byte.

En ese momento los datos del registro de desplazamiento aún no estarán en las salidas, es necesario que la señal STCP reciba un pulso. Cuando STCP sube de nivel bajo a nivel alto, los datos que tenemos en el registro de desplazamiento pasan a estar disponibles en las salidas Q0 – Q7.

En el ejemplo del gráfico de tiempos de arriba, estamos poniendo a nivel ALTO (HIGH) el bit que aparecerá en Q7, y en nivel BAJO (LOW) el resto.

El manejo de las líneas de Arduino

En principio y para mejor comprensión deberíamos dar una mirada a la función shiftOut(). Esta función se ocupará de ir poniendo de a un bit por vez en la salida del Arduino hasta completar los 8 bits del byte que vamos a transferir.

La función shiftOut()

Sintaxis: shiftOut (pinDato, pinClock, ordenBits, valor)

Desplaza un byte de datos (llamado valor) de a un bit por vez hacia el pin indicado en pinDato. Según lo que se indique en el parámetro ordenBits de la función, el desplazamiento comienza desde el bit más significativo (es decir, el que se ubica más a la izquierda en un byte, en la representación estándar) o el menos significativo (más a la derecha). Cada bit se escribe hacia un pin de datos (pinDato), y después se genera un pulso en el pin de reloj en pinClock (alto, luego bajo), lo que indica que el bit está disponible.

Nota: hay que asegurarse que el pin de reloj (pinClock) esté preparado en valor BAJO antes de la llamada a shiftOut(). Por ejemplo, con una llamada a digitalWrite(pinClock, LOW).

Esta es una implementación que utiliza software. Veremos también más adelante la forma de usar la biblioteca SPI, que provee una implementación por hardware más rápida, aunque debemos recordar que solo funciona en los pines definidos para esta interfaz.

Parámetros de la función shiftOut():

pinDato: el pin en el que se coloca cada bit
pinClock: el pin para producir el pulso una vez que se haya establecido el valor correcto en pinDato
ordenBits: indica en qué orden se desplazarán los bits hacia el pin de salida; ya sea MSBFIRST o LSBFIRST (el bit más significativo primero, o el bit menos significativo primero)
valor: los datos a desplazar. (formato byte)

Circuito de ejemplo:

AMPLIAR EL DIAGRAMA

Código de ejemplo:

Supongamos que deseamos poner en los pines de salida un byte con el valor B10101010, o sea así:

Más programas de ejemplo:

El envío de datos en una función propia

El programa anterior repite varias veces un código idéntico para el envío del dato. Es la opción perfecta para convertir esta parte repetida del código en una función propia. Además de reducir la longitud de comandos del programa y hacerlo mucho más legible, creamos una función que nos servirá para cualquier otro programa que envíe dato a un integrado 74HC55. El funcionamiento del envío de datos en este programa a continuación produce exactamente la misma secuencia y funcionamiento del programa.

Diagrama para salida de 16 bits con dos 74HC595

No hay diferencia importante entre los circuitos de cada chip, se ven idénticos; el único cambio es de dónde recibe la información de entrada en DS cada uno: el primero desde la salida digital 11 del Arduino, el segundo desde la salida Q7S del primero. Y así se podría continuar la cadena, agregando de a 8 bits a las salidas. Como se puede observar en el diagrama, las señales de control y clock, STCP y SHCP, de los pines 11 y 12 de los 74HC595, se repiten en paralelo en ambos chips, y así continuaría en toda la cadena si se agregasen más salidas, como se puede ver en el diagrama mostrado más arriba con 4 chips 74HC395.

Programa de ejemplo para 16 bits:

En próximas notas veremos estos circuitos controlados por la biblioteca SPI, en otra el uso del chip serie a paralelo 74LS673 para obtener 16 salidas y en otra nota veremos el uso de un chip paralelo a serie 74HC165 para obtener una ampliación de 8 entradas.


ARTÍCULOS RELACIONADOS:

Arduino: Entradas y salidas – Manipulación de puertos
Ingresar lectura de varios sensores a través de un único pin analógico
Arduino UNO R3 – Conectándolo al mundo exterior