Archivo de la categoría: Arduino

Arduino: cómo hacer que los HEX queden en una carpeta conocida

Varias veces me han preguntado cómo se obtiene el archivo final de la compilación en «idioma de máquina» o hexadecimal (NombrePrograma.HEX) de un programa creado con el IDE de Arduino (también llamado Sketch por algunos).

Este archivo es útil para varias operaciones, como por ejemplo «descompilarlo» para ver el assembler, y también porque sería posible grabar el programa usando un programador de chips en un lote de microcontroladores que se necesite para un proyecto, sin usar bootloader ni una placa Arduino cuando vamos a producir una equis cantidad de plaquetas para uso personal, o para un cliente.

La secuencia para tenerlos en una carpeta accesible es:

1) Abrir el IDE de Arduino

2) Abrir el menú «Archivos» y allí elegir «Preferencias»

3) En el panel de Preferencias, abajo de todo, ingresar a la capeta de «preferences.txt» por medio del enlace que está debajo de un texto que dice «Más preferencias pueden se editadas [etc]…»

4) Una vez abierta la carpeta donde esta el archivo de preferencias, cerrar el IDE de Arduino (esto es muy importante)

5) Hacer una copia del archivo de preferencias para tenerlo de reserva por cualquier problema que se presente.

6) Abrir el TXT preferences.txt con un editor de texto simple, como el Bloc de Notas o Notepad

7) Hay una extensa lista allí. Buscar en el archivo de preferencias la zona donde está esta opción:

sketchbook.path=C:\Users\toshiba pc\Documents\Arduino

Obvio que la dirección dentro del disco C: que va luego del signo «=» será propia de cada máquina

8) Puede estar o no definida la opción build.path (es la que le indica al compilador dónde debe guardar el archivo compilado). Allí se puede crear o editarla. En mi caso, yo debí insertarla porque no existía y escribí:

build.path=C:\Users\toshiba pc\Documents\Arduino\HEX

Nota: En la publicación fuente de esta aplicación dice que es importante que este código agregado quede ubicado después de la opción export.application, pero sin embargo esto sería en una versión anterior, ya que ahora cada vez que se abre el IDE de Arduino estas opciones quedan ordenadas alfabéticamente.

9) Ahora sólo queda guardar este archivo editado y correr el IDE




10) Para comprobar que funciona, compilar cualquier programa y revisar si ha aparecido la carpeta HEX, y dentro de ella el compilado .HEX. Por ejemplo, si se compila el famoso ejemplo Blink.ino encontraremos el archivo Blink.ino.hex. Pero también encontrarán un Blink.ino.with_bootloader.hex. Es importante, ya que en este caso obtendrán un HEX con el que se podrán programar chips que además posean el habitual bootloader de la placa Arduino.

11) Luego uno puede ir distribuyendo estos .HEX en las carpetas de cada proyecto, ya que sólo estarán allí hasta que se haga la compilación de un nuevo programa. El IDE de la versión actual los borra antes de escribir un nuevo HEX.



Ingresar lectura de varios sensores a través de un único pin analógico

Cuando queremos crear un robot que distinga el blanco del negro sobre una superficie, se realiza esa detección con sensores infrarrojos reflectivos. Si la necesidad de determinar las ubicaciones debajo del sensor requiere precisión, hay que usar conjuntos de varios sensores, y sus salidas conectarlas a varios pines de entrada de un microcontrolador.

Por ejemplo, para seguidores de línea veloces (velocistas) tenemos la opción de utilizar un sensor como el de la imagen de arriba, el QTR-8A, fabricado por Pololu. O un conjunto sensor similar hecho por nosotros con, por ejemplo, un conjunto de CNY-70.

La mayoría de las veces los microcontroladores que usamos para controlar un robot tienen una cantidad limitada de pines de entrada y salida, y si tenemos que usar uno de éstos por cada sensor infrarrojo tendremos problemas para añadir funcionalidades a nuestro robot: comunicación serie, acelerómetros, giroscopios, I2C, sensores de distancia, detectores de choque, pulsadores o llaves, motores, tacómetros, leds, etc.

En los robots seguidores de línea el mínimo es dos sensores infrarrojos, aunque con esta cantidad el robot seguidor se moverá oscilando, y es muy posible que se escape en curvas cerradas o cruces de líneas. En los robots de Sumo se necesitan 4, incluso más si es un diseño más sofisticado, y en los seguidores de línea velocistas suele colocarse una hilera de 6 sensores o más.

