Помогите с обработкой кнопки

Здравствуйте! Собираю для отца прибор для диагностики автомобильных электроцепей. Использую микроконтроллер Atmega168pa. Суть такая - при нажатии на кнопку меняются режимы работы прибора: 1 - вольтметр, 2 - тестер масса/+ питания, 3 - генератор сигналов, 4 - частотомер и т.д. Имеется трёхразрядный семисегментный индикатор, информация выводится на него в динамическом режиме. Программу пишу на Arduino IDE, заливаю в камень скетч через Arduino ISP.
Кнопка подключена к 23-й ноге атмеги (она же А0/14, она же PC0/PCINT8) через резистор 10К, замыкается на землю. Вначале всё шло как по маслу. Для обработки нажатия кнопки использовал библиотеку GyverButton. Режимы переключались без проблем. Флагом переключения режима служило значение переменной byte А, которое менялось от нажатия на единицу. При очередной прошивке МК вылезла какая-то ошибка AVR Dude, точное описание не помню, но смысл был в том, что произошла ошибка записи. Я решил, что ошибка из-за потерянного контакта с МК, после чего пошевелил провода, проверил контакты и без проблем залил скетч. Но тут начались странности: кнопка переключения режима стала отрабатывать некорректно. То сработает нажатие, то нет. То сработает после долгого нажатия, то срабатывает после нескольких нажатий с разной частотой, то не срабатывает совсем. В общем, поведение кнопки зависит от настроения. Что я только не делал. И библиотеку обработки кнопки менял, и способы отсчета времени внутри скетча, всё бесполезно.
Решил записать простейший скетч для проверки самой кнопки (мало ли, может что с ней):
‘’‘void setup() {
pinMode(5, OUTPUT);
pinMode(14, INPUT);
digitalWrite(5, LOW);
}
void loop() {
A = digitalRead(14);
if (A == 1)
{digitalWrite(5, HIGH);}
}
‘’’
Кнопка работает нормально: при нажатии загорается светодиод, при отпускании кнопки - гаснет. Значит беда в программной части. Решил повешать обработку кнопки на внешнее прерывание, чтобы смене режима не могли помешать никакие затыки в программе. С помощью библиотеки PinChangeInterrupt.h установил внешнее прерывание на пин А0/14, на котором висит кнопка. Залил прошивку - и кнопка заработала без проблем! Переключение режимов производилось чётко без задержек при каждом нажатии… буквально секунд 15. После чего МК снова начал обрабатывать нажатие кнопки фиг пойми как (ДАЖЕ ПРИ ВНЕШНЕМ ПРЕРЫВАНИИ!). Я уже сломал всю голову. Помогите советом! Что может быть не так?
Код на данный момент представляет из себя вот что:
‘’’
#include <PinChangeInterrupt.h>
#define Button_Pin 14
#define AOFF PORTC &= ~ (1 << 5) //Управление пинами, управляющими сегментами индикатора
#define AON PORTC |= (1 << 5)
#define BOFF PORTD &= ~ (1 << 1)
#define BON PORTD |= (1 << 1)
#define COFF PORTD &= ~ (1 << 3)
#define CON PORTD |= (1 << 3)
#define DOFF PORTD &= ~ (1 << 4)
#define DON PORTD |= (1 << 4)
#define EOFF PORTB &= ~ (1 << 6)
#define EON PORTB |= (1 << 6)
#define FOFF PORTD &= ~ (1 << 0)
#define FON PORTD |= (1 << 0)
#define GOFF PORTD &= ~ (1 << 2)
#define GON PORTD |= (1 << 2)
#define H1OFF PORTC |= (1 << 4)
#define H1ON PORTC &= ~ (1 << 4)
#define H2OFF PORTC |= (1 << 3)
#define H2ON PORTC &= ~ (1 << 3)
#define H3OFF PORTC |= (1 << 2)
#define H3ON PORTC &= ~ (1 << 2)
#define DPOFF PORTB &= ~ (1 << 7)
#define DPON PORTB |= (1 << 7)
#define GREENLEDON PORTD |= (1 << 5)
#define GREENLEDOFF PORTD &= ~ (1 << 5)
#define REDLEDON PORTD &= ~ (1 << 6)
#define REDLEDOFF PORTD |= (1 << 6)

