Какие-то тесты и построение алгоритма. Но ничего прям интересного

This commit is contained in:
Razvalyaev 2025-11-17 01:38:12 +03:00
parent b0813fb7e8
commit b236975f9b
22 changed files with 349 additions and 192 deletions

View File

@ -9,7 +9,7 @@
#endif
#ifdef STM32F4
#define ADC_NOISE_LSB 10 // Шум в LSB (квантах АЦП)
#define ADC_NOISE_LSB 3 // Шум в LSB (квантах АЦП)
#endif
/////////////////////////////---STRUCTURES---///////////////////////////

View File

@ -59,7 +59,7 @@
#define OUT_PORT_NUMB 3
#define THYR_PORT_1_WIDTH 6
#define PM_PORT_2_WIDTH 16
#define PM_PORT_2_WIDTH 32
#define OUT_PORT_3_WIDTH 16
// INPUT/OUTPUTS PARAMS END

View File

@ -32,25 +32,31 @@ void Write_PowerMonitor(real_T* Buffer, int ind_port)
{
int nn = 0;
for (int i = 0; i < 3; i++)
{
WriteOutputArray(upp.pm.U[i], ind_port, nn++);
{ //0-2
WriteOutputArray(upp.pm.measured.Ureal[i], ind_port, nn++);
}
for (int i = 0; i < 3; i++)
{
{ //3-5
WriteOutputArray(upp.pm.zc.Channel[i].HalfWave, ind_port, nn++);
}
for (int i = 0; i < 3; i++)
{
WriteOutputArray(upp.pm.F[i], ind_port, nn++);
{ //6-8
WriteOutputArray(upp.pm.measured.F[i], ind_port, nn++);
}
for (int i = 0; i < 3; i++)
{
WriteOutputArray(upp.pm.I[i], ind_port, nn++);
{ //9-11
WriteOutputArray(upp.pm.measured.Ireal[i], ind_port, nn++);
}
for (int i = 0; i < 2; i++)
{
WriteOutputArray(upp.pm.T[i], ind_port, nn++);
{ //12-13
WriteOutputArray(upp.pm.measured.T[i], ind_port, nn++);
}
{ //14-16
WriteOutputArray(upp.pm.measured.U_mean, ind_port, nn++);
WriteOutputArray(upp.pm.measured.I_mean, ind_port, nn++);
WriteOutputArray(upp.pm.measured.F_mean, ind_port, nn++);
}
}
/**
* @brief Функция для записи входов в приложение МК

View File

@ -1,7 +1,7 @@
clear all
Ts = 5e-6;
Vnom = 380;
Vnom = 690;
Fnom = 50;
Temperature1 = 2.22; % 20 градусов

Binary file not shown.

@ -1 +1 @@
Subproject commit 99652a9ad5ea0686ad9242b165508a9d92ac80a1
Subproject commit 9bff9ad44dd625819ef654e98ca351d5bc5568a9

View File

@ -23,7 +23,7 @@
#include "modbus_devid.h"
/* DEFINE DATA FOR MODBUS */
MB_DataStructureTypeDef MB_DATA = {0};; ///< Coils & Registers
MB_DataStructureTypeDef MB_DATA = {0}; ///< Coils & Registers
MB_DataInternalTypeDef MB_INTERNAL;
/**

View File

@ -65,7 +65,7 @@
//#define FILTER_MEDIAN_MAX_SIZE ///< Максимальный размер окна медианного фильтра (по умолчанию 5)
//#define FILTER_AVERAGE_MAX_SIZE ///< Максимальный размер окна усредняющего фильтра (по умолчанию 8)
//#define FILTER_POLY_MAX_ORDER ///< Максимальный порядок полинома (по умолчанию 4)
#define FILTERS_DISABLE_MOVING_AVERAGE
/** GEN_CONFIG
* @}
*/
@ -96,9 +96,12 @@
*/
//#define BENCH_TIME_ENABLE ///< Включить бенч времени
#define BENCH_TIME_MAX_CHANNELS 16 ///< Максимальное количество каналов измерения
#define BENCH_TIME_ENABLE ///< Включить бенч времени
#define BENCH_TIME_MAX_CHANNELS 5 ///< Максимальное количество каналов измерения
#define BT_ADC 0
#define BT_PWM 1
#define BT_SYSTICK 2
/** GEN_CONFIG
* @}
*/
@ -133,7 +136,7 @@ extern float dbg[16];
#define INCLUDE_TRACKERS_LIB ///< Подключить библиотеку с трекерами
//#define INCLUDE_TRACE_LIB ///< Подключить библиотеку с трейсами
#define INCLUDE_GENERAL_PERIPH_LIBS ///< Подключить библиотеку с периферией
//#define INCLUDE_BENCH_TIME ///< Подключить библиотеку с бенчмарком времени
#define INCLUDE_BENCH_TIME ///< Подключить библиотеку с бенчмарком времени
#define INCLUDE_FILTERS ///< Подключить библиотеку с фильтрами
#endif //MATLAB

View File

@ -34,6 +34,19 @@
* @brief Дефолтные параметры для внешней памяти. Они применятся по команде или по ошибке
* @{
*/
/* Параметри мониторинга сети */
#define PM_EXP_ALPHA_COEF_DEFAULT 0.01
/* Номинальные параметры */
#define NOM_PHASE_NUMB 3
#define NOM_U_V_DEFAULT 690
#define NOM_U_DEVIATION_PLUS_PERCENT_DEFAULT 6
#define NOM_U_DEVIATION_MINUS_PERCENT_DEFAULT 10
#define NOM_F_HZ_DEFAULT 50
#define NOM_F_DEVIATION_PLUS_PERCENT_DEFAULT 5
#define NOM_F_DEVIATION_MINUS_PERCENT_DEFAULT 5
#define NOM_I_A_DEFAULT 5
/* Параметры ПУИ */
#define PUI_Iref_PERCENT_DEFAULT 150
#define PUI_Tnt_MS_DEFAULT 300
@ -52,8 +65,8 @@
#define ADC_I_ZERO_DEFAULT 2048
/* Параметры определения перехода через ноль */
#define ZERO_CROSS_HYSTERESIS_V_DEFAULT 10.0
#define ZERO_CROSS_DEBOUNCE_10US_DEFAULT 2.5*100 // (2.5 * 100 = 2.5 мс)
#define ZERO_CROSS_HYSTERESIS_PERCENT_DEFAULT 2.0
#define ZERO_CROSS_DEBOUNCE_10US_DEFAULT 2*100 // (2.5 * 100 = 2.5 мс)
/* Параметры ШИМ для тиристоров */
#define PWM_THYR_FREQUENCY_HZ_DEFAULT 20000
@ -70,11 +83,11 @@
* @brief Параметры устанавливаемые на этапе компиляции. Без перепрошивки их не поменять
* @{
*/
#define PM_U_NOM_V 690
#define PM_I_NOM_V 5
#define PM_F_NOM_HZ 50
/* Периоды вызова всякого */
#define PM_ADC_PERIOD_US 10 ///< Период опроса АЦП в мкс
#define PM_SLOW_PERIOD_10US 50 ///< Период обновление медленных расчетов в 10мкс
#define PM_TEMP_PERIOD_10US 5000 ///< Период обновление датчиков температуры в 10мкс
#define PM_ADC_PERIOD_MKS 10 ///< Период опроса АЦП в мкс
/* Частоты таймеров в МГц*/
#define ADC_TIM8_FREQ_MZH 180 ///< Частота тиков таймера АЦП
#define PWM_TIM1_FREQ_MHZ 180 ///< Частота тиков таймера ШИМ (1-4 каналы)

View File

@ -29,7 +29,8 @@ typedef enum {
WM_Not_Init = 0, ///< УПП не инициализирован
WM_Ready = 1, ///< УПП в готовности
WM_Running = 2, ///< УПП в работе, управляет тиристорами
WM_Error = 3, ///< УПП в аварии
WM_Done = 3, ///< УПП закончил свою работу
WM_Error = 4, ///< УПП в аварии
} UPP_WorkModeType_t;
/**
@ -147,7 +148,8 @@ typedef struct {
* @brief Дефайны УПП которые используютяс исключительно внутри программы
* @{
*/
#define ANGLE_PERIOD_MS (((float)1/(PM_F_NOM_HZ*2))*1000)
#define ANGLE_PERIOD_MS(_freq_) (((float)1/(_freq_*2))*1000)
/**
* @brief Состояния полуволны
*/

View File

@ -156,7 +156,7 @@ HAL_StatusTypeDef ADC_Handle(ADC_Periodic_t *adc)
{
ADC_Coefs_t *coefs = &adc->Coefs[i];
data[i] = ((float)(raw[i])-coefs->lZero) * coefs->vMax / (coefs->lMax-coefs->lZero);
ADC_UpdateStatistics(adc, i, ADC_LEVEL_AC);
// ADC_UpdateStatistics(adc, i, ADC_LEVEL_AC);
}
// Фильтрация от шумов для всех каналов
@ -169,19 +169,15 @@ HAL_StatusTypeDef ADC_Handle(ADC_Periodic_t *adc)
}
}
// Преобразования температуры по таблице
for (int i = ADC_TEMP_CHANNELS_START; i < ADC_NUMB_OF_CHANNELS; i++)
{
data[i] = Filter_Process(&adc->temp_map[i-ADC_TEMP_CHANNELS_START], raw[i]);
ADC_UpdateStatistics(adc, i, ADC_LEVEL_BASE);
// ADC_UpdateStatistics(adc, i, ADC_LEVEL_BASE);
}
if(Filter_isDataReady(&adc->filter[0]))
adc->f.DataReady = 1;
return HAL_OK;
}
@ -221,7 +217,7 @@ void ADC_UpdateStatistics(ADC_Periodic_t *adc, uint8_t channel, ADC_StatLevel_t
}
// Накопление для Avg/RMS
stat->Sum += value;
stat->Sum += ABS(value);
stat->SumSquares += value * value;
stat->SampleCount++;

View File

@ -67,7 +67,7 @@ typedef struct
typedef enum
{
ADC_LEVEL_DISABLE=0, ///< Базовая статистика - Max/Min
ADC_LEVEL_DISABLE=0, ///< Статистика отключена
ADC_LEVEL_BASE, ///< Базовая статистика - Max/Min
ADC_LEVEL_AC, ///< Статистика для переменных сигналов - AVG, RMS
}ADC_StatLevel_t;

View File

@ -12,9 +12,14 @@
HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
{
if(hpm == NULL)
return HAL_ERROR;
/* Инициализация АЦП */
if(ADC_Init(&hpm->adc, &adc_tim, &hadc3) != HAL_OK)
return HAL_ERROR;
/* Инициализация каналов АЦП */
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_UBA,
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_UBA],
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UBA],
@ -40,9 +45,11 @@ HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
return HAL_ERROR;
/* Инициализация алгоритма перехода через ноль */
if(ZC_Init(&hpm->zc, 3, (float)MB_INTERNAL.param.zc.Hysteresis/100, MB_INTERNAL.param.zc.DebouneCouner) != HAL_OK)
return HAL_ERROR;
/* Инициализация каналов алгоритма перехода через ноль */
if(ZC_ConfigChannel(&hpm->zc, U_BA, ZC_BOTH_EDGES) != HAL_OK)
return HAL_ERROR;
if(ZC_ConfigChannel(&hpm->zc, U_AC, ZC_BOTH_EDGES) != HAL_OK)
@ -50,41 +57,136 @@ HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
if(ZC_ConfigChannel(&hpm->zc, U_BC, ZC_BOTH_EDGES) != HAL_OK)
return HAL_ERROR;
/* Инициализация экпоненциального фильтра медленного алга */
for(int i = 0; i < 3; i++)
{
if(FilterExp_Init(&hpm->measured.exp[i], (float)MB_INTERNAL.param.pm.mean_alpha/65535))
return HAL_ERROR;
Filter_Start(&hpm->measured.exp[i]);
}
/* Инициализация среднего фильтра медленного алга */
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
{
if(FilterAverage_Init(&hpm->measured.avg[i], PM_SLOW_PERIOD_10US, FILTER_MODE_DEFAULT))
return HAL_ERROR;
Filter_Start(&hpm->measured.avg[i]);
}
for(int i = 0; i < ADC_NUMB_OF_T_CHANNELS; i++)
{
if(FilterAverage_Init(&hpm->measured.avg[ADC_TEMP_CHANNELS_START+i], PM_TEMP_PERIOD_10US, FILTER_MODE_DEFAULT))
return HAL_ERROR;
Filter_Start(&hpm->measured.avg[ADC_TEMP_CHANNELS_START+i]);
}
return HAL_OK;
}
HAL_StatusTypeDef PowerMonitor_Start(PowerMonitor_t *hpm)
{
if(ADC_Start(&hpm->adc, PM_ADC_PERIOD_MKS) != HAL_OK)
if(hpm == NULL)
return HAL_ERROR;
if(ADC_Start(&hpm->adc, PM_ADC_PERIOD_US) != HAL_OK)
return HAL_ERROR;
return HAL_OK;
}
void PowerMonitor_SlowHandle(PowerMonitor_t *hpm)
{
if(hpm == NULL)
return;
if(!hpm->f.runSlow)
return;
hpm->f.runSlow = 0;
PowerMonitor_Measured_t *meas = &hpm->measured;
meas->Uslow[U_BC] = -meas->Uslow[U_BA] - meas->Uslow[U_AC];
meas->Islow[I_B] = -meas->Islow[I_A] - meas->Islow[I_C];
float umean = 0;
float imean = 0;
float fmean = 0;
for(int i = 0; i < 3; i++)
{
umean += ABS(meas->Uslow[i]);
imean += ABS(meas->Islow[i]);
fmean += ABS(meas->F[i]);
}
umean /=3;
imean /=3;
fmean /=3;
meas->U_mean = Filter_Process(&meas->exp[0], umean);
meas->I_mean = Filter_Process(&meas->exp[1], imean);
meas->F_mean = Filter_Process(&meas->exp[2], fmean);
}
void PowerMonitor_Handle(PowerMonitor_t *hpm)
{
if(hpm == NULL)
return;
/* Считываем АЦП */
static uint32_t last_zc_cnt[ADC_NUMB_OF_U_CHANNELS] = {0};
ADC_Handle(&hpm->adc);
hpm->U[U_BA] = hpm->adc.Data[ADC_CHANNEL_UBA];
hpm->U[U_AC] = hpm->adc.Data[ADC_CHANNEL_UAC];
hpm->U[U_BC] = -hpm->U[U_BA] - hpm->U[U_AC];
hpm->I[I_C] = hpm->adc.Data[ADC_CHANNEL_IC];
hpm->I[I_A] = hpm->adc.Data[ADC_CHANNEL_IA];
hpm->I[I_B] = -hpm->I[I_A] - hpm->I[I_C];
/* Заполняем величины */
PowerMonitor_Measured_t *meas = &hpm->measured;
meas->Ureal[U_BA] = hpm->adc.Data[ADC_CHANNEL_UBA];
meas->Ureal[U_AC] = hpm->adc.Data[ADC_CHANNEL_UAC];
meas->Ureal[U_BC] = -meas->Ureal[U_BA] - meas->Ureal[U_AC];
meas->Ireal[I_C] = hpm->adc.Data[ADC_CHANNEL_IC];
meas->Ireal[I_A] = hpm->adc.Data[ADC_CHANNEL_IA];
meas->Ireal[I_B] = -meas->Ireal[I_A] - meas->Ireal[I_C];
meas->T[TEMP_1] = hpm->adc.Data[ADC_CHANNEL_TEMP1];
meas->T[TEMP_2] = hpm->adc.Data[ADC_CHANNEL_TEMP2];
hpm->T[TEMP_1] = hpm->adc.Data[ADC_CHANNEL_TEMP1];
hpm->T[TEMP_2] = hpm->adc.Data[ADC_CHANNEL_TEMP2];
ZC_ProcessAllChannels(&hpm->zc, hpm->U, usTick);
/* Преобразуем в относительные единицы (о.е.) */
for(int i = 0; i < 3; i++)
{
meas->U[i] = 10*meas->Ureal[i]/MB_INTERNAL.param.nominal.U;
meas->I[i] = 10*meas->Ireal[i]/MB_INTERNAL.param.nominal.I;
}
hpm->F[i] = ZC_GetFrequency(&hpm->zc, i) / 2;
/* Ищем переход через ноль */
ZC_ProcessAllChannels(&hpm->zc, meas->U, usTick);
for(int i = 0; i < 3; i++)
{
meas->F[i] = ZC_GetFrequency(&hpm->zc, i) / 2;
}
/* Накопление Average для медленной фильтрации */
meas->Uslow[U_BA] = Filter_Process(&meas->avg[0], meas->U[U_BA]);
meas->Uslow[U_AC] = Filter_Process(&meas->avg[1], meas->U[U_AC]);
meas->Islow[I_C] = Filter_Process(&meas->avg[2], meas->I[I_C]);
meas->Islow[I_A] = Filter_Process(&meas->avg[3], meas->I[I_A]);
meas->T[TEMP_1] = Filter_Process(&meas->avg[4], meas->T[TEMP_1]);
meas->T[TEMP_2] = Filter_Process(&meas->avg[5], meas->T[TEMP_2]);
/* Запускаем медленную обработку через slow_period прерываний */
// if(hpm->isr_cnt == PM_SLOW_PERIOD_10US)
/* Запускаем медленную когда фильтры среднего зациклились */
if(Filter_isDataReady(&meas->avg[0]))
{
hpm->isr_cnt = 0;
if(!hpm->f.runSlow)
{
hpm->f.runSlow = 1;
}
else // если уже запущена - ставим overrun slow calc
{
errors.prvt.f.err.slow_calc_overrun = 1;
errors.prvt.cnt.slow_calc_overrun++;
}
}
else
{
hpm->isr_cnt++;
}
}

View File

@ -13,14 +13,55 @@
typedef struct
{
ADC_Periodic_t adc;
ZeroCross_Handle_t zc;
UPP_HalfWave_t CurrentHalfWave[3];
unsigned runSlow:1; ///< Запустить медленный алгоритм в while(1)
float U[3];
float F[3];
float I[3];
float T[2];
unsigned isU:1; ///< Есть ли напряжение
unsigned isI:1; ///< Есть ли ток
unsigned protectUmax:1; ///< Отработка защиты по макс. напряжению
unsigned protectUmin:1; ///< Отработка защиты по мак с. напряжению
unsigned protectImax:1; ///< Отработка защиты по макс. току
unsigned protectImin:1; ///< Отработка защиты по мин. току
}PowerMonitor_Flags_t;
typedef struct
{
float U_mean; ///< Среднее Напряжение по трем фазам
float I_mean; ///< Средний Ток по трем фазам
float F_mean; ///< Средняя Частота по трем фазам
float Uslow[3]; ///< Напряжение от АЦП (в о.е.)
float Islow[3]; ///< Ток от АЦП (в о.е.)
float U[3]; ///< Напряжение от АЦП (в о.е.)
float I[3]; ///< Ток от АЦП (в о.е.)
float F[3]; ///< Частота от Zero Cross
float T[2]; ///< Температура от АЦП
float Ureal[3]; ///< Напряжение от АЦП
float Ireal[3]; ///< Ток от АЦП
FilterExp_t exp[3]; ///< Фильтры для mean
FilterAverage_t avg[6]; ///< Фильтры для avg
}PowerMonitor_Measured_t;
typedef struct
{
}PowerMonitor_Filters_t;
typedef struct
{
ADC_Periodic_t adc; ///< Хендл периодического АЦП
ZeroCross_Handle_t zc; ///< Хендл перехода через ноль
PowerMonitor_Filters_t fltr;
PowerMonitor_Measured_t measured; ///< Измеренные/рассчитанные величины
PowerMonitor_Flags_t f; ///< Флаги мониторинга
uint32_t slow_period;
uint32_t isr_cnt;
}PowerMonitor_t;
extern PowerMonitor_t pm;
@ -28,6 +69,7 @@ extern PowerMonitor_t pm;
HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm);
HAL_StatusTypeDef PowerMonitor_Start(PowerMonitor_t *hpm);
void PowerMonitor_SlowHandle(PowerMonitor_t *hpm);
void PowerMonitor_Handle(PowerMonitor_t *hpm);
#endif /* _POWER_MONITOR_H_ */

View File

@ -15,6 +15,9 @@ static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Channel_t *hCh, uint32_t state
* @brief Инициализация ШИМ тиристоров.
* @param hpwm Указатель на хендл ШИМ тиристоров
* @return HAL Status.
* @details Инициализируется 6 структур на каждый канал ШИМ для тиристора.
* И одна dummy структура для безопасной инициализации неизвестной фазы.
* В конце запускаются все каналы ШИМ (с запрещенным выходом).
*/
HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm)
{
@ -75,6 +78,7 @@ HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm)
* @param hpwm Указатель на хендл ШИМ тиристоров
* @param Phase На какой фазе надо запустить ШИМ
* @return HAL Status.
* @details Переводит автомат канала ШИМ в состояние запуска ШИМ.
*/
HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
{
@ -91,6 +95,7 @@ HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
switch(hpwm->Phase[Phase]->State)
{
// Если мы НЕ в режиме ожидание - ошибка
case PWM_THYR_DISABLED:
case PWM_THYR_TIM_START:
case PWM_THYR_TIM_ACTIVE:
@ -103,7 +108,7 @@ HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
return HAL_OK;
default:
return HAL_ERROR;;
return HAL_ERROR;
}
return HAL_ERROR;
@ -113,7 +118,11 @@ HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
* @brief Остановить ШИМ.
* @param hpwm Указатель на хендл ШИМ тиристоров
* @param Phase На какой фазе надо остановить ШИМ
* @param force_stop_all Принудительно остановить ВЕСЬ ШИМ
* @return HAL Status.
* @details Переводит автомат канала ШИМ в состояние отключенного ШИМ и
* включает канал в режим форсированного неактивного выхода.
* При передаче 1 в force_stop_all, отключаются все каналы ШИМ и выдается дискрет на запрет ШИМ
*/
HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_stop_all)
{
@ -148,6 +157,7 @@ HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_
* @brief Хендл ШИМ тиристоров.
* @param hpwm Указатель на хендл ШИМ тиристоров
* @return HAL Status.
* @details Автомат состояний, который определяет поведение каналов ШИМ
*/
HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
{
@ -165,22 +175,22 @@ HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
switch (hPhase->State)
{
case PWM_THYR_DISABLED:
case PWM_THYR_DISABLED: // канал отключен
__PWM_SetOutputState(hPhase, PWM_DISABLE);
break;
case PWM_THYR_TIM_WAIT:
case PWM_THYR_TIM_WAIT: // канал ожидает команды
__PWM_SetOutputState(hPhase, PWM_DISABLE);
break;
case PWM_THYR_TIM_START:
case PWM_THYR_TIM_START: // начать ШИМ (пачка импульсов)
__PWM_SetOutputState(hPhase, PWM_ENABLE);
hPhase->PulseCnt = hpwm->Config.PulseNumber;
hPhase->State = PWM_THYR_TIM_ACTIVE;
hpwm->f.Running++;
break;
case PWM_THYR_TIM_ACTIVE:
case PWM_THYR_TIM_ACTIVE: // управление пачкой импульсов ШИМ
hPhase->PulseCnt--;
if (hPhase->PulseCnt <= 0)
{
@ -189,13 +199,13 @@ HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
}
break;
case PWM_THYR_TIM_DONE:
case PWM_THYR_TIM_DONE: // пачка импульсов отправлена - отключение
hPhase->State = PWM_THYR_TIM_WAIT;
if(hpwm->f.Running)
hpwm->f.Running--;
break;
default:
default: // чзх
__PWM_SetOutputState(hPhase, PWM_DISABLE);
break;
}
@ -204,7 +214,7 @@ HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
}
/**
* @brief Установка частоты ШИМ.
* @brief Установка параметров ШИМ.
* @param hpwm Указатель на хендл ШИМ тиристоров
* @param Frequency Частота в ГЦ
* @return HAL Status.
@ -213,16 +223,19 @@ HAL_StatusTypeDef PWM_SetConfig(PWM_Handle_t *hpwm, uint8_t PhaseMask, uint16_t
{
if(assert_upp(hpwm))
return HAL_ERROR;
if(hpwm->f.Running)
if(hpwm->f.Running) // Если есть активные каналы - ниче не меняем
return HAL_BUSY;
HAL_TIM_Base_Stop(&hpwm1);
// Остановка таймера
HAL_TIM_Base_Stop_IT(&hpwm1);
hpwm->Config.PhaseMask.all = PhaseMask;
hpwm->Config.PulseNumber = PulseNumber;
hpwm->Config.Frequency = Frequency;
// Высставление периодов
__HAL_TIM_SET_AUTORELOAD(&hpwm1, TIM_FreqToTick(Frequency, PWM_TIM1_FREQ_MHZ));
__HAL_TIM_SET_AUTORELOAD(&hpwm2, TIM_FreqToTick(Frequency, PWM_TIM3_FREQ_MHZ));
// Скважности 50/50
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_1, __HAL_TIM_GET_AUTORELOAD(&hpwm1)/2);
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_2, __HAL_TIM_GET_AUTORELOAD(&hpwm1)/2);
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_3, __HAL_TIM_GET_AUTORELOAD(&hpwm1)/2);
@ -230,6 +243,10 @@ HAL_StatusTypeDef PWM_SetConfig(PWM_Handle_t *hpwm, uint8_t PhaseMask, uint16_t
__HAL_TIM_SET_COMPARE(&hpwm2, PWM_CHANNEL_5, __HAL_TIM_GET_AUTORELOAD(&hpwm2)/2);
__HAL_TIM_SET_COMPARE(&hpwm2, PWM_CHANNEL_6, __HAL_TIM_GET_AUTORELOAD(&hpwm2)/2);
// Сброс счетчиков таймера и запуск заного
__HAL_TIM_SET_COUNTER(&hpwm1, 0);
__HAL_TIM_SET_COUNTER(&hpwm2, 0);
return HAL_TIM_Base_Start_IT(&hpwm1);
}
@ -240,13 +257,13 @@ HAL_StatusTypeDef PWM_SetConfig(PWM_Handle_t *hpwm, uint8_t PhaseMask, uint16_t
* @param Phase Для какой фазы надо установить полуволну
* @param halfwave Какую полуволну установить
* @return HAL Status.
* @details Меняет указатель канала фазы на канал соответствующей полуволны
*/
HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_HalfWave_t halfwave)
{
if(assert_upp(hpwm))
return HAL_ERROR;
// Сбрасываем текущий канал
PWM_Stop(hpwm, Phase, 0);
@ -315,39 +332,3 @@ static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Channel_t *hCh, uint32_t state
}
return HAL_OK;
}
/**
* @brief Установка полуволны для слежения.
* @param hpwm Указатель на хендл ШИМ тиристоров
* @param Phase Для какой фазы надо установить полуволну
* @param halfwave Какую полуволну установить
* @return HAL Status.
*/
UPP_HalfWave_t PWM_GetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
{
if(assert_upp(hpwm))
return UPP_WAVE_UNKNOWED;
// Если канал дурацкий - возвращаем UNKNOWED
if (Phase >= 3)
{
return UPP_WAVE_UNKNOWED;
}
if (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN])
return UPP_WAVE_UNKNOWED;
// Выставляем канал
if(hpwm->Phase[Phase] == &hpwm->AllPhases[Phase])
{
return UPP_WAVE_POSITIVE;
}
else if(hpwm->Phase[Phase] == &hpwm->AllPhases[Phase+3])
{
return UPP_WAVE_NEGATIVE;
}
else
{
return UPP_WAVE_UNKNOWED;
}
}

