некоторый рефакторинг

This commit is contained in:
Razvalyaev 2025-12-30 14:50:50 +03:00
parent 9b4ccd63b0
commit 7286f33709
12 changed files with 168 additions and 126 deletions

Binary file not shown.

@ -1 +1 @@
Subproject commit a6b27da4ce1d3cf60a251225beff3e6d0af1193e
Subproject commit 795ebbd220fd16ba9db4d1c071ed66700c2df928

View File

@ -27,6 +27,8 @@
#define UPP_DISABLE_PROTECT_BOARDPOWER ///< Отключить проверки питания плат (+24, +5 В)
#define UPP_DISABLE_PROTECT_LOSS_PHASE ///< Отключить проверки на потерянные фазы
#define ZC_DISABLE_HYSTERESIS_DEBOUNCE ///< Отключить гиситерезис и дребезг на определении перехода через ноль
/** //UPP_PARAMS_TEST
* @}
*/

View File

@ -7,36 +7,49 @@
******************************************************************************/
#include "adc_tools.h"
static void ADC_EnableAllFilters(ADC_Periodic_t *adc)
{
for(int i = 0; i < ADC_NUMB_OF_CHANNELS; i++)
{
Filter_Start(&adc->filter[i]);
// FilterExpInt_Process(&adc->filter[i], adc->Coefs[i].lZero);
}
}
static void ADC_InitAllFilters(ADC_Periodic_t *adc)
{
// Filter_Init(&adc->filter[ADC_CHANNEL_UBA], coefs_biquad_U);
// Filter_Init(&adc->filter[ADC_CHANNEL_UAC], coefs_biquad_U);
// Filter_Init(&adc->filter[ADC_CHANNEL_IC], coefs_biquad_I);
// Filter_Init(&adc->filter[ADC_CHANNEL_IA], coefs_biquad_I);
// Filter_Init(&adc->filter[ADC_CHANNEL_TEMP1], coefs_biquad_T);
// Filter_Init(&adc->filter[ADC_CHANNEL_TEMP2], coefs_biquad_T);
for(int i = 0; i < ADC_NUMB_OF_CHANNELS; i++)
// FilterBandPassDerivative_Init(&adc->u_fltr[U_AB], (50.0f*PM_FAST_PERIOD_US/1000000), 0.1);
// FilterBandPassDerivative_Init(&adc->u_fltr[U_CA], (50.0f*PM_FAST_PERIOD_US/1000000), 0.1);
//
// FilterMedianInt_Init(&adc->i_fltr[I_C], 5, 2048);
// FilterMedianInt_Init(&adc->i_fltr[I_A], 5, 2048);
//
// FilterLUT_Init(&adc->temp_map[TEMP_1],
// (float *)adc_temp_quants,
// (float *)adc_temp_vals,
// numbof(adc_temp_quants), 1);
// FilterLUT_Init(&adc->temp_map[TEMP_2],
// (float *)adc_temp_quants,
// (float *)adc_temp_vals,
// numbof(adc_temp_quants), 1);
// Инициализация фильтров
for(int i = 0; i < 2; i++)
{
Filter_Init(&adc->filter[i], Filter_Initializator);
FilterBandPassDerivative_Init(&adc->u_fltr[i], (50.0f*PM_FAST_PERIOD_US/1000000), 0.1);
FilterMedianInt_Init(&adc->i_fltr[I_C], 5, 2048);
FilterLUT_Init(&adc->temp_map[i],
(float *)adc_temp_quants,
(float *)adc_temp_vals,
numbof(adc_temp_quants), 1);
}
// Запуск фильтров
for(int i = 0; i < 2; i++)
{
Filter_Start(&adc->u_fltr[i]);
Filter_Start(&adc->i_fltr[i]);
Filter_Start(&adc->temp_map[i]);
}
FilterLUT_Init(&adc->temp_map[0],
(float *)adc_temp_quants,
(float *)adc_temp_vals,
numbof(adc_temp_quants), 1);
FilterLUT_Init(&adc->temp_map[1],
(float *)adc_temp_quants,
(float *)adc_temp_vals,
numbof(adc_temp_quants), 1);
}
__STATIC_FORCEINLINE void ADC_FilterRaw(ADC_Periodic_t *adc, int ch_start, int ch_end)
{
}
/**
* @brief Инициализация периодического АЦП.
* @param adc Указатель на кастомный хендл АЦП
@ -111,17 +124,13 @@ HAL_StatusTypeDef ADC_Start(ADC_Periodic_t *adc, float PeriodUs)
{
return res;
}
// Запускаем АЦП который будет перекидывать данные в ADC_DMA_Buffer
res = HAL_ADC_Start_DMA(adc->hadc, (uint32_t*)adc->RawData, 6); // Затем АЦП с DMA
// Запускаем АЦП который будет перекидывать данные в DMA буфер RawData
res = HAL_ADC_Start_DMA(adc->hadc, (uint32_t*)adc->RawData, 6);
if(res != HAL_OK)
{
return res;
}
ADC_EnableAllFilters(adc);
Filter_Start(&adc->temp_map[0]);
Filter_Start(&adc->temp_map[1]);
return res;
}
/**
@ -139,6 +148,39 @@ HAL_StatusTypeDef ADC_Stop(ADC_Periodic_t *adc)
return HAL_TIM_Base_Stop(adc->htim);
}
/**
* @brief Обновление напряжений АЦП.
* @return HAL Status.
*/
HAL_StatusTypeDef ADC_UpdateRegular(ADC_Periodic_t *adc)
{
if(assert_upp(adc))
return HAL_ERROR;
ADC_Coefs_t *coefs = adc->Coefs;
uint16_t *raw = adc->RawData;
float *data = adc->Data;
// Фильтрация от импульсных шумов каналов токов (напряжения позже фильтруются полосовым фильтром)
for(int i = 0; i < 2; i++)
{
int u_ind = ADC_U_CHANNELS_START + i;
int i_ind = ADC_I_CHANNELS_START + i;
// заменяем сырые данные на отфильтрованные данные
raw[u_ind] = Filter_Process(&adc->u_fltr[i], raw[u_ind]);
raw[i_ind] = Filter_Process(&adc->i_fltr[i], raw[i_ind]);
}
// Перерасчеты Напряжений/Токов в единицы измерения
for(int i = ADC_U_CHANNELS_START; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
{
ADC_Coefs_t *coefs = &adc->Coefs[i];
data[i] = ((float)(raw[i])-coefs->lZero) * coefs->vMax / (coefs->lMax-coefs->lZero);
}
return HAL_OK;
}
/**
@ -152,56 +194,12 @@ HAL_StatusTypeDef ADC_UpdateTemperatures(ADC_Periodic_t *adc)
float *data = adc->Data;
uint16_t *raw = adc->RawData;
// Фильтрация от импульсных шумов для каналов напряжения/токов
for(int i = ADC_TEMP_CHANNELS_START; i < ADC_NUMB_OF_CHANNELS; i++)
{
// заменяем сырые данные на отфильтрованные данные
raw[i] = Filter_Process(&adc->filter[i], raw[i]);
}
// Преобразования температуры по таблице
for (int i = ADC_TEMP_CHANNELS_START; i < ADC_NUMB_OF_CHANNELS; i++)
for (int i = ADC_TEMP_CHANNELS_START; i < ADC_TEMP_CHANNELS_END; i++)
{
data[i] = Filter_Process(&adc->temp_map[i-ADC_TEMP_CHANNELS_START], raw[i]);
}
return HAL_OK;
}
/**
* @brief Обработка АЦП.
* @return HAL Status.
* @note Вызывается в DMA2_Stream0_IRQHandler() для обработки напряжений/токов,
которые пришли по DMA.
*/
HAL_StatusTypeDef ADC_Handle(ADC_Periodic_t *adc)
{
if(assert_upp(adc))
return HAL_ERROR;
ADC_Coefs_t *coefs = adc->Coefs;
uint16_t *raw = adc->RawData;
float *data = adc->Data;
// Фильтрация от импульсных шумов для каналов напряжения/токов
for(int i = 0; i < ADC_NUMB_OF_CHANNELS; i++)
{
// заменяем сырые данные на отфильтрованные данные
raw[i] = Filter_Process(&adc->filter[i], raw[i]);
}
// Перерасчеты Напряжений/Токов в единицы измерения
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
{
ADC_Coefs_t *coefs = &adc->Coefs[i];
data[i] = ((float)(raw[i])-coefs->lZero) * coefs->vMax / (coefs->lMax-coefs->lZero);
}
// if(Filter_isDataReady(&adc->filter[0]))
// adc->f.DataReady = 1;
return HAL_OK;
}

View File

@ -18,12 +18,19 @@
#define ADC_CHANNEL_TEMP2 5
#define ADC_NUMB_OF_CHANNELS 6
#define ADC_NUMB_OF_U_CHANNELS 2
#define ADC_NUMB_OF_I_CHANNELS 2
#define ADC_NUMB_OF_T_CHANNELS 2
#define ADC_NUMB_OF_CHANNELS 6
#define ADC_NUMB_OF_U_CHANNELS 2
#define ADC_NUMB_OF_I_CHANNELS 2
#define ADC_NUMB_OF_T_CHANNELS 2
#define ADC_NUMB_OF_REGULAR_CHANNELS (ADC_NUMB_OF_U_CHANNELS+ADC_NUMB_OF_I_CHANNELS)
#define ADC_TEMP_CHANNELS_START ADC_NUMB_OF_REGULAR_CHANNELS
#define ADC_U_CHANNELS_START 0
#define ADC_U_CHANNELS_END 1
#define ADC_I_CHANNELS_START 2
#define ADC_I_CHANNELS_END 3
#define ADC_TEMP_CHANNELS_START 4
#define ADC_TEMP_CHANNELS_END 5
#define ADC_TEMPERATURES_QUANTS \
{ 2188, 2197, 2206, 2216, 2226, 2236, 2247, 2259, 2271, 2283, \
@ -50,11 +57,7 @@
static const float adc_temp_vals[] = ADC_TEMPERATURES;
static const float adc_temp_quants[] = ADC_TEMPERATURES_QUANTS;
#define Filter_t FilterMedianInt_t
#define Filter_Init FilterMedianInt_Init
#define Filter_Initializator 5, 2048
/**
* @brief Коэфициенты канала АЦП для пересчета в единицы измерения
*/
@ -100,9 +103,9 @@ typedef struct
uint16_t RawData[ADC_NUMB_OF_CHANNELS]; ///< Сырые значения АЦП
ADC_Coefs_t Coefs[ADC_NUMB_OF_REGULAR_CHANNELS]; ///< Коэффициенты @ref ADC_Coefs_t для регулярных каналов (не температуры)
Filter_t filter[ADC_NUMB_OF_CHANNELS]; ///< Фильтр от шумов АЦП
FilterLUT_t temp_map[2]; ///< Коррекция нелинейности датчиков температуры
FilterBandPassDerivative_t u_fltr[ADC_NUMB_OF_U_CHANNELS]; ///< Полосовой Фильтр Напряжений от шумов
FilterMedianInt_t i_fltr[ADC_NUMB_OF_I_CHANNELS]; ///< Медианный Фильтр Токов от шумов
FilterLUT_t temp_map[ADC_NUMB_OF_T_CHANNELS]; ///< Коррекция нелинейности датчиков температуры
float Data[ADC_NUMB_OF_CHANNELS]; ///< Пересчитанные значения АЦП (в Вольтах/Амперах)
@ -128,6 +131,6 @@ HAL_StatusTypeDef ADC_Stop(ADC_Periodic_t *adc);
/* Обновление температур АЦП. */
HAL_StatusTypeDef ADC_UpdateTemperatures(ADC_Periodic_t *adc);
/* Обработка АЦП после получения данных. */
HAL_StatusTypeDef ADC_Handle(ADC_Periodic_t *adc);
HAL_StatusTypeDef ADC_UpdateRegular(ADC_Periodic_t *adc);
#endif //_ADC_TOOLS_H_

View File

@ -125,6 +125,7 @@ void PowerMonitor_SlowCalc(PowerMonitor_t *hpm)
/* Расчет всякого для трех фаз отдельно */
float fmean = 0; // средняя частота по трем фазам
float umean = 0; // средний напряжение по трем фазам
float imean = 0; // средний ток по трем фазам
float iphase_mean = 0; // средний ток каждой фазы
float uphase_mean = 0; // среднее напряжение каждой фазы
@ -134,21 +135,15 @@ void PowerMonitor_SlowCalc(PowerMonitor_t *hpm)
for(int i = 0; i < 3; i++)
{
/* Получение частоты фазы */
meas->final.F[i] = Filter_Process(&hpm->avg[AVG_FAB+i], ZC_GetFrequency(&hpm->zc, i));
meas->final.Offset[i] = ZC_GetOffset(&hpm->zc, i);
meas->final.F[i] = Filter_Process(&hpm->avg[AVG_F+i], ZC_GetFrequency(&hpm->zc, i));
// meas->final.Offset[i] = ZC_GetOffset(&hpm->zc, i);
fmean += meas->final.F[i];
/* Средниее напряжение фазы */
// uphase_mean = fabsf(meas->slow.U[i]);
// uphase_mean = Filter_Process(&hpm->rms[RMS_UAB+i], uphase_mean);
// meas->final.U[i] = uphase_mean*PI/2/SQRT2; /*PI/2 - получить амплитудное, SQRT2 - получить действующее */
uphase_mean = Filter_Process(&hpm->rms[RMS_U+i], meas->slow.U[i]);
meas->final.U[i] = Filter_Process(&hpm->rms_exp[RMS_U+i], uphase_mean);
/* Средний ток фазы */
// iphase_mean = fabsf(meas->slow.I[i]);
// iphase_mean = Filter_Process(&hpm->rms[RMS_IC+i], iphase_mean)*PI/2;
// meas->final.I[i] = iphase_mean*PI/2/SQRT2; /*PI/2 - получить амплитудное, SQRT2 - получить действующее */
iphase_mean = Filter_Process(&hpm->rms[RMS_I+i], meas->slow.I[i]);
meas->final.I[i] = Filter_Process(&hpm->rms_exp[RMS_I+i], iphase_mean);
imean += meas->final.I[i];
@ -159,23 +154,24 @@ void PowerMonitor_SlowCalc(PowerMonitor_t *hpm)
}
/* Получение средней частоты по трем фазам */
meas->final.Fmean = fmean / 3;
/* Оределение сдвига фаз */
static uint32_t prev_tick_phase_a = 0;
if(prev_tick_phase_a != hpm->zc.Channel[0].PeriodStartTime)
{ // Определяем только когда начался новый период фазы A
prev_tick_phase_a = hpm->zc.Channel[0].PeriodStartTime;
meas->final.Phase[0] = 0;
meas->final.Phase[1] = ZC_GetPhaseShift(&hpm->zc, 0, 1);
meas->final.Phase[2] = ZC_GetPhaseShift(&hpm->zc, 0, 2);
}
// /* Оределение сдвига фаз */
// static uint32_t prev_tick_phase_a = 0;
// if(prev_tick_phase_a != hpm->zc.Channel[0].PeriodStartTime)
// { // Определяем только когда начался новый период фазы A
// prev_tick_phase_a = hpm->zc.Channel[0].PeriodStartTime;
// meas->final.Phase[0] = 0;
// meas->final.Phase[1] = ZC_GetPhaseShift(&hpm->zc, 0, 1);
// meas->final.Phase[2] = ZC_GetPhaseShift(&hpm->zc, 0, 2);
// }
/* Расчет амплитуд трехфазной сети */
float uamp = vector_abs_linear_calc(meas->slow.U[U_AB], meas->slow.U[U_CA])/SQRT2; /* SQRT2 - получить действующее */
// float uamp = vector_abs_linear_calc(meas->slow.U[U_AB], meas->slow.U[U_CA])/SQRT2; /* SQRT2 - получить действующее */
// float iamp = vector_abs_phase_calc(meas->slow.I[I_A], meas->slow.I[I_C]);
float uamp = umean / 3;
float iamp = imean / 3;
meas->final.Uamp = Filter_Process(&hpm->rms_exp[RMS_EXP_U], uamp);
meas->final.Iamp = Filter_Process(&hpm->rms_exp[RMS_EXP_I], iamp);
meas->final.Uamp = uamp;//Filter_Process(&hpm->rms_exp[RMS_EXP_U], uamp);
meas->final.Iamp = iamp;//Filter_Process(&hpm->rms_exp[RMS_EXP_I], iamp);
hpm->slow_cnt++;
@ -197,7 +193,7 @@ void PowerMonitor_FastCalc(PowerMonitor_t *hpm)
PowerMonitor_Measured_t *meas = &hpm->measured;
/* Считываем АЦП с пересчетами и медианой фильтрацией от выбросов */
ADC_Handle(&hpm->adc);
ADC_UpdateRegular(&hpm->adc);
/* Заполняем Напряжения/Токи в о.е. */
float uba_fast = hpm->adc.Data[ADC_CHANNEL_UBA]/u_base;

View File

@ -103,6 +103,7 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin
zc_ch->CurrentValue = value;
#ifndef ZC_DISABLE_HYSTERESIS_DEBOUNCE
// Фильтрация дребезга
if(zc_ch->DebounceCounter > 0)
{
@ -144,6 +145,25 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin
zc_detected = -1;
}
}
#else //ZC_DISABLE_HYSTERESIS_DEBOUNCE
// Детектирование rising edge (отрицательное -> положительное)
if ((zc_ch->LastValue < 0) &&
(value > 0))
{
if (zc_ch->EdgeType == ZC_RISING_EDGE || zc_ch->EdgeType == ZC_BOTH_EDGES) {
zc_detected = 1;
}
}
// Детектирование falling edge (положительное -> отрицательное)
else if ((zc_ch->LastValue > 0) &&
(value < 0))
{
if (zc_ch->EdgeType == ZC_FALLING_EDGE || zc_ch->EdgeType == ZC_BOTH_EDGES) {
zc_detected = -1;
}
}
#endif //ZC_DISABLE_HYSTERESIS_DEBOUNCE
if(zc_detected)
{
@ -172,11 +192,15 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin
zc_ch->CrossCount++;
}
#ifndef ZC_DISABLE_HYSTERESIS_DEBOUNCE
// Сохраняем текущее значение для следующей итерации в случае если оно не в мертвой зоне
if((value > zc->Config.Hysteresis) || (value < -zc->Config.Hysteresis))
{
zc_ch->LastValue = value;
}
#else //ZC_DISABLE_HYSTERESIS_DEBOUNCE
zc_ch->LastValue = value;
#endif //ZC_DISABLE_HYSTERESIS_DEBOUNCE
}
/**

View File

@ -87,7 +87,7 @@ int main(void)
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
#ifndef MATLAB

View File

@ -323,37 +323,37 @@ static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Channel_t *hCh, uint32_t state
if (hCh->htim == NULL)
return HAL_ERROR;
uint32_t ch_mode = state;
// Если режим уже выставлен
if(hCh->CurrentMode == state)
{
return HAL_OK;
}
hCh->CurrentMode = state;
// выставляем режим каналов
switch(hCh->ChMask)
{
case TIM_CHANNEL_1:
hCh->htim->Instance->CCMR1 &= ~TIM_OCMODE_PWM2;
hCh->htim->Instance->CCMR1 |= ch_mode;
hCh->htim->Instance->CCMR1 |= state;
break;
case TIM_CHANNEL_2:
hCh->htim->Instance->CCMR1 &= ~(TIM_OCMODE_PWM2 << 8);
hCh->htim->Instance->CCMR1 |= (ch_mode << 8);
hCh->htim->Instance->CCMR1 |= (state << 8);
break;
case TIM_CHANNEL_3:
hCh->htim->Instance->CCMR2 &= ~TIM_OCMODE_PWM2;
hCh->htim->Instance->CCMR2 |= ch_mode;
hCh->htim->Instance->CCMR2 |= state;
break;
case TIM_CHANNEL_4:
hCh->htim->Instance->CCMR2 &= ~(TIM_OCMODE_PWM2 << 8);
hCh->htim->Instance->CCMR2 |= (ch_mode << 8);
hCh->htim->Instance->CCMR2 |= (state << 8);
break;
default:
break;
}
// в последнюю очередь включаем выход. Перед этим настраиваем каналы на ШИМ
if(state == PWM_ENABLE)
{
__HAL_TIM_MOE_ENABLE(hCh->htim);
}
return HAL_OK;
}

View File

@ -54,6 +54,7 @@ typedef struct {
TIM_HandleTypeDef *htim; ///< указатель на соответствующий TIM (hpwm1 или hpwm2)
uint32_t PulseCnt; ///< Счетчик кол-ва импульсов. Инициализируется из структуры @ref PWM_ThyrConfig_t
uint32_t ChMask; ///< TIM_CHANNEL_x
uint32_t CurrentMode; ///< Текущий режим канала
struct {
unsigned Ready:1; ///< Флаг готовности тиристора к работе

View File

@ -175,6 +175,9 @@ int UPP_While(void)
/*======= Состояние В работе =========*/
case UPP_Work:
// Разрешаем выход ШИМ
__HAL_TIM_MOE_ENABLE(&hpwm1);
__HAL_TIM_MOE_ENABLE(&hpwm2);
// Индикация
UPP_DO.Ready(DISABLE);
UPP_DO.Work(ENABLE);