#define PERIOD 6
#define PERIOD2 250
#define PERIOD3 250
#define PERIOD4 6
#define PERIOD5 250
#define PERIOD6 6
#define PERIOD7 300
#define PERIOD8 1000

int u = 0; // переменная для числа пребразования 0-1023
int u2 = 0;
float u_in = 0.0; // переменная для напряжения 0.0-5.0
float u_inR = 0.0;
float u_in2 = 0.0;
int Ut, Des, Ed, Dol;
int32_t timer1 = 0;
int32_t timer2 = 0;
int32_t timer3 = 0;
int32_t timer4 = 0;
int32_t timer5 = 0;
int32_t timer6 = 0;
int32_t timer7 = 0;
int32_t timer8 = 0;
byte B, C, D, E, F, G, H, I;
volatile int A = 0;

void setup() {
attachPCINT(digitalPinToPCINT(Button_Pin), ModeChange, FALLING);
DDRD = B11111111; //назначаем все порты D (пины с 0 по 7) как выходы
pinMode(15, OUTPUT);
pinMode(16, OUTPUT);
pinMode(17, OUTPUT);
pinMode(18, OUTPUT);
pinMode(19, OUTPUT);
pinMode(20, OUTPUT);
pinMode(21, OUTPUT);
pinMode(A7, INPUT);
H1ON;
H2OFF;
H3OFF;
DPOFF;
REDLEDOFF;
GREENLEDOFF;
A = 0;
B = 0;
C = 0;
D = 0;
E = 0;
F = 0;
G = 0;
H = 0;
Ut = 0;
I = 0;
}

void ModeChange(void)
{
static unsigned long millis_prev;
if (millis() - 300 > millis_prev)
{millis_prev = millis(); A++;}
if (A > 3) {A = 0;}

}

//коды управления сегментами индикатора для формирования цифры___________________
void DIG0()
{
AON; BON; CON; DON; EON; FON; GOFF;
}

void DIG1()
{
AOFF; BON; CON; DOFF; EOFF; FOFF; GOFF;
}

void DIG2()
{
AON; BON; COFF; DON; EON; FOFF; GON;
}

void DIG3()
{
AON; BON; CON; DON; EOFF; FOFF; GON;
}

void DIG4()
{
AOFF; BON; CON; DOFF; EOFF; FON; GON;
}

void DIG5()
{
AON; BOFF; CON; DON; EOFF; FON; GON;
}

void DIG6()
{
AON; BOFF; CON; DON; EON; FON; GON;
}

void DIG7()
{
AON; BON; CON; DOFF; EOFF; FOFF; GOFF;
}

void DIG8()
{
AON; BON; CON; DON; EON; FON; GON;
}

void DIG9()
{
AON; BON; CON; DON; EOFF; FON; GON;
}

void SYMT()
{
AOFF; BOFF; COFF; DON; EON; FON; GON;
}

void SYMS()
{
AON; BOFF; CON; DON; EOFF; FON; GON;
}

void SYME()
{
AON; BOFF; COFF; DON; EON; FON; GON;
}

void SYMn()
{
AOFF; BOFF; CON; DOFF; EON; FOFF; GON;
}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Конец передачи кода цифры ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

//Функция переключения цифр в динамической индикации_______________

