Возможность очистить код?
Спокойной ночи! Основываясь на материалах, которые я получаю немного здесь и там, придумал программу для Arduino Audio Selector со сдвиговыми регистрами и некоторыми функциями. Работает как положено, не хватает только подключения релейных плат, но это на будущее. Поскольку у меня есть несколько устройств, вместо того, чтобы записывать все, могу ли я изменить, например, строку, а затем отобразить эту строку на дисплее?
Спасибо. Вот мой код, очень большой, попробуй закоротить часть сдвиговых регистров, но мне кажется, что он нестабилен.
Селектор Arduino 4x20
@Nuno Brandão, 👍0
Обсуждение1 ответ
Лучший ответ:
Я вижу много "почти" повторений, например:
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
- Измерительный датчик HG-C 1100
- avrdude ser_open() can't set com-state
- Печать string and integer LCD
- Очень простая операция Arduino Uno Serial.readString()
- Как преобразовать строку в массив байтов
- Отправка значения с одного Arduino на другой
- Как отправить команду AT на sim800l с помощью SoftwareSerial
- ЖК-дисплей I2C отображает странные символы
Пожалуйста, объясните, что вы имеете в виду, когда говорите: «Я могу изменить, например, строку, а затем показать эту строку на дисплее?». О какой линии вы говорите?, @VE7JRO
Извините, забыл упомянуть ... я думал примерно так: line1 = mp3-плеер, cd 1 = sony, cd2 = Pioneer, и при записи исходников нужно только изменить в начале вместо того, чтобы прокручивать весь код . 73-й CT1JQJ, @Nuno Brandão
В традиционном C они используют
#define / #ifdef
. В С++ есть больше возможностей, но интерпретация/угадывание фона вашего вопроса уже может помочь., @DataFiddler