Components and supplies
LED (generic)
Toggle Switch, Toggle
Breadboard (generic)
Tactile Switch, Top Actuated
Arduino UNO
Resistor 10k ohm
Resistor 220 ohm
ESP32S
Relay (generic)
Jumper wires (generic)
Apps and platforms
Arduino IDE
Project description
Code
ez switch library, .cpp file
c_cpp
Library code file
1// Arduino Switch Library for configuring different switch type wired 2// in common circuit schemes. 3// 4// Ron Bentley, Stafford (UK), March 2021, version 2.0 5// 6// This example and code is in the public domain and 7// may be used without restriction and without warranty. 8// 9 10#include <Arduino.h> 11#include <ez_switch_lib.h> 12 13// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 14// Set up switch cotrol structure and initialise internal variables. 15// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 16 17Switches::Switches(byte max_switches) 18{ 19 // Establish the switch control structure (switches) of the size required. 20 // 21 switches = (switch_control *)malloc(sizeof(*switches) * max_switches); 22 if (switches == NULL) { 23 // malloc failure 24 Serial.begin(115200); 25 Serial.println("!!Failure to acquire memory of required size - PROGRAM TERMINATED!!"); 26 Serial.flush(); 27 exit(1); 28 } 29 30 // Initialise private variables 31 _num_entries = 0; // will be incremented each time a switch is added, up to _max_switches 32 _max_switches = max_switches; // transfer to internal variable 33} 34 35// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36// Generic switch read function. 37// Read the switch defined by the function parameter. 38// Function returns a value indicating if the switch 39// has undergone a transition or not. 40// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 41 42bool Switches::read_switch(byte sw) { 43 bool sw_status; 44 if (sw < 0 || sw >= _num_entries) return !switched; // out of range, slot 'sw' is not configured with a switch 45 if (switches[sw].switch_type == button_switch) { 46 sw_status = read_button_switch(sw); 47 } else { 48 sw_status = read_toggle_switch(sw); 49 } 50 // now determine if switch has output pin associated and if switched 51 // flip the output's status, ie HIGH->LOW, or LOW->HIGH 52 if (sw_status == switched && switches[sw].switch_out_pin > 0) 53 { 54 // flip the output level of associated switch output pin, if defined 55 bool status = switches[sw].switch_out_pin_status; // last status value of out_pin 56 status = HIGH - status; // flip the status value 57 switches[sw].switch_out_pin_status = status; // update current status value 58 digitalWrite(switches[sw].switch_out_pin, status);// change status of linked pin 59 } 60 return sw_status; 61} // End of read_switch 62 63// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 64// Generic toggle switch read function. 65// Test the toggle switch to see if its status has changed since last look. 66// Note that although switch status is a returned value from the function, 67// the current status of the switch ('switches[sw].switch_status') is always 68// maintained and can be tested outside of the function at any point/time. 69// It will either have a status of 'on' or '!on' (ie off). 70// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 71 72bool Switches::read_toggle_switch(byte sw) { 73 byte switch_pin_reading = digitalRead(switches[sw].switch_pin); // test current state of toggle pin 74 if (switches[sw].switch_circuit_type == circuit_C2) { 75 // Need to invert HIGH/LOW if circuit design sets 76 // pin HIGH representing switch in off state. 77 // ie inititialised as INPUT_PULLUP 78 switch_pin_reading = !switch_pin_reading; 79 } 80 if (switch_pin_reading != switches[sw].switch_status && !switches[sw].switch_pending) { 81 // Switch change detected so start debounce cycle 82 switches[sw].switch_pending = true; 83 switches[sw].switch_db_start = millis(); // set start of debounce timing 84 } 85 if (switches[sw].switch_pending) { 86 // We are in the switch transition cycle so check if debounce period has elapsed 87 if (millis() - switches[sw].switch_db_start >= _debounce) { 88 // Debounce period elapsed so assume switch has settled down after transition 89 switches[sw].switch_status = !switches[sw].switch_status; // flip status 90 switches[sw].switch_pending = false; // cease transition cycle 91 last_switched_id = sw; // indicates the last switch to have been processed by read function 92 return switched; 93 } 94 } 95 return !switched; 96} // End of read_toggle_switch 97 98// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 99// Read button switch function. 100// Generic button switch read function. 101// Reading is controlled by: 102// a. the function parameter which indicates which switch 103// is to be polled, and 104// b. the switch control struct(ure), referenced by a). 105// 106// Note that this function works in a nonexclusive way 107// and incorporates debounce code. 108// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 109 110bool Switches::read_button_switch(byte sw) { 111 byte switch_pin_reading = digitalRead(switches[sw].switch_pin); 112 if (switch_pin_reading == switches[sw].switch_on_value) { 113 // Switch is pressed (ON), so start/restart debounce process 114 switches[sw].switch_pending = true; 115 switches[sw].switch_db_start = millis(); // start elapse timing 116 return !switched; // now waiting for debounce to conclude 117 } 118 if (switches[sw].switch_pending && switch_pin_reading != switches[sw].switch_on_value) { 119 // Switch was pressed, now released (OFF), so check if debounce time elapsed 120 if (millis() - switches[sw].switch_db_start >= _debounce) { 121 // debounce time elapsed, so switch press cycle complete 122 switches[sw].switch_pending = false; 123 last_switched_id = sw; // indicates the last switch to have been processed by read function 124 return switched; 125 } 126 } 127 return !switched; 128} // End of read_button_switch 129 130// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 131// Add given switch to switch control structure, but validate 132// given paramters and ensure there is a free slot. 133// 134// Return values from add_switch are: 135// 136// >= 0 the switch control structure entry number ('switch_id') 137// for the switch added, 138// -1 add_falure - no slots available in the switch 139// control structure, 140// -2 bad_params - given paramter(s) for switch are 141// not valid. 142// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 143 144int Switches::add_switch(byte sw_type, byte sw_pin, byte circ_type) { 145 if ((sw_type != button_switch && sw_type != toggle_switch) || 146 (circ_type != circuit_C1 && 147 circ_type != circuit_C2 && 148 circ_type != circuit_C3)) return bad_params; // bad paramters 149 if (_num_entries < _max_switches) { 150 // room to add another switch...initialise the switch's 151 // data depending on type of switch and circuit 152 switches[_num_entries].switch_type = sw_type; 153 switches[_num_entries].switch_pin = sw_pin; 154 switches[_num_entries].switch_circuit_type = circ_type; 155 switches[_num_entries].switch_pending = false; 156 switches[_num_entries].switch_db_start = 0; 157 // define what on means for this switch: 158 if (circ_type != circuit_C2) { 159 // circuit_C1 and circuit_C3 are used with pull down resistors 160 // if circuit_C1 (INPUT) then and external 10k ohm resistor needs to be fitted 161 // to the switch circuit, but if circuit_C3 (INPUT_PULLDOWN) then the resistor 162 // is internal to the microcontroller. 163 // Note that the 'on' state is represented by HIGH (3.3/5v) 164 switches[_num_entries].switch_on_value = HIGH; 165 } else { 166 // circuit_C2 (INPUT_PULLUP) with internal microcontroller pull up resistor 167 // Note that the 'on' state is represented by LOW (0v) 168 switches[_num_entries].switch_on_value = LOW; 169 } 170 if (sw_type == button_switch) { 171 switches[_num_entries].switch_status = not_used; 172 } else { 173 switches[_num_entries].switch_status = !on; 174 } 175 pinMode(sw_pin, circ_type); // establish pin set up 176 // ensure no mapping to an output pin until created explicitly 177 switches[_num_entries].switch_out_pin = 0; 178 switches[_num_entries].switch_out_pin_status = LOW; // set LOW unless explicitly changed 179 180 _num_entries++; // point to next free slot 181 return _num_entries - 1; // return 'switch_id' - given switch now added to switch control structure 182 } else return add_failure; // no room left to add another switch! 183} // End add_switch 184 185 186// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 187// Link or delink the given switch to the given digital pin as an output 188// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 189 190int Switches::link_switch_to_output(byte switch_id, byte output_pin, bool HorL) { 191 if (switch_id > _num_entries) { 192 return link_failure; // no such switch 193 } 194 if (output_pin == 0) { 195 // delink this output from this switch, set the output to the required level first 196 if (switches[switch_id].switch_out_pin == 0) { 197 // no output pin previously defined 198 return link_failure; 199 } 200 // set existing pin to level required state before clearing the link 201 digitalWrite(switches[switch_id].switch_out_pin, HorL); 202 } else { 203 // initialise given output pin 204 pinMode(output_pin, OUTPUT); 205 digitalWrite(output_pin, HorL); // set to param value until switched 206 } 207 switches[switch_id].switch_out_pin = output_pin; 208 switches[switch_id].switch_out_pin_status = HorL; 209 return link_success; // success 210} 211 212// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 213// Return the number of slots left unused 214// in the switch control structure. 215// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 216 217int Switches::num_free_switch_slots() { 218 return _max_switches - _num_entries; 219} // End num_free_switch_slots 220 221// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 222// Set debounce period (milliseconds). 223// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 224 225void Switches::set_debounce(int period) { 226 if (period >= 0) _debounce = period; 227} // End set_debounce 228 229// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 230// Print given switch control data. 231// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 232 233void Switches::print_switch(byte sw) { 234 if (0 <= sw && sw < _num_entries ) { 235 Serial.print(F("sw_id: = ")); 236 Serial.println(sw); 237 Serial.print(F("sw_type = ")); 238 uint8_t sw_type = switches[sw].switch_type; 239 if (sw_type == button_switch)Serial.print(F("BUTTON SWITCH")); 240 else Serial.print(F("TOGGLE SWITCH")); 241 Serial.print(F(" sw_pin = ")); 242 Serial.print(switches[sw].switch_pin); 243 Serial.print(F("\ circ_type = ")); 244 uint8_t circ_type = switches[sw].switch_circuit_type; 245 if (circ_type == circuit_C1) { 246 Serial.print(F("INPUT/circuit_C1/")); 247 } else if (circ_type == circuit_C2) { 248 Serial.print(F("INPUT_PULLUP/circuit_C2/")); 249 } else { 250 Serial.print(F("INPUT_PULLDOWN/circuit_C3/")); 251 } 252 Serial.println(circ_type); 253 Serial.print("on_value = "); 254 if (switches[sw].switch_on_value == HIGH)Serial.print(F("HIGH")); 255 else Serial.print(F("LOW ")); 256 Serial.print(F("\ \ sw_status = ")); 257 uint8_t sw_status = switches[sw].switch_status; 258 if (sw_type == button_switch)Serial.print(F("n/a")); else { 259 if (sw_status == on)Serial.print(F("ON")); 260 else Serial.print(F("OFF")); 261 } 262 Serial.print(F("\ pending = ")); 263 if (switches[sw].switch_pending)Serial.print(F("YES")); 264 else Serial.print(F("NO ")); 265 Serial.print(F("\ db_start = ")); 266 Serial.print(switches[sw].switch_db_start); 267 Serial.println(F(" msecs")); 268 if (switches[sw].switch_out_pin == 0) { 269 // switch does not have a linked output 270 Serial.println(F("*** No linked output pin")); 271 } else { 272 // switch has a linked output 273 Serial.print(F("Linked output pin = ")); 274 Serial.print(switches[sw].switch_out_pin); 275 Serial.print(F("\ linked pin status = ")); 276 if (switches[sw].switch_out_pin_status == LOW)Serial.println(F("LOW")); 277 else Serial.println(F("HIGH")); 278 } 279 Serial.println(); 280 Serial.flush(); 281 } 282} // End print_switch 283 284// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 285// Print all switch control data set up. 286// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 287 288void Switches::print_switches() { 289 Serial.println(F("\ 290Declared & configured switches:")); 291 for (byte sw = 0; sw < _num_entries; sw++) { 292 print_switch(sw); 293 } 294} // End print_switches
ez switch library, keywords file
c_cpp
Keywords for ez switch library
1# Arduino Switch Library for configuring different switch type wired 2# in common circuit schemes. 3# 4# Ron Bentley, Stafford (UK), March 2021, version 2.0 5# 6# This example and code is in the public domain and 7# may be used without restriction and without warranty. 8# 9 10# data and data structures 11Switches KEYWORD1 12switches KEYWORD2 13switch_configured KEYWORD2 14switch_type KEYWORD2 15switch_pin KEYWORD2 16switch_circuit_type KEYWORD2 17switch_pending KEYWORD2 18switch_db_start KEYWORD2 19switch_on_value KEYWORD2 20switch_status KEYWORD2 21switch_out_pin KEYWORD2 22switch_out_pin_status KEYWORD2 23last_switched_id KEYWORD2 24 25# private variables 26_debounce KEYWORD2 27_max_switches KEYWORD2 28_num_entries KEYWORD2 29 30# macro definitions 31switched LITERAL1 32bad_params LITERAL1 33add_failure LITERAL1 34link_success LITERAL1 35link_failure LITERAL1 36on LITERAL1 37configured LITERAL1 38button_switch LITERAL1 39toggle_switch LITERAL1 40not_used LITERAL1 41circuit_C1 LITERAL1 42circuit_C2 LITERAL1 43circuit_C3 LITERAL1 44INPUT_PULLDOWN LITERAL1 45none_switched LITERAL1 46 47 48# functions 49read_switch KEYWORD2 50read_toggle_switch KEYWORD2 51read_button_switch KEYWORD2 52add_switch KEYWORD2 53link_switch_to_output KEYWORD2 54num_free_switch_slots KEYWORD2 55set_debounce KEYWORD2 56print_switch KEYWORD2 57print_switches KEYWORD2 58
ez switch library, .h file
c_cpp
Header file for the ez_switch_lib library
1// Arduino Switch Library for configuring different switch type wired 2// in common circuit schemes. 3// 4// Ron Bentley, Stafford (UK), March 2021, version 2.0 5// 6// This example and code is in the public domain and 7// may be used without restriction and without warranty. 8// 9 10#ifndef ez_switches_h 11#define ez_switches_h 12 13#include <Arduino.h> 14 15class Switches 16{ 17 public: 18 Switches(byte max_switches); 19 20#define button_switch 1 // differentiates switch type 21#define toggle_switch 2 // ditto 22 23#define INPUT_PULLDOWN 9 // not valid for Arduino boards, but it is for ESP32 boards 24#define circuit_C1 INPUT // switch circuit requires an external pull down 10k ohm resistor 25#define circuit_C2 INPUT_PULLUP // switch circuit requires no other components beyond the switch 26#define circuit_C3 INPUT_PULLDOWN // switch circuit requires no other components beyond the switch 27 28#define switched true // signifies switch has been pressed/switch cycle complete 29#define on true // used for toggle switch status 30#define not_used true // helps self document code 31#define bad_params -2 // invalid add_swith paramters 32#define add_failure -1 // add_swith could not insert a given switch, ie no space left 33#define link_success 0 // output successfully linked to a switch 34#define link_failure -1 // output pin could not be linked to a switch 35#define none_switched 255 // 'last_switched_id' initialised to this value 36 37 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38 // % Switch Control Sruct(ure) Declaration % 39 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 40 // 41 struct switch_control { 42 byte switch_type; // type of switch connected 43 byte switch_pin; // digital input pin assigned to the switch 44 byte switch_circuit_type; // the type of circuit wired to the switch 45 bool switch_on_value; // used for BUTTON SWITCHES only - defines what "on" means 46 bool switch_pending; // records if switch in transition or not 47 long unsigned int switch_db_start;// records debounce start time when associated switch starts transition 48 bool switch_status; // used for TOGGLE SWITCHES only - current state of toggle switch. 49 byte switch_out_pin; // the digital pin mapped to this switch, if any 50 bool switch_out_pin_status; // the status of the mapped pin 51 } volatile *switches; // memory will be created when class is initiated 52 53 volatile byte last_switched_id = none_switched; 54 55 // Functions available to end users 56 bool read_switch (byte sw); 57 bool read_toggle_switch (byte sw); 58 bool read_button_switch (byte sw); 59 int add_switch (byte sw_type, byte sw_pin, byte circ_type); 60 int link_switch_to_output (byte switch_id, byte output_pin, bool HorL); 61 int num_free_switch_slots (); 62 void set_debounce (int period); 63 void print_switch (byte sw); 64 void print_switches (); 65 66 private: 67 byte _num_entries = 0; // used for adding switches to switch control structure/list 68 byte _max_switches = 0; // max switches user has initialise 69 int _debounce = 10; // 10 millisecs if not specified by user code 70}; 71 72#endif
github downloads
you can download everything from github here....
github downloads
you can download everything from github here....
ez switch library, keywords file
c_cpp
Keywords for ez switch library
1# Arduino Switch Library for configuring different switch type wired 2# in common circuit schemes. 3# 4# Ron Bentley, Stafford (UK), March 2021, version 2.0 5# 6# This example and code is in the public domain and 7# may be used without restriction and without warranty. 8# 9 10# data and data structures 11Switches KEYWORD1 12switches KEYWORD2 13switch_configured KEYWORD2 14switch_type KEYWORD2 15switch_pin KEYWORD2 16switch_circuit_type KEYWORD2 17switch_pending KEYWORD2 18switch_db_start KEYWORD2 19switch_on_value KEYWORD2 20switch_status KEYWORD2 21switch_out_pin KEYWORD2 22switch_out_pin_status KEYWORD2 23last_switched_id KEYWORD2 24 25# private variables 26_debounce KEYWORD2 27_max_switches KEYWORD2 28_num_entries KEYWORD2 29 30# macro definitions 31switched LITERAL1 32bad_params LITERAL1 33add_failure LITERAL1 34link_success LITERAL1 35link_failure LITERAL1 36on LITERAL1 37configured LITERAL1 38button_switch LITERAL1 39toggle_switch LITERAL1 40not_used LITERAL1 41circuit_C1 LITERAL1 42circuit_C2 LITERAL1 43circuit_C3 LITERAL1 44INPUT_PULLDOWN LITERAL1 45none_switched LITERAL1 46 47 48# functions 49read_switch KEYWORD2 50read_toggle_switch KEYWORD2 51read_button_switch KEYWORD2 52add_switch KEYWORD2 53link_switch_to_output KEYWORD2 54num_free_switch_slots KEYWORD2 55set_debounce KEYWORD2 56reset_switch KEYWORD2 57reset_switches KEYWORD2 58button_is_pressed KEYWORD2 59print_switch KEYWORD2 60print_switches KEYWORD2 61
ez switch library, .cpp file
c_cpp
Library code file
1// Arduino Switch Library for configuring different switch type wired 2// in common circuit schemes. 3// 4// Ron Bentley, Stafford (UK), March 2021, 5// updates: 6// Sept 2022, version 3.00 7// addition of functions 'is_button_pressed' (overloaded) and 8// 'reset_switch' and 'reset_switches' 9// Sept 2022, version 3.01 10// change of library variables to unsigned declarations, generally, 11// eg byte to uint8_t, long unsigned int to uint32_t, etc 12// 13// This example and code is in the public domain and 14// may be used without restriction and without warranty. 15// 16 17#include <Arduino.h> 18#include "ez_switch_lib.h" // change "ez_switch_lib" to <ez_switch_lib> when deploying to libraries 19 20// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21// Set up switch cotrol structure and initialise internal variables. 22// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 23 24Switches::Switches(uint8_t max_switches) 25{ 26 // Establish the switch control structure (switches) of the size required. 27 // 28 switches = (switch_control *)malloc(sizeof(*switches) * max_switches); 29 if (switches == NULL) { 30 // malloc failure 31 Serial.begin(115200); 32 Serial.println("!!Failure to acquire memory of required size - PROGRAM TERMINATED!!"); 33 Serial.flush(); 34 exit(1); 35 } 36 37 // Initialise private variables 38 _num_entries = 0; // will be incremented each time a switch is added, up to _max_switches 39 _max_switches = max_switches; // transfer to internal variable 40} 41 42// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 43// Generic switch read function. 44// Read the switch defined by the function parameter. 45// Function returns a value indicating if the switch 46// has undergone a transition or not. 47// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 48 49bool Switches::read_switch(uint8_t sw) { 50 bool sw_status; 51 if (sw < 0 || sw >= _num_entries) return !switched; // out of range, slot 'sw' is not configured with a switch 52 if (switches[sw].switch_type == button_switch) { 53 sw_status = read_button_switch(sw); 54 } else { 55 sw_status = read_toggle_switch(sw); 56 } 57 // now determine if switch has output pin associated and if switched 58 // flip the output's status, ie HIGH->LOW, or LOW->HIGH 59 if (sw_status == switched && switches[sw].switch_out_pin > 0) 60 { 61 // flip the output level of associated switch output pin, if defined 62 bool status = switches[sw].switch_out_pin_status; // last status value of out_pin 63 status = HIGH - status; // flip the status value 64 switches[sw].switch_out_pin_status = status; // update current status value 65 digitalWrite(switches[sw].switch_out_pin, status);// change status of linked pin 66 } 67 return sw_status; 68} // End of read_switch 69 70// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 71// Generic toggle switch read function. 72// Test the toggle switch to see if its status has changed since last look. 73// Note that although switch status is a returned value from the function, 74// the current status of the switch ('switches[sw].switch_status') is always 75// maintained and can be tested outside of the function at any point/time. 76// It will either have a status of 'on' or '!on' (ie off). 77// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 78 79bool Switches::read_toggle_switch(uint8_t sw) { 80 uint8_t switch_pin_reading = digitalRead(switches[sw].switch_pin); // test current state of toggle pin 81 if (switches[sw].switch_circuit_type == circuit_C2) { 82 // Need to invert HIGH/LOW if circuit design sets 83 // pin HIGH representing switch in off state. 84 // ie inititialised as INPUT_PULLUP 85 switch_pin_reading = !switch_pin_reading; 86 } 87 if (switch_pin_reading != switches[sw].switch_status && !switches[sw].switch_pending) { 88 // Switch change detected so start debounce cycle 89 switches[sw].switch_pending = true; 90 switches[sw].switch_db_start = millis(); // set start of debounce timing 91 } 92 if (switches[sw].switch_pending) { 93 // We are in the switch transition cycle so check if debounce period has elapsed 94 if (millis() - switches[sw].switch_db_start >= _debounce) { 95 // Debounce period elapsed so assume switch has settled down after transition 96 switches[sw].switch_status = !switches[sw].switch_status; // flip status 97 switches[sw].switch_pending = false; // cease transition cycle 98 last_switched_id = sw; // indicates the last switch to have been processed by read function 99 return switched; 100 } 101 } 102 return !switched; 103} // End of read_toggle_switch 104 105// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 106// Read button switch function. 107// Generic button switch read function. 108// Reading is controlled by: 109// a. the function parameter which indicates which switch 110// is to be polled, and 111// b. the switch control struct(ure), referenced by a). 112// 113// Note that this function works in a nonexclusive way 114// and incorporates debounce code. 115// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 116 117bool Switches::read_button_switch(uint8_t sw) { 118 uint8_t switch_pin_reading = digitalRead(switches[sw].switch_pin); 119 if (switch_pin_reading == switches[sw].switch_on_value) { 120 // Switch is pressed (ON), so start/restart debounce process 121 switches[sw].switch_pending = true; 122 switches[sw].switch_db_start = millis(); // start elapse timing 123 return !switched; // now waiting for debounce to conclude 124 } 125 if (switches[sw].switch_pending && switch_pin_reading != switches[sw].switch_on_value) { 126 // Switch was pressed, now released (OFF), so check if debounce time elapsed 127 if (millis() - switches[sw].switch_db_start >= _debounce) { 128 // debounce time elapsed, so switch press cycle complete 129 switches[sw].switch_pending = false; 130 last_switched_id = sw; // indicates the last switch to have been processed by read function 131 return switched; 132 } 133 } 134 return !switched; 135} // End of read_button_switch 136 137// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 138// Add given switch to switch control structure, but validate 139// given paramters and ensure there is a free slot. 140// 141// Return values from add_switch are: 142// 143// >= 0 the switch control structure entry number ('switch_id') 144// for the switch added, 145// -1 add_falure - no slots available in the switch 146// control structure, 147// -2 bad_params - given paramter(s) for switch are 148// not valid. 149// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 150 151int Switches::add_switch(uint8_t sw_type, uint8_t sw_pin, uint8_t circ_type) { 152 if ((sw_type != button_switch && sw_type != toggle_switch) || 153 (circ_type != circuit_C1 && 154 circ_type != circuit_C2 && 155 circ_type != circuit_C3)) return bad_params; // bad paramters 156 if (_num_entries < _max_switches) { 157 // room to add another switch...initialise the switch's 158 // data depending on type of switch and circuit 159 switches[_num_entries].switch_type = sw_type; 160 switches[_num_entries].switch_pin = sw_pin; 161 switches[_num_entries].switch_circuit_type = circ_type; 162 switches[_num_entries].switch_pending = false; 163 switches[_num_entries].switch_db_start = 0; 164 // define what on means for this switch: 165 if (circ_type != circuit_C2) { 166 // circuit_C1 and circuit_C3 are used with pull down resistors 167 // if circuit_C1 (INPUT) then and external 10k ohm resistor needs to be fitted 168 // to the switch circuit, but if circuit_C3 (INPUT_PULLDOWN) then the resistor 169 // is internal to the microcontroller. 170 // Note that the 'on' state is represented by HIGH (3.3/5v) 171 switches[_num_entries].switch_on_value = HIGH; 172 } else { 173 // circuit_C2 (INPUT_PULLUP) with internal microcontroller pull up resistor 174 // Note that the 'on' state is represented by LOW (0v) 175 switches[_num_entries].switch_on_value = LOW; 176 } 177 if (sw_type == button_switch) { 178 switches[_num_entries].switch_status = not_used; 179 } else { 180 switches[_num_entries].switch_status = !on; 181 } 182 pinMode(sw_pin, circ_type); // establish pin set up 183 // ensure no mapping to an output pin until created explicitly 184 switches[_num_entries].switch_out_pin = 0; 185 switches[_num_entries].switch_out_pin_status = LOW; // set LOW unless explicitly changed 186 187 _num_entries++; // point to next free slot 188 return _num_entries - 1; // return 'switch_id' - given switch now added to switch control structure 189 } else return add_failure; // no room left to add another switch! 190} // End add_switch 191 192 193// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 194// Link or delink the given switch to the given digital pin as an output 195// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 196 197int Switches::link_switch_to_output(uint8_t switch_id, uint8_t output_pin, bool HorL) { 198 if (switch_id > _num_entries) { 199 return link_failure; // no such switch 200 } 201 if (output_pin == 0) { 202 // delink this output from this switch, set the output to the required level first 203 if (switches[switch_id].switch_out_pin == 0) { 204 // no output pin previously defined 205 return link_failure; 206 } 207 // set existing pin to level required state before clearing the link 208 digitalWrite(switches[switch_id].switch_out_pin, HorL); 209 } else { 210 // initialise given output pin 211 pinMode(output_pin, OUTPUT); 212 digitalWrite(output_pin, HorL); // set to param value until switched 213 } 214 switches[switch_id].switch_out_pin = output_pin; 215 switches[switch_id].switch_out_pin_status = HorL; 216 return link_success; // success 217} 218 219// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 220// Return the number of slots left unused 221// in the switch control structure. 222// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 223 224int Switches::num_free_switch_slots() { 225 return _max_switches - _num_entries; 226} // End num_free_switch_slots 227 228// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 229// Set debounce period (milliseconds). 230// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 231 232void Switches::set_debounce(uint16_t period) { 233 if (period >= 0) _debounce = period; 234} // End set_debounce 235 236// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 237// % reset the given switch to its 238// % non-pending (non-transition) state 239// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 240 241void Switches::reset_switch(uint8_t switch_id) { 242 if (switch_id < _num_entries - 1) { 243 switches[switch_id].switch_pending = false; 244 } 245} 246 247// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 248// % reset all declared switches to 249// % their non-pending (non-transition) state 250// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 251 252void Switches::reset_switches() { 253 for (uint8_t switch_id = 0; switch_id < _num_entries; switch_id++) { 254 switches[switch_id].switch_pending = false; 255 } 256} 257 258// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 259// % Note: this function applies to button 260// % switches ONLY. 261// % If the specified switch id is a button 262// % switch, then the function will return 263// % true if the button switch is CURRENTLY 264// % being pressed, ie in transition, and false 265// % otherwise. 266// % Note: If the button has a linked output then this 267// % will be automatically switched (toggled) 268// % if the 'process_link' parameter is true, 269// % otherwise, it will not be switched (toggled) 270// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 271 272bool Switches::button_is_pressed(uint8_t switch_id, bool process_link) { 273 // check switch is declared 274 if (switch_id < _num_entries) { 275 // check if switch is a button switch 276 if (switches[switch_id].switch_type == button_switch) { 277 // all checks done, read the switch 278 if (process_link) { 279 // request is to process any lined output. 280 // only the read_switch function will process any linked output 281 read_switch(switch_id); 282 } else { 283 // request is NOT to process any linked output, so we need to use 284 // read_button_switch rather than read_switch, which ignores any 285 // linked output 286 read_button_switch(switch_id); 287 } 288 return switches[switch_id].switch_pending; // this will be either true if in trasition or false if not 289 } 290 } 291 return false; 292} 293 294// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 295// % Note: this function applies to button 296// % switches ONLY. 297// % If the specified switch id is a button 298// % switch, then the function will return 299// % true if the button switch is CURRENTLY 300// % being pressed, ie in transition, and false 301// % otherwise. 302// % Note that this function will NOT process 303// % any linked output associated with this 304// % switch. If this is required then use the 305// % overloaded version, thus: 306// % button_is_pressed(switch_id, true); 307// % 308// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 309 310bool Switches::button_is_pressed(uint8_t switch_id) { 311 return button_is_pressed(switch_id, false); 312} 313 314// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 315// Print given switch control data. 316// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 317 318void Switches::print_switch(uint8_t sw) { 319 if (0 <= sw && sw < _num_entries ) { 320 Serial.print(F("sw_id: = ")); 321 Serial.println(sw); 322 Serial.print(F("sw_type = ")); 323 uint8_t sw_type = switches[sw].switch_type; 324 if (sw_type == button_switch)Serial.print(F("BUTTON SWITCH")); 325 else Serial.print(F("TOGGLE SWITCH")); 326 Serial.print(F(" sw_pin = ")); 327 Serial.print(switches[sw].switch_pin); 328 Serial.print(F("\ circ_type = ")); 329 uint8_t circ_type = switches[sw].switch_circuit_type; 330 if (circ_type == circuit_C1) { 331 Serial.print(F("INPUT/circuit_C1/")); 332 } else if (circ_type == circuit_C2) { 333 Serial.print(F("INPUT_PULLUP/circuit_C2/")); 334 } else { 335 Serial.print(F("INPUT_PULLDOWN/circuit_C3/")); 336 } 337 Serial.println(circ_type); 338 Serial.print("on_value = "); 339 if (switches[sw].switch_on_value == HIGH)Serial.print(F("HIGH")); 340 else Serial.print(F("LOW ")); 341 Serial.print(F("\ \ sw_status = ")); 342 uint8_t sw_status = switches[sw].switch_status; 343 if (sw_type == button_switch)Serial.print(F("n/a")); else { 344 if (sw_status == on)Serial.print(F("ON")); 345 else Serial.print(F("OFF")); 346 } 347 Serial.print(F("\ pending = ")); 348 if (switches[sw].switch_pending)Serial.print(F("YES")); 349 else Serial.print(F("NO ")); 350 Serial.print(F("\ db_start = ")); 351 Serial.print(switches[sw].switch_db_start); 352 Serial.println(F(" msecs")); 353 if (switches[sw].switch_out_pin == 0) { 354 // switch does not have a linked output 355 Serial.println(F("*** No linked output pin")); 356 } else { 357 // switch has a linked output 358 Serial.print(F("Linked output pin = ")); 359 Serial.print(switches[sw].switch_out_pin); 360 Serial.print(F("\ linked pin status = ")); 361 if (switches[sw].switch_out_pin_status == LOW)Serial.println(F("LOW")); 362 else Serial.println(F("HIGH")); 363 } 364 Serial.println(); 365 Serial.flush(); 366 } 367} // End print_switch 368 369// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 370// Print all switch control data set up. 371// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 372 373void Switches::print_switches() { 374 Serial.println(F("\ 375Declared & configured switches:")); 376 for (uint8_t sw = 0; sw < _num_entries; sw++) { 377 print_switch(sw); 378 } 379} // End print_switches 380
ez switch library, .h file
c_cpp
Header file for the ez_switch_lib library
1// Arduino Switch Library for configuring different switch type wired 2// in common circuit schemes. 3// 4// Ron Bentley, Stafford (UK), March 2021, 5// updates: 6// Sept 2022, version 3.00 7// addition of functions 'is_button_pressed' (overloaded) and 8// 'reset_switch' and 'reset_switches' 9// Sept 2022, version 3.01 10// change of library variables to unsigned declarations, generally, 11// eg byte to uint8_t, long unsigned int to uint32_t, etc 12// 13// This example and code is in the public domain and 14// may be used without restriction and without warranty. 15// 16 17#ifndef ez_switches_h 18#define ez_switches_h 19#include <Arduino.h> 20 21class Switches 22{ 23 public: 24 Switches(uint8_t max_switches); 25 26#define button_switch 1 // differentiates switch type 27#define toggle_switch 2 // ditto 28 29#ifndef INPUT_PULLDOWN 30#define INPUT_PULLDOWN INPUT // default to INPUT type if not already defined 31#endif 32 33#define circuit_C1 INPUT // switch circuit requires an external pull down 10k ohm resistor 34#define circuit_C2 INPUT_PULLUP // switch circuit requires no other components beyond the switch 35#define circuit_C3 INPUT_PULLDOWN // switch circuit requires no other components beyond the switch, only ESP 32 36 37#define switched true // signifies switch has been pressed/switch cycle complete 38#define on true // used for toggle switch status 39#define not_used true // helps self document code 40#define bad_params -2 // invalid add_swith paramters 41#define add_failure -1 // add_swith could not insert a given switch, ie no space left 42#define link_success 0 // output successfully linked to a switch 43#define link_failure -1 // output pin could not be linked to a switch 44#define none_switched 255 // 'last_switched_id' initialised to this value 45 46 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 47 // % Switch Control Sruct(ure) Declaration % 48 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 49 // 50 struct switch_control { 51 uint8_t switch_type; // type of switch connected 52 uint8_t switch_pin; // digital input pin assigned to the switch 53 uint8_t switch_circuit_type; // the type of circuit wired to the switch 54 bool switch_on_value; // used for BUTTON SWITCHES only - defines what "on" means 55 bool switch_pending; // records if switch in transition or not 56 uint32_t switch_db_start; // records debounce start time when associated switch starts transition 57 bool switch_status; // used for TOGGLE SWITCHES only - current state of toggle switch. 58 uint8_t switch_out_pin; // the digital pin mapped to this switch, if any 59 bool switch_out_pin_status; // the status of the mapped pin 60 } volatile *switches; // memory will be created when class is instantiated 61 62 volatile uint8_t last_switched_id = none_switched; 63 64 // Functions available to end users 65 bool read_switch (uint8_t switch_id); 66 bool read_toggle_switch (uint8_t switch_id); 67 bool read_button_switch (uint8_t switch_id); 68 int add_switch (uint8_t sw_type, uint8_t sw_pin, uint8_t circ_type); 69 int link_switch_to_output (uint8_t switch_id, uint8_t output_pin, bool HorL); 70 int num_free_switch_slots (); 71 void set_debounce (uint16_t period); 72 void reset_switch (uint8_t switch_id); 73 void reset_switches (); 74 bool button_is_pressed (uint8_t switch_id, bool process_link); 75 bool button_is_pressed (uint8_t switch_id); 76 void print_switch (uint8_t switch_id); 77 void print_switches (); 78 79 private: 80 uint8_t _num_entries = 0; // used for adding switches to switch control structure/list 81 uint8_t _max_switches = 0; // max switches user has initialise 82 uint16_t _debounce = 10; // 10 millisecs if not specified by user code 83}; 84 85#endif 86
Downloadable files
Common switch circuit type C3
Reference schematic for wiring switch
Common switch circuit type C3
Common switch circuit type C1
Reference schematic for wiring switch
Common switch circuit type C1
Common switch circuit type C2
Reference schematic for wiring switch
Common switch circuit type C2
Common switch circuit type C1
Reference schematic for wiring switch
Common switch circuit type C1
Common switch circuit type C2
Reference schematic for wiring switch
Common switch circuit type C2
Common switch circuit type C3
Reference schematic for wiring switch
Common switch circuit type C3
LED circuit
Reference schematic for wiring a LED
LED circuit
Comments
Only logged in users can leave comments
ronbentley1
2 years ago
Thank you for the observation. I will be moving the code and files to be Arduino IDE Library Manager downloadable soon, so that should make things easier. In the mean time, I have updated the zip download link which does work, just move the SRC files into a libraries directory called ez_switch_lib. Cheers
sonofcy
3 years ago
Getting an error when I try to install the library after downloading the zip file. The error is in the IE, it is "Specified folder/zip file does not contain a valid library"
ronbentley1
2 years ago
Thank you for the observation. I will be moving the code and files to be Arduino IDE Library Manager downloadable soon, so that should make things easier. In the mean time, I have updated the zip download link which does work, just move the SRC files into a libraries directory called ez_switch_lib. Cheers
alejandrom
4 years ago
Nice work and documentation. Thanks for sharing.
Anonymous user
2 years ago
Getting an error when I try to install the library after downloading the zip file. The error is in the IE, it is "Specified folder/zip file does not contain a valid library"