void SwitchDIG()
{
if (B == 0) //определеяем, какая цифра должна гореть на первом индикаторе (десятки вольт)
{H3OFF; H1ON;
switch(Des) {
case 0: DIG0(); break;
case 1: DIG1(); break;
case 2: DIG2(); break;
case 3: DIG3(); break;
case 4: DIG4(); break;
}}

if (B == 1)                  //определеяем, какая цифра должна гореть на втором индикаторе (единицы вольт)
   {if (I == 0)              //с точкой
    {
    H1OFF; H2ON; DPON;
    switch(Ed) {
    case 0: DIG0(); break;
    case 1: DIG1(); break;
    case 2: DIG2(); break;
    case 3: DIG3(); break;
    case 4: DIG4(); break;
    case 5: DIG5(); break;
    case 6: DIG6(); break;
    case 7: DIG7(); break;
    case 8: DIG8(); break;
    case 9: DIG9(); break;}
    }
    if (I == 1)             //без точки
      {
    H1OFF; H2ON; DPOFF;
    switch(Ed) {
    case 0: DIG0(); break;
    case 1: DIG1(); break;
    case 2: DIG2(); break;
    case 3: DIG3(); break;
    case 4: DIG4(); break;
    case 5: DIG5(); break;
    case 6: DIG6(); break;
    case 7: DIG7(); break;
    case 8: DIG8(); break;
    case 9: DIG9(); break;}
    }
    }
    
if (B == 2)                  //определеяем, какая цифра должна гореть на третьем индикаторе (десятые доли вольт)
   {H2OFF; DPOFF; H3ON;
   switch(Dol) {
   case 0:  DIG0(); break;
   case 1:  DIG1(); break;
   case 2:  DIG2(); break; 
   case 3:  DIG3(); break; 
   case 4:  DIG4(); break;
   case 5:  DIG5(); break;
   case 6:  DIG6(); break;
   case 7:  DIG7(); break;
   case 8:  DIG8(); break;
   case 9:  DIG9(); break;
   }}
   
   B++; 
if (B == 3)
   {B = 0;}

}

void PrintTst()
{
if (D == 0) {H3OFF; H1ON; SYMT();}
if (D == 1) {H1OFF; H2ON; SYMS();}
if (D == 2) {H2OFF; H3ON; SYMT();}
D++;
if (D == 3) {D = 0;}
}

void PrintGen()
{
if (E == 0) {H3OFF; H1ON; DIG6();}
if (E == 1) {H1OFF; H2ON; SYME();}
if (E == 2) {H2OFF; H3ON; SYMn();}
E++;
if (E == 3) {E = 0;}
}

void voltmeter()
{
if (C == 0) {GREENLEDOFF; REDLEDOFF; C = 1; I=0;} //флаг нажатия

if (millis() - timer2 >= 250) {
 timer2 = millis();
 u = analogRead(A7); // -------------------------------------измерение и калибровка
 u_in = (u * 5.0) / 1023 * 10; // пересчет измерения в вольты
 if (u_in >= 3.5) 
 {u_inR = u_in * 1.128;}
 if (u_in >= 1.0 && u_in < 3.5)
 {u_inR = u_in * 1.27;} 
 if (u_in < 1.0)
 {u_inR = 0.0;} //-------------------------------------------конец измерения и калибровки
 Ut = u_inR * 10;
 Des = Ut / 100 % 10;
 Ed = Ut / 10 % 10;
 Dol = Ut % 10;
 }

if (millis() - timer1 >= 6) { //переключение индикаторов с периодичностью 25 раз в секунду + начало защиты от пропуска шага
timer1 = millis();
SwitchDIG();
}
}