View File

@ -385,7 +385,7 @@
<Ww>
<count>11</count>
<WinNumber>1</WinNumber>
<ItemText>\\Debug_F417\../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c\uwTick</ItemText>
<ItemText>\\Debug_F417\../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c\uwTick,0x0A</ItemText>
</Ww>
<Ww>
<count>12</count>
@ -494,6 +494,21 @@
<WinNumber>2</WinNumber>
<ItemText>upp,0x0A</ItemText>
</Ww>
<Ww>
<count>14</count>
<WinNumber>2</WinNumber>
<ItemText>htim5,0x0A</ItemText>
</Ww>
<Ww>
<count>15</count>
<WinNumber>2</WinNumber>
<ItemText>htim3,0x0A</ItemText>
</Ww>
<Ww>
<count>16</count>
<WinNumber>2</WinNumber>
<ItemText>htim5.Instance-&gt;CNT-2605346416,0x0A</ItemText>
</Ww>
</WatchWindow2>
<Tracepoint>
<THDelay>0</THDelay>
@ -515,7 +530,7 @@
<AscS3>0</AscS3>
<aSer3>0</aSer3>
<eProf>0</eProf>
<aLa>1</aLa>
<aLa>0</aLa>
<aPa1>0</aPa1>
<AscS4>0</AscS4>
<aSer4>0</aSer4>