Не срабатывает прерывание на Меге2560

Вечер добрый, коллеги! Пытаюсь перелопатить свою старую автоматику винокура, столкнулся с невыполнением функции по прерыванию. Ардуино Мега 2560. Железо проверил - контакты надежные, сигнал на ногу прерывания приходит. На пробу убрал из скетча ВСЁ, что не касается прерывания на 18-м пине (INT5) - заработало. Стал “есть слона по частям” (убирать фрагменты) - никак не могу найти, где капкан - в мониторе переменная “but_setup_val”, которая в функции “void BUTTON_SETUP()“ должна по кнопке прибавляться, остается нулевой. Гляньте свежим глазом, пожалуйста, где я напортачил? Специально выкладываю скетч целиком - может, я где-то был невнимателен или по незнанию совершил фатальную ошибку. И не ругайте за неизящные решения (всё еще только учусь). Заранее спасибо!

//Arduino Mega 2560

//БЛОК ИНДИКАТОРОВ МАХ7219_________________________________________________________________
#include <LedControl.h>    //Подключение библиотеки max7219 
//Провода: VCC-белый, GND-серый, clk-зеленый, cs-синий, din-фиолетовый
//Пины модуля индикатора max7219
int pin_din=A0; 
int pin_clk=A2;
int pin_cs=A1;
LedControl lc_max7219 = LedControl(pin_din, pin_clk, pin_cs, 3);  //Создаём объект класса LedControl (din,clk,cs,X) X - количество модулей
//Переменные для индикации
int tys; // Тысячи
int sot; // Сотни
int des; // Десятки
int edi;  // Единицы
// Массив с закодированными символами для надписей.
byte bukvy[16] = 
{
  B00110111,    //H-0
  B01110111,    //A-1
  B01000110,    //Г-2
  B01100111,    //Р-3
  B01001111,    //Е-4
  B01111111,    //В-5
  B01111001,    //З-6
  B01111110,    //O-7
  B01110110,    //П-8
  B00111110,    //И-9
  B01001110,    //С-10
  B00011111,    //Ь-11
  B00000000,    //пробел-12
  B01100011,    //знак градуса-13
  B01011111,    //Б-14
  B00111011,    //У-15
};

/*
Надписи?
РАЗГОН
НАГРЕВ
ЗАПИСЬ

ГРА (дус колонны)_88,8о 
СБР (ос)_88,8о

ПАУЗА_44
НАСОС_99
*/
//____________________________________________________________________________________________
//БЛОК ЭНКОДЕРА НАСТРОЙКИ____________________________________________________________________
//Переменные энкодера настройки
volatile int but_setup_val;  // Значение кнопки настройки
volatile int enc_setup_val=20;  // Значение энкодера настройки 
volatile int enc_setup_flag=0;  // Разрешение работы энкодера настройки
int ten_resist=11; // Сопротивление ТЭНа
int ten_power; // Настроенная мощность ТЭНа
//Пины модуля энкодера настройки
int pin_but_setup=18; //серый
int pin_enc_setupA=19; //фиолетовый 
int pin_enc_setupB=16; //синий 
//Пины управления реле PC817
//VCC=оранжевый 
//GND=синий 
int pin_relay_full=A14; //зеленый 
int pin_relay_stop=A15; //желтый
//Пины управления HY-M154
//GND=коричневый
int pin_plus=A13; //оранжевый 
int pin_minus=A12; //красный
//____________________________________________________________________________________________
//БЛОК ЭНКОДЕРА ТЕМПЕРАТУРЫ____________________________________________________________________
//Переменные энкодера температуры
volatile int but_temp_val;  // Значение кнопки температуры
volatile int enc_temp_val=0;  // Значение энкодера температуры 
volatile int enc_temp_flag=0;  // Разрешение работы энкодера температуры
//Пины модуля энкодера температуры
int pin_but_temp=20; 
int pin_enc_tempA=21;
int pin_enc_tempB=17;
//____________________________________________________________________________________________
//БЛОК ЭНКОДЕРА КЛАПАНА____________________________________________________________________
//Переменные энкодера клапана
volatile int but_valve_val;  // Значение кнопки клапана
volatile int enc_valve_val=0;  // Значение энкодера клапана 
volatile int enc_valve_flag=0;  // Разрешение работы энкодера клапана
//Пины модуля энкодера клапана
int pin_but_valve=2; 
int pin_enc_valveA=3; 
int pin_enc_valveB=14;
//Пины управления клапаном и насосом
int pin_valve=6;
int pin_pump=7; 
//____________________________________________________________________________________________
//БЛОК ДАТЧИКА ТЕМПЕРАТУРЫ____________________________________________________________________
//int pin_ds1820=2; //(!!!)
//____________________________________________________________________________________________
//БЛОК ВЕНТИЛАТОРА АВТОНОМКИ_________________________________________________________________
int pin_cooler=8;
//____________________________________________________________________________________________


