Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
INTERRUPCIONES EN
ARDUINO
28 ABRIL, 2016
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.
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.
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.
Los pines susceptibles de generar interrupciones varían en función del modelo de Arduino.
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.
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.
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).
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.
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)
La función micros() actualiza su valor dentro de una ISR, pero empieza a dar mediciones de
tiempo inexactas pasado el rango de 500us.
CREAR INTERRUPCIONES EN
ARDUINO
Para definir una interrupción en Arduino usamos la función:
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.
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.
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).
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”.
¿Qué es un pulsador?
conexión:
Como se puede observar, están las configuraciones de:
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
proyectos, por ejemplo, el usuario puede presionar una sola vez el pulsador pero
por hardware. En todos los proyectos de este blog se realizarán ambos tipos de
antirrebote muy efectivo sin necesidad de estar usando delays que retarden el
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.
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
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.
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.
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.
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:
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í.
INICIO
ABOUT
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
Código
/* Practica 6 - Función antirebote
Funcion antirebote para leer correctamente
el estado del boton */
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 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.