void tester()
{
if (C ==1) {GREENLEDON; DPOFF; C = 2;} //флаг нажатия

if (millis() - timer3 >= PERIOD3) {                      // измерение напряжения для решения о зажигании красного светодиода и подачи звукового сигнала
 timer3 = millis();
 u = analogRead(A7); // измерение 
 u_in = (u * 5.0) / 1023 * 10; // пересчет измерения в вольты
 if (u_in > 11.0)
    {REDLEDON; tone(15, 1000);}
 else {REDLEDOFF; noTone(15);}

} //---------------------------------------------

if (millis() - timer5 >= PERIOD5) { // измерение напряжения для решения о зажигании зеленого светодиода и подачи звукового сигнала
timer5 = millis();
u2 = analogRead(A6); // измерение
u_in2 = (u2 * 5.0) / 1023; // пересчет измерения в вольты
if (u_in2 <=3.9)
{tone(15, 300);}
// else {noTone(15);}
} //-----------------------------------------------
if (millis() - timer4 >= PERIOD4) { //отображение надписи TST на индикаторе (динамическая индикация)
timer4 = millis();
PrintTst();
}
}

void generator()
{
if (C == 2) {GREENLEDOFF; C=3;}
if (millis() - timer6 >= PERIOD6) { //отображение надписи TST на индикаторе (динамическая индикация)
timer6 = millis();
PrintGen();
// tone(5, 1000);
//delay(80);
// noTone(5);
//delay(80);
}
}

void chastotomer()
{
if (C == 3) {REDLEDON; C=0; I=1;}
if (H == 0)
{u = analogRead(A7);
u_in = (u * 5.0) / 1023 * 10; // пересчет измерения в вольты
if (u_in >= 1.6) {G++; H=1;}}
if (H == 1)
{u = analogRead(A7);
u_in = (u * 5.0) / 1023 * 10; // пересчет измерения в вольты
if (u_in < 1.6) {H=0;}}
if (millis() - timer8 >= PERIOD8) { // измерение напряжения для решения о засчёте очередного герца
timer8 = millis();
Des = G / 100 % 10;
Ed = G / 10 % 10;
Dol = G % 10;
G = 0;}
if (millis() - timer1 >= 6) { //переключение индикаторов с периодичностью 25 раз в секунду + начало защиты от пропуска шага
timer1 = millis();
SwitchDIG();
}
}

//void yield()
//{
//if (millis() - timer6 >= PERIOD6) { //отображение надписи TST на индикаторе (динамическая индикация)
// timer6 = millis();
// PrintGen();
//}
//}

void loop() {

switch(A) {
case 0: voltmeter(); break; //----------------------------------режим по умолчанию-ВОЛЬТМЕТР------------
case 1: tester(); break; //-----------------------------------1-е нажатие кнопки-ТЕСТЕР--------------
case 2: generator(); break; //----------------------------------2-е нажатие кнопки-ГЕНЕРАТОР-------------
case 3: chastotomer(); break; //---------------------------------3-e нажатие кнопки-ЧАСТОТОМЕР-----------

}
} //--------------------------END-----------------------------
‘’’

Кстати, пытался написать скетч с использованием чисто библиотеки обработки кнопки, где весь смысл программы - поочередное включение и выключение светодиода по нажатию кнопки - МК упорно отказывается это делать после того проглюка во время загрузки скетча. Пытался использовать библиотеки Button.h, GyverButton.h, TroykaButton.h - бесполезно. Управление светодиодом напрямую при считывании сигнала с кнопки работает.

Вставьте код по нормальному, в таком виде читать ваше сообщение невозможно

Обратный апостроф там, где буква ё. От слова йоп… Ну ты понял?
Плюс за попытку, минус за невнимательность.

Так и не читайте. Я вот и не читаю :frowning:

Друзья, простите великодушно. Я вроде вставлял через 3 апострофа. Но код как то частично правильно вставился, частично нет. Я сейчас на работе, с телефона неудобно поправить сообщение. Как вернусь домой - обязательно поправлю. Извините ещё раз.

перед/после блока кода поставить пустые строки и будет всем счастье

Вот вставляю код повторно согласно инструкции.

