Автоматика для УМЗЧ, первые проблемы

Решил собрать автоматику для УМЗЧ на Arduino Nano. Для начала: имеем две кнопки, подключены к цифровым входам со встроенной подтяжкой. Одна кнопка последовательно переключает три источника сигнала (подавая логическую 1 на один из трех цифровых выходов). Вторая кнопка включает и отключает(при повторном нажатии) цепь тонкомпенсации (подавая и снимая логическую 1 на еще один цифровой выход). Выбранный вход и включение/отключение тонкомпенсации запоминаются в EEPROM. Еще три выхода - это пока задел на будущее. Наляпал (иначе не скажу) такой скетч

#include <EEPROM.h>

const byte Loud_cell = 0; // место хранения положения тонкомпенсации
const byte Sel_cell = 1; // место хранения активного входа

const byte rel1 = 0;//какое реле к какому контакту потключено
const byte rel2 = 1;
const byte rel3 = 2;
const byte rel4 = 3;// тонкомпенсация
const byte rel5 = 4;// вход1
const byte rel6 = 5;// вход2
const byte rel7 = 6;// вход3
const byte button1=8;// button1 (тонкомпенсация) к ноге8  подключена 
const byte button2=9;// button2 (вход)к ноге9  подключена 
byte Loud;//значение положения реле тонкомпенсации
byte Sel;// значение активного входа
bool button1State;
bool button2State;
bool rel4State;// текущее положение реле 4 тонкомпенсации
bool lastButton1State = HIGH; // пердыдущее положение Button1
bool lastButton2State = HIGH; // пердыдущее положение Button2
unsigned long lastDebounce1Time = 0;  // время нажатия Button1
unsigned long lastDebounce2Time = 0;  // время нажатия Button2
unsigned long debounceDelay = 50;    // время фильтрации дребезга

void setup()
{
 Loud = EEPROM.read(Loud_cell);//читаем EEPROM по адресу Loud_cell
if (Loud>1)// нужен для первого запуска (если считано некорректное значение) 
{
  Loud = 0;
  EEPROM.write(Loud_cell, Loud);
}
 
 Sel = EEPROM.read(Sel_cell);//читаем EEPROM по адресу Sel_cell
if (Sel<1 or Sel>3)// нужен для первого запуска (если считано некорректное значение)  
{
  Sel = 1;
  EEPROM.write(Sel_cell, Sel);
}
pinMode(rel1, OUTPUT);//контролер настроен на выход данные ноги MK
pinMode(rel2, OUTPUT);
pinMode(rel3, OUTPUT);
pinMode(rel4, OUTPUT);
pinMode(rel5, OUTPUT);
pinMode(rel6, OUTPUT);
pinMode(rel7, OUTPUT);

pinMode(button1, INPUT_PULLUP);// контролер настоен на вход данные ноги и подтяжка к (+)
pinMode(button2, INPUT_PULLUP);
// включаем или отключаем реле тонкомпенсации по памяти
      if (Loud == 1)  {rel4State = HIGH;};
      if (Loud == 0)  {rel4State = LOW;};
      digitalWrite(rel4, rel4State);
                           
// включаем вход по памяти
 switch (Sel) {
    case 1:
      digitalWrite(rel6, LOW);//выполняется, когда Sel равно 1
      digitalWrite(rel7, LOW);
      digitalWrite(rel5, HIGH);
      break;
    case 2:
      digitalWrite(rel5, LOW);//выполняется, когда Sel равно 2
      digitalWrite(rel7, LOW);
      digitalWrite(rel6, HIGH);
      break;
    case 3:
      digitalWrite(rel5, LOW);//выполняется, когда Sel равно 3
      digitalWrite(rel6, LOW);
      digitalWrite(rel7, HIGH);
      break;
  }
// подаем питание на блоки усилителя
 delay(2000);//(пауза в миллисекундах)
 digitalWrite(rel1, HIGH);//включить rel1 
 digitalWrite(rel2, HIGH);//включить rel2 
 digitalWrite(rel3, HIGH);//включить rel3 
}

