Возможность очистить код?

Спокойной ночи! Основываясь на материалах, которые я получаю немного здесь и там, придумал программу для Arduino Audio Selector со сдвиговыми регистрами и некоторыми функциями. Работает как положено, не хватает только подключения релейных плат, но это на будущее. Поскольку у меня есть несколько устройств, вместо того, чтобы записывать все, могу ли я изменить, например, строку, а затем отобразить эту строку на дисплее?

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

Селектор Arduino 4x20

, 👍0

Обсуждение

Пожалуйста, объясните, что вы имеете в виду, когда говорите: «Я могу изменить, например, строку, а затем показать эту строку на дисплее?». О какой линии вы говорите?, @VE7JRO

Извините, забыл упомянуть ... я думал примерно так: line1 = mp3-плеер, cd 1 = sony, cd2 = Pioneer, и при записи исходников нужно только изменить в начале вместо того, чтобы прокручивать весь код . 73-й CT1JQJ, @Nuno Brandão

В традиционном C они используют #define / #ifdef. В С++ есть больше возможностей, но интерпретация/угадывание фона вашего вопроса уже может помочь., @DataFiddler


1 ответ


Лучший ответ:

2

Я вижу много "почти" повторений, например:

  if (RelaySourceDigi == 7) {
    shifter.setPin(16, LOW);
    shifter.setPin(17, LOW);
    shifter.setPin(18, LOW);
    shifter.setPin(19, LOW);
    shifter.setPin(20, LOW);
    shifter.setPin(21, LOW);
    shifter.setPin(22, HIGH);
    shifter.setPin(23, LOW);
    shifter.write();
    lcd.setCursor(0, 2);
    lcd.write(8);
    lcd.setCursor(2, 2);
    lcd.print("Coaxial 3");
  }

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

Ниже я изменил всю программу. Примечание. Я не проверял наличие ошибок во время выполнения, и вполне возможно, что я сделал некоторые ошибки копирования/вставки, но это даст вам подсказку, что вы можете изменить. Как видите, программа радикально укорочена (и более удобна в сопровождении).

