Использование сторонних функций в функции прерывания

Тема в разделе "ESP8266, ESP32", создана пользователем WhiteFox, 24 ноя 2021.

  1. WhiteFox

    WhiteFox Нерд

    Есть 3 функции прерывания interruptKey, interruptS1, interruptS2. В каждой функции есть объединяющая функция findCommand.
    Проблема: Из функций interruptKey, interruptS1, interruptS2 нельзя призвать findCommand.

    Код (C++):
    #define historyBit 16

    void IRAM_ATTR findCommand(Encoder_t *encoder)
    {
      for (uint8_t indexConfigCommand = 0; indexConfigCommand != encoder->lengthConfigCommand; indexConfigCommand++)
      {
        uint8_t shiftBit = historyBit - encoder->configCommand[indexConfigCommand]->lengthCommand;
        uint8_t index;
        for (index = 0; index != 3; index++)
        {
          if ((encoder->history[index] << shiftBit) != (encoder->configCommand[indexConfigCommand]->command[index] << shiftBit))
            break;
        }
        if(index == 3){
        encoder->command = indexConfigCommand + 1;
        break;
        }
      }
    }
    void IRAM_ATTR interruptKey(void* args)
    {
      Encoder_t *encoder = (Encoder_t*)args;
      encoder->history[0] = ~(encoder->history[0] & 1) | (encoder->history[0] << 1);
      encoder->history[1] = (encoder->history[1] & 1) | (encoder->history[1] << 1);
      encoder->history[2] = (encoder->history[2] & 1) | (encoder->history[2] << 1);
      findCommand(encoder);
    }
    void IRAM_ATTR interruptS1(void* args)
    {
      Encoder_t *encoder = (Encoder_t*)args;
      encoder->history[0] = (encoder->history[0] & 1) | (encoder->history[0] << 1);
      encoder->history[1] = ~(encoder->history[1] & 1) | (encoder->history[1] << 1);
      encoder->history[2] = (encoder->history[2] & 1) | (encoder->history[2] << 1);
      findCommand(encoder);
    }
    void IRAM_ATTR interruptS2(void* args)
    {
      Encoder_t *encoder = (Encoder_t*)args;
      encoder->history[0] = (encoder->history[0] & 1) | (encoder->history[0] << 1);
      encoder->history[1] = (encoder->history[1] & 1) | (encoder->history[1] << 1);
      encoder->history[2] = ~(encoder->history[2] & 1) | (encoder->history[2] << 1);
      findCommand(encoder);
    }

    void setupEncoder(Encoder_t *encoder, gpio_num_t pinKey, gpio_num_t pinS1, gpio_num_t pinS2)
    {
      encoder->command = 0;
      gpio_config_t io_conf = {
          .intr_type = GPIO_INTR_ANYEDGE,
          .pin_bit_mask = (1ULL << pinKey) | (1ULL << pinS1) | (1ULL << pinS2),
          .mode = GPIO_MODE_INPUT,
          .pull_down_en = 0,
          .pull_up_en = 1};
      gpio_config(&io_conf);
      encoder->history[0] = gpio_get_level(pinKey);
      encoder->history[1] = gpio_get_level(pinS1);
      encoder->history[2] = gpio_get_level(pinS2);
      gpio_install_isr_service(0);
      gpio_isr_handler_add(pinKey, interruptKey, encoder);
      gpio_isr_handler_add(pinS1, interruptS1, encoder);
      gpio_isr_handler_add(pinS2, interruptS2, encoder);
    }

    uint8_t getCommandEncoder(Encoder_t *encoder)
    {
      uint8_t output = encoder->command;
      encoder->command = 0;
      return output;
    }
    Код (C++):
    typedef struct
    {
        uint16_t command[3];
        uint8_t lengthCommand;
    } ConfigCommand_t;

    typedef struct
    {
        uint8_t command;
        uint16_t history[3];
        ConfigCommand_t **configCommand;
        uint8_t lengthConfigCommand;
    } Encoder_t;
     
  2. Asper Daffy

    Asper Daffy Иксперд

    Почему нельзя? Мама запретила?
     
  3. WhiteFox

    WhiteFox Нерд

    Все было намного проще...
    Проблема была в массиве configCommand, а не в функциях, как казалось на первый взгляд.
     
  4. WhiteFox

    WhiteFox Нерд

    Пока исправлял ошибки, заметил, что прерывания введут себя странно.
    При нажатии кнопки энкодера работает так как задумано, а именно:
    Сдвигаю историю кнопки энкодера на 1 бит влево и приписываю в правую часть значение входного GPIO.
    История энкодера это 3 переменные типа unsigned short, каждая переменная отвечает за историю определенного входного контакта GPIO.
    Код (C++):
    encoder->history[0] = (encoder->history[0] << 1) | gpio_get_level(encoder->pinKey);
    Пример:
    Жму 4 раза на кнопку, тогда история будет выглядеть так: 0000000101010101, где 0-кнопка нажата, а 1-отпущена.

    А при поворотах энкодера в историю записывается полная случайность, но в основном 1111111111111111, при этом за 4 такта энкодера прерывание вызывается большое кол-во раз.
    Предполагаю, что прерывания работают в аналоговом режиме, то есть срабатывают на малейшее изменение в напряжении.
    Если я прав, то как настроить прерывание в цифровой режим?

    Инициализировал входы GPIO так:
    Код (C++):
    .pinKey = GPIO_NUM_36,
     .pinS1 = GPIO_NUM_39,
     .pinS2 = GPIO_NUM_34
    Код (C++):
     gpio_pad_select_gpio(encoder->pinKey);
     gpio_pad_select_gpio(encoder->pinS1);
     gpio_pad_select_gpio(encoder->pinS2);
     gpio_config_t io_conf = {
     .intr_type = GPIO_INTR_ANYEDGE,
     .pin_bit_mask = (1ULL << encoder->pinKey) | (1ULL << encoder->pinS1) | (1ULL << encoder->pinS2),
     .mode = GPIO_MODE_INPUT,
     .pull_down_en = 0,
     .pull_up_en = 0};
     gpio_config(&io_conf);
     
  5. parovoZZ

    parovoZZ Гуру

    бред. Таких прерываний нет.

    любой механический (и даже оптический) контакт порождает дребезг при коммутациях. С ними необходимо бороться либо программно, либо аппаратно.
     
    Рокки1945 и Andrey12 нравится это.
  6. WhiteFox

    WhiteFox Нерд

    Благодарствую.
    С новой информацией и силами продолжил гуглить и узнал, что на энкодере ec11 установлена схема от дребезга контактов(аппаратная), но она не спасает. Питаю энкодер от 3.3V, но это никак не должно сказываться на его работе. Может не хватает ёмкости конденсаторов на энкодере?
    Мне кажется, что дело явно не в энкодере, а в инициализации входных GPIO, попробую уйти в это направление.
    Самое интересное, что кнопка работает как положено без всякого дребезга, по схеме ec11 видно, что на линии не установлен конденсатор...
    Данный энкодер прекрасно работает на микрухе ATmega2560 в среде разработки Arduino.
     
    Последнее редактирование: 25 ноя 2021
  7. b707

    b707 Гуру

    а у вас какой МК и какая среда?
     
  8. WhiteFox

    WhiteFox Нерд

    Среда разработки - ESP IDF
    Микруха - ESP32 38pins
     
  9. WhiteFox

    WhiteFox Нерд

    Вообщем стало интересно, что там по пассивному напряжению на входных GPIO.
    Снял энкодер с платы и замерил напряжение на всех 3 контактах в режимах pull up, pull down и без.
    Во всех случаях напряжение равнялось 1.4V, думаю так не должно быть...
    Посмотрел парочку чужих кодов, а инициализация такая же как у меня, неужели микруха поломана?

    Немножко логов:
    I (589) gpio: GPIO[34]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 1| Intr:3
    I (599) gpio: GPIO[36]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 1| Intr:3
    I (609) gpio: GPIO[39]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 1| Intr:3
     
    Последнее редактирование: 26 ноя 2021
  10. WhiteFox

    WhiteFox Нерд

    Походу - нет, проверил напряжение на пинах 12, 25, 32.
    Работают так как и требуется, но это никак не решает мою проблему.
    Видимо контакты которые способны только измерять сигнал(36, 39, 34, 35), не могут устанавливать подтягивающие резисторы.
     
    Последнее редактирование: 25 ноя 2021
  11. WhiteFox

    WhiteFox Нерд

    Сделал программный антидребезг - работает отлично!
    Получается, что вся проблема в аппаратном антидребезге.

    Код (C++):
    void IRAM_ATTR interrupt(void* args)
    {
      Encoder_t *encoder = (Encoder_t*)args;
      if((encoder->interruptTime + 5000) < esp_timer_get_time()){
      encoder->history[0] = (encoder->history[0] << 1) | gpio_get_level(encoder->pinKey);
      encoder->history[1] = (encoder->history[1] << 1) | gpio_get_level(encoder->pinS1);
      encoder->history[2] = (encoder->history[2] << 1) | gpio_get_level(encoder->pinS2);

      // for (uint8_t indexConfigCommand = 0; indexConfigCommand != encoder->lengthConfigCommand; indexConfigCommand++)
      // {
      //   uint8_t shiftBit = historyBit - encoder->configCommand[indexConfigCommand].lengthCommand;
      //   uint8_t index;
      //   for (index = 0; index != 3; index++)
      //   {
      //     if ((encoder->history[index] << shiftBit) != (encoder->configCommand[indexConfigCommand].command[index] << shiftBit))
      //       break;
      //   }
      //   if(index == 3){
      //   encoder->command = indexConfigCommand + 1;
      //   break;
      //   }
      // }
      }
      encoder->interruptTime = esp_timer_get_time();
    }