Archivo de la etiqueta: Programas Arduino

Entendiendo ASCII en el desarrollo de lenguaje de máquina integrado

Este artículo, que sirve como preparación para una discusión de cadenas (strings) en lenguaje C, presenta el concepto de caracteres ASCII y explica dos beneficios de las técnicas de codificación basadas en ASCII.


Un microprocesador o microcontrolador es una colección compleja de circuitos que manipulan voltajes lógicos altos y voltajes lógicos bajos. Para mayor comodidad, nos referimos a estos voltajes como unos y ceros, y diseñamos los procesadores de manera que estos unos y ceros puedan manipularse en conjunto y tratarse como números binarios.

La mayoría de la gente se volvería loca o se quedaría dormida si se vieran obligados a observar el flujo interminable de números binarios dentro y fuera de un microprocesador. La tecnología computacional ha transformado la existencia humana porque estos números binarios se pueden usar para representar cosas que a las personas realmente les importan: música, fotografías o, en el caso del ASCII, letras y dígitos.

Entendiendo el ASCII

ASCII significa Código Estándar Americano para el Intercambio de Información (American Standard Code for Information Interchange = ASCII). En este código, un número binario significa exactamente un caracter, donde “caracter” se refiere a una letra mayúscula, una letra minúscula, un dígito, un signo de puntuación, o varias otras cosas que se pueden encontrar en un teclado. La siguiente tabla le brinda la “traducción” entre los números (aquí, escrita en notación decimal en lugar de binaria) y los caracteres ASCII correspondientes al alfabeto en mayúsculas y minúsculas.

(Nota: Quede claro que cuando en EEUU dicen “americano” se refieren a algo que se aplica solamente a ellos, no a toda América. Quedaba afuera, en principio, toda letra que no se usa en el inglés actual, letras con acentos, diéresis, circunflejo, tildes, y otras diferenciaciones fonéticas en otros idiomas, y por eso se creó la tabla de ASCII extendido, que está incluida más abajo).


Es esencial comprender que su microcontrolador no sabe nada acerca de las letras del inglés u otra lengua (y menos aún de los caracteres acentuados de diferentes maneras o especiales en cada idioma), los signos de puntuación o los dígitos. Su microcontrolador es una máquina muy pequeña, diseñada para procesar números binarios, y cualquier carácter que esté presente en su lenguaje de máquina (firmware) es simplemente su interpretación de los números binarios.

Se puede producir una seria confusión debido a la impresión errónea de que sus variables, o elementos de matriz, contienen realmente caracteres ASCII de una forma u otra. El desarrollo de firmware se vuelve más claro, más ágil y más flexible cuando uno se da cuenta de que los caracteres en realidad son números binarios, y se pueden almacenar, transferir y manipular como números binarios; no se convierten en caracteres ASCII hasta que esté todo listo para interpretarlos como caracteres ASCII.

ASCII Extendido

Beneficios y contras del ASCII

El ASCII es necesario para la programación humana. Hay muchas aplicaciones integradas que pueden beneficiarse del uso de caracteres ASCII, y creo que es una buena idea adquirir el hábito de reconocer situaciones en las que se puede incorporar caracteres ASCII en su código.




Un estándar ampliamente utilizado

Un beneficio innegable de ASCII es la estandarización. Los entornos de desarrollo integrado, los programas de terminal y los paquetes de software computacional comprenden el ASCII y, por lo tanto, los caracteres ASCII son una forma conveniente y efectiva de transferir y mostrar información.

En este ejemplo, una aplicación muestra una representación binaria basada en datos de un sensor:

Transferencia de datos confiable

Un beneficio más sutil, pero quizás igual de importante, es el hecho de que el ASCII proporciona un medio para representar información utilizando un conjunto restringido de números binarios. Cualquier valor numérico puede representarse mediante una secuencia de los dígitos ASCII del 0 al 9 (junto con el punto decimal ASCII si es necesario). Estos caracteres ASCII corresponden a un subconjunto muy pequeño de los 256 valores ofrecidos por un número binario de 8 bits. Pero ¿por qué esto importa?

Imagine que tiene una aplicación en la que un microcontrolador debe transferir mediciones impredecibles y altamente variables de sensores de 8 bits a una PC. Si se transfieren los datos como números binarios ordinarios, un byte individual puede contener un número cualquiera del 0 al 255. Esto nos deja sin una forma conveniente y sencilla de organizar datos o incorporar comandos en el flujo de datos, porque para transferir las mediciones en bruto solo son necesarios todos los números binarios posibles. El PC (y menos nosotros) no puede distinguir entre los datos de medición numéricos y otros tipos de información.

