Чет делал систему управления углом и поломалось всё... Угол неправильно рассчитывается и не в то время включается тиристор

This commit is contained in:
Razvalyaev 2025-11-17 18:49:43 +03:00
parent e69eb0c8c9
commit b887114510
20 changed files with 976 additions and 244 deletions

View File

@ -7,7 +7,7 @@
#include "app_wrapper.h"
float dbg[16];
extern float iref_dbg;
#define PIN_READ(_verbname_) (_verbname_##_GPIO_Port->ODR & (_verbname_##_Pin)) ? 1 : 0
void Write_Thyristors(real_T* Buffer, int ind_port)
@ -33,7 +33,7 @@ void Write_PowerMonitor(real_T* Buffer, int ind_port)
int nn = 0;
for (int i = 0; i < 3; i++)
{ //0-2
WriteOutputArray(upp.pm.measured.U[i], ind_port, nn++);
WriteOutputArray(upp.pm.measured.fast.U[i], ind_port, nn++);
}
for (int i = 0; i < 3; i++)
{ //3-5
@ -41,23 +41,23 @@ void Write_PowerMonitor(real_T* Buffer, int ind_port)
}
for (int i = 0; i < 3; i++)
{ //6-8
WriteOutputArray(upp.pm.measured.F[i], ind_port, nn++);
WriteOutputArray(upp.pm.measured.final.F[i], ind_port, nn++);
}
for (int i = 0; i < 3; i++)
{ //9-11
WriteOutputArray(upp.pm.measured.I[i], ind_port, nn++);
WriteOutputArray(upp.pm.measured.fast.I[i], ind_port, nn++);
}
for (int i = 0; i < 2; i++)
{ //12-13
WriteOutputArray(upp.pm.measured.T[i], ind_port, nn++);
WriteOutputArray(upp.pm.measured.final.T[i], ind_port, nn++);
}
{ //14-19
WriteOutputArray(upp.pm.measured.Uvec, ind_port, nn++);
WriteOutputArray(upp.pm.measured.Ivec, ind_port, nn++);
WriteOutputArray(upp.pm.measured.Imean[0], ind_port, nn++);
WriteOutputArray(upp.pm.measured.Imean[1], ind_port, nn++);
WriteOutputArray(upp.pm.measured.Imean[2], ind_port, nn++);
WriteOutputArray(upp.pm.measured.Fmean, ind_port, nn++);
WriteOutputArray(upp.pm.measured.final.Uamp, ind_port, nn++);
WriteOutputArray(upp.pm.measured.final.Iamp, ind_port, nn++);
WriteOutputArray(upp.pm.measured.final.I[0], ind_port, nn++);
WriteOutputArray(upp.pm.measured.final.I[1], ind_port, nn++);
WriteOutputArray(upp.pm.measured.final.I[2], ind_port, nn++);
WriteOutputArray(upp.pm.measured.final.Fmean, ind_port, nn++);
}
}
@ -74,8 +74,14 @@ void app_readInputs(const real_T* Buffer) {
ADC_Set_Channel_Value(ADC3, 8, ReadInputArray(0,4));
ADC_Set_Channel_Value(ADC3, 10, ReadInputArray(0,5));
alpha_dbg = ReadInputArray(1, 0);
iref_dbg = ReadInputArray(1, 0);
upp.call->go = ReadInputArray(1, 1);
MB_INTERNAL.param.angle.Angle_Max = ReadInputArray(1, 2)*65535;
MB_INTERNAL.param.angle.Angle_Min = ReadInputArray(1, 3)*65535;
MB_INTERNAL.param.angle.PID_Kp = ReadInputArray(1, 4) * 10000;
MB_INTERNAL.param.angle.PID_Ki = ReadInputArray(1, 5) * 10000;
MB_INTERNAL.param.angle.PID_Kd = ReadInputArray(1, 6) * 10000;
// USER APP INPUT END
}
@ -92,20 +98,24 @@ void app_writeOutputBuffer(real_T* Buffer) {
int nn = 0;
WriteOutputArray(iref_dbg, 2, nn++);
WriteOutputArray(upp.pm.measured.final.Iamp, 2, nn++);
WriteOutputArray(upp.hangle.alpha, 2, nn++);
//WriteOutputArray(upp.hangle.htim->Instance->CNT, 2, nn++);
WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR1) - upp.hangle.htim->Instance->CNT, 2, nn++);
WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR2) - upp.hangle.htim->Instance->CNT, 2, nn++);
WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR3) - upp.hangle.htim->Instance->CNT, 2, nn++);
//WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR1) - upp.hangle.htim->Instance->CNT, 2, nn++);
//WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR2) - upp.hangle.htim->Instance->CNT, 2, nn++);
//WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR3) - upp.hangle.htim->Instance->CNT, 2, nn++);
//WriteOutputArray(dbg[0], 2, nn++);
//WriteOutputArray(dbg[1], 2, nn++);
//WriteOutputArray(dbg[2], 2, nn++);
WriteOutputArray(upp.hpwm.AllPhases[PHASE_A_POS].State, 2, nn++);
WriteOutputArray(upp.hpwm.AllPhases[PHASE_A_NEG].State, 2, nn++);
WriteOutputArray(upp.hpwm.AllPhases[PHASE_B_POS].State, 2, nn++);
WriteOutputArray(upp.hpwm.AllPhases[PHASE_B_NEG].State, 2, nn++);
WriteOutputArray(upp.hpwm.AllPhases[PHASE_C_POS].State, 2, nn++);
WriteOutputArray(upp.hpwm.AllPhases[PHASE_C_NEG].State, 2, nn++);
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_A_POS].State, 2, nn++);
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_A_NEG].State, 2, nn++);
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_B_POS].State, 2, nn++);
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_B_NEG].State, 2, nn++);
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_C_POS].State, 2, nn++);
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_C_NEG].State, 2, nn++);
// USER APP OUTPUT END
}

Binary file not shown.

View File

@ -18,24 +18,32 @@
#define assert_upp(_struct_) check_null_ptr_2(_struct_, (_struct_)->f.Initialized)
/* Дефайны для индексов */
/* Линейные напряжения */
#define U_BA 0
#define U_AC 1
#define U_BC 2
/* Токи фаз */
#define I_C 0
#define I_A 1
#define I_B 2
/* Температуры */
#define TEMP_1 0
#define TEMP_2 1
/**
* @addtogroup UPP_DEFAULT_PARAMS Default params for external flash
* @ingroup UPP_CONFIG
* @brief Дефолтные параметры для внешней памяти. Они применятся по команде или по ошибке
* @{
*/
/* Параметри мониторинга сети */
#define PM_EXP_ALPHA_COEF_DEFAULT 0.01
/* Номинальные параметры */
#define SETPOINT_TEMP_WARN 70
#define SETPOINT_TEMP_ERR 85
/* Номинальные параметры */
#define NOM_PHASE_NUMB 3
@ -58,6 +66,12 @@
#define PUI_Tdelay_SECONDS_DEFAULT 30
#define PUI_Interlace_EN_DEFAULT 5000
/* Дефолтное коливчество тиков для задержки выставления ошибки */
#define ERRORS_DELAY_TICKS_DEFAULT 10
/* Параметри мониторинга сети */
#define PM_EXP_ALPHA_COEF_DEFAULT 0.01
/* Параметры АЦП */
#define ADC_U_MAX_V_DEFAULT 1216.0
#define ADC_I_MAX_A_DEFAULT 53.0
@ -88,6 +102,7 @@
#define PM_SLOW_PERIOD_CNT 50 ///< Период обновления медленных расчетов тиках @ref PM_ADC_PERIOD_US
#define PM_TEMP_SLOW_PERIOD_CNT 200 ///< Период обновления датчиков температуры в тиках @ref PM_SLOW_PERIOD_CNT
/* Частоты таймеров в МГц*/
#define ADC_TIM8_FREQ_MZH 180 ///< Частота тиков таймера АЦП
#define PWM_TIM1_FREQ_MHZ 180 ///< Частота тиков таймера ШИМ (1-4 каналы)

View File

