276

Re: BD37534FV - Sound Processor with Built-in 3-band Equalizer

Не должно ни как повлиять

277

Re: BD37534FV - Sound Processor with Built-in 3-band Equalizer

Спасибо

278 (2025-03-29 09:51:16 отредактировано opertech)

Re: BD37534FV - Sound Processor with Built-in 3-band Equalizer

Здравствуйте. Можно ли обойти превышение размеров прошивки (104% от памяти контроллера) при использовании 328P-LQFP32(MiniEVB) если использовать стандартную прошивку из среды через сн340(загрузчик)?

279

Re: BD37534FV - Sound Processor with Built-in 3-band Equalizer

Надо по возможности все повторяющиеся фрагменты кода перенести в функцию для уменьшения размера скетча

280

Re: BD37534FV - Sound Processor with Built-in 3-band Equalizer

Спасибо

281

Re: BD37534FV - Sound Processor with Built-in 3-band Equalizer

Здравствуйте собрал Ваш проект скетч из поста 260 не отключается звук в режиме MUTE на экране режим отображается

282

Re: BD37534FV - Sound Processor with Built-in 3-band Equalizer

Замените

if(power==0){
  if((digitalRead(MUTE_BUTTON)==LOW || ir.value==IR_MUTE)&& mute==0){mute=1;gr1=0;gr2=0;cl();
    myOLED.setFont(SmallFont);myOLED.print(F("MUTE"), CENTER, 10);myOLED.update();cl();menu=100;}
  if((digitalRead(MUTE_BUTTON)==LOW  || ir.value==IR_MUTE)&& mute==1){mute=0;gr1=0;gr2=0;times=millis();w=1;w2=1;cl();menu=0;} 
}

на

if(power==0){
  if((digitalRead(MUTE_BUTTON)==LOW || ir.value==IR_MUTE)&& mute==0){mute=1;gr1=0;gr2=0;cl();
    myOLED.setFont(SmallFont);myOLED.print(F("MUTE"), CENTER, 10);myOLED.update();cl();menu=100;audio();}
  if((digitalRead(MUTE_BUTTON)==LOW  || ir.value==IR_MUTE)&& mute==1){mute=0;gr1=0;gr2=0;times=millis();w=1;w2=1;cl();menu=0;audio();} 
}

283

Re: BD37534FV - Sound Processor with Built-in 3-band Equalizer

Спасибо за быстрый ответ еще хотелось добавить 2 пина на  IN2  и IN3
#define IN2_OUT 6
#define IN3_OUT 7
чтобы при включении соответствующего входа  на них был высокий уровень.нужны для коммутации индикатора уровня

284

Re: BD37534FV - Sound Processor with Built-in 3-band Equalizer

swith(in_reg){
  case 1: digitalWrite(IN2_OUT,HIGH); digitalWrite(IN3_OUT,LOW);break;
  case 2: digitalWrite(IN2_OUT,LOW); digitalWrite(IN3_OUT,HIGH);break;
}

285

Re: BD37534FV - Sound Processor with Built-in 3-band Equalizer

буду тестировать

286

Re: BD37534FV - Sound Processor with Built-in 3-band Equalizer

рабочий протестированный код
#define STANDBY_OUT 13
#define IN2_OUT 6
#define IN3_OUT 7

#define IR_POWER 0x106FBA45
#define IR_MUTE 0x106FE21D
#define IR_UP 0x20DF40BF
#define IR_DW 0x20DFC03F
#define IR_MENU 0x106F8A75
#define IR_INPUT 0x106F9A65
#define IR_SET 0x106FE01F

#include <Wire.h>
#include <OLED_I2C.h>
#include <EEPROM.h>
#include <IRremote.h>
#include <BD37534FV.h>
#include <avr/wdt.h>

BD37534FV tda;
OLED myOLED(SDA, SCL, 8);
extern uint8_t SmallFont[], BigNumbers[];
IRrecv irrecv(12);
decode_results ir;

// Константы меню
const int MENU_MAIN_COUNT = 6;
const int MENU_SETTINGS_START = 10;
const int MENU_SETTINGS_END = 23;
const int MENU_SETTINGS_COUNT = 14;

// Константы EEPROM
const int EEPROM_VOLUME = 0;
const int EEPROM_INPUT = 1;
const int EEPROM_GAIN1 = 2;
const int EEPROM_GAIN2 = 3;
const int EEPROM_GAIN3 = 4;
const uint8_t EEPROM_INIT_FLAG = 0xAA;
const int EEPROM_INIT_ADDR = 100;