Вам нужно сделать следующее:

  • Проверяйте каждое изменение
  • Проверить наличие ошибок копирования/вставки
  • Почитайте немного об указателях (например, о конструкциях &RelaySource и *t)
  • Кроме того, я настоятельно рекомендую не использовать так много констант, а использовать enum для обозначения значения для каждого режима, который у вас есть. Таким образом, вместо case 1 вы можете написать case TAPE_1.
  • Разделите цикл на более мелкие функции (например, по одной функции на режим).
  • Я не устанавливал ваши библиотеки, но использовал, например, #include "LiquidCrystal_I2C.h" и заглушил все функции (это означает, что я могу вызывать их, но они ничего не делают, только для проверки ошибок компилятора в основной программе).
  • Также вместо Aux используйте логическое значение (true, false).
  • Видите ли, я использую много конструкций (state - 1). Обычно принято начинать считать с 0, а не с 1, это облегчит вам жизнь. Только при отображении значения для пользователя добавляйте +1. Ниже программы.

    //Библиотеки
    #include "LCD.h"
    #include "LiquidCrystal_I2C.h"
    #include "Shifter.h"
    
    #define SER_Pin 8 //SER_IN 14 на 74HC595
    #define RCLK_Pin 9 //L_CLOCK 12 на 74HC595
    #define SRCLK_Pin 10 //CLOCK 11 на 74HC595
    #define NUM_REGISTERS 3 //сколько регистров в цепочке
    //инициализируем шифтер с помощью библиотеки Shifter
    Shifter shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS);
    
    LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Устанавливаем I2C-адрес ЖК-дисплея
    
    const int ButtonPinUp = 2;
    int ButtonPinUpState = 0;
    const int ButtonPinDn = 3;
    int ButtonPinDnState = 0;
    const int MuteButtonPin = 5;
    int MuteButtonPinState = 0;
    const int AuxButtonPin = 4;
    int AuxButtonPinState = 0;
    const int fbutton = 6;
    int RelaySource = 1;
    int RelaySourceDigi = 1;
    int RelayRec = 1;
    int RecDigi = 1;
    int Mute = 0;
    int Mode = 0;
    int Aux = 1;
    int state = 0;
    int old = 0;
    int ButtonPoll = 0;
    
    
    byte opt[8] = {
      0b00000,
      0b01110,
      0b11011,
      0b10001,
      0b10001,
      0b10001,
      0b11111,
      0b00000
    };
    
    byte coax[8] = {
      0b00100,
      0b01110,
      0b11111,
      0b10001,
      0b10001,
      0b01110,
      0b00100,
      0b00100
    };
    
    byte mut[8] = {
      0b00001,
      0b00011,
      0b00111,
      0b11111,
      0b11111,
      0b00111,
      0b00011,
      0b00001
    };
    
    
    byte outp[8] = {
      B00000,
      B00100,
      B00110,
      B11111,
      B11111,
      B00110,
      B00100,
      B00000
    };
    
    byte upp[8] = {
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111,
      0b11111
    };
    
    byte inpp[8] {
      0b10000,
      0b10000,
      0b10100,
      0b10110,
      0b11111,
      0b00110,
      0b00100,
      0b00000
    };
    
    
    byte ann[8] {
    
      0b11111,
      0b10001,
      0b10101,
      0b10101,
      0b10001,
      0b10101,
      0b10101,
      0b11111
    };
    
    
    byte dnn[8] = {
      0b11111,
      0b10011,
      0b10101,
      0b10101,
      0b10101,
      0b10101,
      0b10011,
      0b11111
    };
    
    byte too[8] = {
      0b00000,
      0b00100,
      0b00110,
      0b11111,
      0b00110,
      0b00100,
      0b00000,
      0b00000
    };
    
    void printAtCursor(int a, int b, const char* c)
    {
      lcd.setCursor(a, b);
      lcd.print(c);
    }
    
    void setup() {
      lcd.begin(20, 4);
      lcd.backlight();
    
      byte* list[] = {outp, coax, mut, opt, upp, inpp, ann, dnn, too };
      for (int n = 0; n < 9; n++)
      {
        lcd.createChar(n + 1, list[n]);
      }
    
      pinMode(fbutton, INPUT);
      pinMode(ButtonPinUp, INPUT);
      pinMode(MuteButtonPin, INPUT);
      pinMode(ButtonPinDn, INPUT);
      pinMode(AuxButtonPin, INPUT);
    
      for (int n = 11; n < 14; n++)
      {
        pinMode(n, OUTPUT);
      }
    
      printAtCursor(3, 0, "Digital/Analog");
      printAtCursor(3, 1, "Audio Selector");
      printAtCursor(4, 2, "Built-In DAC");
      printAtCursor(2, 3, "V2.0f (23052020)");
      delay(4000);
      lcd.clear();
    }
    
    
    void setPin(int first, int last, int pin)
    {
      for (int n = first; n < last + 1; n++)
      {
        shifter.setPin(n, pin == n ? HIGH : LOW);
      }
    
      shifter.write();
    }
    
    
    void setLines(int a, int b, const char* t, int x = -1, const char* u = "")
    {
        lcd.setCursor(0, a);
        lcd.write(b);
        lcd.setCursor(2, a);
        lcd.print(t);
        if (x != -1)
        {
          lcd.write(x);
          lcd.print(u);
        }
    }
    
    void loop() 
    {
      // shifter.clear(); // устанавливаем все контакты в цепочке регистров сдвига в LOW
      shifter.write(); //отправляем изменения в цепочку и отображаем их
      //проверка состояний кнопок
      ButtonPinUpState = digitalRead(ButtonPinUp);
      ButtonPinDnState = digitalRead(ButtonPinDn);
      MuteButtonPinState = digitalRead(MuteButtonPin);
      AuxButtonPinState = digitalRead(AuxButtonPin);
      ButtonPoll = digitalRead(fbutton);
    
      if (AuxButtonPinState == HIGH && RelaySource == 1 && state == 1) {
        lcd.clear();
        Aux           = ~Aux;
        digitalWrite(13, Aux == 0 ? LOW : HIGH);
      }
    
      if (ButtonPoll == HIGH) {
        state = old + 1;
      }
    
      lcd.clear(); // Происходит во всех случаях
      switch (state) {
        case 1: // Провал
        case 2: // Провал
        case 3: // Провал
        case 4:
          lcd.setCursor(1, state - 1);
          lcd.write(5);
          old = state;
          break;
    
        default:
          old = 0;
          break;
      }
    
      // Предположим, что состояние = 1..4
      if (ButtonPinUpState == HIGH)
      {
        lcd.clear();
        int* t = NULL;
        int maxValue = -1;
    
        switch (state)
        {
          case 1: t = &RelaySource;     maxValue = 8; break;
          case 2: t = &RelayRec;        maxValue = 5; break;
          case 3: t = &RelaySourceDigi; maxValue = 8; break;
          case 4: t = &RecDigi;         maxValue = 4; break;
          default: break;
        }
    
        *t = min(1, max(maxValue, *t + (ButtonPinUpState == HIGH ? 1 : 0) + (ButtonPinDnState == HIGH ? -1 : 0)));
      }
    
      if (MuteButtonPinState == HIGH) {
        lcd.clear();
        Mute = (Mute == 0 ? 1 : 0);
        digitalWrite(12, Mute == 0 ? HIGH : LOW);
      }
    
      // Источник реле
      setPin(0, 7, RelaySource - 1);
      if (RelaySource == 1 && Aux == 0)
      {
        setLines(0, 7, "D", 9, "A:");
      }
      else
      {
        const char* rs1[] = { "Line 1", "Line 2", "CD 1", "CD 2", "Tape 1", "Tape 2/DCC", "Tape 3/DAT", "MD", "MD" };
        setLines(0, 7, rs1[RelaySource - 1]);
      }
    
      if (RelaySource == 8)
      {
        shifter.setPin(0, LOW); // устанавливаем контакт 1 в цепочке (второй контакт) ВЫСОКИМ
      }
    
      // RelayRec
      int         rr1[] = { 8      , -1   , 9       , 10      , 11       };
      const char* rr2[] = {"Source", "OFF", "Tape 1", "Tape 2", "Tape 3" };
      const int   rr3[] = { -1     , -1   , 9       , 9       , 9        };
      const char* rr4[] = { ""     , ""   , "2,3"   , "1,3"   , "1,2"    };  
    
      setPin(8, 11, rr1[RelayRec - 1]);
      setLines(1, 6, rr2[RelayRec - 1], rr3[RelayRec - 1], rr4[RelayRec - 1]);
    
      // RelaySourceDigi
      setPin(16, 23, 17 - RelaySourceDigi);
      if (RelaySource == 1 && Aux == 0) 
      {
        lcd.setCursor(7, 0);
        const char* t[] = { "Optical 1", "Optical 2", "Optical 3", "Optical 4", "Coaxial 1", "Coaxial 2", "Coaxial 3", "Coaxial 4" };
        lcd.print(t[RelaySource - 1]);
      }
    
      const char* t1[] = { "Sony 5-CD", "Sony MD[", "Optical 3", "Optical 4", "Philips CD-R [", "Coaxial 2", "Coaxial 3", "Coaxial 4" };
      const int   t2[] = { 4          , 4         , -1         , -1         , 2               , -1        , -1         , -1          };
      const char* t3[] = { "]"        , "]"       , ""         , ""         , "]"             , ""        , ""         , ""          };
      setLines(2, 8, t1[RelaySourceDigi - 1], t2[RelaySourceDigi - 1], t3[RelaySourceDigi - 2]);
    
      // RecDigi
      const char* t[] = { "Optical Out1", "Optical Out 2", "Coaxial Out 1", "Coaxial Out2" };
      setPin(12, 15, 11 + RecDigi);
      setLines(3, 6, t[RecDigi - 1]);
    
      delay(150);
    }
    