Si se transfieren los datos de medición utilizando caracteres ASCII en lugar de números binarios ordinarios, entran en juego los beneficios de un conjunto restringido. Solo se necesitan diez valores binarios (correspondientes a los dígitos ASCII del 0 al 9) para representar los datos numéricos, y varios otros valores binarios pueden reservarse para una funcionalidad especial, porque nunca aparecerán en los datos de medición.

Aquí, los dígitos ASCII se utilizan para transferir una lectura de temperatura. El final de cada lectura se identifica con un retorno de carro (abreviado CR = Carrier Return); el valor binario correspondiente a CR nunca aparecerá en los datos de medición.

Reducción de la eficiencia

El precio que se paga por esta estandarización y transferencia de datos mejorada es que se usa con menos eficiencia la memoria, el ancho de banda del procesador y el ancho de banda de la comunicación.

El ASCII es un sistema basado en bytes. Cada carácter requiere ocho bits, incluyendo, por ejemplo, el dígito “1”, que en circunstancias binarias normales puede representarse mediante un número de 1 bit en lugar de un número de 8 bits.

En la experiencia de un programador actual, esto rara vez es un problema serio; los microcontroladores modernos tienen recursos de procesamiento y memoria que exceden con creces los requisitos de muchas aplicaciones. Sin embargo, si realmente se necesita maximizar el rendimiento o minimizar el uso de la memoria, es posible que debamos renunciar a la conveniencia de usar ASCII.

De ASCII a cadenas de caracteres

Este artículo no es solo una descripción general de ASCII sino también una introducción a la forma en que se maneja una representación basada en caracteres en el lenguaje de programación C. Nos referimos a este tipo de representación como una cadena (string), que es una secuencia o “encadenamienro” de caracteres ASCII.

Veremos más en detalle las cadenas en un próximo artículo.



Módulo de teclado sensible al tacto TTP229

Este teclado de 16 teclas se conecta utilizando una conexión I2C (2-Wire), aunque en el chip sensor capacitivo TTP229 tiene implementada la opción de conectar solamente 8 teclas, que tienen salida directa en los pines del módulo. Son los pines marcados como OUT1 a OUT8. Las líneas marcadas SDO y SCL pertenecen a la interfaz I2C.

Características

■ Fácil de usar, calibración automática
■ LED de encendido
■ Funciona en modo 8 o 16 canales.
■ La salida puede ser configurada como activa alta o baja
■ Simple para reemplazar salidas de llaves mecánicas
■ La salida se puede conectar directamente a los pines de entrada del microcontrolador

Especificaciones

■ Voltaje de funcionamiento: 2V-5,5V
■ Tiempo de calibración de inicio: 0,5 seg.
■ Tamaño de la plaqueta: 49,3 x 64,5mm

Este módulo es una buena alternativa para reemplazar teclados mecánicos, ya que es durable, fácil de instalar (es totalmente plano), se puede proteger con una membrana en ambientes de atmósfera corrosiva, y proporciona más durabilidad en condiciones de trabajo continuado.

Puentes que definen las opciones

(Ver las opciones definibles en la tabla abajo)

EJEMPLO:

Diagrama de pines del circuito integrado TTP229

El teclado se puede configurar tanto para usar con 8 teclas como con 16. Para el primer caso, parece poco razonable usar sólo la mitad, ya que en realidad se venden módulos directamente con sólo 8 teclas, y también con 4 y hasta con una sola.

En todo caso, la división de funciones, y la multiplicidad de opciones que se pueden elegir usando una serie de puentes en la plaqueta aportan amplia funcionalidad y una buena adaptación para distintos usos.

Cuando se elige la opción de 16 teclas, se los lee por medio de una interfaz serie de 2 vías, llamada comúnmente 2-Wire en el mundo Arduino, o I2C.

Una vez conectado el hardware y descargando el código al Arduino, al pulsar los teclas se pueden observar los resultados en el Monitor Serie del IDE Arduino.

Diagrama en bloques del circuito integrado TTP229

Diagrama del módulo de teclado TTP229

PROGRAMAS DE PRUEBA

Conexión directa de las salidas de 8 teclas

Si en alguna ocasión se necesita utilizar sólo la serie de teclas del 1 a 8, la configuración y la lectura por programa es más sencilla y simple de entender. La conexión involucra 8 pines del conector del módulo de teclado al Arduino, y dos más de ellas para alimentación +5 y GND.