// Константы времени
const unsigned long VOLUME_STEP_DELAY = 150;
const unsigned long IR_DEBOUNCE = 200;
const unsigned long EEPROM_SAVE_DELAY = 5000;
const unsigned long REPEAT_DELAY = 500;
const unsigned long REPEAT_INTERVAL = 100;
const unsigned long POWER_DEBOUNCE = 1000;

// Основные переменные
int menu = 0;
int vol_reg = 0, in_reg = 0, treb_reg = 0, bass_reg = 0, mid_reg = 0;
int gain0 = 0, gain1 = 0, gain2 = 0, gain3 = 0;
bool power = false, mute = false, set = false; // Начинаем с выключенного состояния

// Настройки эквалайзера
int f_treb = 1, q_treb = 0, f_mid = 1, q_mid = 1, f_bass = 1, q_bass = 1;
int f_sub = 2, f_lon = 1, gain_lon = 10;

// Усилители каналов
int gain_lf = 0, gain_rf = 0, gain_lr = 0, gain_rr = 0, gain_sub = 0;

// Флаги состояния
unsigned long lastIrTime = 0;
unsigned long eepromSaveTime = 0;
bool eepromDirty = false;
uint32_t lastCommand = 0;
unsigned long lastRepeatTime = 0;
bool repeatEnabled = false;
unsigned long lastPowerCommandTime = 0;

// Строки в PROGMEM
const char str_power_off[] PROGMEM = "POWER OFF";
const char str_mute[] PROGMEM = "MUTE";
const char str_volume[] PROGMEM = "VOLUME";
const char str_treble[] PROGMEM = "TREBLE";
const char str_middle[] PROGMEM = "MIDDLE";
const char str_bass[] PROGMEM = "BASS";
const char str_input[] PROGMEM = "INPUT";
const char str_gain[] PROGMEM = "GAIN";
const char str_in[] PROGMEM = "IN";
const char str_settings_saved[] PROGMEM = "SETTINGS SAVED";
const char str_bd37534fv[] PROGMEM = "BD37534FV";

// Класс для безопасной работы со временем
class SafeTimer {
private:
    unsigned long lastTime = 0;
   
public:
    bool isTimePassed(unsigned long interval) {
        unsigned long currentTime = millis();
        if (currentTime - lastTime >= interval) {
            lastTime = currentTime;
            return true;
        }
        return false;
    }
   
    void reset() {
        lastTime = millis();
    }
   
    bool isTimePassedFrom(unsigned long startTime, unsigned long interval) {
        unsigned long currentTime = millis();
        return (currentTime - startTime) >= interval;
    }
};

// Функция для обновления текущего усиления
void updateCurrentGain() {
    switch (in_reg) {
        case 0: gain0 = gain1; break;
        case 1: gain0 = gain2; break;
        case 2: gain0 = gain3; break;
    }
    gain0 = constrain(gain0, 0, 20);
}

// Класс для управления EEPROM
class EEPROMManager {
private:
    bool dirty = false;
    unsigned long saveTime = 0;
   
public:
    void loadSettings() {
        // Проверка инициализации EEPROM
        if (EEPROM.read(EEPROM_INIT_ADDR) != EEPROM_INIT_FLAG) {
            // Первая инициализация
            EEPROM.update(EEPROM_VOLUME, 79);
            EEPROM.update(EEPROM_INPUT, 0);
            EEPROM.update(EEPROM_GAIN1, 0);
            EEPROM.update(EEPROM_GAIN2, 0);
            EEPROM.update(EEPROM_GAIN3, 0);
            EEPROM.update(EEPROM_INIT_ADDR, EEPROM_INIT_FLAG);
        }

        // Безопасная загрузка
        uint8_t stored_vol = EEPROM.read(EEPROM_VOLUME);
        vol_reg = constrain(stored_vol - 79, -79, 15);
       
        uint8_t stored_input = EEPROM.read(EEPROM_INPUT);
        in_reg = constrain(stored_input, 0, 2);
       
        gain1 = constrain(EEPROM.read(EEPROM_GAIN1), 0, 20);
        gain2 = constrain(EEPROM.read(EEPROM_GAIN2), 0, 20);
        gain3 = constrain(EEPROM.read(EEPROM_GAIN3), 0, 20);
       
        updateCurrentGain();
    }
   