void setup() 
{               
  Serial.begin(115200);// Объявляем скорость порта
  //Инициализация индикаторов
  lc_max7219.shutdown(0, false); //Выводим из спящего режима
  lc_max7219.setIntensity(0,7);  //Яркость дисплея на 7. Всего возможных режимов яркости от 0 до 15
  lc_max7219.clearDisplay(0);    //Очистить дисплей 
  lc_max7219.shutdown(1, false); //Выводим из спящего режима
  lc_max7219.setIntensity(1,7);  //Яркость дисплея на 7. Всего возможных режимов яркости от 0 до 15
  lc_max7219.clearDisplay(1);    //Очистить дисплей 
  lc_max7219.shutdown(2, false); //Выводим из спящего режима
  lc_max7219.setIntensity(2,7);  //Яркость дисплея на 7. Всего возможных режимов яркости от 0 до 15
  lc_max7219.clearDisplay(2);    //Очистить дисплей 
  
  //Пин насоса на выход
  pinMode(pin_pump, OUTPUT); 
  //Пины вентилятора на выход
  pinMode(pin_cooler, OUTPUT); 

  //Пины модуля энкодера настройки на вход
  pinMode(pin_but_setup, INPUT);  
  pinMode(pin_enc_setupA, INPUT); 
  pinMode(pin_enc_setupB, INPUT);   
  
  //Пины модуля энкодера температуры на вход
  pinMode(pin_but_temp, INPUT);  
  pinMode(pin_enc_tempA, INPUT); 
  pinMode(pin_enc_tempB, INPUT); 
  
  //Пины модуля энкодера клапана на вход
  pinMode(pin_but_valve, INPUT);  
  pinMode(pin_enc_valveA, INPUT); 
  pinMode(pin_enc_valveB, INPUT); 
  
  //Пины индикатора max7219 на выход
  pinMode(pin_din, OUTPUT);  
  pinMode(pin_clk, OUTPUT);  
  pinMode(pin_cs, OUTPUT);  
  
  /*Пины управления реле на PC817 на выход !!!Светодиоды загораются при LOW (замкнуты левые клеммы)
                                           !!!Светодиоды гаснут при HIGH (замкнуты правые клеммы) */
  pinMode(pin_relay_full, OUTPUT);  
  pinMode(pin_relay_stop, OUTPUT);  
  digitalWrite (pin_relay_full,HIGH);  
  digitalWrite (pin_relay_stop,HIGH);
  
  //Пины управления HY-M154 на выход
  pinMode(pin_plus, OUTPUT);  
  pinMode(pin_minus, OUTPUT);  
  digitalWrite (pin_plus,LOW);  
  digitalWrite (pin_minus,LOW);
  
  //Назначение прерываний
  attachInterrupt(0, BUTTON_VALVE, FALLING);   //пин (2)прерывания кнопки клапана
  attachInterrupt(1, ENCODER_VALVE, FALLING);  //пин (3) прерывания энкодера клапана
  attachInterrupt(5, BUTTON_SETUP, FALLING);   //пин (18)прерывания кнопки настройки
  attachInterrupt(4, ENCODER_SETUP, FALLING);  //пин (19) прерывания энкодера настройки 
  attachInterrupt(3, BUTTON_TEMP, FALLING);   //пин (20)прерывания кнопки температуры
  attachInterrupt(2, ENCODER_TEMP, FALLING);  //пин (21) прерывания энкодера температуры

}