Esta forma de uso tiene la desventaja de que ocupa muchas entradas digitales (que nunca sobran), aunque la ventaja es que no necesariamente se debe usar un Arduino u otro microcontrolador para recibir datos desde el módulo si se lo usa con esta configuración. Podría servir para introducir órdenes de teclado en un circuito puramente digital, sin procesador ni programa.

Diagrama de conexiones con Arduino

Código simple para 8 teclas

Resultado en Monitor Serie




Conexión para leer las 16 teclas

Para leer los teclas del 1 a 16 se debe hacer a través de la interfaz serie I2C o 2-Wire del Arduino, utilizando SCL y SDO, y con dos pines digitales que uno elija y el programa adecuado, que en general es muy simple.

Conexión entre el Arduino y el teclado para el ejemplo de 16 teclas por I2C

Cablear como se muestra a continuación y además hacer un puente en el módulo del teclado para configurarlo para funcionar con 16 teclas, sobre los puntos marcados “TP2”, que se muestran abajo en naranja.

Esto se hace soldando un alambrecito que una estos 2 terminales.

Diagrama de la conexión con Arduino

Código para la lectura de 16 teclas

Resultado en Monitor Serie

Lectura de 16 teclas con posibilidad de pulsar más de una a la vez

Como en cada caso en que se habilitan 16 teclas, la comunicación con el microcontrolador se realiza por medio del protocolo I2C. Cada tecla está asociada a un bit en un entero sin signo de dos bytes.

Estos son algunos ejemplos:

La tecla 1 aparecerá como 0000 0000 0000 0001
La tecla 2 aparecerá como 0000 0000 0000 0010
La tecla 3 aparecerá como 0000 0000 0000 0100
… …
La tecla 9 aparecerá como 0000 0001 0000 0000
La tecla 12 aparecerá como 0000 1000 0000 0000
La tecla 16 aparecerá como 1000 0000 0000 0000

Cuando se tocan dos o más teclas, el entero asociado contendrá dos bits o más en 1. Por ejemplo, si se pulsan la tecla 1 y la 16 al mismo tiempo, el entero asociado será 1000 0000 0000 0001

Conexiones:

Los pines TP0 a TP4 en el teclado se deben conectar (hacer un puente) como en la figura siguiente:

Diagrama de conexión con el Arduino:

Código para 16 teclas – multitecla – interfaz 2-wire:

En la Terminal Serie del IDE de Arduino se verá lo que sigue al pulsar las teclas desde 1 a 16 (Nota: debido a la manera en que la función Serial.println maneja las variables, el Monitor Serie no muestra los ceros a la izquierda del entero de 16 bits):

Para este ejemplo: PDFs de ayuda (en inglés) desde el siguiente enlace:
http://osoyoo.com/driver/TTP229.rar

Se puede descargar el programa INO (con textos en inglés) desde el siguiente enlace:
http://osoyoo.com/wp-content/uploads/2016/07/TTP229_all.rar


Comprendiendo Variables al programar en C

Este es un análisis de la naturaleza y el uso de las variables en lenguaje C en el contexto de las aplicaciones para microcontroladores

Muchos de nosotros escuchamos la palabra “variable” en las clases de matemáticas mucho antes de saber mucho, si es que sabemos algo, acerca de la programación de computadoras. Una variable matemática es una cantidad cuyo valor no se conoce o no se limita a un número. Este uso es similar, aunque no idéntico, al concepto de una variable C.

Dos diferencias importantes: primero, en matemáticas, usualmente usamos una letra como x o y para representar una variable, mientras que en C usamos frecuentemente una palabra o frase descriptiva como contadorPulsos, velocidadMedia o cantidadVueltas. En segundo lugar, hay situaciones en las que usamos una variable de C para identificar una cantidad conocida y que no se pretende que cambie del valor original.

Variables en hardware

Las variables son convenientes e intuitivas para los programadores. Para el hardware computacional, por otro lado, no tienen un significado real. Los microprocesadores almacenan datos en registros y ubicaciones de memoria. Esta diferencia fundamental entre las personas que escriben el idioma de máquina y las máquinas que ejecutan este programa se supera mediante lenguajes de alto nivel como C, que maneja varios detalles asociados con la traducción entre variables basadas en texto y la realidad física de un procesador.

Los diseñadores de sistemas integrados trabajan a menudo con procesadores de 8 bits. En estos dispositivos, por lo general, el tamaño fundamental de los datos es un byte. La memoria se organiza de acuerdo con los bytes, el tamaño de los registros es de un byte y la CPU está diseñada para procesar datos de 8 bits. Esta es una limitación bastante incómoda porque hay muchas situaciones en las que el valor de una variable excederá el valor máximo de un número de 8 bits.