    void saveSettings() {
        EEPROM.update(EEPROM_VOLUME, vol_reg + 79);
        EEPROM.update(EEPROM_INPUT, in_reg);
        EEPROM.update(EEPROM_GAIN1, gain1);
        EEPROM.update(EEPROM_GAIN2, gain2);
        EEPROM.update(EEPROM_GAIN3, gain3);
        EEPROM.update(EEPROM_INIT_ADDR, EEPROM_INIT_FLAG);
        dirty = false;
    }
   
    void markDirty() {
        dirty = true;
        saveTime = millis();
    }
   
    bool shouldSave() {
        return dirty && (millis() - saveTime >= EEPROM_SAVE_DELAY);
    }
};

// Класс для управления питанием
class PowerManager {
private:
    uint8_t standbyPin;
    unsigned long lastPowerChange = 0;
   
public:
    PowerManager(uint8_t pin) : standbyPin(pin) {}
   
    void initialize() {
        pinMode(standbyPin, OUTPUT);
        digitalWrite(standbyPin, LOW); // Начинаем с выключенного состояния
    }
   
    bool canChangePower() {
        return (millis() - lastPowerChange) >= POWER_DEBOUNCE;
    }
   
    void turnOn() {
        if (!canChangePower()) return;
       
        digitalWrite(standbyPin, HIGH);
        lastPowerChange = millis();
       
        // Плавное включение дисплея
        for (int i = 0; i <= 100; i += 20) {
            myOLED.setBrightness(i);
            delay(30);
        }
    }
   
    void turnOff() {
        if (!canChangePower()) return;
       
        // Плавное выключение дисплея
        for (int i = 100; i >= 0; i -= 20) {
            myOLED.setBrightness(i);
            delay(30);
        }
       
        digitalWrite(standbyPin, LOW);
        lastPowerChange = millis();
    }
};

// Класс для управления аудио
class AudioManager {
private:
    BD37534FV* processor;
   
public:
    AudioManager(BD37534FV* audioProcessor) : processor(audioProcessor) {}
   
    void applyEqualizerSettings() {
        if (!power) return;
       
        // Здесь должны быть вызовы функций настройки эквалайзера
        // Временная заглушка - реализовать когда будут готовы функции в библиотеке
    }
   
    void updateAudio() {
        if (!power) {
            // Полное отключение
            processor->setIn_gain(0, 1);
            return;
        }
       
        if (mute) {
            // Режим MUTE
            processor->setIn_gain(gain0, 1);
        } else {
            // Нормальный режим
            processor->setIn(in_reg);
            processor->setIn_gain(gain0, 0);
            processor->setVol(vol_reg);
            processor->setFront_1(gain_lf);
            processor->setFront_2(gain_rf);
            processor->setRear_1(gain_lr);
            processor->setRear_2(gain_rr);
            processor->setSub(gain_sub);
            processor->mix();
            processor->setBass_gain(bass_reg);
            processor->setMiddle_gain(mid_reg);
            processor->setTreble_gain(treb_reg);
           
            applyEqualizerSettings();
        }
    }
   
    void updateInputOutputs() {
        switch (in_reg) {
            case 0:
                digitalWrite(IN2_OUT, LOW);
                digitalWrite(IN3_OUT, LOW);
                break;
            case 1:
                digitalWrite(IN2_OUT, HIGH);
                digitalWrite(IN3_OUT, LOW);
                break;
            case 2:
                digitalWrite(IN2_OUT, LOW);
                digitalWrite(IN3_OUT, HIGH);
                break;
        }
    }
};

// Глобальные экземпляры классов
PowerManager powerManager(STANDBY_OUT);
EEPROMManager eepromManager;
AudioManager audioManager(&tda);

