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.