Sei sulla pagina 1di 44

QUÉ SON Y CÓMO USAR

INTERRUPCIONES EN
ARDUINO

28 ABRIL, 2016

Las interrupciones son un mecanismo muy potente y valioso en procesadores y


autómatas. Arduino, por supuesto, no es una excepción. En esta entrada veremos qué son las
interrupciones, y como usarlas en nuestro código.

Para entender la utilidad y necesidad de las interrupciones, supongamos que tenemos


Arduino conectado a un sensor, por ejemplo encoder óptico que cuenta las revoluciones de un
motor, un detector que emite una alarma de nivel de agua en un depósito, o un simple pulsador
de parada.

Si queremos detectar un cambio de estado en esta entrada, el método que hemos usado
hasta ahora es emplear las entradas digitales para consultar repetidamente el valor de la
entrada, con un intervalo de tiempo (delay) entre consultas.

Este mecanismo se denomina “poll”, y tiene 3 claras desventajas.

Anuncio:
 Suponer un continuo consumo de procesador y de energía, al tener que preguntar continuamente
por el estado de la entrada.

 Si la acción necesita ser atendida inmediatamente, por ejemplo en una alerta de colisión, esperar
hasta el punto de programa donde se realiza la consulta puede ser inaceptable.

 Si el pulso es muy corto, o si el procesador está ocupado haciendo otra tarea mientras se
produce, es posible que nos saltemos el disparo y nunca lleguemos a verlo.

Para resolver este tipo de problemas, los microprocesadores incorporan el concepto de


interrupción, que es un mecanismo que permite asociar una función a la ocurrencia de un
determinado evento. Esta función de callback asociada se denomina ISR (Interruption Service
Rutine).

Cuando ocurre el evento el procesador “sale” inmediatamente del flujo normal del
programa y ejecuta la función ISR asociada ignorando por completo cualquier otra tarea (por
esto se llama interrupción). Al finalizar la función ISR asociada, el procesador vuelve al flujo
principal, en el mismo punto donde había sido interrumpido.

Como vemos, las interrupciones son un mecanismo muy potente y cómodo que mejora
nuestros programas y nos permite realizar acciones que no serían posibles sin el uso de
interrupciones.

Para usar interrupciones en dispositivos físicos (como pulsadores, sensores ópticos, … ) debemos
antes eliminar el efecto “rebote”, como podéis ver en la entrada Aplicar debounce al usar
interrupciones en Arduino