Обновить

Я хотел сам увидеть, как полностью очистить его, поэтому я попытался ниже.

Все еще проверяйте наличие проблем с копированием/вставкой, так как я не выполнял скетч (но он компилируется без предупреждений).

Исходный скетч: 2746 байт (8%) места для хранения программы, 142 байта (6%) динамической памяти Схема ниже: 1546 байт (4%) для хранения программ, 40 байт (2%) динамической памяти.

Вывод:

  • Используется на 25 % меньше места для хранения программ
  • Используется на 67 % меньше динамической памяти
  • Меньше строк кода
  • Удобство чтения
  • Удобство обслуживания
  • Нет (или меньше) дублирования кода
  • Меньшая сложность функции
  • Меньше операторов (добавлено больше к инициализации)

Код:

//Библиотеки
#include "LCD.h"
#include "LiquidCrystal_I2C.h"
#include "Shifter.h"

const uint8_t SER_Pin = 8; //SER_IN 14 на 74HC595
const uint8_t RCLK_Pin = 9; //L_CLOCK 12 на 74HC595
const uint8_t SRCLK_Pin = 10; // ЧАСЫ 11 на 74HC595
const uint8_t NUM_REGISTERS = 3; //сколько регистров в цепочке

Shifter _shifter(SER_Pin, RCLK_Pin, SRCLK_Pin, NUM_REGISTERS);
LiquidCrystal_I2C _lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Устанавливаем I2C-адрес ЖК-дисплея