// Прототипы функций
void displayMainMenu();
void displayVolumeMenu();
void displayTrebleMenu();
void displayMiddleMenu();
void displayBassMenu();
void displayInputGainMenu();
void displaySettingsMenu();
void displaySettingFreqTreble();
void displaySettingFreqMiddle();
void displaySettingFreqBass();
void displaySettingFreqSub();
void displaySettingFreqLoudness();
void displaySettingQTreble();
void displaySettingQMiddle();
void displaySettingQBass();
void displaySettingGainLoudness();
void displaySettingGainLF();
void displaySettingGainRF();
void displaySettingGainLR();
void displaySettingGainRR();
void displaySettingGainSub();
void handlePowerCommand();
void handleMuteCommand();
void handleSetCommand();
void handleMenuCommand();
void handleInputCommand();
void handleUpDownButtons(uint32_t cmd);
bool adjustValue(int direction);
bool changeVolume(int direction);
bool changeTone(int &value, int direction, int min_val, int max_val);
void saveCurrentGain();
void constrainValues();
void displayMenu();
void displayPowerOff();
void displayMute();

void constrainValues() {
    vol_reg = constrain(vol_reg, -79, 15);
    treb_reg = constrain(treb_reg, -20, 20);
    mid_reg = constrain(mid_reg, -20, 20);
    bass_reg = constrain(bass_reg, -20, 20);
    gain0 = constrain(gain0, 0, 20);
    gain1 = constrain(gain1, 0, 20);
    gain2 = constrain(gain2, 0, 20);
    gain3 = constrain(gain3, 0, 20);
}

void setup() {
    wdt_disable(); // Отключить watchdog на время инициализации
   
    Wire.begin();
    Wire.setClock(400000L);
   
    // Инициализация пинов
    pinMode(IN2_OUT, OUTPUT);
    pinMode(IN3_OUT, OUTPUT);
    pinMode(12, INPUT_PULLUP); // Защита от помех на IR входе
   
    powerManager.initialize();
   
    // Инициализация IR
    irrecv.enableIRIn();
   
    // Инициализация дисплея
    myOLED.begin();
    myOLED.setBrightness(0); // Начинаем с выключенного дисплея
   
    // Загрузка настроек
    eepromManager.loadSettings();
   
    // Быстрая заставка
    myOLED.clrScr();
    myOLED.setFont(SmallFont);
    char buffer[20];
    strcpy_P(buffer, str_bd37534fv);
    myOLED.print(buffer, CENTER, 20);
    myOLED.update();
    delay(500);
   
    // Остаемся в выключенном состоянии
    displayMenu();
   
    wdt_enable(WDTO_2S); // Включить watchdog (2 секунды)
}

bool handleIR() {
    if (irrecv.decode(&ir)) {
        unsigned long now = millis();
       
        // Защита от дребезга
        if (now - lastIrTime < IR_DEBOUNCE) {
            irrecv.resume();
            return false;
        }
        lastIrTime = now;
       
        uint32_t value = ir.value;
        irrecv.resume();
       
        // Фильтрация невалидных команд
        if (value == 0) {
            return false;
        }
       
        // Обработка повторяющихся команд
        if (value == 0xFFFFFFFF) {
            if (repeatEnabled && (now - lastRepeatTime >= REPEAT_INTERVAL)) {
                lastRepeatTime = now;
                value = lastCommand;
            } else {
                return false;
            }
        } else {
            // Новая команда
            lastCommand = value;
            repeatEnabled = true;
            lastRepeatTime = now + REPEAT_DELAY;
        }
       
        // Обработка команд
        if (value == IR_POWER) {
            handlePowerCommand();
            return true;
        }
       
        if (!power) return true; // Остальные команды игнорируем при выключенном питании
       
        if (value == IR_MUTE) {
            handleMuteCommand();
            return true;
        }
       
        if (value == IR_SET) {
            handleSetCommand();
            return true;
        }
       
        // Если в режиме mute, блокируем остальные команды кроме навигации
        if (mute) {
            if (value == IR_MENU) {
                handleMenuCommand();
            }
            return true;
        }
       
        // Обработка остальных команд при включенном питании и снятом mute
        switch (value) {
            case IR_MENU:
                handleMenuCommand();
                break;
            case IR_INPUT:
                handleInputCommand();
                break;
            case IR_UP:
            case IR_DW:
                handleUpDownButtons(value);
                break;
        }
       
        return true;
    }
    return false;
}

void handlePowerCommand() {
    power = !power;
    if (power) {
        powerManager.turnOn();
        mute = false; // Снимаем mute при включении
        menu = 0;
        set = false;
    } else {
        powerManager.turnOff();
    }
    audioManager.updateAudio();
    displayMenu();
}

void handleMuteCommand() {
    if (!power) return;
    mute = !mute;
    audioManager.updateAudio();
    displayMenu();
}