void loop()  //на кнопку тонкомпенсации не реагирует адекватно
{
  // считываем button1 в локальную переменную:
  bool reading1 = digitalRead(button1);
  
  // если кнопка похожа на нажатую
  if (reading1 != lastButton1State) {
    // сбрасывем таймер антидребезга
    lastDebounce1Time = millis();
  }
   

  if ((millis() - lastDebounce1Time) > debounceDelay) {
    // если кнопка нажата дольше времени фильтрации, значит реально нажата

    // если состояние кнопки изменилось
    if (reading1 != button1State) {
      button1State = reading1;

      // при измененном состоянии кнопки меняем значение активного входа Sel 
      if (button1State == LOW) {
                  Sel = Sel+1;}
      if (Sel==4) {Sel=1;}  // круговое изменение значения sel в интервале 1..3
      
    }
  }
   // считываем button2 в локальную переменную:
  bool reading2 = digitalRead(button2);
   // если кнопка похожа на нажатую
   if (reading2 != lastButton2State) {
    // сбрасывем таймер антидребезга
    lastDebounce2Time = millis();
  }
  if ((millis() - lastDebounce2Time) > debounceDelay) {
    // если кнопка нажата дольше времени фильтрации, значит реально нажата

    // если состояние кнопки изменилось
    if (reading2 != button2State) {
      button2State = reading2;

      // при измененном состоянии кнопки меняем значение переменной реле тонкомпенсации rel4State
      if (button2State == LOW) {
         rel4State = !rel4State;
                }
    }
  }
  // переключаем входы согласно положению sel :
  switch (Sel) {
    case 1:
      digitalWrite(rel6, LOW);//выполняется, когда Sel равно 1
      digitalWrite(rel7, LOW);
      digitalWrite(rel5, HIGH);
      break;
    case 2:
      digitalWrite(rel5, LOW);//выполняется, когда Sel равно 2
      digitalWrite(rel7, LOW);
      digitalWrite(rel6, HIGH);
      break;
    case 3:
      digitalWrite(rel5, LOW);//выполняется, когда Sel равно 3
      digitalWrite(rel6, LOW);
      digitalWrite(rel7, HIGH);
      break;
      }

  //включаем или отключаем тонкомпенсацию по переменной rel4State
  digitalWrite(rel4, rel4State);
  // сохраняем положение кнопок для следующего цикла опроса
  lastButton1State = reading1;
  lastButton2State = reading2;
  // записываем состояние активного входа и тонкомпесации в EEPROM
  if (rel4State=HIGH) (Loud = 1); //
  if (rel4State=LOW)(Loud = 0); //
  
  if (EEPROM.read(Loud_cell) != Loud) {EEPROM.write(Loud_cell, Loud);};//если Loud отличается от записанного, записывем новое положение Loud в память.
 
  if (EEPROM.read(Sel_cell) != Sel) {EEPROM.write(Sel_cell, Sel);};//если Sel отличается от записанного, записывем новое положение Sel в память.
    
}

Часть кода моего сочинения. Фильтрация дребезга из примера к IDE 1.8.5, только переписана под кнопки, замыкающие вход на землю и с использование внутренних резисторов подтяжки к питанию. Плюс комментарии переписал.
И есть особенность: переключение входов работает так как надо, а тонкомпесация не работает (на макете светодиод коротко моргает при нажатии кнопки и все).
Причем если закомментировать эту часть кода (строки 152-153), вот так

  // записываем состояние активного входа и тонкомпесации в EEPROM
  //if (rel4State=HIGH) (Loud = 1); //
  //if (rel4State=LOW)(Loud = 0); //

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

что-то больна многа букав для такой задачи

1 лайк

… + повторяющийся код нужно выносить в функции…

что-то подобное было тут в старом форуме
https://arduino.ru/forum/pesochnitsa-razdel-dlya-novichkov/pereklyuchenie-rezhimov-s-programmirovaniem-ochen-plokho-pod#comment-599789

Не увидел здесь я того, что стоит выносить в функции, тем боле на данном этапе.

Примерно того же результата я уже достиг, если указанные в первом сообщении строки закомментировать. Просто мне хочется чтобы еще и сохранялось включенное положение.

Лучше не трогайте пины 0 и 1 на нано.

Участки кода начиная с 57 и 128 строк абсолютно одинаковы, не говоря уже о том, что сам оператор switch - это чаще всего признак того, что автор не смог написать более структурированный код.

Участки кода начиная с 57 и 128 строк абсолютно одинаковы, не говоря уже о том, что сам оператор switch - это чаще всего признак того, что автор не смог написать более структурированный код.

Можно и вынести этот код в функцию, но проблему это не решит. Да и как-то хочется чтобы сначала заработало, а потом уже допиливать до идеала, (который для некоторых заключается в написании всего кода на ассемблере, но мне такого точно не надо…)

Если тебе «нудные советы» не нужны - зачем пришел на форум?