enum EMode
{
  RELAY_SOURCE,
  RELAY_REC,
  RELAY_SOURCE_DIGI,
  REC_DIGI,
  LAST_MODE
};

static const uint8_t _buttonPinUp = 2;
bool _buttonPinUpState = false;
static const uint8_t _buttonPinDown = 3;
bool _buttonPinDownState = false;
static const uint8_t _muteButtonPin = 5;
bool _muteButtonPinState = false;
static const uint8_t _auxButtonPin = 4;
bool _auxButtonPinState = false;
static const uint8_t _forwardButton = 6;
uint8_t _relaySource = 0;
uint8_t _relaySourceDigi = 0;
uint8_t _relayRec = 0;
uint8_t _recDigi = 0;
bool _mute = false;
bool _aux = true;
EMode _mode = RELAY_SOURCE;
bool _buttonPoll = false;

static const byte OPT[8]  PROGMEM = {  0b00000,  0b01110,  0b11011,  0b10001,  0b10001,  0b10001,  0b11111,  0b00000 };
static const byte COAX[8] PROGMEM = {  0b00100,  0b01110,  0b11111,  0b10001,  0b10001,  0b01110,  0b00100,  0b00100 };
static const byte MUT[8]  PROGMEM = {  0b00001,  0b00011,  0b00111,  0b11111,  0b11111,  0b00111,  0b00011,  0b00001 };
static const byte OUTP[8] PROGMEM = {  B00000 ,  B00100 ,  B00110 ,  B11111 ,  B11111 ,  B00110 ,  B00100 ,  B00000  };
static const byte UPP[8]  PROGMEM = {  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111,  0b11111 };
static const byte INPP[8] PROGMEM = {  0b10000,  0b10000,  0b10100,  0b10110,  0b11111,  0b00110,  0b00100,  0b00000 };
static const byte ANN[8]  PROGMEM = {  0b11111,  0b10001,  0b10101,  0b10101,  0b10001,  0b10101,  0b10101,  0b11111 };
static const byte DNN[8]  PROGMEM = {  0b11111,  0b10011,  0b10101,  0b10101,  0b10101,  0b10101,  0b10011,  0b11111 };
static const byte TOO[8]  PROGMEM = {  0b00000,  0b00100,  0b00110,  0b11111,  0b00110,  0b00100,  0b00000,  0b00000 };

static const byte* const CHAR_LIST[] PROGMEM = {OUTP, COAX, MUT, OPT, UPP, INPP, ANN, DNN, TOO };
static const uint8_t PINS[] PROGMEM = { _forwardButton, _buttonPinUp, _muteButtonPin, _buttonPinDown, _auxButtonPin };