View File

@ -96,8 +96,6 @@ HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_
HAL_StatusTypeDef PWM_SetConfig(PWM_Handle_t *hpwm, uint8_t PhaseMask, uint16_t Frequency, uint8_t PulseNumber);
/* Установка полуволны для слежения. */
HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_HalfWave_t halfwave);
/* Установка полуволны для слежения. */
UPP_HalfWave_t PWM_GetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase);
/* Хендл ШИМ тиристоров. */
HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm);

View File

@ -12,7 +12,7 @@ static int __CheckSimpleParamF(float *paramDist, uint16_t paramSrc, float Coef);
static int __CheckSimpleParamU32(uint32_t *paramDist, uint16_t paramSrc, float Coef);
static int __CheckSimpleParamU16(uint16_t *paramDist, uint16_t paramSrc);
static int __CheckSimpleParamU8(uint8_t *paramDist, uint16_t paramSrc, float Coef);
static int __AngleSetLimit(void);
static void __AngleSetLimit(void);
/**
* @brief Контроль внутренних параметров УПП.
@ -38,6 +38,8 @@ void UPP_Control_InternalParams(void)
uint8_t pwm_phase_mask = upp.hpwm.Config.PhaseMask.all;
uint16_t pwm_freq = upp.hpwm.Config.Frequency;
uint8_t pwm_pulse_num = upp.hpwm.Config.PulseNumber;
// временная переменная для параметров Мониторинга сети
float pm_alpha = upp.pm.measured.exp[0].alpha;
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
@ -58,11 +60,11 @@ void UPP_Control_InternalParams(void)
}
// Параметры алгоритма перехода через ноль
if(__CheckSimpleParamF(&zc_hysteresis, MB_INTERNAL.param.zc.Hysteresis, 100))
if(__CheckSimpleParamF(&zc_hysteresis, MB_INTERNAL.param.zc.Hysteresis, 10000))
{
zc_update = 1;
}
if(__CheckSimpleParamU16(&zc_debounce, MB_INTERNAL.param.zc.Hysteresis))
if(__CheckSimpleParamU16(&zc_debounce, MB_INTERNAL.param.zc.DebouneCouner))
{
zc_update = 1;
}
@ -80,6 +82,15 @@ void UPP_Control_InternalParams(void)
{
pwm_update = 1;
}
// Параметры мониторинга
if(__CheckSimpleParamF(&pm_alpha, MB_INTERNAL.param.pm.mean_alpha, 65535))
{
for(int i = 0; i < 3; i++)
{
Filter_ReInit(&upp.pm.measured.exp[i], pm_alpha);
}
}
// Обновление АЦП конфигов
@ -142,6 +153,17 @@ void UPP_SetDefault(int pui_default, int internal_default)
if(internal_default)
{
MB_INTERNAL.param.nominal.PhaseNumber = NOM_PHASE_NUMB;
MB_INTERNAL.param.nominal.U = NOM_U_V_DEFAULT*10;
MB_INTERNAL.param.nominal.U_deviation_plus = NOM_U_DEVIATION_PLUS_PERCENT_DEFAULT*100;
MB_INTERNAL.param.nominal.U_deviation_minus = NOM_U_DEVIATION_MINUS_PERCENT_DEFAULT*100;
MB_INTERNAL.param.nominal.F = NOM_F_HZ_DEFAULT*100;
MB_INTERNAL.param.nominal.F_deviation_plus = NOM_F_DEVIATION_PLUS_PERCENT_DEFAULT*100;
MB_INTERNAL.param.nominal.F_deviation_minus = NOM_F_DEVIATION_MINUS_PERCENT_DEFAULT*100;
MB_INTERNAL.param.nominal.I = NOM_I_A_DEFAULT*10;
MB_INTERNAL.param.pm.mean_alpha = PM_EXP_ALPHA_COEF_DEFAULT*65535;
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UBA] = ADC_U_MAX_V_DEFAULT*10;
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UAC] = ADC_U_MAX_V_DEFAULT*10;
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_IC] = ADC_I_MAX_A_DEFAULT*10;
@ -155,7 +177,7 @@ void UPP_SetDefault(int pui_default, int internal_default)
MB_INTERNAL.param.pwm.Frequency = (float)PWM_THYR_FREQUENCY_HZ_DEFAULT;
MB_INTERNAL.param.pwm.PulseNumber = PWM_THYR_PULSE_NUMBER_DEFAULT;
MB_INTERNAL.param.zc.Hysteresis = ZERO_CROSS_HYSTERESIS_V_DEFAULT*100;
MB_INTERNAL.param.zc.Hysteresis = ZERO_CROSS_HYSTERESIS_PERCENT_DEFAULT*100;
MB_INTERNAL.param.zc.DebouneCouner = ZERO_CROSS_DEBOUNCE_10US_DEFAULT;
//__AngleSetLimit();
}
@ -163,10 +185,10 @@ void UPP_SetDefault(int pui_default, int internal_default)
static int __AngleSetLimit(void)
static void __AngleSetLimit(void)
{
// Перерасчет максимально допустимого угла
float pulses_percent_of_period = ((MB_INTERNAL.param.pwm.PulseNumber / MB_INTERNAL.param.pwm.Frequency) * 1000) / ANGLE_PERIOD_MS;
float pulses_percent_of_period = ((MB_INTERNAL.param.pwm.PulseNumber / MB_INTERNAL.param.pwm.Frequency) * 1000) / ANGLE_PERIOD_MS(NOM_F_HZ_DEFAULT);
float angle_limit = 1 - pulses_percent_of_period;
Angle_SetLimit(&upp.hangle, angle_limit);
}

View File

@ -12,10 +12,10 @@
typedef struct
{
unsigned set_default_pui:1;
unsigned set_default_internal:1;
unsigned go:1;
unsigned stop:1;
unsigned set_default_pui:1; ///< Выставить настройки ПУИ в дефолтные
unsigned set_default_internal:1;///< Выставить внутренние настройки в дефолтные
unsigned go:1; ///< Запустить УПП
unsigned stop:1; ///< Выставить внутренние настройки в дефолтные
unsigned reserved:11;
@ -25,33 +25,51 @@ typedef struct
typedef struct
{
struct
{
uint16_t mean_alpha; ///< Коэф альфа x10000 для эксп. фильтра Umean, Imean, Fmean
}pm;
struct
{
uint16_t PhaseNumber; ///< Количество
uint16_t U; ///< В x 10
uint16_t U_deviation_plus; ///< Проценты x 100
uint16_t U_deviation_minus; ///< Проценты x 100
uint16_t F; ///< Гц x 100
uint16_t F_deviation_plus; ///< Проценты x 100
uint16_t F_deviation_minus; ///< Проценты x 100
uint16_t I; ///< Амперы x 10
}nominal;
/* Параметры АЦП */
struct
{
uint16_t ADC_Max[4];
uint16_t ADC_Zero[4];
uint16_t ADC_Max[4]; ///< В x 10
uint16_t ADC_Zero[4]; ///< Кванты АЦП
}adc;
/* Параметры ШИМ */
struct
{
uint16_t PhaseMask;
uint16_t Frequency;
uint16_t PulseNumber;
uint16_t PhaseMask; ///< Битовяя маска на какие фазы подавать ШИМ: 0 бит - a, 1 бит - b, 2 бит - c
uint16_t Frequency; ///< Частота ШИМ для пачки импульсов на тиристоры
uint16_t PulseNumber; ///< Количесво импульсов в пачке
}pwm;
/* Параметры Угла */
struct
{
uint16_t Hysteresis;
uint16_t DebouneCouner;
uint16_t Hysteresis; ///< Гистерезис для определения перехода через ноль
uint16_t DebouneCouner; ///< Защита от дребезга: через сколько тактов снова начать фиксировать переход через ноль
}zc;
/* Параметры Угла */
struct
{
uint16_t Angle_Max;
uint16_t Angle_Min;
uint16_t Angle_Max; ///< Максимальный угол открытия тиристора
uint16_t Angle_Min; ///< Минимальный угол открытия тиристора
}angle;