#include <PinChangeInterrupt.h>
#define Button_Pin 14
#define AOFF PORTC &= ~ (1 << 5) //Управление пинами, управляющими сегментами индикатора
#define AON PORTC |= (1 << 5)
#define BOFF PORTD &= ~ (1 << 1)
#define BON PORTD |= (1 << 1)
#define COFF PORTD &= ~ (1 << 3)
#define CON PORTD |= (1 << 3)
#define DOFF PORTD &= ~ (1 << 4)
#define DON PORTD |= (1 << 4)
#define EOFF PORTB &= ~ (1 << 6)
#define EON PORTB |= (1 << 6)
#define FOFF PORTD &= ~ (1 << 0)
#define FON PORTD |= (1 << 0)
#define GOFF PORTD &= ~ (1 << 2)
#define GON PORTD |= (1 << 2)
#define H1OFF PORTC |= (1 << 4)
#define H1ON PORTC &= ~ (1 << 4)
#define H2OFF PORTC |= (1 << 3)
#define H2ON PORTC &= ~ (1 << 3)
#define H3OFF PORTC |= (1 << 2)
#define H3ON PORTC &= ~ (1 << 2)
#define DPOFF PORTB &= ~ (1 << 7)
#define DPON PORTB |= (1 << 7)
#define GREENLEDON PORTD |= (1 << 5)
#define GREENLEDOFF PORTD &= ~ (1 << 5)
#define REDLEDON PORTD &= ~ (1 << 6)
#define REDLEDOFF PORTD |= (1 << 6)

#define PERIOD 6
#define PERIOD2 250
#define PERIOD3 250
#define PERIOD4 6
#define PERIOD5 250
#define PERIOD6 6
#define PERIOD7 300
#define PERIOD8 1000

int u = 0; // переменная для числа пребразования 0-1023
int u2 = 0;
float u_in = 0.0; // переменная для напряжения 0.0-5.0
float u_inR = 0.0;
float u_in2 = 0.0;
int Ut, Des, Ed, Dol;
int32_t timer1 = 0;
int32_t timer2 = 0;
int32_t timer3 = 0;
int32_t timer4 = 0;
int32_t timer5 = 0;
int32_t timer6 = 0;
int32_t timer7 = 0;
int32_t timer8 = 0;
byte B, C, D, E, F, G, H, I;
volatile int A = 0;

void setup() {
attachPCINT(digitalPinToPCINT(Button_Pin), ModeChange, FALLING);
DDRD = B11111111; //назначаем все порты D (пины с 0 по 7) как выходы
pinMode(15, OUTPUT);
pinMode(16, OUTPUT);
pinMode(17, OUTPUT);
pinMode(18, OUTPUT);
pinMode(19, OUTPUT);
pinMode(20, OUTPUT);
pinMode(21, OUTPUT);
pinMode(A7, INPUT);
H1ON;
H2OFF;
H3OFF;
DPOFF;
REDLEDOFF;
GREENLEDOFF;
A = 0;
B = 0;
C = 0;
D = 0;
E = 0;
F = 0;
G = 0;
H = 0;
Ut = 0;
I = 0;
}

void ModeChange(void)
{
static unsigned long millis_prev;
if (millis() - 300 > millis_prev)
{millis_prev = millis(); A++;}
if (A > 3) {A = 0;}

}

//коды управления сегментами индикатора для формирования цифры___________________
void DIG0()
{
AON; BON; CON; DON; EON; FON; GOFF;
}

void DIG1()
{
AOFF; BON; CON; DOFF; EOFF; FOFF; GOFF;
}

void DIG2()
{
AON; BON; COFF; DON; EON; FOFF; GON;
}

void DIG3()
{
AON; BON; CON; DON; EOFF; FOFF; GON;
}

void DIG4()
{
AOFF; BON; CON; DOFF; EOFF; FON; GON;
}

void DIG5()
{
AON; BOFF; CON; DON; EOFF; FON; GON;
}

void DIG6()
{
AON; BOFF; CON; DON; EON; FON; GON;
}

void DIG7()
{
AON; BON; CON; DOFF; EOFF; FOFF; GOFF;
}

