Archivo por meses: diciembre 2019

Arduino: Usando la función millis() en lugar de delay()

El código que sigue es un típico ejemplo de escritura a través de la comunicación serie de Arduino. Escribe “Hola” a través del puerto COM serie (visible con el Monitor Serie de Arduino, en la pestaña Herramientas), y espera durante 1000 milisegundos (1 segundo) al final de cada iteración del bucle.

La función delay() es muy fácil de usar para crear esperas, pero tiene un inconveniente: deja al microcontrolador «atrapado» dentro de la ejecución de esta función durante el tiempo que se ha indicado. Si hubiese un cambio en un pin que debería detectar, o si llegase información a través de cualquiera de las comunicaciones posibles (serie, I2C o SPI) el microcontrolador sólo se enteraría luego de completarse el retardo.

Una solución es crear un retardo que no deje insensible al sistema durante un tiempo tan extenso.

La función millis()

millis() devuelve el número de milisegundos desde que la placa Arduino empezó a ejecutar, luego de un reinicio o el encendido. Este número se desbordará (volverá a cero), después de aproximadamente 50 días.

Retorna la cantidad de milisegundos en un valor long sin signo (unsigned long).

Nota: Tenga en cuenta que como el valor de retorno para millis() es un long sin signo (unsigned long), pueden producirse errores lógicos si un programador intenta hacer operaciones aritméticas con tipos de datos más pequeños, como de tipo int. Incluso con los long con signo se pueden producir errores ya que su valor máximo es la mitad que la de su contraparte sin signo.




Ejemplo de texto «Hola» utilizando la función millis()

Hacerlo de esta manera solo tiene sentido como ejemplo, ya que es evidente que en este caso directamente se puede usar una función delay(1000). Pero de todos modos la diferencia entre este ejemplo y el código que usa la función delay(1000) es que el ciclo del código que usa la función millis() se ejecutará una vez por segundo con la máxima precisión posible. El bucle en un código con delay(1000) se ejecutará en algo más de tiempo, ya que se produce un retardo al ejecutar Serial.println(«Hola»). Ocurrirá igual con cualquier otra serie de instrucciones que se incluyan dentro del bucle.

¿Por qué usar millis() en lugar de delay()?

Presentaré dos ventajas al utilizar millis() para crear retardos, en comparación con el uso habitual de delay().

1. Cronometraje preciso

La primera ventaja que discutiremos es la exactitud en el tiempo.

Con millis() podemos garantizar que el bucle se ejecute tantas veces como queramos dentro del retardo sin afectar su extensión, independientemente del tiempo de ejecución (obviamente, siempre que el tiempo de ejecución de todas las instrucciones sea menor al retardo deseado).

Con delay() esto no es posible, ya que no sabemos cuánto tiempo durará el tiempo de ejecución de todas las instrucciones de programa que están dentro del ciclo.

Una sincronización precisa como esta es muy útil cuando se muestrea a una cierta frecuencia, o cuando se utilizan filtros, entre otras cosas.

2. Sin bloqueo

La ventaja principal de la función millis() es que no nos impide ejecutar otro código mientras estamos «esperando».

Ejemplo: digamos que queremos imprimir «Hola» en el puerto serie una vez por segundo mientras hacemos otras cosas. Esto no es posible con delay(), ya que entrar a la función delay() pausa todo el código.

Aquí hay una manera de hacer esto:

Este fragmento de código es bastante similar al primer ejemplo que mostramos, excepto que este no bloquea el resto del programa mientras no se está imprimiendo hacia la línea serie.

3. Un simple secuenciador

Vamos a escribir un ejemplo simple en el que creamos un planificador que imprime ciertos trozos de texto a través de la línea serie a diferentes intervalos.

Así es como se ven los primeros 60 segundos en el Monitor Serie:

Esta es una manera agradable y fácil de sincronizar las ejecuciones en su código. También se puede ejecutar otras partes de código simultáneamente.

4. Una nueva función delay()