void loop() 
{
  Serial.println(but_setup_val);
  if (but_setup_val==1 && enc_setup_flag==1) //При 1-м нажатии кнопки настройки проводим полуавтоматическую настройку РМ-2н
  {
    RM_SETUP();
    //Высчитываем и прописываем мощность на индикаторе	
    ten_power=(enc_setup_val*enc_setup_val)/ten_resist; // Расчет мощности по напряжению
    tys = enc_setup_val / 1000;
    sot = enc_setup_val % 1000/100;
    des = enc_setup_val % 100 / 10;
    edi = enc_setup_val % 10;

    //Гасим левые нули
    if (tys==0) //До 999 вт
    {
      lc_max7219.setRow(0, 7, bukvy[12]);//Гасим 0
      lc_max7219.setDigit(0, 6, sot, false);
      lc_max7219.setDigit(0, 5, des, false);
      lc_max7219.setDigit(0, 4, edi, false);
      lc_max7219.setRow(0, 2, bukvy[12]);//Индикация " "  
      lc_max7219.setRow(0, 1, bukvy[5]);//Индикация "В"  
      lc_max7219.setRow(0, 0, bukvy[1]);//Индикация "А" 
    }
    if (tys==0 && sot==0) //До 999 вт
    {
      lc_max7219.setRow(0, 7, bukvy[12]);//Гасим 0
      lc_max7219.setRow(0, 6, bukvy[12]);//Гасим 0
      lc_max7219.setDigit(0, 5, des, false);
      lc_max7219.setDigit(0, 4, edi, false);
      lc_max7219.setRow(0, 2, bukvy[12]);//Индикация " "  
      lc_max7219.setRow(0, 1, bukvy[5]);//Индикация "В"  
      lc_max7219.setRow(0, 0, bukvy[1]);//Индикация "А"      
    }  
    if (tys==0 && sot==0 && des==0) //До 9 вт
    {
      lc_max7219.setRow(0, 7, bukvy[12]);//Гасим 0
      lc_max7219.setRow(0, 6, bukvy[12]);//Гасим 0
      lc_max7219.setRow(0, 5, bukvy[12]);//Гасим 0
      lc_max7219.setDigit(0, 4, edi, false);
      lc_max7219.setRow(0, 2, bukvy[12]);//Индикация " "  
      lc_max7219.setRow(0, 1, bukvy[5]);//Индикация "В"  
      lc_max7219.setRow(0, 0, bukvy[1]);//Индикация "А"  
    }
    if (tys>0) //До 9999 вт
    {
      lc_max7219.setDigit(0, 6, tys, false);
      lc_max7219.setDigit(0, 5, sot, false);
      lc_max7219.setDigit(0, 4, des, false);
      lc_max7219.setDigit(0, 3, edi, false);
      lc_max7219.setRow(0, 2, bukvy[12]);//Гасим 0 
      lc_max7219.setRow(0, 1, bukvy[5]);//Индикация "В"  
      lc_max7219.setRow(0, 0, bukvy[1]);//Индикация "А"  
    }

}
  if (but_setup_val==2 ) //При 2-м нажатии кнопки настройки запускаем разгон (максимальная можность)
  {
    digitalWrite (pin_relay_full,LOW); //Реле замыкает клеммы + и Р на РМ-2н
    //Пишем " РАЗГОН " на индикаторе
    lc_max7219.setRow(0, 7, bukvy[12]);//Индикация "_"
    lc_max7219.setRow(0, 6, bukvy[3]);//Индикация "Р"
    lc_max7219.setRow(0, 5, bukvy[1]);//Индикация "А"
    lc_max7219.setRow(0, 4, bukvy[6]);//Индикация "З"  
    lc_max7219.setRow(0, 3, bukvy[2]);//Индикация "Г"  
    lc_max7219.setRow(0, 2, bukvy[7]);//Индикация "О"  
    lc_max7219.setRow(0, 1, bukvy[0]);//Индикация "Н"  
    lc_max7219.setRow(0, 0, bukvy[12]);//Индикация "_"    
}
  if (but_setup_val==3 ) //При 3-м нажатии кнопки настройки переходим в рабочий режим нагрева
  {
    digitalWrite (pin_relay_full,HIGH); //Реле размыкает клеммы + и Р на РМ-2н (отключается разгон, переход на ранее настроенную мощность)
    //Пишем " НАГРЕВ " на индикаторе
    lc_max7219.setRow(0, 7, bukvy[12]);//Индикация "_"
    lc_max7219.setRow(0, 6, bukvy[0]);//Индикация "Н"
    lc_max7219.setRow(0, 5, bukvy[1]);//Индикация "А"
    lc_max7219.setRow(0, 4, bukvy[2]);//Индикация "Г"  
    lc_max7219.setRow(0, 3, bukvy[3]);//Индикация "Р"  
    lc_max7219.setRow(0, 2, bukvy[4]);//Индикация "Е"  
    lc_max7219.setRow(0, 1, bukvy[5]);//Индикация "В"  
    lc_max7219.setRow(0, 0, bukvy[12]);//Индикация "_"
  }
} 

