Update version to 1.0.3. Everest timeout changed to 2000ms. CP Line improved, added hysteresis, debounce and EMA filtering

This commit is contained in:
raduet
2026-03-25 11:09:55 +03:00
parent 14b4f0595f
commit 317e418111
14 changed files with 20844 additions and 23690 deletions

View File

@@ -2,13 +2,50 @@
#include "adc.h"
#include "board.h"
#include "tim.h"
#include "debug.h"
#include <stdint.h>
#define MAX_DUTY 450
#define CP_EMA_ALPHA_Q8 38
#define CP_DEBOUNCE_MS_DEFAULT 10
#define CP_DEBOUNCE_MS_F 60
#define CP_DEBOUNCE_MS_F_LOW_DUTY 100
#define CP_LOW_DUTY_THRESHOLD_PERCENT 10
#define CP_A_ENTER_MV 11000
#define CP_A_EXIT_MV 10000
#define CP_B_ENTER_LOW_MV 8000
#define CP_B_ENTER_HIGH_MV 10000
#define CP_B_EXIT_LOW_MV 7500
#define CP_B_EXIT_HIGH_MV 10500
#define CP_C_ENTER_LOW_MV 5000
#define CP_C_ENTER_HIGH_MV 7000
#define CP_C_EXIT_LOW_MV 4500
#define CP_C_EXIT_HIGH_MV 7500
#define CP_D_ENTER_LOW_MV 2000
#define CP_D_ENTER_HIGH_MV 4000
#define CP_D_EXIT_LOW_MV 1500
#define CP_D_EXIT_HIGH_MV 4500
#define CP_E_ENTER_LOW_MV -1000
#define CP_E_ENTER_HIGH_MV 2000
#define CP_E_EXIT_LOW_MV -1500
#define CP_E_EXIT_HIGH_MV 2500
#define CP_F_ENTER_MV -11500
#define CP_F_EXIT_MV -10500
static int32_t cp_voltage_mv = 0;
static int32_t cp_voltage_filt_mv = 0;
static uint8_t cp_filter_initialized = 0;
static uint8_t cp_duty = 0;
CP_State_t fake_cp_state = EV_STATE_ACQUIRING;
static CP_State_t cp_stable_state = EV_STATE_ACQUIRING;
static CP_State_t cp_candidate_state = EV_STATE_ACQUIRING;
static uint32_t cp_candidate_since_ms = 0;
static uint32_t CP_ReadAdcChannel(uint32_t ch) {
uint32_t adc = 0;
@@ -23,6 +60,64 @@ static uint32_t CP_ReadAdcChannel(uint32_t ch) {
}
#define VREFINT_CAL_ADDR ((uint16_t*)0x1FFFF7BA) // для STM32F1!
static uint8_t CP_IsInRange(int32_t v, int32_t lo, int32_t hi) {
return (v >= lo && v <= hi) ? 1u : 0u;
}
static int32_t CP_ApplyEma(int32_t raw_mv) {
if (!cp_filter_initialized) {
cp_voltage_filt_mv = raw_mv;
cp_filter_initialized = 1;
return cp_voltage_filt_mv;
}
cp_voltage_filt_mv += ((raw_mv - cp_voltage_filt_mv) * CP_EMA_ALPHA_Q8) / 256;
return cp_voltage_filt_mv;
}
static CP_State_t CP_ClassifyWithHysteresis(int32_t v, CP_State_t prev) {
switch (prev) {
case EV_STATE_A_IDLE:
if (v >= CP_A_EXIT_MV) return EV_STATE_A_IDLE;
break;
case EV_STATE_B_CONN_PREP:
if (CP_IsInRange(v, CP_B_EXIT_LOW_MV, CP_B_EXIT_HIGH_MV)) return EV_STATE_B_CONN_PREP;
break;
case EV_STATE_C_CONN_ACTIVE:
if (CP_IsInRange(v, CP_C_EXIT_LOW_MV, CP_C_EXIT_HIGH_MV)) return EV_STATE_C_CONN_ACTIVE;
break;
case EV_STATE_D_CONN_ACT_VENT:
if (CP_IsInRange(v, CP_D_EXIT_LOW_MV, CP_D_EXIT_HIGH_MV)) return EV_STATE_D_CONN_ACT_VENT;
break;
case EV_STATE_E_NO_POWER:
if (CP_IsInRange(v, CP_E_EXIT_LOW_MV, CP_E_EXIT_HIGH_MV)) return EV_STATE_E_NO_POWER;
break;
case EV_STATE_F_ERROR:
if (v <= CP_F_EXIT_MV) return EV_STATE_F_ERROR;
break;
default:
break;
}
if (v >= CP_A_ENTER_MV) return EV_STATE_A_IDLE;
if (CP_IsInRange(v, CP_B_ENTER_LOW_MV, CP_B_ENTER_HIGH_MV)) return EV_STATE_B_CONN_PREP;
if (CP_IsInRange(v, CP_C_ENTER_LOW_MV, CP_C_ENTER_HIGH_MV)) return EV_STATE_C_CONN_ACTIVE;
if (CP_IsInRange(v, CP_D_ENTER_LOW_MV, CP_D_ENTER_HIGH_MV)) return EV_STATE_D_CONN_ACT_VENT;
if (CP_IsInRange(v, CP_E_ENTER_LOW_MV, CP_E_ENTER_HIGH_MV)) return EV_STATE_E_NO_POWER;
if (v <= CP_F_ENTER_MV) return EV_STATE_F_ERROR;
return EV_STATE_ACQUIRING;
}
static uint32_t CP_GetDebounceMs(CP_State_t next_state) {
if (next_state == EV_STATE_F_ERROR) {
if (cp_duty <= CP_LOW_DUTY_THRESHOLD_PERCENT) {
return CP_DEBOUNCE_MS_F_LOW_DUTY;
}
return CP_DEBOUNCE_MS_F;
}
return CP_DEBOUNCE_MS_DEFAULT;
}
static int32_t CP_ReadVoltageMv(void)
{
uint32_t adc = 0;
@@ -75,27 +170,28 @@ int32_t CP_GetVoltage(void) {
}
CP_State_t CP_GetState(void) {
int32_t voltage_real = cp_voltage_mv;
int32_t voltage_real = cp_voltage_filt_mv;
uint32_t now = HAL_GetTick();
if(fake_cp_state != EV_STATE_ACQUIRING) {
return fake_cp_state;
}
if (voltage_real >= (12000-1000)) {
return EV_STATE_A_IDLE;
} else if (voltage_real >= (9000-1000) && voltage_real <= (9000+1000)) {
return EV_STATE_B_CONN_PREP;
} else if (voltage_real >= (6000-1000) && voltage_real <= (6000+1000)) {
return EV_STATE_C_CONN_ACTIVE;
} else if (voltage_real >= (3000-1000) && voltage_real <= (3000 + 1000)) {
return EV_STATE_D_CONN_ACT_VENT;
} else if (voltage_real >= (0-1000) && voltage_real <= (0+2000)){
return EV_STATE_E_NO_POWER;
} else if (voltage_real <= (-12000+1000)) {
return EV_STATE_F_ERROR;
CP_State_t instant_state = CP_ClassifyWithHysteresis(voltage_real, cp_stable_state);
if (instant_state == cp_stable_state) {
cp_candidate_state = cp_stable_state;
cp_candidate_since_ms = now;
} else {
return EV_STATE_ACQUIRING;
if (cp_candidate_state != instant_state) {
cp_candidate_state = instant_state;
cp_candidate_since_ms = now;
} else if ((now - cp_candidate_since_ms) >= CP_GetDebounceMs(cp_candidate_state)) {
cp_stable_state = cp_candidate_state;
}
}
return cp_stable_state;
}
void CP_Loop(void) {
@@ -109,6 +205,7 @@ void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
return;
}
cp_voltage_mv = CP_ReadVoltageMv();
(void)CP_ApplyEma(cp_voltage_mv);
ADC_Unlock();
}
}