La función delay() estándar podemos reemplazarla por una implementada con la función millis(). Si bien parece que es lo mismo, ya veremos a continuación qué ventaja nos puede ofrecer su estructura de programa:

Además de esperar el tiempo indicado, esta función monitorea un pin de entrada del Arduino que haya sido cableado para detectar que ha sucedido algún evento externo. Si esa señal va a nivel BAJO (LOW), se interrumpe el retardo.

Para conectar varias entradas capaces de interrumpir el ciclo de retardo, se pueden agregar más elementos en la comparación de cierre del while, por ejemplo

while (Contador<=millis() && digitalRead(12)==HIGH) && digitalRead(11)==HIGH);

O se puede conectar a la entrada por el pin 12 (u otro pin elegido) un circuito como el que sigue, un AND realizado con lógica de diodos de señal (1N914 o 1N4148), que tiene la ventaja de que se puede ampliar indefinidamente. También se puede implementar con un circuito integrado compuerta AND.

Nota: quede claro que el circuito se representa con pulsadores, pero cada una de estas entradas puede ser un microswith, los contactos de un relé, o cualquier otro sensor que cierre circuito hacia GND (tierra o común).

Función micros() y desbordamiento

Al igual que delay() tiene una versión en microsegundos llamada delayMicroseconds(), la función millis() tiene como compañera para tiempos breves la función micros(). Si necesitamos una mejor resolución, micros() puede ser el camino a seguir. Sin embargo, tenga en cuenta que el valor devuelto por micros() se desbordará (volverá a cero) después de aproximadamente 70 minutos, en comparación con los 50 días de millis(). “Desbordamiento” significa que el conteo llega a su máximo, y entonces los valores de retorno de la función recomienzan desde cero.

Resumen

millis() y micros() son funciones realmente útiles para usar en tareas relacionadas con el tiempo. La opción inicial y típica de un programador de Arduino es usar delay(), que no siempre funcionará tan bien, principalmente cuando se programan muchas funciones que tienen que ver con el tiempo y existen eventos que no se pueden perder.




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

El VL53L0X es un producto novedoso basado en el sistema FlightSense de la empresa ST Microelectronics. Es una tecnología innovadora que permite medir distancia con independencia de la reflectividad del objetivo.

En lugar de calcular la distancia midiendo la cantidad de luz reflejada desde el objeto (en lo que influye significativamente el color y tipo de superficie), el VL53L0X mide con precisión el tiempo que tarda la luz en viajar desde el objeto más cercano y volver reflejada hasta el sensor (un proceso llamado Time-of-Fly, o Tiempo de vuelo).

Debido a que utiliza una fuente de luz con un haz muy estrecho, es bueno para determinar la distancia de solamente la superficie que está directamente delante. A diferencia de los sonares ultrasónicos que hacen rebotar sus ondas de sonido, en este caso el «cono» de la detección es muy estrecho. A diferencia de los sensores de distancia IR que intentan medir la cantidad de luz que regresa, el VL53L0x es mucho más preciso y no tiene problemas de linealidad o «imágenes dobles», en las que no se puede saber si un objeto está muy lejos o muy cerca.

Puede medir distancia con un alcance de hasta 2 m.

El control del procesador y la lectura de los resultados se realizan por medio de una interfaz I2C.

Características clave

  • Emisor infrarrojo: 940 nm
  • Distancia: hasta 2000 mm
  • Dirección I2C: Programable
  • Fuente de luz VCSEL (Vertical-cavity surface-emitting laser = Láser de emisión de superficie de cavidad vertical)
  • Sensor de rango con avanzado microcontrolador
  • El chip mide sólo 4,4 x 2,4 x 1,0 mm
  • Medición de distancia rápida y precisa
  • Mide rango absoluto hasta 2 m.
  • El rango reportado es independiente de la reflectividad del objetivo
  • Compensación óptica cruzada integrada avanzada para simplificar la selección del vidrio de cobertura
  • Seguro para el ojo humano
  • Dispositivo láser de clase 1 que cumple con la última norma IEC 60825-1: 2014 – 3ª edición
  • Fácil integración por el sistema de montaje de soldadura del chip
  • No tiene óptica adicional
  • Fuente de alimentación individual
  • Regulador de voltaje integrado en la plaqueta
  • Interfaz I2C para control de dispositivos y transferencia de datos
  • Pines de entrada salida de uso general Xshutdown (para reinicio) e Interrupt (interrupción)
  • Dirección I2C programable

