Paso 5: Agregar botones y va OO
Como vimos en el paso anterior, se hace difícil de escalar. Hay variables de estado mundial, que se refieren por algunas funciones. Imagine añadir un 2 º botón: comienza la pesadilla; no habla acerca de un botón de 3...
Programación: Va OO (orientado a objetos)
Arduino utiliza el lenguaje de procesamiento sobre C++, entonces ¿por qué no utilizar algunas características OO?
Tenemos que empacar estas variables globales dentro de las estructuras que podemos crear a voluntad. Estas estructuras, con funciones de control de asociados se llaman clases y métodos en el mundo OO. Una clase es simplemente la descripción del objeto, mientras que la memoria efectiva asignada para cada objeto se llama la instancia.
La primera foto de este paso demuestra que hemos añadido un botón 2. La segunda imagen muestra el ya tradicionales Prensas de largo/corto, trabajando de forma independiente muy bien. El 2 º botón tiene, por cierto, un umbral más de largo-prensa.
Pro/contras
Este código es cada vez más complejo, que es normal porque cuando escala, la complejidad genera un paso significativo. La buena noticia es que luego puede apoyar cualquier número de botones adicionales en ningún aumento de la complejidad.
Proceso establece algunas limitaciones (por ejemplo, no es ninguna creación dinámica: no existen los operadores new y delete ). Que no es malo, porque no queremos perdernos en alguno de los lados particularmente sangrientos de C++, que son innecesarios (discutiblemente) en pequeños sistemas embebidos como Arduino.
Seguro que el mismo puede ser hecho en C puro, así que si necesidad/prefiere una implementación en C, solo me preguntan.
Código
––––––––––8<––––––––––
#define BUTTON1_PIN 2 // Button 1 #define BUTTON2_PIN 3 // Button 2 #define DEFAULT_LONGPRESS_LEN 25 // Min nr of loops for a long press #define DELAY 20 // Delay per loop in ms ////////////////////////////////////////////////////////////////////////////// enum { EV_NONE=0, EV_SHORTPRESS, EV_LONGPRESS }; ////////////////////////////////////////////////////////////////////////////// // Class definition class ButtonHandler { public: // Constructor ButtonHandler(int pin, int longpress_len=DEFAULT_LONGPRESS_LEN); // Initialization done after construction, to permit static instances void init(); // Handler, to be called in the loop() int handle(); protected: boolean was_pressed; // previous state int pressed_counter; // press running duration const int pin; // pin to which button is connected const int longpress_len; // longpress duration }; ButtonHandler::ButtonHandler(int p, int lp) : pin(p), longpress_len(lp) { } void ButtonHandler::init() { pinMode(pin, INPUT); digitalWrite(pin, HIGH); // pull-up was_pressed = false; pressed_counter = 0; } int ButtonHandler::handle() { int event; int now_pressed = !digitalRead(pin); if (!now_pressed && was_pressed) { // handle release event if (pressed_counter < longpress_len) event = EV_SHORTPRESS; else event = EV_LONGPRESS; } else event = EV_NONE; // update press running duration if (now_pressed) ++pressed_counter; else pressed_counter = 0; // remember state, and we're done was_pressed = now_pressed; return event; } ////////////////////////////////////////////////////////////////////////////// // Instantiate button objects ButtonHandler button1(BUTTON1_PIN); ButtonHandler button2(BUTTON2_PIN, DEFAULT_LONGPRESS_LEN*2); void setup() { Serial.begin(9600); // init buttons pins; I suppose it's best to do here button1.init(); button2.init(); } void print_event(const char* button_name, int event) { if (event) Serial.print(button_name); Serial.print(".SL"[event]); } void loop() { // handle button int event1 = button1.handle(); int event2 = button2.handle(); // do other things print_event("1", event1); print_event("2", event2); // add newline sometimes static int counter = 0; if ((++counter & 0x1f) == 0) Serial.println(); delay(DELAY); }
––––––––––>8––––––––––