void DIG8()
{
AON; BON; CON; DON; EON; FON; GON;
}

void DIG9()
{
AON; BON; CON; DON; EOFF; FON; GON;
}

void SYMT()
{
AOFF; BOFF; COFF; DON; EON; FON; GON;
}

void SYMS()
{
AON; BOFF; CON; DON; EOFF; FON; GON;
}

void SYME()
{
AON; BOFF; COFF; DON; EON; FON; GON;
}

void SYMn()
{
AOFF; BOFF; CON; DOFF; EON; FOFF; GON;
}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^Конец передачи кода цифры ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

//Функция переключения цифр в динамической индикации_______________

void SwitchDIG()
{
if (B == 0) //определеяем, какая цифра должна гореть на первом индикаторе (десятки вольт)
{H3OFF; H1ON;
switch(Des) {
case 0: DIG0(); break;
case 1: DIG1(); break;
case 2: DIG2(); break;
case 3: DIG3(); break;
case 4: DIG4(); break;
}}

if (B == 1)                  //определеяем, какая цифра должна гореть на втором индикаторе (единицы вольт)
   {if (I == 0)              //с точкой
    {
    H1OFF; H2ON; DPON;
    switch(Ed) {
    case 0: DIG0(); break;
    case 1: DIG1(); break;
    case 2: DIG2(); break;
    case 3: DIG3(); break;
    case 4: DIG4(); break;
    case 5: DIG5(); break;
    case 6: DIG6(); break;
    case 7: DIG7(); break;
    case 8: DIG8(); break;
    case 9: DIG9(); break;}
    }
    if (I == 1)             //без точки
      {
    H1OFF; H2ON; DPOFF;
    switch(Ed) {
    case 0: DIG0(); break;
    case 1: DIG1(); break;
    case 2: DIG2(); break;
    case 3: DIG3(); break;
    case 4: DIG4(); break;
    case 5: DIG5(); break;
    case 6: DIG6(); break;
    case 7: DIG7(); break;
    case 8: DIG8(); break;
    case 9: DIG9(); break;}
    }
    }
    
if (B == 2)                  //определеяем, какая цифра должна гореть на третьем индикаторе (десятые доли вольт)
   {H2OFF; DPOFF; H3ON;
   switch(Dol) {
   case 0:  DIG0(); break;
   case 1:  DIG1(); break;
   case 2:  DIG2(); break; 
   case 3:  DIG3(); break; 
   case 4:  DIG4(); break;
   case 5:  DIG5(); break;
   case 6:  DIG6(); break;
   case 7:  DIG7(); break;
   case 8:  DIG8(); break;
   case 9:  DIG9(); break;
   }}
   
   B++; 
if (B == 3)
   {B = 0;}
}

void PrintTst()
{
if (D == 0) {H3OFF; H1ON; SYMT();}
if (D == 1) {H1OFF; H2ON; SYMS();}
if (D == 2) {H2OFF; H3ON; SYMT();}
D++;
if (D == 3) {D = 0;}
}

void PrintGen()
{
if (E == 0) {H3OFF; H1ON; DIG6();}
if (E == 1) {H1OFF; H2ON; SYME();}
if (E == 2) {H2OFF; H3ON; SYMn();}
E++;
if (E == 3) {E = 0;}
}

void voltmeter()
{
if (C == 0) {GREENLEDOFF; REDLEDOFF; C = 1; I=0;} //флаг нажатия

if (millis() - timer2 >= 250) {
 timer2 = millis();
 u = analogRead(A7); // -------------------------------------измерение и калибровка
 u_in = (u * 5.0) / 1023 * 10; // пересчет измерения в вольты
 if (u_in >= 3.5) 
 {u_inR = u_in * 1.128;}
 if (u_in >= 1.0 && u_in < 3.5)
 {u_inR = u_in * 1.27;} 
 if (u_in < 1.0)
 {u_inR = 0.0;} //-------------------------------------------конец измерения и калибровки
 Ut = u_inR * 10;
 Des = Ut / 100 % 10;
 Ed = Ut / 10 % 10;
 Dol = Ut % 10;
 }
if (millis() - timer1 >= 6) { //переключение индикаторов с периодичностью 25 раз в секунду + начало защиты от пропуска шага
timer1 = millis();
SwitchDIG();
}
}