Подход неверный.
В беспорядочно написанном коде практически нереально искать ошибки.
Поэтому, чтобы сделать код пригодным для отладки, делают рефакторинг, основная задача которого сделать код легко читаемым.
Так что на практике все наоборот: сначала делаем код читаемым, и только потом добиваемся от него работоспособности.

И еще: в правильно написанном коде должны быть вменяемые комментарии.

 switch (Sel) {
    case 1:
      digitalWrite(rel6, LOW);//выполняется, когда Sel равно 1
      digitalWrite(rel7, LOW);
      digitalWrite(rel5, HIGH);
      break;
    case 2:

Вот здесь в третьей строке комментарии явно невменяемые: какой смысл повторять, что и так написано в коде. Что мы делаем, и так видно, нужно написать, зачем мы это делаем. Например, “подаем питание на правый двигатель”.
Впрочем, у Вас есть и такие: //включаем или отключаем тонкомпенсацию по переменной rel4State, но только такими должны быть все.

1 лайк

Согласен. Я вообще создаю некий “каркас” с пустыми строчками и пишу по-человечески что надо делать, типа так:

А потом уже намного проще переводить это в код.

Вы пришли сюда поспорить?

Так не работает. Вернее, работает, но с кратно большим трахом усилиями, чем могло бы быть. Вы это как “качалку” рассматриваете?

Впрочем, если Вам всего этого

то, удачи Вам разобраться самостоятельно!

Ну вот и хочешь тут людЯм помочь… Огрызаются, однако.)

1 лайк
#include <EEPROM.h>       //подключаем библиотеку для работы с EEPROM

const byte Loud_cell = 0; // место хранения положения тонкомпенсации
const byte Sel_cell = 1;  // место хранения значения активного входа

//const byte rel1 = 0;//какое реле к какому контакту потключено
//const byte rel2 = 1;
const byte rel3 = 2;
const byte rel4 = 3;
const byte rel5 = 4;
const byte rel6 = 5;
const byte rel7 = 6;
const byte button1=8;// button1 (тонкомпенсация) к ноге8  подключена 
const byte button2=9;// button2 (вход)к ноге9  подключена 
byte Loud;//значение положения реле тонкомпенсации
byte Sel;// значение активного входа
bool button1State;
bool button2State;
//bool rel4State;// текущее положение реле 4 тонкомпенсации
bool lastButton1State = HIGH; // пердыдущее положение Button1
bool lastButton2State = HIGH; // пердыдущее положение Button2
unsigned long lastDebounce1Time = 0;  // время нажатия Button1
unsigned long lastDebounce2Time = 0;  // время нажатия Button2
unsigned long debounceDelay = 50;     // время фильтрации дребезга

void InputSelect (byte In_Sel){// функция переключает входы согласно значению In_Sel :
    switch (In_Sel) {
    case 1:                   //при In_Sel=1
      digitalWrite(rel6, LOW);//выключаем rel6,rel7
      digitalWrite(rel7, LOW);
      digitalWrite(rel5, HIGH);//включаем rel4
      break;
    case 2:                   //при In_Sel=2
      digitalWrite(rel5, LOW);//выключаем rel5,rel7
      digitalWrite(rel7, LOW);
      digitalWrite(rel6, HIGH);//включаем rel4
      break;
    case 3:                   //при In_Sel=3
      digitalWrite(rel5, LOW);//выключаем rel5,rel6
      digitalWrite(rel6, LOW);
      digitalWrite(rel7, HIGH);//включаем rel4
      break;
                  }
                                }

void LoudSelect (byte Loud_Sel){                  // функция включение и отключение тонкомпенсации по значению Loud_Sel
     if (Loud_Sel == 1)  digitalWrite(rel4, HIGH);// если значение Loud_Sel=1 включаем тонкомпенсацию
     if (Loud_Sel == 0)  digitalWrite(rel4, LOW); // если значение Loud_Sel=0 выключаем тонкомпенсацию            
                               }