@ -59,6 +59,8 @@ typedef enum {
Err_OverVoltage = 13, ///< Напряжение сети выше допустимого (см. Umах в @ref UPP_PUI_Params_t)
Err_OverTemperature = 14, ///< Температура выше допустимой (плюс 85 °C)
Err_UnderVoltage = 15, ///< Напряжение сети ниже допустимого (см. Umin в @ref UPP_PUI_Params_t)
Err_OverFrequency = 22, ///< Частота сети выше допустимой
Err_UnderFrequency = 23, ///< Частота сети ниже допустимой
/* Ошибки по обрывам фаз */
Err_LossPhaseAll = 16, ///< Обрыв трёх фаз (см. Imin в @ref UPP_PUI_Params_t)
@ -69,8 +71,6 @@ typedef enum {
/* Другие ошибки */
Err_LongStart = 20, ///< Затянутый пуск (ток не спадает за установленное время) (см. Tdelay в @ref UPP_PUI_Params_t)
Err_Interlace = 21, ///< Неправильный порядок чередования фаз (см. Interlace в @ref UPP_PUI_Params_t)
Err_OverFrequency = 22, ///< Частота сети выше допустимой
Err_UnderFrequency = 23, ///< Частота сети ниже допустимой
} UPP_ErrorType_t;
@ -148,6 +148,7 @@ typedef struct {
* @brief Дефайны УПП которые используютяс исключительно внутри программы
* @{
*/
#define PM_SLOW_PERIOD_US (PM_ADC_PERIOD_US*PM_SLOW_PERIOD_CNT)
#define ANGLE_PERIOD_MS(_freq_) (((float)1/(_freq_*2))*1000)
/**

View File

@ -11,7 +11,6 @@
/**
* @brief Рассчитать результирующий вектор трехфазной системы по фазным величинам.
* @return Длина вектора (модуль).
* @note Вызывается в DMA2_Stream0_IRQHandler() для обработки всего, что пришло по DMA.
*/
float vector_abs_phase_calc(float phase1, float phase2)
{
@ -30,7 +29,6 @@ float vector_abs_phase_calc(float phase1, float phase2)
/**
* @brief Рассчитать результирующий вектор трехфазной системы по линейным величинам.
* @return Длина вектора (модуль).
* @note Вызывается в DMA2_Stream0_IRQHandler() для обработки всего, что пришло по DMA.
*/
float vector_abs_linear_calc(float phase1, float phase2)
{
@ -46,4 +44,40 @@ float vector_abs_linear_calc(float phase1, float phase2)
return 0;
}
/**
* @brief Рассчитать фазные напряжения из линейных (звезда)
* @param Ulin Линейные напряжения [Uba Uac Ubc]
* @param Uph Фазные напряжения [Ua Ub Uc]
*/
void linear_to_phase_star(float *Ulin, float *Uph)
{
if(Ulin == NULL || Uph == NULL)
return;
// Соответствие макросам: Ulin[0] = UBA, Ulin[1] = UAC, Ulin[2] = UBC
float Uba = Ulin[0];
float Uac = Ulin[1];
float Ubc = Ulin[2];
// Формулы для звезды (сумма фаз = 0)
Uph[0] = (Uba - Ubc)/3.0f; // Ua
Uph[1] = (Ubc - Uac)/3.0f; // Ub
Uph[2] = (Uac - Uba)/3.0f; // Uc
}
/**
* @brief Рассчитать фазные напряжения из линейных (треугольник)
* @param Ulin Линейные напряжения [Uba Uac Ubc]
* @param Uph Фазные напряжения [Ua Ub Uc]
*/
void linear_to_phase_delta(float *Ulin, float *Uph)
{
if(Ulin == NULL || Uph == NULL)
return;
// Соответствие макросам: Ulin[0] = UBA, Ulin[1] = UAC, Ulin[2] = UBC
// Для треугольника фазные напряжения равны линейным
Uph[0] = Ulin[0]; // Ua = Uba
Uph[1] = Ulin[2]; // Ub = Ubc
Uph[2] = Ulin[1]; // Uc = Uac
}

View File

@ -12,5 +12,8 @@
float vector_abs_phase_calc(float phase1, float phase2);
/* Рассчитать результирующий вектор трехфазной системы по линейным величинам. */
float vector_abs_linear_calc(float phase1, float phase2);
/* Рассчитать фазные напряжения из линейных (звезда) */
void linear_to_phase_star(float *Ulin, float *UphUc);
/* Рассчитать фазные напряжения из линейных (треугольник) */
void linear_to_phase_delta(float *Ulin, float *Uph);
#endif /* _PHASES_TRANSFORM_H_ */

View File

@ -6,12 +6,21 @@
* @details
******************************************************************************/
#include "power_monitor.h"
#include "power_protect.h"
#include "phases_transform.h"
#include "adc.h"
#include "tim.h"
#define U_BC_calc(_u1_, _u2_) (-((_u1_) + (_u2_)))
#define I_B_calc(_i1_, _i2_) (-((_i1_) + (_i2_)))
static void __SynchAvgFilters(PowerMonitor_t *hpm);
/**
* @brief Инициализация мониторинга сети.
* @param hpm Указатель на структуру мониторинга сети
* @details Инициализирует: АЦП, Алгоритм перехода через ноль, Фильтры
*/
HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
{
if(hpm == NULL)
@ -24,31 +33,31 @@ HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
/* Инициализация каналов АЦП */
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],
to_float(MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UBA], 10),
4095) != HAL_OK)
return HAL_ERROR;
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_UAC,
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_UAC],
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UAC],
to_float(MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UAC], 10),
4095) != HAL_OK)
return HAL_ERROR;
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_IC,
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_IC],
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_IC],
to_float(MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_IC], 10),
4095) != HAL_OK)
return HAL_ERROR;
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_IA,
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_IA],
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_IA],
to_float(MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_IA], 10),
4095) != HAL_OK)
return HAL_ERROR;
/* Инициализация алгоритма перехода через ноль */
if(ZC_Init(&hpm->zc, 3, (float)MB_INTERNAL.param.zc.Hysteresis/100, MB_INTERNAL.param.zc.DebouneCouner) != HAL_OK)
if(ZC_Init(&hpm->zc, 3, to_float(MB_INTERNAL.param.zc.Hysteresis, 100), MB_INTERNAL.param.zc.DebouneCouner) != HAL_OK)
return HAL_ERROR;
/* Инициализация каналов алгоритма перехода через ноль */
@ -63,7 +72,7 @@ HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
/* Инициализация экпоненциального фильтра медленного алга */
for(int i = 0; i < EXP_ALL; i++)
{
if(FilterExp_Init(&hpm->exp[i], (float)MB_INTERNAL.param.pm.mean_alpha/65535))
if(FilterExp_Init(&hpm->exp[i], to_float(MB_INTERNAL.param.pm.mean_alpha,65535)))
return HAL_ERROR;
Filter_Start(&hpm->exp[i]);
}
@ -88,6 +97,11 @@ HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
}
/**
* @brief Запустить мониторинг сети.
* @param hpm Указатель на структуру мониторинга сети
* @details Запускает АЦП с периодом @ref PM_ADC_PERIOD_US
*/
HAL_StatusTypeDef PowerMonitor_Start(PowerMonitor_t *hpm)
{
if(hpm == NULL)
@ -100,51 +114,68 @@ HAL_StatusTypeDef PowerMonitor_Start(PowerMonitor_t *hpm)
}
void PowerMonitor_SlowHandle(PowerMonitor_t *hpm)
/**
* @brief Медленные расчеты АЦП.
* @param hpm Указатель на структуру мониторинга сети
* @details Вызывается в main после накопления @ref PM_SLOW_PERIOD_CNT выборок АЦП.
* Делаются всякие расчеты для более подробного мониторинга сети и защит.
* Сам АЦП считывается в @ref PowerMonitor_FastCalc
*/
void PowerMonitor_SlowCalc(PowerMonitor_t *hpm)
{
if(hpm == NULL)
return;
if(!hpm->f.runSlow)
return;
PowerMonitor_Measured_t *meas = &hpm->measured;
/* Обработка температур */
float t1 = hpm->adc.Data[ADC_CHANNEL_TEMP1];
float t2 = hpm->adc.Data[ADC_CHANNEL_TEMP2];
meas->T[TEMP_1] = Filter_Process(&hpm->avg[ADC_CHANNEL_TEMP1], t1);
meas->T[TEMP_2] = Filter_Process(&hpm->avg[ADC_CHANNEL_TEMP2], t2);
meas->final.T[TEMP_1] = Filter_Process(&hpm->avg[ADC_CHANNEL_TEMP1], t1);
meas->final.T[TEMP_2] = Filter_Process(&hpm->avg[ADC_CHANNEL_TEMP2], t2);
/* Расчет третьей фазы */
meas->Uslow[U_BC] = -meas->Uslow[U_BA] - meas->Uslow[U_AC];
meas->Islow[I_B] = -meas->Islow[I_A] - meas->Islow[I_C];
meas->slow.U[U_BC] = U_BC_calc(meas->slow.U[U_BA], meas->slow.U[U_AC]);
meas->slow.I[I_B] = I_B_calc(meas->slow.I[I_A], meas->slow.I[I_C]);
/* Расчет всякого для трех фаз отдельно */
float fmean = 0; // средняя частота по трем фазам
float iphase_mean = 0; // средний ток каждой фазы
float uphase_mean = 0; // среднее напряжение каждой фазы
for(int i = 0; i < 3; i++)
{
/* Получение частоты фазы */
meas->F[i] = ZC_GetFrequency(&hpm->zc, i) / 2;
fmean += meas->F[i];
meas->final.F[i] = ZC_GetFrequency(&hpm->zc, i) / 2;
fmean += meas->final.F[i];
/* Средниее напряжение фазы */
uphase_mean = fabsf(meas->slow.U[i]);
meas->final.U[i] = Filter_Process(&hpm->exp[EXP_UBA+i], uphase_mean);
/* Средний ток фазы */
iphase_mean = fabsf(meas->Islow[i]);
meas->Imean[i] = Filter_Process(&hpm->exp[EXP_IC+i], iphase_mean);
iphase_mean = fabsf(meas->slow.I[i]);
meas->final.I[i] = Filter_Process(&hpm->exp[EXP_IC+i], iphase_mean);
}
/* Получение средней частоты по трем фазам */
fmean /= 3;
meas->Fmean = Filter_Process(&hpm->exp[EXP_F], fmean);
meas->final.Fmean = fmean / 3;
/* Расчет результирущих векторов трехфазной сети */
float uvec = vector_abs_linear_calc(meas->Uslow[U_BA], meas->Uslow[U_AC]);
float ivec = vector_abs_phase_calc(meas->Islow[I_A], meas->Islow[I_C]);
meas->Uvec = Filter_Process(&hpm->exp[EXP_U], uvec);
meas->Ivec = Filter_Process(&hpm->exp[EXP_I], ivec);
hpm->f.runSlow = 0;
/* Расчет амплитуд трехфазной сети */
float uamp = vector_abs_linear_calc(meas->slow.U[U_BA], meas->slow.U[U_AC]);
float iamp = vector_abs_phase_calc(meas->slow.I[I_A], meas->slow.I[I_C]);
meas->final.Uamp = Filter_Process(&hpm->exp[EXP_U], uamp);
meas->final.Iamp = Filter_Process(&hpm->exp[EXP_I], iamp);
}
void PowerMonitor_Handle(PowerMonitor_t *hpm)
/**
* @brief Считывание АЦП и быстрые расчеты.
* @param hpm Указатель на структуру мониторинга сети
* @details Вызывается в прерывании АЦП по получению данных.
* Далее данные считываются и делаются базовые преобразования
* Более подробные расчеты в @ref PowerMonitor_SlowCalc
*/
void PowerMonitor_FastCalc(PowerMonitor_t *hpm)
{
if(hpm == NULL)
return;
@ -153,31 +184,32 @@ void PowerMonitor_Handle(PowerMonitor_t *hpm)
/* Заполняем величины Напряжений/Токов */
PowerMonitor_Measured_t *meas = &hpm->measured;
meas->U[U_BA] = hpm->adc.Data[ADC_CHANNEL_UBA];
meas->U[U_AC] = hpm->adc.Data[ADC_CHANNEL_UAC];
meas->U[U_BC] = -meas->U[U_BA] - meas->U[U_AC];
meas->I[I_C] = hpm->adc.Data[ADC_CHANNEL_IC];
meas->I[I_A] = hpm->adc.Data[ADC_CHANNEL_IA];
meas->I[I_B] = -meas->I[I_A] - meas->I[I_C];
meas->real.U[U_BA] = hpm->adc.Data[ADC_CHANNEL_UBA];
meas->real.U[U_AC] = hpm->adc.Data[ADC_CHANNEL_UAC];
meas->real.U[U_BC] = U_BC_calc(meas->real.U[U_BA], meas->real.U[U_AC]);
meas->real.I[I_C] = hpm->adc.Data[ADC_CHANNEL_IC];
meas->real.I[I_A] = hpm->adc.Data[ADC_CHANNEL_IA];
meas->real.I[I_B] = I_B_calc(meas->real.I[I_A], meas->real.I[I_C]);
/* Преобразуем в относительные единицы (о.е.) */
for(int i = 0; i < 3; i++)
{
meas->Ufast[i] = 10*meas->U[i]/MB_INTERNAL.param.nominal.U;
meas->Ifast[i] = 10*meas->I[i]/MB_INTERNAL.param.nominal.I;
meas->fast.U[i] = 10*meas->real.U[i]/MB_INTERNAL.param.nominal.U;
meas->fast.I[i] = 10*meas->real.I[i]/MB_INTERNAL.param.nominal.I;
}
/* Ищем переход через ноль */
ZC_ProcessAllChannels(&hpm->zc, meas->Ufast, usTick);
ZC_ProcessAllChannels(&hpm->zc, meas->fast.U, usTick);
/* Вообще фильтры должны рабтоать синхронно, но на всякий синхронизация */
__SynchAvgFilters(hpm);
/* Накопление Average для медленной фильтрации */
meas->Uslow[U_BA] = Filter_Process(&hpm->avg[ADC_CHANNEL_UBA], meas->Ufast[U_BA]);
meas->Uslow[U_AC] = Filter_Process(&hpm->avg[ADC_CHANNEL_UAC], meas->Ufast[U_AC]);
meas->Islow[I_C] = Filter_Process(&hpm->avg[ADC_CHANNEL_IC], meas->Ifast[I_C]);
meas->Islow[I_A] = Filter_Process(&hpm->avg[ADC_CHANNEL_IA], meas->Ifast[I_A]);
/* Average для медленной фильтрации */
meas->slow.U[U_BA] = Filter_Process(&hpm->avg[ADC_CHANNEL_UBA], meas->fast.U[U_BA]);
meas->slow.U[U_AC] = Filter_Process(&hpm->avg[ADC_CHANNEL_UAC], meas->fast.U[U_AC]);
meas->slow.I[I_C] = Filter_Process(&hpm->avg[ADC_CHANNEL_IC], meas->fast.I[I_C]);
meas->slow.I[I_A] = Filter_Process(&hpm->avg[ADC_CHANNEL_IA], meas->fast.I[I_A]);
/* Запускаем медленную обработку через slow_period прерываний */
@ -186,7 +218,6 @@ void PowerMonitor_Handle(PowerMonitor_t *hpm)
/* Берем 0 фильтр, просто так, потому что они все должны работать синхронно */
if(Filter_isDataReady(&hpm->avg[0]))
{
hpm->isr_cnt = 0;
if(!hpm->f.runSlow)
{
@ -204,6 +235,46 @@ void PowerMonitor_Handle(PowerMonitor_t *hpm)
}
}
/**
* @brief Проверяет защиты питания и температур.
* @param measure Указатель на структуру с измеренными значениями
* @param Running Флаг:
* - 1 - УПП в работе,
* - 0 - УПП ожидает команды
* @return 1 - была обнаружена ощибка, 0 - все ок
*/
int PowerMonitor_Protect(PowerMonitor_t *hpm, uint8_t Running)
{
if(hpm == NULL)
return 1;
PowerMonitor_Measured_t *measure = &hpm->measured;
UPP_PUI_Params_t *protect = &MB_DATA.HoldRegs.pui_params;
UPP_ParamsNominal_t *nominal = &MB_INTERNAL.param.nominal;
/*=============== ЗАЩИТЫ ПО НАПРЯЖЕНИЮ ==================*/
hpm->f.isU = Protect_Voltages(measure, protect, nominal);
/* Если УПП в работе */
if(Running)
{
/*=============== ЗАЩИТЫ ПО ТОКУ ==================*/
hpm->f.isI = Protect_Currents(measure, protect, nominal);
}
/*=============== ЗАЩИТЫ ВСЯКИЕ ДРУГИЕ ==================*/
Protect_Misc(measure, protect, nominal);
if(errors.prvt.f.all)
return 1;
else
return 0;
}
/* Синхронизация фильтров. Но вообще не должна никогда отрабатывать */
static void __SynchAvgFilters(PowerMonitor_t *hpm)
{

View File

@ -11,58 +11,72 @@
#include "zero_cross.h"
/* Индексы экспоненциальных фильтров */
#define EXP_ALL 6
#define EXP_ALL 8
#define EXP_U 0
#define EXP_I 1
#define EXP_IC 2
#define EXP_IA 3
#define EXP_IB 4
#define EXP_F 5
#define EXP_UBA 1
#define EXP_UAC 2
#define EXP_UBC 3
#define EXP_I 4
#define EXP_IC 5
#define EXP_IA 6
#define EXP_IB 7
/**
* @brief Флаги Мониторинга сети
*/
typedef struct
{
unsigned runSlow:1; ///< Запустить медленный алгоритм в while(1)
unsigned isU:1; ///< Есть ли напряжение
unsigned isI:1; ///< Есть ли ток
unsigned protectUmax:1; ///< Отработка защиты по макс. напряжению
unsigned protectUmin:1; ///< Отработка защиты по мак с. напряжению
unsigned protectImax:1; ///< Отработка защиты по макс. току
unsigned protectImin:1; ///< Отработка защиты по мин. току
}PowerMonitor_Flags_t;
/**
* @brief Измеренные и приведенные значения с АЦП
*/
typedef struct
{
/* Усредненные величины (о.е.) */
float Uvec; ///< Результирующий вектор Напряжения по трем фазам
float Ivec; ///< Результирующий вектор Тока по трем фазам
float Imean[3]; ///< Средний Ток по трем фазам
float Fmean; ///< Средняя Частота по трем фазам
/** @brief Усредненные величины (о.е.) */
struct
{
float Uamp; ///< Результирующий вектор Напряжения по трем фазам
float Iamp; ///< Результирующий вектор Тока по трем фазам
float U[3]; ///< Среднее Наряжение по трем фазам
float I[3]; ///< Средний Ток по трем фазам
float Fmean; ///< Средняя Частота по трем фазам
float F[3]; ///< Частота от Zero Cross (обновляется в main)
float T[2]; ///< Температура (обновляется в main)
}final;
/* Быстрые величины (в о.е.) - обновляются в каждом прерывании АЦП */
float Ufast[3]; ///< Напряжение
float Ifast[3]; ///< Ток
/* Медленные величины (в о.е.) - обновляются в main в @ref PowerMonitor_SlowHandle */
float Uslow[3]; ///< Напряжение
float Islow[3]; ///< Ток
/* Реальные величины - обновляются кто где, и содержат значения в В/А/Цельсиях */
float U[3]; ///< Напряжение (обновляется в прерывании АЦП)
float I[3]; ///< Ток (обновляется в прерывании АЦП)
float F[3]; ///< Частота от Zero Cross (обновляется в main)
float T[2]; ///< Температура (обновляется в main)
/** @brief Быстрые величины (в о.е.) - обновляются в каждом прерывании АЦП @ref PowerMonitor_FastCalc */
struct
{
float U[3]; ///< Напряжение
float I[3]; ///< Ток
}fast;
/** @brief Медленные величины (в о.е.) - обновляются в main в @ref PowerMonitor_SlowCalc */
struct
{
float U[3]; ///< Напряжение
float I[3]; ///< Ток
}slow;
/** @brief Реальные величины - обновляются кто где, и содержат значения в В/А */
struct
{
float U[3]; ///< Напряжение (обновляется в прерывании АЦП)
float I[3]; ///< Ток (обновляется в прерывании АЦП)
}real;
}PowerMonitor_Measured_t;
typedef struct
{
}PowerMonitor_Filters_t;
/**
* @brief Структура для мониторинга сети
*/
typedef struct
{
ADC_Periodic_t adc; ///< Хендл периодического АЦП
@ -70,22 +84,24 @@ typedef struct
PowerMonitor_Measured_t measured; ///< Измеренные/рассчитанные величины
FilterExp_t exp[EXP_ALL]; ///< Фильтры для mean
FilterAverage_t avg[ADC_NUMB_OF_CHANNELS]; ///< Фильтры для avg
FilterExp_t exp[EXP_ALL]; ///< Фильтры для сглаживания мговенного значения Напряжения/Токов
FilterAverage_t avg[ADC_NUMB_OF_CHANNELS]; ///< Фильтры для сглаживания медленных величин АЦП
PowerMonitor_Flags_t f; ///< Флаги мониторинга
uint32_t slow_period;
uint32_t isr_cnt;
uint32_t isr_cnt;
}PowerMonitor_t;
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);
/* Медленные расчеты АЦП */
void PowerMonitor_SlowCalc(PowerMonitor_t *hpm);
/* Считывание АЦП и быстрые расчеты */
void PowerMonitor_FastCalc(PowerMonitor_t *hpm);
/* Проверяет защиты питания и температур */
int PowerMonitor_Protect(PowerMonitor_t *hpm, uint8_t Running);
#endif /* _POWER_MONITOR_H_ */

View File

@ -5,4 +5,199 @@
******************************************************************************
* @details
******************************************************************************/
#include "power_protect.h"
#include "power_protect.h"
/**
* @brief Проверяет защиты по напряжению.
* @note Заполняет флаги prvt ошибок (приватные).
* Потом в @ref UPP_ErrorsHandle исходя из них заполняются ошибки для ПУИ
* @return 1 - напряжение есть, 0 - напряжения нет
*/
int Protect_Voltages(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal)
{
/* Переводим уставки ПУИ в удобный вид */
float lUmin = to_float(protect->Umin, 100)/**to_float(nominal->U, 10)*/;
float lUmax = to_float(protect->Umax, 100)/**to_float(nominal->U, 10)*/;
float lPhaseSequence = to_float(nominal->PhaseSequence, 100);
/* Общее напряжение */
if(measure->final.Uamp > lUmax)
{
errors.prvt.f.err.uamp_max = 1;
}
else if (measure->final.Uamp < lUmin)
{
errors.prvt.f.err.uamp_min = 1;
}
else
{
errors.prvt.f.err.uamp_max = 0;
errors.prvt.f.err.uamp_min = 0;
}
/* Последовательность фаз */
int realPhaseSequence = 0;
if(realPhaseSequence != lPhaseSequence)
{
errors.prvt.f.err.interlance = 1;
}
else
{
errors.prvt.f.err.interlance = 0;
}
return (errors.prvt.f.err.uamp_min == 0);
}
/**
* @brief Проверяет защиты по току.
* @note Заполняет флаги prvt ошибок (приватные).
* Потом в @ref UPP_ErrorsHandle исходя из них заполняются ошибки для ПУИ
*/
int Protect_Currents(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal)
{
/* Переводим уставки ПУИ в удобный вид */
float lIref = to_float(protect->Iref, 100)/**to_float(nominal->I, 10)*/;
float lImax = to_float(protect->Imax, 100)/**to_float(nominal->I, 10)*/;
float lImin = to_float(protect->Imin, 100)/**to_float(nominal->I, 10)*/;
/* Общий ток */
if(measure->final.Iamp > lImax)
{
errors.prvt.f.err.iamp_max = 1;
}
else if (measure->final.Iamp < lImin)
{
errors.prvt.f.err.iamp_min = 1;
}
else
{
errors.prvt.f.err.iamp_max = 0;
errors.prvt.f.err.iamp_min = 0;
}
/* Ток по фазам */
if(measure->final.I[I_A] > lImax)
{
errors.prvt.f.err.ia_max = 1;
}
else if (measure->final.I[I_A] < lImin)
{
errors.prvt.f.err.ia_min = 1;
}
else
{
errors.prvt.f.err.ia_max = 0;
errors.prvt.f.err.ia_min = 0;
}
if(measure->final.I[I_B] > lImax)
{
errors.prvt.f.err.ib_max = 1;
}
else if (measure->final.I[I_B] < lImin)
{
errors.prvt.f.err.ib_min = 1;
}
else
{
errors.prvt.f.err.ib_max = 0;
errors.prvt.f.err.ib_min = 0;
}
if(measure->final.I[I_C] > lImax)
{
errors.prvt.f.err.ic_max = 1;
}
else if (measure->final.I[I_C] < lImin)
{
errors.prvt.f.err.ic_min = 1;
}
else
{
errors.prvt.f.err.ic_max = 0;
errors.prvt.f.err.ic_min = 0;
}
return (errors.prvt.f.err.iamp_min == 0);
}
/**
* @brief Проверяет всякие другие защиты (частота, температура).
* @note Заполняет флаги prvt ошибок (приватные).
* Потом в @ref UPP_ErrorsHandle исходя из них заполняются ошибки для ПУИ
*/
void Protect_Misc(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal)
{
/* Переводим внутренние уставки в удобный вид */
float lFnom = to_float(MB_INTERNAL.param.nominal.F, 100);
float lFmin = lFnom - lFnom*to_float(MB_INTERNAL.param.nominal.F_deviation_minus, 100);
float lFmax = lFnom + lFnom*to_float(MB_INTERNAL.param.nominal.F_deviation_plus, 100);
float lTwarn = to_float(MB_INTERNAL.param.setpoints.TemperatureWarn, 100);
float lTerr = to_float(MB_INTERNAL.param.setpoints.TemperatureWarn, 100);
/*=============== ЗАЩИТЫ ПО ЧАСТОТЕ ==================*/
if(measure->final.F[U_AC] > lFmax)
{
errors.prvt.f.err.fac_max = 1;
}
else if (measure->final.F[U_AC] < lFmin)
{
errors.prvt.f.err.fac_min = 1;
}
else
{
errors.prvt.f.err.fac_max = 0;
errors.prvt.f.err.fac_min = 0;
}
if(measure->final.F[U_BA] > lFmax)
{
errors.prvt.f.err.fba_max = 1;
}
else if (measure->final.F[U_BA] < lFmin)
{
errors.prvt.f.err.fba_min = 1;
}
else
{
errors.prvt.f.err.fba_max = 0;
errors.prvt.f.err.fba_min = 0;
}
if(measure->final.F[U_BC] > lFmax)
{
errors.prvt.f.err.fbc_max = 1;
}
else if (measure->final.F[U_BC] < lFmin)
{
errors.prvt.f.err.fbc_min = 1;
}
else
{
errors.prvt.f.err.fbc_max = 0;
errors.prvt.f.err.fbc_min = 0;
}
/*=============== ЗАЩИТЫ ПО ТЕМПЕРАТУРЕ ==================*/
if(measure->final.T[TEMP_1] > lTerr)
{
errors.prvt.f.err.temp_err = 1;
}
else if (measure->final.T[TEMP_1] > lTwarn)
{
errors.prvt.f.err.temp_warn = 1;
}
else
{
errors.prvt.f.err.temp_err = 0;
errors.prvt.f.err.temp_warn = 0;
}
}

View File

@ -6,6 +6,13 @@
*****************************************************************************/
#ifndef _POWER_PROTECT_H_
#define _POWER_PROTECT_H_
#include "main.h"
#include "power_monitor.h"
/* Проверяет защиты по напряжению. */
int Protect_Voltages(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal);
/* Проверяет защиты по току. */
int Protect_Currents(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal);
/* Проверяет всякие другие защиты (частота, температура). */
void Protect_Misc(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal);
#endif /* _POWER_PROTECT_H_ */

View File

@ -23,8 +23,6 @@
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "upp_main.h"
#include "pwm_thyristors.h"
#include "angle_control.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/

View File

@ -21,19 +21,90 @@ HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle)
hangle->htim = &angletim;
// Инициализация ПИД
float kp = to_float(MB_INTERNAL.param.angle.PID_Kp, 10000);
float ki = to_float(MB_INTERNAL.param.angle.PID_Ki, 10000);
float kd = to_float(MB_INTERNAL.param.angle.PID_Kd, 10000);
Angle_PID_Init(hangle, kp, ki, kd);
// Инициализация каналов
HAL_TIM_OC_Start_IT(hangle->htim, ANGLE_CHANNEL_1);
HAL_TIM_OC_Start_IT(hangle->htim, ANGLE_CHANNEL_2);
HAL_TIM_OC_Start_IT(hangle->htim, ANGLE_CHANNEL_3);
// Сброс всех каналов
Angle_Reset(hangle, UPP_PHASE_A);
Angle_Reset(hangle, UPP_PHASE_B);
Angle_Reset(hangle, UPP_PHASE_C);
// Инициализация углов
float angle_max = to_float(MB_INTERNAL.param.angle.Angle_Max, 65535);
float angle_min = to_float(MB_INTERNAL.param.angle.Angle_Min, 65535);
hangle->f.Initialized = 1;
return HAL_OK;
}
/**
* @brief Управление углом через ПИД регулятор.
* @param hangle Указатель на таймер
* @param setpoint Уставка куда регулировать
* @param measurement Измеренные регулируемые величины
*/
void Angle_PID(Angle_Handle_t *hangle, float setpoint, float measurement)
{
if(assert_upp(hangle))
return;
float err = setpoint - measurement;
/* Вычисляем выход PID */
float angle = arm_pid_f32(&hangle->pid, err); // делта подаём как ошибку
/* Ограничиваем диапазон и сохраняем в alpha */
if(angle > hangle->Config.AngleMax) angle = hangle->Config.AngleMax;
if(angle < hangle->Config.AngleMin) angle = hangle->Config.AngleMin;
Angle_SetAngle(hangle, angle);
}
/**
* @brief Сброс ПИД регулятора.
* @param hangle Указатель на таймер
*/
void Angle_PID_Reset(Angle_Handle_t *hangle)
{
if(assert_upp(hangle))
return;
/* Вычисляем выход PID */
arm_pid_reset_f32(&hangle->pid);
Angle_SetAngle(hangle, hangle->Config.AngleLimit);
Angle_Reset(hangle, UPP_PHASE_A);
Angle_Reset(hangle, UPP_PHASE_B);
Angle_Reset(hangle, UPP_PHASE_C);
}
/**
* @brief Инициализация ПИД регулятора.
* @param hangle Указатель на таймер
* @param kp, ki kd Коэффициенты регулятора
*/
void Angle_PID_Init(Angle_Handle_t *hangle, float kp, float ki, float kd)
{
if(assert_upp(hangle))
return;
hangle->pid.Kp = kp;
hangle->pid.Ki = ki;
hangle->pid.Kd = kd;
arm_pid_init_f32(&hangle->pid, 1);
}
/**
* @brief Инициализация углов открытия.
* @param hangle Указатель на таймер
@ -67,6 +138,28 @@ HAL_StatusTypeDef Angle_SetRange(Angle_Handle_t *hangle, float AngleMin, float A
return HAL_OK;
}
/**
* @brief Выставление текущего угла открытия тиристоров.
* @param hangle Указатель на таймер
* @param AngleLimit Лимит AngleMax, рассчитывается от параметров ШИМ
* @param AngleMin Минимально возможный угол открытия
* @param AngleMax Максимально возможный угол открытия
* @return HAL Status.
*/
HAL_StatusTypeDef Angle_SetAngle(Angle_Handle_t *hangle, float Angle)
{
if(assert_upp(hangle))
return HAL_ERROR;
if(Angle > hangle->Config.AngleLimit)
Angle = hangle->Config.AngleLimit;
hangle->alpha = Angle;
return HAL_OK;
}
/**
* @brief Инициализация предельного угла открытия.
* @param hangle Указатель на таймер
@ -129,7 +222,7 @@ UPP_Phase_t Angle_Handle(Angle_Handle_t *hangle)
* @param Phase Для какой фазы надо установить угол открытия
* @return HAL Status.
*/
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float Angle, float PeriodMs)
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float PeriodMs)
{
if(assert_upp(hangle))
return HAL_ERROR;
@ -139,16 +232,16 @@ HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float A
{
return HAL_ERROR;
}
if(Angle > hangle->Config.AngleMax)
if(hangle->alpha > hangle->Config.AngleMax)
{
Angle = hangle->Config.AngleMax;
hangle->alpha = hangle->Config.AngleMax;
}
if(Angle < hangle->Config.AngleMin)
if(hangle->alpha < hangle->Config.AngleMin)
{
Angle = hangle->Config.AngleMin;
hangle->alpha = hangle->Config.AngleMin;
}
uint32_t timer_ticks = TIM_MillisToTick(PeriodMs*Angle, ANGLE_TIM2_FREQ_MHZ);
uint32_t timer_ticks = TIM_MillisToTick(PeriodMs*hangle->alpha, ANGLE_TIM2_FREQ_MHZ);
uint32_t ccr_ticks = __HAL_TIM_GET_COUNTER(hangle->htim) + timer_ticks;
switch(Phase)

View File

@ -8,6 +8,9 @@
#define _ANGLE_CONTROL_H_
#include "main.h"
/**
* @brief Конфигурация алгоритма управления углом открытия
*/
typedef struct
{
float AngleLimit; ///< Лимит AngleMax, рассчитывается от параметров ШИМ
@ -15,25 +18,39 @@ typedef struct
float AngleMax; ///< Максимально возможный угол открытия
}Angle_Config_t;
/**
* @brief Структура для управления углом открытия
*/
typedef struct
{
TIM_HandleTypeDef *htim;
Angle_Config_t Config;
TIM_HandleTypeDef *htim; ///< Указатель на таймер для расчета угла
Angle_Config_t Config; ///< Конфигурации алгоритма расчета угла открытия тиристоров
float alpha; ///< текущий угол открытия
arm_pid_instance_f32 pid; ///< ПИД регулятор для управления углом
struct {
unsigned Initialized : 1;
unsigned Initialized : 1; ///< Структура инициализирована
unsigned Running : 3; ///< Сколько каналов запущено сейчас
} f;
} f; ///< Флаги
}Angle_Handle_t;
/* Инициализация Таймера для рассчета угла открытия. */
HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle);
/* Управление углом через ПИД регулятор */
void Angle_PID(Angle_Handle_t *hangle, float setpoint, float measurement);
/* Сброс ПИД регулятора. */
void Angle_PID_Reset(Angle_Handle_t *hangle);
/* Инициализация ПИД регулятора. */
void Angle_PID_Init(Angle_Handle_t *hangle, float kp, float ki, float kd);
/* Выставление текущего угла открытия тиристоров. */
HAL_StatusTypeDef Angle_SetAngle(Angle_Handle_t *hangle, float Angle);
/* Инициализация углов открытия. */
HAL_StatusTypeDef Angle_SetRange(Angle_Handle_t *hangle, float AngleMin, float AngleMax);
/* Инициализация предельного угла открытия. */
HAL_StatusTypeDef Angle_SetLimit(Angle_Handle_t *hangle, float AngleLimit);
/* Установка угла открытия в таймер. */
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float Angle, float PeriodMs);
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float PeriodMs);
/* Сброс угла открытия у таймера. */
HAL_StatusTypeDef Angle_Reset(Angle_Handle_t *hangle, UPP_Phase_t Phase);

