Устранение дребезга с применением вертикальных счетчиков.

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем SergeiL, 16 мар 2017.

  1. SergeiL

    SergeiL Гуру

    Периодически читая форум, увидел, что у многих часто возникает вопрос с устранением дребезга при обработке нажатий кнопок или переключателей, чтения состояния оборудования, подключенного к цифровым входам.

    Видел, что кто-то пытается устранять дребезг дополнительными элементами обвязки, но мне кажется это излишнее. Достаточно лишь элементов защиты порта от перенапряжения или напряжения обратной полярности на входе, а дребезг прекрасно устраняется программно.

    В связи с этим, решил поделиться используемой мной, уже много лет, функцией устранения дребезга с так называемыми «вертикальными счетчиками».

    Обработка делится на две части:

    Первая часть - это детектирование событий.
    Идея состоит в периодической ( период 5-10мс ) загрузке состояний со всех входов в переменную, где каждый бит отвечает за определенный вход. Далее функция устранения дребезга проверяет, не менялось ли состояние входа последние 4 проверки. Если состояние было стабильным последние 4 раза и стабильное состояние не соответствует предыдущему стабильному значению, в переменной флагов взводится бит, соответствующий данному входу.
    Главное что вся обработка дребезга выполняется параллельно для всех входов и делается это несколькими инструкциями, что позволяет разместить ее в даже в обработчике таймера.

    Переменных флагов две:
    • в одной бит взводится в 1, если вход перешел в ON или нажата кнопка
    • во второй бит взводится в 1, если вход перешел в OFF или кнопка отпущена.

    Вторая часть - это обработка событий.
    В этой части проверяются флаги и если флаг взведен вызывается обработчик, далее флаг обязательно сбрасывается.

    В случае Arduino, обе части могут выполняться последовательно в loop(), но возможны варианты.

    Можно первую и вторую часть перенести в обработчик таймера, и тогда устройство будет очень стабильно реагировать на входные события.

    Можно первую часть перенести в обработчик таймера, а вторую оставить в loop() или main() .

    Главное достоинство данного варианта – это компактность, скорость обработки и надежность.

    Собственно функция:
    Код (C++):
    //------------------ ФУНКЦИЯ УСТР. ДРЕБЕЗГА --------------------------------------
    // Глобальные переменные

    // биты в байтах ниже взводятся обработчике дребезга, можно в прерывании от таймера и сбрасываются программой обработчиком событий
    byte LATCH_ON   = 0;     // вход перешел в 1
    byte LATCH_OFF  = 0;     // вход вернулся в 0

    void Input_CHK(void)         // вызывается каждые 10 мсек, можно из таймера
    {
      static byte SWKEYS = 0;  // состояние вводов
      static byte SLATCH = 0;  // текущее устоявшееся значение входов после устранения дребезга  
      static byte VCBIT0 = 0;  // Вертикальный счетчик бит 0
      static byte VCBIT1 = 0;  // Вертикальный счетчик бит 1
      static byte VCMASK = 0;  // Маска
      static byte VCTEMP = 0;  //


        SWKEYS = Input_Read();         // загрузим значения входов в глобальную переменную SWKEYS

        VCMASK = SWKEYS ^ SLATCH;                     // скинем счетчики для установившихся и неактивных значений
        VCBIT0 &= VCMASK;
        VCBIT1 &= VCMASK;
                                                      //  Каждая '1' в SLATCH представляет установившееся значение  
                                                      //  каждый '0' установившееся нулевое значение                
        SLATCH ^= (VCTEMP = VCMASK & VCBIT0 & VCBIT1);

        if( VCTEMP )                                  // есть изменения входов, взведем флаги
      {
         LATCH_ON  |= VCTEMP &  SWKEYS;               // взведем биты нажатых кнопок и сработавших входов.
         LATCH_OFF |= VCTEMP & ~SWKEYS;               // Биты сбрасываются в обработчиках.
      }
     
        VCBIT1 ^= (VCMASK & VCBIT0);                   // инкрементируем счетчик.
        VCBIT0 ^= (VCMASK);

    }

    //------------------ Чтение цифровых входов --------------------------------------

    byte Input_Read(void)
    {
          byte result = 0;                              // копим побитовое состояние входов
          byte i,j;
          for (i=1,j=0; j < PIN_IN_NUMB; j++,i=i<<1)    // пробежимся по всем входам
          {                                  
                                                        // Если при нажатии кнопки на входе появляется VCC - в if оставляем == HIGH.
              if ( digitalRead(InputPins[j]) == HIGH )  // Если при нажатии кнопки на входе появляется GND - заменить HIGH на LOW
                result |= i;                            // Дальше всегда будем считать, что если бит в 1 - это кнопка нажата или на входе ON.
          }                                             //                                             0 - это кнопка отпущена или на входе OFF.
                                                        // в result "1" взводится в соответствующем бите, если на входе присутствует ON. номер бита сответствует номеру входа
                                                        // например, если на входе 2 - ( в define в самом верху определено, что это цифровой пин 0),
                                                        // (диапазон 0-7 InputPins[2]) присутсвует 1 - в result добавится 1 в 2-ом от нуля бите.  00000100
          return(result);
    }
     
     
    Последнее редактирование: 6 фев 2018
    KindMan и ИгорьК нравится это.
  2. SergeiL

    SergeiL Гуру

    Пример с чтением 8-ми входов и устранением дребезга:
    Код (C++):
    #define PIN_IN_0 3     // для удобства назначим физическим портам ардуино логическое имя, которое занесем потом в массив
    #define PIN_IN_1 1
    #define PIN_IN_2 0     //  Логический вход 2: соответствует Цифровому входу 0 на Arduino
    #define PIN_IN_3 4
    #define PIN_IN_4 5
    #define PIN_IN_5 7
    #define PIN_IN_6 6
    #define PIN_IN_7 2

    #define PIN_IN_NUMB 8 // количество используемых входов значение от 1 до 8.
                          // Если входов больше 8 ходов - меняем размер переменных участвующих в хранении результатов с byte на unsigned int или long

    byte InputPins[PIN_IN_NUMB] = { PIN_IN_0,PIN_IN_1,PIN_IN_2,PIN_IN_3,PIN_IN_4,PIN_IN_5,PIN_IN_6,PIN_IN_7};  // заносим номера пинов в массив, для обработки через for

    #define PIN_READ_TO 10L             // 10 ms  периодичность проверки входов. Оптимальным является интервал 5-10мс. соответственно в результате сигнал о нажатии будет получен через 20-40мс  (в данном случае 40мс)
    unsigned long   LastPinReadMs;      // переменная для сохранения времени, когда были считаны значения с цифорвых входов


    //------------------ Чтение цифровых входов --------------------------------------

    byte Input_Read(void)
    {
          byte result = 0;                              // копим побитовое состояние входов
          byte i,j;
          for (i=1,j=0; j < PIN_IN_NUMB; j++,i=i<<1)    // пробежимся по всем входам
          {                              
                                                        // Если при нажатии кнопки на входе появляется VCC - в if оставляем == HIGH.
              if ( digitalRead(InputPins[j]) == HIGH )  // Если при нажатии кнопки на входе появляется GND - заменить HIGH на LOW
                result |= i;                            // Дальше всегда будем считать, что если бит в 1 - это кнопка нажата или на входе ON.
          }                                             //                                             0 - это кнопка отпущена или на входе OFF.
                                                        // в result "1" взводится в соответствующем бите, если на входе присутствует ON. номер бита сответствует номеру входа
                                                        // например, если на входе 2 - ( в define в самом верху определено, что это цифровой пин 0),
                                                        // (диапазон 0-7 InputPins[2]) присутсвует 1 - в result добавится 1 в 2-ом от нуля бите.  00000100
          return(result);
    }

    //------------------ ФУНКЦИЯ УСТР. ДРЕБЕЗГА --------------------------------------
    // Глобальные переменные

    // биты в байтах ниже взводятся обработчике дребезга, можно в прерывании от таймера и сбрасываются программой обработчиком событий
    byte LATCH_ON   = 0;     // вход перешел в 1
    byte LATCH_OFF  = 0;     // вход вернулся в 0

    void Input_CHK(void)         // вызывается каждые 10 мсек, можно из таймера
    {
        static byte SWKEYS = 0;            // состояние вводов
        static byte SLATCH = 0;            // текущее устоявшееся значение входов после устранения дребезга  
        static byte VCBIT0 = 0;            // Вертикальный счетчик бит 0
        static byte VCBIT1 = 0;            // Вертикальный счетчик бит 1
        static byte VCMASK = 0;            // Маска
        static byte VCTEMP = 0;            //

        SWKEYS = Input_Read();                         // загрузим значения входов в глобальную переменную SWKEYS

        VCMASK = SWKEYS ^ SLATCH;                   // скинем счетчики для установившихся и неактивных значений
        VCBIT0 &= VCMASK;
        VCBIT1 &= VCMASK;
                                                      //  Каждая '1' в SLATCH представляет установившееся значение
                                                      //  каждый '0' установившееся нулевое значение            
        SLATCH ^= (VCTEMP = VCMASK & VCBIT0 & VCBIT1);

        if( VCTEMP )                                  // есть изменения входов, взведем флаги
      {
         LATCH_ON  |= VCTEMP &  SWKEYS;               // взведем биты нажатых кнопок и сработавших входов.
         LATCH_OFF |= VCTEMP & ~SWKEYS;               // Биты сбрасываются в обработчиках.
      }

        VCBIT1 ^= (VCMASK & VCBIT0);                   // инкрементируем счетчик.
        VCBIT0 ^= (VCMASK);

    }

    void setup()
    {
        unsigned long strt_ms;
        byte j;

        for (j=0; j < PIN_IN_NUMB; j++)        // переключим нужные порты на ввод
            pinMode(InputPins[j], INPUT);
     
        Serial.begin(115200);

        strt_ms = millis();
        while (millis()- strt_ms < 5000L ) // 5 sec wait for serial port. Needed for Leonardo only
        {
          if (Serial)
          {
            Serial.println("Serial Connected");
            break;
          }
        }
    }


    void Input_On(byte number)
    {
      Serial.print("  Input ");                // выполним действие по нажатию на кнопку.  номер кнопку в переменной "number"
      Serial.print(number);
      Serial.print(" = ON");
    }

    void Input_Off(byte number)
    {
      Serial.print("  Input ");                // ЕСЛИ НУЖНО! выполним действие по отпусканию кнопки.  номер кнопку в переменной "number"
      Serial.print(number);
      Serial.print(" = OFF");
    }


    void loop()
    {
       byte j,i;

       if ((millis() - LastPinReadMs) > PIN_READ_TO)      // выполняется каждые 10мс (PIN_READ_TO)
       {  
          Input_CHK();                                    // читаем значение, игнорируем дребезг
          LastPinReadMs = millis();                       // запомним время
       }


       if (LATCH_ON != 0 || LATCH_OFF != 0  )          // Если есть изменения на входах - обработаем.
       {
            Serial.println("");
            for (i=1,j=0; j < PIN_IN_NUMB; j++,i=i<<1)   // пробежимся по всем входам
            {
              if (LATCH_ON & i)                          // Если копка была нажата или вход перешел в ON
              {
                Input_On(j);
                LATCH_ON &= ~i;                          // Обязательно сбросим бит, так как данное событие обработано
              }
     
              if (LATCH_OFF & i)                          // Если копка была отпущена или вход перешел в OFF  ЕСЛИ НУЖНО.
              {
                Input_Off(j);
                LATCH_OFF &= ~i;                        // Обязательно сбросим бит, так как данное событие обработано
              }
            }
       }
       


      //   ваш код....

    }

    Пример работы функции, если на входах появляется следующая последовательность:
    0,1,3,0,1,3,3,2,3,1,1,3,0,2,3,4,0,2,0,0,0,0,0;

    1 - это 00000001 - на нулевом входе "1", остальные "0"
    3 - это 00000011 - на нулевом и первом входах "1", остальные "0"

    Результат после обработки:
    Step = 00 Test Val = 000
    Step = 01 Test Val = 001
    Step = 02 Test Val = 011
    Step = 03 Test Val = 000
    Step = 04 Test Val = 001
    Step = 05 Test Val = 011
    Step = 06 Test Val = 011
    Step = 07 Test Val = 010
    Step = 08 Test Val = 011
    Input 1 = ON Первый вход перешел в "1"
    Step = 09 Test Val = 001
    Step = 10 Test Val = 001
    Step = 11 Test Val = 011
    Input 0 = ON Нулевой вход перешел в "1"
    Step = 12 Test Val = 000
    Step = 13 Test Val = 010
    Step = 14 Test Val = 011
    Step = 15 Test Val = 100
    Step = 16 Test Val = 000
    Step = 17 Test Val = 010
    Step = 18 Test Val = 000
    Input 0 = OFF Нулевой вход перешел в "0"
    Step = 19 Test Val = 000
    Step = 20 Test Val = 000
    Step = 21 Test Val = 000
    Input 1 = OFF Первый вход перешел в "0"
    Step = 22 Test Val = 000


    В свое время, когда нашел эту идею, был приятно поражен решением!
     
    Последнее редактирование: 6 фев 2018
    ИгорьК нравится это.
  3. ostrov

    ostrov Гуру

    Вы про кольцевой буфер слышали когда нибудь? Задача антидребезга решается несколькими строками для любого кол-ва кнопок.
     
  4. SergeiL

    SergeiL Гуру

    А мне кажется, Вы не поняли о чем это...
    Это про то, как обработать дребезг на 8 ДИСКРЕТНЫХ входах,
    • ПАРАЛЛЕЛЬНО,
    • с использованием всего 8-ми одно байтовых переменных,
    • без FOR и IF.
    Посчитайте сколько команд процессора у Вас займет обработка дребезга на кольцевых буферах,
    обрабатывая последовательно каждый вход!

    Здесь все входы обрабатываются параллельно:
    Код (C++):
    void Input_CHK(void)
    {
        SWKEYS = Input_Read();
        VCMASK = SWKEYS ^ SLATCH;                
        VCBIT0 &= VCMASK;
        VCBIT1 &= VCMASK;
        SLATCH ^= (VCTEMP = VCMASK & VCBIT0 & VCBIT1);
        if( VCTEMP )                            
      {
         LATCH_ON  |= VCTEMP &  SWKEYS;          
         LATCH_OFF |= VCTEMP & ~SWKEYS;          
      }
        VCBIT1 ^= (VCMASK & VCBIT0);              
        VCBIT0 ^= (VCMASK);
    }
    А если 32 входа. Сколько байт вы отдадите под кольцевые буфера?
    А здесь 8 "unsigned long" и та же функция, правда операций будет чуть больше, так как процессоры в основном 8-ми битные.
     
    Последнее редактирование: 16 мар 2017
  5. Tomasina

    Tomasina Сушитель лампочек Команда форума

    а что за цикл такой странный?
    Код (C++):
    for (i=1,j=0; j < PIN_IN_NUMB; j++,i=i<<1)
     
  6. SergeiL

    SergeiL Гуру

    Цикл по "j" от 0 до 8 (в этом примере),
    при этом вначале j присваиваем 0, а i присваиваем 1
    после выполнения цикла - j увеличиваем на 1, а i сдвигаем на 1 влево.

    тем самым выполняем цикл 8 раз, при этом значение i меняется следующим образом:
    в бинарном виде:
    00000001
    00000010
    00000100
    00001000
    00010000
    00100000
    01000000
    10000000

    В ардуино порты идут не подряд, в разнобой.

    На AVR это не нужно.
    Можно загрузить сразу байт (все восемь бит одного порта), одной командой.
     
  7. SergeiL

    SergeiL Гуру

    Тем кто хочет протестировать работу функции - выкладываю пример, берущий данные не со входов контроллера, а из массива входных значений. Таким образом можно поэкспериментировать с работой функции.

    Тест загружает значения из массива каждые 10мс, обрабатывает, и выводит результаты, в Serial Monitor как представлено выше.
    Когда значения закончились, попадаем в бесконечный цикл, и больше ничего не делаем.

    Код (C++):
    #define PIN_IN_0 3     // для удобства назначим физическим портам ардуино логическое имя, которое занесем потом в массив
    #define PIN_IN_1 1
    #define PIN_IN_2 0     //  Логический вход 2: соответствует Цифровому входу 0 на Arduino
    #define PIN_IN_3 4
    #define PIN_IN_4 5
    #define PIN_IN_5 7
    #define PIN_IN_6 6
    #define PIN_IN_7 2

    #define PIN_IN_NUMB 8 // количество используемых входов значение от 1 до 8.
                          // Если входов больше 8 ходов - меняем размер переменных участвующих в хранении результатов с byte на unsigned int или long

    byte InputPins[PIN_IN_NUMB] = { PIN_IN_0,PIN_IN_1,PIN_IN_2,PIN_IN_3,PIN_IN_4,PIN_IN_5,PIN_IN_6,PIN_IN_7};  // заносим номера пинов в массив, для обработки через for

    #define PIN_READ_TO 10L             // 10 ms  периодичность проверки входов. Оптимальным является интервал 5-10мс. соответственно в результате сигнал о нажатии будет получен через 20-40мс  (в данном случае 40мс)
    unsigned long   LastPinReadMs;      // переменная для сохранения времени, когда были считаны значения с цифорвых входов


    // --------------- ТОЛЬКО ДЛЯ ТЕСТА ФУНКЦИИ УСТР. ДРЕБЕЗГА ------------------------

    byte Test_Buff[] = {0,1,3,0,1,3,3,2,3,1,1,3,0,2,3,4,0,2,0,0,0,0,0};   // буфер с тестовыми значениями
    byte Test_Counter = 0;                                              // счетчик текущего, загружаемого значения

    byte TestBuff_Read(void)
    {
          byte result;
          if (Test_Counter < 23)                                        // пока не закончились значения в тестовом буфере
          {
            result=Test_Buff[Test_Counter];
            Serial.println("");
            Serial.print("Step = ");
            Serial.print(Test_Counter);
            Serial.print("  Test Val = ");
            Serial.print(result,BIN);
            Test_Counter++;
          }
          else
            while(1);               // !!! ЗАЦИКЛИВАЕМСЯ !!! Если тестовый буфер закончился. Для теста больше ничего делать не нужно
         
          return(result);
    }
    //------------------ Чтение цифровых входов --------------------------------------

    byte Input_Read(void)
    {
          byte result = 0;                              // копим побитовое состояние входов
          byte i,j;
          for (i=1,j=0; j < PIN_IN_NUMB; j++,i=i<<1)    // пробежимся по всем входам
          {                                  
                                                        // Если при нажатии кнопки на входе появляется VCC - в if оставляем == HIGH.
              if ( digitalRead(InputPins[j]) == HIGH )  // Если при нажатии кнопки на входе появляется GND - заменить HIGH на LOW
                result |= i;                            // Дальше всегда будем считать, что если бит в 1 - это кнопка нажата или на входе ON.
          }                                             //                                             0 - это кнопка отпущена или на входе OFF.
                                                        // в result "1" взводится в соответствующем бите, если на входе присутствует ON. номер бита сответствует номеру входа
                                                        // например, если на входе 2 - ( в define в самом верху определено, что это цифровой пин 0),
                                                        // (диапазон 0-7 InputPins[2]) присутсвует 1 - в result добавится 1 в 2-ом от нуля бите.  00000100
          return(result);
    }

    //------------------ ФУНКЦИЯ УСТР. ДРЕБЕЗГА --------------------------------------
    // Глобальные переменные

    // биты в байтах ниже взводятся обработчике дребезга, можно в прерывании от таймера и сбрасываются программой обработчиком событий
    byte LATCH_ON   = 0;     // вход перешел в 1
    byte LATCH_OFF  = 0;     // вход вернулся в 0

    void Input_CHK(void)         // вызывается каждые 10 мсек, можно из таймера
    {

      static byte SWKEYS = 0;  // состояние вводов
      static byte SLATCH = 0;  // текущее устоявшееся значение входов после устранения дребезга  
      static byte VCBIT0 = 0;  // Вертикальный счетчик бит 0
      static byte VCBIT1 = 0;  // Вертикальный счетчик бит 1
      static byte VCMASK = 0;  // Маска
      static byte VCTEMP = 0;  //

    //  SWKEYS = Input_Read();         // загрузим значения входов в глобальную переменную SWKEYS
        SWKEYS = TestBuff_Read();        // ТОЛЬКО для ТЕСТА. Убрать. Загрузим значения из тестового буфера в глобальную переменную SWKEYS

        VCMASK = SWKEYS ^ SLATCH;                     // скинем счетчики для установившихся и неактивных значений
        VCBIT0 &= VCMASK;
        VCBIT1 &= VCMASK;
                                                      //  Каждая '1' в SLATCH представляет установившееся значение  
                                                      //  каждый '0' установившееся нулевое значение                
        SLATCH ^= (VCTEMP = VCMASK & VCBIT0 & VCBIT1);

        if( VCTEMP )                                  // есть изменения входов, взведем флаги
      {
         LATCH_ON  |= VCTEMP &  SWKEYS;               // взведем биты нажатых кнопок и сработавших входов.
         LATCH_OFF |= VCTEMP & ~SWKEYS;               // Биты сбрасываются в обработчиках.
      }
     
        VCBIT1 ^= (VCMASK & VCBIT0);                   // инкрементируем счетчик.
        VCBIT0 ^= (VCMASK);

    }

    void setup()
    {
        unsigned long strt_ms;
        byte j;
     
        for (j=0; j < PIN_IN_NUMB; j++)        // переключим нужные порты на ввод
            pinMode(InputPins[j], INPUT);    
         
        Serial.begin(115200);

        strt_ms = millis();
        while (millis()- strt_ms < 5000L ) // 5 sec wait for serial port. Needed for Leonardo only
        {
          if (Serial)
          {
            Serial.println("Serial Connected");
            break;
          }
        }
    }


    void Input_On(byte number)
    {
      Serial.print("  Input ");                // выполним действие по нажатию на кнопку.  номер кнопку в переменной "number"
      Serial.print(number);
      Serial.print(" = ON");
    }

    void Input_Off(byte number)
    {
      Serial.print("  Input ");                // ЕСЛИ НУЖНО! выполним действие по отпусканию кнопки.  номер кнопку в переменной "number"
      Serial.print(number);
      Serial.print(" = OFF");
    }


    void loop()
    {
       byte j,i;
     
       if ((millis() - LastPinReadMs) > PIN_READ_TO)      // выполняется каждые 10мс (PIN_READ_TO)
       {   //-----------------------
          Input_CHK();                                    // читаем значение, игнорируем дребезг
          LastPinReadMs = millis();                       // запомним время
       
          if (LATCH_ON != 0 || LATCH_OFF != 0  )          // Если есть изменения на входах - обработаем.
          {
            Serial.println("");
            for (i=1,j=0; j < PIN_IN_NUMB; j++,i=i<<1)   // пробежимся по всем входам
            {
              if (LATCH_ON & i)                          // Если копка была нажата или вход перешел в ON
              {
                Input_On(j);
                LATCH_ON &= ~i;                          // Обязательно сбросим бит, так как данное событие обработано
              }
         
              if (LATCH_OFF & i)                          // Если копка была отпущена или вход перешел в OFF  ЕСЛИ НУЖНО.
              {
                Input_Off(j);
                LATCH_OFF &= ~i;                        // Обязательно сбросим бит, так как данное событие обработано
              }
            }
         }
       } //  ---------------------


      //   ваш код....
     
    }
     
    Последнее редактирование: 6 фев 2018
  8. ostrov

    ostrov Гуру

    В чем разница то. Битовые операции зачастую проще и изящнее. На примере 8 кнопок. Каждые 40-50 мс опрашивается порт, собирается байт, закидывается в буфер длиной 3. Анализиоуются последовательномть битов на 011 или 0011 для параноиков двумя-тремя логичискими операциями и формируется байт вкл-выкл. Все прозрачно.

    А чем вас if смущает?
     
  9. mcureenab

    mcureenab Гуру

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

    Все это нужно в библиотеку или хотя бы в класс оформить. Иначе после прекрасного устранения дребезга программно на "наш код" мало что остается. И желательно, чтобы в случае перехода на аппаратную обработку дребезга можно было легко убрать ненужные программные фильтры.

    На кой ляд вы своими локальными переменными в глобальное пространство имен гадите? Почитайте про static модификатор.
     
  10. SergeiL

    SergeiL Гуру

    "Глобальное пространство" оно тоже мое. :) в чем проблема то?

    Про статик, я уже лет эдак 30 знаю , но специально не стал грузить начинающих еще и доступностью переменных. Да, согласен,шесть можно перенести, а остальные - нет.
    Я по этому и указатели на функции убрал! Чтобы грузить меньше!

    Общую картину памяти это же не изменит.
    Как было N локальных + M глобальных - так и останется.

    UPD: Поменял на статик
     
    Последнее редактирование: 10 авг 2018
  11. SergeiL

    SergeiL Гуру

    Да практически ни в чем, разница в перпендикулярности! :)
    В моем примере счетчики-то вертикальные, а у Вас горизонтальные. :)

    Я же не претендую на самый лучший вариант. Я предложил тот, который мне показался лучшим.
    Я же не заставляю Вас пользоваться этим вариантом.

    А вы так и не сказали сколько тактов процессора и памяти тратится на Вашу обработку дребезга на кольцевых буферах для 8 входов при глубине анализа на четыре значения.

    Предложите Ваш пример, Может он лучше! Все возьмем на вооружение!
    Ну хоть свою функцию, обрабатывающую дребезг на 8-и входах покажите. :)
     
  12. ostrov

    ostrov Гуру

    На самом деле МК так загружен, что каждый такт на счету???
     
  13. SergeiL

    SergeiL Гуру

    В тестовом примере, МК, совсем не загружен.

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

    Поэтому и говорил - Предложите Ваш пример, Может он лучше! Все возьмем его на вооружение!

    НО. В последней задаче для ESP, мене было важно, чтобы обработка входов и выдача сигнала управления на выходы выполнялась в real time, независимо от процессов в loop() типа выбора WiFi или подключения к WiFi.

    Поэтому обработка входов, анализ данных, и формирование сигнала на выход, были перенесены в Ticker.
    А чем короче код в таймере - тем лучше.
     
  14. ostrov

    ostrov Гуру

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

    SergeiL Гуру

    Изменение на входе означает нажатие клавиши или изменение состояния датчика на входе. В других ситуациях изменений и прерываний не возникнет. А в случае нажатия клавиши или изменения входа все равно придется проснуться, нужно же это обработать. Поэтому на 20мс раньше с программным вариантом или на 20мс позже, с аппаратной защитой от дребезга, это не так важно.
    За то конструкция упрощается, а на батареи, как мне кажется, это не сильно скажется.
     
    Последнее редактирование: 16 мар 2017
  16. SergeiL

    SergeiL Гуру

    И...

    Где код? :)

    Код-то будем сравнивать? :)

    Ну чтобы не просто так, в воздух :)
     
    Последнее редактирование: 16 мар 2017
  17. ostrov

    ostrov Гуру

    Ну сейчас я работу брошу и кинусь код писать. Я вам принцип рассказал, по этому алгоритму у меня клавиатуры работают, энкодеры и прочие щелевые оптроны. Опрос длится какие то труднофиксируемые микросекунды, потому что энкодеры орашиваются, к примеру, раз в 1 мс или чаще, и это по прерыванию, то есть не мешая основной задаче. Чтобы сравнивать точно, надо переписать именно под те же условия что и у вас, а это время хотя бы на то чтобы вникнуть в задачу. Возможно вечером уделю время.