Есть 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;
Все было намного проще... Проблема была в массиве configCommand, а не в функциях, как казалось на первый взгляд.
Пока исправлял ошибки, заметил, что прерывания введут себя странно. При нажатии кнопки энкодера работает так как задумано, а именно: Сдвигаю историю кнопки энкодера на 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);
бред. Таких прерываний нет. любой механический (и даже оптический) контакт порождает дребезг при коммутациях. С ними необходимо бороться либо программно, либо аппаратно.
Благодарствую. С новой информацией и силами продолжил гуглить и узнал, что на энкодере ec11 установлена схема от дребезга контактов(аппаратная), но она не спасает. Питаю энкодер от 3.3V, но это никак не должно сказываться на его работе. Может не хватает ёмкости конденсаторов на энкодере? Мне кажется, что дело явно не в энкодере, а в инициализации входных GPIO, попробую уйти в это направление. Самое интересное, что кнопка работает как положено без всякого дребезга, по схеме ec11 видно, что на линии не установлен конденсатор... Данный энкодер прекрасно работает на микрухе ATmega2560 в среде разработки Arduino.
Вообщем стало интересно, что там по пассивному напряжению на входных 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
Походу - нет, проверил напряжение на пинах 12, 25, 32. Работают так как и требуется, но это никак не решает мою проблему. Видимо контакты которые способны только измерять сигнал(36, 39, 34, 35), не могут устанавливать подтягивающие резисторы.
Сделал программный антидребезг - работает отлично! Получается, что вся проблема в аппаратном антидребезге. Код (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(); }