void tester()
{
if (C ==1) {GREENLEDON; DPOFF; C = 2;} //флаг нажатия

if (millis() - timer3 >= PERIOD3) {                      // измерение напряжения для решения о зажигании красного светодиода и подачи звукового сигнала
 timer3 = millis();
 u = analogRead(A7); // измерение 
 u_in = (u * 5.0) / 1023 * 10; // пересчет измерения в вольты
 if (u_in > 11.0)
    {REDLEDON; tone(15, 1000);}
 else {REDLEDOFF; noTone(15);}
} //---------------------------------------------

if (millis() - timer5 >= PERIOD5) { // измерение напряжения для решения о зажигании зеленого светодиода и подачи звукового сигнала
timer5 = millis();
u2 = analogRead(A6); // измерение
u_in2 = (u2 * 5.0) / 1023; // пересчет измерения в вольты
if (u_in2 <=3.9)
{tone(15, 300);}
// else {noTone(15);}
} //-----------------------------------------------
if (millis() - timer4 >= PERIOD4) { //отображение надписи TST на индикаторе (динамическая индикация)
timer4 = millis();
PrintTst();
}
}

void generator()
{
if (C == 2) {GREENLEDOFF; C=3;}
if (millis() - timer6 >= PERIOD6) { //отображение надписи TST на индикаторе (динамическая индикация)
timer6 = millis();
PrintGen();
// tone(5, 1000);
//delay(80);
// noTone(5);
//delay(80);
}
}

void chastotomer()
{
if (C == 3) {REDLEDON; C=0; I=1;}
if (H == 0)
{u = analogRead(A7);
u_in = (u * 5.0) / 1023 * 10; // пересчет измерения в вольты
if (u_in >= 1.6) {G++; H=1;}}
if (H == 1)
{u = analogRead(A7);
u_in = (u * 5.0) / 1023 * 10; // пересчет измерения в вольты
if (u_in < 1.6) {H=0;}}
if (millis() - timer8 >= PERIOD8) { // измерение напряжения для решения о засчёте очередного герца
timer8 = millis();
Des = G / 100 % 10;
Ed = G / 10 % 10;
Dol = G % 10;
G = 0;}
if (millis() - timer1 >= 6) { //переключение индикаторов с периодичностью 25 раз в секунду + начало защиты от пропуска шага
timer1 = millis();
SwitchDIG();
}
}

//void yield()
//{
//if (millis() - timer6 >= PERIOD6) { //отображение надписи TST на индикаторе (динамическая индикация)
// timer6 = millis();
// PrintGen();
//}
//}

void loop() {

switch(A) {
case 0: voltmeter(); break; //----------------------------------режим по умолчанию-ВОЛЬТМЕТР------------
case 1: tester(); break; //-----------------------------------1-е нажатие кнопки-ТЕСТЕР--------------
case 2: generator(); break; //----------------------------------2-е нажатие кнопки-ГЕНЕРАТОР-------------
case 3: chastotomer(); break; //---------------------------------3-e нажатие кнопки-ЧАСТОТОМЕР-----------

}
} //--------------------------END-----------------------------

Это вы сами писали? Написано, скорее всего, живым человеком, а выглядит как FLProg.

Откройте для себя функции с парметрами - сможете весь этот ужас с 95 по 230 строку запихнуть примерно в 30 строк

По поводу вопроса по кнопке.
Вот эту переменную тоже надо бы описать как volatile, раз оно в прерывании:

И вот тут непонятно