Esto lleva al uso de demasiado pines de entrada en nuestro micro. Se podría utilizar algún tipo de multiplexor (como el CD74HC4067) para ir leyendo cíclicamente los sensores, pero eso significa el uso adicional de al menos 3 líneas, necesarias para seleccionar las entradas del multiplexor si se trata de un conjunto desde 6 y hasta 8 sensores, o 4 líneas adicionales si tenemos hasta 16 sensores. (Esta cantidad de sensores no es excesiva en un robot medianamente operativo y desarrollado.)

Pero veremos una manera de leer varios sensores de infrarrojos usando sólo un pin analógico del microcontrolador.

La idea es vieja: convertir la activación de los sensores en una selección de resistores que aportan cada uno diferentes corrientes, y que al sumarse entregan una salida combinada, con valores diferentes de voltaje. A esta configuración se le llama “resistor ladder” (escala de resistores) y lo que construimos es, en concreto, un convertidor digital a analógico.

Al usar varias resistencias, dependiendo de la entrada que se active, el pin del micro recibe una tensión distinta. Si el conjunto de resistores está bien diseñado, se puede determinar cuál es la entrada que se ha activado.




Con sensores basados en led infrarrojos y fototransistores, la señal obtenida será analógica y relacionada con la luz que se refleja, a menos que los sectores blanco y negro sean muy definidos y que no haya luz ambiente que interfiera. Para convertir estos valores intermedios a ceros y unos utilizamos un chip CMOS inversor Schmitt trigger 40106 o 74HC14, y en sus salidas ponemos resistencias en serie de distintos valores, que al final de la cadena se unen a un punto en común.

Desde ese punto se tomará el valor de la tensión utilizando una entrada analógica, y si está bien calculado el conjunto de resistencias, el valor analógico será distinto dependiendo del sensor que se haya activado. De ese modo, en el caso de un seguidor de líneas, conoceremos la posición del robot respecto al curso que debe seguir.

La ventaja es que tener varios sensores CNY70, o un conjunto QTR-8A ya no es un problema, porque podemos leer todos los valores con un único pin de nuestro microcontrolador, y dejar el resto libre para otras funciones.

Recordemos que la conversión de analógico a digital dentro del módulo de un microcontrolador lleva tiempo. Por cada sensor que se lee con los pines analógicos se produce una pausa, ya que la lectura de un convertidor de analógico a digital (ADC) típico tarda un tiempo en completarse. Si se conectan y leen por separado, a este retardo hay que multiplicarlo por la cantidad de sensores.

Sin embargo, con esta solución sólo se hace UNA lectura analógica.

Como vamos a usar un inversor schmitt trigger, y éste sólo nos da una señal alta (5V) o baja (0V) en su salida, con las resistencias siempre vamos a obtener los mismos resultados de tensión, aunque cambiemos de entorno (pistas de competición, o caseras con distinta iluminación), por tanto no hay necesidad de calibrar.

Y utilizando las resistencias correctas, sólo es necesario tener un ADC de 8 bits (0-255) para medir el voltaje (en tramos de 0,02V aproximadamente) con una referencia de 5V. En un Arduino el ADC tiene 4 veces más resolución, ya que su conversión es de 10 bits, o sea que entrega valores digitales entre 0 y 1023.

Pondremos como ejemplo 8 sensores infrarrojos que leen una superficie que tiene fondo blanco (que devuelve un valor cercano a 0), y la línea de color negro (que es cuando devuelve un voltaje mayor). Como inversor schmitt trigger se puede usar un 40106 o un 74HCT14. Ambos tienen 6 entradas/salidas. Como se necesitan 2 entradas más para llegar a las 8 del sensor, debemos usar un segundo chip inversor. También se necesitan 8 diodos y 9 resistores.

La salida de cada CNY-70, o de cada elemento del conjunto QTR-8A, va dirigida a una de las entradas de uno de los inversores. La salida correspondiente de ese inversor va a un diodo de señal como el 1N914 o 1N4148. Esto es necesario, ya que al estar unidas todas las salidas del otro lado de los resistores, con los diodos se evita que si una salida está a 5V, y otra a 0V, se derive una corriente entre ellas.

Después del diodo viene el resistor, que dependiendo de su valor hará que la tensión en el punto de unión caiga más, o menos. El valor del resistor debe ser único, diferente del de otros sensores, para que cada caída de tensión sea distinta.

Finalmente se unen todas las salidas a otro resistor para crear lo que se denomina un divisor de tensión. La línea que va al pin analógico del microcontrolador se debe conectar en ese punto, para que éste pueda medir el voltaje total y diferenciar qué sensor o sensores se activan.