Conexión con Arduino

  • VCC (en algunos fabricantes VIN) es la fuente de alimentación, el módulo acepta de 3 a 5V de alimentación. Use el mismo voltaje en el que se basa la lógica del microcontrolador. Para la mayoría de los Arduinos es 5V.
  • Conecte GND a tierra/alimentación común (marcado también GND en el Arduino).
  • Conecte el pin SCL al pin SCL (señal de reloj I2C en su Arduino. En un Arduino UNO también se conoce como pin A5, aunque está disponible del lado de los pines digitales. En un Mega es el digital 21 y en un Leonardo es el digital 3.
  • Conecte el pin SDA al pin SDA (datos I2C) en su Arduino. En un Arduino UNO también se conoce como pin A4, en un Mega es el digital 20 y en un Leonardo es el digital 2.

Los pines adicionales son:

GPIO1: este es un pin que usa el sensor para indicar que están listos los datos. Es útil para cuando se realiza una detección continua. Tenga en cuenta que no hay ajuste de nivel en este pin, es posible que no se pueda leer el voltaje de nivel lógico de 2,8V en un microcontrolador de 5V (podríamos en un Arduino UNO, pero no es seguro). La biblioteca de Adafruit no hace uso de este pin, pero está ahí para usuarios avanzados.

XSHUT – es el pin de apagado/reinicio para el sensor. Por defecto es alto. Hay un diodo de cambio de nivel para que se pueda usar la lógica de 3,3 – 5 V en este pin. Cuando el pin va a nivel bajo, el sensor entra en modo de apagado.




Abra el IDE de Arduino. Mantenga siempre actualizado a la última versión.

Abra en el menú HERRAMIENTAS la opción ADMINISTRAR BIBLIOTECAS.

Búsqueda y carga en el IDE Arduino de la biblioteca del VL53L0X

La elección ADMINISTRAR BIBLIOTECAS abrirá la siguiente ventana del Gestor de Bibliotecas:

En esa ventana tenemos, en la parte superior derecha una ventana de editor con la leyenda «Filtre su búsqueda…«, donde debemos escribir el nombre del dispositivo:

Esta búsqueda nos ofrece varias bibliotecas. Para Arduino UNO y relacionados tenemos la de Adafruit y la de Pololu. En artículos en la web recomiendan la de Pololu, porque es más simple que la del otro fabricante. De todos modos, podemos instalar ambas. No hay conflictos en esto. El botón que dice «Instalar» aparece cuando se coloca el puntero del mouse en la biblioteca elegida. Si no aparece, es porque ya está instalada. Si no fuese así, recurra a el enlace «More info» y descargue la biblioteca desde el sitio GitHub, en formato ZIP, y proceda a instalarla con las instrucciones que ofrecen AQUÍ.

El gestor nos indicará que la biblioteca está lista con un cartel remarcado «INSTALLED».

Las bibliotecas quedan listas para ser utilizadas. La que corresponde a Pololu se llama VL53L0X, mientras que la de Adafruit se llama igual y está dentro de todas las bibliotecas de este fabricante, que llevan su nombre comercial como prefijo.

Dirección para el bus I2C

La dirección por defecto de I2C es 0x29, pero recuerde que es posible programar esta dirección en el VL53L0X. Con la biblioteca Adafruit, hay dos maneras de establecer la nueva dirección. Durante la inicialización, en lugar de llamar a lox.begin(), se llama a lox.begin(0x30) para establecer la dirección en 0x30. O se puede, más adelante, llamar a lox.setAddress(0x30) en cualquier momento. Es importante realizar esta operación con una sola placa VL53L0X conectada al bus I2C, o todas quedarán cambiadas.

Programas de prueba

«Continuous», de Pololu
(Este ejemplo muestra cómo usar el «modo continuo» para tomar mediciones de distancia con el VL53L0X. La información se muestra en la pantalla emergente del Monitor Serie, que debe estar fijado en 9600 baudios.)

Y el que sigue es un ejemplo con la biblioteca de Adafruit, con los comentarios traducidos. Siempre con la misma conexión del diagrama de arriba.

En el programa que sigue, para reducir el ruido de la medición se muestra el promedio de varias medidas. Las líneas comentadas muestran los distintos modos de funcionamiento.



Auxiliares para control y digitalización de señales analógicas

Muchas de las señales que ingresan a un sistema digital, que provienen del mundo real y que por eso en pocas ocasiones se pueden considerar «binarias» (digital «0 y 1», «Sí y No», «valor» o «no valor»), son en su mayoría lecturas analógicas.

Si bien los microcontroladores incluyen entradas para señales analógicas, a veces no alcanza la precisión de lectura que poseen, o no alcanza la cantidad de entradas disponibles, y para esto necesitamos elementos auxiliares que nos ayuden a direccionarlas y leerlas, como los que presento aquí.

Convertidor analógico a digital ADS1115

Para los microcontroladores sin convertidor analógico a digital o cuando se quiere un ADC de mayor precisión, el ADS1115 proporciona una precisión de 16 bits a 860 muestras/segundo sobre I2C. El chip se puede configurar como 4 canales de entrada de un solo extremo, o dos canales diferenciales. Como una buena ventaja, incluso incluye un amplificador de ganancia programable, hasta X16, para ayudar a aumentar las señales individuales / diferenciales más pequeñas al rango completo. El ADC puede funcionar de 2 V a 5 V de alimentación lógica, puede medir un amplio rango de señales y es súper fácil de usar. Es un gran convertidor de 16 bits de propósito general.

La interconexión se realiza a través de la interfaz I2C. La dirección se puede cambiar a una de cuatro opciones para que pueda tener hasta 4 ADS1115 conectados en un solo bus I2C de 2 hilos para 16 entradas de terminación simple.

Especificaciones técnicas

Amplio rango de alimentación: 2,0V a 5,5V
Consumo de corriente bajo: Modo continuo: solo 150μA
Modo de disparo único: apagado automático
Tasas de datos programables: 8 SPS a 860 SPS (SPS = senseos por segundo)
Referencia interna de baja tensión de deriva interna: Sí
Oscilador interno: Sí
PGA incorporado: Sí (PGA = Amplificador de Ganancia Programable)
INTERFAZ I2C: Direcciones seleccionables por pines
Número de entradas analógicas: 4 simples o 2 Diferenciales
Comparador programable
Direcciones I2C: direcciones de bits entre 0x48-0x4B, seleccionables con puentes
Dimensiones mecánicas: 26.0 mm (L) x 9.4 mm (W) x 2.2 mm (H)
Separación de los pines: estándar 2,54 mm / 0,1 pulgada

Compatible con:

Placas Arduino como UNO, MEGA2560, DUE, Leonardo, Pro-mini, Pro-Micro, Nano, etc.
Raspberry Pi
ESP32, ESP8266, NodeMCU, WeMOS,
Microcontroladores PIC32, STM8, STM32, AVR, ATMEGA

Documentos y descargas:

ADS1115 Hoja de datos
ADS1115 Librería Python
ADS1115 Librería Arduino
ADS1115 Tutorial (Módulo similar, en breve publicaré nuestro propio tutorial)

Circuito típico

Conexiones

Selector analógico bidireccional CD74HC4067

Selector analógico bidireccional (multiplexor / demultiplexor) de 16 canales. Funciona como direccionador de 16 entradas analógicas a 1 vía de salida, o como 1 entrada analógica a 16 vías de salida.

Opera con alimentación entre 1,2 a 6 V.

Controla voltajes analógicos dentro del rango entre cero y el voltaje de alimentación.

Al ser bidireccionales permiten que las señales analógicas controladas sean, indistintamente, entradas o salidas. Estos selectores tienen baja resistencia al estar en estado de conducción, y alta resistencia al estar cerrados.


Ejemplos

Múltiples señales analógicas dirigidas a una entrada del microcontrolador

Múltiples Led controlados desde un único pin digital del microcontrolador

Hoja de datos:

CD74HC4067: http://www.ti.com/lit/ds/symlink/cd74hc4067.pdf

Puente H: Placa controladora de motores L9110S

La placa L9110S está diseñada para que los microcontroladores o circuitos lógicos puedan controlar con sencillez motores de corriente continua.

Driver de motores L9110S

El circuito está diseñado en base al chip controlador L9110, fabricado en la clásica cápsula DIP8 o en un diseño SOP8 SMD y basado en transistores MOSFET.

Circuito integrado L9110S

La tensión de alimentación para los motores puede variar de 2,5 a 12 V.

Diagrama de conexión

Como se observa en el siguiente diagrama, el control con el cableado típico no requiere componentes adicionales.

Conexión básica

Las entradas se pueden conectar directamente al microcontrolador. Si se conectan a un circuito que tiene salidas OC (Open Colector, o Colector Abierto) se requiere una resistencia pull-up conectada a la alimentación de 5V. Si bien en la hoja de datos del chip indica que el valor adecuado es ?1 k?, el módulo en sí incluye en su circuito resistores de 10 k? conectados al voltaje de alimentación de la lógica, o Vcc.

El circuito tiene dos entradas: una que puesta en ALTO hará que el motor avance, y una que puesta en ALTO hará que retroceda. Si se desea que el motor esté detenido, ambas entradas deben estar en el mismo valor: las dos en estado BAJO (LOW), o ambas en estado alto (HIGH). La placa tiene dos salidas, con bornera, que se conectan directamente al motor.

Las entradas que no se conectan a un circuito son tomadas como nivel BAJO (L, o Low) sin que ingrese ruido. Con un nivel ALTO (H, o HIGH), la corriente en esa entrada será de alrededor de 1 mA. El nivel de tensión para que el chip detecte la entrada en estado lógico BAJO o L es como máximo de 0,7 V.

Típicamente, para el nivel ALTO o H, la tensión en el pin de entrada debe ser de alrededor de la mitad del valor de alimentación o más (hasta, como máximo, el valor de la tensión de alimentación).

La corriente del motor se puede mantener constantemente desde 0,75 hasta 0,8 A (750 a 800 mA), y el circuito soporta picos de 1,5 a 2 A.

La hoja de datos ofrece una lista de los valores lógicos de las entradas y salidas.

nuevo-5

Esta tabla se puede ampliar para situaciones no típicas. Si sólo hay una entrada en el nivel H y la otra está en nivel L, el motor gira. Pero si ambas entradas están en H, o ambas entradas están en L, las salidas están en un tercer estado, o “flotante” (ningún voltaje), y no ambas en 0 volt, o “L”, como se muestra en la tabla.

Las salidas están conectadas internamente a diodos que protegen al circuito de los pulsos de contracorriente.




El L9110 gestiona dinámicamente frecuencias de hasta 40 kHz, mientras que el tiempo de conmutación más breve para la regulación por ancho de pulso (PWM) es de alrededor de 15 uS.

Diagrama de conexiones

Conexiones

Diagrama eléctrico

Circuito Eléctrico

Ejemplo práctico para controlar un robot

Ejemplo práctico - Control de un Robot

Ejemplo de programa para Arduino: prueba de movimientos

L9110S como amplificador de sonido para su robot

El control de un motor no es la única aplicación posible. El circuito también se puede utilizar como un sustituto de amplificador de potencia para una salida de audio digital de un microcontrolador.

En lugar de conmutar corriente a través del parlante como se realiza habitualmente, con un transistor, este circuito proporciona una doble amplitud de los impulsos de salida y, por lo tanto, aporta una potencia significativamente mayor.

Para una fuente de alimentación de 5 V es conveniente conectar un altavoz con una impedancia de 8 ? (o superior), mientras que con una entrada de 3 voltios puede utilizarse un altavoz adaptado a un voltaje menor. Para controlar el altavoz es necesario utilizar dos salidas en las que el nivel H alternará en cada media onda de la frecuencia del sonido.

En la siguiente figura hay una conexión que es normal con una salida, y funciona bien de 5 Hz a aproximadamente 30 kHz. Es importante mantener la condición de salida del microcontrolador en un nivel H cuando no se emite sonido, de lo contrario circulará corriente constante por el parlante.

Amplificador

Artículos relacionados:
Uso de la placa L298N para motores de CC
Puente H: Placa controladora de motores L9110S
Guía rápida de placas de control de motores
Manejo de potencia para motores con el integrado L293D
Control de motores de CC por Ancho de Pulso (PWM)



Guía rápida de placas de control de motores

1. DRV8835: Controlador de dos motores. Plaqueta de 18 mm x 10 mm para control bidireccional de dos motores de CC con voltajes de 0 V a 11 V. Tecnología MOSFET. Puede manejar hasta 1,2 A continuos por canal y puede soportar picos de corriente de hasta 1,5 A por canal por unos segundos. Protección incorporada contra voltaje inverso, bajo voltaje, sobrecorriente y sobrecalentamiento.

DRV8835



2. Shield L293D: Placa montable sobre Arduino UNO. Dos interfaces para servos. Maneja 4 motores de CC o 2 motores paso a paso. Controla la velocidad y sentido de marcha de los motores de CC con una selección de velocidad de 8 bit. Provee 0,6 A por salida (con picos de corriente de hasta 1,2 A) con protección térmica, con voltajes desde 4,5V a 36V.

Shield Arduino L293D



3. PCA9685: Placa de control de 16 servos o LEDs controlada por I2C. Con sólo 2 pines se controlan 16 salidas de ancho de pulso regulado. Resolución: 12 bit. VoltaJe: CC 5-10V. Tamaño: 60 x 25 mm.

Control de Servos



4. A3967: Controlador de microstepping compatible con motores paso a paso de 4, 6 y 8 cables, con rangos de tensión de 7 V a 30 V. Cuanto mayor sea el voltaje, mayor será el par en altas velocidades. Dispone además de un potenciómetro para ajustar el control de corriente de 150 a 750 mA por fase.

EasyDriver v4.4



5. A4988: Modulo de manejo para impresoras 3D, CNC y control de motores paso a paso. Con DISIPADOR. Permite controlar el giro de 1 motor paso a paso bipolar controlando micropasos. Protección por sobre-temperatura, bajo voltaje y cortocircuito. Voltaje de operación 8 a 35 volts. Máxima corriente por bobina: 2 A.

A4988



6. HG7881: controla 4 motores de corriente continua, o dos motor paso a paso de 2 fases, 4 hilos. Basado en integrados de tecnología MOSFET. Voltaje: 2,5 a 12V. Máxima corriente de funcionamiento: 0,8 A. Tamaño: 49 mm x 36 mm

HG7881



7. L9110S dual: Doble puente H para control bidireccional de 2 motores de CC. Basado en integrados de tecnología MOSFET. Corriente: 800 mA por cada salida. Rango de voltaje: 2,5 a 12V. Medidas: 29 mm x 23 mm.

L9110S dual



8. L298N: Módulo doble puente H para manejo de motores CC, con disipador. Tecnología con transistores NPN/PNP. Voltaje 5 a 35 V. Corriente máxima hasta 2A por salida.

L298N

Artículos relacionados:
Uso de la placa L298N para motores de CC
Puente H: Placa controladora de motores L9110S
Guía rápida de placas de control de motores
Manejo de potencia para motores con el integrado L293D
Control de motores de CC por Ancho de Pulso (PWM)