void handleSetCommand() {
    if (!power) return;
    set = !set;
    if (set) {
        menu = MENU_SETTINGS_START;
    } else {
        menu = 0;
    }
    displayMenu();
}

void handleMenuCommand() {
    if (!set) {
        // Основные меню
        menu = (menu + 1) % MENU_MAIN_COUNT;
        if (menu == 4) menu = 5; // Пропускаем 4
    } else {
        // Меню настроек
        menu++;
        if (menu > MENU_SETTINGS_END) menu = MENU_SETTINGS_START;
    }
    displayMenu();
}

void handleInputCommand() {
    in_reg = (in_reg + 1) % 3;
    menu = 5;
    audioManager.updateInputOutputs();
    updateCurrentGain();
    audioManager.updateAudio();
    eepromManager.markDirty();
    displayMenu();
}

void handleUpDownButtons(uint32_t cmd) {
    bool changed = false;
   
    if (cmd == IR_UP) {
        changed = adjustValue(1);
    }
    else if (cmd == IR_DW) {
        changed = adjustValue(-1);
    }
   
    if (menu == 5 && changed) {
        saveCurrentGain();
    }
   
    if (changed) {
        audioManager.updateAudio();
        eepromManager.markDirty();
        displayMenu();
    }
}

bool adjustValue(int direction) {
    switch (menu) {
        case 0: return changeVolume(direction);
        case 1: return changeTone(treb_reg, direction, -20, 20);
        case 2: return changeTone(mid_reg, direction, -20, 20);
        case 3: return changeTone(bass_reg, direction, -20, 20);
        case 5: return changeTone(gain0, direction, 0, 20);
        case 10: return changeTone(f_treb, direction, 0, 3);
        case 11: return changeTone(f_mid, direction, 0, 3);
        case 12: return changeTone(f_bass, direction, 0, 3);
        case 13: return changeTone(f_sub, direction, 0, 4);
        case 14: return changeTone(f_lon, direction, 0, 3);
        case 15: return changeTone(q_treb, direction, 0, 1);
        case 16: return changeTone(q_mid, direction, 0, 3);
        case 17: return changeTone(q_bass, direction, 0, 3);
        case 18: return changeTone(gain_lon, direction, 0, 20);
        case 19: return changeTone(gain_lf, direction, -79, 15);
        case 20: return changeTone(gain_rf, direction, -79, 15);
        case 21: return changeTone(gain_lr, direction, -79, 15);
        case 22: return changeTone(gain_rr, direction, -79, 15);
        case 23: return changeTone(gain_sub, direction, -79, 15);
        default: return false;
    }
}

bool changeVolume(int direction) {
    int new_vol = vol_reg + direction;
    if (new_vol >= -79 && new_vol <= 15) {
        vol_reg = new_vol;
        return true;
    }
    return false;
}

bool changeTone(int &value, int direction, int min_val, int max_val) {
    int new_val = value + direction;
    if (new_val >= min_val && new_val <= max_val) {
        value = new_val;
        return true;
    }
    return false;
}

void saveCurrentGain() {
    switch (in_reg) {
        case 0: gain1 = gain0; break;
        case 1: gain2 = gain0; break;
        case 2: gain3 = gain0; break;
    }
}

void displayMenu() {
    myOLED.clrScr();
   
    if (!power) {
        displayPowerOff();
        myOLED.update();
        return;
    }
   
    if (mute) {
        displayMute();
        myOLED.update();
        return;
    }
   
    if (!set) {
        displayMainMenu();
    } else {
        displaySettingsMenu();
    }
   
    myOLED.update();
}

void displayPowerOff() {
    myOLED.setFont(SmallFont);
    char buffer[20];
    strcpy_P(buffer, str_power_off);
    myOLED.print(buffer, CENTER, 30);
}

void displayMute() {
    myOLED.setFont(SmallFont);
    char buffer[20];
    strcpy_P(buffer, str_mute);
    myOLED.print(buffer, CENTER, 17);
   
    myOLED.setFont(SmallFont);
    myOLED.print(F("VOL:"), 25, 45);
    myOLED.printNumI(vol_reg + 79, 30, 45);
    myOLED.print(F("IN:"), 80, 45);
    myOLED.printNumI(in_reg + 1, 90, 45);
}