static uint8_t* const    MODE_VALUES[] PROGMEM = { &_relaySource, &_relayRec, &_relaySourceDigi, &_recDigi };
static const uint8_t     MAX_VALUES[] PROGMEM = { 7             , 4         , 7                , 3         };

static const char* const RELAY_SOURCES[] PROGMEM = { "Line 1", "Line 2", "CD 1", "CD 2", "Tape 1", "Tape 2/DCC", "Tape 3/DAT", "MD", "MD" };

static const char* const RELAY_SOURCE_DIGI_1[] PROGMEM = { "Sony 5-CD", "Sony MD[", "Optical 3", "Optical 4", "Philips CD-R [", "Coaxial 2", "Coaxial 3", "Coaxial 4" };
static const int         RELAY_SOURCE_DIGI_2[]         = { 4          , 4         , -1         , -1         , 2               , -1        , -1         , -1          };
static const char* const RELAY_SOURCE_DIGI_3[] PROGMEM = { "]"        , "]"       , ""         , ""         , "]"             , ""        , ""         , ""          };

static const int         RELAY_REC_1[] PROGMEM = { 8      , -1   , 9       , 10      , 11       };
static const char* const RELAY_REC_2[] PROGMEM = {"Source", "OFF", "Tape 1", "Tape 2", "Tape 3" };
static const int         RELAY_REC_3[] PROGMEM = { -1     , -1   , 9       , 9       , 9        };
static const char* const RELAY_REC_4[] PROGMEM = { ""     , ""   , "2,3"   , "1,3"   , "1,2"    };  

static const char* const DIGI_RELAY_SOURCES[] PROGMEM = { "Optical 1", "Optical 2", "Optical 3", "Optical 4", "Coaxial 1", "Coaxial 2", "Coaxial 3", "Coaxial 4" };


void printAtCursor(int a, int b, const char* c)
{
  _lcd.setCursor(a, b);
  _lcd.print(c);
}


void setup() 
{
  _lcd.begin(20, 4);
  _lcd.backlight();

  for (int n = 0; n < 9; n++)
  {
    _lcd.createChar(n + 1, (byte*) CHAR_LIST[n]);
  }

  for (int n = 0; n < sizeof(PINS) / sizeof(uint8_t); n++)
  {
    pinMode(PINS[n], INPUT);
  }

  for (int n = 11; n < 14; n++)
  {
    pinMode(n, OUTPUT);
  }

  printAtCursor(3, 0, "Digital/Analog");
  printAtCursor(3, 1, "Audio Selector");
  printAtCursor(4, 2, "Built-In DAC");
  printAtCursor(2, 3, "V2.0f (23052020)");
  delay(4000);
}


void setPin(int first, int last, int pin)
{
  for (int n = first; n < last + 1; n++)
  {
    _shifter.setPin(n, pin == n ? HIGH : LOW);
  }

  _shifter.write();
}


void setLines(int a, int b, const char* t, int x = -1, const char* u = "")
{
    _lcd.setCursor(0, a);
    _lcd.write(b);
    _lcd.setCursor(2, a);
    _lcd.print(t);

    if (x != -1)
    {
      _lcd.write(x);
      _lcd.print(u);
    }
}


void ResetShifter()
{
  // _shifter.clear(); // устанавливаем все контакты в цепочке регистров сдвига в LOW
  _shifter.write(); //отправляем изменения в цепочку и отображаем их
}


void ReadButtons()
{
  _buttonPinUpState = digitalRead(_buttonPinUp) == HIGH;
  _buttonPinDownState = digitalRead(_buttonPinDown) == HIGH;
  _muteButtonPinState = digitalRead(_muteButtonPin) == HIGH;
  _auxButtonPinState = digitalRead(_auxButtonPin) == HIGH;
  _buttonPoll = digitalRead(_forwardButton) == HIGH;
}


void HandleAuxButton()
{
  if (_auxButtonPinState && (_relaySource == 0) && (_mode == EMode::RELAY_SOURCE)) 
  {
    _aux = !_aux;
    digitalWrite(13, _aux ? HIGH : LOW);
  }
}