PCINT прерывания ведь не поддерживают FALLING? или это какая-то библиотека особая, про которую Влад писал?

Если порт D через регистр, то почему пины 15-21 через pinMode() ?

Похоже что все надергано из разных мест…

Скорее всего эта.GitHub - NicoHood/PinChangeInterrupt: A simple & compact PinChangeInterrupt library for Arduino

Разумеется, сам.

Возможно. Но ведь это тема для новичков, разве нет?

Насколько мне известно, volatile должна обозначаться переменная, изменение которой в преывании влияет на ход остального скетча. Тут же millis_prev не выходит за пределы прерывания, поэтому обозначать её как volatile ни к чему. Разве не так?

Я переназначил прерывание на пин А0 с помощью библиотеки PinChangeInterrupt.h, в описании которой на ГитХабе указано, что есть три режима: RISING, CHANGE и FALLING. Все три режима работают корректно, проверял, поэтому да, это особая библиотека, получается.

Порты D через регистр я назначил, так как все порты D моего микроконтроллера работают на выход, так короче. А порты В и С не все на выход, там по разному.
Текст скетча не надёрган, а написан мной. Да, некоторые моменты сделаны как мне удобно. Но разве описанные вами моменты как-то влияют на работу кнопки? Могу, кстати, скинуть схему, чтобы было более понятно, что к чему (она, правда, от руки нарисована, но там всё просто).

Именно.

Именно поэтому я вам и посоветовал, как это написать красивее и короче.

Не обижайтесь, но сейчас у вас код выглядит так, будто он вышел из автоматического генератора кода - огромное количество коротких ничего не значащих переменных, кучи дублирующих функций.
В таком коде, кроме того что он “некрасив”, еще и очень сложно искать ошибки.

1 лайк

Спасибо, я этот момент обязательно учту. Но в будущем. Сейчас же я хочу разобраться с кнопкой. Я сломал всю голову. В голову лезет мысль, что порт А0 МК как-то подгорел слегка, что-ли. Но мини-скетч, который я описал вначале, работает, значит микроконтроллер способен отслеживать сигналы на этом порте (А0). В общем, я в растерянности. Готов уже символически отблагодарить человека, который мне поможет.

Сорри, беглым взглядом грубых ошибок не вижу.

Но разбираться в таких смысловых конструкциях - это жесть, здесь можно в упор смотреть на проблему и не увидеть

1 лайк

Я не обижаюсь. Хорошо. Приведу ещё один скетч, который МК никак не отрабатывает , хотя там всё проще некуда:

#include <TroykaButton.h>
TroykaButton button(14);
byte A=0;
void setup() {
  // put your setup code here, to run once:
 pinMode(6, OUTPUT);
 button.begin();
 
}

void loop() {
   button.read();
   if (button.justPressed()) 
   {A++; 
    if (A > 1) {A=0;}    
    if (A==1) {digitalWrite(6, LOW);}
    if (A==0) {digitalWrite(6, HIGH);}
   }
}

На пин 6 повешан светодиод. При нажатии кнопки согласно этому скетчу светодиод должен то загораться, то гаснуть. Но светодиод не загорается. Хотя, что тут может быть не так?
Та же беда с библиотекой GyverButton.
Хотя изначально всё работало как часы до того самого сбоя при загрузке скетча.

всякий раз когда вы работаете с библиотекой - все что угодно может быть не так. Всегда заглядывайте в код. что там авторы напихали.
Особенно с таким автором как Гайвер.

Уж для кнопок то использовать чужую либу смысла нет. Напишите сами, примеров в инете полно.
Зато будете четко уверены, что все ошибки - ваши, а не гайвера.

Так может дело в кнопке?

Сначала всё работало. Потом сбой при загрузке скетча - и всё пошло наперекосяк. Я пытался нагуглить информацию, может ли при неудачной загрузке скетча изпортить МК - ничего не нашёл.