void displayMainMenu() {
    switch (menu) {
        case 0: displayVolumeMenu(); break;
        case 1: displayTrebleMenu(); break;
        case 2: displayMiddleMenu(); break;
        case 3: displayBassMenu(); break;
        case 5: displayInputGainMenu(); break;
    }
}

void displayVolumeMenu() {
    char buffer[20];
    myOLED.setFont(SmallFont);
    strcpy_P(buffer, str_volume);
    myOLED.print(buffer, LEFT, 0);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(vol_reg + 79, 75, 0);
    myOLED.setFont(SmallFont);
    strcpy_P(buffer, str_in);
    myOLED.print(buffer, LEFT, 10);
    myOLED.printNumI(in_reg + 1, 30, 10);
    strcpy_P(buffer, str_gain);
    myOLED.print(buffer, LEFT, 20);
    myOLED.printNumI(gain0, 30, 20);
    myOLED.drawLine(0, 30, 128, 30);
    myOLED.setFont(SmallFont);
    strcpy_P(buffer, str_treble);
    myOLED.print(buffer, LEFT, 35);
    myOLED.printNumI(treb_reg, 75, 35);
    strcpy_P(buffer, str_middle);
    myOLED.print(buffer, LEFT, 45);
    myOLED.printNumI(mid_reg, 75, 45);
    strcpy_P(buffer, str_bass);
    myOLED.print(buffer, LEFT, 55);
    myOLED.printNumI(bass_reg, 75, 55);
}

void displayTrebleMenu() {
    char buffer[20];
    myOLED.setFont(SmallFont);
    strcpy_P(buffer, str_treble);
    myOLED.print(buffer, LEFT, 0);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(treb_reg, 75, 0);
    myOLED.setFont(SmallFont);
    switch (f_treb) {
        case 0: myOLED.print(F("F 7.5 kHz"), LEFT, 10); break;
        case 1: myOLED.print(F("F 10  kHz"), LEFT, 10); break;
        case 2: myOLED.print(F("F 12.5kHz"), LEFT, 10); break;
        case 3: myOLED.print(F("F 15  kHz"), LEFT, 10); break;
    }
    myOLED.setFont(SmallFont);
    switch (q_treb) {
        case 0: myOLED.print(F("Q 0.75"), LEFT, 20); break;
        case 1: myOLED.print(F("Q 1.25"), LEFT, 20); break;
    }
    myOLED.drawLine(0, 30, 128, 30);
    myOLED.setFont(SmallFont);
    strcpy_P(buffer, str_middle);
    myOLED.print(buffer, LEFT, 35);
    myOLED.printNumI(mid_reg, 75, 35);
    strcpy_P(buffer, str_bass);
    myOLED.print(buffer, LEFT, 45);
    myOLED.printNumI(bass_reg, 75, 45);
    strcpy_P(buffer, str_volume);
    myOLED.print(buffer, LEFT, 55);
    myOLED.printNumI(vol_reg + 79, 75, 55);
}

void displayMiddleMenu() {
    char buffer[20];
    myOLED.setFont(SmallFont);
    strcpy_P(buffer, str_middle);
    myOLED.print(buffer, LEFT, 0);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(mid_reg, 75, 0);
    myOLED.setFont(SmallFont);
    switch (f_mid) {
        case 0: myOLED.print(F("F 500 Hz"), LEFT, 10); break;
        case 1: myOLED.print(F("F 1  kHz"), LEFT, 10); break;
        case 2: myOLED.print(F("F 1.5kHz"), LEFT, 10); break;
        case 3: myOLED.print(F("F 2.5kHz"), LEFT, 10); break;
    }
    myOLED.setFont(SmallFont);
    switch (q_mid) {
        case 0: myOLED.print(F("Q 0.75"), LEFT, 20); break;
        case 1: myOLED.print(F("Q 1.00"), LEFT, 20); break;
        case 2: myOLED.print(F("Q 1.25"), LEFT, 20); break;
        case 3: myOLED.print(F("Q 1.50"), LEFT, 20); break;
    }
    myOLED.drawLine(0, 30, 128, 30);
    myOLED.setFont(SmallFont);
    strcpy_P(buffer, str_bass);
    myOLED.print(buffer, LEFT, 35);
    myOLED.printNumI(bass_reg, 75, 35);
    strcpy_P(buffer, str_volume);
    myOLED.print(buffer, LEFT, 45);
    myOLED.printNumI(vol_reg + 79, 75, 45);
    strcpy_P(buffer, str_treble);
    myOLED.print(buffer, LEFT, 55);
    myOLED.printNumI(treb_reg, 75, 55);
}