Este resistor de terminación al que se une el resto va, en su otro extremo, a la alimentación (Vcc).

Esta configuración está diseñada para poder leer un fondo blanco con una línea negra, siempre y cuando los sensores nos den un valor cercano a 0 cuando leen el fondo blanco, y un valor mucho mayor cuando leen la línea negra. Si se necesita cambiar este comportamiento, se puede conectar la resistencia final a masa e invertir los diodos.

Ahora que ya recibimos distintas tensiones en el pin analógico del microcontrolador, dependiendo de los sensores que estén activos o no, debemos plantearnos cuántas mediciones posibles podemos obtener.

Como trabajamos en el ejemplo de un seguidor velocista, se pueden dar los siguientes casos:

  • Todos los sensores leen el fondo blanco.
  • Un sensor lee la línea negra y el resto el fondo blanco.
  • Dos sensores leen la línea negra y el resto el fondo blanco.

Con esta combinatoria, para conocer las variaciones debemos multiplicar el número de sensores por 2. En total tenemos 16 mediciones posibles (y diferentes) para todos los estados en que pueden estar los sensores.

He aquí un esquema con los distintos estados, el voltaje resultante (según una simulación) y el valor del ADC llevado a 8 bits:

Para un robot de Sumo ya no vale el cálculo anterior, ya que habría 7 combinaciones posibles de sus 4 sensores, y el fondo es negro con una línea blanca:

Ahora sólo queda medir una primera vez los diferentes valores de los sensores, y luego programar en nuestro microcontrolador una tabla con esos valores, para utilizar luego en las comparaciones del programa. Esta lista de valores servirá para siempre. Por supuesto, como los valores de los resistores tienen un margen de error, y la caída de tensión sobre los diodos no suele ser siempre el mismo, sólo podremos hablar de valores orientativos y únicamente podemos obtener los valores correctos midiéndolos directamente con un tester, o conectando el circuito al microcontrolador y que éste nos los informe a través del puerto COM y un monitor serie.



Comparación Arduino Uno – Arduino Nano

He aquí una comparación entre los pines del Arduino Nano y los del Arduino Uno. Para conocer más detalles de los pines de Arduino Uno se puede consultar esta publicación anterior.

Arduino Nano y Arduino Uno utilizan microcontroladores de la serie ATMega328, pero al ser de diferentes encapsulados, hay diferencias entre el modelo de configuración de pines del chip ATMega328 utilizado por Nano y el chip del Uno, ATMega328P.

En el Arduino Nano, la configuración de pines corresponde a una cápsula TQFP (Thin Plastic Quad Flat Package = Cápsula Cuadrada Plástica Delgada), y Arduino Uno usa la configuración de pines de cápsula PDIP (encapsulado plástico de doble línea de pines).





En la hoja de datos del ATMega328 se puede observar que los modelos TQFP y PDIP tienen diferencias en la cantidad de pines. Para TQFP son 32, mientras que para el PDIP son 28 pines.

Esta diferencia implica que el modelo de configuración de pines TQFP, al tener más conexiones al exterior, presenta entradas ADC (Convertidor Analógico Digitaal) adicionales. Para la configuración de pin TQFP son 8 las entradas analógicas o ADC de 10 bits. Miden desde 0 a 5 voltios, aunque es posible disminuir el extremo superior del rango utilizando la función analogReference() de referencia analógica. Los pines analógicos 6 al pin 7 no se pueden usar como pines digitales, mientras que los pines analógicos 0 al 5 se pueden usar como pines digitales.

Para la configuración de pines del modelo PDIP, existen 6 canales ADC de 10 bits, y los pines 0 hasta 5 se pueden usar como pines digitales.

El convertidor de USB a serie en el Arduino Uno es diferente del de Arduino Nano. El Arduino UNO no usa un chip FTDI controlador de USB a serie. En su lugar, la función la cumple un Atmega16U2 que está programado como un convertidor de USB a serie. En el Arduino Nano, utiliza el chip controlador FTDI232 USB a serie.

Para ver más claramente las diferencias entre Arduino Nano y Arduino Uno, se muestran en la siguiente tabla.




Convertidor de voltaje MT3608

El convertidor de voltaje CC-CC Step-Up (elevador) MT3608 tiene como función entregar un voltaje de salida regulado y constante superior al voltaje de entrada, sin importar las variaciones del voltaje de entrada o de carga. Soporta corrientes de salida de hasta 2A, voltaje de entrada entre 2V a 24V, y voltaje de salida entre 2V a 28V. El voltaje de salida se ajusta mediante un potenciómetro multivuelta o preset.