Finalmente, todas las variables C cuidadosamente definidas y con un nombre ilustrativo terminan como bits en la memoria (o registros)

El lenguaje C no limita el tamaño de una variable a 8 bits, incluso cuando está trabajando con un procesador de 8 bits. Esto significa que una variable en el programa en lenguaje de máquina que ejecuta el microprocesador puede corresponder a múltiples registros o ubicaciones de memoria en el hardware. “Manualmente” administrar variables de múltiples bytes (es decir, a través del lenguaje ensamblador) no parece muy deseable, pero a los compiladores no les importa en absoluto, y hacen el trabajo muy bien.

Definiendo variables

El primer paso para usar una variable es definir esa variable. Los componentes esenciales de una definición de variable son el tipo y el nombre.

Hay muchos tipos de variables; La lista completa, así como los detalles de la implementación del hardware, variarán según el compilador que esté utilizando. Aquí hay unos ejemplos:

char : un valor con signo de un byte
int : un valor con signo de dos o cuatro bytes
long : un valor con signo de cuatro bytes
float : un valor de cuatro bytes que puede tener números después del punto decimal; en otras palabras, no está limitado a enteros
bit : el valor de la variable puede ser cero o uno

Esta es una representación visual de cómo una serie de bits se interpreta de manera diferente en función de si una variable se considera con signo (utilizando la notación de complemento a dos) o sin signo:

El siguiente código muestra definiciones de variables que consisten solo en un tipo básico y un nombre (la forma más técnica de referirse al nombre es “identificador”):

Inicializando variables

En muchos casos, es una buena idea darle un valor inicial a una variable. Esto facilita la depuración y es esencial si la variable se utilizará antes de que le fije un valor conocido. Puede inicializar una variable en la definición, o en otra parte de su código, pero incluir el valor inicial en la definición es una buena manera de mantener el código organizado y desarrollar el hábito de inicializar siempre que sea necesario.

Aquí hay ejemplos de definiciones de variables que incluyen una inicialización:

Definiciones de variables delicadas

Hay varias otras palabras que se pueden incluir en una definición de variable. Estos se utilizan para especificar con mayor precisión la naturaleza de la variable o para dar instrucciones al compilador sobre cómo implementar la variable en el hardware.

Las siguientes palabras clave podrían ser útiles en sus proyectos de programa para microcontroladores:

■ unsigned : como habrá adivinado, esto le dice al compilador que interprete la variable como un valor sin signo en lugar de un valor con signo. Uno defino le mayoría de sus variables como sin signo, porque rara vez se necesitan números negativos.

■ const : el calificador de tipo const indica al compilador que el valor de una variable no debe cambiar. Como dice al principio del artículo, a veces el valor de una “variable” C no es variable. Si usted comete un error en su código e intenta modificar el valor de una variable const, el compilador generará un error.

■ volatile : los compiladores sofisticados no solo toman su código original y lo traducen directamente al lenguaje de máquina. También intentan hacer que el código funcione de manera más eficiente, y este proceso se conoce como “optimización”. En general, la optimización es algo bueno. Sin embargo, de vez en cuando, puede arruinar el día, porque el compilador se optimiza solo en función del código y no puede tener en cuenta los eventos de hardware que interactúan con el código. Cuando una variable tiene el calificador de tipo volátil, el compilador sabe que debe tener cuidado con las optimizaciones relacionadas con esa variable.

Una interrupción puede hacer que el valor de una variable se modifique de una manera que el compilador no espera, y esto puede llevar a una optimización problemática

■ tipos de memoria, como xdata , idata y code : estas palabras obligan al compilador a ubicar una variable en una parte específica de la memoria del microprocesador. El tipo que aloja en la memoria de programa es particularmente útil: los recursos de RAM en un microcontrolador a menudo son mucho más limitados que la memoria de programa no volátil, y el tipo de memoria de código le permite utilizar memoria de programa adicional para almacenar datos que se usan en su programa pero nunca se modifican.

Aquí hay unos ejemplos:

Uso de las variables

No hay mucho que decir acerca de cómo usar sus variables después de que se hayan definido. En realidad, con respecto a la variable en sí, la definición es la mayor parte del trabajo. Después de eso, usted simplemente incorpora el identificador de la variable en operaciones matemáticas, bucles, llamadas a funciones, etc. Un buen compilador no solo manejará los detalles de la implementación del hardware, sino que también buscará formas de optimizar el código con respecto a la velocidad de ejecución o el tamaño del programa.