INTERRUPCIONES EN ARDUINO
Arduino dispone de dos tipos de eventos en los que definir interrupciones. Por un lado
tenemos las interrupciones de timers (que veremos en su momento al hablar de temporizadores.
Por otro lado, tenemos las interrupciones de hardware, que responden a eventos ocurridos
en ciertos pines físicos.

Dentro de las interrupciones de hardware, que son las que nos ocupan en esta
entrada, Arduino es capaz de detectar los siguientes eventos.

 RISING, ocurre en el flanco de subida de LOW a HIGH.

 FALLING, ocurre en el flanco de bajada de HIGH a LOW.

 CHANGING, ocurre cuando el pin cambia de estado (rising + falling).

 LOW, se ejecuta continuamente mientras está en estado LOW.

Los pines susceptibles de generar interrupciones varían en función del modelo de Arduino.

En Arduino y Nano se dispone de dos interrupciones, 0 y 1, asociados a los pines digitales


2 y 3.El Arduino Mega dispone de 6 interrupciones, en los pines 2, 3, 21, 20, 19 y 18
respectivamente. Arduino Due dispone de interrupciones en todos sus pines.
LA FUNCIÓN ISR
La función asociada a una interrupción se denomina ISR (Interruption Service Routines) y,
por definición, tiene que ser una función que no recibe nada y no devuelva nada.

Dos ISR no pueden ejecutarse de forma simultánea. En caso de dispararse otra


interrupción mientras se ejecuta una ISR, la función ISR se ejecuta una a continuación de otra.

LA ISR, CUANTO MÁS CORTA MEJOR

Al diseñar una ISR debemos mantener como objetivo que tenga el menor tiempo de
ejecución posible, dado que mientras se esté ejecutando el bucle principal y todo el resto de
funciones se encuentran detenidas.
Imaginemos, por ejemplo, que el programa principal ha sido interrumpido mientras un
motor acercaba un brazo para coger un objeto. Una interrupción larga podría hacer que el brazo
no para a tiempo, tirando o dañando el objeto.

Frecuentemente la función de la ISR se limitará a activar un flag, incrementar un


contador, o modificar una variable. Esta modificación será atendida posteriormente en el hilo
principal, cuando sea oportuno.

No empleéis en una ISR un proceso que consuma tiempo. Esto incluye cálculos complejos,
comunicación (serial, I2C y SPI) y, en la medida de lo posible, cambio de entradas o salidas tanto
digitales como analógicas.

LAS VARIABLES DE LA ISR COMO “VOLATILES”

Para poder modificar una variable externa a la ISR dentro de la misma debemos
declararla como “volatile”. El indicador “volatile” indica al compilador que la variable tiene
que ser consultada siempre antes de ser usada, dado que puede haber sido modificada de forma
ajena al flujo normal del programa (lo que, precisamente, hace una interrupción).

Al indicar una variable como Volatile el compilador desactiva ciertas optimizaciones, lo


que supone una pérdida de eficiencia. Por tanto, sólo debemos marcar como volatile las
variables que realmente lo requieran, es decir, las que se usan tanto en el bucle principal
como dentro de la ISR.

EFECTOS DE LA INTERRUPCIÓN Y LA
MEDICIÓN DEL TIEMPO
Las interrupciones tienen efectos en la medición del tiempo de Arduino, tanto fuera
como dentro de la ISR, porque Arduino emplea interrupciones de tipo Timer para actualizar la
medición del tiempo.

EFECTOS FUERA DE LA ISR

Durante la ejecución de una interrupción Arduino no actualiza el valor de la función


millis y micros. Es decir, el tiempo de ejecución de la ISR no se contabiliza y Arduino tiene un
desfase en la medición del tiempo.

Si un programa tiene muchas interrupciones y estas suponen un alto tiempo de


ejecución, la medida del tiempo de Arduino puede quedar muy distorsionada respecto a la
realidad (nuevamente, un motivo para hacer las ISR cortas).

EFECTOS DENTRO DE LA ISR


Dentro de la ISR el resto de interrupciones están desactivadas. Esto supone:

 La función millis no actualiza su valor, por lo que no podemos utilizarla para medir el tiempo
dentro de la ISR. (sí podemos usarla para medir el tiempo entre dos ISR distintas)

 Como consecuencia la función delay() no funciona, ya que basa su funcionamiento en la función


millis()

 La función micros() actualiza su valor dentro de una ISR, pero empieza a dar mediciones de
tiempo inexactas pasado el rango de 500us.

 En consecuencia, la función delayMicroseconds funciona en ese rango de tiempo, aunque


debemos evitar su uso porque no deberíamos introducir esperas dentro de una ISR.

CREAR INTERRUPCIONES EN
ARDUINO
Para definir una interrupción en Arduino usamos la función:

1 attachInterrupt(interrupt, ISR, mode);


Donde interrupt es el número de la interrupción que estamos definiendo, ISR la función de
callback asociada, y mode una de las opciones disponibles (Falling, Rising, Change y Low)

No obstante, es más limpio emplear la función digitalPinToInterrupt(), que convierte


un Pin a la interrupción equivalente. De esta forma se favorece el cambio de modelo de placa
sin tener que modificar el código.

1 attachInterrupt(digitalPinToInterrupt(pin), ISR, mode);


Otras funcionas interesantes para la gestión de interrupciones son:

 DetachInterrupt(interrupt ), anula la interrupción.

 NoInterrupts(), desactiva la ejecución de interrupciones hasta nueva orden. Equivale a sli()

 Interrupts(), reactiva las interrupciones. Equivale a cli()


PROBANDO LAS INTERRUPCIONES EN
ARDUINO
Para probar las interrupciones en Arduino, vamos a emplear una salida digital de Arduino
para emular una señal digital. En el mundo real, sería otro dispositivo (un sensor, otro
procesador…) el que generaría esta señal, y nosotros la captaríamos con Arduino.

Conectamos mediante un cable el pin digital 10 al pin digital 2, asociado a la interrupción


0.

HACIENDO PARPADEAR UN LED A TRAVÉS DE


INTERRUPCIONES
En el siguiente código definimos el pin digital 10 como salida, para emular una onda
cuadrada de periodo 300ms (150ms ON y 150ms OFF).

Para visualizar el funcionamiento de la interrupción, en cada flanco activo del pulso


simulado, encendemos/apagamos el LED integrado en la placa, por lo que el LED parpadea a
intervalos de 600ms (300ms ON y 300ms OFF)
Puede que a estas alturas ver parpadear un LED no parezca muy espectacular, pero no es
tan simple como parece. No estamos encendiendo el LED con una salida digital, si no que es la
interrupción que salta la que enciende y apaga el LED (el pin digital solo emula una señal
externa).

1 const int emuPin = 10;


2
3 const int LEDPin = 13;
4 const int intPin = 2;
5 volatile int state = LOW;
6
7 void setup() {
8 pinMode(emuPin, OUTPUT);
9 pinMode(LEDPin, OUTPUT);
10 pinMode(intPin, INPUT_PULLUP);
11 attachInterrupt(digitalPinToInterrupt(intPin), blink, CHANGE);
12 }
13
14 void loop() {
15 //esta parte es para emular la salida
16 digitalWrite(emuPin, HIGH);
17 delay(150);
18 digitalWrite(emuPin, LOW);
19 delay(150);
20 }
21
22 void blink() {
23 state = !state;
24 digitalWrite(LEDPin, state);
25 }

CONTANDO DISPAROS DE UNA INTERRUPCIÓN


El siguiente código empleamos el mismo pin digital para emular una onda cuadrada, esta
vez de intervalo 2s (1s ON y 1s OFF).

En cada interrupción actualizamos el valor de un contador. Posteriormente, en el bucle


principal, comprobamos el valor del contador, y si ha sido modificado mostramos el nuevo
valor.

Al ejecutar el código, veremos que en el monitor serie se imprimen números consecutivos


a intervalos de dos segundos.
1 const int emuPin = 10;
2
3 const int intPin = 2;
4 volatile int ISRCounter = 0;
5 int counter = 0;
6
7
8 void setup()
9 {
10 pinMode(emuPin, OUTPUT);
11
12 pinMode(intPin, INPUT_PULLUP);
13 Serial.begin(9600);
14 attachInterrupt(digitalPinToInterrupt(intPin), interruptCount, LOW);
15 }
16
17 void loop()
18 {
19 //esta parte es para emular la salida
20 digitalWrite(emuPin, HIGH);
21 delay(1000);
22 digitalWrite(emuPin, LOW);
23 delay(1000);
24
25
26 if (counter != ISRCounter)
27 {
28 counter = ISRCounter;
29 Serial.println(counter);
30 }
31 }
32
33 void interruptCount()
34 {
35 ISRCounter++;
36 timeCounter = millis();
37 }
Lógicamente, nuestro objetivo es emplear interrupciones de hardware no solo con otros
dispositivos digitales, si no también con dispositivos físicoscomo pulsadores, sensores
ópticos…

Sin embargo, como hemos adelantado, estos dispositivos generan mucho ruido en los
cambios de estado, lo que provoca que las interrupciones se disparen múltiples veces. Este
fenómeno se denomina “rebote” y aprenderemos a eliminarlo en la siguiente entrada.
LEER UN PULSADOR
CON ARDUINO CON
INTERRUPCIONES Y
DEBOUNCE

4 MAYO, 2016

En la entrada anterior vimos qué son las interrupciones y cómo usarlas para responder a
eventos de hardware en pins.

También dejamos claro que los dispositivos físicos, como pulsadores, detectores ópticos,
etc, presentan un efecto rebote que interfiere con el uso de interrupciones, y que
necesitamos eliminarlo o no podremos usar interrupciones con estos dispositivos.

El proceso de eliminación de este rebote se llama “debounce”. En esta entrada


aprenderemos qué es el rebote y aprenderemos a eliminarlo con debounce por hardware y por
software.
¿QUÉ ES EL DEBOUNCE?
Los dispositivos electrónicos al cambiar de estado generan una señal que, sin ser
perfectamente cuadrada, en general es más o menos “limpia”. Veamos, por ejemplo, la señal
que genera Arduino al cambiar el estado de una salida digital de HIGH a LOW.

Sin embargo el mundo real no es tan bonito. Muchos dispositivos físicos


habitualmente generan ruido en los flancos de señal. Como ejemplo, veamos la variación de
tensión que ocurre cuando el cambio de estado se genera por un pulsador.

Anuncio:
Observar la cantidad de ruido ocurrido tras el flanco. En esencia, en el rango de unos
microsegundos la señal es puro ruido. Todos esos picos pueden provocar disparos múltiples
de una interrupción.

PROBANDO EL REBOTE
Para probar el rebote, simplemente vamos a emplear un cable para conectar el Pin 2 y
Ground (también podéis usar un pulsador o un interruptor).
Activamos la resistencia interna de Pull UP en el Pin 2 y definimos una interrupción al
evento de bajada en el PIN, y en la función ISR asociada simplemente incrementamos un
contador.

En el bucle principal, comprobamos si el contador, y si este ha sido modificado mostramos


su valor por el puerto serie.

1 const int intPin = 2;


2 volatile int ISRCounter = 0;
3 int counter = 0;
4
5
6 void setup()
7 {
8 pinMode(intPin, INPUT_PULLUP);
9 Serial.begin(9600);
10 attachInterrupt(digitalPinToInterrupt(intPin), debounceCount, LOW);
11 }
12
13 void loop()
14 {
15 if (counter != ISRCounter)
16 {
17 counter = ISRCounter;
18 Serial.println(counter);
19 }
20 }
21
22 void debounceCount()
23 {
24 ISRCounter++;
25 }
Al probar nuestro montaje y poner en contacto el PIN 2 a GROUND, esperaríamos que la
variable se incrementara de uno en uno. Pero veremos que en realidad salta varios números
cada vez (incluso varias decenas).

Este es el efecto del rebote. El ruido de la señal está generando múltiples interrupciones
cada vez que conectamos el cable.

ELIMINANDO EL REBOTE
Disponemos de dos formas de aplicar el debounce. Añadiendo dispositivos electrónicos
que filtren la señal (debounce por hardware) o modificando nuestro código para eliminar el
rebote (debounce por hardware).

DEBOUNCE POR HARDWARE


Aplicar un debounce por hardware tiene la ventaja de no incrementar el tiempo de
ejecución de nuestro código. Además, en general, es una solución más robusta. Por contra, tiene
la desventaja de aumentar la complejidad de nuestro montaje.

La forma más sencilla de aplicar un debounce por hardware es colocar un condensador


en paralelo con el dispositivo (pulsador, interruptor, sensor…). Un condensador del orden de
1uF debería ser suficiente para filtrar la mayoría del ruido.

El esquema de conexión es el siguiente.


En general siempre es conveniente añadir un filtro por hardware cuando empleamos entradas
físicas con interrupciones.

DEBOUNCE POR SOFTWARE


El debounce por software tiene la ventaja de no requerir componentes adicionales.
Resolvemos el rebote únicamente modificando el código de nuestro programa.

Como desventaja, incrementa levemente el tiempo de ejecución y la complejidad del


código. Además, si no aplicamos el código correctamente podemos ignorar interrupciones
“verdaderas”.

La forma más sencilla de aplicar un debounce por software es comprobar el tiempo entre
disparos de la interrupción. Si el tiempo es inferior a un determinado umbral de tiempo
(threshold) simplemente ignoramos la interrupción. En definitiva, hemos definido una “zona
muerta” en la que ignoramos las interrupciones generadas.

Para aplicar el debounce por software, modificamos la función ISR de la siguiente forma.
1 const int timeThreshold = 150;
2 const int intPin = 2;
3 volatile int ISRCounter = 0;
4 int counter = 0;
5 long timeCounter = 0;
6
7
8 void setup()
9 {
10 pinMode(intPin, INPUT_PULLUP);
11 Serial.begin(9600);
12 attachInterrupt(digitalPinToInterrupt(intPin), debounceCount, FALLING);
13 }
14
15 void loop()
16 {
17 if (counter != ISRCounter)
18 {
19 counter = ISRCounter;
20 Serial.println(counter);
21 }
22 }
23
24 void debounceCount()
25 {
26 if (millis() > timeCounter + timeThreshold)
27 {
28 ISRCounter++;
29 timeCounter = millis();
30 }
31 }
Un tiempo de 100-200ms es correcto para un pulsador pero en otros casos deberemos
ajustar el tiempo de forma que eliminemos el rebote, pero no ignoremos dos posibles eventos
cercanos “verdaderos”.

En un montaje real, lo mejor es emplear una combinación de ambos sistemas, a la vez


que ajustamos correctamente el valor del condensados y los tiempos del filtro por software para
adaptarlos a nuestro sistema.
Pulsadores y antirrebote con Arduino
el enero 07, 2017

Utilizando pulsadores con Arduino

¿Qué es un pulsador?

Un pulsador es un tipo de interruptor eléctrico, que consta de dos contactos

metálicos separados que cuando se unen al ser presionado el botón, permiten el

paso de corriente. Su simbología es la siguiente:

Existen dos formas de conectar un pulsador, y a pesar de que la función

principal es la misma, a la hora de programar es necesario tener en cuenta dicha

conexión:
Como se puede observar, están las configuraciones de:

 Pull Up: En este caso cuando se presiona el pulsador, el Arduino "ve" o

lee un cero en ese pin

 Pull Down: En este caso cuando se presiona el pulsador, el Arduino "ve"


o lee un uno en ese pin.

En este proyecto, y en los que siguen de ahora en adelante, se utilizará el

esquema correspondiente a Pull Up, donde el Arduino va a leer un 0 al

presionar un pulsador.

Los pulsadores son dispositivos que tienen un defecto, el cual se llama rebote.
Cuando se presiona o se suelta el pulsador, se produce una fluctuación entre sus
contactos internos, por lo tanto cuando se va a pasar de un 1 (HIGH) a un 0

(LOW) o viceversa, esas fluctuaciones son también leídas por el Arduino y se

produce un comportamiendo inesperado en el funcionamiento de nuestros

proyectos, por ejemplo, el usuario puede presionar una sola vez el pulsador pero

por culpa del rebote el Arduino podría interpretarlo como si se hubiese

presionado varias veces.

El antirrebote viene a solucionar este problema. Puede realizarse por software y

por hardware. En todos los proyectos de este blog se realizarán ambos tipos de

antirrebote al mismo tiempo, para tener seguridad de que ningún pulsador va a

producir un comportamiento indeseado.


Por software, se coloca un condicional en donde una variable cambia

su valor cuando el pulsador se presiona, es decir, cuando se encuentra en LOW.

Luego de que la variable tenga su nuevo valor y cuando se suelte el pulsador, se

realiza entonces la acción deseada en el proyecto.

if (digitalRead(pulsador) == LOW) //Pregunta si el pulsador está presionado

presionado = 1; //La variable cambia de valor

if (digitalRead(pulsador) == HIGH && presionado == 1)

//Realiza la acción deseada

presionado = 0; //La variable vuelve a su valor original

Es necesario poner un condensador de 10uF en el pulsador. Esto es para realizar

un antirrebote por hardware, el cual es muy efectivo. El circuito quedaría así

para la configuración en Pull Up:


Con el método del software mas el del hardware, habremos realizado un

antirrebote muy efectivo sin necesidad de estar usando delays que retarden el

funcionamiento de nuestro programa.


ISPLAY MÚLTIPLE DE 7
SEGMENTOS
28 febrero, 2014 Vicente García
PROLOGO.
Quien no dispone en su cajón desastre, de un conjunto de display a LED con
dos, tres o cuatro dígitos. Este es el momento de reutilizar dicho display
(multiplexado) en un contador cuya aplicación puede mejorar una presentación
que tenía pendiente. En este artículo, veremos como aplicar código a un display
multiplexado y como debe funcionar.

INICIANDO.
Actualmente es fácil encontrar en Internet códigos sobre pantallas LCD y cómo
adaptarlas a distintas aplicaciones. En cambio, son muy pocos los sitios donde
se describe cómo utilizar un display de siete segmentos y no digamos, cuando se
trata de conjuntos de displays de 2, 3 o 4 dígitos multiplexados. Sin embargo,
este dispositivo es bastante común en un gran número de electrodomésticos que
podemos desguazar y reutilizar su display. Aquí, con este artículo, voy a intentar
rellenar esta laguna.
Este artículo, no se puede considerar como una extensión a uno anterior que
puede verse aquí. En aquella ocasión se contemplaba el caso de aplicar el
contador de dos dígitos, como contador en una aplicación del propio Arduino
que, como ejercicio es esclarecedor y consigue ayudar el interesado en realizar
un contador de esas características. En esta ocasión, si bien, puede utilizarse con
unos pequeños ajustes, del mismo modo, la diferencia radica en que se
visualizará la cuenta obtenida reflejada en un pantalla o display de dos, tres o
cuatro dígitos de siete segmentos a LED, mediante la multiplexación de los
dígitos utilizados. Esta es la estructura del display múltiple.

Estructura
Sin más, vamos a entrar en harina, como diría un panadero. La teoría, se puede
ver en el mencionado artículo, así que sólo nos preocuparemos de los tipos de
pantalla a utilizar, para este caso usaremos un display múltiple (multiplexado).
El display que vamos a utilizar aquí, tiene la particularidad en su encapsulado,
es decir, que en una pieza ( o encapsulado) nos presenta varios dígitos. Tenemos
que tener en cuenta que en algunos casos, las patillas que vienen en el
encapsulado, parece que no están bien, ya que hay menos de las que se supone
debería tener, esto es debido a que se han dispuesto de forma especial, lo que se
llama multiplexado.
EL PROGRAMA.
La cuestión importante radica en el propio programa. El programa consta de 3
partes bien diferenciadas:

1. Los displays, definición propia de los segmentos, de como se constituyen los dígitos
(estructura interna).
2. La asignación y correspondencia de los pines del display, del Arduino y pulsadores, para su
aplicación sin posteriores consultas por ese motivo.
3. Rutinas, además de la configuración (Set up), dentro del lazo (loop) se encuentran las
subrutinas pertenecientes a los pulsadores.

LOS DISPLAYS.
No voy a describir con detalle cómo se construye un display, más arriba se
puede ver su estructura. El display que voy a utilizar en este artículo, es el de un
display multiplexado, es decir, que sus segmentos están conectados
internamente de tal manera que al exterior sólo aparecen (normalmente) los
correspondientes a los siete segmentos, más el común de cada uno de los dígitos
que lo componen, en el caso de cuatro dígitos, muestra los siete pines de los
siete segmentos, más cuatro correspondientes a cada uno de los cuatro dígitos.
Estos son, unos ejemplos de encapsulados.
Hay que tener en cuenta que podemos encontrar estos displays en cátodo
común y en ánodo común. Si usted, no dispone de un encapsulado de este tipo y
está interesado en poner en práctica un contador de los descritos aquí y en
cambio, si dispone de los display individuales, tranquilo, usted puede auto
construir uno fácilmente, con los dígitos que necesite, vea cómo está construido
el de 2 dígitos, de abajo y póngase a su construcción.

Se pueden apreciar con todo detalle, los dos cablecillos blancos que son los
comunes de cada dígito, por otra parte los siete hilos rojos, corresponden a los 7
segmentos, los cuales unen entre sí, los pares de segmentos (porque son dos) de
cada dígito en paralelo. Recuerde utilizar todos en ánodo o cátodo común.

CIRCUITO DE 1 DÍGITO.
El circuito de montaje de encendido de un dígito, es muy simple, se muestra a
continuación y debajo el código.
El código es igual de sencillo, se ha incluido el Dp (pin digital point), por ese
motivo se ha añadido la octava resistencia. La secuencia enciende y apaga cada
segmento y luego una secuencia de los 7 al tiempo. Por cierto, el display es un
ánodo común FND507 que tenía a mano.
Encendido de 7 segmentos.

1 // Creado por V. García 26.02.2014


2 //
3 // definimos los 7 segmentos y los asignamos a los pines
4 int A = 2;
5 int B = 3;
6 int C = 4;
7 int D = 5;
8 int E = 6;
9 int F = 7;
10 int G = 8;
11 int Dp = 9;
12
13 // Configuramos los pines.
14 void setup() {
15 pinMode (A, OUTPUT);
16 pinMode (B, OUTPUT);
17 pinMode (C, OUTPUT);
18 pinMode (D, OUTPUT);
19 pinMode (E, OUTPUT);
20 pinMode (G, OUTPUT);
21 pinMode (F, OUTPUT);
22 pinMode (Dp, OUTPUT);
23 }
24
25 // Y encendemos los segmentos.
26 void loop() {
27 digitalWrite(A, HIGH);
28 delay(300);
29 digitalWrite(A, LOW);
30 delay(300);
31 digitalWrite(B, HIGH);
32 delay(300);
33 digitalWrite(B, LOW);
34 delay(300);
35 digitalWrite(C, HIGH);
36 delay(300);
37 digitalWrite(C, LOW);
38 delay(300);
39 digitalWrite(D, HIGH);
40 delay(300);
41 digitalWrite(D, LOW);
42 delay(300);
43 digitalWrite(E, HIGH);
44 delay(300);
45 digitalWrite(E, LOW);
46 delay(300);
47 digitalWrite(F, HIGH);
48 delay(300);
49 digitalWrite(F, LOW);
50 delay(300);
51 digitalWrite(G, HIGH);
52 delay(300);
53 digitalWrite(G, LOW);
54 delay(300);
55 digitalWrite(Dp, HIGH);
56 delay(300);
57 digitalWrite(Dp, LOW);
58 delay(600);
59
60 digitalWrite(A, HIGH);
61 digitalWrite(B, HIGH);
62 digitalWrite(C, HIGH);
63 digitalWrite(D, HIGH);
64 digitalWrite(E, HIGH);
65 digitalWrite(F, HIGH);
66 digitalWrite(G, HIGH);
67 delay(600);
68 digitalWrite(A, LOW);
69 digitalWrite(B, LOW);
70 digitalWrite(C, LOW);
71 digitalWrite(D, LOW);
72 digitalWrite(E, LOW);
73 digitalWrite(F, LOW);
74 digitalWrite(G, LOW);
75 delay(600);
76 }
Por supuesto que este código se puede reducir, sin embargo, he querido
mostrarlo de esta forma para que los que se inician puedan seguirlo con mayor
facilidad.
CIRCUITO DE 2 DÍGITOS.
El circuito se muestra a continuación. Es muy sencillo y no creo necesario entrar
a describir cada componente. Dos apuntes importantes:

 Este mismo circuito, con sólo añadir unas resistencias, nos sirve, para el resto de ejemplos
que se describen.
 Los pines analógicos del Arduino (A0…A6), pueden tomarse como digitales, siguiendo el
orden, A0 = A14; A1 = A15; … A6 = A19.

1 . EJEMPLO.
ER

Esta es una primera versión y su correspondiente código realizado con Arduino


v.013 y v.023. El display utilizado para este caso es de cátodo común (CC).
Como de costumbre, puede seleccionar el código y pegarlo en su editor dándole
un nombre para guardarlo y su posterior ejecución.

CONTADOR CON DOS DISPLAY DE 7 SEGMENTOS.

1 //
2 // Doble Didplay siete-segmentos LED con botones
3 //
4 // Basado en un trabajo de Natalia Fargasch Norman
5 //
6 //
7 // Common Catode digit 1 pin 10
8 // Common Catode digit 2 pin 5
9 //
10 // Modificado y mejorado 11.08.11
11 // V. García
12 //
13 // Utiliza 2202 bytes con Arduino v0013
14
15 // CA1 G F A B
16 // | | | | | | -> pines y segmentos de control
17 // --------- ---------
18 // | A | | A |
19 // F| |B F| |B
20 // |---G---| |---G---|
21 // E| |C E| |C
22 // | D | | D |
23 // --------- ---------
24 // | | | | | | -> pines y segmentos de control
25 // D DP E C CA2
26
27 // Composición de los digitos en Segmentos
28 // 0 => -FEDCBA
29 // 1 => ----BC-
30 // 2 => G-ED-BA
31 // 3 => G--DCBA
32 // 4 => GF--CB-
33 // 5 => GF-DC-A
34 // 6 => GFEDC-A
35 // 7 => ----CBA
36 // 8 => GFEDCBA
37 // 9 => GF-DCBA
38
39 // Pines digitales usados Arduino para encender
40 // los correspondientes segmentos LED del display
41 #define A 2
42 #define B 3
43 #define C 4
44 #define D 5
45 #define E 6
46 #define F 7
47 #define G 8
48
49 // Pulsadoes boton conectados a pines 9 y 10
50 #define BTN1 14
51 #define BTN2 15
52 #define led 13
53 // Pines comunes de cada display de anodo comun
54 #define CA1 9
55 #define CA2 10
56
57 // Pines para A B C D E F G, en secuencia
58 // se pueden usar los que más interesen
59 const int segs[7] = { 2, 3, 4, 5, 6, 7, 8 };
60
61 // Segmentos que componen cada número
62 // Para CC.
63 const byte numbers[10] = { 0b0111111, 0b0000110, 0b1011011, 0b1001111, 0b1100110,
64 0b1101101, 0b1111101, 0b0000111, 0b1111111, 0b1101111};
65 // Para CA. descomentar las 2 líneas que siguen.
66 // const byte numbers[10] = { 0b1000000, 0b1111001, 0b0100100, 0b0110000, 0b0011001, 0b0010010,
67 // 0b0000010, 0b1111000, 0b0000000, 0b0010000};
68
69 int digit1 = 0;
70 int digit2 = 0;
71
72 void setup()
73 {
74 pinMode(A, OUTPUT);
75 pinMode(B, OUTPUT);
76 pinMode(C, OUTPUT);
77 pinMode(D, OUTPUT);
78 pinMode(E, OUTPUT);
79 pinMode(F, OUTPUT);
80 pinMode(G, OUTPUT);
81 pinMode(BTN1, INPUT);
82 pinMode(BTN2, INPUT);
83 digitalWrite(BTN1, HIGH); // activa RPA
84 digitalWrite(BTN2, HIGH); // activa RPA
85 pinMode(CA1, OUTPUT);
86 pinMode(CA2, OUTPUT);
87 pinMode(led, OUTPUT);
88
89 // digit1 = 9; digit2 = 9;
90
91 }
92
93 void loop()
94 {
95 // chequea boton1. Incrementa
96 int val1 = digitalRead(BTN1);
97 if (val1 == LOW)
98 {
99 if (digit2 >= 9 && digit1 >= 9)
100 {
101 digit2 = 0;
102 digit1++;
103 digit1 %= 10;
104 if (digit1 >=9)
105 {
106 digit2++;
107 }
108 } else if (digit1 >= 9)
109 {
110 digit2++;
111 digit2 %= 10;
112 }
113 digit1++;
114 digit1 %= 10;
115 delay(10);
116 }
117
118 // cheque boton2. Decrementa
119 int val2 = digitalRead(BTN2);
120 if (val2 == LOW)
121 {
122 if (digit1 >= 0)
123 {
124 if (digit1 < 0)
125 {
126 digit1 = 0;
127 }
128 digit1--;
129 }
130 if(digit1 < 0)
131 {
132 digit1 = 9;
133 if (digit2 < 0)
134 {
135 digit2 = 0;
136 }
137 digit2--;
138 }
139 if (digit2 < 0)
140 {
141 digit2 = 9;
142 }
143 }
144
145 // display numero
146 unsigned long startTime = millis();
147 for (unsigned long elapsed=0; elapsed < 300; elapsed = millis() - startTime)
148 {
149 lightDigit1(numbers[digit1]);
150 delay(5);
151 lightDigit2(numbers[digit2]);
152 delay(5);
153 }
154 }
155
156 void lightDigit1(byte number)
157 {
158 digitalWrite(CA1, LOW);
159 digitalWrite(CA2, HIGH);
160 lightSegments(number);
161 }
162
163 void lightDigit2(byte number)
164 {
165 digitalWrite(CA1, HIGH);
166 digitalWrite(CA2, LOW);
167 lightSegments(number);
168 }
169
170 void lightSegments(byte number)
171 {
172 for (int i = 0; i < 7; i++)
173 {
174 int bit = bitRead(number, i);
175 digitalWrite(segs[i], bit);
176 }
177 }

2º EJEMPLO.
En este segundo ejemplo, voy a utilizar otra forma de resolver el programa y
además aprovechando que dispongo de un display múltiple de 4 dígitos, haré un
contador de dos dígitos.
El circuito electrónico es similar al del ejemplo anterior, con unos pocos
cambios, por lo que no lo mostraré aquí. El código se muestra a continuación.

CONTADOR 2 X 7 SEGMENTOS Y 2 BOTONES.

1 //
2 // Doble Didplay siete-segmentos LED con botones
3 //
4 // Basado en un trabajo de Natalia Fargasch Norman
5 //
6 //
7 // Common Catode digit 1 pin 10
8 // Common Catode digit 2 pin 5
9 //
10 // Modificado y mejorado 11.08.11
11 // V. García
12 //
13 // Utiliza 2138 bytes con Arduino v0013
14
15 //
16 // CA1 G F A B
17 // | | | | | -> pins and segments they control
18 // --------- ---------
19 // | A | | A |
20 // F| |B F| |B
21 // |---G---| |---G---|
22 // E| |C E| |C
23 // | D | | D |
24 // --------- ---------
25 // | | | | | -> pins and segments they control
26 // D DP E C CA2
27
28 // Composición de los digitos en Segmentos
29 // 0 => -FEDCBA
30 // 1 => ----BC-
31 // 2 => G-ED-BA
32 // 3 => G--DCBA
33 // 4 => GF--CB-
34 // 5 => GF-DC-A
35 // 6 => GFEDC-A
36 // 7 => ----CBA
37 // 8 => GFEDCBA
38 // 9 => GF-DCBA
39
40 // Pines digitales usados Arduino para encender
41 // los correspondientes segmentos LED del display
42 #define A 2
43 #define B 3
44 #define C 4
45 #define D 5
46 #define E 6
47 #define F 7
48 #define G 8
49
50 // Pulsadoes boton conectados a pines 9 y 10
51 #define BTN1 14
52 #define BTN2 15
53 #define led 13
54 // Pines comunes de cada display de anodo comun
55 #define CC1 12
56 #define CC2 11
57
58 int estadobtn1 = 0;
59 int estadobtn2 = 0;
60 int count = 0;
61
62 // Pines para A B C D E F G, en secuencia
63 // se pueden usar los que más interesen
64 const int segs[7] = { 2, 3, 4, 5, 6, 7, 8 };
65
66 // Segmentos que componen cada número
67 const byte numbers[10] = { 0b0111111, 0b0000110, 0b1011011, 0b1001111, 0b1100110,
68 0b1101101, 0b1111101, 0b0000111, 0b1111111, 0b1101111};
69
70 int digit1 = 0;
71 int digit2 = 0;
72
73 void setup() {
74 pinMode(A, OUTPUT);
75 pinMode(B, OUTPUT);
76 pinMode(C, OUTPUT);
77 pinMode(D, OUTPUT);
78 pinMode(E, OUTPUT);
79 pinMode(F, OUTPUT);
80 pinMode(G, OUTPUT);
81 pinMode(BTN1, INPUT);
82 pinMode(BTN2, INPUT);
83 digitalWrite(BTN1, HIGH); // activa RPA
84 digitalWrite(BTN2, HIGH); // activa RPA
85 pinMode(CC1, OUTPUT);
86 pinMode(CC2, OUTPUT);
87 pinMode(led, OUTPUT);
88 // digit1 = 9; digit2 = 9; // para depurar
89 }
90
91 void loop()
92 {
93 // chequea boton1. Incrementa
94 int val1 = digitalRead(BTN1);
95 if (val1 == LOW)
96 {
97 if (digit1 >= 9 ) { digit1 ++; } if (digit1 > 9)
98 {
99 digit1 = 0;
100 digit2++;
101 if (digit2 > 9)
102 {
103 digit2 = 0;
104 }
105 }
106 }
107
108 // cheque boton2. Decrementa
109 int val2 = digitalRead(BTN2);
110 if (val2 == LOW)
111 {
112 if (digit1 >= 0)
113 {
114 if (digit1 < 0)
115 {
116 digit1 = 0;
117 }
118 digit1--;
119 }
120 if(digit1 < 0)
121 {
122 digit1 = 9;
123 if (digit2 < 0)
124 {
125 digit2 = 0;
126 }
127 digit2--;
128 }
129 if (digit2 < 0)
130 {
131 digit2 = 9;
132 }
133 }
134
135 // display numero
136 unsigned long startTime = millis();
137 for (unsigned long elapsed=0; elapsed < 200; elapsed = millis() - startTime) {
138 lightDigit1(numbers[digit1]);
139 delay(5);
140 lightDigit2(numbers[digit2]);
141 delay(5);
142 }
143 }
144
145 void lightDigit1(byte number) {
146 digitalWrite(CC1, LOW);
147 digitalWrite(CC2, HIGH);
148 lightSegments(number);
149 }
150
151 void lightDigit2(byte number) {
152 digitalWrite(CC1, HIGH);
153 digitalWrite(CC2, LOW);
154 lightSegments(number);
155 }
156
157 void lightSegments(byte number) {
158 for (int i = 0; i < 7; i++) {
159 int bit = bitRead(number, i);
160 digitalWrite(segs[i], bit);
161 }
162 }
Este ejemplo, muestra un código mejorado al representado en el primer
ejemplo. Como puede apreciarse, he utilizado los mismos pines del Arduino, en
cada ejemplo. Con esto, trato de minorar los errores de asignación en los
distintos listados de código.

PROBLEMAS A CAUSA DEL MULTIPLEXADO.


El problema que se puede encontrar el programador, frente a una
representación por multiplexado, radica en los tiempos de muestreo de cada
dígito, por este motivo, recomiendo que se tenga en cuenta, diría, muy en
cuenta, no utilizar o minimizar los delay(), ya que éstos, tienden a producir el
efecto de “parpadeo” que se aprecia en los dígitos.
En un multiplexado, siempre se producirá un parpadeo, aunque éste sea poco
apreciable, cuantos más dígitos se muestren, más evidente se hará. Por ese
motivo hay que reducir en lo posible los tiempos de muestreo.

3ER. EJEMPLO.
Voy a presentar el código de un contador de 3 dígitos en un display de 7
segmentos LED. El lector, puede apreciar las pocas diferencias que se presentan
en este código. Un punto a tener en en cuenta, se encuentra precisamente en la
rutina de asignación de encendido de cada dígito, representados por digit1,
digit2 y digit3, con sus fórmulas.
CONTADOR 3 DISPLAYS DE 7 SEGMENTOS.

1 //
2 // Basado en un trabajo de: Natalia Fargasch Norman
3 //
4 // Modificado y actualizado por Vins el 12.08.11
5 //
6 // Three seven-segment LED Display with buttons
7 // Common Catode digit 1
8 // Common Catode digit 2
9
10 // CA1 G F A B
11 // | | | | | -> pins and segments they control
12 // --------- ---------
13 // | A | | A |
14 // F| |B F| |B
15 // |---G---| |---G---|
16 // E| |C E| |C
17 // | D | | D |
18 // --------- ---------
19 // | | | | | -> pins and segments they control
20 // D DP E C CA2
21 // Segments that make each number when lit:
22 // 0 => -FEDCBA
23 // 1 => ----BC-
24 // 2 => G-ED-BA
25 // 3 => G--DCBA
26 // 4 => GF--CB-
27 // 5 => GF-DC-A
28 // 6 => GFEDC-A
29 // 7 => ----CBA
30 // 8 => GFEDCBA
31 // 9 => GF-DCBA
32 // Arduino digital pins used to light up
33 // corresponding segments on the LED display
34 #define A 2
35 #define B 3
36 #define C 4
37 #define D 5
38 #define E 6
39 #define F 7
40 #define G 8
41 // Pushbuttons connected to pins 9 and 10
42 #define BTN1 14
43 #define BTN2 15
44 #define led 13
45
46 // Pins driving common anodes
47 #define CA1 9
48 #define CA2 10
49 #define CA3 11
50
51 // Pins for A B C D E F G, in sequence
52 const int segs[7] = { 2, 3, 4, 5, 6, 7, 8 };
53
54 // Segments that make each number
55 const byte numbers[10] = { 0b0111111, 0b0000110, 0b1011011, 0b1001111, 0b1100110,
56 0b1101101, 0b1111101, 0b0000111, 0b1111111, 0b1101111};
57 int estadobtn1 = 0;
58 int estadobtn2 = 0;
59 int digit1 = 0;
60 int digit2 = 0;
61 int digit3 = 0;
62 int count = 0;
63 int val;
64 int val2;
65
66 void setup() {
67 pinMode(A, OUTPUT);
68 pinMode(B, OUTPUT);
69 pinMode(C, OUTPUT);
70 pinMode(D, OUTPUT);
71 pinMode(E, OUTPUT);
72 pinMode(F, OUTPUT);
73 pinMode(G, OUTPUT);
74 pinMode(BTN1, INPUT);
75 pinMode(BTN2, INPUT);
76 pinMode(CA1, OUTPUT);
77 pinMode(CA2, OUTPUT);
78 pinMode(CA3, OUTPUT);
79 digitalWrite(BTN1, HIGH); // activa RPA
80 digitalWrite(BTN2, HIGH); // activa RPA
81 count = 0;
82 }
83 void loop() {
84 // incrementa
85 val = digitalRead(BTN1); // lee el valor de entrada y almacénelo en val
86 if (val != estadobtn1) // el estado de botón ha cambiado!
87 {
88 if (val == LOW) // compruebe si el botón es presionado
89 {
90 count++;
91 count %= 1000;
92 }
93 }
94 estadobtn1=val;
95
96 // decrementa
97 val = digitalRead(BTN2); // lee el valor de entrada y almacénelo en val
98 if (val != estadobtn2) // el estado de botón ha cambiado!
99 {
100 if (val == LOW) // compruebe si el botón es presionado
101 {
102 if (count == 0)
103 {
104 count=999;
105 } else
106 {
107 count--;
108 }
109 }
110 }
111 estadobtn2=val;
112
113 // display number
114 digit1=count / 100;
115 digit2=(count - (digit1*100)) / 10;
116 digit3=count % 10;
117 //
118 lightDigit1(numbers[digit1]);
119 delay(2);
120 lightDigit2(numbers[digit2]);
121 delay(2);
122 lightDigit3(numbers[digit3]);
123 delay(2);
124 }
125 void lightDigit1(byte number) {
126 digitalWrite(CA1, LOW);
127 digitalWrite(CA2, HIGH);
128 digitalWrite(CA3, HIGH);
129 lightSegments(number);
130 }
131 void lightDigit2(byte number) {
132 digitalWrite(CA1, HIGH);
133 digitalWrite(CA2, LOW);
134 digitalWrite(CA3, HIGH);
135 lightSegments(number);
136 }
137
138 void lightDigit3(byte number) {
139 digitalWrite(CA1, HIGH);
140 digitalWrite(CA2, HIGH);
141 digitalWrite(CA3, LOW);
142 lightSegments(number);
143 }
144
145 void lightSegments(byte number) {
146 for (int i = 0; i < 7; i++) {
147 int bit = bitRead(number, i);
148 digitalWrite(segs[i], bit);
149 }
150 }
Veamos la importancia que tiene la reducción de lo que yo llamo tiempos
muertos, probemos a modificar estas líneas, simplemente, comentemos las que
aquí se muestran, compilemos y carguemos el programa en el Arduino:

1 // incrementa + + + +
2 val = digitalRead(BTN1); // lee el valor de entrada y almacénalo en val
3 // delay(4); // 10 milisegundos son una buena cantidad de tiempo
4 // val2 = digitalRead(BTN1); // lee la entrada otra vez para comprobar saltos
5 // if (val == val2) // asegurar que conseguimos 2 lecturas constantes
6 // {
7 if (val != estadobtn1) // el estado de botón ha cambiado!
8 {
9 if (val == LOW) <span style="color: #009900;"> // compruebe si el botón es presionado
10 {
11 count++;
12 count %= 1000;
13 }
14 }
15 estadobtn1=val;
16 // }
17
18 // decrementa - - - -
19 val = digitalRead(BTN2); // lee el valor de entrada y almacenalo en val
20 // delay(4); // 10 milisegundos son una buena cantidad de tiempo
21 // val2 = digitalRead(BTN2); // lee la entrada otra vez para comprobar saltos
22 // if (val == val2) // asegurar que conseguimos 2 lecturas constantes
23 // {
24 if (val != estadobtn2) // el estado de botón ha cambiado!
25 {
26 if (val == LOW) // compruebe si el botón es presionado
27 {
28 if (count == 0)
29 {
30 count=999;
31 } else
32 {
33 count--;
34 }
35 }
36 }
37 estadobtn2=val;
38 // } </span>
Habrá comprobado que ahora el parpadeo no parece afectar a la normal visión
del contador. A esto es, a lo que me refería, con llevar cuidado al programar,
evitando rutinas que tomen excesivo tiempo en tareas que retengan el normal
desarrollo del microprocesador.
Ahora, puede eliminar de su código, las líneas que ha comentado, guarde el
archivo, compile y cargue el programa en el Arduino y finalmente compruebe
que la solución es la esperada.

4º EJEMPLO.
En este ejemplo, vamos a utilizar los cuatro dígitos del encapsulado del display
(es uno que tenía de una impresora). En este programa la tarea de multiplexar
se dedica a cuatro displays, lo que puede llevar algún problema si no se vigilan
los tiempos. Si no utilizamos bien las rutinas, aparecerán dos consecuencias, el
parpadeo y una notable bajada de luminosidad de los dígitos.
Veamos el listado del código, estos listados están probados y sin duda funcionan
como se espera de ellos.

CONTADOR CON 4 DISPLAYS DE 7 SEGMENTOS.


1 /*
2 *
3 * Esta es la colaboración que a
4 * modificado y mejorado por Vins el 12.08.11
5 *
6 * Four seven-segment LED Display with two buttons
7 * Un botón incrementa la cuenta. Otro botón decrementa la cuenta.
8
9 * Common Catode digit 1 pin 10
10 * Common Catode digit 2 pin 5
11
12 // CC1 A F CC3 CC2 B
13 // | | | | | | -> pins and segments they control
14 // --------- --------- --------- ---------
15 // | A | | A | | A | | A |
16 // F| |B F| |B F| |B F| |B
17 // |---G---| |---G---| |---G---| |---G---|
18 // E| |C E| |C E| |C E| |C
19 // | D | | D | | D | | D |
20 // --------- --------- --------- ---------
21 // | | | | | | -> pins and segments they control
22 // E D C G CC4
23
24 // Segments that make each number when lit:
25 // 0 => -FEDCBA
26 // 1 => ----BC-
27 // 2 => G-ED-BA
28 // 3 => G--DCBA
29 // 4 => GF--CB-
30 // 5 => GF-DC-A
31 // 6 => GFEDC-A
32 // 7 => ----CBA
33 // 8 => GFEDCBA
34 // 9 => GF-DCBA
35 */
36
37 // Arduino digital pins used to light up
38 // corresponding segments on the LED display
39 #define A 2
40 #define B 3
41 #define C 4
42 #define D 5
43 #define E 6
44 #define F 7
45 #define G 8
46
47 // Pushbuttons connected to pins 9 and 10
48 #define BTN1 14
49 #define BTN2 15
50
51 // Pins driving common anodes
52 #define CC1 9
53 #define CC2 10
54 #define CC3 11
55 #define CC4 12
56 // Pins for A B C D E F G, in sequence
57 const int segs[7] = { 2, 3, 4, 5, 6, 7, 8 };
58
59 // Segments that make each number
60 const byte numbers[10] = { 0b0111111, 0b0000110, 0b1011011, 0b1001111, 0b1100110, 0b1101101,
61 0b1111101, 0b0000111, 0b1111111, 0b1101111};
62
63 int estadobtn1 = 0;
64 int estadobtn2 = 0;
65 int digit1 = 0;
66 int digit2 = 0;
67 int digit3 = 0;
68 int digit4 = 0;
69 int count = 0;
70 int val;
71 int val2;
72
73 void setup() {
74 pinMode(A, OUTPUT);
75 pinMode(B, OUTPUT);
76 pinMode(C, OUTPUT);
77 pinMode(D, OUTPUT);
78 pinMode(E, OUTPUT);
79 pinMode(F, OUTPUT);
80 pinMode(G, OUTPUT);
81 pinMode(BTN1, INPUT);
82 pinMode(BTN2, INPUT);
83 digitalWrite(BTN1, HIGH); // activa RPA
84 digitalWrite(BTN2, HIGH); // activa RPA
85 pinMode(CC1, OUTPUT);
86 pinMode(CC2, OUTPUT);
87 pinMode(CC3, OUTPUT);
88 pinMode(CC4, OUTPUT);
89 count = 0;
90 }
91
92 void loop() {
93 val = digitalRead(BTN1); // lee el valor de entrada y almacénlo en val
94 if (val != estadobtn1) // el estado de botón ha cambiado!
95 {
96 if (val == LOW) // compruebe si el botón es presionado
97 {
98 count++;
99 count %= 10000;
100 }
101 }
102 estadobtn1=val;
103
104 val = digitalRead(BTN2); // lee el valor de entrada y almacénlo en val
105 if (val != estadobtn2) // el estado de botón ha cambiado!
106 {
107 if (val == LOW) // compruebe si el botón es presionado
108 {
109 if (count == 0)
110 {
111 count=9999;
112 } else {
113 count--;
114 }
115 }
116 estadobtn2=val;
117 }
118 // display number
119 digit1=count / 1000;
120 digit2=(count - (digit1 * 1000)) / 100;
121 digit3=(count - (digit1*1000) - (digit2*100)) / 10;
122 digit4=count % 10;
123
124 lightDigit1(numbers[digit1]);
125 delay(2);
126 lightDigit2(numbers[digit2]);
127 delay(2);
128 lightDigit3(numbers[digit3]);
129 delay(2);
130 lightDigit4(numbers[digit4]);
131 delay(2);
132 }
133
134 void lightDigit1(byte number) {
135 digitalWrite(CC1, LOW);
136 digitalWrite(CC2, HIGH);
137 digitalWrite(CC3, HIGH);
138 digitalWrite(CC4, HIGH);
139 lightSegments(number);
140 }
141
142 void lightDigit2(byte number) {
143 digitalWrite(CC1, HIGH);
144 digitalWrite(CC2, LOW);
145 digitalWrite(CC3, HIGH);
146 digitalWrite(CC4, HIGH);
147 lightSegments(number);
148 }
149
150 void lightDigit3(byte number) {
151 digitalWrite(CC1, HIGH);
152 digitalWrite(CC2, HIGH);
153 digitalWrite(CC3, LOW);
154 digitalWrite(CC4, HIGH);
155 lightSegments(number);
156 }
157
158 void lightDigit4(byte number) {
159 digitalWrite(CC1, HIGH);
160 digitalWrite(CC2, HIGH);
161 digitalWrite(CC3, HIGH);
162 digitalWrite(CC4, LOW);
163 lightSegments(number);
164 }
165
166 void lightSegments(byte number) {
167 for (int i = 0; i < 7; i++) {
168 int bit = bitRead(number, i);
169 digitalWrite(segs[i], bit);
170 }
}
A demás de lo comentado, el punto delicado de este sistema de multiplexado
está en la elección correcta de la rutina de control de presentación de dígitos,
cuanto menor tiempo se utilice en comparaciones, retardos, etc. más rápido se
logrará la activación del dígito a visualizar:

1 // display number
2 digit1=count / 1000;
3 digit2=(count - (digit1 * 1000)) / 100;
4 digit3=(count - (digit1*1000) - (digit2*100)) / 10;
5 digit4=count % 10;
Esto es un pequeño vídeo de baja calidad que muestra el contador de 4 dígitos y
7 segmentos a LED, ciertamente no se ve con la calidad que hubiera deseado.
También puede descargar una versión, desde aquí.

Con estos ejemplos, he querido llenar un vacío que, había entre tantos ejemplos
que se pueden encontrar en diferentes foros de Arduino. Realmente, en los foros
se puede encontrar mucha colaboración y en la web, muchos artículos que
hablan de contadores, realizados con LCD. Sin embargo, no son muchos los que
se inclinan por los displays de siete segmentos a LED. En la mayoría de los que
se encuentran teorizan y hablan de como funcionan, pero que lo describan en
español, hay pocos. Por ese motivo, me he tomado la tarea de introducir al
interesado en este tema de la multiplexación, en este caso, de unos dígitos. Tal
vez le pueda ayudar a alguien en su trabajo.
Como siempre, comentarios, criticas y sugerencias para mejorar este artículo,
son bienvenidos y apreciados.
Anexo.
2017-09-14 Se modifica un error en listado ‘Contador 4 dígitos 7 segmentos’, decía:

 void lightDigit3(byte number) {

digitalWrite(CA1, HIGH);

digitalWrite(CC2, HIGH);

digitalWrite(CC3, LOW);

digitalWrite(CC4, HIGH);

lightSegments(number);

}
Por:
 void lightDigit3(byte number) {

digitalWrite(CC1, HIGH);

digitalWrite(CC2, HIGH);

digitalWrite(CC3, LOW);

digitalWrite(CC4, HIGH);

lightSegments(number);

Probados los programas con Arduino v.1.6.12 Pruebe a descargar las librerías
desde aquí.

Manual de Practicas Arduino


Manual de Practicas Arduino
Saltar al contenido.

 INICIO
 ABOUT

Practica 06 – Funcion Antirebote


4 respuestas
Objetivo:
Elaborar una función anti rebote.

Material necesario:
1 – Tarjeta ARDUINO UNO
1 – Cable USB para Arduino
1 – Tarjeta Protoboard
1 – Software IDE de Arduino
1 – Botón
1 – Resistencia de 10K
Cables

Descripción

1. Conectar un botón a nuestra protoboard.


2. Conectarle una resistencia al botón para que vaya a tierra.
3. Entre la conexión de la resistencia y el botón conectar un cable que vaya al pin 4 digital de
nuestra Arduino.
4. Conectar un cable al otro lado del botón para alimentación.
5. Conectar los cables de corriente y tierra de nuestra Arduino a la protoboard.
6. Cargar el código.

Diagrama de conexión de la práctica realizado en Fritzing

Código
/* Practica 6 - Función antirebote
Funcion antirebote para leer correctamente
el estado del boton */

const int boton= 4; // boton conectado al pin 4


const int tiempoAntirebote =10;

int cuenta =0; //Guarda el numero de veces que el boton ha sido presionado
int estadoBoton;
int estadoBotonAnterior;

/*Función antirebote*/
boolean antirebote (int pin ) {
int contador =0;
boolean estado; // guarda el estado del boton
boolean estadoAnterior; // guarda el ultimo estado del boton

do {
estado = digitalRead (pin);
if (estado != estadoAnterior ){ // comparamos el estado actual
contador = 0; // reiniciamos el contador
estadoAnterior = estado;
}
else{
contador = contador +1; // aumentamos el contador en 1
}
delay (1);
}
while (contador < tiempoAntirebote);
return estado;
}

void setup (){


Serial.begin(9600); //Iniciamos la comunicacion serial
pinMode(boton,INPUT); //declaramos el boton como entrada
}

void loop () {
estadoBoton =digitalRead (boton); //leemos el estado del boton
if (estadoBoton != estadoBotonAnterior) { //si hay cambio con respeto al
estado
if (antirebote (boton)){ //checamos si esta preionado y
si lo esta
cuenta++; //aumentamos la cuenta
Serial.println (cuenta);
}
}
estadoBotonAnterior = estadoBoton; // guardamos el estado del boton
}

Resultados
El resultado de esta práctica es una función anti rebote, para probar su funcionamiento se conectó un
botón y se activó la conexión serial para probar su funcionamiento. Cada vez que el botón se oprimía
no importaba el tiempo que se mantenía presionado, el contador en el monitor serial iba avanzando
en uno.
Experiencia
Aprendí que la programación en Arduino también cuenta con funciones que uno puede crear para
resolver las necesidades de cada quien. También que aparte del for también existe el ciclo do-while.

Potrebbero piacerti anche