Skip to content

Instantly share code, notes, and snippets.

@CravApp
Created May 17, 2025 02:01
Show Gist options
  • Save CravApp/f781fe6856111082c5aaca9d129249df to your computer and use it in GitHub Desktop.
Save CravApp/f781fe6856111082c5aaca9d129249df to your computer and use it in GitHub Desktop.
Programar Arduino
/*
Proyecto: ARPS2-Intro-2-Variables
Actividad: mirobo.tech/arps-intro-2
Actualizado: 21 de febrero de 2025
Esta actividad introductoria de programación para el circuito mirobo.tech ARPS2
demuestra el uso de una variable para contar pulsaciones de botón y comparaciones
constantes dentro de condiciones para activar una acción cuando se alcanza un límite.
Análisis de programa adicional y actividades de programación demuestran el uso de
variables booleanas (o bool) para almacenar el estado durante bucles de programa
sucesivos, la creación de un juego de clics rápidos para dos jugadores, la simulación
de botones de alternancia y multifunción del mundo real, y alientan a los aprendices
a crear código de programa para medir y mitigar el rebote de contacto del interruptor.
Consulta la página web https://mirobo.tech/arps para obtener recursos
adicionales de ARPS2, actividades de programación y programas de inicio.
*/
// Dispositivos de E/S de inicio educativo ARPS2
const int SW2 = 0; // Los pulsadores SW2 y SW3 son totalmente compatibles en
const int SW3 = 1; // Arduino UNO R4 Minima y Arduino UNO R4 WiFi
const int SW4 = 2; // Los pulsadores SW4 y SW5 funcionan en todas las placas
const int SW5 = 4; // de circuito Arduino UNO
const int LED2 = 3; // LEDs ARPS2
const int LED3 = 9;
const int LED4 = 10;
const int LED5 = 11;
const int BEEPER = 6; // Zumbador piezoeléctrico LS1 de ARPS2
// LED predefinido de Arduino UNO
// LED_BUILTIN (D13) // LED integrado (compartido con H2 y SONAR TRIG)
// Define constantes del programa
const int maxCount = 50;
// Define variables del programa
int SW2State;
int SW3State;
int SW4State;
int SW5State;
int SW2Count = 0;
bool SW2Pressed = false;
// El código de configuración se ejecuta una vez para configurar los pines de E/S antes de ejecutar el bucle principal
void setup() {
pinMode(SW2, INPUT_PULLUP);
pinMode(SW3, INPUT_PULLUP);
pinMode(SW4, INPUT_PULLUP);
pinMode(SW5, INPUT_PULLUP);
pinMode(LED2, OUTPUT);
pinMode(LED3, OUTPUT);
pinMode(LED4, OUTPUT);
pinMode(LED5, OUTPUT);
pinMode(BEEPER, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
tone(BEEPER, 4000, 100); // ¡Hola!
}
// El código del bucle principal se repite indefinidamente
void loop() {
SW2State = digitalRead(SW2); // Cambiar a SW4 para Arduino UNO R3
SW5State = digitalRead(SW5);
// Cuenta las pulsaciones del botón SW2
if (SW2State == LOW) {
digitalWrite(LED2, HIGH);
SW2Count = SW2Count + 1;
}
else {
digitalWrite(LED2, LOW);
}
// Enciende el LED D3 cuando se ha alcanzado el conteo máximo
if (SW2Count >= maxCount) {
digitalWrite(LED3, HIGH);
}
// Apaga el LED D3 y reinicia el conteo si se presiona SW5
if (SW5State == LOW) {
digitalWrite(LED3, LOW);
SW2Count = 0;
}
delay(10); // El retardo añadido ayuda a los simuladores a ejecutar este programa
}
/* Aprende Más -- Actividades de Análisis del Programa
1. La variable 'SW2Count' se define como una ubicación de memoria de 16 bits dentro de
la RAM del microcontrolador mediante la declaración del programa: 'int SW2Count = 0;'
¿Qué rango de números puede almacenar una variable int de 16 bits? ¿Qué sucederá
si intentas almacenar un número mayor que el límite superior de un 'int' en
la variable SW2Count?
2. La instrucción del programa 'const int maxCount = 50;' define una constante
del programa utilizando exactamente el mismo tipo de declaración que se usó para
definir los pines de E/S del microcontrolador. ¿Cómo crees que el
IDE de Arduino sabe que 'SW3' es un pin de E/S de hardware y que
'maxCount' es un número? No parece haber ninguna diferencia real
entre las dos declaraciones, entonces, ¿qué más podría llevar a que
SW3 y maxCount se interpreten de manera diferente?
3. La constante maxCount se utiliza al comienzo de una condición if:
if(SW2Count >= maxCount) {
La condición compara el valor de la variable SW2Count con
la constante maxCount para verificar si se ha alcanzado un límite.
Definir una constante para esto parece un trabajo extra cuando la
declaración condicional simplemente podría haberse escrito como:
if(SW2Count >= 50) {
¿Se te ocurren algunas ventajas de definir y usar la constante maxCount
en lugar de simplemente incrustar el número 50 en la
condición? Enumera al menos dos ventajas.
4. A primera vista, parece que este programa debería encender el LED D2
e incrementar la variable SW2Count cada vez que se presiona SW2,
pero ese no es el caso.
Carga el programa y ejecútalo, contando mentalmente cuántas veces
presionaste SW2 hasta que se enciende el LED D3. El conteo y el LED D3
se pueden reiniciar presionando SW5 para que puedas intentarlo varias veces.
¿El conteo llegó a 50? Si no, ¿puedes describir por qué o qué
podría estar sucediendo en el programa para que cuente mal? Puede que
obtengas alguna idea de lo que podría estar sucediendo
presionando y soltando rápidamente SW2 durante un intento de alcanzar
50, borrando el conteo con SW5 y luego repitiendo el intento
presionando y soltando SW2 lentamente.
5. Está bien si aún no has identificado ningún problema obvio con el
programa. Podemos agregar algo de código de depuración que podría ayudar a
descubrir la naturaleza del problema. Parece que el programa
está contando demasiado rápido. Para verificarlo, agreguemos otra condición para
apagar el LED D3 si el conteo se vuelve muy grande, digamos diez veces mayor
de lo esperado. Agregaremos esta nueva condición justo después de la
condición existente que enciende el LED D3, así:
// Enciende el LED D3 cuando se ha alcanzado el conteo máximo
if(SW2Count >= maxCount) {
digitalWrite(LED3,HIGH);
}
// Apaga el LED D3 si el conteo real es enorme.
if(SW2Count >= maxCount * 10) {
digitalWrite(LED3,LOW);
}
Ahora, mantén presionado el pulsador SW2 durante al menos 10 segundos mientras
observas el LED D3. El LED D3 debería permanecer apagado hasta que el valor de
la variable SW2Count se vuelva mayor que maxCount. Si el LED D3 se enciende,
debería permanecer encendido hasta que el valor de SW2Count se vuelva diez
veces mayor que maxCount. Si el LED D3 se apaga mientras aún mantienes
presionado SW2, el SW2Count debe ser al menos diez veces el valor de maxCount.
Si el LED D3 hace eso, ¿puedes explicar cómo el conteo podría llegar tan
alto mientras SW2 solo se presionó una vez?
6. Uno de los desafíos fundamentales al crear programas que se ejecutan
dentro de un bucle de programa principal es separar los eventos de entrada del
estado de entrada. Dado que el estado de SW2 se detecta en cada ciclo a través de
la función principal loop(), leer su estado como LOW simplemente significa que
el botón resultó estar presionado durante el ciclo actual del bucle.
Dado que los humanos somos lentos y los microcontroladores pueden ejecutar un
bucle simple como este muy rápido, es probable que el botón se lea
como presionado durante muchos ciclos a través del bucle. Esto explica por qué
SW2Count excede rápidamente maxCount.
Para resolver este problema, el programa no puede simplemente leer el estado
del interruptor y asumir que una entrada LOW es una nueva pulsación de botón.
En cambio, el programa tiene que identificar el cambio de una entrada HIGH a
una entrada LOW durante bucles sucesivos, ya que este *cambio* de estado
es el único indicador confiable de que ha ocurrido una nueva pulsación de botón.
Para hacer esto, se requiere una nueva variable para almacenar el estado del
botón del ciclo anterior a través del bucle. El tipo de variable más simple,
y uno que es ideal para esto, es una variable booleana (o bool). Las variables
booleanas almacenan uno de dos valores binarios; en el lenguaje de programación C,
los valores están representados por las palabras 'false' y 'true'.
A continuación, se muestra una función de entrada reescrita que incorpora la variable
booleana SW2Pressed que se ha predefinido en el encabezado del programa.
Reemplaza la primera estructura condicional 'if-else' de SW2 con las siguientes
dos nuevas estructuras condicionales 'if':
// Cuenta las pulsaciones del botón SW2
if(SW2State == LOW && SW2Pressed == false) {
digitalWrite(LED2,HIGH);
SW2Pressed = true;
SW2Count += 1;
}
if(SW2State == HIGH) {
digitalWrite(LED2,LOW);
SW2Pressed = false;
}
La primera condición 'if' ahora combina lógicamente (AND) tanto el estado
actual del botón como la variable booleana SW2Pressed que representa
el estado anterior del botón. Usando esta lógica, el botón debe
estar actualmente presionado y su estado anterior debe ser falso
para que se cuente como una nueva pulsación de botón. Cuando ambas condiciones
se cumplen, el LED D2 se encenderá, la variable booleana SW2Pressed se
establecerá en 'true' y la variable SW2Count se incrementará en 1
usando el operador compuesto en la instrucción 'SW2Count += 1;'
(esto produce el mismo resultado usando menos código que la instrucción original
'SW2Count = SW2Count + 1;').
Observa que incluso si SW2State sigue siendo LOW la próxima vez que se pasa
por el bucle principal, la variable SW2Pressed siendo 'true' evitará que
la misma pulsación de botón se cuente más de una vez. Se utiliza una segunda
condición if para restablecer la variable booleana SW2Pressed a 'false'
cuando se ha soltado el interruptor.
Prueba estos nuevos bloques de código en tu programa y verifica que cada
pulsación de botón individual ahora se cuenta correctamente.
7. La declaración condicional en la primera condición if también se puede
escribir:
if(SW2State == LOW && !SW2Pressed) {
La expresión '!SW2Pressed' se lee como 'no SW2Pressed' y es
equivalente a que SW2Pressed sea falso (o *no verdadero*). De manera similar,
usar el nombre de la variable booleana SW2Pressed por sí solo es
equivalente a que sea verdadero. Intenta reemplazar la primera condición if
en tu programa con esta expresión y verifica que funcione como
se esperaba.
8. Las declaraciones de constantes, como las que se utilizan en la parte superior del programa
para asignar pines de E/S y establecer maxCount, también se pueden utilizar para
representar el estado de un pulsador. Hacer esto puede hacer que el código
del programa sea más fácil de leer.
Agrega las siguientes definiciones de constantes a la sección 'Define program
constants' del encabezado del programa:
const int pressed = LOW;
const int notPressed = HIGH;
Ahora, en lugar de comparar el estado del pulsador con 'LOW' o 'HIGH',
el estado del botón se puede comparar con una de estas definiciones
recién nombradas. Prueba el siguiente código en tu programa y luego
modifica el código del botón de reinicio SW5 para usar las mismas
definiciones 'pressed' y 'notPressed'.
// Cuenta las pulsaciones del botón SW2
if(SW2State == pressed && !SW2Pressed) {
digitalWrite(LED2,HIGH);
SW2Pressed = true;
SW2Count += 1;
}
if(SW2State == notPressed) {
digitalWrite(LED2,LOW);
SW2Pressed = false;
}
9. ¿Puedes crear términos constantes similares 'on' y 'off' y usarlos
para controlar los LEDs en tu circuito? Por ejemplo, podrías escribir
'digitalWrite(LED2,on);' en lugar de 'digitalWrite(LED2,HIGH);'.
¿Cuándo podría no ser una buena idea usar 'on' u 'off' en lugar de
HIGH o LOW?
Actividades de Programación
1. Crea un juego de estilo "rapid-clicker" para dos jugadores utilizando este programa
como punto de partida. ¡El único propósito del juego será ver
qué jugador puede presionar un botón más rápido y convertirse en el primer
jugador en alcanzar el conteo máximo y ganar el juego!
Usa SW4 para el segundo jugador y enciende el LED D5 cuando se presiona el botón SW4.
Enciende el LED D4 para mostrar cuándo el conteo del segundo jugador
iguala el maxCount.
Comienza duplicando las variables del programa existentes para crear un
conjunto similar para el segundo jugador. Luego, crea copias de las
estructuras condicionales if para el segundo jugador y modifícalas para
usar las variables creadas para el segundo jugador. Finalmente, modifica
SW5 para reiniciar los conteos y los LEDs para ambos jugadores.
Nota: cuando uses ARPS-2 con Arduino UNO Rev 3, SW2 y SW3 no
serán utilizables. En este caso, usa SW4 y SW5 para los interruptores
de dos jugadores y el botón Reset (SW1) para reiniciar el juego.
2. Cuando dos jugadores igualados están jugando al "rapid-clicker",
puede ser difícil saber qué jugador alcanzó primero el valor
maxCount. Utiliza tu conocimiento de las variables booleanas para evitar
que más pulsaciones aumenten los conteos de los jugadores una vez que un
jugador ha alcanzado el conteo máximo.
3. Usa una variable booleana para crear un programa que simule el
funcionamiento de un botón de alternancia. Cada nueva pulsación del botón
de alternancia debe 'alternar' un LED a su estado opuesto. (Los botones
de alternancia se usan comúnmente como botones de encendido/apagado en
dispositivos digitales, como el botón de encendido que enciende y apaga
un monitor de computadora).
Presionar y mantener presionado el botón de alternancia solo debe hacer que
el LED cambie de estado, o se alterne, una vez, y no que se encienda y apague
rápidamente de forma continua. Prueba la acción de tu botón para verificar
su confiabilidad.
4. Se puede usar un botón multifunción para iniciar una acción cuando
se presiona, y una segunda acción o alternativa cuando se mantiene
presionado durante un cierto período de tiempo. Una forma de implementar
un botón multifunción es usar una variable que cuente los bucles de
programa cronometrados, ¡exactamente como lo hizo este programa inicialmente
(e involuntariamente)!
Crea un programa que implemente un botón multifunción para encender
un LED tan pronto como se presiona un botón, y enciende un segundo LED
si el botón se mantiene presionado durante más de un segundo. Haz que ambos
LEDs se apaguen cuando se suelta el botón.
5. ¿Rebotan tus pulsadores? El rebote de interruptor es el término utilizado para
describir los contactos del interruptor que se cierran y abren repetidamente
antes de asentarse en su estado final (cerrado). El rebote de interruptor en
el interruptor de luz de una habitación podría no ser una gran preocupación porque
sucede tan rápido que no notaríamos que las luces parpadean brevemente
antes de permanecer encendidas. Pero, el rebote de interruptor podría ser un
problema en un programa de botón de software porque la alta velocidad de
funcionamiento de un microcontrolador le permite ver cada cierre de contacto
como un evento nuevo y separado. Imagina si un botón de encendido configurado
como un botón de alternancia rebotara y cada pulsación tuviera entre 1 y 4
cierres de contacto. El dispositivo no podría encenderse o apagarse de
manera confiable.
Para determinar si los pulsadores de tu circuito exhiben rebote de interruptor,
crea un programa que cuente el número de veces que se cierran los
contactos de un pulsador y luego muestre el
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment