цифровая электроника
вычислительная техника
встраиваемые системы

 


Библиотека Arduino для работы с переключателями switch_lib

Автор: Mike(admin) от 21-03-2021, 23:55

Переключатели порой могут быть неприятными и проблематичными в работе для непосвященных и для тех, кто хорошо привык использовать их в своих проектах. Это такое простое устройство, но с таким несметным количеством стилей, типов и характеристик.


Библиотека Arduino для работы с переключателями switch_lib

Но если вы довольны работой с переключателями всех типов, то, возможно, эта статья не для вас, продолжайте делать то, как вам удобно. Однако, если переключатели для вас в новинку, вы боретесь с ними или хотите использовать другой набор инструментов и методов для их включения в свои проекты, тогда читайте дальше – библиотека switch_lib предлагает такую поддержку.


Вкратце, библиотека switch_lib предоставляет набор расширенных возможностей для считывания значений переключателей разных типов и различных схем подключения, а также устраняет проблемы разработчика, связанные с «шумом» переключения. Действительно, switch_lib дает разработчику выбор способа подключения коммутатора, поддерживая обе наиболее распространенные схемы подключения без дополнительных компонентов, помимо проводов, и, при желании, устанавливать понижающие резисторы на 10 кОм. Библиотека switch_lib предоставляет программный подход к управлению и контролю переключателя.


Библиотека Arduino для работы с переключателями switch_lib

Библиотека Arduino для работы с переключателями switch_lib

Библиотека switch_lib обеспечивает следующие функции и возможности:


  • распределение динамической памяти в зависимости от количества переключателей, которые вы хотите включить в свой проект
  • возможности многопозиционного типа
  • смешивание разных типов переключателей
  • поддержка схемы подключения с двумя переключателями, прозрачная для разработчика программного обеспечения
  • поддержка как кнопочных, так и тумблерных переключателей простая настройка переключателя, с переключением выхода переключателя или без него
  • возможность подключения цифрового выходного контакта к любому переключателю для автоматического переключения выходных контактов без кодирования конечным пользователем
  • настраиваемый и автоматический дребезг коммутационных цепей
  • общая функция считывания значения переключателя (независимая от типа переключателя)
  • функция чтения специального кнопочного переключателя
  • перехват ошибок из функций чтения и связывания
  • прямой доступ ко всем переменным управления переключателем
  • отчет о состоянии управления переключателем через последовательный монитор
  • подробное руководство пользователя

Руководство пользователя предоставляет исчерпывающее описание объема и возможностей библиотеки switch_lib, включая скетчи рабочих примеров. Чтобы полностью оценить возможности библиотеки switch_lib, загрузите руководство пользователя с github, перейдя по ссылке https://github.com/ronbentley1/switch_lib-Arduino-Library/blob/main/switch_lib_user_guide%2C%20v1.00.pdf. Далее также будут представлены основные файлы библиотеки.


switch_lib.h



#ifndef switches_h
#define switches_h

#include <Arduino.h>

class Switches
{
  public:
    Switches(byte max_switches);

#define button_switch         1      // differentiates switch type
#define toggle_switch         2      // ditto

#define circuit_C1        INPUT      // switch circuit requires an external pull down 10k ohm resistor
#define circuit_C2 INPUT_PULLUP      // switch circuit requires no other components beyond the switch

#define switched           true      // signifies switch has been pressed/switch cycle complete
#define on                 true      // used for toggle switch status
#define not_used           true      // helps self document code
#define bad_params           -2      // invalid add_swith paramters
#define add_failure          -1      // add_swith could not insert a given switch, ie no space left
#define link_success          0      // output successfully linked to a switch
#define link_failure         -1      // output pin could not be linked to a switch

    // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    // %                   Switch Control Sruct(ure) Declaration                 %
    // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    //
    struct switch_control {
      byte switch_type;                 // type of switch connected
      byte switch_pin;                  // digital input pin assigned to the switch
      byte switch_circuit_type;         // the type of circuit wired to the switch
      bool switch_on_value;             // used for BUTTON SWITCHES only - defines what "on" means
      bool switch_pending;              // records if switch in transition or not
      long unsigned int switch_db_start;// records debounce start time when associated switch starts transition
      bool switch_status;               // used for TOGGLE SWITCHES only - current state of toggle switch.
      byte switch_out_pin;              // the digital pin mapped to this switch, if any
      bool switch_out_pin_status;       // the status of the mapped pin

    } *switches;                        // memory will be created when class is initiated

    // Functions available to end users
    bool read_switch           (byte sw);
    bool read_toggle_switch    (byte sw);
    bool read_button_switch    (byte sw);
    int  add_switch            (byte sw_type, byte sw_pin, byte circ_type);
    int  link_switch_to_output(byte switch_id, byte output_pin, bool HorL);
    int  num_free_switch_slots ();
    void set_debounce          (int period);
    void print_switch          (byte sw);
    void print_switches        ();

  private:
    byte _num_entries  = 0;  // used for adding switches to switch control structure/list
    byte _max_switches = 0;  // max switches user has initialise
    int _debounce      = 10; // 10 milliscs if not specified by user code
};

#endif

switch_lib.cpp



#include <Arduino.h>
#include <switch_lib.h>

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Set up switch cotrol structure and initialise internal variables.
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Switches::Switches(byte max_switches)
{
  // Establish the switch control structure (switches) of the size required
  switches = malloc(sizeof(*switches) * max_switches);
  if (switches == NULL) {
    // malloc failure
    Serial.begin(9600);
    Serial.println("!!Failure to acquire memory of required size - PROGRAM TERMINATED!!");
    Serial.flush();
    exit(1);
  }

  // Initialise private variables
  _num_entries  = 0;            // will be incremented each time a switch is added, up to _max_switches
  _max_switches = max_switches; // transfer to internal variable
}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Generic switch read function.
// Read the switch defined by the function parameter.
// Function returns a value indicating if the switch
// has undergone a transition or not.
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bool Switches::read_switch(byte sw) {
  bool sw_status;
  if (sw < 0 || sw >= _num_entries) return !switched; // out of range, slot 'sw' is not configured with a switch
  if (switches[sw].switch_type == button_switch) {
    sw_status = read_button_switch(sw);
  } else {
    sw_status = read_toggle_switch(sw);
  }
  // now determine if switch has output pin associated and if switched
  // flip the output's status, ie HIGH->LOW, or LOW->HIGH
  if (sw_status == switched && switches[sw].switch_out_pin > 0)
   {
     // flip the output level of associated switch output pin, if defined
     bool status = switches[sw].switch_out_pin_status; // last status value of out_pin
     status = HIGH - status;                           // flip the status value
     switches[sw].switch_out_pin_status = status;      // update current status value
     digitalWrite(switches[sw].switch_out_pin, status);
   }
   return sw_status;
}  // End of read_switch

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Generic toggle switch read function.
// Test the toggle switch to see if its status has changed since last look.
// Note that although switch status is a returned value from the function,
// the current status of the switch ('switches[sw].switch_status') is always
// maintained and can be tested outside of the function at any point/time.
// It will either have a status of 'on' or '!on' (ie off).
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bool Switches::read_toggle_switch(byte sw) {
  byte switch_pin_reading = digitalRead(switches[sw].switch_pin);  // test current state of toggle pin
  if (switches[sw].switch_circuit_type == circuit_C2) {
    // Need to invert HIGH/LOW if circuit design sets
    // pin HIGH representing switch in off state.
    // ie inititialised as INPUT_PULLUP
    switch_pin_reading = !switch_pin_reading;
  }
  if (switch_pin_reading != switches[sw].switch_status && !switches[sw].switch_pending) {
    // Switch change detected so start debounce cycle
    switches[sw].switch_pending = true;
    switches[sw].switch_db_start = millis();  // set start of debounce timing
  }
    if (switches[sw].switch_pending) {
      // We are in the switch transition cycle so check if debounce period has elapsed
      if (millis() - switches[sw].switch_db_start >= _debounce) {
        // Debounce period elapsed so assume switch has settled down after transition
        switches[sw].switch_status  = !switches[sw].switch_status;  // flip status
        switches[sw].switch_pending = false;                        // cease transition cycle
        return switched;
     }
  }
  return !switched;
} // End of read_toggle_switch

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Read button switch function.
// Generic button switch read function.
// Reading is controlled by:
//   a. the function parameter which indicates which switch
//      is to be polled, and
//   b. the switch control struct(ure), referenced by a).
//
// Note that this function works in a nonexclusive way
// and incorporates debounce code.
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

bool Switches::read_button_switch(byte sw) {
  byte switch_pin_reading = digitalRead(switches[sw].switch_pin);
  if (switch_pin_reading == switches[sw].switch_on_value) {
    // Switch is pressed (ON), so start/restart debounce process
    switches[sw].switch_pending = true;
    switches[sw].switch_db_start   = millis();  // start elapse timing
    return !switched;                           // now waiting for debounce to conclude
  }
  if (switches[sw].switch_pending && switch_pin_reading != switches[sw].switch_on_value) {
    // Switch was pressed, now released (OFF), so check if debounce time elapsed
    if (millis() - switches[sw].switch_db_start >= _debounce) {
      // dounce time elapsed, so switch press cycle complete
      switches[sw].switch_pending = false;
      return switched;
    }
  }
  return !switched;
}  // End of read_button_switch

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Add given switch to switch control structure, but validate
// given paramters and ensure there is a free slot.
//
// Return values from add_switch are:
//
//    >= 0 the switch control structure entry number ('switch_id')
//         for the switch added,
//      -1 add_falure - no slots available in the switch
//         control structure,
//      -2 bad_params - given paramter(s) for switch are
//         not valid.
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