View File

@ -104,7 +104,7 @@ typedef struct
uint64_t all;
struct
{
unsigned :1;
unsigned slow_calc_overrun:1;
}err;
}f;
@ -113,6 +113,7 @@ typedef struct
uint16_t adc_reinit_err;
uint16_t zc_reinit_err;
uint16_t pwm_reinit_err;
uint16_t slow_calc_overrun;
}cnt;
}prvt; ///< Приватные ошибки, не идущие напрямую в ПУИ

View File

@ -6,6 +6,7 @@
* @details
******************************************************************************/
#include "upp_main.h" // всё остальное по работе с УПП
#include "tim.h"
UPP_t upp;
float alpha_dbg = 0.5;
@ -17,6 +18,7 @@ float alpha_dbg = 0.5;
*/
int UPP_Init(void)
{
BenchTime_Init();
// Подключение указателей
upp.errors = &errors;
upp.PUI.params = &MB_DATA.HoldRegs.pui_params;
@ -60,8 +62,6 @@ int UPP_While(void)
{
upp.call->stop = 0;
}
// Сброс на дефолтные по запросу
if(upp.call->set_default_pui)
{
@ -74,6 +74,8 @@ int UPP_While(void)
PowerMonitor_SlowHandle(&upp.pm);
// Если СТОП - переходим в ошибку
if (upp.call->stop)
upp.workmode = WM_Error;
@ -107,6 +109,13 @@ int UPP_While(void)
PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
break;
case WM_Done:
PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
break;
default:
break;
}
@ -132,6 +141,8 @@ void UPP_Tick(void)
void UPP_ADC_Handle(void)
{
BenchTime_Start(BT_ADC, angletim.Instance->CNT, HAL_MAX_DELAY);
PowerMonitor_Handle(&upp.pm);
for(int phase = 0; phase < 3; phase++)
@ -152,10 +163,14 @@ void UPP_ADC_Handle(void)
}
// Проверяем на ошибки
upp.Timings.isr_adc = BenchTime_End(BT_ADC, angletim.Instance->CNT);
}
void UPP_PWM_Handle(void)
{
BenchTime_Start(BT_PWM, angletim.Instance->CNT, HAL_MAX_DELAY);
PWM_Handle(&upp.hpwm);
upp.Timings.isr_pwm = BenchTime_End(BT_PWM, angletim.Instance->CNT);
}
void UPP_Angle_Handle(void)
@ -186,6 +201,8 @@ void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim)
{
if (htim == upp.hangle.htim)
{
BenchTime_Start(BT_SYSTICK, angletim.Instance->CNT, HAL_MAX_DELAY);
UPP_Angle_Handle();
upp.Timings.isr_systick = BenchTime_End(BT_SYSTICK, angletim.Instance->CNT);
}
}