void displayBassMenu() {
    char buffer[20];
    myOLED.setFont(SmallFont);
    strcpy_P(buffer, str_bass);
    myOLED.print(buffer, LEFT, 0);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(bass_reg, 75, 0);
    myOLED.setFont(SmallFont);
    switch (f_bass) {
        case 0: myOLED.print(F("F 60 Hz"), LEFT, 10); break;
        case 1: myOLED.print(F("F 80 Hz"), LEFT, 10); break;
        case 2: myOLED.print(F("F 100 Hz"), LEFT, 10); break;
        case 3: myOLED.print(F("F 120 Hz"), LEFT, 10); break;
    }
    switch (q_bass) {
        case 0: myOLED.print(F("Q 0.50"), LEFT, 20); break;
        case 1: myOLED.print(F("Q 1.00"), LEFT, 20); break;
        case 2: myOLED.print(F("Q 1.50"), LEFT, 20); break;
        case 3: myOLED.print(F("Q 2.00"), LEFT, 20); break;
    }
    myOLED.drawLine(0, 30, 128, 30);
    myOLED.setFont(SmallFont);
    strcpy_P(buffer, str_volume);
    myOLED.print(buffer, LEFT, 35);
    myOLED.printNumI(vol_reg + 79, 75, 35);
    strcpy_P(buffer, str_treble);
    myOLED.print(buffer, LEFT, 45);
    myOLED.printNumI(treb_reg, 75, 45);
    strcpy_P(buffer, str_middle);
    myOLED.print(buffer, LEFT, 55);
    myOLED.printNumI(mid_reg, 75, 55);
}

void displayInputGainMenu() {
    char buffer[20];
    myOLED.setFont(SmallFont);
    strcpy_P(buffer, str_input);
    myOLED.print(buffer, LEFT, 0);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(in_reg + 1, 65, 0);
    myOLED.drawLine(0, 30, 128, 30);
    myOLED.setFont(SmallFont);
    strcpy_P(buffer, str_gain);
    myOLED.print(buffer, LEFT, 35);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(gain0, 65, 35);
}

void displaySettingsMenu() {
    switch (menu) {
        case 10: displaySettingFreqTreble(); break;
        case 11: displaySettingFreqMiddle(); break;
        case 12: displaySettingFreqBass(); break;
        case 13: displaySettingFreqSub(); break;
        case 14: displaySettingFreqLoudness(); break;
        case 15: displaySettingQTreble(); break;
        case 16: displaySettingQMiddle(); break;
        case 17: displaySettingQBass(); break;
        case 18: displaySettingGainLoudness(); break;
        case 19: displaySettingGainLF(); break;
        case 20: displaySettingGainRF(); break;
        case 21: displaySettingGainLR(); break;
        case 22: displaySettingGainRR(); break;
        case 23: displaySettingGainSub(); break;
    }
}

void displaySettingFreqTreble() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("Frequency TREBLE"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    switch (f_treb) {
        case 0: myOLED.print(F("7.50"), CENTER, 20); break;
        case 1: myOLED.print(F("10.0"), CENTER, 20); break;
        case 2: myOLED.print(F("12.5"), CENTER, 20); break;
        case 3: myOLED.print(F("15.0"), CENTER, 20); break;
    }
    myOLED.setFont(SmallFont);
    myOLED.print(F("kHz"), CENTER, 50);
}

void displaySettingFreqMiddle() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("Frequency MIDDLE"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    switch (f_mid) {
        case 0: myOLED.print(F("0.5"), CENTER, 20); break;
        case 1: myOLED.print(F("1.0"), CENTER, 20); break;
        case 2: myOLED.print(F("1.5"), CENTER, 20); break;
        case 3: myOLED.print(F("2.5"), CENTER, 20); break;
    }
    myOLED.setFont(SmallFont);
    myOLED.print(F("kHz"), CENTER, 50);
}

void displaySettingFreqBass() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("Frequency BASS"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    switch (f_bass) {
        case 0: myOLED.print(F("60"), CENTER, 20); break;
        case 1: myOLED.print(F("80"), CENTER, 20); break;
        case 2: myOLED.print(F("100"), CENTER, 20); break;
        case 3: myOLED.print(F("120"), CENTER, 20); break;
    }
    myOLED.setFont(SmallFont);
    myOLED.print(F("Hz"), CENTER, 50);
}