void BUTTON_SETUP() //Работа кнопки настройки
{
  but_setup_val++;
  if (but_setup_val=!1) {enc_setup_flag=0;}  // Запрещаем работу энкодера настройки		
  if (but_setup_val>3) {but_setup_val=0;} // Обнуляем кнопку настройки
}
void BUTTON_TEMP() //Работа кнопки температуры 
{

}
void BUTTON_VALVE() //Работа кнопки клапана
{

}  
void ENCODER_SETUP()  //Работа энкодера настройки 
{ 
   if (but_setup_val==1) //Если кнопка настройки в положении 1, настройка мощности нагрева
  {
     //Считываем энкодер настройки 
    int clk=digitalRead(pin_enc_setupA); 
    int dt=digitalRead(pin_enc_setupB);

    if (clk<dt && enc_setup_val<261) //Повышаем рабочее напряжение
    {
      enc_setup_val++;
      digitalWrite (pin_plus,HIGH);
  	delay (200);  
  	digitalWrite (pin_plus,LOW);
    }
    if (clk>dt && enc_setup_val>19) //Понижаем рабочее напряжение
    {
      enc_setup_val--;
      digitalWrite (pin_minus,HIGH);
      delay (200);  
      digitalWrite (pin_minus,LOW);
    }

  }

}
void ENCODER_TEMP()  //Работа энкодера температуры  
{
  
}
void ENCODER_VALVE()  //Работа энкодера клапана 
{
  
}
void RM_SETUP()
{
  digitalWrite (pin_plus,HIGH);
  delay (200);  
  digitalWrite (pin_plus,LOW);
  delay (200);  
  digitalWrite (pin_plus,HIGH);
  delay (200);  
  digitalWrite (pin_plus,LOW);
  delay (200);
  digitalWrite (pin_plus,HIGH);
  delay (200);  
  digitalWrite (pin_plus,LOW);
  delay (200);
  digitalWrite (pin_plus,HIGH);
  delay (200);  
  digitalWrite (pin_plus,LOW);
  delay (200);
  digitalWrite (pin_minus,HIGH);
  delay (200);  
  digitalWrite (pin_minus,LOW); 
  enc_setup_flag=1;
  but_setup_val=1;
}

В строке №251 Вы присваиваете ноль Вашей but_setup_val.

 if (but_setup_val=!1) {enc_setup_flag=0;}  // Запрещаем работу энкодера настройки		

Видимо, там имелось в виду !=, а Вы по сути написали but_setup_val = (!1), т.е. присвоили 0.

Если будете ещё что-то спрашивать, дайте ссылку на библиотеку, я у себя поставлю, запущу посмотрю.

2 лайка

GitHub - hafsahshahbaz/LedControl: библиотека Arduino для отображения двоичных чисел на светодиодах

Спасибо, одну ошибку я уже нашёл. Посмотрите, если не поможет, пишите, я через полчаса вернусь.

Может правильней !=

Спасибо! Да, это оно! Я еще раз посмотрел в иньтерьнете, как правильно пишется. Именно “!=“. Кнопка заработала. Однако интересно, что компилятор на эту ошибку никак не прореагировал. Сегодня уже ваять не буду - замотался, а завтра с утра трудиться… Продолжу. Если вылезет что-то еще и не смогу ликвидировать - возьму на себя смелость побеспокоить.

Он правильно среагировал и присвоил значение 0 переменой, все как просили))
Написали бы

if (but_setup_val == !1) 

Все срослось бы)

Так это не ошибка. Это команда присвоения переменной значения “обратного” 1, т.е. 0.
Вам ЕвгенийП написал же -

Компилятор в принципе не может реагировать на такие ошибки, он ведь не знает, что именно программист хотел написать, поэтому исходит из того, что программист написал.

Спасибо, коллеги! Все понял, в том числе и собственную оплошность продолжу ваять…

И помните! Казнить нельзя помиловать! :wink:

1 лайк

Приключения не закончились :slight_smile:

Энкодер “одет“ в антидребезг посредством SN74HC14A (триггер Шмита). Схема на триггере тут: https://cloud.mail.ru/public/9jdq/BGafVoz3a

Нарисовал, минуя принятые правила, но, думаю, понятно. Железо проверено: КЗ и непропаек нет, сигналы на пины Ардуино поступают.

Примитивный скетч для теста энкодера показал следующее:

  1. Кнопка отрабатывает нормально.
  2. Вращение энкодера влево нормально дает на мониторе: 1 щелчок → переменная “enc“ уменьшается на единицу.
  3. Вращение энкодера вправо по одному щелчку ни к чему не приводит.
  4. Резкое быстрое вращение энкодера вправо (несколько щелчков) увеличивает переменную “enc“ на произвольное количество единиц.

Предположения: или гавкнул энкодер или я опять где-то напортачил (хотя где можно в таком коротком скетче напортачить?)

Ваши мнения, коллеги?

Заранее спасибо!

//Arduino Mega 2560

volatile int but;  
volatile int enc=20;
volatile int clk;
volatile int dt; 
int pin_but=18; 
int pin_encA=19;
int pin_encB=16;

void setup() 
{               
  Serial.begin(115200);
  pinMode(pin_but, INPUT_PULLUP);  
  pinMode(pin_encA, INPUT_PULLUP); 
  pinMode(pin_encB, INPUT_PULLUP);   
  
  attachInterrupt(5, BUTTON, FALLING); 
  attachInterrupt(4, ENCODER, FALLING);
}

void loop() 
{
  Serial.print(but);
  Serial.print(" ");
  Serial.println(enc);
} 

void BUTTON() 
{
  but++;
}
  
void ENCODER()
{ 
   clk=digitalRead(pin_encA); 
   dt=digitalRead(pin_encB);
   if (clk>dt) {enc++;}
   if (clk<dt) {enc--;}
}
 

А как будет срабатывать прерывание для этого пина, если оно не выставлено?
P.S. @Sonologist А поменяйте местами физические выводы энкодера. Что-то изменится?

2 лайка

Заводи “blue” тоже на прерывание. Например, на 20й. И обрабатывай вращения влево/вправо каждый в своем прерывании.

А вообще, я не понимаю - зачем морока с этими прерываниями нужна?
Берешь вот эту библиотеку и всё прекрасно работает в loop’е:

#include <Rotary.h>

Rotary r = Rotary(2, 3);

void setup() {
  Serial.begin(9600);
  r.begin(true);
}

void loop() {
  unsigned char result = r.process();
  if (result) {
    Serial.println(result == DIR_CW ? "Right" : "Left");
  }
}

Она же и с прерываниями работает, если сильно хочется. Но только всё равно на оба вывода энкодера прерывания нужно вешать…

Легко запомнить. “Не” “равно“ –> “!” “=“

1 лайк

Я что-то вообще не пойму, как оно (прерывание) будет срабатывать, если обработчик назначен на INT4

attachInterrupt(4, ENCODER, FALLING);

а вывод энкодера (причём почему-то ОДИН) подключен к пину 19 (INT2)?

Вот именно! Странная какая-то реализация у ТС..
И аппаратный “антидребезг”, ИМХО, вообще лишний, без проблем софтовым можно обойтись.
Кстати.. У себя энкодеры (механические) подключаю по немного “усложнённой” схеме.
Сплагиатил с какого-то модуля китайского энкодера. :wink:

1 лайк

А в чем смысл? Я про 2х10к которые идут к МК.

ЗЫ: Чтобы энкодер “прожил дольше” нужно резисторы Ом на 100 ставить между выводом энкодера (А/В) и конденсаторами 0.1 мкФ.

Плата int.0 int.1 int.2 int.3 int.4 int.5
UNO, Ethernet 2 3
Mega2560 2 3 21 20 19 18
Leonardo 3 2 0 1 7

Я попробовал рассуждать следующим образом:

Запуск функции “void ENCODER” по прерыванию с ОДНОЙ ИЗ ног энкодера. В ней - читаю состояние пинов обеих ног, сравниваю их и по результату либо увеличиваю либо уменьшаю переменную “enc“. Зачем прерывание с другой ноги энкодера?

Библиотеку попробую, спасибо!

Менял. Та же картина, только “++” поменялся с “- -”.