999 вопросов по программированию

Тема в разделе "Флудилка", создана пользователем CYITEP_BAC9I, 9 авг 2018.

  1. CYITEP_BAC9I

    CYITEP_BAC9I Гик

    Ночер всем добрый. осваиваю потихоньку PlatformIO. заодно изобретаю велосипед по опросу кнопок. гуру гляньте пожалуйста. может ли иметь такой способ опроса кнопок, место под солнцем?
    (написал все в PlatformIO, пишется намного быстрее чем в Ардуино ИДЕ, но компилирую в "родном" ардуиновском он меньше претензий предъявляет )
    код по опросу кнопок
    Код (C++):
    #include <Arduino.h>
    uint32_t time_butt = 0;
    bool up_butt=0;   //флаг факта нажатия кнопки вверх
    bool down_butt=0; // флаг нажатия кнопки вниз
    bool OK_butt=0;   // флаг нажатия кнопки подтверждения
    bool cancel_butt=0; // флаг нажатия кнопки отмена
    //сброс флагов после выполнения действий

    void setup() {
    DDRC &= ~((1<<0)|(1<<1)|(1<<2)|(1<<3)); //A0 A1 A2 A3 вход
    }

    void loop() {
      uint32_t time = millis();
      //считываем порт с
      if( (PINC & (1<<0))|| (PINC & (1<<1))||(PINC & (1<<2))||(PINC & (1<<3))&&time-time_butt>=30  )//если нажатие хоть на одну кнопку
    {
        byte A =PINC; // передаем значение в переменную А
        //сравниваем что было нажато и по результату взводим флаги
    switch (A)
    {

    case 0b00000001:
    up_butt=1;
    break;
    case 0b00000010:
    down_butt=1;
    break;
    case 0b00000100:
    OK_butt=1;
    break;
    case 0b00001000:
    cancel_butt=1;
    break;
    default:

    }
    time_butt=time;
    }
    //проверка на отжатие кнопки в принципе это и не к чему
    if( (~PINC & (1<<0))&& (~PINC & (1<<1))&&(~PINC & (1<<2))&&(~PINC & (1<<3))&&time-time_butt>=30  )
    time_butt=time;

    }
     
    Последнее редактирование: 9 авг 2018
  2. SergeiL

    SergeiL Оракул Модератор

    А что нужно то? :)

    С первого взгляда, нет сброса переменных нажатия кнопки.
    Нажали кнопку - переменная перешла в 1, и осталась в 1 до выключения контроллера.
    Обработка дребезга - очень упрощена.

    Я уже писал про оптимальный, с моей точки зрения, алгоритм опроса кнопок, могу выложить еще раз, в Вашем варианте, но многие здесь его "не приветствуют" :). Сложный говорят, :) можно "проще" через буфера.

    По памяти и быстродействию, думаю точно будет короче и быстрее ;).
     
    Сусемьбек нравится это.
  3. Спасибо за комментарии. Хотел чтоб глянули, дичь это или нет)
    Значит можно) флаги будут сбрасываться после выполнения действия в другой части кода. На симуляторе вроде работает
     
  4. SergeiL

    SergeiL Оракул Модератор

    После default: точки с запятой не хватает.
    Нужно обрабатывать отпускание кнопки?
     
    Сусемьбек нравится это.
  5. Дефаулт это я уже здесь дописал, пришла мысль , что могут и 2 кнопки разом нажаты. Нужно все предусмотреть. Отжатие не нужно отслеживать. Долгих и двойных нажатий не планируется, так как возможно игрушкой будут пользоваться не программисты и делал чтоб было интуитивно понятным управление.
     
  6. SergeiL

    SergeiL Оракул Модератор

    Понятно.

    Ваш код (без сброса флагов нажатий кнопок, и анализа одновременных нажатий):
    Скетч использует 670 байт (2%) памяти устройства. Всего доступно 30720 байт.
    Глобальные переменные используют 17 байт (0%) динамической памяти, оставляя 2031 байт для локальных переменных. Максимум: 2048 байт.

    Код с полноценной обработкой дребезга, независимо и параллельно, на четырех входах, сбросом флагов, и анализом одновременных нажатий (анализ отпускания кнопок закомментировал ):
    Код (C++):
    #define PIN_READ_TO 10L   // 10 ms  периодичность проверки входов. Оптимальным является интервал 5-10мс. соответственно в результате сигнал о нажатии будет получен через 20-40мс  (в данном случае 40мс)
    #define PIN_IN_NUMB 4     // количество используемых входов значение от 1 до 8.


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

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

    uint8_t vc_debounce(uint8_t SWKEYS)        // Verical_Couners_debounce, вызывается каждые 10 мсек, можно из таймера
    {                                          // в SWKEYS состояние вводов
        static uint8_t SLATCH = 0;             // текущее устоявшееся значение входов после устранения дребезга
        static uint8_t VCBIT0 = 0;             // счетчик бит 0
        static uint8_t VCBIT1 = 0;             // счетчик бит 1
        uint8_t        vcmask = 0;             // Маска
        uint8_t        vctemp = 0;             //
        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()
    {
        DDRC &= ~((1<<0)|(1<<1)|(1<<2)|(1<<3)); //A0 A1 A2 A3 вход
    }


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

    */

    void loop()
    {
       static uint32_t    LastPinReadMs = 0 ;      // переменная для сохранения времени, когда были считаны значения с цифорвых входов
       uint8_t            current_state;           // переменная для текущего состояние по кнопкам

       byte j,i;

       if ((millis() - LastPinReadMs) > PIN_READ_TO)          // выполняется каждые 10мс (PIN_READ_TO)
       {   //-----------------------
          current_state= PINC & ((1<<0)|(1<<1)|(1<<2)|(1<<3));  // читаем значение
          vc_debounce(current_state);                         //  2) отбросим дребезг по всем входам, на основании предыдущих проверок (игнорируем состояния, держащиеся на входе менее 4 проверок подряд)
          LastPinReadMs = millis();                           // запомним время
     
    //      if (LATCH_ON != 0 || LATCH_OFF != 0  )          // Если есть изменения на входах - обработаем.
          if (LATCH_ON != 0   )          // Если есть изменения на входах - обработаем.
          {
            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;                         // Обязательно сбросим бит, так как данное событие обработано
              }
    */
         
            }
         }
       } //  ---------------------


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

    }
    Скетч использует 644 байт (2%) памяти устройства. Всего доступно 30720 байт.
    Глобальные переменные используют 17 байт (0%) динамической памяти, оставляя 2031 байт для локальных переменных. Максимум: 2048 байт.

    Код короче, по памяти столько же.
     
    Сусемьбек нравится это.
  7. Спасибо большое
     
  8. parovoZZ

    parovoZZ Гуру

    А если одновременно две нажаты или требуется такое действие?
     
  9. SergeiL

    SergeiL Оракул Модератор

    Одновременно, "в реальном времени" :), не бывает ;).
     
  10. parovoZZ

    parovoZZ Гуру

    Дарю макрос, по которому можно определить состояние одного бита в регистре
    Код (C++):
    #define BitIsClear(reg, bit)    ((reg & (1<<(bit))) == 0)
    //пример: if (BitIsClear(PORTB,1)) {...} //если бит очищен
    И не надо ничего никуда копировать. Устранить дребезг - вызывать функцию по таймеру. Ну раз 50 в секунду хватит. И отзывчивость сохранишь, и от дребезга избавишься. Плюсом, если внутри завести счетчик (в структуре кнопки, например), то можешь отслеживать длинные и короткие нажатия.
     
    Сусемьбек нравится это.
  11. SergeiL

    SergeiL Оракул Модератор

    Макрос - не новость, толку -то от него????
    Хотите все входы последовательно опрашивать, последовательно, для каждого входа, анализировать состояние - пожалуйста, флаги Вам в руки ;)

    И Супермен расстроил! :)

    Одним словом, Кто как хочет, тот так и "делает" :)

    Мне так удобнее, уже говорил об этом!
    Многие не понимают прелести, данного варианта, ну что же тут сделаешь, может когда-нибудь поймут ;)
     
  12. parovoZZ

    parovoZZ Гуру

    так а можешь алгоритм нарисовать, а то у меня глаза в разные стороны смотрят и все коды двоятся))) Может и возьму на вооружение. Особенно, когда 10 или больше кнопок)))
     
  13. SergeiL

    SergeiL Оракул Модератор

    Уже описал все здесь . Больше года назад. В ответ была только критика ;), не поняли ;)!
    Когда разобрался, лет 15 назад, честно говоря прибалдел от оптимальности, скорости и компактности.
    Знакомые, после объяснения, только этим вариантом и пользуются.
     
  14. parovoZZ

    parovoZZ Гуру

    так ведь тоже последовательно опрашиваем вот здесь
     
  15. SergeiL

    SergeiL Оракул Модератор

    Это пример, это уже после устранения дребезга по всем входам.
    Обрабатываем установившееся значение. Его все равно нужно обрабатывать.

    А устранение дребезга - это 10 строчек для 8 или 16 входов одновременно.
    (в зависимости от разрядности регистров)

    Без for, и while.

    Я устраняю дребезг в прерывании от таймера, а флаги анализирую в main или loop ;)
     
  16. parovoZZ

    parovoZZ Гуру

    При опросе кнопок не чаще 50 раз в секунду дребезг самоустраниться без лишних телодвижений.
     
  17. parovoZZ

    parovoZZ Гуру

    Это в дизасме 10 машиноинструкций? А то ведь в абдурино 1 строчка кода выливается в 100 машинных инструкций(((
     
  18. parovoZZ

    parovoZZ Гуру

    При очередном опросе - запросто.
     
  19. SergeiL

    SergeiL Оракул Модератор

    Ну не знаю, мне так проще
    Какие 100 инструкций, там булевые операции...
    И Супермен расстроил окончательно!!! :)
    Все, надоело, :mad: "делайте" как хотите, мне все равно.:mad:
     
  20. parovoZZ

    parovoZZ Гуру

    Не обижайся, чо)))
    Я просто хочу понять - вот в прерывании таймера мы опросили порт. Потом идёт функция проверки на дребезг. А зачем? Если между двумя прерываниями таймера выясняется, что кнопка ещё дребезжит, значит период опроса кнопок надо увеличить. И не нужны никакие функции проверки на дребезг - таймер все за нас сделал.