CONTADOR DIGITAL ARRIBA ABAJO.
INTRODUCCIÓN.
En gran cantidad de dispositivos actuales se puede encontrar un contador electrónico, son innumerables los elementos que incorporan algún tipo de contador electrónico. Del mismo modo hay en libros o artículos de electrónica o en la misma red, donde se describen contadores, sencillos o más complejos, pero todos diseñados con el mismo fin, contar unos eventos que se producen con cierta regularidad, aunque a veces no tanto.
EL CONTADOR.
En unos de mis viejos artículos se describe un contador de dos dígitos capaz de mostrar registros desde 00 a 99 mediante circuitos integrados estándar. Estoy refiriéndome al artículo contador de 00 a 99, en aquel caso se trataba de un contador realizado mediante circuitos integrados de tipo comercial de la serie CMOS 4000 (serie cuatro mil). Sin embargo en esta ocasión, aprovechando las posibilidades que nos ofrecen los microcontroladores y en concreto Arduino, trataré de describir cómo realizar uno de estos contadores de eventos. El detector de entrada, puede ser cualquier sensor y de cualquier forma, lo importante es que, entregue una señal digital adecuada, para su lectura.
En principio vamos a implementar mediante una rutina un sistema antirrebote debouncing en inglés que sea fiable. Dos pulsadores para proporcionar los pulsos que vamos a contar, uno para incrementar y el otro para decrementar la cuenta. Por lo tanto, nos serviremos de una variable val para leer si se presiona el pulsador y otra variable val2 para comparar con la lectura anterior. De esta forma podemos saber si ha cambiado el estado de la entrada. Una variable botonStado que guarde el estado del pulsador y la variable buttonCounter que guarde el número de pulsaciones. Con estas variables, vamos a crear un código que lleve la cuenta a medida que ésta cambie y la muestre en el monitor serie de Arduino, así, siempre habrá constancia de las pulsaciones que se han producido.
Vamos a empezar por escribir el listado del código que sea capaz de contar y mostrar la cuenta desde 0 hasta 99, este tope se puede modificar a gusto del usuario. De esta forma abordaremos los pasos poco a poco de manera que podamos resolverlos con seguridad para no abandonar por que los problemas nos abrumen.
En primer lugar declaramos las variables:
1 2 3 4 5 6 |
int switchPin = 8; // switch se conecta al pin 8 int ledPin = 2; // el LED se conecta al pin 2 int val; // variable para lectura del estado del pin int val2; // variable para leer el estado delayed/debounced int botonStado; // variable para mantener el estado del botón int buttonCounter =0 ; // contador para el número de pulsos de botón |
Ahora, vamos a configurar el setup() donde estableceremos los pines de entrada y la comunicación serie para presentar los resultados en el monitor serie, veamos:
1 2 3 4 5 |
void setup() { pinMode(switchPin, INPUT); // pone el pin switch como entrada pinMode(ledPin, OUTPUT); Serial.begin(9600); // Comunicación serie puesta a 9600bps botonStado = digitalRead(switchPin); // lee el estado inicial |
En el loop() tenemos una primera lectura del pin switchPin seguido de una segunda lectura del mismo pin, estas dos lecturas se comparan y si coinciden se considera valida la lectura, evitando así el efecto rebote o debouncing.
1 2 3 4 5 |
void loop(){ val = digitalRead(switchPin); delay(10); // intérvalo de 10 milisegundos son una cantidad buena de tiempo val2 = digitalRead(switchPin); if (val == val2) { // asegurar que conseguimos 2 lecturas constantes |
El resto del código está igualmente descrito y creo que no es necesario entrar en más detalle, este es el listado del código, puede copiarlo y pegarlo en su editor de texto preferido, guárdelo con el nombre contador_incremental_doble.pde u otro nombre apropiado para seguir el proyecto.
CONTADOR INCREMENTAL DOS DÍGITOS
Este es el código para el programa contador incremental de dos dígitos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
/* * contadordepulsos.pde * * Contador de dos dígitos de 00 a 99 * * Cada vez el pin de entrada va de ALTO a BAJO, el pin de salida * es basculado de ALTO a BAJO o de BAJO a ALTO. Hay un retraso * mínimo entre basculados para evitar los rebotes del circuito. * * Fecha: 30/08/10 * Autor: V. Garcia * */ int switchPin = 8; // switch se conecta al pin 8 int ledPin = 2; // el LED se conecta al pin 2 int val; // variable para lectura del estado del pin int val2; // variable para leer el estado delayed/debounced int botonStado; // variable para mantener el estado del botón int buttonCounter =0 ; // contador para el número de pulsos de botón int lightMode = 0; // Esta la luz EN o AP void setup() { pinMode(switchPin, INPUT); // pone el pin switch como entrada pinMode(ledPin, OUTPUT); Serial.begin(9600); // Comunicación serie puesta a 9600bps botonStado = digitalRead(switchPin); // lee el estado inicial // buttonCounter = 92; // lo uso para saltarme los 91 primeros. Despues se quita } void loop(){ val = digitalRead(switchPin); // lee el valor de entrada y almacénlo en val delay(10); // 10 milisegundos son una cantidad de tiempo buena val2 = digitalRead(switchPin); // lee la entrada otra vez para comprobar saltos if (val == val2) { // asegúrar que conseguimos 2 lecturas constantes if (val != botonStado) { // el estado de botón ha cambiado! if (val == LOW) { // compruebe si el botón es presionado buttonCounter + + ; if (lightMode == 0) { // esta la luz AP? lightMode = 1; // conecta la luz! digitalWrite(ledPin, HIGH); } else { lightMode = 0; // apaga la luz! digitalWrite(ledPin, LOW); } Serial.print(«Número de pulsaciones: «); // muestro las if (buttonCounter <10) Serial.print(«0»); // pulsaciones Serial.println(buttonCounter, DEC); // habidas } if (buttonCounter >= 99){ buttonCounter = 0; } } botonStado = val; // guardar el nuevo estado en la variable } } |
Si ha seguido los pasos descritos hasta ahora, es de suponer que todo ha salido bien. Abra el monitor serie de Arduino y observe los cambios producidos al pulsar los pulsadores. En caso contrario, vuelva sobre sus pasos y analice donde está el error cometido, para poder seguir. Con esto, tenemos resuelta la primera parte del proyecto que habíamos planteado al principio. Qué ha observado con los resultados, ¡ah! que no funciona siempre la cuenta ¿qué puede ser?, vamos a solucionar este problema de una forma sencilla, pongamos una línea más en el código, en concreto en el setup():
1 2 3 4 |
void setup() { pinMode(switchPin, INPUT); // pone el pin switch como entrada digitalWrite(channelPinA, HIGH);// activa la resistencia de pull-up. ... |
Esta simple orden activa la resistencia interna de pull-up del pin indicado, inserte esta línea en el código y compruebe que ahora si funciona bien. Observe que aunque deje presionado el pulsador el contador avanza una sola cuenta por cada pulsación y cuando llega a 99 la cuenta se inicia denuevo.
Analizando lo que hemos hecho, podemos abordar la segunda parte; la cual, deducimos que se puede considerar una copia casi idéntica del anterior código, naturalmente hay que realizar algún cambio para que sirva nuestros intereses. Veamos estos puntos a modificar.
En primer lugar, la cuenta de las pulsaciones deberá ser llevada igualmente por una variable vval que guarde las pulsaciones. Como en el caso anterior, vval2 será la variable que usaremos para evitar el rebote mecánico del pulsador.
Probemos este código, ¡ah!, pero antes hagamos los cambios. Para hacer más fácil las modificaciones, añadiremos un 2 a las variables, exceptuando val y val2, a las que antepondremos una v. Por supuesto que modificaremos el número del pin en el caso de la entrada del pulsador (switchPin2 = 9) y la salida del LED (ledPin2 = 3) que ocuparan los pines libres que siguen al anterior.
La línea que representa el contador, se bebe modificar ya que ahora el contador disminuye o sea, es regresivo. Con esto, cada presión del pulsador se identifica con la resta de un dígito sobre la cuenta anterior. Esta es la nueva forma del «contador«.
1 2 |
if (vval == LOW) { // compruebe si el botón es presionado buttonCounter2 -- ; |
Esta línea que sigue, tampoco es necesaria:
1 |
// if (buttonCounter2 > -10) Serial.print("0"); // pulsaciones |
Ya que en este caso, no creo necesario anteponer un «0» al contador.
Sin embargo es conveniente prestar atención al contador ya que estamos en sentido regresivo y el signo – (menos), puede causarnos algún retraso en conseguir la solución. Hay que prestar atención a la comparación, siga los pasos del código y comprenderá mejor el funcionamiento.
Este es el código del contador regresivo, lo puede y pegarlo en su editor de texto y compilarlo, para comprobar su efectividad.
CONTADOR REGRESIVO DE DOS DÍGITOS.
Este es el código para el programa del contador regresivo de dos dígitos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
/* * Contadorregresivo.pde … * * Fecha: 30/08/10 * Autor: V. Garcia * */ int switchPin2 = 9; // switch se conecta al pin 9 int ledPin2 = 3; // el LED se conecta al pin 3 int vval; // variable para lectura del estado del pin int vval2; // variable para leer el estado delayed/debounced int botonStado2; // variable para mantener el estado del botón int buttonCounter2 = 0 ; // contador para el número de pulsos de botón int lightMode2 = 0; // Esta la luz EN o AP void setup() { pinMode(switchPin2, INPUT); // pone el pin switch como entrada pinMode(ledPin2, OUTPUT); Serial.begin(9600); // Comunicación serie puesta a 9600bps botonStado2 = digitalRead(switchPin2); // lee el estado inicial // buttonCounter2 = -92; // lo uso para saltarme los 91 primeros. Después se quita } void loop(){ vval = digitalRead(switchPin2); // lee el valor de entrada y almacénalo en val delay(10); // 10 milisegundos son una cantidad de tiempo buena vval2 = digitalRead(switchPin2); // lee la entrada otra vez para comprobar saltos if (vval == vval2) { // asegurar que conseguimos 2 lecturas constantes if (vval != botonStado2) { // el estado de botón ha cambiado! if (vval == LOW) { // compruebe si el botón es presionado buttonCounter2 — ; if (lightMode2 == 0) { // esta la luz AP? lightMode2 = 1; // conecta la luz! digitalWrite(ledPin2, HIGH); } else { lightMode2 = 0; // apaga la luz! digitalWrite(ledPin2, LOW); } Serial.print(«Numero de pulsaciones: «); // muestro las // if (buttonCounter2 > -10) Serial.print(«0»); // pulsaciones Serial.println(buttonCounter2, DEC); // habidas } if (buttonCounter2 <= -99){ buttonCounter2 = 0; } } botonStado2 = vval; // guardar el nuevo estado en la variable } } |
COMBINAR LOS DOS CÓDIGOS.
Hemos logrado que los dos códigos realicen lo que teníamos previsto. Eso sí, los contadores, cuentan, cada uno en su dirección, como lo habíamos previsto. El caso es que ambos programas deben formar parte de un mismo código. Este es el reto actual ¿Cómo lo vamos a abordar?
Debe observarse que se han realizado unos pequeños cambios en cada subrutina, de modo que puedan compartir el código y cumplan con lo previsto. Se ha creado una nueva subrutina para la presentación en el monitor serie de Arduino, los resultados que se van produciendo en la medida que se generan las pulsaciones.
Esta rutina la he llamado anota(), por que eso es lo que hace. La he sacado fuera del código principal para que si al interesado no le aporta información en su aplicación, pueda prescindir de ella, eliminando las llamadas a dicha rutina y la misma.
En el listado que sigue, puede observarse lo descrito. Si está interesado en el código, para su utilización, como siempre copie y guarde con un nombre significativo, ábralo en su editor de texto preferido y compílelo con su Arduino, para cargarlo y comprobar su buen funcionamiento.
CONTADOR ARRIBA-ABAJO.
Este es el código completo para el programa de contador arriba-abajo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
/* /* * contador_arriba_abajo.pde * * Contador de dos dígitos de 00 a 99 y a 00. * * En el monitor, muestra los pulsos de cada pulsador y tambien * muestra el total de pulsaciones entre ambos pulsadores. * * Cada vez que presionamos un pulsador, el pin de salida correspondiente * bascula de ALTO a BAJO o de BAJO a ALTO. Hay un retardo * máximo entre pulsos para evitar los rebotes del circuito. * * Fecha: 31/08/10 * Autor: V. Garcia * * Consume 2984 bytes compilado con version 0013Alpha. */ int switchPin = 8; // switch se conecta al pin 8 int switchPin2 = 9; // switch se conecta al pin 9 int ledPin = 2; // el LED se conecta al pin 2 int ledPin2 = 3; // el LED se conecta al pin 3 int val = 0; // variable para lectura del estado del pin int val2 = 0; // variable para leer el estado delayed/debounced int vval = 0; // variable para lectura del estado del pin int vval2 = 0; // variable para leer el estado delayed/debounced int botonStado; // variable para mantener el estado del botón int botonStado2; // variable para mantener el estado del botón int buttonCounter =0 ; // contador para el número de pulsos de botón int buttonCounter2 =0 ; // contador para el número de pulsos de botón int lightMode = 0; // Esta la luz EN o AP int lightMode2 = 0; // Esta la luz EN o AP void setup() { pinMode(switchPin, INPUT); // pone el pin switch como entrada digitalWrite(switchPin, HIGH); pinMode(switchPin2, INPUT); // pone el pin switch como entrada digitalWrite(switchPin2, HIGH); pinMode(ledPin, OUTPUT); pinMode(ledPin2, OUTPUT); Serial.begin(9600); // Comunicación serie puesta a 9600bps botonStado = digitalRead(switchPin); // lee el estado inicial botonStado2 = digitalRead(switchPin2); // lee el estado inicial // buttonCounter = 92; // lo uso para saltarme los 91 primeros. Después se quita Serial.println(«contador_00a99_00.ino Listo \n»); } void loop(){ // Incrementa // val = digitalRead(switchPin); // lee el valor de entrada y almacena en val delay(10); // 10 milisegundos son una cantidad de tiempo buena val2 = digitalRead(switchPin); // lee la entrada otra vez para comprobar saltos if (val == val2) { // asegurar que conseguimos 2 lecturas constantes if (val != botonStado) { // el estado de botón ha cambiado! if (val == LOW) { // compruebe si el botón es presionado if (lightMode == 0) { // esta la luz AP? lightMode = 1; // conecta la luz! digitalWrite(ledPin, HIGH); } else { lightMode = 0; // apaga la luz! digitalWrite(ledPin, LOW); } buttonCounter ++ ; anota(); } if (buttonCounter >= 99){ buttonCounter = 0; } } botonStado = val; // guardar el nuevo estado en la variable } // Decrementa // vval = digitalRead(switchPin2); // lee el valor de entrada y almacena en val delay(10); // 10 milisegundos son una cantidad de tiempo buena vval2 = digitalRead(switchPin2); // lee la entrada otra vez para comprobar saltos if (vval == vval2) { // asegurar que conseguimos 2 lecturas constantes if (vval != botonStado2) { // el estado de botón ha cambiado! if (vval == LOW) { // compruebe si el botón es presionado if (lightMode2 == 0) { // esta la luz AP? lightMode2 = 1; // conecta la luz! digitalWrite(ledPin2, HIGH); } else { lightMode2 = 0; // apaga la luz! digitalWrite(ledPin2, LOW); } buttonCounter2 — ; anota(); } if (buttonCounter2 <= -99){ buttonCounter2 = 0; if (buttonCounter <= -99){ buttonCounter = 0; } } botonStado2 = vval; // guardar el nuevo estado en la variable } } } void anota() { Serial.print(» Cuenta: «); // muestro las Serial.print(buttonCounter + buttonCounter2, DEC); // habidas Serial.print(» Total pulsaciones: «); Serial.println(buttonCounter + buttonCounter2*-1, DEC); } |
Ahora, ya puede disfrutar de un doble contador de eventos. Piense usted en una aplicación para darle una utilidad, por ej. con unos pocos cambios un contador para una cancha deportiva. Es una idea.
En la figura 2 se muestra el monitor serie con las cuentas. Como siempre, comentarios, criticas y sugerencias para mejorar este artículo, son bienvenidos y apreciados.