Вращение ручки энкодера дублирует нажатие его кнопки

С предыдущим вопросом справился (не хватало мощности порта): внешний ИП решил проблему. И вот новая непонятка: вращение ручки энкодера дублирует нажатие его кнопки. Распайку проверил - нигде КЗ или непропая нет. Где рыться?
Заранее спасибо!
PS: На моей Меге прерывания как указано на нашем сайте, а не на распространённых картинках.

//Mega2560
/*Пины прерываний
 пин2 (прерывание 0) 
 пин3 (прерывание 1)
 пин18 (прерывание 5)
 пин19 (прерывание 4)
 пин20 (прерывание 3)
 пин21 (прерывание 2)*/


int temp_col=678; // Температура датчика
volatile int temp_adj; // Температура настройки
volatile int but_adj=1;  // Значение кнопки настройки


void setup() 
{               
  Serial.begin(115200);// Объявляем скорость порта
  //Назначение пинов чтения энкодера и кнопок на вход
  for (int ind=16;ind<22;ind++)
  {
    pinMode(ind, INPUT);  //Пины на вход
  }
  //Назначение прерываний
  attachInterrupt(4, BUTTON_ADJ, RISING);   //Пин прерывания кнопки настройки
  attachInterrupt(5, ENCODER_ADJ, RISING);  //Пин прерывания энкодера настройки
}


void loop() 
{
  //Переключение температуры настройки на 99,9°С и обратно
  if (but_adj==0) {temp_adj=temp_col;}
  else {temp_adj=999;}
  Serial.println (but_adj);
}

void ENCODER_ADJ()  //Читаем энкодер настройки
{ 

}
void BUTTON_ADJ()  //Читаем кнопку настройки
{
  if (but_adj==0) {but_adj=1;}
  else {but_adj=0;}
}

Без схемы не понятно что и куда подключено…

Работа пока с нижнем на рисунке энкодером.

Слона надо есть по частям.
Может, начать с того, что удалить из схемы все лишнее? Оставить только один энкодер и Мегу.
А так, начать с того, что снять логическим анализатором при вращении энкодера сигналы с ног триггера Шмитта.