void HandlePollButton()
{
  if (_buttonPoll) 
  {
    _mode = (EMode) ((_mode + 1) % EMode::LAST_MODE);
  }
}


void StartLcd()
{
  _lcd.clear(); // Происходит во всех случаях
  _lcd.setCursor(1, (int) _mode);
  _lcd.write(5);
}


void HandleButtonPinUp()
{
  if (_buttonPinUpState)
  {
    static uint8_t* const modeValue = MODE_VALUES[_mode];
    static uint8_t maxValue = MAX_VALUES[_mode];
    *modeValue = min(0, max(maxValue, *modeValue + (_buttonPinUpState ? 1 : 0) + (_buttonPinDownState ? -1 : 0)));
  }
}


void HandleMuteButton()
{
  if (_muteButtonPinState) 
  {
    _mute = !_mute;
    digitalWrite(12, _mute ? HIGH : LOW);
  }
}


void ProcessRelaySource()
{
  // Источник реле
  setPin(0, 7, _relaySource);
  if (_relaySource == 0 && !_aux)
  {
    setLines(0, 7, "D", 9, "A:");
  }
  else
  {
    setLines(0, 7, RELAY_SOURCES[_relaySource]);
  }

  if (_relaySource == 7)
  {
    _shifter.setPin(0, LOW); // устанавливаем контакт 1 в цепочке (второй контакт) ВЫСОКИМ
  }
}


void ProcessRelayRec()
{
  setPin(8, 11, RELAY_REC_1[_relayRec]);
  setLines(1, 6, RELAY_REC_2[_relayRec], RELAY_REC_3[_relayRec], RELAY_REC_4[_relayRec]);
}


void ProcessRelaySourceDigi()
{
  setPin(16, 23, 17 - _relaySourceDigi);
  if (_relaySource == 0 && !_aux) 
  {
    _lcd.setCursor(7, 0);
    _lcd.print(DIGI_RELAY_SOURCES[_relaySource]);
  }
  setLines(2, 8, RELAY_SOURCE_DIGI_1[_relaySourceDigi - 1], RELAY_SOURCE_DIGI_2[_relaySourceDigi - 1], RELAY_SOURCE_DIGI_3[_relaySourceDigi - 2]);
}


void ProcessRecDigi()
{
  static const char* const t[] PROGMEM = { "Optical Out1", "Optical Out 2", "Coaxial Out 1", "Coaxial Out2" };
  setPin(12, 15, 12 + _recDigi);
  setLines(3, 6, t[_recDigi]);
  delay(150);
}


void loop() 
{
  ResetShifter();
  ReadButtons();

  HandleAuxButton();
  HandlePollButton();
  StartLcd();
  HandleButtonPinUp();
  HandleMuteButton();

  ProcessRelaySource();
  ProcessRelayRec();
  ProcessRelaySourceDigi();
  ProcessRecDigi();
}
,

Привет. Все еще пытаюсь понять это, новичок в ардуино, спасибо за информацию, @Nuno Brandão

проголосуйте за очень хороший ответ... вы можете еще больше упростить свой код... lcd.setCursor(0, 2); жк.запись(8); lcd.setCursor(2, 2); lcd.print("Sony MD ["); жк.запись(4); lcd.print("]"); .... такое же, как это .... lcd.setCursor(0, 2); lcd.print("\x08 Sony MD [\x04]");, @jsotola

@jsotola спасибо ... однако в моем оптимизированном коде я не уверен, смогу ли я использовать его, поскольку позиции курсора являются переменными., @Michel Keijzers

Большое спасибо, увидев это, я понял, что я на самом деле новичок! Я попробую это завтра, пока пробовал с поворотным энкодером и меню, но это не очень нравится., @Nuno Brandão

Я профессиональный инженер-программист, так что для меня это «обычные вещи», хотя я до сих пор мало знаю о многих специфических деталях Arduino. (Кстати, набросок можно улучшить, но это «низко висящие плоды». Если вы в следующий раз попытаетесь сделать свою петлю настолько простой, насколько я знал, ваш общий дизайн в целом будет намного проще., @Michel Keijzers