STM32_11.KMU_FishSTM32G030F6P6

Water Level Protection Controller

Sterownik zabezpieczenia poziomu wody z trwałą pamięcią alarmu. Implementacja na STM32G030F6P6 z obsługą czujnika pływakowego, przekaźnika AC i trybu uśpienia.

STM32G0CHALGPIOEEPROM emulationLow power
Sterownik poziomu wody z mikrokontrolerem STM32G030 i elementami wykonawczymi.

Informacje

  • Repozytorium: STM32_11.KMU_FishSTM32G030F6P6
  • Płytka / obszar: STM32G030F6P6
  • Kategoria: Embedded controller
  • Status: Public repository

Opis techniczny

  • Repozytorium ma typową strukturę STM32CubeIDE: Core, Drivers, plik .ioc, linker script oraz konfiguracje Debug/Release.
  • Firmware obsługuje konkretny układ zabezpieczenia poziomu wody: czujnik pływakowy, ręczny reset, sygnalizację i odcięcie zasilania przez przekaźnik.
  • Schemat i kod są zgodne z małym wariantem STM32G030: wejścia GPIO obsługują czujnik pływakowy i przycisk, a wyjścia sterują LED, buzzerem oraz przekaźnikami AC.
  • Wersja na STM32G030 ogranicza zasoby sprzętowe do minimum potrzebnego dla czujnika poziomu, sygnalizacji i wyjścia wykonawczego.
  • Projekt używa typowej konfiguracji STM32CubeIDE dla STM32G0, z kodem aplikacyjnym opartym o HAL GPIO, flash/EEPROM emulation i niski pobór energii.

Co dzieje się w kodzie

Wybrane najważniejsze mechanizmy z projektu.

  • Projekt jest sterownikiem zabezpieczenia/układu wykonawczego dla małego STM32G030F6P6. Główne elementy to UserSwitch, FloatSensor, ACRelay, LED i tryb uśpienia.
  • Kod zapamiętuje stan LowLevelWasReached i licznik naciśnięć przycisku w emulowanej pamięci EEPROM przez EE_WriteVariable/EE_ReadVariable.
  • Po starcie firmware odczytuje flash. Jeżeli wcześniej wykryto niski poziom, przekaźnik AC pozostaje wyłączony po restarcie, czyli stan alarmowy jest trwały.
  • Główna pętla przechodzi do Sleep Mode przez WFE, a wybudzenie następuje zdarzeniami GPIO. Sterownik działa więc zdarzeniowo i ogranicza pobór energii między akcjami.
  • UserSwitch służy jako ręczny reset alarmu, ale tylko gdy FloatSensor nie wskazuje aktywnego niskiego poziomu.
  • LED sygnalizuje alarm przez miganie, a ACRelay jest wyłączany przy wykryciu niskiego poziomu.

Kluczowe fragmenty kodu

Kod jest skrócony do części istotnych dla zrozumienia projektu.

Trwały stan alarmu w emulowanej EEPROM

Core/Src/app_fish_tank.c
#define FLASH_MAGIC_16          ((uint16_t)0x7A4D)
#define VA_MAGIC                ((uint16_t)0x1001)
#define VIRTADDR_KEYCOUNT       ((uint16_t)0x1002)
#define VIRTADDR_LOWLEVEL       ((uint16_t)0x1003)

typedef struct {
    uint16_t magic;
    uint16_t keyPressedCount;
    bool lowLevelWasReached;
} DataFlash;

uint16_t VirtAddVarTab[NB_OF_VAR] = {
    VA_MAGIC,
    VIRTADDR_KEYCOUNT,
    VIRTADDR_LOWLEVEL
};

Ten fragment definiuje dane utrwalane we flash: magic value, licznik naciśnięć i flagę niskiego poziomu. Po zaniku zasilania sterownik nie powinien zapomnieć, że osiągnięto stan alarmowy.

Reakcja po starcie na zapamiętany niski poziom

Core/Src/app_fish_tank.c
static void App_ApplyStoredRelayState(void)
{
    if (app.flashData.lowLevelWasReached) {
        App_SetRelayEnabled(false);
        Send("AC Relay: Disable 
");
        app.disableACRelay = true;
        app.goToSleepMode = false;
        app.lowLevelWasReachedPrev = true;
        app.blinkLedFromTick = HAL_GetTick();
    } else {
        App_SetRelayEnabled(true);
        Send("AC Relay: Enable 
");
        app.disableACRelay = false;
    }
}

Po restarcie urządzenie odtwarza ostatni istotny stan. Jeśli wcześniej był niski poziom, przekaźnik AC jest wyłączony, LED świeci, a urządzenie nie przechodzi od razu spać.

Uśpienie przez WFE

Core/Src/app_fish_tank.c
static void App_EnterSleepIfAllowed(void)
{
    if (!app.goToSleepMode) {
        return;
    }

    Send("Going to sleep mode!
");

    __SEV();
    __WFE();
    __WFE();

    HAL_SuspendTick();
    HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFE);
    HAL_ResumeTick();
}

To jest część odpowiedzialna za oszczędzanie energii. Kod czyści mechanizm zdarzeń sekwencją SEV/WFE/WFE, zawiesza SysTick i wchodzi w Sleep Mode do czasu zdarzenia.

Warunki resetu alarmu i wyłączenia przekaźnika

Core/Src/app_fish_tank.c
static void App_HandleKeyPress(void)
{
    if (app.flashData.keyPressedCount < UINT16_MAX) {
        app.flashData.keyPressedCount++;
    }

    app.flashData.lowLevelWasReached = false;
    app.lowLevelWasReachedPrev = false;
    app.disableACRelay = false;

    Send("Key pressed
");
    Send("FloatSensor Reset !
");

    App_SetRelayEnabled(true);

    if (EE_WriteVariable(VIRTADDR_KEYCOUNT, app.flashData.keyPressedCount) != EE_OK) {
        Send("Blad zapisu KeyPressedCount!
");
    }

    if (EE_WriteVariable(VIRTADDR_LOWLEVEL, 0U) != EE_OK) {
        Send("Blad zapisu LowLevelWasReached!
");
    }

    app.goToSleepMode = true;
    HAL_Delay(100U);
}

static void App_HandleLowWaterDetected(void)
{
    if (app.lowLevelWasReachedPrev) {
        return;
    }

    Send("FloatSensor Low Level !
");

    app.lowLevelWasReachedPrev = true;
    app.flashData.lowLevelWasReached = true;

    if (!app.disableACRelay) {
        App_SetRelayEnabled(false);
        Send("Stan wody: NISKI 
");
        Send("AC Relay: Disable 
");
        app.disableACRelay = true;

        if (EE_WriteVariable(VIRTADDR_LOWLEVEL, 1U) != EE_OK) {
            Send("Blad zapisu LowLevelWasReached!
");
        }
    }

    app.blinkLedFromTick = HAL_GetTick();
    app.goToSleepMode = false;
}

Logika ma dwa scenariusze: przycisk resetuje alarm tylko przy nieaktywnym czujniku poziomu, a aktywny FloatSensor zapisuje alarm i wyłącza przekaźnik. To jest rdzeń zabezpieczenia sprzętowego.