VENTAJOSA UTILIZACIÓN EN SISTEMAS BASADOS EN UN MICROCONTROLADOR

Cuando un sistema basado en Arduino debe ser móvil, es normal utilizar una pila de 9V para alimentar el Arduino y aislarlo de las variaciones de voltaje del conjunto de pilas que se utilice. Más aún cuando estas pilas alimentan elementos como motores, que generan pulsos de consumo en el momento del arranque y producen bajones momentáneos, que pueden reiniciar al Arduino, o bajones cuando aumenta el esfuerzo que deben hacer, y las pilas se van descargando.

La tecnología nos ofrece hoy otra opción, que resulta mejor en varios sentidos: el módulo MT3608 es más barato o vale casi igual que una pila de 9V, pero dura muchísimo mas que ella (y las pilas de 9V recargables son muy caras, en el orden de 10 a 20 veces más que una pila descartable, o el módulo). El voltaje de alimentación que ofrece es extremadamente estable y se mantiene hasta que las pilas que alimentan el sistema se descarguen por debajo de 2V. Y para aplicaciones móviles, lo importante, que es el peso: el módulo es bastante más liviano que la pila.

CONVERTIDORES CC-CC (DC-DC en inglés)

Los convertidores CC-CC son circuitos capaces de transformar un nivel de voltaje a otro de mayor nivel, o de menor nivel.

Existen dos estilos de circuito en los convertidores o reguladores CC-CC: lineales y conmutados (switching). Los reguladores de tipo lineal, como el clásico LM7805 o el LM317, son muy sencillos de utilizar pero no son eficientes energéticamente. Por el contrario, los reguladores de tipo conmutado presentan altos niveles de eficiencia energética (superior al 80%).

Los convertidores conmutados convierten el voltaje mediante el almacenamiento periódico de energía de entrada y la posterior liberación de esa energía en la salida de forma que el nivel de voltaje final es el deseado.

Los convertidores CC-CC conmutados con el objetivo de convertir la energía eléctrica con la máxima eficiencia poseen componentes que no producen perdidas de alimentación, es decir, que no absorben energía.

Encontramos en estos circuitos componentes principales de dos tipos básicos: conmutadores y almacenadores. Los conmutadores son interruptores del paso de corriente, que idealmente no presentan pérdidas por conmutación. Normalmente son transistores MOSFET. Los componentes almacenadores son los inductores y capacitores, que almacenan la energía temporalmente para luego devolverla al circuito.

Podemos clasificar a los conmutadores CC-CC por relación voltaje de entrada-voltaje de salida en: reductores (Step-Down o Buck), elevadores (Step-Up o Boost), y en algunos casos de doble función: reductores-elevadores (Step-Up-Down o Buck-Boost).

El convertidor CC-CC MT3608 es un regulador de tipo conmutado elevador (Step-Up o Boost) con una alta eficiencia de conversión, excelente regulación de línea y bajo voltaje de alterna superpuesta a la salida (ripple en inglés).





El módulo reduce al mínimo el uso de componentes externos para simplificar el diseño de fuentes de alimentación. Permite obtener un voltaje regulado a partir de una fuente con un voltaje inferior, por ejemplo: obtener 5V, 9V o 12V a partir de una batería de litio de 3,7V. Es capaz de manejar una carga de hasta 2A, o 6W máx.

DIAGRAMA DE COMPONENTES

ESPECIFICACIONES TÉCNICAS

  • Convertidor CC-CC Boost: MT3608
  • Voltaje de entrada: 2V a 24V CC
  • Voltaje de salida: 5V a 28V CC
  • Voltaje de salida ajustable (regulable por un potenciómetro)
  • Corriente de salida: máxima 2A (usar disipador para corrientes mayores a 1,5A)
  • Potencia de salida: 6W
  • Eficiencia de conversión: 93% máx.
  • Frecuencia de Trabajo: 1,2MHz
  • Protección de sobre-temperatura: SI (apaga la salida)
  • Protección de corto circuito: NO
  • Protección limitadora de corriente: SI (4A)
  • Protección frente a inversión de polaridad: NO
  • Dimensiones: 36mm x 17mm x 7mm

APLICACIONES

  • Fuentes de voltajes de salida de 6 a 28 V a partir de voltajes menores, como conjuntos de pilas recargables de 4,5 a 6V, o de litio de 3,7V
  • Robótica móvil

CONEXIONES

ENLACES

Hoja de datos del chip regulador MT3608
Concepto de convertidor CC-CC
Concepto de convertidor Boost
Video sobre convertidores CC-CC



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.