int Switches::add_switch(byte sw_type, byte sw_pin, byte circ_type) {
  if ((sw_type != button_switch && sw_type != toggle_switch) ||
      (circ_type != circuit_C1 && circ_type != circuit_C2)) return bad_params;  // bad paramters
  if (_num_entries < _max_switches) {
    // room to add another switch...initialise the switch's
    // data depending on type of switch and circuit
    switches[_num_entries].switch_type    = sw_type;
    switches[_num_entries].switch_pin     = sw_pin;
    switches[_num_entries].switch_circuit_type   = circ_type;
    switches[_num_entries].switch_pending = false;
    switches[_num_entries].switch_db_start   = 0;
    if (circ_type == circuit_C1) {
      switches[_num_entries].switch_on_value = HIGH;
    } else {
      switches[_num_entries].switch_on_value = LOW;
    }
    if (sw_type == button_switch) {
      switches[_num_entries].switch_status = not_used;
    } else {
      switches[_num_entries].switch_status = !on;
    }
    pinMode(sw_pin, circ_type);  // establish pin set up
    // ensure no mapping to an output pin until created explicitly
    switches[_num_entries].switch_out_pin        = 0;
    switches[_num_entries].switch_out_pin_status = LOW;  // set LOW unless explicitly changed

    _num_entries++;              // point to next free slot
    return _num_entries - 1;     // return 'switch_id' - given switch now added to switch control structure
  } else return add_failure;     // no room left to add another switch!
}  // End add_switch


// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Link or delink the given switch to the given digital pin as an output
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

int Switches::link_switch_to_output(byte switch_id, byte output_pin, bool HorL){
  if(switch_id > _num_entries) {return link_failure;} // no such switch
  if (output_pin == 0){
    // delink this output from this switch, set te output to the required level first
    if (switches[switch_id].switch_out_pin == 0){
      // no output pin previously defined
      return link_failure;
    }
    // set existing pin to level required state before clearing the link
    digitalWrite(switches[switch_id].switch_out_pin, HorL); 
  }else {
    // initialise given output pin
    pinMode(output_pin, OUTPUT); 
    digitalWrite(output_pin, HorL); // set to param value until switched
  }
  switches[switch_id].switch_out_pin        = output_pin;
  switches[switch_id].switch_out_pin_status = HorL;
  return link_success;           // success
}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Return the number of slots left unused
// in the switch control structure.
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

int Switches::num_free_switch_slots() {
  return _max_switches - _num_entries;
} // End num_free_switch_slots

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Set debounce period (milliseconds).
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void Switches::set_debounce(int period) {
  if (period >= 0)  _debounce = period;
}  // End set_debounce

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Print given switch control data.
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void Switches::print_switch(byte sw) {
  if (0 <= sw && sw < _num_entries ) {
    Serial.print("slot: ");
    Serial.print(sw);
    Serial.print("  sw_type= ");
    Serial.print(switches[sw].switch_type);
    Serial.print("\tsw_pin= ");
    Serial.print(switches[sw].switch_pin);
    Serial.print("\tcirc_type= ");
    Serial.print(switches[sw].switch_circuit_type);
    Serial.print("\tpending= ");
    Serial.print(switches[sw].switch_pending);
    Serial.print("\tdb_start= "); 
    Serial.print(switches[sw].switch_db_start);
    Serial.print("\ton_value= ");
    Serial.print( switches[sw].switch_on_value);
    Serial.print("\tsw_status= ");
    Serial.println(switches[sw].switch_status);
    Serial.print("\t\t\top_pin= ");
    Serial.print(switches[sw].switch_out_pin);
    Serial.print("\top_status= ");
    Serial.println(switches[sw].switch_out_pin_status);
    Serial.flush();
  }
} // End print_switch

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Print all switch control data set up.
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

void Switches::print_switches() {
  Serial.println(F("\nDeclared & configured switches:"));
  for (byte sw = 0; sw < _num_entries; sw++) {
    print_switch(sw);
  }
} // End print_switches

Список ключей библиотеки



# data and data structures
Switches	KEYWORD1
switches	KEYWORD2
switch_configured	KEYWORD2
switch_type	KEYWORD2
switch_pin	KEYWORD2
switch_circuit_type	KEYWORD2
switch_pending	KEYWORD2
switch_db_start	KEYWORD2
switch_on_value	KEYWORD2
switch_status	KEYWORD2
switch_out_pin	KEYWORD2
switch_out_pin_status	KEYWORD2

# private variables
_debounce	KEYWORD2
_max_switches	KEYWORD2
_num_entries	KEYWORD2

# macro definitions
switched	KEYWORD2
bad_params	KEYWORD2
add_failure	KEYWORD2
link_success	KEYWORD2
link_failure	KEYWORD2
on	KEYWORD2
configured	KEYWORD2
button_switch	KEYWORD2
toggle_switch	KEYWORD2
not_used	KEYWORD2
circuit_C1	KEYWORD2
circuit_C2	KEYWORD2


# functions
read_switch	KEYWORD2
read_toggle_switch	KEYWORD2
read_button_switch	KEYWORD2
add_switch	KEYWORD2
link_switch_to_output	KEYWORD2
num_free_switch_slots	KEYWORD2
set_debounce	KEYWORD2
print_switch	KEYWORD2
print_switches	KEYWORD2



© digitrode.ru


Теги: Arduino




Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Комментарии:

Оставить комментарий