View File

@ -6,7 +6,6 @@
* @details
******************************************************************************/
#include "pwm_thyristors.h"
#include "angle_control.h"
#include "tim.h"
static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Channel_t *hCh, uint32_t state);

View File

@ -24,10 +24,17 @@ void UPP_Control_InternalParams(void)
return;
// флаги обновились ли конфиги
static int alpha_update = 0;
static int adc_channel_update[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
static int zc_update = 0;
static int pwm_update = 0;
// временная переменная для параметров Мониторинга сети
float angle_max = upp.hangle.Config.AngleMax;
float angle_min = upp.hangle.Config.AngleMin;
float angle_pid_kp = upp.hangle.pid.Kp;
float angle_pid_ki = upp.hangle.pid.Ki;
float angle_pid_kd = upp.hangle.pid.Kd;
// временная переменная для параметров каналов АЦП
float adc_channel_max[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
uint16_t adc_channel_zero[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
@ -42,6 +49,32 @@ void UPP_Control_InternalParams(void)
float pm_alpha = upp.pm.exp[0].alpha;
// Параметры регулятора Угла открытия
if(__CheckSimpleParamF(&angle_max, MB_INTERNAL.param.angle.Angle_Max, 65535))
{
alpha_update = 1;
}
if(__CheckSimpleParamF(&angle_min, MB_INTERNAL.param.angle.Angle_Min, 65535))
{
alpha_update = 1;
}
if(__CheckSimpleParamF(&angle_pid_kp, MB_INTERNAL.param.angle.PID_Kp, 10000))
{
alpha_update = 1;
}
if(__CheckSimpleParamF(&angle_pid_ki, MB_INTERNAL.param.angle.PID_Ki, 10000))
{
alpha_update = 1;
}
if(__CheckSimpleParamF(&angle_pid_kd, MB_INTERNAL.param.angle.PID_Kd, 10000))
{
alpha_update = 1;
}
// Параметры АЦП
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
{
adc_channel_max[i] = upp.pm.adc.Coefs[i].vMax;
@ -85,7 +118,7 @@ void UPP_Control_InternalParams(void)
// Параметры мониторинга
if(__CheckSimpleParamF(&pm_alpha, MB_INTERNAL.param.pm.mean_alpha, 65535))
{
for(int i = 0; i < 3; i++)
for(int i = 0; i < EXP_ALL; i++)
{
Filter_ReInit(&upp.pm.exp[i], pm_alpha);
}
@ -93,6 +126,12 @@ void UPP_Control_InternalParams(void)
// Обновление регулятора угла открытия
if(alpha_update)
{
Angle_SetRange(&upp.hangle, angle_max, angle_max);
Angle_PID_Init(&upp.hangle, angle_pid_kp, angle_pid_ki, angle_pid_kd);
}
// Обновление АЦП конфигов
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
{
@ -152,7 +191,10 @@ void UPP_SetDefault(int pui_default, int internal_default)
}
if(internal_default)
{
{
MB_INTERNAL.param.setpoints.TemperatureWarn = SETPOINT_TEMP_WARN*10;
MB_INTERNAL.param.setpoints.TemperatureErr = SETPOINT_TEMP_ERR*10;
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;

View File

@ -10,6 +10,8 @@
#define _UPP_CONTROL_H
#include "upp_defs.h"
#define to_float(_u16_, _coef_) ((float)_u16_/_coef_)
typedef struct
{
unsigned set_default_pui:1; ///< Выставить настройки ПУИ в дефолтные
@ -23,53 +25,66 @@ typedef struct
}UPP_FuncCalls_t;
typedef struct
{
uint16_t PhaseSequence; ///< Последовательность фаз todo
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]
}UPP_ParamsNominal_t;
typedef struct
{
uint16_t TemperatureWarn; ///< Предупредительный порог температуры [Градусы x 100]
uint16_t TemperatureErr; ///< Аварийный порог температуры [Градусы x 100]
}UPP_ParamsSetpoints_t;
typedef struct
{
struct
{
uint16_t mean_alpha; ///< Коэф альфа x10000 для эксп. фильтра Umean, Imean, Fmean
uint16_t mean_alpha; ///< Коэф альфа для усредняющего эксп. фильтра [0..1 x 65535]
}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;
UPP_ParamsNominal_t nominal;
UPP_ParamsSetpoints_t setpoints;
/* Параметры АЦП */
struct
{
uint16_t ADC_Max[4]; ///< В x 10
uint16_t ADC_Zero[4]; ///< Кванты АЦП
uint16_t ADC_Max[4]; ///< Величина в единицах измерения при АЦП = 4095 [В или А x 10]
uint16_t ADC_Zero[4]; ///< Кванты АЦП когда на входе ноль
}adc;
/* Параметры ШИМ */
struct
{
uint16_t PhaseMask; ///< Битовяя маска на какие фазы подавать ШИМ: 0 бит - a, 1 бит - b, 2 бит - c
uint16_t Frequency; ///< Частота ШИМ для пачки импульсов на тиристоры
uint16_t PulseNumber; ///< Количесво импульсов в пачке
uint16_t Frequency; ///< Частота ШИМ для пачки импульсов на тиристоры [Герцы]
uint16_t PulseNumber; ///< Количесво импульсов в пачке [Количество]
}pwm;
/* Параметры Угла */
struct
{
uint16_t Hysteresis; ///< Гистерезис для определения перехода через ноль
uint16_t DebouneCouner; ///< Защита от дребезга: через сколько тактов снова начать фиксировать переход через ноль
uint16_t Hysteresis; ///< Гистерезис для определения перехода через ноль [Проценты x 100]
uint16_t DebouneCouner; ///< Защита от дребезга: через сколько тактов снова начать фиксировать переход через ноль [Количество]
}zc;
/* Параметры Угла */
struct
{
uint16_t Angle_Max; ///< Максимальный угол открытия тиристора
uint16_t Angle_Min; ///< Минимальный угол открытия тиристора
uint16_t Angle_Max; ///< Максимальный угол открытия тиристора [0..1 x 65535]
uint16_t Angle_Min; ///< Минимальный угол открытия тиристора [0..1 x 65535]
uint16_t PID_Kp; ///< Пропорциональный коэфициент ПИ регулятора угла [x 1000]
uint16_t PID_Ki; ///< Интегральный коэфициент ПИ регулятора угла [x 1000]
uint16_t PID_Kd; ///< Интегральный коэфициент ПИ регулятора угла [x 1000]
}angle;

View File

@ -1,13 +1,173 @@
/**
******************************************************************************
* @file upp_errors.c
* @brief Ошибки УПП и их обработка
* @brief Формирование ошибок в ПУИ
******************************************************************************
* @details
******************************************************************************/
#include "upp_main.h" // УПП
#include "upp_errors.h" // всё остальное по работе с УПП
UPP_Errors_t errors;
static UPP_ErrorType_t UPP_SelectCommonError(void);
static int setError(int condition, int flag, int *timer, int delay);
void UPP_Errors_Program(void);
void UPP_Errors_Power(void);
void UPP_Errors_Ranges(void);
void UPP_Errors_LossPhase(void);
void UPP_Errors_Other(void);
void UPP_Errors_Handle(void)
{
/*====== Программные ошибки ======*/
UPP_Errors_Program();
/*====== Ошибки питания плат ======*/
UPP_Errors_Power();
/*====== Ошибки выхода за допустимые пределы ======*/
UPP_Errors_Ranges();
/*====== Потери фазы ======*/
UPP_Errors_LossPhase();
/*====== Остальные ======*/
UPP_Errors_Other();
errors.common = UPP_SelectCommonError();
}
void UPP_Errors_Program(void)
{
}
void UPP_Errors_Power(void)
{
//read discrete inputs
}
void UPP_Errors_Ranges(void)
{
/* Преобразуем уставки в нормальные тики */
float ticksTiMax = to_float(MB_DATA.HoldRegs.pui_params.TiMax, 1)/PM_SLOW_PERIOD_US;
/* Счетчики для отсчитывания задержки выставления ошибки */
static int IMaxCnt = 0;
static int UMaxCnt = 0;
static int UMinCnt = 0;
static int FMaxCnt = 0;
static int FMinCnt = 0;
static int TMaxCnt = 0;
/* Напряжения */
errors.pui.err.OverVoltage = setError(errors.prvt.f.err.uamp_max,
errors.pui.err.OverVoltage,
&UMaxCnt,
ticksTiMax);
errors.pui.err.UnderVoltage = setError(errors.prvt.f.err.uamp_min,
errors.pui.err.UnderVoltage,
&UMinCnt,
ticksTiMax);
/* Токи */
int i_max = ( errors.prvt.f.err.iamp_max ||
errors.prvt.f.err.ia_max ||
errors.prvt.f.err.ib_max ||
errors.prvt.f.err.ic_max);
errors.pui.err.OverCurrent = setError(i_max,
errors.pui.err.OverCurrent,
&IMaxCnt,
ticksTiMax);
/* Частота */
int f_max = ( errors.prvt.f.err.fac_max ||
errors.prvt.f.err.fba_max ||
errors.prvt.f.err.fbc_max);
int f_min = ( errors.prvt.f.err.fac_max ||
errors.prvt.f.err.fba_max ||
errors.prvt.f.err.fbc_max);
errors.pui.err.OverFrequency = setError(f_max,
errors.pui.err.OverFrequency,
&FMaxCnt,
ERRORS_DELAY_TICKS_DEFAULT);
errors.pui.err.UnderFrequency = setError( f_min,
errors.pui.err.UnderFrequency,
&FMinCnt,
ERRORS_DELAY_TICKS_DEFAULT);
/* Температуры */
errors.pui.err.OverTemperature = setError(errors.prvt.f.err.temp_err,
errors.pui.err.OverTemperature,
&TMaxCnt,
ERRORS_DELAY_TICKS_DEFAULT);
}
void UPP_Errors_LossPhase(void)
{
/* Счетчики для отсчитывания задержки выставления ошибки */
static int LossPhaseAllCnt = 0;
static int LossPhaseACnt = 0;
static int LossPhaseBCnt = 0;
static int LossPhaseCCnt = 0;
int loss_phases_all = ( errors.prvt.f.err.ia_min &&
errors.prvt.f.err.ib_min &&
errors.prvt.f.err.ic_min );
errors.pui.err.LossPhaseAll = setError( loss_phases_all,
errors.pui.err.LossPhaseAll,
&LossPhaseAllCnt,
ERRORS_DELAY_TICKS_DEFAULT);
/* Если хотя бы одна фаза есть проверяем фазы отдельно */
if(!errors.pui.err.LossPhaseAll)
{
errors.pui.err.LossPhaseA = setError( errors.prvt.f.err.ia_min,
errors.pui.err.LossPhaseA,
&LossPhaseACnt,
ERRORS_DELAY_TICKS_DEFAULT);
errors.pui.err.LossPhaseB = setError( errors.prvt.f.err.ib_min,
errors.pui.err.LossPhaseB,
&LossPhaseBCnt,
ERRORS_DELAY_TICKS_DEFAULT);
errors.pui.err.LossPhaseC = setError( errors.prvt.f.err.ic_min,
errors.pui.err.LossPhaseC,
&LossPhaseCCnt,
ERRORS_DELAY_TICKS_DEFAULT);
}
/* Если всех фаз нет, то отдельные не смотрим */
else
{
errors.pui.err.LossPhaseA = 0;
errors.pui.err.LossPhaseB = 0;
errors.pui.err.LossPhaseC = 0;
}
}
void UPP_Errors_Other(void)
{
static int InterlaceCnt = 0;
if(errors.prvt.f.err.longstart)
errors.pui.err.LongStart = 1;
else
errors.pui.err.LongStart = 0;
errors.pui.err.Interlace = setError(errors.prvt.f.err.interlance,
errors.pui.err.Interlace,
&InterlaceCnt,
ERRORS_DELAY_TICKS_DEFAULT);
//Interlance
}
static UPP_ErrorType_t UPP_SelectCommonError(void)
{
// Пока нет ошибки
@ -38,7 +198,20 @@ static UPP_ErrorType_t UPP_SelectCommonError(void)
return best;
}
void UPP_ErrorsHandle(void)
static int setError(int condition, int flag, int *timer, int delay)
{
errors.common = UPP_SelectCommonError();
if (condition) {
if (*timer < delay)
(*timer)++;
else
flag = 1;
} else {
if (*timer > 0)
(*timer)--;
else
flag = 0;
}
return flag;
}

View File

@ -64,36 +64,37 @@ typedef struct
struct
{
/* Програмные ошибки */
unsigned Internal_1:1; ///< Внутренняя неисправность УПП 1
unsigned Internal_2:1; ///< Внутренняя неисправность УПП 2
unsigned Internal_3:1; ///< Внутренняя неисправность УПП 3
unsigned Internal_4:1; ///< Внутренняя неисправность УПП 4
unsigned Internal_5:1; ///< Внутренняя неисправность УПП 5
unsigned Internal_6:1; ///< Внутренняя неисправность УПП 6
unsigned Internal_1:1; ///< Ошибка 1: Внутренняя неисправность УПП 1
unsigned Internal_2:1; ///< Ошибка 2: Внутренняя неисправность УПП 2
unsigned Internal_3:1; ///< Ошибка 3: Внутренняя неисправность УПП 3
unsigned Internal_4:1; ///< Ошибка 4: Внутренняя неисправность УПП 4
unsigned Internal_5:1; ///< Ошибка 5: Внутренняя неисправность УПП 5
unsigned Internal_6:1; ///< Ошибка 6: Внутренняя неисправность УПП 6
/* Ошибки по питанию */
unsigned Power_Digit_5V:1; ///< Неисправность цифрового источника питания (5 В)
unsigned Power_24V:1; ///< Неисправность источника питания 24 В
unsigned Power_Analog_5V:1; ///< Неисправность аналогового источника питания микроконтроллера (± 5 В)
unsigned Power_SCI_5V:1; ///< Неисправность источника питания последовательных интерфейсов микроконтроллера (5 В)
unsigned Power_DIO_24V:1; ///< Неисправность источника питания дискретных входов/выходов (24 В)
unsigned Power_Digit_5V:1; ///< Ошибка 7: Неисправность цифрового источника питания (5 В)
unsigned Power_24V:1; ///< Ошибка 8: Неисправность источника питания 24 В
unsigned Power_Analog_5V:1; ///< Ошибка 9: Неисправность аналогового источника питания микроконтроллера (± 5 В)
unsigned Power_SCI_5V:1; ///< Ошибка 10: Неисправность источника питания последовательных интерфейсов микроконтроллера (5 В)
unsigned Power_DIO_24V:1; ///< Ошибка 11: Неисправность источника питания дискретных входов/выходов (24 В)
/* Ошибки по допустимым пределам Наряжений/Токов/Температуры */
unsigned OverCurrent:1; ///< Ток выше допустимого (см. Imax и TiMax в @ref UPP_PUI_Params_t)
unsigned OverVoltage:1; ///< Напряжение сети выше допустимого (см. Umах в @ref UPP_PUI_Params_t)
unsigned OverTemperature:1; ///< Температура выше допустимой (плюс 85 °C)
unsigned UnderVoltage:1; ///< Напряжение сети ниже допустимого (см. Umin в @ref UPP_PUI_Params_t)
unsigned OverCurrent:1; ///< Ошибка 12: Ток выше допустимого (см. Imax и TiMax в @ref UPP_PUI_Params_t)
unsigned OverVoltage:1; ///< Ошибка 13: Напряжение сети выше допустимого (см. Umах в @ref UPP_PUI_Params_t)
unsigned OverTemperature:1; ///< Ошибка 14: Температура выше допустимой (плюс 85 °C)
unsigned UnderVoltage:1; ///< Ошибка 15: Напряжение сети ниже допустимого (см. Umin в @ref UPP_PUI_Params_t)
/* Ошибки по обрывам фаз */
unsigned LossPhaseA:1; ///< Обрыв фазы A (см. Imin в @ref UPP_PUI_Params_t)
unsigned LossPhaseB:1; ///< Обрыв фазы B (см. Imin в @ref UPP_PUI_Params_t)
unsigned LossPhaseC:1; ///< Обрыв фазы C (см. Imin в @ref UPP_PUI_Params_t)
unsigned LossPhaseAll:1; ///< Ошибка 16: Обрыв трёх фаз (см. Imin в @ref UPP_PUI_Params_t)
unsigned LossPhaseA:1; ///< Ошибка 17: Обрыв фазы A (см. Imin в @ref UPP_PUI_Params_t)
unsigned LossPhaseB:1; ///< Ошибка 18: Обрыв фазы B (см. Imin в @ref UPP_PUI_Params_t)
unsigned LossPhaseC:1; ///< Ошибка 19: Обрыв фазы C (см. Imin в @ref UPP_PUI_Params_t)
/* Другие ошибки */
unsigned LongStart:1; ///< Затянутый пуск (ток не спадает за установленное время) (см. Tdelay в @ref UPP_PUI_Params_t)
unsigned Interlace:1; ///< Неправильный порядок чередования фаз (см. Interlace в @ref UPP_PUI_Params_t)
unsigned OverFrequency:1; ///< Частота сети выше допустимой
unsigned UnderFrequency:1; ///< Частота сети ниже допустимой
unsigned LongStart:1; ///< Ошибка 20: Затянутый пуск (ток не спадает за установленное время) (см. Tdelay в @ref UPP_PUI_Params_t)
unsigned Interlace:1; ///< Ошибка 21: Неправильный порядок чередования фаз (см. Interlace в @ref UPP_PUI_Params_t)
unsigned OverFrequency:1; ///< Ошибка 22: Частота сети выше допустимой
unsigned UnderFrequency:1; ///< Ошибка 23: Частота сети ниже допустимой
}err;
}pui;
@ -104,6 +105,39 @@ typedef struct
uint64_t all;
struct
{
unsigned uamp_max:1;
unsigned uamp_min:1;
unsigned iamp_max:1;
unsigned iamp_min:1;
unsigned ic_max:1;
unsigned ic_min:1;
unsigned ib_max:1;
unsigned ib_min:1;
unsigned ia_max:1;
unsigned ia_min:1;
unsigned uba_max:1;
unsigned uba_min:1;
unsigned uac_max:1;
unsigned uac_min:1;
unsigned ubc_max:1;
unsigned ubc_min:1;
unsigned fba_max:1;
unsigned fba_min:1;
unsigned fac_max:1;
unsigned fac_min:1;
unsigned fbc_max:1;
unsigned fbc_min:1;
unsigned temp_warn:1;
unsigned temp_err:1;
unsigned longstart:1;
unsigned interlance:3;
unsigned slow_calc_overrun:1;
}err;
}f;
@ -120,6 +154,6 @@ typedef struct
}UPP_Errors_t;
extern UPP_Errors_t errors;
void UPP_ErrorsHandle(void);
void UPP_Errors_Handle(void);
#endif //_UPP_ERRORS_H

View File

@ -9,7 +9,7 @@
#include "tim.h"
UPP_t upp;
float alpha_dbg = 0.5;
float iref_dbg = 0;
// ОСНОВНОЙ ЦИКЛ main.c
/**
@ -52,73 +52,84 @@ int UPP_PreWhile(void)
*/
int UPP_While(void)
{
// если ошибка вызываем СТОП
if(errors.pui.all)
if(upp.pm.f.runSlow)
{
upp.call->stop = 1;
}
// иначе снимаем СТОП
// если ошибка вызываем СТОП
if(errors.pui.all)
{
upp.call->stop = 0;
}
// иначе снимаем СТОП
else
{
upp.call->stop = 0;
}
if (upp.call->stop)
upp.workmode = WM_Error;
// Сброс на дефолтные по запросу
if(upp.call->set_default_pui)
{
UPP_SetDefault(1, 0);
}
if(upp.call->set_default_internal)
{
UPP_SetDefault(0, 1);
}
PowerMonitor_SlowCalc(&upp.pm);
// Если СТОП - переходим в ошибку
// Автомат состояний УПП
switch(upp.workmode)
{
case WM_Ready:
// если пришла команда на запуск
if (upp.call->go)
{
upp.workmode = WM_Running;
Angle_PID_Reset(&upp.hangle);
upp.StartTick = local_time();
}
break;
case WM_Running:
// если пришла команда на остановку
if (!upp.call->go)
upp.workmode = WM_Ready;
// Регулирование тиристоров
Angle_PID(&upp.hangle, iref_dbg, upp.pm.measured.final.Iamp);
// если слишком долгий запуск
if((local_time() - upp.StartTick) > (upp.PUI.params->Tdelay*1000))
{
errors.pui.err.LongStart = 1;
}
break;
case WM_Error:
if(errors.common == Err_None)
upp.workmode = WM_Ready;
PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
break;
case WM_Done:
PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
break;
default:
break;
}
upp.pm.f.runSlow = 0;
}//if(upp.pm.f.runSlow)
else
{
upp.call->stop = 0;
}
// Сброс на дефолтные по запросу
if(upp.call->set_default_pui)
{
UPP_SetDefault(1, 0);
}
if(upp.call->set_default_internal)
{
UPP_SetDefault(0, 1);
}
PowerMonitor_SlowHandle(&upp.pm);
// Если СТОП - переходим в ошибку
if (upp.call->stop)
upp.workmode = WM_Error;
// Автомат состояний УПП
switch(upp.workmode)
{
case WM_Ready:
// если пришла команда на запуск
if (upp.call->go)
{
upp.workmode = WM_Running;
upp.StartTick = local_time();
}
break;
case WM_Running:
// если пришла команда на остановку
if (!upp.call->go)
upp.workmode = WM_Ready;
// если слишком долгий запуск
if((local_time() - upp.StartTick) > (upp.PUI.params->Tdelay*1000))
{
errors.pui.err.LongStart = 1;
}
break;
case WM_Error:
if(errors.common == Err_None)
upp.workmode = WM_Ready;
PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
break;
case WM_Done:
PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
break;
default:
break;
}
return 0;
}
@ -131,7 +142,7 @@ void UPP_Tick(void)
{
if(upp.workmode == WM_Not_Init)
return;
UPP_ErrorsHandle();
UPP_Errors_Handle();
UPP_Control_InternalParams();
}
@ -143,7 +154,7 @@ void UPP_ADC_Handle(void)
{
BenchTime_Start(BT_ADC, angletim.Instance->CNT, HAL_MAX_DELAY);
PowerMonitor_Handle(&upp.pm);
PowerMonitor_FastCalc(&upp.pm);
for(int phase = 0; phase < 3; phase++)
{
@ -157,7 +168,7 @@ void UPP_ADC_Handle(void)
UPP_HalfWave_t curr_halfwave = ZC_GetHalfWave(&upp.pm.zc, phase);
PWM_SetHalfWave(&upp.hpwm, phase, curr_halfwave);
// Начинаем отсчитывать угол
Angle_Start(&upp.hangle, phase, alpha_dbg, 10);
Angle_Start(&upp.hangle, phase, 10);
}
}
}

View File

@ -17,8 +17,6 @@
#include "upp_status.h" // статус упп
#include "upp_control.h" // управление упп
extern float alpha_dbg;
typedef struct
{