void setup() //инициализация
{
 Loud = EEPROM.read(Loud_cell);//читаем EEPROM по адресу Loud_cell
 if (Loud>1)// нужен для первого запуска (если считано некорректное значение) 
          {
   Loud = 0;
   EEPROM.write(Loud_cell, Loud);// то записываем минимальное корректное 
          }
 
 Sel = EEPROM.read(Sel_cell);//читаем EEPROM по адресу Sel_cell
 if (Sel<1 or Sel>3)// нужен для первого запуска (если считано некорректное значение)  
                  {
  Sel = 1;
  EEPROM.write(Sel_cell, Sel);// то записываем минимальное корректное
                  }
//настройка выводов MK на выход
 //pinMode(rel1, OUTPUT);  
 //pinMode(rel2, OUTPUT);
 pinMode(rel3, OUTPUT);
 pinMode(rel4, OUTPUT);
 pinMode(rel5, OUTPUT);
 pinMode(rel6, OUTPUT);
 pinMode(rel7, OUTPUT);
//настройка выводов МК на вход и подтяжка к (+)
 pinMode(button1, INPUT_PULLUP);
 pinMode(button2, INPUT_PULLUP);

  // включаем или отключаем реле тонкомпенсации по памяти
     LoudSelect (Loud);
  // включаем вход по памяти
     InputSelect (Sel); 
// подаем питание на блоки усилителя
// delay(1000);//(пауза в миллисекундах)
//digitalWrite(rel1, HIGH);//включить rel1 
// delay(1000);//(пауза в миллисекундах)
// digitalWrite(rel2, HIGH);//включить rel2 
 delay(1000);//(пауза в миллисекундах)
 digitalWrite(rel3, HIGH);//включить rel3 
}//конец инициализации

void loop()  //рабочий цикл
{
  
  bool reading1 = digitalRead(button1); // считываем button1 в локальную переменную:
  if (reading1 != lastButton1State) {   // если кнопка похожа на нажатую
  lastDebounce1Time = millis();         // сбрасывем таймер антидребезга
                                    }
  if ((millis() - lastDebounce1Time) > debounceDelay) {// если кнопка нажата дольше времени фильтрации, значит реально нажата
  if (reading1 != button1State) {                      // если состояние кнопки изменилось
      button1State = reading1;
      if (button1State == LOW) {Sel++;}  // при измененном состоянии кнопки меняем значение активного входа Sel 
      if (Sel==4) {Sel=1;}               // круговое изменение значения sel в интервале 1..3
                                }
                                                      }
   
  bool reading2 = digitalRead(button2);// считываем button2 в локальную переменную:
  if (reading2 != lastButton2State) {// если кнопка похожа на нажатую
  lastDebounce2Time = millis();// сбрасывем таймер антидребезга
                                    }
  if ((millis() - lastDebounce2Time) > debounceDelay) {// если кнопка нажата дольше времени фильтрации, значит реально нажата
  if (reading2 != button2State) {                      // если состояние кнопки изменилось
      button2State = reading2;
      if (button2State == LOW) {Loud++;}// при измененном состоянии кнопки меняем значение переменной реле тонкомпенсации Loud
      if (Loud==2) {Loud=0;}//круговое изменение значения Loud в интервале 0..1
  
                                }
                                                     }
  // сохраняем положение кнопок для следующего цикла опроса 
  lastButton1State = reading1;
  lastButton2State = reading2;
  
  // переключаем входы согласно положению Sel :
  InputSelect(Sel); 

  //включаем или отключаем тонкомпенсацию по переменной Loud
  LoudSelect(Loud);
  
  // записываем состояние активного входа и тонкомпесации в EEPROM
  if (EEPROM.read(Loud_cell) != Loud) {EEPROM.write(Loud_cell, Loud);};//если Loud отличается от записанного, записывем новое положение Loud в память.
  if (EEPROM.read(Sel_cell) != Sel) {EEPROM.write(Sel_cell, Sel);};//если Sel отличается от записанного, записывем новое положение Sel в память.
    
}//конец рабочего цикла

Заработало. Почему не работало? сам не понял! Только чуть поправил способ сохранения значения переменной, ответственной за включение тонкомпенсации.
Ну и чуть причесал код. Хотя тут, как говориться, аппетит приходит во время еды. А вот как избавиться от оператора Switch я пока не понял.

За дельными советами.

Так в том то и дело, что для тебя они «нудные», а по факту «дельные» (я бы даже сказал - «правильные»).

Ни одного реально дельного я тут пока не увидел(ссылка на код сосвсем без комментариев в оном, и с Delay в цикле, пусть и мне бы оно не повредило в этой самоделке, но все же Delay - моветон,еще бы GO TO приделать и вообще красота(сарказм если что); просьбы писать более подробные комментарии, ну вроде и дельно, но к поиску ошибки меня нисколько не привело) сначала заработало, а потом уже причесывал. Во второй раз если возьму за что-то подобное, то возможно и начну по-другому все писать. Еще здорово мешает, то что раньше изучал(на очень начальном уровне) Паскаль и Дельфи, а тут больше на Си похож язык.

Другим не мешает. Только поначалу непривычно

Это и есть С++

Удачи в творчестве. Х#ле тут еще скажешь? :joy:

1 лайк