Так и сделано уже: верхний энкодер на рисунке присутствует, но на самом деле отключен (перерисовывать было лень). Беда в том, что нетути логического анализатора :(. Можно было бы и двухлучевой осцилл применить, но его тоже нема :(… Посредством тестера (в режиме вольтметра) на ногах триггера, вроде, все нормально. То есть, при вращении ручки 0 меняется на 4,97в на входе элементов, и наоборот на выходе. То есть, норма. Уже замучился искать причину, потому и пишу тут слёзные сентенции. Если будут какие мысли, опубликуйте, только по ним буду следовать уже после выходных. Заранее спасибо!

Нажатие на кнопку без вращения, отрабатывается правильно? Как одно нажатие на кнопку?

Да, кнопка как одно нажатие. А крутилка дурит. Но, нашел, кажись, трабл. Покупал модули энкодеров на Озоне. Все три бракованные. Копейки стоят, конечно, рекламацией заниматься не буду, но обидно (успел впаять в плату). Проверено подключением другого энкодера (нашел в закромах). Заработало.
Всем спасибо за помощь!

В отзывах соответствующую запись сделать нужно

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

Закрома наше всё:)
Всегда пркупал по две штуки каждого, последние пару лет по две от двух разных продаванов.
А вообще энкодер наверно можно было проверить на (теплом ламповом) осциллогрофе с остановленной разверткой.
Искать иголки.

Ну вот, устройство собрано. Все, наконец, заработало. Сбоев нет. Всем спасибо за помощь и советы! Но вот какие «смутные сомнения».

  1. Во многих постах сообщалось, что на входе пинов Ардуино УЖЕ стоят триггеры, поэтому для убивания дребезга достаточно закоротить кнопку (или выводы энкодера) RC-цепочкой. В моем случае это оказалось не так. RC-цепочки ни «от балды» ни рассчитанная не спасали. Стоило же только между Мегой и кнопкой поставить триггер (SN74HC14N), как эффект дребезга исчез. RC-цепочку на кнопке, естественно, оставил. Так что, все-таки, нету триггеров в Ардуине?
  2. После загрузки скетча с ПК устройство сразу начинает выполнять программу. Если же отключить его от ПК и запитать от внешнего источника, то сначала на одном из трех индикаторов max7219 (в скетче он обозначен как “lc_val”) кратковременно зажигаются все восьмерки с точками. Потом индикатор гаснет, и устройство приступает к выполнению программы. Это не сильно парит, но неприятно. Проблема в скетче или чисто аппаратная (типа где-то дребезг или что-то иное)? Есть ли какой-то способ избежать (или победить) это нештатное вспыхивание индикатора?
    На всякий случай привожу сам скетч.
//Mega2560
/*Пины прерываний
  пин2 (прерывание 0)
  пин3 (прерывание 1)
  пин18 (прерывание 5)
  пин19 (прерывание 4)
  пин20 (прерывание 3)
  пин21 (прерывание 2)*/

//Пины термодатчика колонны
int pin_col = 47; //Пин термодатчика колонны 47
int pin_col_vcc = 49; //Пин 5v термодатчика колонны 49
int pin_col_gnd = 45; //Пин gnd термодатчика колонны 45

//Пин клапана
int pin_val = 12; //Пин клапана

//Переменные
//Температура колонны
volatile int temp_col; // Температура ректификационной колонны
unsigned long ds18b20_time; //Переменная периода опроса термодатчиков
//Температура отсечки
volatile int temp_adj; // Температура отсечки хвостов
volatile int but_adj = 0; // Значение кнопки отсечки
//Работа клапана
volatile long val_interval = 1000; //  Время закрытого клапана, умноженное на 1000 (открытый всегда на 1000 мсек)
volatile long val_change = 1; // Данные энкодера клапана
volatile int but_val;  // Значение кнопки клапана
volatile int flag_val = 0; // Включать или нет клапан
int val_state = LOW;      // Состояние клапана
long previousMillis = 0;  // храним время последнего переключения кларана
int flag_val_temp = 0; // Состояние отсечки хвостов

int sot;  //Для интикаторов сотни
int des;  //Для интикаторов десятки
int edi;  //Для интикаторов единицы
volatile int clk;  //Состояние пина прерывания энкодера
volatile int dt;  //Состояние второго пина энкодера
volatile int sw;  //Состояние пина пина прерывания кнопки

//Подключение библиотеки  термодатчика колонны
#include <OneWire.h>
OneWire ds_col(pin_col);  // Датчик T° колонны на пине 47
//Подвязывание рабочих переменных к библиотеке датчика
byte i;
byte present = 0;
byte data[12];
byte addr_col[8];

//Подключение библиотеки max7219
#include <LedControl.h>
//создаём объект класса LedControl (din,clk,cs,X) X - количество модулей
//Провода: clk-зеленый, cs-желтый, din-оранжевый
LedControl lc_col = LedControl(30, 34, 32, 1);
LedControl lc_adj = LedControl(38, 42, 40, 1);
LedControl lc_val = LedControl(46, 50, 48, 1);
// Массив с закодированными символами для надписей.
byte bukvy[12] =
{
  B01001110,    //C-0
  B00011101,    //o-1
  B00001100,    //l-2
  B01110111,    //A-3
  B00111101,    //d-4
  B00011000,    //j-5
  B01100011,    //°-6
  B01111110,    //O-7
  B01000111,    //F-8
  B00010101,    //n-9
  B00000000,    //пусто-10
  B00000001,    //тире-11
};



void setup()
{
  Serial.begin(115200);// Объявляем скорость порта
  //Инициализация пина клапана
  pinMode(pin_val, OUTPUT);   //Пин клапана на выход

  //Инициализация пинов датчика колонны
  pinMode(pin_col, INPUT);   //Пин термодатчика колонны на вход
  pinMode(pin_col_vcc, OUTPUT);   //Пин 5v термодатчика колонны на выход
  digitalWrite (pin_col_vcc, HIGH);
  pinMode(pin_col_gnd, OUTPUT);   //Пин gnd термодатчика колонны на выход
  digitalWrite (pin_col_gnd, LOW);

  //Запрос термодатчику колонны на измерение температуры
  if ( !ds_col.search(addr_col)) {}
  //Инициируем датчик температуры колонны
  ds_col.reset();
  ds_col.select(addr_col);
  ds_col.write(0x44);

  //Назначение пинов индикаторов на выход
  for (int ind = 30; ind <= 50; ind++)
  {
    pinMode(ind, OUTPUT);
  }

  //Инициализация модулей индикаторов
  lc_col.shutdown(0, false); //Выводим из спящего режима
  lc_col.setIntensity(0, 7); //Яркость дисплея на 7. Всего возможных режимов яркости от 0 до 15
  lc_col.clearDisplay(0);    //Очистить дисплей
  lc_adj.shutdown(0, false); //Выводим из спящего режима
  lc_adj.setIntensity(0, 7); //Яркость дисплея на 7. Всего возможных режимов яркости от 0 до 15
  lc_adj.clearDisplay(0);    //Очистить дисплей
  lc_val.shutdown(0, false); //Выводим из спящего режима
  lc_val.setIntensity(0, 7); //Яркость дисплея на 7. Всего возможных режимов яркости от 0 до 15
  lc_val.clearDisplay(0);    //Очистить дисплей
  //Тест №1
    //Пишем цифры от 0 до 7
    for (int dig = 7; dig >-1; dig--)
    {
      lc_col.setDigit(0, dig, 7-dig, false);
      delay (150);
    }
    delay (150);
    for (int dig = 7; dig >-1; dig--)
    {
      lc_adj.setDigit(0, dig, 7-dig, false);
      delay (150);
    }
    delay (150);
    for (int dig = 7; dig >-1; dig--)
    {
      lc_val.setDigit(0, dig, 7-dig, false);
      delay (150);
    }
    delay (150);
    //Очищаем индикаторы
    lc_col.clearDisplay(0);    //Очистить дисплей
    lc_adj.clearDisplay(0);    //Очистить дисплей
    lc_val.clearDisplay(0);    //Очистить дисплей

    //Проверяем восьмерки
    for (int dig = 7; dig >-1; dig--) //Восьмерки в левом индикаторе
    {
      lc_col.setDigit(0, dig, 8, true);
      delay (75);
      lc_col.clearDisplay(0);    //Очистить дисплей
    }  
     for (int dig = 7; dig >-1; dig--) //Восьмерки в среднем индикаторе
    {
      lc_adj.setDigit(0, dig, 8, true);
      delay (75);
      lc_adj.clearDisplay(0);    //Очистить дисплей
    }  
    for (int dig = 7; dig >-1; dig--) //Восьмерки в правом индикаторе
    {
      lc_val.setDigit(0, dig, 8, true);
      delay (75);
      lc_val.clearDisplay(0);    //Очистить дисплей
    }  
    delay (200);
  
  //Пишем "Col"
  lc_col.setRow(0, 7, bukvy[0]);//Индикация C"
  lc_col.setRow(0, 6, bukvy[1]);//Индикация "o"
  lc_col.setRow(0, 5, bukvy[2]);//Индикация "l"
  lc_col.setRow(0, 0, bukvy[6]);//Индикация "°"
  //Пишем "Adj"
  lc_adj.setRow(0, 7, bukvy[3]);//Индикация "A"
  lc_adj.setRow(0, 6, bukvy[4]);//Индикация "d"
  lc_adj.setRow(0, 5, bukvy[5]);//Индикация "j"
  lc_adj.setRow(0, 0, bukvy[6]);//Индикация "°"
  //Пишем "OFF"
  lc_val.setRow(0, 7, bukvy[7]);//Индикация "O"
  lc_val.setRow(0, 6, bukvy[8]);//Индикация "F"
  lc_val.setRow(0, 5, bukvy[8]);//Индикация "F"
  lc_val.setDigit(0, 3, 1, false); //Индикация "1"
  lc_val.setRow(0, 2, bukvy[11]);//Индикация "-"

  //Назначение пинов чтения энкодера и кнопок на вход
  for (int ind = 16; ind < 22; ind++)
  {
    pinMode(ind, INPUT);  //пины на вход
  }

  //Назначение прерываний
  attachInterrupt(5, BUTTON_ADJ, FALLING);   //пин прерывания кнопки отсечки хвостов
  attachInterrupt(4, ENCODER_ADJ, FALLING);  //пин прерывания энкодера отсечки хвостов
  attachInterrupt(3, BUTTON_VAL, FALLING);   //пин прерывания кнопки клапана
  attachInterrupt(2, ENCODER_VAL, FALLING);  //пин прерывания энкодера клапана




  Serial.begin(115200);// Объявляем скорость порта
}

void loop()
{
  //Опрос показаний датчика температуры колонны 1 раз в 850 мсек
  if (millis() - ds18b20_time > 850)
    //Опрашиваем датчик колонны
    present = ds_col.reset();
  ds_col.select(addr_col);
  ds_col.write(0xBE);
  for ( i = 0; i < 9; i++)
  {
    data[i] = ds_col.read();
  }
  int16_t raw = (data[1] << 8) | data[0];
  temp_col = raw / 1.6;
  //Очередной запрос термодатчику колонны на измерение температуры
  if ( !ds_col.search(addr_col)) {}
  //Инициируем датчик температуры колонны
  ds_col.reset();
  ds_col.select(addr_col);
  ds_col.write(0x44);

  //Раскладка данных температуры колонны и индикация
  sot = temp_col / 100;
  des = temp_col % 100 / 10;
  edi = temp_col % 10;
  lc_col.setDigit(0, 3, sot, false);
  lc_col.setDigit(0, 2, des, true);
  lc_col.setDigit(0, 1, edi, false);

  //Раскладка данных температуры отсечки и индикация
  if (temp_adj > 999) {
    temp_adj = 999; //Предел 999
  }
  if (temp_adj < 0) {
    temp_adj = 0; //Предел 0
  }
  sot = temp_adj / 100;
  des = temp_adj % 100 / 10;
  edi = temp_adj % 10;
  lc_adj.setDigit(0, 3, sot, false);
  lc_adj.setDigit(0, 2, des, true);
  lc_adj.setDigit(0, 1, edi, false);

  //Раскладка данных клапана
  if (flag_val == 0)
  {
    lc_val.setRow(0, 7, bukvy[7]);//Индикация "O"
    lc_val.setRow(0, 6, bukvy[8]);//Индикация "F"
    lc_val.setRow(0, 5, bukvy[8]);//Индикация "F"
  }
  if (flag_val == 1)
  {
    lc_val.setRow(0, 7, bukvy[7]);//Индикация "O"
    lc_val.setRow(0, 6, bukvy[9]);//Индикация "n"
    lc_val.setRow(0, 5, bukvy[10]);//Индикация "_"
  }

  if (val_change > 59) {
    val_change = 59; //Предел 59
  }
  if (val_change < 1) {
    val_change = 1; //Предел 1
  }
  des = val_change % 100 / 10;
  edi = val_change % 10;
  lc_val.setDigit(0, 1, des, false);
  lc_val.setDigit(0, 0, edi, false);

  //Работа клапана
    if(temp_col>temp_adj)  //Если температура колонны выше температуры отсечки
  {
    flag_val_temp=0;
    lc_val.setChar (0,4,' ', false);  
  }
  
  else //Если температура колонны ниже температуры отсечки
  {flag_val_temp=1;
    lc_val.setChar (0,4,' ', true);  
  } 
 
  unsigned long currentMillis = millis(); // Приравниваем время отслеживания к таймеру
  if (currentMillis - previousMillis > val_interval) //Если прошел нужный интервал
  {
    previousMillis = currentMillis; // сохраняем время последнего переключения
    if (flag_val == 1 && flag_val_temp == 1) //если разрешено работать клапану
    {
      // если клапан закрыт, то открываем, и наоборот
      if (val_state == LOW)
      {
        val_state = HIGH;
        val_interval = 1000;
      }
      else
      {
        val_state = LOW;
        val_interval = val_change * 1000;
      }

      digitalWrite(pin_val, val_state);// устанавливаем состояния выхода, чтобы включить или выключить клапан
    }
    else {digitalWrite(pin_val, LOW);} // если запрещено работать клапану

      
  }







  Serial.println (flag_val); //Вывод на монитор
}

void ENCODER_ADJ()  //Читаем энкодер отсечки
{
  clk = digitalRead(19);
  dt = digitalRead(16);
  if (clk < dt) {
    temp_adj++;
  }
  else {
    temp_adj--;
  }
}
void BUTTON_ADJ()  //Читаем кнопку отсечки
{
  but_adj++;
  if (but_adj == 1) {
    temp_adj = temp_col;
  }
  if (but_adj == 2) {
    temp_adj = 999;
  }
  if (but_adj == 3) {
    but_adj = 0;
  }
}
void ENCODER_VAL() //Читаем энкодер клапана
{
  clk = digitalRead(20);
  dt = digitalRead(17);
  if (clk < dt) {
    val_change--;
  }
  else {
    val_change++;
  }
}
void BUTTON_VAL() //Читаем кнопку клапана
{
  if (flag_val == 0) {
    flag_val = 1;
  }
  else {
    flag_val = 0;
  }
}

  1. Есть.
  2. Есть.

Режим тестирования. Штатная штука, в принципе, отключаемая

Когда-то давно собирал схемы на рассыпной логике, rc-цепочки давили дребезг безо всяких триггеров

Хмм… Режим тестирования, который осуществляется только при подаче напруги от внешнего ИП? Тогда вопросы:

  1. Почему вспыхивает только один модуль из трех?
  2. Как отключить эту штуку?

Трудно спорить и возражать… Но в моем случае все вышло, как описал: без триггера цепочки не помогали.

запиши скетч программатором, тогда паузы на старте не будет

А где он этот Ваш случай?

Ну так вот и описан он в посте под пунктом 1. Только цепочка - дребезг есть. Цепочка с триггером - нет.

Мои познания пока не так глубоки. Что за программатор? Где взять, где про него почитать?