View File

@ -38,6 +38,13 @@ typedef struct
UPP_Errors_t *errors; ///< Ошибки УПП
uint32_t StartTick;
struct
{
uint32_t isr_adc;
uint32_t isr_pwm;
uint32_t isr_systick;
}Timings;
}UPP_t;
extern UPP_t upp;

View File

@ -564,57 +564,6 @@
<FileName>dma.c</FileName>
<FileType>1</FileType>
<FilePath>../Core/Src/dma.c</FilePath>
<FileOption>
<CommonProperty>
<UseCPPCompiler>2</UseCPPCompiler>
<RVCTCodeConst>0</RVCTCodeConst>
<RVCTZI>0</RVCTZI>
<RVCTOtherData>0</RVCTOtherData>
<ModuleSelection>0</ModuleSelection>
<IncludeInBuild>1</IncludeInBuild>
<AlwaysBuild>2</AlwaysBuild>
<GenerateAssemblyFile>2</GenerateAssemblyFile>
<AssembleAssemblyFile>2</AssembleAssemblyFile>
<PublicsOnly>2</PublicsOnly>
<StopOnExitCode>11</StopOnExitCode>
<CustomArgument></CustomArgument>
<IncludeLibraryModules></IncludeLibraryModules>
<ComprImg>1</ComprImg>
</CommonProperty>
<FileArmAds>
<Cads>
<interw>2</interw>
<Optim>0</Optim>
<oTime>2</oTime>
<SplitLS>2</SplitLS>
<OneElfS>2</OneElfS>
<Strict>2</Strict>
<EnumInt>2</EnumInt>
<PlainCh>2</PlainCh>
<Ropi>2</Ropi>
<Rwpi>2</Rwpi>
<wLevel>0</wLevel>
<uThumb>2</uThumb>
<uSurpInc>2</uSurpInc>
<uC99>2</uC99>
<uGnu>2</uGnu>
<useXO>2</useXO>
<v6Lang>0</v6Lang>
<v6LangP>0</v6LangP>
<vShortEn>2</vShortEn>
<vShortWch>2</vShortWch>
<v6Lto>2</v6Lto>
<v6WtE>2</v6WtE>
<v6Rtti>2</v6Rtti>
<VariousControls>
<MiscControls></MiscControls>
<Define></Define>
<Undefine></Undefine>
<IncludePath></IncludePath>
</VariousControls>
</Cads>
</FileArmAds>
</FileOption>
</File>
<File>
<FileName>iwdg.c</FileName>