Quizás el error más común relacionado con el uso variable es un desbordamiento. Esto se refiere a una situación en la que el valor asignado a una variable está fuera del rango numérico asociado con el tipo de datos de la variable.

Se debe pensar en todos los escenarios posibles relacionados con una variable determinada y luego elegir el tipo de datos en consecuencia.

Resumen

La funcionalidad de la variable básica proporcionada por el lenguaje C es intuitiva y directa, pero hay algunos detalles que pueden ayudarlo a hacer que una aplicación integrada sea más confiable y eficiente. Si tiene alguna duda relacionada con las variables de C, no dude en preguntar en nuestro grupo en Facebook Robots Didácticos.




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: bibliotecas de funciones personales

A menudo tenemos fragmentos de código con funciones que podemos reutilizar en muchos programas. Algo muy habitual en programación. Creamos una función que resuelve una necesidad concreta y queremos tenerla disponible para reutilizarla en cualquier otro programa en el que debamos resolver la misma necesidad.

Lo habitual —pero no lo más práctico— es copiar el código de esa función especial dentro de cada nuevo programa. Pero conviene tenerla en un formato reutilizable con facilidad, sobre todo si la función es muy extensa.

Para lograrlo, guardamos esa función (y todas las variables y constantes que incluya) en un archivo .ino separado, pero no debemos cargarlo individualmente en una placa Arduino, sino que luego lo incluiremos en cada programa que necesitemos, de al modo que siempre lo tendremos disponible.

( Nota: no le llamamos “sketch” sino “programa” para Arduino. )

¿Cómo incluimos un trozo de programa en otro?

Vamos a crear un código reutilizable, y lo guardaremos en una ubicación conocida del disco, un “reservorio” de funciones útiles que llevan un nombre que nos recuerde qué es y lo que hace.

Quedará con la extensión .INO, pero no es un programa para cargar al Arduino y ejecutarlo. Queda con esa extensión porque todos los programas editados en la IDE de Arduino se graban siempre con la extensión .ino.

El código es uno que hayamos creado como función o grupo de funciones dentro de un programa mayor.

Tomaremos como ejemplo una cantidad de funciones creadas para los distintos movimientos de los motores en un programa para un robot navegador.

El circuito que este programa mueve, para mejor comprensión de los ejemplos, es este:

Veamos el programa original con las funciones incluidas dentro de él:

Ahora vamos a escribir un programa diferente, con otra serie de movimientos. Suponemos que estamos editando en el IDE de Arduino, como sigue:

Pero así no funcionaría, ya que tiene llamados a funciones (como adelanteDerecho, atrasIzquierdo, etc.) que están en otro lugar.

De modo que abrimos el programa que las tiene, copiamos las funciones que necesitamos…

… y las pegamos en una ventana vacía del IDE. Luego las guardamos con Guardar como… en la carpeta que deseemos. A esta carpeta podemos llamarla, por ejemplo: /FuncionesUtiles/

El archivo de funciones que creamos y guardamos es este: FuncionesMotor.ino, y es así:

Ahora sólo debemos ver cómo hacemos para incluir el archivo de funciones auxiliares en nuestro nuevo programa.

Para eso desplegamos el menú Programa en la barra de menúes de la parte superior del IDE. Seleccionamos la opción Añadir fichero… y se nos abre un cuadro de diálogo para que busquemos el .ino que guardamos allí, con las funciones de motor que queremos incluir en este programa nuevo.




Lo abrimos, como si fuera un .ino estándar, pero, debido a la opción que hemos elegido, en lugar de abrirse en una nueva ventana del IDE se abre en una nueva pestaña auxiliar de la misma ventana. Nuestra ventana de trabajo queda como vemos aquí:

Ya podemos regresar a la pestaña principal, compilar y subir el programa al Arduino.

Cuando guardemos este programa principal, y volvamos a abrirlo otro día, el IDE de Arduino se abrirá con las dos pestañas. Si se observa dentro de la carpeta que, como es habitual, lleva el nombre del programa (en este ejemplo Otro_control_de_motores) veremos que dentro de ella están los dos archivos .ino: Otro_control_de_motores.ino y FuncionesMotor.ino

Esto no significa que el IDE haya movido FuncionesMotor.ino desde la carpeta /FuncionesUtiles/ que creamos, sino que sólo lo ha copiado. Así que, por supuesto, este archivo .ino de funciones auxiliares para adjuntar podemos incluirlo en todos los programas donde sea necesario. No será propiedad exclusiva de ninguno de ellos.