void displaySettingFreqSub() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("Frequency SUBWOOFER"), CENTER, 0);
    switch (f_sub) {
        case 0: myOLED.print(F("OFF"), CENTER, 25); break;
        case 1: myOLED.print(F("55 Hz"), CENTER, 25); break;
        case 2: myOLED.print(F("85 Hz"), CENTER, 25); break;
        case 3: myOLED.print(F("120 Hz"), CENTER, 25); break;
        case 4: myOLED.print(F("160 Hz"), CENTER, 25); break;
    }
}

void displaySettingFreqLoudness() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("Frequency LOUDNESS"), CENTER, 0);
    switch (f_lon) {
        case 0: myOLED.print(F("250 Hz"), CENTER, 25); break;
        case 1: myOLED.print(F("400 Hz"), CENTER, 25); break;
        case 2: myOLED.print(F("800 Hz"), CENTER, 25); break;
        case 3: myOLED.print(F("PROHIBIT"), CENTER, 25); break;
    }
}

void displaySettingQTreble() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("Q TREBLE"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    switch (q_treb) {
        case 0: myOLED.print(F("0.75"), CENTER, 20); break;
        case 1: myOLED.print(F("1.25"), CENTER, 20); break;
    }
}

void displaySettingQMiddle() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("Q MIDDLE"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    switch (q_mid) {
        case 0: myOLED.print(F("0.75"), CENTER, 20); break;
        case 1: myOLED.print(F("1.00"), CENTER, 20); break;
        case 2: myOLED.print(F("1.25"), CENTER, 20); break;
        case 3: myOLED.print(F("1.50"), CENTER, 20); break;
    }
}

void displaySettingQBass() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("Q BASS"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    switch (q_bass) {
        case 0: myOLED.print(F("0.50"), CENTER, 20); break;
        case 1: myOLED.print(F("1.00"), CENTER, 20); break;
        case 2: myOLED.print(F("1.50"), CENTER, 20); break;
        case 3: myOLED.print(F("2.00"), CENTER, 20); break;
    }
}

void displaySettingGainLoudness() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("GAIN LOUDNESS"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(gain_lon, CENTER, 20);
    myOLED.setFont(SmallFont);
    myOLED.print(F("dB"), CENTER, 50);
}

void displaySettingGainLF() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("GAIN LEFT FRONT"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(gain_lf, CENTER, 20);
    myOLED.setFont(SmallFont);
    myOLED.print(F("dB"), CENTER, 50);
}

void displaySettingGainRF() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("GAIN RIGHT FRONT"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(gain_rf, CENTER, 20);
    myOLED.setFont(SmallFont);
    myOLED.print(F("dB"), CENTER, 50);
}

void displaySettingGainLR() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("GAIN LEFT REAR"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(gain_lr, CENTER, 20);
    myOLED.setFont(SmallFont);
    myOLED.print(F("dB"), CENTER, 50);
}

void displaySettingGainRR() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("GAIN RIGHT REAR"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(gain_rr, CENTER, 20);
    myOLED.setFont(SmallFont);
    myOLED.print(F("dB"), CENTER, 50);
}

void displaySettingGainSub() {
    myOLED.setFont(SmallFont);
    myOLED.print(F("GAIN SUBWOOFER"), CENTER, 0);
    myOLED.setFont(BigNumbers);
    myOLED.printNumI(gain_sub, CENTER, 20);
    myOLED.setFont(SmallFont);
    myOLED.print(F("dB"), CENTER, 50);
}

void loop() {
    wdt_reset(); // Сброс watchdog таймера
   
    // Обработка ИК-команд
    handleIR();
   
    // Автосохранение в EEPROM
    if (eepromManager.shouldSave()) {
        eepromManager.saveSettings();
       
        // Краткое сообщение о сохранении
        myOLED.clrScr();
        myOLED.setFont(SmallFont);
        char buffer[20];
        strcpy_P(buffer, str_settings_saved);
        myOLED.print(buffer, CENTER, 30);
        myOLED.update();
        delay(300);
        displayMenu();
    }
   
    delay(10);
}
Скетч использует 20786 байт (64%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 1573 байт (76%) динамической памяти, оставляя 475 байт для локальных переменных. Максимум: 2048 байт.