Compare commits
15 Commits
c26319f832
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7286f33709 | ||
|
|
9b4ccd63b0 | ||
|
|
67be0b2304 | ||
|
|
9234b4508b | ||
|
|
1690cdcb93 | ||
|
|
2703f7efda | ||
|
|
aa59f84fb7 | ||
|
|
c0eea077d9 | ||
|
|
2775e0a9b6 | ||
|
|
3750d579fa | ||
|
|
eb6979aa27 | ||
|
|
7d40322f1e | ||
|
|
0de4aad4ef | ||
|
|
854ea6f6c2 | ||
|
|
5624468d09 |
@@ -3,6 +3,8 @@
|
|||||||
#include "dsp/none.h"
|
#include "dsp/none.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define _sqrtf(...) sqrtf(__VA_ARGS__)
|
||||||
|
|
||||||
#define __disable_irq()
|
#define __disable_irq()
|
||||||
|
|
||||||
#ifndef __ASM
|
#ifndef __ASM
|
||||||
|
|||||||
@@ -95,16 +95,76 @@ void DMA_Sim_Transfer(DMA_TypeDef* DMAx, uint32_t stream)
|
|||||||
stream_sim->current_index++;
|
stream_sim->current_index++;
|
||||||
|
|
||||||
|
|
||||||
// Проверяем завершение передачи
|
// Определяем какой регистр использовать (LISR или HISR) в зависимости от потока
|
||||||
|
volatile uint32_t* lisr_reg = NULL;
|
||||||
|
volatile uint32_t* hisr_reg = NULL;
|
||||||
|
uint32_t tcif_mask = 0;
|
||||||
|
uint32_t htif_mask = 0;
|
||||||
|
|
||||||
|
// Настраиваем маски флагов в зависимости от потока
|
||||||
|
if (DMAx == DMA1) {
|
||||||
|
lisr_reg = &DMA1->LISR;
|
||||||
|
hisr_reg = &DMA1->HISR;
|
||||||
|
}
|
||||||
|
#ifdef DMA2
|
||||||
|
else if (DMAx == DMA2) {
|
||||||
|
lisr_reg = &DMA2->LISR;
|
||||||
|
hisr_reg = &DMA2->HISR;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Устанавливаем маски для конкретного потока
|
||||||
|
switch (stream) {
|
||||||
|
case 0:
|
||||||
|
case 4:
|
||||||
|
tcif_mask = DMA_FLAG_TCIF0_4; htif_mask = DMA_FLAG_HTIF0_4; break;
|
||||||
|
case 1:
|
||||||
|
case 5:
|
||||||
|
tcif_mask = DMA_FLAG_TCIF1_5; htif_mask = DMA_FLAG_HTIF1_5; break;
|
||||||
|
case 2:
|
||||||
|
case 6:
|
||||||
|
tcif_mask = DMA_FLAG_TCIF2_6; htif_mask = DMA_FLAG_HTIF2_6; break;
|
||||||
|
case 3:
|
||||||
|
case 7:
|
||||||
|
tcif_mask = DMA_FLAG_TCIF3_7; htif_mask = DMA_FLAG_HTIF3_7; break;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Проверяем и выставляем флаги
|
||||||
|
if (stream_sim->current_index == stream_sim->buffer_size / 2) {
|
||||||
|
// Половинное заполнение - выставляем флаг HTIF
|
||||||
|
if (stream < 4) {
|
||||||
|
*lisr_reg |= htif_mask; // Потоки 0-3 в LISR
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*hisr_reg |= htif_mask; // Потоки 4-7 в HISR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Вызываем обработчик прерывания
|
||||||
|
//DMA_Call_IRQHandller(DMAx, stream); //todo
|
||||||
|
}
|
||||||
|
|
||||||
if (stream_sim->current_index >= stream_sim->buffer_size) {
|
if (stream_sim->current_index >= stream_sim->buffer_size) {
|
||||||
|
// Полное заполнение - выставляем флаг TCIF
|
||||||
|
if (stream < 4) {
|
||||||
|
*lisr_reg |= tcif_mask; // Потоки 0-3 в LISR
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*hisr_reg |= tcif_mask; // Потоки 4-7 в HISR
|
||||||
|
}
|
||||||
|
|
||||||
stream_sim->transfer_complete = 1;
|
stream_sim->transfer_complete = 1;
|
||||||
|
|
||||||
if (stream_sim->circular_mode) {
|
if (stream_sim->circular_mode) {
|
||||||
stream_sim->current_index = 0;
|
stream_sim->current_index = 0;
|
||||||
} else {
|
// В циклическом режиме не сбрасываем флаги - они должны быть сброшены программно
|
||||||
|
}
|
||||||
|
else {
|
||||||
stream_sim->transfer_enabled = 0;
|
stream_sim->transfer_enabled = 0;
|
||||||
stream_sim->enabled = 0;
|
stream_sim->enabled = 0;
|
||||||
DMA_Call_IRQHandller(DMAx, stream);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Вызываем обработчик прерывания
|
||||||
|
DMA_Call_IRQHandller(DMAx, stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -737,15 +737,15 @@ void TIM_Call_IRQHandller(TIM_TypeDef* TIMx)
|
|||||||
TIM6_DAC_IRQHandler();
|
TIM6_DAC_IRQHandler();
|
||||||
else if (TIMx == TIM7)
|
else if (TIMx == TIM7)
|
||||||
TIM7_IRQHandler();
|
TIM7_IRQHandler();
|
||||||
else if ((TIMx == TIM8) || (TIMx == TIM13))
|
else if (((TIMx == TIM8) && (TIM8->SR & TIM_SR_UIF)) || (TIMx == TIM13))
|
||||||
TIM8_UP_TIM13_IRQHandler();
|
TIM8_UP_TIM13_IRQHandler();
|
||||||
else if ((TIMx == TIM1) || (TIMx == TIM9))
|
else if (((TIMx == TIM1) && 0) || (TIMx == TIM9))
|
||||||
TIM1_BRK_TIM9_IRQHandler();
|
TIM1_BRK_TIM9_IRQHandler();
|
||||||
else if ((TIMx == TIM1) || (TIMx == TIM11))
|
else if (((TIMx == TIM1) && (TIM1->SR & (TIM_SR_CC1IF|TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF))) || (TIMx == TIM11))
|
||||||
TIM1_TRG_COM_TIM11_IRQHandler();
|
TIM1_TRG_COM_TIM11_IRQHandler();
|
||||||
else if ((TIMx == TIM8) || (TIMx == TIM12))
|
else if (((TIMx == TIM8) && 0) || (TIMx == TIM12))
|
||||||
TIM8_BRK_TIM12_IRQHandler();
|
TIM8_BRK_TIM12_IRQHandler();
|
||||||
else if ((TIMx == TIM8) || (TIMx == TIM14))
|
else if (((TIMx == TIM8) && (TIM8->SR & (TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF))) || (TIMx == TIM14))
|
||||||
TIM8_TRG_COM_TIM14_IRQHandler();
|
TIM8_TRG_COM_TIM14_IRQHandler();
|
||||||
|
|
||||||
SR_PROCESS(TIMx, SR);
|
SR_PROCESS(TIMx, SR);
|
||||||
|
|||||||
@@ -22,14 +22,16 @@ SIM__MCUHandleTypeDef hmcu; ///< Хендл для управления
|
|||||||
*/
|
*/
|
||||||
const int inLengths[IN_PORT_NUMB] = {
|
const int inLengths[IN_PORT_NUMB] = {
|
||||||
ADC_PORT_1_WIDTH,
|
ADC_PORT_1_WIDTH,
|
||||||
IN_PORT_2_WIDTH
|
PUI_PORT_2_WIDTH,
|
||||||
|
INTERNAL_PORT_3_WIDTH
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @brief Таблица смещений в выходном массиве IN
|
* @brief Таблица смещений в выходном массиве IN
|
||||||
*/
|
*/
|
||||||
const int inOffsets[IN_PORT_NUMB] = {
|
const int inOffsets[IN_PORT_NUMB] = {
|
||||||
OFFSET_IN_ARRAY_1,
|
OFFSET_IN_ARRAY_1,
|
||||||
OFFSET_IN_ARRAY_2
|
OFFSET_IN_ARRAY_2,
|
||||||
|
OFFSET_IN_ARRAY_3
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -53,9 +53,10 @@
|
|||||||
|
|
||||||
// Parameters of S_Function
|
// Parameters of S_Function
|
||||||
// INPUT/OUTPUTS PARAMS START
|
// INPUT/OUTPUTS PARAMS START
|
||||||
#define IN_PORT_NUMB 2
|
#define IN_PORT_NUMB 3
|
||||||
#define ADC_PORT_1_WIDTH 6
|
#define ADC_PORT_1_WIDTH 6
|
||||||
#define IN_PORT_2_WIDTH 16
|
#define PUI_PORT_2_WIDTH 10
|
||||||
|
#define INTERNAL_PORT_3_WIDTH 16
|
||||||
|
|
||||||
#define OUT_PORT_NUMB 5
|
#define OUT_PORT_NUMB 5
|
||||||
#define THYR_PORT_1_WIDTH 6
|
#define THYR_PORT_1_WIDTH 6
|
||||||
@@ -94,11 +95,12 @@
|
|||||||
|
|
||||||
// INPUT/OUTPUTS AUTO-PARAMS START
|
// INPUT/OUTPUTS AUTO-PARAMS START
|
||||||
/// === Полный размер буфера ===
|
/// === Полный размер буфера ===
|
||||||
#define TOTAL_IN_SIZE (ADC_PORT_1_WIDTH + IN_PORT_2_WIDTH)
|
#define TOTAL_IN_SIZE (ADC_PORT_1_WIDTH + PUI_PORT_2_WIDTH + INTERNAL_PORT_3_WIDTH)
|
||||||
|
|
||||||
/// === Смещения массивов (внутри общего буфера) ===
|
/// === Смещения массивов (внутри общего буфера) ===
|
||||||
#define OFFSET_IN_ARRAY_1 0
|
#define OFFSET_IN_ARRAY_1 0
|
||||||
#define OFFSET_IN_ARRAY_2 (OFFSET_IN_ARRAY_1 + ADC_PORT_1_WIDTH)
|
#define OFFSET_IN_ARRAY_2 (OFFSET_IN_ARRAY_1 + ADC_PORT_1_WIDTH)
|
||||||
|
#define OFFSET_IN_ARRAY_3 (OFFSET_IN_ARRAY_2 + PUI_PORT_2_WIDTH)
|
||||||
|
|
||||||
/// === Полный размер буфера ===
|
/// === Полный размер буфера ===
|
||||||
#define TOTAL_OUT_SIZE (THYR_PORT_1_WIDTH + DO_PORT_2_WIDTH + PM_PORT_3_WIDTH + ANGLE_PORT_4_WIDTH + OUT_PORT_5_WIDTH)
|
#define TOTAL_OUT_SIZE (THYR_PORT_1_WIDTH + DO_PORT_2_WIDTH + PM_PORT_3_WIDTH + ANGLE_PORT_4_WIDTH + OUT_PORT_5_WIDTH)
|
||||||
|
|||||||
@@ -6,21 +6,52 @@
|
|||||||
#include "mcu_wrapper_conf.h"
|
#include "mcu_wrapper_conf.h"
|
||||||
#include "app_wrapper.h"
|
#include "app_wrapper.h"
|
||||||
|
|
||||||
|
float dbg_err_limit = 0;
|
||||||
float dbg[16];
|
float dbg[16];
|
||||||
extern float dbg_iref;
|
|
||||||
#define PIN_READ(_verbname_) (_verbname_##_GPIO_Port->ODR & (_verbname_##_Pin)) ? 1 : 0
|
#define PIN_READ(_verbname_) (_verbname_##_GPIO_Port->ODR & (_verbname_##_Pin)) ? 1 : 0
|
||||||
|
|
||||||
|
void pwm_wtf(PWM_State_t state1, PWM_State_t state2, int* pwm_pin)
|
||||||
|
{
|
||||||
|
if ((*pwm_pin == 0) && (state1 == PWM_THYR_TIM_ACTIVE))
|
||||||
|
{
|
||||||
|
*pwm_pin = 1;
|
||||||
|
}
|
||||||
|
else if ((*pwm_pin == 1) && (state2 == PWM_THYR_TIM_ACTIVE))
|
||||||
|
{
|
||||||
|
*pwm_pin = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pwm1_pin = 0;
|
||||||
|
int pwm2_pin = 0;
|
||||||
|
int pwm3_pin = 0;
|
||||||
|
int pwm4_pin = 0;
|
||||||
|
int pwm5_pin = 0;
|
||||||
|
int pwm6_pin = 0;
|
||||||
void Write_UPP_Outputs(real_T* Buffer, int ind_port)
|
void Write_UPP_Outputs(real_T* Buffer, int ind_port)
|
||||||
{
|
{
|
||||||
int pwm1_pin = PIN_READ(PWM1);
|
//int pwm1_pin = PIN_READ(PWM1);
|
||||||
int pwm2_pin = PIN_READ(PWM2);
|
//int pwm2_pin = PIN_READ(PWM2);
|
||||||
int pwm3_pin = PIN_READ(PWM3);
|
//int pwm3_pin = PIN_READ(PWM3);
|
||||||
int pwm4_pin = PIN_READ(PWM4);
|
//int pwm4_pin = PIN_READ(PWM4);
|
||||||
int pwm5_pin = PIN_READ(PWM5);
|
//int pwm5_pin = PIN_READ(PWM5);
|
||||||
int pwm6_pin = PIN_READ(PWM6);
|
//int pwm6_pin = PIN_READ(PWM6);
|
||||||
|
int pwm1_pin = (upp.hpwm.AllPhases[PHASE_A_POS].State == PWM_THYR_TIM_ACTIVE);
|
||||||
|
int pwm2_pin = (upp.hpwm.AllPhases[PHASE_A_NEG].State == PWM_THYR_TIM_ACTIVE);
|
||||||
|
int pwm3_pin = (upp.hpwm.AllPhases[PHASE_B_POS].State == PWM_THYR_TIM_ACTIVE);
|
||||||
|
int pwm4_pin = (upp.hpwm.AllPhases[PHASE_B_NEG].State == PWM_THYR_TIM_ACTIVE);
|
||||||
|
int pwm5_pin = (upp.hpwm.AllPhases[PHASE_C_POS].State == PWM_THYR_TIM_ACTIVE);
|
||||||
|
int pwm6_pin = (upp.hpwm.AllPhases[PHASE_C_NEG].State == PWM_THYR_TIM_ACTIVE);
|
||||||
|
|
||||||
|
//pwm_wtf(upp.hpwm.AllPhases[PHASE_A_POS].State, upp.hpwm.AllPhases[PHASE_A_NEG].State, &pwm1_pin);
|
||||||
|
//pwm_wtf(upp.hpwm.AllPhases[PHASE_A_NEG].State, upp.hpwm.AllPhases[PHASE_A_POS].State, &pwm2_pin);
|
||||||
|
//pwm_wtf(upp.hpwm.AllPhases[PHASE_B_POS].State, upp.hpwm.AllPhases[PHASE_B_NEG].State, &pwm3_pin);
|
||||||
|
//pwm_wtf(upp.hpwm.AllPhases[PHASE_B_NEG].State, upp.hpwm.AllPhases[PHASE_B_POS].State, &pwm4_pin);
|
||||||
|
//pwm_wtf(upp.hpwm.AllPhases[PHASE_C_POS].State, upp.hpwm.AllPhases[PHASE_C_NEG].State, &pwm5_pin);
|
||||||
|
//pwm_wtf(upp.hpwm.AllPhases[PHASE_C_NEG].State, upp.hpwm.AllPhases[PHASE_C_POS].State, &pwm6_pin);
|
||||||
int err = PIN_READ(RDO1);
|
int err = PIN_READ(RDO1);
|
||||||
int work = PIN_READ(RDO2);
|
int work = PIN_READ(RDO2);
|
||||||
int ready = PIN_READ(RDO3);
|
int ready = upp.errors->common;
|
||||||
|
|
||||||
if (CEN_GPIO_Port->ODR & CEN_Pin)
|
if (CEN_GPIO_Port->ODR & CEN_Pin)
|
||||||
{
|
{
|
||||||
@@ -84,6 +115,12 @@ void Write_PowerMonitor(real_T* Buffer, int ind_port)
|
|||||||
WriteOutputArray(upp.pm.measured.final.I[2], ind_port, nn++);
|
WriteOutputArray(upp.pm.measured.final.I[2], ind_port, nn++);
|
||||||
WriteOutputArray(upp.pm.measured.final.Fmean, ind_port, nn++);
|
WriteOutputArray(upp.pm.measured.final.Fmean, ind_port, nn++);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ //20-21
|
||||||
|
WriteOutputArray(upp.pm.isr_cnt, ind_port, nn++);
|
||||||
|
WriteOutputArray(upp.pm.slow_cnt%PM_SLOW_PERIOD_CNT, ind_port, nn++);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -115,18 +152,38 @@ void app_readInputs(const real_T* Buffer) {
|
|||||||
ADC_Set_Channel_Value(ADC3, 8, ReadInputArray(0,4));
|
ADC_Set_Channel_Value(ADC3, 8, ReadInputArray(0,4));
|
||||||
ADC_Set_Channel_Value(ADC3, 10, ReadInputArray(0,5));
|
ADC_Set_Channel_Value(ADC3, 10, ReadInputArray(0,5));
|
||||||
|
|
||||||
dbg_iref = ReadInputArray(1, 0);
|
upp.call->go = ReadInputArray(1, 0);
|
||||||
upp.call->go = ReadInputArray(1, 1);
|
|
||||||
|
|
||||||
MB_INTERNAL.param.angle.Angle_Max = ReadInputArray(1, 2)*65535;
|
if (upp.workmode != UPP_Work)
|
||||||
MB_INTERNAL.param.angle.Angle_Min = ReadInputArray(1, 3)*65535;
|
{
|
||||||
MB_INTERNAL.param.angle.PID_Kp = ReadInputArray(1, 4) * 10000;
|
MB_DATA.HoldRegs.pui_params.Iref = ReadInputArray(1, 1);
|
||||||
MB_INTERNAL.param.angle.PID_Ki = ReadInputArray(1, 5) * 10000;
|
MB_DATA.HoldRegs.pui_params.Tnt = ReadInputArray(1, 2);
|
||||||
MB_INTERNAL.param.angle.PID_Kd = ReadInputArray(1, 6) * 10000;
|
MB_DATA.HoldRegs.pui_params.Umin = ReadInputArray(1, 3);
|
||||||
MB_INTERNAL.param.angle.PID_ExpAlpha = ReadInputArray(1, 7) * 65535;
|
MB_DATA.HoldRegs.pui_params.Umax = ReadInputArray(1, 4);
|
||||||
|
MB_DATA.HoldRegs.pui_params.Imax = ReadInputArray(1, 5);
|
||||||
|
MB_DATA.HoldRegs.pui_params.Imin = ReadInputArray(1, 6);
|
||||||
|
MB_DATA.HoldRegs.pui_params.TiMax = ReadInputArray(1, 7);
|
||||||
|
MB_DATA.HoldRegs.pui_params.Tdelay = ReadInputArray(1, 8);
|
||||||
|
MB_DATA.HoldRegs.pui_params.Interlace = ReadInputArray(1, 9);
|
||||||
|
|
||||||
MB_INTERNAL.param.nominal.U = ReadInputArray(1, 8) * 10;
|
|
||||||
MB_INTERNAL.param.nominal.I = ReadInputArray(1, 9) * 10;
|
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UAC] = ReadInputArray(2, 0) * 10;
|
||||||
|
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UBA] = ReadInputArray(2, 0) * 10;
|
||||||
|
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_IA] = ReadInputArray(2, 1) * 10;
|
||||||
|
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_IC] = ReadInputArray(2, 1) * 10;
|
||||||
|
|
||||||
|
MB_INTERNAL.param.nominal.U = ReadInputArray(2, 2) * 10;
|
||||||
|
MB_INTERNAL.param.nominal.I = ReadInputArray(2, 3) * 10;
|
||||||
|
|
||||||
|
MB_INTERNAL.param.angle.PID_Kp = ReadInputArray(2, 4) * 10000;
|
||||||
|
MB_INTERNAL.param.angle.PID_Ki = ReadInputArray(2, 5) * 10000;
|
||||||
|
MB_INTERNAL.param.angle.PID_Kd = ReadInputArray(2, 6) * 10000;
|
||||||
|
|
||||||
|
MB_INTERNAL.param.angle.Angle_Max = ReadInputArray(2, 7)/180 * 65535;
|
||||||
|
MB_INTERNAL.param.angle.Angle_Min = ReadInputArray(2, 8)/180 * 65535;
|
||||||
|
MB_INTERNAL.param.pwm.PulseLength = ReadInputArray(2, 9)/180 * 65535;
|
||||||
|
|
||||||
|
}
|
||||||
// USER APP INPUT END
|
// USER APP INPUT END
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
23
MATLAB/calc_pi.m
Normal file
23
MATLAB/calc_pi.m
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
clc, clear all
|
||||||
|
%% Ввод данных
|
||||||
|
Ku = 0.03; % Твой Ku
|
||||||
|
Tu = 0.0847; % Твой Tu
|
||||||
|
Ts = 0.0005; % Твой Ts
|
||||||
|
|
||||||
|
%% Расч
|
||||||
|
Kp = 0.45 * Ku;
|
||||||
|
Ti = 0.85 * Tu;
|
||||||
|
Ki_abs = Kp / Ti; % Абсолютное Ki
|
||||||
|
Ki_disc = Ki_abs * Ts; % Дискретное Ki (если программа делит на Ts)
|
||||||
|
|
||||||
|
%% Вывод
|
||||||
|
fprintf('Kp = %.3f\n', Kp);
|
||||||
|
fprintf('Ki абсолютное = %.3f\n', Ki_abs);
|
||||||
|
fprintf('Ki дискретное = %.6f (если программа делит на Ts)\n', Ki_disc);
|
||||||
|
|
||||||
|
%% Рекомендация (с запасом)
|
||||||
|
Kp_safe = Kp * 0.7;
|
||||||
|
Ki_safe = Ki_abs * 0.7;
|
||||||
|
fprintf('\nС запасом 30%%:\n');
|
||||||
|
fprintf('Kp = %.3f\n', Kp_safe);
|
||||||
|
fprintf('Ki = %.3f\n', Ki_safe);
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
clear all
|
clear all
|
||||||
|
|
||||||
|
IadcMax = 200;%50;
|
||||||
|
VadcMax = 1216;
|
||||||
|
|
||||||
Ts = 5e-6;
|
Ts = 5e-6;
|
||||||
Vnom = 400;
|
Vnom = 400;
|
||||||
Inom = 30;
|
Inom = 30;%4.2;
|
||||||
Fnom = 50;
|
Fnom = 50;
|
||||||
|
|
||||||
Temperature1 = 2.22; % 20 градусов
|
Temperature1 = 2.22; % 20 градусов
|
||||||
Temperature2 = 2.99; % 34 градусов
|
Temperature2 = 2.99; % 34 градусов
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Submodule UPP/AllLibs/Modbus updated: e0ce0e6dbf...df3f71cdff
Submodule UPP/AllLibs/MyLibs updated: 513f56fe7d...795ebbd220
Submodule UPP/AllLibs/PeriphGeneral updated: 11c00f1e0c...c0733a1d31
@@ -21,6 +21,7 @@
|
|||||||
#include "modbus_holdregs.h"
|
#include "modbus_holdregs.h"
|
||||||
#include "modbus_inputregs.h"
|
#include "modbus_inputregs.h"
|
||||||
#include "modbus_devid.h"
|
#include "modbus_devid.h"
|
||||||
|
#include "upp_main.h"
|
||||||
|
|
||||||
/* DEFINE DATA FOR MODBUS */
|
/* DEFINE DATA FOR MODBUS */
|
||||||
MB_DataStructureTypeDef MB_DATA = {0}; ///< Coils & Registers
|
MB_DataStructureTypeDef MB_DATA = {0}; ///< Coils & Registers
|
||||||
@@ -66,10 +67,16 @@ MB_ExceptionTypeDef MB_Check_Address_For_Arr(uint16_t Addr, uint16_t Qnt, uint16
|
|||||||
* @details Определение адреса начального регистра.
|
* @details Определение адреса начального регистра.
|
||||||
* @note WriteFlag пока не используется.
|
* @note WriteFlag пока не используется.
|
||||||
*/
|
*/
|
||||||
MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType)
|
MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, uint16_t Qnt, uint8_t RegisterType, uint8_t WriteFlag)
|
||||||
{
|
{
|
||||||
|
/* В режиме работа ничего не записываем */
|
||||||
|
if(upp.workmode == UPP_Work)
|
||||||
|
{
|
||||||
|
return ET_ILLEGAL_FUNCTION;
|
||||||
|
}
|
||||||
|
|
||||||
/* check quantity error */
|
/* check quantity error */
|
||||||
if (Qnt > DATA_SIZE)
|
if (Qnt > MbData_size)
|
||||||
{
|
{
|
||||||
return ET_ILLEGAL_DATA_VALUE; // return exception code
|
return ET_ILLEGAL_DATA_VALUE; // return exception code
|
||||||
}
|
}
|
||||||
@@ -125,6 +132,12 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u
|
|||||||
*/
|
*/
|
||||||
MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag)
|
MB_ExceptionTypeDef MB_DefineCoilsAddress(uint16_t **pCoils, uint16_t Addr, uint16_t Qnt, uint16_t *start_shift, uint8_t WriteFlag)
|
||||||
{
|
{
|
||||||
|
/* В режиме работа ничего не записываем */
|
||||||
|
if(upp.workmode == UPP_Work)
|
||||||
|
{
|
||||||
|
return ET_ILLEGAL_FUNCTION;
|
||||||
|
}
|
||||||
|
|
||||||
/* check quantity error */
|
/* check quantity error */
|
||||||
if (Qnt > 2000)
|
if (Qnt > 2000)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -97,12 +97,14 @@
|
|||||||
|
|
||||||
|
|
||||||
#define BENCH_TIME_ENABLE ///< Включить бенч времени
|
#define BENCH_TIME_ENABLE ///< Включить бенч времени
|
||||||
#define BENCH_TIME_MAX_CHANNELS 5 ///< Максимальное количество каналов измерения
|
#define BENCH_TIME_MAX_CHANNELS 6 ///< Максимальное количество каналов измерения
|
||||||
|
|
||||||
#define BT_SLOWCALC 0
|
#define BT_SLOWCALC_PRD 0
|
||||||
#define BT_ADC 1
|
#define BT_SLOWCALC 1
|
||||||
#define BT_PWM 2
|
#define BT_ADC 2
|
||||||
#define BT_SYSTICK 3
|
#define BT_ADC_PRD 3
|
||||||
|
#define BT_PWM 4
|
||||||
|
#define BT_SYSTICK 5
|
||||||
/** GEN_CONFIG
|
/** GEN_CONFIG
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -14,33 +14,60 @@
|
|||||||
#define _UPP_CONFIG_H_
|
#define _UPP_CONFIG_H_
|
||||||
#include "stm32f4xx_hal.h"
|
#include "stm32f4xx_hal.h"
|
||||||
|
|
||||||
// Проверка корректности структуры
|
|
||||||
#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_PARAMS_TEST Params for tests
|
||||||
|
* @ingroup UPP_CONFIG
|
||||||
|
* @brief Параметры для тестирования УПП. Отключение всякого и включение всяких специфичных режимов
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
#define UPP_DISABLE_ERROR_BLOCK ///< Отключить блокировку УПП при ошибках
|
#define UPP_DISABLE_ERROR_BLOCK ///< Отключить блокировку УПП при ошибках
|
||||||
#define UPP_SIMULATE_I ///< Симулировт токи (Iref/2) а не брать с АЦП
|
//#define UPP_SIMULATE_I ///< Симулировт токи (Iref/2) а не брать с АЦП
|
||||||
#define UPP_DISABLE_PROTECT_BOARDPOWER ///< Отключить проверки питания плат (+24, +5 В)
|
#define UPP_DISABLE_PROTECT_BOARDPOWER ///< Отключить проверки питания плат (+24, +5 В)
|
||||||
#define UPP_DISABLE_PROTECT_LOSS_PHASE ///< Отключить проверки на потерянные фазы
|
#define UPP_DISABLE_PROTECT_LOSS_PHASE ///< Отключить проверки на потерянные фазы
|
||||||
|
|
||||||
|
#define ZC_DISABLE_HYSTERESIS_DEBOUNCE ///< Отключить гиситерезис и дребезг на определении перехода через ноль
|
||||||
|
|
||||||
|
/** //UPP_PARAMS_TEST
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup UPP_COMPILED_PARAMS Fixed params
|
||||||
|
* @ingroup UPP_CONFIG
|
||||||
|
* @brief Параметры устанавливаемые на этапе компиляции. Без перепрошивки их не поменять
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Периоды обновления всякого */
|
||||||
|
#define PM_FAST_PERIOD_US 25 ///< Период обновления быстрых расчетов в мкс (АЦП, пересечение нуля, ШИМ)
|
||||||
|
#define PM_SLOW_PERIOD_US 500 ///< Период обновления медленных расчетов в мкс (сглаженные и действующие значения, ПИД угла, ошибки)
|
||||||
|
#define PM_TEMP_SLOW_PERIOD_MS 1000 ///< Период обновлениия (фильтрации) датчиков температуры в мс
|
||||||
|
#define PM_F_SLOW_PERIOD_MS 40 ///< Период обновления (фильтрации) частоты в мс
|
||||||
|
#define UPP_INIT_BEFORE_READY_MS 2000 ///< Сколько сканировать сеть, перед выставлением состояния готовности
|
||||||
|
#define UPP_HALFWAVE_PERIOD 10 ///< Период полуволны. От него будет рассчитываться углы от 0 до 180 градусов
|
||||||
|
|
||||||
|
/* Частоты таймеров в МГц*/
|
||||||
|
#define PWM_TIM1_FREQ_MHZ 180 ///< Частота тактирования таймера ШИМ (1-4 каналы)
|
||||||
|
#define PWM_TIM8_FREQ_MHZ 180 ///< Частота тактирования таймера ШИМ (5-6 каналы)
|
||||||
|
#define ADC_TIM3_FREQ_MZH 90 ///< Частота тактирования таймера АЦП
|
||||||
|
#define ANGLE_TIM2_FREQ_MHZ 90 ///< Частота тактирования таймера для отсчета угла открытия тиристоров
|
||||||
|
#define US_TIM5_FREQ_MHZ 90 ///< Частота тактирования микросекундного таймера
|
||||||
|
|
||||||
|
/** //UPP_COMPILED_PARAMS
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup UPP_PARAMS_DEFAULT Default params for external flash
|
* @addtogroup UPP_PARAMS_DEFAULT Default params for external flash
|
||||||
* @ingroup UPP_CONFIG
|
* @ingroup UPP_CONFIG
|
||||||
* @brief Дефолтные параметры для внешней памяти. Они применятся по команде или по ошибке
|
* @brief Дефолтные параметры для внешней памяти. Они применятся по команде или по ошибке
|
||||||
* @details Префиксы
|
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -51,7 +78,7 @@
|
|||||||
|
|
||||||
/* Номинальные параметры */
|
/* Номинальные параметры */
|
||||||
#define NOM_PHASE_NUMB 3
|
#define NOM_PHASE_NUMB 3
|
||||||
#define NOM_U_V_DEFAULT 1216
|
#define NOM_U_V_DEFAULT 380
|
||||||
#define NOM_U_DEVIATION_PLUS_PERCENT_DEFAULT 6
|
#define NOM_U_DEVIATION_PLUS_PERCENT_DEFAULT 6
|
||||||
#define NOM_U_DEVIATION_MINUS_PERCENT_DEFAULT 10
|
#define NOM_U_DEVIATION_MINUS_PERCENT_DEFAULT 10
|
||||||
#define NOM_F_HZ_DEFAULT 50
|
#define NOM_F_HZ_DEFAULT 50
|
||||||
@@ -62,6 +89,7 @@
|
|||||||
/* Параметры ПУИ */
|
/* Параметры ПУИ */
|
||||||
#define PUI_Iref_PERCENT_DEFAULT 1.5
|
#define PUI_Iref_PERCENT_DEFAULT 1.5
|
||||||
#define PUI_Tnt_MS_DEFAULT 300
|
#define PUI_Tnt_MS_DEFAULT 300
|
||||||
|
#define PUI_Tnt_CalcAlpha(...) FilterExp_CalcAlpha95(__VA_ARGS__) ///< Уровень в процентах, до куда нарастет ток за время Tnt
|
||||||
#define PUI_Umin_PERCENT_DEFAULT 0.8
|
#define PUI_Umin_PERCENT_DEFAULT 0.8
|
||||||
#define PUI_Umax_PERCENT_DEFAULT 1.2
|
#define PUI_Umax_PERCENT_DEFAULT 1.2
|
||||||
#define PUI_Imax_PERCENT_DEFAULT 0.99
|
#define PUI_Imax_PERCENT_DEFAULT 0.99
|
||||||
@@ -78,15 +106,15 @@
|
|||||||
|
|
||||||
/* Параметры регулятора угла */
|
/* Параметры регулятора угла */
|
||||||
#define ANGLE_PULSE_LENGTH_RESERVE_PERCENT_DEFAULT 1.0
|
#define ANGLE_PULSE_LENGTH_RESERVE_PERCENT_DEFAULT 1.0
|
||||||
#define ANGLE_MAX_PERCENT_DEFAULT 0.8
|
#define ANGLE_MAX_PERCENT_DEFAULT 1
|
||||||
#define ANGLE_MIN_PERCENT_DEFAULT 0.1
|
#define ANGLE_MIN_PERCENT_DEFAULT 0.1
|
||||||
#define ANGLE_PID_KP_COEF_DEFAULT 0.0001
|
#define ANGLE_PID_KP_COEF_DEFAULT 0.0001
|
||||||
#define ANGLE_PID_KI_COEF_DEFAULT 0.0001
|
#define ANGLE_PID_KI_COEF_DEFAULT 0.0001
|
||||||
#define ANGLE_PID_KD_COEF_DEFAULT 0
|
#define ANGLE_PID_KD_COEF_DEFAULT 0
|
||||||
#define ANGLE_REF_TAU_COEF_DEFAULT 20.0
|
|
||||||
|
|
||||||
/* Параметри мониторинга сети */
|
/* Параметри мониторинга сети */
|
||||||
#define PM_EXP_TAU_COEF_DEFAULT 0.05
|
#define PM_RMS_WINDOW_PERIOD_US_DEFAULT 20000
|
||||||
|
#define PM_RMS_EXT_TAU_US_DEFAULT 0.02*3 // 3 периода 50 Гц
|
||||||
|
|
||||||
/* Параметры АЦП */
|
/* Параметры АЦП */
|
||||||
#define ADC_U_MAX_V_DEFAULT 1216.0
|
#define ADC_U_MAX_V_DEFAULT 1216.0
|
||||||
@@ -99,48 +127,36 @@
|
|||||||
#define ZERO_CROSS_DEBOUNCE_CNT_DEFAULT 2*100 // (2.5 * 100 = 2.5 мс)
|
#define ZERO_CROSS_DEBOUNCE_CNT_DEFAULT 2*100 // (2.5 * 100 = 2.5 мс)
|
||||||
|
|
||||||
/* Параметры ШИМ для тиристоров */
|
/* Параметры ШИМ для тиристоров */
|
||||||
#define PWM_THYR_FREQUENCY_HZ_DEFAULT 20000
|
#define PWM_THYR_FREQUENCY_HZ_DEFAULT 16000
|
||||||
#define PWM_THYR_PULSE_NUMBER_DEFAULT 20
|
#define PWM_THYR_DUTY_PERCENT_DEFAULT 0.5
|
||||||
|
#define PWM_THYR_PULSE_LENGTH_DEFAULT (60.0/180.0)
|
||||||
|
|
||||||
/** //UPP_PARAMS_DEFAULT
|
/** //UPP_PARAMS_DEFAULT
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @addtogroup UPP_COMPILED_PARAMS Fixed params
|
|
||||||
* @ingroup UPP_CONFIG
|
|
||||||
* @brief Параметры устанавливаемые на этапе компиляции. Без перепрошивки их не поменять
|
|
||||||
* @{
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Периоды обновления всякого */
|
|
||||||
#define PM_ADC_PERIOD_US 30 ///< Период опроса АЦП в мкс
|
|
||||||
#define PM_SLOW_PERIOD_US 500 ///< Период обновления медленных расчетов в мкс (чтобы делилось на @ref PM_ADC_PERIOD_US)
|
|
||||||
#define PM_TEMP_SLOW_PERIOD_MS 1000 ///< Период опроса АЦП в мс
|
|
||||||
#define PM_F_SLOW_PERIOD_MS 40 ///< Период обновления частоты в мс
|
|
||||||
#define UPP_INIT_BEFORE_READY_MS 2000 ///< Сколько сканировать сеть, перед выставлением состояния готовности
|
|
||||||
|
|
||||||
/* Частоты таймеров в МГц*/
|
|
||||||
#define PWM_TIM1_FREQ_MHZ 180 ///< Частота тиков таймера ШИМ (1-4 каналы)
|
|
||||||
#define PWM_TIM8_FREQ_MHZ 180 ///< Частота тиков таймера ШИМ (5-6 каналы)
|
|
||||||
#define US_TIM5_FREQ_MHZ 90 ///< Частота тиков микросекундного таймера
|
|
||||||
#define ADC_TIM3_FREQ_MZH 90 ///< Частота тиков таймера АЦП
|
|
||||||
#define ANGLE_TIM2_FREQ_MHZ 90 ///< Частота тиков таймера отсчета угла открытия тиристоров
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ===== ОТЛАДОЧНЫЕ ШТУКИ ДЛЯ 417 ======
|
// ===== ОТЛАДОЧНЫЕ ШТУКИ ДЛЯ 417 ======
|
||||||
#if defined(STM32F417xx)
|
#if defined(STM32F417xx)
|
||||||
|
|
||||||
|
// У старой платы УПП другие диапазоны датчиков
|
||||||
|
#undef ADC_U_MAX_V_DEFAULT
|
||||||
|
#undef ADC_I_MAX_A_DEFAULT
|
||||||
|
|
||||||
|
#define ADC_U_MAX_V_DEFAULT 707.11
|
||||||
|
#define ADC_I_MAX_A_DEFAULT 424.26
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// У 417 меньше частота поэтому меняем прескалер
|
||||||
#undef PWM_TIM1_FREQ_MHZ
|
#undef PWM_TIM1_FREQ_MHZ
|
||||||
#undef PWM_TIM8_FREQ_MHZ
|
#undef PWM_TIM8_FREQ_MHZ
|
||||||
#undef US_TIM5_FREQ_MHZ
|
#undef US_TIM5_FREQ_MHZ
|
||||||
#undef ADC_TIM3_FREQ_MZH
|
#undef ADC_TIM3_FREQ_MZH
|
||||||
#undef ANGLE_TIM2_FREQ_MHZ
|
#undef ANGLE_TIM2_FREQ_MHZ
|
||||||
|
|
||||||
// У 417 меньше частота поэтому меняем прескалер
|
|
||||||
#define PWM_TIM1_FREQ_MHZ 168 ///< Частота тиков таймера ШИМ (1-4 каналы)
|
#define PWM_TIM1_FREQ_MHZ 168 ///< Частота тиков таймера ШИМ (1-4 каналы)
|
||||||
#define PWM_TIM8_FREQ_MHZ 168 ///< Частота тиков таймера ШИМ (5-6 каналы)
|
#define PWM_TIM8_FREQ_MHZ 168 ///< Частота тиков таймера ШИМ (5-6 каналы)
|
||||||
#define US_TIM5_FREQ_MHZ 84 ///< Частота тиков микросекундного таймера
|
#define US_TIM5_FREQ_MHZ 84 ///< Частота тиков микросекундного таймера
|
||||||
@@ -148,9 +164,10 @@
|
|||||||
#define ANGLE_TIM2_FREQ_MHZ 84 ///< Частота тиков таймера отсчета угла открытия тиристоров
|
#define ANGLE_TIM2_FREQ_MHZ 84 ///< Частота тиков таймера отсчета угла открытия тиристоров
|
||||||
|
|
||||||
#define HAL_PWREx_EnableOverDrive() HAL_ERROR
|
#define HAL_PWREx_EnableOverDrive() HAL_ERROR
|
||||||
#endif
|
|
||||||
// ===== ОТЛАДОЧНЫЕ ШТУКИ ДЛЯ MATLAB ======
|
|
||||||
|
|
||||||
|
#endif //defined(STM32F417xx)
|
||||||
|
|
||||||
|
// ===== ОТЛАДОЧНЫЕ ШТУКИ ДЛЯ MATLAB ======
|
||||||
#if defined(MATLAB)
|
#if defined(MATLAB)
|
||||||
#undef UPP_INIT_BEFORE_READY_MS
|
#undef UPP_INIT_BEFORE_READY_MS
|
||||||
|
|
||||||
@@ -158,8 +175,5 @@
|
|||||||
#define UPP_INIT_BEFORE_READY_MS 100 ///< Сколько сканировать сеть, перед выставлением состояния готовности
|
#define UPP_INIT_BEFORE_READY_MS 100 ///< Сколько сканировать сеть, перед выставлением состояния готовности
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif //defined(MATLAB)
|
||||||
/** //UPP_COMPILED_PARAMS
|
|
||||||
* @}
|
|
||||||
*/
|
|
||||||
#endif //_UPP_CONFIG_H_
|
#endif //_UPP_CONFIG_H_
|
||||||
|
|||||||
@@ -149,17 +149,35 @@ typedef struct {
|
|||||||
* @brief Дефайны УПП которые используютяс исключительно внутри программы
|
* @brief Дефайны УПП которые используютяс исключительно внутри программы
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
/* Перерасчеты в тики */
|
|
||||||
#define PM_SLOW_PERIOD_CNT (PM_SLOW_PERIOD_US/PM_ADC_PERIOD_US) ///< Период обновления медленных расчетов тиках @ref PM_ADC_PERIOD_US
|
// Проверка корректности структуры
|
||||||
#define US_TO_SLOW_TICKS(_us_) ((_us_)/PM_SLOW_PERIOD_US)
|
#define assert_upp(_struct_) check_null_ptr_2(_struct_, (_struct_)->f.Initialized)
|
||||||
#define MS_TO_SLOW_TICKS(_ms_) US_TO_SLOW_TICKS((_ms_)*1000)
|
// Проверка корректности структуры и фазы
|
||||||
#define PM_F_SLOW_PERIOD_CNT (MS_TO_SLOW_TICKS(PM_F_SLOW_PERIOD_MS)) ///< Период обновления частоты в тиках @ref PM_SLOW_PERIOD_CNT
|
#define assert_upp_phase(_struct_, _phase_) (check_null_ptr_2(_struct_, (_struct_)->f.Initialized) || (_phase_ >= 3))
|
||||||
|
|
||||||
|
|
||||||
|
/* Дефайны для индексов */
|
||||||
|
/* Линейные напряжения */
|
||||||
|
#define U_AB 0
|
||||||
|
#define U_CA 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
|
||||||
|
|
||||||
/* Перерасчеты в тики */
|
/* Перерасчеты в тики */
|
||||||
#define ANGLE_PERIOD_MS(_freq_) (((float)1/(_freq_*2))*1000) ///< Период обновления частоты в тиках @ref PM_SLOW_PERIOD_CNT
|
#define PM_SLOW_PERIOD_CNT (PM_SLOW_PERIOD_US/PM_FAST_PERIOD_US) ///< Период обновления медленных расчетов тиках @ref PM_FAST_PERIOD_US
|
||||||
|
#define US_TO_FAST_TICKS(_us_) ((_us_)/PM_FAST_PERIOD_US) ///< Пересчитать мкс в тики быстрых расчетов
|
||||||
|
#define MS_TO_FAST_TICKS(_ms_) US_TO_FAST_TICKS((_ms_)*1000) ///< Пересчитать мс в тики быстрых расчетов
|
||||||
|
#define US_TO_SLOW_TICKS(_us_) ((_us_)/PM_SLOW_PERIOD_US) ///< Пересчитать мкс в тики медленных расчетов
|
||||||
|
#define MS_TO_SLOW_TICKS(_ms_) US_TO_SLOW_TICKS((_ms_)*1000) ///< Пересчитать мс в тики медленных расчетов
|
||||||
|
#define PM_F_SLOW_PERIOD_CNT (MS_TO_SLOW_TICKS(PM_F_SLOW_PERIOD_MS)) ///< Период обновления частоты в тиках @ref PM_SLOW_PERIOD_CNT
|
||||||
|
|
||||||
/* Расчет коэффициента альфа для экспоненциального фильтра */
|
#define SQRT2 1.4142135
|
||||||
#define CALC_TAU_COEF(tau, TsUs) (((float)TsUs/1000000) / (((float)TsUs/1000000) + (tau)))
|
|
||||||
|
|
||||||
/* Дефайны для "удобного" доступа к структурам */
|
/* Дефайны для "удобного" доступа к структурам */
|
||||||
#define PARAM_INTERNAL MB_INTERNAL.param
|
#define PARAM_INTERNAL MB_INTERNAL.param
|
||||||
@@ -183,8 +201,8 @@ typedef enum {
|
|||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
UPP_PHASE_A = 0,
|
UPP_PHASE_A = 0,
|
||||||
UPP_PHASE_B = 1,
|
UPP_PHASE_C = 1,
|
||||||
UPP_PHASE_C = 2,
|
UPP_PHASE_B = 2,
|
||||||
UPP_PHASE_UNKNOWN = 3
|
UPP_PHASE_UNKNOWN = 3
|
||||||
} UPP_Phase_t;
|
} UPP_Phase_t;
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ void PendSV_Handler(void);
|
|||||||
void SysTick_Handler(void);
|
void SysTick_Handler(void);
|
||||||
void TIM1_UP_TIM10_IRQHandler(void);
|
void TIM1_UP_TIM10_IRQHandler(void);
|
||||||
void TIM2_IRQHandler(void);
|
void TIM2_IRQHandler(void);
|
||||||
|
void TIM8_UP_TIM13_IRQHandler(void);
|
||||||
void TIM8_TRG_COM_TIM14_IRQHandler(void);
|
void TIM8_TRG_COM_TIM14_IRQHandler(void);
|
||||||
void DMA2_Stream0_IRQHandler(void);
|
void DMA2_Stream0_IRQHandler(void);
|
||||||
/* USER CODE BEGIN EFP */
|
/* USER CODE BEGIN EFP */
|
||||||
|
|||||||
@@ -7,35 +7,49 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "adc_tools.h"
|
#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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static void ADC_InitAllFilters(ADC_Periodic_t *adc)
|
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 Инициализация периодического АЦП.
|
* @brief Инициализация периодического АЦП.
|
||||||
* @param adc Указатель на кастомный хендл АЦП
|
* @param adc Указатель на кастомный хендл АЦП
|
||||||
@@ -81,7 +95,6 @@ HAL_StatusTypeDef ADC_ConfigChannel(ADC_Periodic_t *adc, int ChNumb, uint16_t le
|
|||||||
adc->Coefs[ChNumb].vMax = valueMax;
|
adc->Coefs[ChNumb].vMax = valueMax;
|
||||||
adc->Coefs[ChNumb].lZero = levelZero;
|
adc->Coefs[ChNumb].lZero = levelZero;
|
||||||
|
|
||||||
ADC_ResetStatistics(adc, ChNumb);
|
|
||||||
return HAL_OK;
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,24 +117,20 @@ HAL_StatusTypeDef ADC_Start(ADC_Periodic_t *adc, float PeriodUs)
|
|||||||
HAL_TIM_Base_Stop(adc->htim);
|
HAL_TIM_Base_Stop(adc->htim);
|
||||||
|
|
||||||
// Запускаем таймер который будет запускать опрос АЦП с заданным периодом
|
// Запускаем таймер который будет запускать опрос АЦП с заданным периодом
|
||||||
__HAL_TIM_SET_AUTORELOAD_FORCE(adc->htim, TIM_MicrosToTick(PeriodUs, ADC_TIM3_FREQ_MZH-1));
|
__HAL_TIM_SET_AUTORELOAD_FORCE(adc->htim, TIM_MicrosToTick(PeriodUs, ADC_TIM3_FREQ_MZH));
|
||||||
|
|
||||||
res = HAL_TIM_Base_Start(adc->htim);
|
res = HAL_TIM_Base_Start(adc->htim);
|
||||||
if(res != HAL_OK)
|
if(res != HAL_OK)
|
||||||
{
|
{
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
// Запускаем АЦП который будет перекидывать данные в ADC_DMA_Buffer
|
// Запускаем АЦП который будет перекидывать данные в DMA буфер RawData
|
||||||
res = HAL_ADC_Start_DMA(adc->hadc, (uint32_t*)adc->RawData, 6); // Затем АЦП с DMA
|
res = HAL_ADC_Start_DMA(adc->hadc, (uint32_t*)adc->RawData, 6);
|
||||||
if(res != HAL_OK)
|
if(res != HAL_OK)
|
||||||
{
|
{
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
ADC_EnableAllFilters(adc);
|
|
||||||
Filter_Start(&adc->temp_map[0]);
|
|
||||||
Filter_Start(&adc->temp_map[1]);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@@ -139,14 +148,11 @@ HAL_StatusTypeDef ADC_Stop(ADC_Periodic_t *adc)
|
|||||||
return HAL_TIM_Base_Stop(adc->htim);
|
return HAL_TIM_Base_Stop(adc->htim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Обработка АЦП.
|
* @brief Обновление напряжений АЦП.
|
||||||
* @return HAL Status.
|
* @return HAL Status.
|
||||||
* @details По факту остановка таймера, который запускает АЦП. Сам АЦП продолжает работу.
|
|
||||||
* @note Вызывается в DMA2_Stream0_IRQHandler() для обработки всего, что пришло по DMA.
|
|
||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef ADC_Handle(ADC_Periodic_t *adc)
|
HAL_StatusTypeDef ADC_UpdateRegular(ADC_Periodic_t *adc)
|
||||||
{
|
{
|
||||||
if(assert_upp(adc))
|
if(assert_upp(adc))
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
@@ -155,92 +161,45 @@ HAL_StatusTypeDef ADC_Handle(ADC_Periodic_t *adc)
|
|||||||
uint16_t *raw = adc->RawData;
|
uint16_t *raw = adc->RawData;
|
||||||
float *data = adc->Data;
|
float *data = adc->Data;
|
||||||
|
|
||||||
// // Фильтрация от импульсных шумов для всех каналов
|
// Фильтрация от импульсных шумов каналов токов (напряжения позже фильтруются полосовым фильтром)
|
||||||
// for(int i = 0; i < ADC_NUMB_OF_CHANNELS; i++)
|
for(int i = 0; i < 2; i++)
|
||||||
// {
|
{
|
||||||
// if(Filter_isEnable(&adc->filter[i]))
|
int u_ind = ADC_U_CHANNELS_START + i;
|
||||||
// {
|
int i_ind = ADC_I_CHANNELS_START + i;
|
||||||
// // заменяем данные на отфильтрованные данные
|
// заменяем сырые данные на отфильтрованные данные
|
||||||
// data[i] = Filter_Process(&adc->filter[i], data[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 = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
for(int i = ADC_U_CHANNELS_START; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
ADC_Coefs_t *coefs = &adc->Coefs[i];
|
ADC_Coefs_t *coefs = &adc->Coefs[i];
|
||||||
data[i] = ((float)(raw[i])-coefs->lZero) * coefs->vMax / (coefs->lMax-coefs->lZero);
|
data[i] = ((float)(raw[i])-coefs->lZero) * coefs->vMax / (coefs->lMax-coefs->lZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Преобразования температуры по таблице
|
|
||||||
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]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Filter_isDataReady(&adc->filter[0]))
|
|
||||||
adc->f.DataReady = 1;
|
|
||||||
|
|
||||||
return HAL_OK;
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Сбор статистики.
|
* @brief Обновление температур АЦП.
|
||||||
|
* @return HAL Status.
|
||||||
*/
|
*/
|
||||||
void ADC_UpdateStatistics(ADC_Periodic_t *adc, uint8_t channel, ADC_StatLevel_t level)
|
HAL_StatusTypeDef ADC_UpdateTemperatures(ADC_Periodic_t *adc)
|
||||||
{
|
{
|
||||||
if (level < ADC_LEVEL_BASE)
|
|
||||||
return;
|
|
||||||
if(assert_upp(adc))
|
if(assert_upp(adc))
|
||||||
return;
|
return HAL_ERROR;
|
||||||
if (channel >= ADC_NUMB_OF_REGULAR_CHANNELS)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
float *data = adc->Data;
|
||||||
ADC_Statistics *stat = &adc->Stat[channel];
|
uint16_t *raw = adc->RawData;
|
||||||
float value = adc->Data[channel];
|
|
||||||
|
// Преобразования температуры по таблице
|
||||||
// Первая инициализация
|
for (int i = ADC_TEMP_CHANNELS_START; i < ADC_TEMP_CHANNELS_END; i++)
|
||||||
if (stat->SampleCount == 0) {
|
|
||||||
stat->Max = value;
|
|
||||||
stat->Min = value;
|
|
||||||
stat->Sum = 0;
|
|
||||||
stat->SumSquares = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Обновление min/max
|
|
||||||
if (value > stat->Max) stat->Max = value;
|
|
||||||
if (value < stat->Min) stat->Min = value;
|
|
||||||
|
|
||||||
// если не выбраны характеристики переменного сигнала - уходим
|
|
||||||
if(level < ADC_LEVEL_AC)
|
|
||||||
{
|
{
|
||||||
return;
|
data[i] = Filter_Process(&adc->temp_map[i-ADC_TEMP_CHANNELS_START], raw[i]);
|
||||||
}
|
}
|
||||||
|
return HAL_OK;
|
||||||
// Накопление для Avg/RMS
|
|
||||||
stat->Sum += fabsf(value);
|
|
||||||
stat->SumSquares += value * value;
|
|
||||||
stat->SampleCount++;
|
|
||||||
|
|
||||||
// Расчет Avg/RMS (периодически или по запросу)
|
|
||||||
if (stat->SampleCount >= 4000) { // Пример: пересчет каждые 1000 samples
|
|
||||||
stat->Avg = stat->Sum / stat->SampleCount;
|
|
||||||
stat->RMS = sqrtf(stat->SumSquares / stat->SampleCount);
|
|
||||||
// Сброс накопителей
|
|
||||||
stat->Sum = 0;
|
|
||||||
stat->SumSquares = 0;
|
|
||||||
stat->SampleCount = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Сброс статистики.
|
|
||||||
*/
|
|
||||||
void ADC_ResetStatistics(ADC_Periodic_t *adc, uint8_t channel)
|
|
||||||
{
|
|
||||||
if (channel < ADC_NUMB_OF_REGULAR_CHANNELS) {
|
|
||||||
memset(&adc->Stat[channel], 0, sizeof(ADC_Statistics));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -18,12 +18,19 @@
|
|||||||
#define ADC_CHANNEL_TEMP2 5
|
#define ADC_CHANNEL_TEMP2 5
|
||||||
|
|
||||||
|
|
||||||
#define ADC_NUMB_OF_CHANNELS 6
|
#define ADC_NUMB_OF_CHANNELS 6
|
||||||
#define ADC_NUMB_OF_U_CHANNELS 2
|
#define ADC_NUMB_OF_U_CHANNELS 2
|
||||||
#define ADC_NUMB_OF_I_CHANNELS 2
|
#define ADC_NUMB_OF_I_CHANNELS 2
|
||||||
#define ADC_NUMB_OF_T_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_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 \
|
#define ADC_TEMPERATURES_QUANTS \
|
||||||
{ 2188, 2197, 2206, 2216, 2226, 2236, 2247, 2259, 2271, 2283, \
|
{ 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_vals[] = ADC_TEMPERATURES;
|
||||||
static const float adc_temp_quants[] = ADC_TEMPERATURES_QUANTS;
|
static const float adc_temp_quants[] = ADC_TEMPERATURES_QUANTS;
|
||||||
|
|
||||||
#define Filter_t FilterMedianInt_t
|
|
||||||
#define Filter_Init FilterMedianInt_Init
|
|
||||||
#define Filter_Initializator 5
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Коэфициенты канала АЦП для пересчета в единицы измерения
|
* @brief Коэфициенты канала АЦП для пересчета в единицы измерения
|
||||||
*/
|
*/
|
||||||
@@ -100,12 +103,11 @@ typedef struct
|
|||||||
uint16_t RawData[ADC_NUMB_OF_CHANNELS]; ///< Сырые значения АЦП
|
uint16_t RawData[ADC_NUMB_OF_CHANNELS]; ///< Сырые значения АЦП
|
||||||
ADC_Coefs_t Coefs[ADC_NUMB_OF_REGULAR_CHANNELS]; ///< Коэффициенты @ref ADC_Coefs_t для регулярных каналов (не температуры)
|
ADC_Coefs_t Coefs[ADC_NUMB_OF_REGULAR_CHANNELS]; ///< Коэффициенты @ref ADC_Coefs_t для регулярных каналов (не температуры)
|
||||||
|
|
||||||
Filter_t filter[ADC_NUMB_OF_CHANNELS]; ///< Фильтр от шумов АЦП
|
FilterBandPassDerivative_t u_fltr[ADC_NUMB_OF_U_CHANNELS]; ///< Полосовой Фильтр Напряжений от шумов
|
||||||
|
FilterMedianInt_t i_fltr[ADC_NUMB_OF_I_CHANNELS]; ///< Медианный Фильтр Токов от шумов
|
||||||
FilterLUT_t temp_map[2]; ///< Коррекция нелинейности датчиков температуры
|
FilterLUT_t temp_map[ADC_NUMB_OF_T_CHANNELS]; ///< Коррекция нелинейности датчиков температуры
|
||||||
|
|
||||||
float Data[ADC_NUMB_OF_CHANNELS]; ///< Пересчитанные значения АЦП (в Вольтах/Амперах)
|
float Data[ADC_NUMB_OF_CHANNELS]; ///< Пересчитанные значения АЦП (в Вольтах/Амперах)
|
||||||
ADC_Statistics Stat[ADC_NUMB_OF_REGULAR_CHANNELS]; ///< Статистика для регулярных каналов (не температуры)
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
@@ -126,13 +128,9 @@ HAL_StatusTypeDef ADC_ConfigChannel(ADC_Periodic_t *adc, int ChNumb, uint16_t le
|
|||||||
HAL_StatusTypeDef ADC_Start(ADC_Periodic_t *adc, float PeriodUs);
|
HAL_StatusTypeDef ADC_Start(ADC_Periodic_t *adc, float PeriodUs);
|
||||||
/* Остановка АЦП. */
|
/* Остановка АЦП. */
|
||||||
HAL_StatusTypeDef ADC_Stop(ADC_Periodic_t *adc);
|
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);
|
||||||
|
|
||||||
/* Сбор статистики. */
|
|
||||||
void ADC_UpdateStatistics(ADC_Periodic_t *adc, uint8_t channel, ADC_StatLevel_t level);
|
|
||||||
/* Сброс статистики. */
|
|
||||||
void ADC_ResetStatistics(ADC_Periodic_t *adc, uint8_t channel);
|
|
||||||
|
|
||||||
#endif //_ADC_TOOLS_H_
|
#endif //_ADC_TOOLS_H_
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
#include "adc.h"
|
#include "adc.h"
|
||||||
#include "tim.h"
|
#include "tim.h"
|
||||||
|
|
||||||
#define U_BC_calc(_u1_, _u2_) (-((_u1_) + (_u2_)))
|
#define U_BC_calc(_uab_, _uca_) (-((_uab_) + (_uca_)))
|
||||||
#define I_B_calc(_i1_, _i2_) (-((_i1_) + (_i2_)))
|
#define I_B_calc(_ia_, _ic_) (-((_ia_) + (_ic_)))
|
||||||
|
|
||||||
static void __SynchAvgFilters(PowerMonitor_t *hpm);
|
static void __SynchAvgFilters(PowerMonitor_t *hpm);
|
||||||
|
|
||||||
@@ -28,55 +28,21 @@ HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
|
|||||||
|
|
||||||
/* Инициализация АЦП */
|
/* Инициализация АЦП */
|
||||||
if(ADC_Init(&hpm->adc, &adc_tim, &hadc3) != HAL_OK)
|
if(ADC_Init(&hpm->adc, &adc_tim, &hadc3) != HAL_OK)
|
||||||
return HAL_ERROR;
|
|
||||||
|
|
||||||
/* Инициализация каналов АЦП */
|
|
||||||
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_UBA,
|
|
||||||
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_UBA],
|
|
||||||
to_float(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_UBA], 10),
|
|
||||||
4095) != HAL_OK)
|
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_UAC,
|
|
||||||
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_UAC],
|
|
||||||
to_float(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_UAC], 10),
|
|
||||||
4095) != HAL_OK)
|
|
||||||
return HAL_ERROR;
|
|
||||||
|
|
||||||
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_IC,
|
|
||||||
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_IC],
|
|
||||||
to_float(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_IC], 10),
|
|
||||||
4095) != HAL_OK)
|
|
||||||
return HAL_ERROR;
|
|
||||||
|
|
||||||
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_IA,
|
|
||||||
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_IA],
|
|
||||||
to_float(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_IA], 10),
|
|
||||||
4095) != HAL_OK)
|
|
||||||
return HAL_ERROR;
|
|
||||||
|
|
||||||
|
|
||||||
/* Инициализация алгоритма перехода через ноль */
|
/* Инициализация алгоритма перехода через ноль */
|
||||||
if(ZC_Init(&hpm->zc, 3, to_float(PARAM_INTERNAL.zc.Hysteresis, 100), PARAM_INTERNAL.zc.DebouneCouner) != HAL_OK)
|
if(ZC_Init(&hpm->zc, 3, 0, 0) != HAL_OK)
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
/* Инициализация каналов алгоритма перехода через ноль */
|
/* Инициализация каналов алгоритма перехода через ноль */
|
||||||
if(ZC_ConfigChannel(&hpm->zc, U_BA, ZC_BOTH_EDGES) != HAL_OK)
|
if(ZC_ConfigChannel(&hpm->zc, U_AB, ZC_BOTH_EDGES) != HAL_OK)
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
if(ZC_ConfigChannel(&hpm->zc, U_AC, ZC_BOTH_EDGES) != HAL_OK)
|
if(ZC_ConfigChannel(&hpm->zc, U_CA, ZC_BOTH_EDGES) != HAL_OK)
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
if(ZC_ConfigChannel(&hpm->zc, U_BC, ZC_BOTH_EDGES) != HAL_OK)
|
if(ZC_ConfigChannel(&hpm->zc, U_BC, ZC_BOTH_EDGES) != HAL_OK)
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
|
|
||||||
/* Инициализация экпоненциального фильтра медленного алга */
|
|
||||||
for(int i = 0; i < EXP_ALL; i++)
|
|
||||||
{
|
|
||||||
if(FilterExp_Init(&hpm->exp[i], to_float(PARAM_INTERNAL.pm.mean_alpha,65535)))
|
|
||||||
return HAL_ERROR;
|
|
||||||
Filter_Start(&hpm->exp[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Инициализация среднего фильтра медленного алга */
|
/* Инициализация среднего фильтра медленного алга */
|
||||||
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
||||||
{
|
{
|
||||||
@@ -96,11 +62,21 @@ HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
|
|||||||
/* Инициализация среднего фильтра для частот */
|
/* Инициализация среднего фильтра для частот */
|
||||||
for(int i = 0; i < 3; i++)
|
for(int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
if(FilterAverage_Init(&hpm->avg[AVG_FBA+i], MS_TO_SLOW_TICKS(PM_F_SLOW_PERIOD_MS), FILTER_MODE_DEFAULT))
|
if(FilterAverage_Init(&hpm->avg[AVG_FAB+i], MS_TO_SLOW_TICKS(PM_F_SLOW_PERIOD_MS), FILTER_MODE_DEFAULT))
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
Filter_Start(&hpm->avg[ADC_TEMP_CHANNELS_START+i]);
|
Filter_Start(&hpm->avg[ADC_TEMP_CHANNELS_START+i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Инициализация фильтра для сглаживания синусоиды*/
|
||||||
|
for(int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
if(FilterBandPassDerivative_Init(&hpm->ufltr[i], (50.0f*PM_FAST_PERIOD_US/1000000), 0.1))
|
||||||
|
return HAL_ERROR;
|
||||||
|
|
||||||
|
Filter_Start(&hpm->ufltr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return HAL_OK;
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
@@ -109,14 +85,14 @@ HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
|
|||||||
/**
|
/**
|
||||||
* @brief Запустить мониторинг сети.
|
* @brief Запустить мониторинг сети.
|
||||||
* @param hpm Указатель на структуру мониторинга сети
|
* @param hpm Указатель на структуру мониторинга сети
|
||||||
* @details Запускает АЦП с периодом @ref PM_ADC_PERIOD_US
|
* @details Запускает АЦП с периодом @ref PM_FAST_PERIOD_US
|
||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef PowerMonitor_Start(PowerMonitor_t *hpm)
|
HAL_StatusTypeDef PowerMonitor_Start(PowerMonitor_t *hpm)
|
||||||
{
|
{
|
||||||
if(hpm == NULL)
|
if(hpm == NULL)
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
if(ADC_Start(&hpm->adc, PM_ADC_PERIOD_US) != HAL_OK)
|
if(ADC_Start(&hpm->adc, PM_FAST_PERIOD_US) != HAL_OK)
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
return HAL_OK;
|
return HAL_OK;
|
||||||
@@ -137,61 +113,68 @@ void PowerMonitor_SlowCalc(PowerMonitor_t *hpm)
|
|||||||
PowerMonitor_Measured_t *meas = &hpm->measured;
|
PowerMonitor_Measured_t *meas = &hpm->measured;
|
||||||
|
|
||||||
/* Обработка температур */
|
/* Обработка температур */
|
||||||
|
ADC_UpdateTemperatures(&hpm->adc);
|
||||||
float t1 = hpm->adc.Data[ADC_CHANNEL_TEMP1];
|
float t1 = hpm->adc.Data[ADC_CHANNEL_TEMP1];
|
||||||
float t2 = hpm->adc.Data[ADC_CHANNEL_TEMP2];
|
float t2 = hpm->adc.Data[ADC_CHANNEL_TEMP2];
|
||||||
meas->final.T[TEMP_1] = Filter_Process(&hpm->avg[AVG_TEMP1], t1);
|
meas->final.T[TEMP_1] = Filter_Process(&hpm->avg[AVG_TEMP1], t1);
|
||||||
meas->final.T[TEMP_2] = Filter_Process(&hpm->avg[AVG_TEMP2], t2);
|
meas->final.T[TEMP_2] = Filter_Process(&hpm->avg[AVG_TEMP2], t2);
|
||||||
|
|
||||||
/* Расчет третьей фазы */
|
/* Расчет третьей фазы */
|
||||||
meas->slow.U[U_BC] = U_BC_calc(meas->slow.U[U_BA], meas->slow.U[U_AC]);
|
meas->slow.U[U_BC] = U_BC_calc(meas->slow.U[U_AB], meas->slow.U[U_CA]);
|
||||||
meas->slow.I[I_B] = I_B_calc(meas->slow.I[I_A], meas->slow.I[I_C]);
|
meas->slow.I[I_B] = I_B_calc(meas->slow.I[I_A], meas->slow.I[I_C]);
|
||||||
|
|
||||||
/* Расчет всякого для трех фаз отдельно */
|
/* Расчет всякого для трех фаз отдельно */
|
||||||
float fmean = 0; // средняя частота по трем фазам
|
float fmean = 0; // средняя частота по трем фазам
|
||||||
|
float umean = 0; // средний напряжение по трем фазам
|
||||||
|
float imean = 0; // средний ток по трем фазам
|
||||||
float iphase_mean = 0; // средний ток каждой фазы
|
float iphase_mean = 0; // средний ток каждой фазы
|
||||||
float uphase_mean = 0; // среднее напряжение каждой фазы
|
float uphase_mean = 0; // среднее напряжение каждой фазы
|
||||||
// Дополнительно посчитаем значения в реальных Вольтах/Амперах
|
// Дополнительно посчитаем значения в реальных Вольтах/Амперах
|
||||||
float u_base = to_float(PARAM_INTERNAL.nominal.U, 10);
|
float u_base = u2f(PARAM_INTERNAL.nominal.U, 10);
|
||||||
float i_base = to_float(PARAM_INTERNAL.nominal.I, 10);
|
float i_base = u2f(PARAM_INTERNAL.nominal.I, 10);
|
||||||
for(int i = 0; i < 3; i++)
|
for(int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
/* Получение частоты фазы */
|
/* Получение частоты фазы */
|
||||||
meas->final.F[i] = Filter_Process(&hpm->avg[AVG_FBA+i], ZC_GetFrequency(&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);
|
// meas->final.Offset[i] = ZC_GetOffset(&hpm->zc, i);
|
||||||
fmean += meas->final.F[i];
|
fmean += meas->final.F[i];
|
||||||
|
|
||||||
/* Средниее напряжение фазы */
|
/* Средниее напряжение фазы */
|
||||||
uphase_mean = fabsf(meas->slow.U[i]);
|
uphase_mean = Filter_Process(&hpm->rms[RMS_U+i], meas->slow.U[i]);
|
||||||
meas->final.U[i] = Filter_Process(&hpm->exp[EXP_UBA+i], uphase_mean);
|
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_I+i], meas->slow.I[i]);
|
||||||
meas->final.I[i] = Filter_Process(&hpm->exp[EXP_IC+i], iphase_mean);
|
meas->final.I[i] = Filter_Process(&hpm->rms_exp[RMS_I+i], iphase_mean);
|
||||||
|
imean += meas->final.I[i];
|
||||||
|
|
||||||
/* Реальные единицы измерения (Вольты/Амперы) */
|
/* Реальные единицы измерения (Вольты/Амперы) */
|
||||||
meas->real.I[i] = meas->slow.I[i]*i_base;
|
meas->real.I[i] = meas->final.I[i]*i_base;
|
||||||
meas->real.U[i] = meas->slow.U[i]*u_base;
|
meas->real.U[i] = meas->final.U[i]*u_base;
|
||||||
}
|
}
|
||||||
/* Получение средней частоты по трем фазам */
|
/* Получение средней частоты по трем фазам */
|
||||||
meas->final.Fmean = fmean / 3;
|
meas->final.Fmean = fmean / 3;
|
||||||
/* Оределение сдвига фаз */
|
// /* Оределение сдвига фаз */
|
||||||
static uint32_t prev_tick_phase_a = 0;
|
// static uint32_t prev_tick_phase_a = 0;
|
||||||
if(prev_tick_phase_a != hpm->zc.Channel[0].PeriodStartTime)
|
// if(prev_tick_phase_a != hpm->zc.Channel[0].PeriodStartTime)
|
||||||
{ // Определяем только когда начался новый период фазы A
|
// { // Определяем только когда начался новый период фазы A
|
||||||
prev_tick_phase_a = hpm->zc.Channel[0].PeriodStartTime;
|
// prev_tick_phase_a = hpm->zc.Channel[0].PeriodStartTime;
|
||||||
meas->final.Phase[0] = 0;
|
// meas->final.Phase[0] = 0;
|
||||||
meas->final.Phase[1] = ZC_GetPhaseShift(&hpm->zc, 0, 1);
|
// meas->final.Phase[1] = ZC_GetPhaseShift(&hpm->zc, 0, 1);
|
||||||
meas->final.Phase[2] = ZC_GetPhaseShift(&hpm->zc, 0, 2);
|
// meas->final.Phase[2] = ZC_GetPhaseShift(&hpm->zc, 0, 2);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
/* Расчет амплитуд трехфазной сети */
|
/* Расчет амплитуд трехфазной сети */
|
||||||
float uamp = vector_abs_linear_calc(meas->slow.U[U_BA], meas->slow.U[U_AC]);
|
// 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 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);
|
float uamp = umean / 3;
|
||||||
meas->final.Iamp = Filter_Process(&hpm->exp[EXP_I], iamp);
|
float iamp = imean / 3;
|
||||||
|
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++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -204,17 +187,20 @@ void PowerMonitor_SlowCalc(PowerMonitor_t *hpm)
|
|||||||
void PowerMonitor_FastCalc(PowerMonitor_t *hpm)
|
void PowerMonitor_FastCalc(PowerMonitor_t *hpm)
|
||||||
{
|
{
|
||||||
if(hpm == NULL)
|
if(hpm == NULL)
|
||||||
return;
|
return;
|
||||||
/* Считываем АЦП с пересчетами и медианой фильтрацией от выбросов */
|
float u_base = u2f(PARAM_INTERNAL.nominal.U, 10);
|
||||||
ADC_Handle(&hpm->adc);
|
float i_base = u2f(PARAM_INTERNAL.nominal.I, 10);
|
||||||
|
|
||||||
/* Заполняем Напряжения/Токи в о.е. */
|
|
||||||
float u_base = to_float(PARAM_INTERNAL.nominal.U, 10);
|
|
||||||
float i_base = to_float(PARAM_INTERNAL.nominal.I, 10);
|
|
||||||
PowerMonitor_Measured_t *meas = &hpm->measured;
|
PowerMonitor_Measured_t *meas = &hpm->measured;
|
||||||
meas->fast.U[U_BA] = hpm->adc.Data[ADC_CHANNEL_UBA]/u_base;
|
|
||||||
meas->fast.U[U_AC] = hpm->adc.Data[ADC_CHANNEL_UAC]/u_base;
|
/* Считываем АЦП с пересчетами и медианой фильтрацией от выбросов */
|
||||||
meas->fast.U[U_BC] = U_BC_calc(meas->fast.U[U_BA], meas->fast.U[U_AC]);
|
ADC_UpdateRegular(&hpm->adc);
|
||||||
|
|
||||||
|
/* Заполняем Напряжения/Токи в о.е. */
|
||||||
|
float uba_fast = hpm->adc.Data[ADC_CHANNEL_UBA]/u_base;
|
||||||
|
float uac_fast = hpm->adc.Data[ADC_CHANNEL_UAC]/u_base;
|
||||||
|
meas->fast.U[U_AB] = Filter_Process(&hpm->ufltr[U_AB], uba_fast);
|
||||||
|
meas->fast.U[U_CA] = Filter_Process(&hpm->ufltr[U_CA], uac_fast);
|
||||||
|
meas->fast.U[U_BC] = U_BC_calc(meas->fast.U[U_AB], meas->fast.U[U_CA]);
|
||||||
|
|
||||||
meas->fast.I[I_C] = hpm->adc.Data[ADC_CHANNEL_IC]/i_base;
|
meas->fast.I[I_C] = hpm->adc.Data[ADC_CHANNEL_IC]/i_base;
|
||||||
meas->fast.I[I_A] = hpm->adc.Data[ADC_CHANNEL_IA]/i_base;
|
meas->fast.I[I_A] = hpm->adc.Data[ADC_CHANNEL_IA]/i_base;
|
||||||
@@ -227,8 +213,8 @@ void PowerMonitor_FastCalc(PowerMonitor_t *hpm)
|
|||||||
//__SynchAvgFilters(hpm);
|
//__SynchAvgFilters(hpm);
|
||||||
|
|
||||||
/* Average для медленной фильтрации */
|
/* Average для медленной фильтрации */
|
||||||
meas->slow.U[U_BA] = Filter_Process(&hpm->avg[AVG_UBA], meas->fast.U[U_BA]);
|
meas->slow.U[U_AB] = Filter_Process(&hpm->avg[AVG_UAB], meas->fast.U[U_AB]);
|
||||||
meas->slow.U[U_AC] = Filter_Process(&hpm->avg[AVG_UAC], meas->fast.U[U_AC]);
|
meas->slow.U[U_CA] = Filter_Process(&hpm->avg[AVG_UCA], meas->fast.U[U_CA]);
|
||||||
meas->slow.I[I_C] = Filter_Process(&hpm->avg[AVG_IC], meas->fast.I[I_C]);
|
meas->slow.I[I_C] = Filter_Process(&hpm->avg[AVG_IC], meas->fast.I[I_C]);
|
||||||
meas->slow.I[I_A] = Filter_Process(&hpm->avg[AVG_IA], meas->fast.I[I_A]);
|
meas->slow.I[I_A] = Filter_Process(&hpm->avg[AVG_IA], meas->fast.I[I_A]);
|
||||||
|
|
||||||
|
|||||||
@@ -12,26 +12,32 @@
|
|||||||
#include "adc_tools.h"
|
#include "adc_tools.h"
|
||||||
#include "zero_cross.h"
|
#include "zero_cross.h"
|
||||||
|
|
||||||
/* Индексы экспоненциальных фильтров */
|
/* Индексы RMS фильтров */
|
||||||
#define EXP_ALL 8
|
#define RMS_ALL 6
|
||||||
#define EXP_U 0
|
#define RMS_U 0
|
||||||
#define EXP_UBA 1
|
#define RMS_UAB 0
|
||||||
#define EXP_UAC 2
|
#define RMS_UCA 1
|
||||||
#define EXP_UBC 3
|
#define RMS_UBC 2
|
||||||
#define EXP_I 4
|
#define RMS_I 3
|
||||||
#define EXP_IC 5
|
#define RMS_IC 3
|
||||||
#define EXP_IA 6
|
#define RMS_IA 4
|
||||||
#define EXP_IB 7
|
#define RMS_IB 5
|
||||||
|
/* Это только сглаживающий, RMS с таким индексом нет */
|
||||||
|
#define RMS_EXP_ALL 8
|
||||||
|
#define RMS_EXP_U 6
|
||||||
|
#define RMS_EXP_I 7
|
||||||
|
|
||||||
|
/* Индексы усредняющих фильтров */
|
||||||
#define AVG_ALL 9
|
#define AVG_ALL 9
|
||||||
#define AVG_UBA 0
|
#define AVG_UAB 0
|
||||||
#define AVG_UAC 1
|
#define AVG_UCA 1
|
||||||
#define AVG_IC 2
|
#define AVG_IC 2
|
||||||
#define AVG_IA 3
|
#define AVG_IA 3
|
||||||
#define AVG_TEMP1 4
|
#define AVG_TEMP1 4
|
||||||
#define AVG_TEMP2 5
|
#define AVG_TEMP2 5
|
||||||
#define AVG_FBA 6
|
#define AVG_F 6
|
||||||
#define AVG_FAC 7
|
#define AVG_FAB 6
|
||||||
|
#define AVG_FCA 7
|
||||||
#define AVG_FBC 8
|
#define AVG_FBC 8
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,11 +86,11 @@ typedef struct
|
|||||||
float I[3]; ///< Ток
|
float I[3]; ///< Ток
|
||||||
}slow;
|
}slow;
|
||||||
|
|
||||||
/** @brief Реальные величины - обновляются кто где, и содержат значения в В/А */
|
/** @brief Реальные величины - обновляются в main в @ref PowerMonitor_SlowCalc, и содержат значения в В/А */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
float U[3]; ///< Напряжение (обновляется в прерывании АЦП)
|
float U[3]; ///< Напряжение (Действующее)
|
||||||
float I[3]; ///< Ток (обновляется в прерывании АЦП)
|
float I[3]; ///< Ток (Действующее)
|
||||||
}real;
|
}real;
|
||||||
|
|
||||||
}PowerMonitor_Measured_t;
|
}PowerMonitor_Measured_t;
|
||||||
@@ -99,11 +105,14 @@ typedef struct
|
|||||||
|
|
||||||
PowerMonitor_Measured_t measured; ///< Измеренные/рассчитанные величины
|
PowerMonitor_Measured_t measured; ///< Измеренные/рассчитанные величины
|
||||||
|
|
||||||
FilterExp_t exp[EXP_ALL]; ///< Фильтры для сглаживания мговенного значения Напряжения/Токов
|
FilterBandPassDerivative_t ufltr[2]; ///< Фильтры для сглаживаний напряжений в синусы
|
||||||
FilterAverage_t avg[AVG_ALL]; ///< Фильтры для сглаживания медленных величин АЦП
|
FilterRMS_t rms[RMS_ALL]; ///< Фильтры для расчета действующего значения Напряжения/Токов
|
||||||
|
FilterExp_t rms_exp[RMS_EXP_ALL]; ///< Фильтры для сглаживания действующего значения Напряжения/Токов +2 для результируюзих U, I
|
||||||
|
FilterAverage_t avg[AVG_ALL]; ///< Фильтры для сглаживания медленных величин АЦП
|
||||||
|
|
||||||
PowerMonitor_Flags_t f; ///< Флаги мониторинга
|
PowerMonitor_Flags_t f; ///< Флаги мониторинга
|
||||||
uint32_t isr_cnt;
|
uint32_t isr_cnt;
|
||||||
|
uint32_t slow_cnt;
|
||||||
}PowerMonitor_t;
|
}PowerMonitor_t;
|
||||||
extern PowerMonitor_t pm;
|
extern PowerMonitor_t pm;
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
int Protect_Voltages(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal)
|
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 lUmin = u2f(protect->Umin, 100)/**u2f(nominal->U, 10)*/;
|
||||||
float lUmax = to_float(protect->Umax, 100)/**to_float(nominal->U, 10)*/;
|
float lUmax = u2f(protect->Umax, 100)/**u2f(nominal->U, 10)*/;
|
||||||
float lPhaseSequence = to_float(nominal->PhaseSequence, 100);
|
float lPhaseSequence = u2f(nominal->PhaseSequence, 100);
|
||||||
|
|
||||||
/* Общее напряжение */
|
/* Общее напряжение */
|
||||||
if(measure->final.Uamp > lUmax)
|
if(measure->final.Uamp > lUmax)
|
||||||
@@ -58,9 +58,9 @@ int Protect_Voltages(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect
|
|||||||
int Protect_Currents(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)
|
||||||
{
|
{
|
||||||
/* Переводим уставки ПУИ в удобный вид */
|
/* Переводим уставки ПУИ в удобный вид */
|
||||||
float lIref = to_float(protect->Iref, 100)/**to_float(nominal->I, 10)*/;
|
float lIref = u2f(protect->Iref, 100)/**u2f(nominal->I, 10)*/;
|
||||||
float lImax = to_float(protect->Imax, 100)/**to_float(nominal->I, 10)*/;
|
float lImin = u2f(protect->Imin, 100)/**u2f(nominal->I, 10)*/;
|
||||||
float lImin = to_float(protect->Imin, 100)/**to_float(nominal->I, 10)*/;
|
float lImax = u2f(protect->Imax, 100) * 50 / u2f(nominal->I, 10); // Imax процентов от 50 А, в о.е. от номинального
|
||||||
|
|
||||||
/* Общий ток */
|
/* Общий ток */
|
||||||
if(measure->final.Iamp > lImax)
|
if(measure->final.Iamp > lImax)
|
||||||
@@ -133,20 +133,20 @@ int Protect_Currents(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect
|
|||||||
void Protect_Misc(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)
|
||||||
{
|
{
|
||||||
/* Переводим внутренние уставки в удобный вид */
|
/* Переводим внутренние уставки в удобный вид */
|
||||||
float lFnom = to_float(PARAM_INTERNAL.nominal.F, 100);
|
float lFnom = u2f(PARAM_INTERNAL.nominal.F, 100);
|
||||||
float lFmin = lFnom - lFnom*to_float(PARAM_INTERNAL.nominal.F_deviation_minus, 10000);
|
float lFmin = lFnom - lFnom*u2f(PARAM_INTERNAL.nominal.F_deviation_minus, 10000);
|
||||||
float lFmax = lFnom + lFnom*to_float(PARAM_INTERNAL.nominal.F_deviation_plus, 10000);
|
float lFmax = lFnom + lFnom*u2f(PARAM_INTERNAL.nominal.F_deviation_plus, 10000);
|
||||||
|
|
||||||
float lTwarn = to_float(PARAM_INTERNAL.setpoints.TemperatureWarn, 100);
|
float lTwarn = u2f(PARAM_INTERNAL.setpoints.TemperatureWarn, 100);
|
||||||
float lTerr = to_float(PARAM_INTERNAL.setpoints.TemperatureWarn, 100);
|
float lTerr = u2f(PARAM_INTERNAL.setpoints.TemperatureWarn, 100);
|
||||||
|
|
||||||
|
|
||||||
/*=============== ЗАЩИТЫ ПО ЧАСТОТЕ ==================*/
|
/*=============== ЗАЩИТЫ ПО ЧАСТОТЕ ==================*/
|
||||||
if(measure->final.F[U_AC] > lFmax)
|
if(measure->final.F[U_CA] > lFmax)
|
||||||
{
|
{
|
||||||
ERR_PRIVATE.fac_max = 1;
|
ERR_PRIVATE.fac_max = 1;
|
||||||
}
|
}
|
||||||
else if (measure->final.F[U_AC] < lFmin)
|
else if (measure->final.F[U_CA] < lFmin)
|
||||||
{
|
{
|
||||||
ERR_PRIVATE.fac_min = 1;
|
ERR_PRIVATE.fac_min = 1;
|
||||||
}
|
}
|
||||||
@@ -156,11 +156,11 @@ void Protect_Misc(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, U
|
|||||||
ERR_PRIVATE.fac_min = 0;
|
ERR_PRIVATE.fac_min = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(measure->final.F[U_BA] > lFmax)
|
if(measure->final.F[U_AB] > lFmax)
|
||||||
{
|
{
|
||||||
ERR_PRIVATE.fba_max = 1;
|
ERR_PRIVATE.fba_max = 1;
|
||||||
}
|
}
|
||||||
else if (measure->final.F[U_BA] < lFmin)
|
else if (measure->final.F[U_AB] < lFmin)
|
||||||
{
|
{
|
||||||
ERR_PRIVATE.fba_min = 1;
|
ERR_PRIVATE.fba_min = 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin
|
|||||||
zc_ch->CurrentValue = value;
|
zc_ch->CurrentValue = value;
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ZC_DISABLE_HYSTERESIS_DEBOUNCE
|
||||||
// Фильтрация дребезга
|
// Фильтрация дребезга
|
||||||
if(zc_ch->DebounceCounter > 0)
|
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;
|
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)
|
if(zc_detected)
|
||||||
{
|
{
|
||||||
@@ -172,11 +192,15 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin
|
|||||||
zc_ch->CrossCount++;
|
zc_ch->CrossCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef ZC_DISABLE_HYSTERESIS_DEBOUNCE
|
||||||
// Сохраняем текущее значение для следующей итерации в случае если оно не в мертвой зоне
|
// Сохраняем текущее значение для следующей итерации в случае если оно не в мертвой зоне
|
||||||
if((value > zc->Config.Hysteresis) || (value < -zc->Config.Hysteresis))
|
if((value > zc->Config.Hysteresis) || (value < -zc->Config.Hysteresis))
|
||||||
{
|
{
|
||||||
zc_ch->LastValue = value;
|
zc_ch->LastValue = value;
|
||||||
}
|
}
|
||||||
|
#else //ZC_DISABLE_HYSTERESIS_DEBOUNCE
|
||||||
|
zc_ch->LastValue = value;
|
||||||
|
#endif //ZC_DISABLE_HYSTERESIS_DEBOUNCE
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -80,13 +80,14 @@ int main(void)
|
|||||||
__HAL_FREEZE_TIM8_DBGMCU();
|
__HAL_FREEZE_TIM8_DBGMCU();
|
||||||
__HAL_FREEZE_TIM11_DBGMCU();
|
__HAL_FREEZE_TIM11_DBGMCU();
|
||||||
__HAL_FREEZE_TIM12_DBGMCU();
|
__HAL_FREEZE_TIM12_DBGMCU();
|
||||||
|
__HAL_FREEZE_TIM14_DBGMCU();
|
||||||
/* USER CODE END 1 */
|
/* USER CODE END 1 */
|
||||||
|
|
||||||
/* MCU Configuration--------------------------------------------------------*/
|
/* MCU Configuration--------------------------------------------------------*/
|
||||||
|
|
||||||
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
|
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
|
||||||
HAL_Init();
|
HAL_Init();
|
||||||
|
|
||||||
/* USER CODE BEGIN Init */
|
/* USER CODE BEGIN Init */
|
||||||
|
|
||||||
#ifndef MATLAB
|
#ifndef MATLAB
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ void TIM1_UP_TIM10_IRQHandler(void)
|
|||||||
/* USER CODE END TIM1_UP_TIM10_IRQn 0 */
|
/* USER CODE END TIM1_UP_TIM10_IRQn 0 */
|
||||||
HAL_TIM_IRQHandler(&htim1);
|
HAL_TIM_IRQHandler(&htim1);
|
||||||
/* USER CODE BEGIN TIM1_UP_TIM10_IRQn 1 */
|
/* USER CODE BEGIN TIM1_UP_TIM10_IRQn 1 */
|
||||||
UPP_PWM_Handle();
|
//UPP_PWM_Handle();
|
||||||
/* USER CODE END TIM1_UP_TIM10_IRQn 1 */
|
/* USER CODE END TIM1_UP_TIM10_IRQn 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,12 +232,27 @@ void TIM2_IRQHandler(void)
|
|||||||
/* USER CODE END TIM2_IRQn 1 */
|
/* USER CODE END TIM2_IRQn 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function handles TIM8 update interrupt and TIM13 global interrupt.
|
||||||
|
*/
|
||||||
|
void TIM8_UP_TIM13_IRQHandler(void)
|
||||||
|
{
|
||||||
|
/* USER CODE BEGIN TIM8_UP_TIM13_IRQn 0 */
|
||||||
|
|
||||||
|
/* USER CODE END TIM8_UP_TIM13_IRQn 0 */
|
||||||
|
HAL_TIM_IRQHandler(&htim8);
|
||||||
|
/* USER CODE BEGIN TIM8_UP_TIM13_IRQn 1 */
|
||||||
|
//UPP_PWM_Handle();
|
||||||
|
/* USER CODE END TIM8_UP_TIM13_IRQn 1 */
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function handles TIM8 trigger and commutation interrupts and TIM14 global interrupt.
|
* @brief This function handles TIM8 trigger and commutation interrupts and TIM14 global interrupt.
|
||||||
*/
|
*/
|
||||||
void TIM8_TRG_COM_TIM14_IRQHandler(void)
|
void TIM8_TRG_COM_TIM14_IRQHandler(void)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN TIM8_TRG_COM_TIM14_IRQn 0 */
|
/* USER CODE BEGIN TIM8_TRG_COM_TIM14_IRQn 0 */
|
||||||
|
|
||||||
#ifndef MATLAB // в матлабе нет htim14, т.к. это систем тики
|
#ifndef MATLAB // в матлабе нет htim14, т.к. это систем тики
|
||||||
/* USER CODE END TIM8_TRG_COM_TIM14_IRQn 0 */
|
/* USER CODE END TIM8_TRG_COM_TIM14_IRQn 0 */
|
||||||
HAL_TIM_IRQHandler(&htim8);
|
HAL_TIM_IRQHandler(&htim8);
|
||||||
@@ -253,11 +268,14 @@ void TIM8_TRG_COM_TIM14_IRQHandler(void)
|
|||||||
void DMA2_Stream0_IRQHandler(void)
|
void DMA2_Stream0_IRQHandler(void)
|
||||||
{
|
{
|
||||||
/* USER CODE BEGIN DMA2_Stream0_IRQn 0 */
|
/* USER CODE BEGIN DMA2_Stream0_IRQn 0 */
|
||||||
|
// Вторая половина буфера (Transfer Complete)
|
||||||
|
if (DMA2->LISR & DMA_LISR_TCIF0) {
|
||||||
|
UPP_ADC_Handle();
|
||||||
|
}
|
||||||
/* USER CODE END DMA2_Stream0_IRQn 0 */
|
/* USER CODE END DMA2_Stream0_IRQn 0 */
|
||||||
HAL_DMA_IRQHandler(&hdma_adc3);
|
HAL_DMA_IRQHandler(&hdma_adc3);
|
||||||
/* USER CODE BEGIN DMA2_Stream0_IRQn 1 */
|
/* USER CODE BEGIN DMA2_Stream0_IRQn 1 */
|
||||||
UPP_ADC_Handle();
|
|
||||||
/* USER CODE END DMA2_Stream0_IRQn 1 */
|
/* USER CODE END DMA2_Stream0_IRQn 1 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ void MX_TIM1_Init(void)
|
|||||||
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
|
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||||
htim1.Init.Period = 65535;
|
htim1.Init.Period = 65535;
|
||||||
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||||
htim1.Init.RepetitionCounter = 20;
|
htim1.Init.RepetitionCounter = 0;
|
||||||
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||||
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
|
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
|
||||||
{
|
{
|
||||||
@@ -209,7 +209,7 @@ void MX_TIM3_Init(void)
|
|||||||
Error_Handler();
|
Error_Handler();
|
||||||
}
|
}
|
||||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
|
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
|
||||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
|
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
|
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
|
||||||
{
|
{
|
||||||
Error_Handler();
|
Error_Handler();
|
||||||
@@ -268,6 +268,7 @@ void MX_TIM8_Init(void)
|
|||||||
/* USER CODE END TIM8_Init 0 */
|
/* USER CODE END TIM8_Init 0 */
|
||||||
|
|
||||||
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
|
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
|
||||||
|
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
|
||||||
TIM_MasterConfigTypeDef sMasterConfig = {0};
|
TIM_MasterConfigTypeDef sMasterConfig = {0};
|
||||||
TIM_OC_InitTypeDef sConfigOC = {0};
|
TIM_OC_InitTypeDef sConfigOC = {0};
|
||||||
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
|
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
|
||||||
@@ -280,7 +281,7 @@ void MX_TIM8_Init(void)
|
|||||||
htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
|
htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||||
htim8.Init.Period = 65535;
|
htim8.Init.Period = 65535;
|
||||||
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||||
htim8.Init.RepetitionCounter = 20;
|
htim8.Init.RepetitionCounter = 0;
|
||||||
htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||||
if (HAL_TIM_Base_Init(&htim8) != HAL_OK)
|
if (HAL_TIM_Base_Init(&htim8) != HAL_OK)
|
||||||
{
|
{
|
||||||
@@ -299,6 +300,12 @@ void MX_TIM8_Init(void)
|
|||||||
{
|
{
|
||||||
Error_Handler();
|
Error_Handler();
|
||||||
}
|
}
|
||||||
|
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
|
||||||
|
sSlaveConfig.InputTrigger = TIM_TS_ITR0;
|
||||||
|
if (HAL_TIM_SlaveConfigSynchro(&htim8, &sSlaveConfig) != HAL_OK)
|
||||||
|
{
|
||||||
|
Error_Handler();
|
||||||
|
}
|
||||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
|
||||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
|
if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
|
||||||
@@ -461,6 +468,8 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
|
|||||||
__HAL_RCC_TIM8_CLK_ENABLE();
|
__HAL_RCC_TIM8_CLK_ENABLE();
|
||||||
|
|
||||||
/* TIM8 interrupt Init */
|
/* TIM8 interrupt Init */
|
||||||
|
HAL_NVIC_SetPriority(TIM8_UP_TIM13_IRQn, 0, 0);
|
||||||
|
HAL_NVIC_EnableIRQ(TIM8_UP_TIM13_IRQn);
|
||||||
HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 15, 0);
|
HAL_NVIC_SetPriority(TIM8_TRG_COM_TIM14_IRQn, 15, 0);
|
||||||
HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
|
HAL_NVIC_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
|
||||||
/* USER CODE BEGIN TIM8_MspInit 1 */
|
/* USER CODE BEGIN TIM8_MspInit 1 */
|
||||||
@@ -604,6 +613,7 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
|
|||||||
__HAL_RCC_TIM8_CLK_DISABLE();
|
__HAL_RCC_TIM8_CLK_DISABLE();
|
||||||
|
|
||||||
/* TIM8 interrupt Deinit */
|
/* TIM8 interrupt Deinit */
|
||||||
|
HAL_NVIC_DisableIRQ(TIM8_UP_TIM13_IRQn);
|
||||||
HAL_NVIC_DisableIRQ(TIM8_TRG_COM_TIM14_IRQn);
|
HAL_NVIC_DisableIRQ(TIM8_TRG_COM_TIM14_IRQn);
|
||||||
/* USER CODE BEGIN TIM8_MspDeInit 1 */
|
/* USER CODE BEGIN TIM8_MspDeInit 1 */
|
||||||
|
|
||||||
|
|||||||
@@ -21,12 +21,6 @@ HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle)
|
|||||||
|
|
||||||
hangle->htim = &angletim;
|
hangle->htim = &angletim;
|
||||||
|
|
||||||
// Инициализация ПИД
|
|
||||||
float kp = to_float(PARAM_INTERNAL.angle.PID_Kp, 10000);
|
|
||||||
float ki = to_float(PARAM_INTERNAL.angle.PID_Ki, 10000);
|
|
||||||
float kd = to_float(PARAM_INTERNAL.angle.PID_Kd, 10000);
|
|
||||||
float ref_alpha = to_float(PARAM_INTERNAL.angle.PID_ExpAlpha, 65535);
|
|
||||||
Angle_PID_Init(hangle, kp, ki, kd, ref_alpha);
|
|
||||||
|
|
||||||
// Инициализация каналов
|
// Инициализация каналов
|
||||||
HAL_TIM_OC_Start_IT(hangle->htim, ANGLE_CHANNEL_1);
|
HAL_TIM_OC_Start_IT(hangle->htim, ANGLE_CHANNEL_1);
|
||||||
@@ -38,11 +32,10 @@ HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle)
|
|||||||
Angle_Reset(hangle, UPP_PHASE_B);
|
Angle_Reset(hangle, UPP_PHASE_B);
|
||||||
Angle_Reset(hangle, UPP_PHASE_C);
|
Angle_Reset(hangle, UPP_PHASE_C);
|
||||||
|
|
||||||
// Инициализация углов
|
|
||||||
float angle_max = to_float(PARAM_INTERNAL.angle.Angle_Max, 65535);
|
|
||||||
float angle_min = to_float(PARAM_INTERNAL.angle.Angle_Min, 65535);
|
|
||||||
|
|
||||||
hangle->f.Initialized = 1;
|
hangle->f.Initialized = 1;
|
||||||
|
hangle->Config.PeriodLimit = 1;
|
||||||
|
|
||||||
return HAL_OK;
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,10 +45,10 @@ HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle)
|
|||||||
* @param hangle Указатель на таймер
|
* @param hangle Указатель на таймер
|
||||||
* @param kp, ki kd Коэффициенты регулятора
|
* @param kp, ki kd Коэффициенты регулятора
|
||||||
*/
|
*/
|
||||||
void Angle_PID_Init(Angle_Handle_t *hangle, float kp, float ki, float kd, float alpha)
|
HAL_StatusTypeDef Angle_PID_Init(Angle_Handle_t *hangle, float kp, float ki, float kd, float alpha)
|
||||||
{
|
{
|
||||||
if(assert_upp(hangle))
|
if(assert_upp(hangle))
|
||||||
return;
|
return HAL_ERROR;
|
||||||
|
|
||||||
// Сам ПИД регулятор
|
// Сам ПИД регулятор
|
||||||
hangle->pid.Kp = kp;
|
hangle->pid.Kp = kp;
|
||||||
@@ -67,6 +60,8 @@ void Angle_PID_Init(Angle_Handle_t *hangle, float kp, float ki, float kd, float
|
|||||||
FilterExp_Init(&hangle->refFilter, alpha);
|
FilterExp_Init(&hangle->refFilter, alpha);
|
||||||
Filter_Start(&hangle->refFilter);
|
Filter_Start(&hangle->refFilter);
|
||||||
Filter_Process(&hangle->refFilter, 0);
|
Filter_Process(&hangle->refFilter, 0);
|
||||||
|
|
||||||
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,25 +70,40 @@ void Angle_PID_Init(Angle_Handle_t *hangle, float kp, float ki, float kd, float
|
|||||||
* @param setpoint Уставка куда регулировать
|
* @param setpoint Уставка куда регулировать
|
||||||
* @param measurement Измеренные регулируемые величины
|
* @param measurement Измеренные регулируемые величины
|
||||||
*/
|
*/
|
||||||
void Angle_PID(Angle_Handle_t *hangle, float setpoint, float measurement)
|
void Angle_PID(Angle_Handle_t *hangle, float setpoint, float measurement, float Correction)
|
||||||
{
|
{
|
||||||
if(assert_upp(hangle))
|
if(assert_upp(hangle))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* Плавное нарастание уставки */
|
||||||
hangle->Iref = Filter_Process(&hangle->refFilter, setpoint);
|
hangle->Iref = Filter_Process(&hangle->refFilter, setpoint);
|
||||||
hangle->Imeas = measurement;
|
hangle->Imeas = measurement;
|
||||||
/* Ошибка регулирования = уставка - измеренное */
|
/* Ошибка регулирования = уставка - измеренное */
|
||||||
float err = hangle->Iref - hangle->Imeas;
|
float err = hangle->Iref - hangle->Imeas;
|
||||||
|
|
||||||
/* ПИД регулирование */
|
/* ПИД регулирование */
|
||||||
float open_control = arm_pid_f32(&hangle->pid, err); // 0 - открыть максимально поздно, 1 - открыть макситмально рано
|
float open_level = arm_pid_f32(&hangle->pid, err); // 0 - открыть максимально поздно, 1 - открыть макситмально рано
|
||||||
|
|
||||||
|
|
||||||
/* Ограничиваем диапазон */
|
/* Ограничиваем диапазон */
|
||||||
if (open_control > 1) open_control = 1;
|
if (open_level > 1)
|
||||||
if(open_control < 0) open_control = 0;
|
{
|
||||||
|
open_level = 1;
|
||||||
|
}
|
||||||
|
if(open_level < 0)
|
||||||
|
{
|
||||||
|
open_level = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Приводим уровень открытия к косинусу [-1:1]*/
|
||||||
|
float OpenLevelForCos = (open_level*2)-1;
|
||||||
|
|
||||||
|
float alpha_rad = acosf(OpenLevelForCos); // угол в радианах
|
||||||
|
float alpha = alpha_rad/PI*hangle->Config.AngleMax; // угол открытия тиристора в о.е. от максимально заданного
|
||||||
|
|
||||||
/* Выставляем заданный уровень открытия */
|
/* Выставляем заданный уровень открытия */
|
||||||
Angle_SetAngle(hangle, open_control);
|
Angle_SetAlpha(hangle, alpha, Correction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,7 +125,8 @@ void Angle_PID_Reset(Angle_Handle_t *hangle)
|
|||||||
Filter_Start(&hangle->refFilter);
|
Filter_Start(&hangle->refFilter);
|
||||||
Filter_Process(&hangle->refFilter, 0);
|
Filter_Process(&hangle->refFilter, 0);
|
||||||
|
|
||||||
Angle_SetAngle(hangle, 0);
|
Angle_SetAlpha(hangle, 1, 30); // максимально закрываем
|
||||||
|
|
||||||
Angle_Reset(hangle, UPP_PHASE_A);
|
Angle_Reset(hangle, UPP_PHASE_A);
|
||||||
Angle_Reset(hangle, UPP_PHASE_B);
|
Angle_Reset(hangle, UPP_PHASE_B);
|
||||||
Angle_Reset(hangle, UPP_PHASE_C);
|
Angle_Reset(hangle, UPP_PHASE_C);
|
||||||
@@ -124,36 +135,28 @@ void Angle_PID_Reset(Angle_Handle_t *hangle)
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Выставление степени открытия тиристоров.
|
* @brief Выставление степени открытия тиристоров.
|
||||||
* @param hangle Указатель на таймер
|
* @param hangle Указатель на таймер
|
||||||
* @param OpenLevel Насколько открыть тиристор:
|
* @param Alpha Угол открытия тиристора в о.е. от 180 градусов:
|
||||||
- 0 - максимально закрыт,
|
- 0 - максимально закрыт,
|
||||||
- 1 - максимально открыт
|
- 1 - максимально открыт
|
||||||
|
* @param Коррекция угла в градусах
|
||||||
* @return HAL Status.
|
* @return HAL Status.
|
||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef Angle_SetAngle(Angle_Handle_t *hangle, float OpenLevel)
|
HAL_StatusTypeDef Angle_SetAlpha(Angle_Handle_t *hangle, float Alpha, float Correction)
|
||||||
{
|
{
|
||||||
if(assert_upp(hangle))
|
if(assert_upp(hangle))
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
/* Приводим уровень открытия к косинусу [-1:1]*/
|
|
||||||
float OpenLevelForCos = (OpenLevel*2)-1;
|
|
||||||
|
|
||||||
float alpha_rad = acosf(OpenLevelForCos); // угол в радианах
|
|
||||||
float alpha = alpha_rad/PI; // время открытие в процентах от периода - когда открыть
|
|
||||||
|
|
||||||
if(alpha > hangle->Config.AngleMax)
|
|
||||||
alpha = hangle->Config.AngleMax;
|
|
||||||
if(alpha < hangle->Config.AngleMin)
|
|
||||||
alpha = hangle->Config.AngleMin;
|
|
||||||
// if(alpha > hangle->Config.PeriodLimit)
|
|
||||||
// {
|
|
||||||
// alpha = hangle->Config.PeriodLimit;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// float alpha_degree = alpha*180;// угол в градусах
|
if(Alpha > hangle->Config.AngleMax)
|
||||||
// hangle->alpha_degree = alpha_degree;
|
Alpha = hangle->Config.AngleMax;
|
||||||
|
if(Alpha < hangle->Config.AngleMin)
|
||||||
|
Alpha = hangle->Config.AngleMin;
|
||||||
|
|
||||||
hangle->alpha = alpha;
|
// сколько надо выжидать исходя из заданного угла
|
||||||
|
hangle->alpha_real = Alpha + (Correction/180.0);
|
||||||
|
hangle->alpha = Alpha;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -168,26 +171,11 @@ HAL_StatusTypeDef Angle_SetAngle(Angle_Handle_t *hangle, float OpenLevel)
|
|||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float PeriodMs)
|
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float PeriodMs)
|
||||||
{
|
{
|
||||||
if(assert_upp(hangle))
|
if(assert_upp_phase(hangle, Phase))
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
// Если канал дурацкий - возвращаем ошибку
|
|
||||||
if(Phase >= 3)
|
|
||||||
{
|
|
||||||
return HAL_ERROR;
|
|
||||||
}
|
|
||||||
// Дополнительно проверяем на соответствие альфа диапазону
|
|
||||||
if(hangle->alpha > hangle->Config.AngleMax)
|
|
||||||
{
|
|
||||||
hangle->alpha = hangle->Config.AngleMax;
|
|
||||||
}
|
|
||||||
if(hangle->alpha < hangle->Config.AngleMin)
|
|
||||||
{
|
|
||||||
hangle->alpha = hangle->Config.AngleMin;
|
|
||||||
}
|
|
||||||
|
|
||||||
// сколько тиков надо выждать для угла
|
// сколько тиков надо выждать для угла
|
||||||
uint32_t timer_ticks = TIM_MillisToTick(PeriodMs*hangle->alpha, ANGLE_TIM2_FREQ_MHZ);
|
uint32_t timer_ticks = TIM_MillisToTick(PeriodMs*hangle->alpha_real, ANGLE_TIM2_FREQ_MHZ);
|
||||||
// сколько тиков будет в таймере когда угол отсчитается (пойдет в CCRx регистр)
|
// сколько тиков будет в таймере когда угол отсчитается (пойдет в CCRx регистр)
|
||||||
uint32_t ccr_ticks = __HAL_TIM_GET_COUNTER(hangle->htim) + timer_ticks;
|
uint32_t ccr_ticks = __HAL_TIM_GET_COUNTER(hangle->htim) + timer_ticks;
|
||||||
|
|
||||||
@@ -252,15 +240,9 @@ HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float P
|
|||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef Angle_Reset(Angle_Handle_t *hangle, UPP_Phase_t Phase)
|
HAL_StatusTypeDef Angle_Reset(Angle_Handle_t *hangle, UPP_Phase_t Phase)
|
||||||
{
|
{
|
||||||
if(assert_upp(hangle))
|
if(assert_upp_phase(hangle, Phase))
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
// Если канал дурацкий - возвращаем ошибку
|
|
||||||
if(Phase >= 3)
|
|
||||||
{
|
|
||||||
return HAL_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(Phase)
|
switch(Phase)
|
||||||
{
|
{
|
||||||
case UPP_PHASE_A:
|
case UPP_PHASE_A:
|
||||||
@@ -306,7 +288,7 @@ HAL_StatusTypeDef Angle_SetLimit(Angle_Handle_t *hangle, float PeriodLimit)
|
|||||||
if(hangle->f.Running)
|
if(hangle->f.Running)
|
||||||
return HAL_BUSY;
|
return HAL_BUSY;
|
||||||
|
|
||||||
if(PeriodLimit < 0 || PeriodLimit > 1)
|
if(PeriodLimit <= 0 || PeriodLimit > 1)
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
hangle->Config.PeriodLimit = PeriodLimit;
|
hangle->Config.PeriodLimit = PeriodLimit;
|
||||||
@@ -333,12 +315,7 @@ HAL_StatusTypeDef Angle_SetRange(Angle_Handle_t *hangle, float AngleMin, float A
|
|||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
if(AngleMin < 0 || AngleMin > 1)
|
if(AngleMin < 0 || AngleMin > 1)
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
if(AngleMax > hangle->Config.PeriodLimit)
|
|
||||||
AngleMax = hangle->Config.PeriodLimit;
|
|
||||||
if(AngleMin > hangle->Config.PeriodLimit)
|
|
||||||
AngleMin = hangle->Config.PeriodLimit;
|
|
||||||
|
|
||||||
if(AngleMin >= AngleMax)
|
if(AngleMin >= AngleMax)
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,13 @@ typedef struct
|
|||||||
Angle_Config_t Config; ///< Конфигурации алгоритма расчета угла открытия тиристоров
|
Angle_Config_t Config; ///< Конфигурации алгоритма расчета угла открытия тиристоров
|
||||||
|
|
||||||
float Iref; ///< текущее задание тока в о.е. [0..1]
|
float Iref; ///< текущее задание тока в о.е. [0..1]
|
||||||
float Imeas; ///< измеренное значение тока в о.е. [0..1]
|
float Imeas; ///< измеренное значение тока в о.е. [0..1]
|
||||||
float alpha; ///< текущий угол открытия в о.е. [0..1] (% от периода)
|
float alpha; ///< текущий угол открытия в о.е. [0..1] от 180 градусов
|
||||||
|
|
||||||
|
|
||||||
|
float alpha_real; /*!< @brief Фактический отсчитываемый угол открытия в о.е. [0..1] от 180 градусов
|
||||||
|
@details Этот угол отличается от @ref alpha дополнительными задержками и компенсациями:
|
||||||
|
- 30 градусов - смещение между линейными и фазными напряжение (мы смотрим линейные, а коммутируем фазные) */
|
||||||
|
|
||||||
arm_pid_instance_f32 pid; ///< ПИД регулятор для управления углом
|
arm_pid_instance_f32 pid; ///< ПИД регулятор для управления углом
|
||||||
FilterExp_t refFilter; ///< Фильтр для плавного нарастания регулирования
|
FilterExp_t refFilter; ///< Фильтр для плавного нарастания регулирования
|
||||||
@@ -44,13 +49,13 @@ typedef struct
|
|||||||
/* Инициализация Таймера для рассчета угла открытия. */
|
/* Инициализация Таймера для рассчета угла открытия. */
|
||||||
HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle);
|
HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle);
|
||||||
/* Инициализация ПИД регулятора. */
|
/* Инициализация ПИД регулятора. */
|
||||||
void Angle_PID_Init(Angle_Handle_t *hangle, float kp, float ki, float kd, float alpha);
|
HAL_StatusTypeDef Angle_PID_Init(Angle_Handle_t *hangle, float kp, float ki, float kd, float alpha);
|
||||||
|
|
||||||
// ====== УПРАВЛЕНИЕ ==========
|
// ====== УПРАВЛЕНИЕ ==========
|
||||||
/* Управление углом через ПИД регулятор */
|
/* Управление углом через ПИД регулятор */
|
||||||
void Angle_PID(Angle_Handle_t *hangle, float setpoint, float measurement);
|
void Angle_PID(Angle_Handle_t *hangle, float setpoint, float measurement, float Correction);
|
||||||
/* Выставление текущего угла открытия тиристоров. */
|
/* Выставление текущего угла открытия тиристоров. */
|
||||||
HAL_StatusTypeDef Angle_SetAngle(Angle_Handle_t *hangle, float Angle);
|
HAL_StatusTypeDef Angle_SetAlpha(Angle_Handle_t *hangle, float Angle, float Correction);
|
||||||
/* Установка угла открытия в таймер. */
|
/* Установка угла открытия в таймер. */
|
||||||
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float PeriodMs);
|
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float PeriodMs);
|
||||||
|
|
||||||
|
|||||||
@@ -59,8 +59,6 @@ HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm)
|
|||||||
PWM_SetHalfWave(hpwm, UPP_PHASE_B, UPP_WAVE_UNKNOWED);
|
PWM_SetHalfWave(hpwm, UPP_PHASE_B, UPP_WAVE_UNKNOWED);
|
||||||
PWM_SetHalfWave(hpwm, UPP_PHASE_C, UPP_WAVE_UNKNOWED);
|
PWM_SetHalfWave(hpwm, UPP_PHASE_C, UPP_WAVE_UNKNOWED);
|
||||||
|
|
||||||
PWM_SetConfig(hpwm, PARAM_INTERNAL.pwm.PhaseMask, PARAM_INTERNAL.pwm.Frequency, PARAM_INTERNAL.pwm.PulseNumber);
|
|
||||||
|
|
||||||
HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_1);
|
HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_1);
|
||||||
HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_2);
|
HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_2);
|
||||||
HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_3);
|
HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_3);
|
||||||
@@ -69,10 +67,8 @@ HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm)
|
|||||||
HAL_TIM_PWM_Start(&hpwm2, PWM_CHANNEL_6);
|
HAL_TIM_PWM_Start(&hpwm2, PWM_CHANNEL_6);
|
||||||
PWM_Stop(hpwm, 0, 1);
|
PWM_Stop(hpwm, 0, 1);
|
||||||
|
|
||||||
#ifndef PWM_HARDWARE_IMPULSES_CONTROL
|
|
||||||
__PWM_ReConfigToSoftwarePulses();
|
__PWM_ReConfigToSoftwarePulses();
|
||||||
HAL_TIM_Base_Start_IT(&hpwm1);
|
HAL_TIM_Base_Start(&hpwm1);
|
||||||
#endif
|
|
||||||
|
|
||||||
return HAL_OK;
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
@@ -85,16 +81,8 @@ HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm)
|
|||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
|
HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
|
||||||
{
|
{
|
||||||
if(assert_upp(hpwm))
|
if(assert_upp_phase(hpwm, Phase))
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
// Если уже какой-то канал запущен - не запускаем
|
|
||||||
if(hpwm->f.Running)
|
|
||||||
return HAL_BUSY;
|
|
||||||
// Если канал дурацкий - возвращаем ошибку
|
|
||||||
if(Phase >= 3)
|
|
||||||
{
|
|
||||||
return HAL_ERROR;
|
|
||||||
}
|
|
||||||
if (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN])
|
if (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN])
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
@@ -112,22 +100,8 @@ HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
|
|||||||
|
|
||||||
// Запуск только если таймер в режиме ожидания
|
// Запуск только если таймер в режиме ожидания
|
||||||
case PWM_THYR_TIM_WAIT:
|
case PWM_THYR_TIM_WAIT:
|
||||||
#ifndef PWM_HARDWARE_IMPULSES_CONTROL
|
|
||||||
hpwm->Phase[Phase]->State = PWM_THYR_TIM_START;
|
hpwm->Phase[Phase]->State = PWM_THYR_TIM_START;
|
||||||
return HAL_OK;
|
return HAL_OK;
|
||||||
#else
|
|
||||||
hpwm->Phase[Phase]->State = PWM_THYR_TIM_ACTIVE;
|
|
||||||
|
|
||||||
if(hpwm->Config.PulseNumber)
|
|
||||||
hpwm->Phase[Phase]->htim->Instance->RCR = hpwm->Config.PulseNumber-1;
|
|
||||||
else
|
|
||||||
return HAL_ERROR;
|
|
||||||
|
|
||||||
__PWM_SetOutputState(hpwm->Phase[Phase], PWM_ENABLE);
|
|
||||||
|
|
||||||
hpwm->f.Running++;
|
|
||||||
return HAL_TIM_Base_Start_IT(hpwm->Phase[Phase]->htim);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
@@ -146,7 +120,7 @@ HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
|
|||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_stop_all)
|
HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_stop_all)
|
||||||
{
|
{
|
||||||
if(assert_upp(hpwm))
|
if(assert_upp_phase(hpwm, Phase))
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
// Если force_stop_all - сбрасываем ВСЕ КАНАЛЫ
|
// Если force_stop_all - сбрасываем ВСЕ КАНАЛЫ
|
||||||
@@ -154,7 +128,6 @@ HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_
|
|||||||
{
|
{
|
||||||
// в первую очередь выключаем канал, потом выставим режим каналов
|
// в первую очередь выключаем канал, потом выставим режим каналов
|
||||||
__HAL_TIM_MOE_DISABLE(&hpwm1);
|
__HAL_TIM_MOE_DISABLE(&hpwm1);
|
||||||
// в первую очередь выключаем канал, потом выставим режим каналов
|
|
||||||
__HAL_TIM_MOE_DISABLE(&hpwm2);
|
__HAL_TIM_MOE_DISABLE(&hpwm2);
|
||||||
|
|
||||||
|
|
||||||
@@ -167,75 +140,12 @@ HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_
|
|||||||
}
|
}
|
||||||
// Если НЕ force_stop_all - сбрасываем ТОЛЬКО заданный канал
|
// Если НЕ force_stop_all - сбрасываем ТОЛЬКО заданный канал
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Если канал дурацкий - возвращаем ошибку
|
|
||||||
if(Phase >= 3)
|
|
||||||
{
|
|
||||||
return HAL_ERROR;
|
|
||||||
}
|
|
||||||
if (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN])
|
|
||||||
return HAL_ERROR;
|
|
||||||
|
|
||||||
// Если не force_stop_all - сбрасываем только текущий канал
|
// Если не force_stop_all - сбрасываем только текущий канал
|
||||||
__PWM_SetOutputState(hpwm->Phase[Phase], PWM_DISABLE);
|
__PWM_SetOutputState(hpwm->Phase[Phase], PWM_DISABLE);
|
||||||
if(hpwm->Phase[Phase]->State != PWM_THYR_DISABLED)
|
|
||||||
{
|
|
||||||
hpwm->Phase[Phase]->State = PWM_THYR_DISABLED;
|
|
||||||
#ifdef PWM_HARDWARE_IMPULSES_CONTROL
|
|
||||||
if(hpwm->f.Running)
|
|
||||||
hpwm->f.Running--;
|
|
||||||
HAL_TIM_Base_Stop(hpwm->Phase[Phase]->htim);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
return HAL_OK;
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Установка параметров ШИМ.
|
|
||||||
* @param hpwm Указатель на хендл ШИМ тиристоров
|
|
||||||
* @param Frequency Частота в ГЦ
|
|
||||||
* @return HAL Status.
|
|
||||||
*/
|
|
||||||
HAL_StatusTypeDef PWM_SetConfig(PWM_Handle_t *hpwm, uint8_t PhaseMask, uint16_t Frequency, uint8_t PulseNumber)
|
|
||||||
{
|
|
||||||
if(assert_upp(hpwm))
|
|
||||||
return HAL_ERROR;
|
|
||||||
if(hpwm->f.Running) // Если есть активные каналы - ниче не меняем
|
|
||||||
return HAL_BUSY;
|
|
||||||
|
|
||||||
// Остановка таймера
|
|
||||||
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-1));
|
|
||||||
__HAL_TIM_SET_AUTORELOAD(&hpwm2, TIM_FreqToTick(Frequency, PWM_TIM8_FREQ_MHZ-1));
|
|
||||||
// Скважности 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);
|
|
||||||
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_4, __HAL_TIM_GET_AUTORELOAD(&hpwm1)/2);
|
|
||||||
__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);
|
|
||||||
|
|
||||||
PWM_Stop(hpwm, 0, 1);
|
|
||||||
|
|
||||||
#ifndef PWM_HARDWARE_IMPULSES_CONTROL
|
|
||||||
return HAL_TIM_Base_Start_IT(&hpwm1);
|
|
||||||
#else
|
|
||||||
return HAL_OK;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Установка полуволны для слежения.
|
* @brief Установка полуволны для слежения.
|
||||||
* @param hpwm Указатель на хендл ШИМ тиристоров
|
* @param hpwm Указатель на хендл ШИМ тиристоров
|
||||||
@@ -246,19 +156,10 @@ HAL_StatusTypeDef PWM_SetConfig(PWM_Handle_t *hpwm, uint8_t PhaseMask, uint16_t
|
|||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_HalfWave_t halfwave)
|
HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_HalfWave_t halfwave)
|
||||||
{
|
{
|
||||||
if(assert_upp(hpwm))
|
if(assert_upp_phase(hpwm, Phase))
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
// Сбрасываем текущий канал
|
// Выставляем текущий активную полуволну
|
||||||
PWM_Stop(hpwm, Phase, 0);
|
|
||||||
|
|
||||||
// Если канал дурацкий - выставляем заглушку
|
|
||||||
if(Phase >= 3)
|
|
||||||
{
|
|
||||||
hpwm->Phase[Phase] = &hpwm->AllPhases[PHASE_UNKNOWN];
|
|
||||||
return HAL_ERROR;
|
|
||||||
}
|
|
||||||
// Выставляем канал
|
|
||||||
switch(halfwave)
|
switch(halfwave)
|
||||||
{
|
{
|
||||||
case UPP_WAVE_POSITIVE:
|
case UPP_WAVE_POSITIVE:
|
||||||
@@ -277,6 +178,51 @@ HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_Hal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Установка параметров ШИМ.
|
||||||
|
* @param hpwm Указатель на хендл ШИМ тиристоров
|
||||||
|
* @param Frequency Частота в ГЦ
|
||||||
|
* @return HAL Status.
|
||||||
|
*/
|
||||||
|
HAL_StatusTypeDef PWM_SetConfig(PWM_Handle_t *hpwm, uint8_t PhaseMask, uint16_t Frequency, float Duty, float PulseLength)
|
||||||
|
{
|
||||||
|
if(assert_upp(hpwm))
|
||||||
|
return HAL_ERROR;
|
||||||
|
if(hpwm->f.Running) // Если есть активные каналы - ниче не меняем
|
||||||
|
return HAL_BUSY;
|
||||||
|
|
||||||
|
// Остановка таймера
|
||||||
|
HAL_TIM_Base_Stop(&hpwm1);
|
||||||
|
|
||||||
|
hpwm->Config.PhaseMask.all = PhaseMask;
|
||||||
|
hpwm->Config.PulseLength = PulseLength;
|
||||||
|
hpwm->Config.Frequency = Frequency;
|
||||||
|
hpwm->Config.Duty = Duty;
|
||||||
|
// Высставление периодов
|
||||||
|
__HAL_TIM_SET_AUTORELOAD(&hpwm1, TIM_FreqToTick(Frequency, PWM_TIM1_FREQ_MHZ-1));
|
||||||
|
__HAL_TIM_SET_AUTORELOAD(&hpwm2, TIM_FreqToTick(Frequency, PWM_TIM8_FREQ_MHZ-1));
|
||||||
|
// Скважности
|
||||||
|
uint32_t pwm1_duty_ccr = (float)__HAL_TIM_GET_AUTORELOAD(&hpwm1)*(1-Duty);
|
||||||
|
uint32_t pwm2_duty_ccr = (float)__HAL_TIM_GET_AUTORELOAD(&hpwm2)*(1-Duty);
|
||||||
|
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_1, pwm1_duty_ccr);
|
||||||
|
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_2, pwm1_duty_ccr);
|
||||||
|
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_3, pwm1_duty_ccr);
|
||||||
|
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_4, pwm1_duty_ccr);
|
||||||
|
__HAL_TIM_SET_COMPARE(&hpwm2, PWM_CHANNEL_5, pwm2_duty_ccr);
|
||||||
|
__HAL_TIM_SET_COMPARE(&hpwm2, PWM_CHANNEL_6, pwm2_duty_ccr);
|
||||||
|
|
||||||
|
|
||||||
|
// Сброс счетчиков таймера и запуск заного
|
||||||
|
__HAL_TIM_SET_COUNTER(&hpwm1, 0);
|
||||||
|
__HAL_TIM_SET_COUNTER(&hpwm2, 0);
|
||||||
|
|
||||||
|
PWM_Stop(hpwm, 0, 1);
|
||||||
|
|
||||||
|
return HAL_TIM_Base_Start(&hpwm1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Установка полярности шим.
|
* @brief Установка полярности шим.
|
||||||
* @param hpwm Указатель на хендл ШИМ тиристоров
|
* @param hpwm Указатель на хендл ШИМ тиристоров
|
||||||
@@ -307,7 +253,7 @@ HAL_StatusTypeDef PWM_SetPolarity(PWM_Handle_t *hpwm, int polarity)
|
|||||||
* @return HAL Status.
|
* @return HAL Status.
|
||||||
* @details Автомат состояний, который определяет поведение каналов ШИМ
|
* @details Автомат состояний, который определяет поведение каналов ШИМ
|
||||||
*/
|
*/
|
||||||
HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
|
HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm, float PeriodMs)
|
||||||
{
|
{
|
||||||
if(assert_upp(hpwm))
|
if(assert_upp(hpwm))
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
@@ -321,7 +267,6 @@ HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
|
|||||||
if (hPhase->htim == NULL)
|
if (hPhase->htim == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
#ifndef PWM_HARDWARE_IMPULSES_CONTROL
|
|
||||||
switch (hPhase->State)
|
switch (hPhase->State)
|
||||||
{
|
{
|
||||||
case PWM_THYR_DISABLED: // канал отключен
|
case PWM_THYR_DISABLED: // канал отключен
|
||||||
@@ -334,7 +279,7 @@ HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
|
|||||||
|
|
||||||
case PWM_THYR_TIM_START: // начать ШИМ (пачка импульсов)
|
case PWM_THYR_TIM_START: // начать ШИМ (пачка импульсов)
|
||||||
__PWM_SetOutputState(hPhase, PWM_ENABLE);
|
__PWM_SetOutputState(hPhase, PWM_ENABLE);
|
||||||
hPhase->PulseCnt = hpwm->Config.PulseNumber - 1; // 1 импульс уже прошел
|
hPhase->PulseCnt = MS_TO_FAST_TICKS(PeriodMs*hpwm->Config.PulseLength) - 1; // 1 импульс уже прошел
|
||||||
hPhase->State = PWM_THYR_TIM_ACTIVE;
|
hPhase->State = PWM_THYR_TIM_ACTIVE;
|
||||||
hpwm->f.Running++;
|
hpwm->f.Running++;
|
||||||
break;
|
break;
|
||||||
@@ -358,16 +303,6 @@ HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
|
|||||||
__PWM_SetOutputState(hPhase, PWM_DISABLE);
|
__PWM_SetOutputState(hPhase, PWM_DISABLE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#else //PWM_HARDWARE_IMPULSES_CONTROL
|
|
||||||
// после того как пачка импульсов прошла отключаем активный канал
|
|
||||||
if (hPhase->State == PWM_THYR_TIM_ACTIVE)
|
|
||||||
{
|
|
||||||
if(hpwm->f.Running)
|
|
||||||
hpwm->f.Running--;
|
|
||||||
__PWM_SetOutputState(hPhase, PWM_DISABLE);
|
|
||||||
HAL_TIM_Base_Stop(hPhase->htim);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return HAL_OK;
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
@@ -388,37 +323,37 @@ static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Channel_t *hCh, uint32_t state
|
|||||||
if (hCh->htim == NULL)
|
if (hCh->htim == NULL)
|
||||||
return HAL_ERROR;
|
return HAL_ERROR;
|
||||||
|
|
||||||
uint32_t ch_mode = state;
|
// Если режим уже выставлен
|
||||||
|
if(hCh->CurrentMode == state)
|
||||||
|
{
|
||||||
|
return HAL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
hCh->CurrentMode = state;
|
||||||
|
|
||||||
// выставляем режим каналов
|
// выставляем режим каналов
|
||||||
switch(hCh->ChMask)
|
switch(hCh->ChMask)
|
||||||
{
|
{
|
||||||
case TIM_CHANNEL_1:
|
case TIM_CHANNEL_1:
|
||||||
hCh->htim->Instance->CCMR1 &= ~TIM_OCMODE_PWM2;
|
hCh->htim->Instance->CCMR1 &= ~TIM_OCMODE_PWM2;
|
||||||
hCh->htim->Instance->CCMR1 |= ch_mode;
|
hCh->htim->Instance->CCMR1 |= state;
|
||||||
break;
|
break;
|
||||||
case TIM_CHANNEL_2:
|
case TIM_CHANNEL_2:
|
||||||
hCh->htim->Instance->CCMR1 &= ~(TIM_OCMODE_PWM2 << 8);
|
hCh->htim->Instance->CCMR1 &= ~(TIM_OCMODE_PWM2 << 8);
|
||||||
hCh->htim->Instance->CCMR1 |= (ch_mode << 8);
|
hCh->htim->Instance->CCMR1 |= (state << 8);
|
||||||
break;
|
break;
|
||||||
case TIM_CHANNEL_3:
|
case TIM_CHANNEL_3:
|
||||||
hCh->htim->Instance->CCMR2 &= ~TIM_OCMODE_PWM2;
|
hCh->htim->Instance->CCMR2 &= ~TIM_OCMODE_PWM2;
|
||||||
hCh->htim->Instance->CCMR2 |= ch_mode;
|
hCh->htim->Instance->CCMR2 |= state;
|
||||||
break;
|
break;
|
||||||
case TIM_CHANNEL_4:
|
case TIM_CHANNEL_4:
|
||||||
hCh->htim->Instance->CCMR2 &= ~(TIM_OCMODE_PWM2 << 8);
|
hCh->htim->Instance->CCMR2 &= ~(TIM_OCMODE_PWM2 << 8);
|
||||||
hCh->htim->Instance->CCMR2 |= (ch_mode << 8);
|
hCh->htim->Instance->CCMR2 |= (state << 8);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// в последнюю очередь включаем выход. Перед этим настраиваем каналы на ШИМ
|
|
||||||
if(state == PWM_ENABLE)
|
|
||||||
{
|
|
||||||
__HAL_TIM_MOE_ENABLE(hCh->htim);
|
|
||||||
}
|
|
||||||
|
|
||||||
return HAL_OK;
|
return HAL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,16 @@
|
|||||||
|
|
||||||
// Индексы для структур каналов @ref PWM_Handle_t
|
// Индексы для структур каналов @ref PWM_Handle_t
|
||||||
#define PHASE_A_POS 0
|
#define PHASE_A_POS 0
|
||||||
#define PHASE_B_POS 1
|
#define PHASE_C_POS 1
|
||||||
#define PHASE_C_POS 2
|
#define PHASE_B_POS 2
|
||||||
#define PHASE_A_NEG 3
|
#define PHASE_A_NEG 3
|
||||||
#define PHASE_B_NEG 4
|
#define PHASE_C_NEG 4
|
||||||
#define PHASE_C_NEG 5
|
#define PHASE_B_NEG 5
|
||||||
#define PHASE_UNKNOWN 6
|
#define PHASE_UNKNOWN 6
|
||||||
|
|
||||||
|
|
||||||
|
#define PWM_PulseLengthToCnt(_length_, _period_) ((_length_)*(_period_)/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Состояния канала
|
* @brief Состояния канала
|
||||||
*/
|
*/
|
||||||
@@ -52,6 +54,7 @@ typedef struct {
|
|||||||
TIM_HandleTypeDef *htim; ///< указатель на соответствующий TIM (hpwm1 или hpwm2)
|
TIM_HandleTypeDef *htim; ///< указатель на соответствующий TIM (hpwm1 или hpwm2)
|
||||||
uint32_t PulseCnt; ///< Счетчик кол-ва импульсов. Инициализируется из структуры @ref PWM_ThyrConfig_t
|
uint32_t PulseCnt; ///< Счетчик кол-ва импульсов. Инициализируется из структуры @ref PWM_ThyrConfig_t
|
||||||
uint32_t ChMask; ///< TIM_CHANNEL_x
|
uint32_t ChMask; ///< TIM_CHANNEL_x
|
||||||
|
uint32_t CurrentMode; ///< Текущий режим канала
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned Ready:1; ///< Флаг готовности тиристора к работе
|
unsigned Ready:1; ///< Флаг готовности тиристора к работе
|
||||||
@@ -72,16 +75,17 @@ typedef struct {
|
|||||||
uint8_t phC:1;
|
uint8_t phC:1;
|
||||||
};
|
};
|
||||||
}PhaseMask; ///< Какими каналами управлять
|
}PhaseMask; ///< Какими каналами управлять
|
||||||
uint8_t PulseNumber; ///< Сколько импульсов отправить в пакете для открытия тиристоров
|
float PulseLength; ///< Длина импульса в о.е. от 180 градусов
|
||||||
uint16_t Frequency; ///< Частота импульсов
|
uint16_t Frequency; ///< Частота импульсов
|
||||||
|
float Duty; ///< Скважность импульсов
|
||||||
} PWM_ThyrConfig_t;
|
} PWM_ThyrConfig_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Хендл управляюзщий тиристорами */
|
* @brief Хендл управляюзщий тиристорами */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PWM_ThyrConfig_t Config;
|
PWM_ThyrConfig_t Config; ///< Конфигурации ШИМ
|
||||||
PWM_Channel_t *Phase[3]; ///< Текущие каналы для фаз
|
PWM_Channel_t *Phase[3]; ///< Каналы для активной в данный момент фазы
|
||||||
PWM_Channel_t AllPhases[7]; ///< Все каналы для фаз (+1 для деинициализированного канала)
|
PWM_Channel_t AllPhases[7]; ///< Все каналы для фаз (+1 для деинициализированного канала)
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
unsigned Initialized : 1;
|
unsigned Initialized : 1;
|
||||||
@@ -100,12 +104,12 @@ HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase);
|
|||||||
/* Остановить ШИМ. */
|
/* Остановить ШИМ. */
|
||||||
HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_stop_all);
|
HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_stop_all);
|
||||||
/* Установка частоты ШИМ. */
|
/* Установка частоты ШИМ. */
|
||||||
HAL_StatusTypeDef PWM_SetConfig(PWM_Handle_t *hpwm, uint8_t PhaseMask, uint16_t Frequency, uint8_t PulseNumber);
|
HAL_StatusTypeDef PWM_SetConfig(PWM_Handle_t *hpwm, uint8_t PhaseMask, uint16_t Frequency, float Duty, float PulseLength);
|
||||||
/* Установка полуволны для слежения. */
|
/* Установка полуволны для слежения. */
|
||||||
HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_HalfWave_t halfwave);
|
HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_HalfWave_t halfwave);
|
||||||
/* Установка полярности шим. */
|
/* Установка полярности шим. */
|
||||||
HAL_StatusTypeDef PWM_SetPolarity(PWM_Handle_t *hpwm, int polarity);
|
HAL_StatusTypeDef PWM_SetPolarity(PWM_Handle_t *hpwm, int polarity);
|
||||||
// ====== СЕРВИС ==========
|
// ====== СЕРВИС ==========
|
||||||
/* Хендл ШИМ тиристоров. */
|
/* Хендл ШИМ тиристоров. */
|
||||||
HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm);
|
HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm, float PeriodMs);
|
||||||
#endif /* _PWM_THYRISTORS_H */
|
#endif /* _PWM_THYRISTORS_H */
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
UPP_Errors_t errors;
|
UPP_Errors_t errors;
|
||||||
|
|
||||||
static UPP_ErrorType_t UPP_SelectCommonError(void);
|
static UPP_ErrorType_t UPP_SelectCommonError(void);
|
||||||
static int setError(int condition, int flag, int *timer, int delay);
|
__STATIC_FORCEINLINE int setError(int condition, int flag, int *timer, int delay);
|
||||||
void UPP_Errors_Program(void);
|
void UPP_Errors_Program(void);
|
||||||
void UPP_Errors_Power(void);
|
void UPP_Errors_Power(void);
|
||||||
void UPP_Errors_Ranges(void);
|
void UPP_Errors_Ranges(void);
|
||||||
@@ -77,7 +77,7 @@ void UPP_Errors_Power(void)
|
|||||||
void UPP_Errors_Ranges(void)
|
void UPP_Errors_Ranges(void)
|
||||||
{
|
{
|
||||||
/* Преобразуем уставки в нормальные тики */
|
/* Преобразуем уставки в нормальные тики */
|
||||||
float ticksTiMax = to_float(PARAM_PUI.TiMax, 1)/PM_SLOW_PERIOD_US;
|
float ticksTiMax = u2f(PARAM_PUI.TiMax, 1)/PM_SLOW_PERIOD_US;
|
||||||
/* Счетчики для отсчитывания задержки выставления ошибки */
|
/* Счетчики для отсчитывания задержки выставления ошибки */
|
||||||
static int IMaxCnt = 0;
|
static int IMaxCnt = 0;
|
||||||
static int UMaxCnt = 0;
|
static int UMaxCnt = 0;
|
||||||
@@ -225,7 +225,7 @@ static UPP_ErrorType_t UPP_SelectCommonError(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int setError(int condition, int flag, int *timer, int delay)
|
__STATIC_FORCEINLINE int setError(int condition, int flag, int *timer, int delay)
|
||||||
{
|
{
|
||||||
if (condition) {
|
if (condition) {
|
||||||
if (*timer < delay)
|
if (*timer < delay)
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ typedef struct
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
uint16_t angle_reinit_err;
|
||||||
uint16_t adc_reinit_err;
|
uint16_t adc_reinit_err;
|
||||||
uint16_t zc_reinit_err;
|
uint16_t zc_reinit_err;
|
||||||
uint16_t pwm_reinit_err;
|
uint16_t pwm_reinit_err;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ static void UPP_DO5_Write(int state);
|
|||||||
*/
|
*/
|
||||||
void UPP_IO_Init(void)
|
void UPP_IO_Init(void)
|
||||||
{
|
{
|
||||||
/* Дискретне выходы */
|
/* Дискретные выходы */
|
||||||
UPP_DO.CEN = &UPP_CEN_Write;
|
UPP_DO.CEN = &UPP_CEN_Write;
|
||||||
UPP_DO.Ready = &UPP_RDO3_Write;
|
UPP_DO.Ready = &UPP_RDO3_Write;
|
||||||
UPP_DO.Work = &UPP_RDO2_Write;
|
UPP_DO.Work = &UPP_RDO2_Write;
|
||||||
@@ -99,7 +99,11 @@ void UPP_UART2_SetDirection(int state)
|
|||||||
|
|
||||||
static void UPP_CEN_Write(int state)
|
static void UPP_CEN_Write(int state)
|
||||||
{
|
{
|
||||||
|
#if !defined(STM32F417xx)
|
||||||
HAL_GPIO_WritePin(CEN_GPIO_Port, CEN_Pin, !state);
|
HAL_GPIO_WritePin(CEN_GPIO_Port, CEN_Pin, !state);
|
||||||
|
#else
|
||||||
|
HAL_GPIO_WritePin(CEN_GPIO_Port, CEN_Pin, state);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
static void UPP_RDO1_Write(int state)
|
static void UPP_RDO1_Write(int state)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,7 +10,10 @@
|
|||||||
#define _UPP_IO_H
|
#define _UPP_IO_H
|
||||||
#include "mylibs_include.h"
|
#include "mylibs_include.h"
|
||||||
|
|
||||||
|
#define DIN_Pusk_GPIO_Port DIN1_GPIO_Port
|
||||||
|
#define DIN_Pusk_Pin DIN1_Pin
|
||||||
|
#define DIN_MestDist_GPIO_Port DIN2_GPIO_Port
|
||||||
|
#define DIN_MestDist_Pin DIN2_Pin
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,8 +15,7 @@
|
|||||||
|
|
||||||
UPP_t upp;
|
UPP_t upp;
|
||||||
HAL_StatusTypeDef res; // сюда сохраняется результат от выполения всяких функций
|
HAL_StatusTypeDef res; // сюда сохраняется результат от выполения всяких функций
|
||||||
float dbg_iref = 2;
|
int dbg_polarity = 1;
|
||||||
int dbg_polarity = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Инициализация УПП.
|
* @brief Инициализация УПП.
|
||||||
@@ -52,6 +51,10 @@ int UPP_App_Init(void)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(UPP_Params_Init() != HAL_OK)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,17 +63,16 @@ int UPP_App_Init(void)
|
|||||||
* @return 0 - если ОК, >1 если ошибка.
|
* @return 0 - если ОК, >1 если ошибка.
|
||||||
*/
|
*/
|
||||||
int UPP_PreWhile(void)
|
int UPP_PreWhile(void)
|
||||||
{
|
{
|
||||||
UPP_Params_ControlInternal();
|
UPP_Params_Control();
|
||||||
|
|
||||||
if(Angle_SetRange(&upp.hangle, 0.0, 0.8) != HAL_OK)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if(PowerMonitor_Start(&upp.pm) != HAL_OK)
|
if(PowerMonitor_Start(&upp.pm) != HAL_OK)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
#ifdef MATLAB
|
||||||
|
dbg_polarity = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
UPP_DO.CEN(ENABLE);
|
UPP_DO.CEN(ENABLE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -86,20 +88,29 @@ int UPP_While(void)
|
|||||||
if(upp.pm.f.runSlow)
|
if(upp.pm.f.runSlow)
|
||||||
{
|
{
|
||||||
static uint32_t slow_cnt = 0;
|
static uint32_t slow_cnt = 0;
|
||||||
|
upp.Timings.slow_calc_prd_us = BenchTime_Period(BT_SLOWCALC_PRD, angletim.Instance->CNT, HAL_MAX_DELAY)/ANGLE_TIM2_FREQ_MHZ;
|
||||||
BenchTime_Start(BT_SLOWCALC, angletim.Instance->CNT, HAL_MAX_DELAY);
|
BenchTime_Start(BT_SLOWCALC, angletim.Instance->CNT, HAL_MAX_DELAY);
|
||||||
res = HAL_IWDG_Refresh(&hiwdg);
|
res = HAL_IWDG_Refresh(&hiwdg); // если не вызываются медленные расчеты - что-то не то сбрасываемся по watchdog
|
||||||
// Медленные расчеты
|
// Медленные расчеты
|
||||||
PowerMonitor_SlowCalc(&upp.pm);
|
PowerMonitor_SlowCalc(&upp.pm);
|
||||||
|
|
||||||
|
int razgon_done = (fabsf(upp.hangle.Iref - u2f(PARAM_PUI.Iref, 100)) < 0.1);
|
||||||
|
|
||||||
#ifdef UPP_SIMULATE_I // симулируем токи
|
#ifdef UPP_SIMULATE_I // симулируем токи
|
||||||
upp.pm.measured.final.Iamp = upp.hangle.Iref/2;
|
upp.pm.measured.final.Iamp = upp.hangle.Iref/2;
|
||||||
// Защиты // При симуляции тока не включаем его проверку
|
// При симуляции тока не включаем его проверку
|
||||||
PowerMonitor_Protect(&upp.pm, 0);
|
razgon_done = 0;
|
||||||
#else
|
|
||||||
// Защиты // Определенные защиты по току включаем только в после разгона
|
|
||||||
PowerMonitor_Protect(&upp.pm, (fabsf(upp.hangle.Iref - dbg_iref) < 0.1));
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Защиты // Определенные защиты по току включаем только после разгона
|
||||||
|
PowerMonitor_Protect(&upp.pm, razgon_done);
|
||||||
|
// Обрабока ошибок и выставление итоговой Ошибки
|
||||||
|
UPP_Errors_Handle();
|
||||||
|
// Контроль парамеров
|
||||||
|
UPP_Params_Control();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef UPP_DISABLE_ERROR_BLOCK
|
#ifndef UPP_DISABLE_ERROR_BLOCK
|
||||||
// если ошибка вызываем СТОП
|
// если ошибка вызываем СТОП
|
||||||
@@ -123,6 +134,8 @@ int UPP_While(void)
|
|||||||
{
|
{
|
||||||
/*======= Состояние Инициализация =========*/
|
/*======= Состояние Инициализация =========*/
|
||||||
case UPP_Init:
|
case UPP_Init:
|
||||||
|
res = PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
|
||||||
|
// Индикация
|
||||||
UPP_DO.Ready(DISABLE);
|
UPP_DO.Ready(DISABLE);
|
||||||
UPP_DO.Work(DISABLE);
|
UPP_DO.Work(DISABLE);
|
||||||
UPP_DO.Error(DISABLE);
|
UPP_DO.Error(DISABLE);
|
||||||
@@ -162,6 +175,9 @@ int UPP_While(void)
|
|||||||
|
|
||||||
/*======= Состояние В работе =========*/
|
/*======= Состояние В работе =========*/
|
||||||
case UPP_Work:
|
case UPP_Work:
|
||||||
|
// Разрешаем выход ШИМ
|
||||||
|
__HAL_TIM_MOE_ENABLE(&hpwm1);
|
||||||
|
__HAL_TIM_MOE_ENABLE(&hpwm2);
|
||||||
// Индикация
|
// Индикация
|
||||||
UPP_DO.Ready(DISABLE);
|
UPP_DO.Ready(DISABLE);
|
||||||
UPP_DO.Work(ENABLE);
|
UPP_DO.Work(ENABLE);
|
||||||
@@ -169,9 +185,14 @@ int UPP_While(void)
|
|||||||
// если пришла команда на остановку
|
// если пришла команда на остановку
|
||||||
if (!upp.call->go)
|
if (!upp.call->go)
|
||||||
upp.workmode = UPP_Init;
|
upp.workmode = UPP_Init;
|
||||||
|
|
||||||
|
// Коррекция для отсчета угла открытия
|
||||||
|
// 30 градусов - сдвиг между линейными и фазными напряжениями
|
||||||
|
// 30 градусов - фазовое смщеение эксп. фильтра АЦП для сглаживания напряжений
|
||||||
|
float Correction = 30 + 0;
|
||||||
|
|
||||||
// Регулирование тиристоров
|
// Регулирование тиристоров
|
||||||
Angle_PID(&upp.hangle, dbg_iref, upp.pm.measured.final.Iamp);
|
Angle_PID(&upp.hangle, u2f(PARAM_PUI.Iref,100), upp.pm.measured.final.Iamp, Correction);
|
||||||
|
|
||||||
// если слишком долгий запуск
|
// если слишком долгий запуск
|
||||||
if((local_time() - upp.StartTick) > (upp.PUI.params->Tdelay*1000))
|
if((local_time() - upp.StartTick) > (upp.PUI.params->Tdelay*1000))
|
||||||
@@ -194,7 +215,7 @@ int UPP_While(void)
|
|||||||
default:
|
default:
|
||||||
PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
|
PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
|
||||||
// Индикация
|
// Индикация
|
||||||
UPP_DO.Ready(ENABLE);
|
UPP_DO.Ready(DISABLE);
|
||||||
UPP_DO.Work(DISABLE);
|
UPP_DO.Work(DISABLE);
|
||||||
UPP_DO.Error(ENABLE);
|
UPP_DO.Error(ENABLE);
|
||||||
// Находимся до тех пор пока ошибки не будет устранена
|
// Находимся до тех пор пока ошибки не будет устранена
|
||||||
@@ -222,13 +243,10 @@ int UPP_While(void)
|
|||||||
*/
|
*/
|
||||||
void UPP_Tick(void)
|
void UPP_Tick(void)
|
||||||
{
|
{
|
||||||
|
// Начинаем все проверять только после того как уйдем из режима инициализации
|
||||||
if(upp.workmode == UPP_Init)
|
if(upp.workmode == UPP_Init)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Обрабока ошибок и выставление итоговой Ошибки
|
|
||||||
UPP_Errors_Handle();
|
|
||||||
//
|
|
||||||
UPP_Params_ControlInternal();
|
|
||||||
|
|
||||||
if(GPIO_Read_Switch(&UPP_DIN.Pusk))
|
if(GPIO_Read_Switch(&UPP_DIN.Pusk))
|
||||||
{
|
{
|
||||||
@@ -242,10 +260,16 @@ void UPP_Tick(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// ПРЕРЫВАНИЯ stm32f4xx_it.c
|
//================ ПРЕРЫВАНИЯ stm32f4xx_it.c ===================
|
||||||
|
/**
|
||||||
|
* @brief @ref DMA2_Stream0_IRQHandler
|
||||||
|
*/
|
||||||
void UPP_ADC_Handle(void)
|
void UPP_ADC_Handle(void)
|
||||||
{
|
{
|
||||||
|
upp.Timings.isr_adc_prd_us = BenchTime_Period(BT_ADC_PRD, angletim.Instance->CNT, HAL_MAX_DELAY)/ANGLE_TIM2_FREQ_MHZ;
|
||||||
BenchTime_Start(BT_ADC, angletim.Instance->CNT, HAL_MAX_DELAY);
|
BenchTime_Start(BT_ADC, angletim.Instance->CNT, HAL_MAX_DELAY);
|
||||||
|
|
||||||
|
|
||||||
if(upp.pm.f.inIsr)
|
if(upp.pm.f.inIsr)
|
||||||
{
|
{
|
||||||
ERR_PRIVATE.overrun_fast_calc = 1;
|
ERR_PRIVATE.overrun_fast_calc = 1;
|
||||||
@@ -268,25 +292,23 @@ void UPP_ADC_Handle(void)
|
|||||||
UPP_HalfWave_t curr_halfwave = ZC_GetHalfWave(&upp.pm.zc, phase);
|
UPP_HalfWave_t curr_halfwave = ZC_GetHalfWave(&upp.pm.zc, phase);
|
||||||
res = PWM_SetHalfWave(&upp.hpwm, phase, curr_halfwave);
|
res = PWM_SetHalfWave(&upp.hpwm, phase, curr_halfwave);
|
||||||
// Начинаем отсчитывать угол
|
// Начинаем отсчитывать угол
|
||||||
res = Angle_Start(&upp.hangle, phase, 10);
|
res = Angle_Start(&upp.hangle, phase, UPP_HALFWAVE_PERIOD);
|
||||||
if(res != HAL_OK)
|
if(res != HAL_OK)
|
||||||
__NOP();
|
__NOP();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Проверяем на ошибки
|
// ШИМим ключи
|
||||||
|
res = PWM_Handle(&upp.hpwm, UPP_HALFWAVE_PERIOD);
|
||||||
|
|
||||||
upp.Timings.isr_adc_us = BenchTime_End(BT_ADC, angletim.Instance->CNT)/ANGLE_TIM2_FREQ_MHZ;
|
upp.Timings.isr_adc_us = BenchTime_End(BT_ADC, angletim.Instance->CNT)/ANGLE_TIM2_FREQ_MHZ;
|
||||||
upp.pm.f.inIsr = 0;
|
upp.pm.f.inIsr = 0;
|
||||||
}
|
}
|
||||||
void UPP_PWM_Handle(void)
|
|
||||||
{
|
|
||||||
BenchTime_Start(BT_PWM, angletim.Instance->CNT, HAL_MAX_DELAY);
|
|
||||||
res = PWM_Handle(&upp.hpwm);
|
|
||||||
upp.Timings.isr_pwm_us = BenchTime_End(BT_PWM, angletim.Instance->CNT)/ANGLE_TIM2_FREQ_MHZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief @ref HAL_TIM_OC_DelayElapsedCallback
|
||||||
|
*/
|
||||||
void UPP_Angle_Handle(void)
|
void UPP_Angle_Handle(void)
|
||||||
{
|
{
|
||||||
UPP_Phase_t phase = Angle_Handle(&upp.hangle);
|
UPP_Phase_t phase = Angle_Handle(&upp.hangle);
|
||||||
@@ -313,7 +335,9 @@ void UPP_Angle_Handle(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback по совпадению CCRx
|
/**
|
||||||
|
* @brief Callback по совпадению CCRx c CNT
|
||||||
|
*/
|
||||||
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim)
|
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim)
|
||||||
{
|
{
|
||||||
if (htim == upp.hangle.htim)
|
if (htim == upp.hangle.htim)
|
||||||
@@ -321,6 +345,9 @@ void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim)
|
|||||||
UPP_Angle_Handle();
|
UPP_Angle_Handle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @brief @ref HAL_TIM_PeriodElapsedCallback
|
||||||
|
*/
|
||||||
void HAL_IncTick(void)
|
void HAL_IncTick(void)
|
||||||
{
|
{
|
||||||
BenchTime_Start(BT_SYSTICK, angletim.Instance->CNT, HAL_MAX_DELAY);
|
BenchTime_Start(BT_SYSTICK, angletim.Instance->CNT, HAL_MAX_DELAY);
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ typedef struct
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
uint32_t slow_calc_prd_us;
|
||||||
uint32_t slow_calc_us;
|
uint32_t slow_calc_us;
|
||||||
|
uint32_t isr_adc_prd_us;
|
||||||
uint32_t isr_adc_us;
|
uint32_t isr_adc_us;
|
||||||
uint32_t isr_pwm_us;
|
uint32_t isr_pwm_us;
|
||||||
uint32_t isr_systick_us;
|
uint32_t isr_systick_us;
|
||||||
|
|||||||
@@ -1,26 +1,105 @@
|
|||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @file upp_params.c
|
* @file upp_params.c
|
||||||
* @brief Модуль определябщий поведение УПП
|
* @brief Модуль проверяющий параметры УПП
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @details
|
* @details
|
||||||
******************************************************************************/
|
* ИНСТРУКЦИЯ ПО ДОБАВЛЕНИЮ НОВЫХ ПАРАМЕТРОВ:
|
||||||
|
*
|
||||||
|
* 1. Добавить новый параметр в соответствующую структуру в файле параметров:
|
||||||
|
* - PARAM_PUI для параметров от ПУИ (пульт управления и индикации)
|
||||||
|
* - PARAM_INTERNAL для внутренних параметров УПП
|
||||||
|
*
|
||||||
|
* 2. В функции UPP_Params_ControlInternal() или UPP_Params_ControlPUI():
|
||||||
|
* a. Объявить временную переменную для хранения текущего значения
|
||||||
|
* b. Проверить изменение параметра (можно с помощью __CheckParamX() функции)
|
||||||
|
* c. Обновить параметр в соответствующем модуле новым параметром если он изменился
|
||||||
|
*
|
||||||
|
* 3. В функции UPP_Params_SetDefault() добавить установку значения по умолчанию
|
||||||
|
*
|
||||||
|
* 4. При необходимости добавить сатурацию параметра в UPP_Params_Saturate()
|
||||||
|
*
|
||||||
|
* Пример добавления простого параметра:
|
||||||
|
*
|
||||||
|
* // В UPP_Params_ControlInternal():
|
||||||
|
* float new_param = module.param;
|
||||||
|
* if(__CheckParamF(&new_param, PARAM_INTERNAL.new_param, 1000))
|
||||||
|
* {
|
||||||
|
* module_update = 1;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // В блоке обновления модуля:
|
||||||
|
* if(module_update)
|
||||||
|
* {
|
||||||
|
* if(Module_SetParam(&module, new_param) == HAL_OK)
|
||||||
|
* module_update = 0;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* // В UPP_Params_SetDefault():
|
||||||
|
* PARAM_INTERNAL.new_param = NEW_PARAM_DEFAULT * 1000;
|
||||||
|
*
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
#include "upp_main.h" // всё остальное по работе с УПП
|
#include "upp_main.h" // всё остальное по работе с УПП
|
||||||
|
|
||||||
|
#define SATURATE_U16(value, min, max) \
|
||||||
|
value = ((value) < (min) ? (min) : ((value) > (max) ? (max) : (value)))
|
||||||
|
|
||||||
static int __CheckSimpleParamF(float *paramDist, uint16_t paramSrc, float Coef);
|
static int __CheckParamF(float *paramDist, uint16_t paramSrc, float Coef);
|
||||||
static int __CheckSimpleParamU32(uint32_t *paramDist, uint16_t paramSrc, float Coef);
|
static int __CheckParamU32(uint32_t *paramDist, uint16_t paramSrc, float Coef);
|
||||||
static int __CheckSimpleParamU16(uint16_t *paramDist, uint16_t paramSrc);
|
static int __CheckParamU16(uint16_t *paramDist, uint16_t paramSrc);
|
||||||
static int __CheckSimpleParamU8(uint8_t *paramDist, uint16_t paramSrc, float Coef);
|
static int __CheckParamU8(uint8_t *paramDist, uint16_t paramSrc, float Coef);
|
||||||
static void __AngleSetLimit(void);
|
static void __AngleSetLimit(void);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Контроль параметров УПП.
|
||||||
|
* @return HAL Status.
|
||||||
|
*/
|
||||||
|
void UPP_Params_Control(void)
|
||||||
|
{
|
||||||
|
/* Проверяем параметры на корректный диапазон */
|
||||||
|
UPP_Params_Saturate();
|
||||||
|
/* Чекаем изменились ли параметры от ПУИ */
|
||||||
|
UPP_Params_ControlPUI();
|
||||||
|
/* Чекаем изменились ли внутренние параметры */
|
||||||
|
UPP_Params_ControlInternal();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Контроль параметров от ПУИ.
|
||||||
|
* @return HAL Status.
|
||||||
|
*/
|
||||||
|
void UPP_Params_ControlPUI(void)
|
||||||
|
{
|
||||||
|
if(upp.call->go) // при запущеном УПП ничего не меняем
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Tnt - Уставка на скорость нарастания пускового тока */
|
||||||
|
float angle_ref_alphaPUI = PUI_Tnt_CalcAlpha(u2f(PARAM_PUI.Tnt, 1000), PM_SLOW_PERIOD_US);
|
||||||
|
float angle_ref_alpha = upp.hangle.refFilter.alpha;
|
||||||
|
if(angle_ref_alpha != angle_ref_alphaPUI)
|
||||||
|
{
|
||||||
|
angle_ref_alpha = angle_ref_alphaPUI;
|
||||||
|
if(Angle_PID_Init(&upp.hangle,
|
||||||
|
upp.hangle.pid.Kp,
|
||||||
|
upp.hangle.pid.Ki,
|
||||||
|
upp.hangle.pid.Kd,
|
||||||
|
angle_ref_alpha) != HAL_OK)
|
||||||
|
ERR_PRIVATE_CNT.angle_reinit_err++;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Контроль внутренних параметров УПП.
|
* @brief Контроль внутренних параметров УПП.
|
||||||
* @return HAL Status.
|
* @return HAL Status.
|
||||||
*/
|
*/
|
||||||
void UPP_Params_ControlInternal(void)
|
void UPP_Params_ControlInternal(void)
|
||||||
{
|
{
|
||||||
__AngleSetLimit();
|
|
||||||
if(upp.call->go) // при запущеном УПП ничего не меняем
|
if(upp.call->go) // при запущеном УПП ничего не меняем
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -34,9 +113,8 @@ void UPP_Params_ControlInternal(void)
|
|||||||
float angle_max = upp.hangle.Config.AngleMax;
|
float angle_max = upp.hangle.Config.AngleMax;
|
||||||
float angle_min = upp.hangle.Config.AngleMin;
|
float angle_min = upp.hangle.Config.AngleMin;
|
||||||
float angle_pid_kp = upp.hangle.pid.Kp;
|
float angle_pid_kp = upp.hangle.pid.Kp;
|
||||||
float angle_pid_ki = upp.hangle.pid.Ki;
|
float angle_pid_ki = upp.hangle.pid.Ki/((float)PM_SLOW_PERIOD_US/1000000);
|
||||||
float angle_pid_kd = upp.hangle.pid.Kd;
|
float angle_pid_kd = upp.hangle.pid.Kd;
|
||||||
float angle_ref_alpha = upp.hangle.refFilter.alpha;
|
|
||||||
// временная переменная для параметров каналов АЦП
|
// временная переменная для параметров каналов АЦП
|
||||||
float adc_channel_max[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
|
float adc_channel_max[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
|
||||||
uint16_t adc_channel_zero[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
|
uint16_t adc_channel_zero[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
|
||||||
@@ -46,38 +124,35 @@ void UPP_Params_ControlInternal(void)
|
|||||||
// временная переменная для параметров ШИМ
|
// временная переменная для параметров ШИМ
|
||||||
uint8_t pwm_phase_mask = upp.hpwm.Config.PhaseMask.all;
|
uint8_t pwm_phase_mask = upp.hpwm.Config.PhaseMask.all;
|
||||||
uint16_t pwm_freq = upp.hpwm.Config.Frequency;
|
uint16_t pwm_freq = upp.hpwm.Config.Frequency;
|
||||||
uint8_t pwm_pulse_num = upp.hpwm.Config.PulseNumber;
|
float pwm_duty = upp.hpwm.Config.Duty;
|
||||||
|
float pwm_pulse_len = upp.hpwm.Config.PulseLength;
|
||||||
// временная переменная для параметров Мониторинга сети
|
// временная переменная для параметров Мониторинга сети
|
||||||
float pm_alpha = upp.pm.exp[0].alpha;
|
uint16_t pm_rms_widnow_size = upp.pm.rms[0].window_size;
|
||||||
|
float pm_rms_exp_alpha = upp.pm.rms_exp[0].alpha;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Параметры регулятора Угла открытия
|
// Параметры регулятора Угла открытия
|
||||||
if(__CheckSimpleParamF(&angle_max, PARAM_INTERNAL.angle.Angle_Max, 65535))
|
if(__CheckParamF(&angle_max, PARAM_INTERNAL.angle.Angle_Max, 65535))
|
||||||
{
|
{
|
||||||
alpha_update = 1;
|
alpha_update = 1;
|
||||||
}
|
}
|
||||||
if(__CheckSimpleParamF(&angle_min, PARAM_INTERNAL.angle.Angle_Min, 65535))
|
if(__CheckParamF(&angle_min, PARAM_INTERNAL.angle.Angle_Min, 65535))
|
||||||
{
|
{
|
||||||
alpha_update = 1;
|
alpha_update = 1;
|
||||||
}
|
}
|
||||||
if(__CheckSimpleParamF(&angle_pid_kp, PARAM_INTERNAL.angle.PID_Kp, 10000))
|
if(__CheckParamF(&angle_pid_kp, PARAM_INTERNAL.angle.PID_Kp, 10000))
|
||||||
{
|
{
|
||||||
alpha_update = 1;
|
alpha_update = 1;
|
||||||
}
|
}
|
||||||
if(__CheckSimpleParamF(&angle_pid_ki, PARAM_INTERNAL.angle.PID_Ki, 10000))
|
if(__CheckParamF(&angle_pid_ki, PARAM_INTERNAL.angle.PID_Ki, 10000))
|
||||||
{
|
{
|
||||||
alpha_update = 1;
|
alpha_update = 1;
|
||||||
}
|
}
|
||||||
if(__CheckSimpleParamF(&angle_pid_kd, PARAM_INTERNAL.angle.PID_Kd, 10000))
|
if(__CheckParamF(&angle_pid_kd, PARAM_INTERNAL.angle.PID_Kd, 10000))
|
||||||
{
|
{
|
||||||
alpha_update = 1;
|
alpha_update = 1;
|
||||||
}
|
}
|
||||||
if(__CheckSimpleParamF(&angle_ref_alpha, PARAM_INTERNAL.angle.PID_ExpAlpha, 65535))
|
|
||||||
{
|
|
||||||
alpha_update = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Параметры АЦП
|
// Параметры АЦП
|
||||||
@@ -87,56 +162,82 @@ void UPP_Params_ControlInternal(void)
|
|||||||
adc_channel_zero[i] = upp.pm.adc.Coefs[i].lZero;
|
adc_channel_zero[i] = upp.pm.adc.Coefs[i].lZero;
|
||||||
|
|
||||||
// Максимальное измеряемое напряжение
|
// Максимальное измеряемое напряжение
|
||||||
if(__CheckSimpleParamF(&adc_channel_max[i], PARAM_INTERNAL.adc.ADC_Max[i], 10))
|
if(__CheckParamF(&adc_channel_max[i], PARAM_INTERNAL.adc.ADC_Max[i], 10))
|
||||||
{
|
{
|
||||||
adc_channel_update[i] = 1;
|
adc_channel_update[i] = 1;
|
||||||
}
|
}
|
||||||
// Значение АЦП при нулевом входе
|
// Значение АЦП при нулевом входе
|
||||||
if(__CheckSimpleParamU16(&adc_channel_zero[i], PARAM_INTERNAL.adc.ADC_Zero[i]))
|
if(__CheckParamU16(&adc_channel_zero[i], PARAM_INTERNAL.adc.ADC_Zero[i]))
|
||||||
{
|
{
|
||||||
adc_channel_update[i] = 1;
|
adc_channel_update[i] = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Параметры алгоритма перехода через ноль
|
// Параметры алгоритма перехода через ноль
|
||||||
if(__CheckSimpleParamF(&zc_hysteresis, PARAM_INTERNAL.zc.Hysteresis, 10000))
|
if(__CheckParamF(&zc_hysteresis, PARAM_INTERNAL.zc.Hysteresis, 10000))
|
||||||
{
|
{
|
||||||
zc_update = 1;
|
zc_update = 1;
|
||||||
}
|
}
|
||||||
if(__CheckSimpleParamU16(&zc_debounce, PARAM_INTERNAL.zc.DebouneCouner))
|
if(__CheckParamU16(&zc_debounce, PARAM_INTERNAL.zc.DebouneCouner))
|
||||||
{
|
{
|
||||||
zc_update = 1;
|
zc_update = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Параметры ШИМ токов
|
// Параметры ШИМ
|
||||||
if(__CheckSimpleParamU8(&pwm_phase_mask, PARAM_INTERNAL.pwm.PhaseMask, 1))
|
if(__CheckParamU8(&pwm_phase_mask, PARAM_INTERNAL.pwm.PhaseMask, 1))
|
||||||
{
|
{
|
||||||
pwm_update = 1;
|
pwm_update = 1;
|
||||||
}
|
}
|
||||||
if(__CheckSimpleParamU16(&pwm_freq, PARAM_INTERNAL.pwm.Frequency))
|
if(__CheckParamU16(&pwm_freq, PARAM_INTERNAL.pwm.Frequency))
|
||||||
{
|
{
|
||||||
pwm_update = 1;
|
pwm_update = 1;
|
||||||
}
|
}
|
||||||
if(__CheckSimpleParamU8(&pwm_pulse_num, PARAM_INTERNAL.pwm.PulseNumber, 1))
|
if(__CheckParamF(&pwm_duty, PARAM_INTERNAL.pwm.Duty, 100))
|
||||||
{
|
{
|
||||||
pwm_update = 1;
|
pwm_update = 1;
|
||||||
}
|
}
|
||||||
|
if(__CheckParamF(&pwm_pulse_len, PARAM_INTERNAL.pwm.PulseLength, 65535))
|
||||||
|
{
|
||||||
|
pwm_update = 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Параметры мониторинга
|
// Параметры мониторинга
|
||||||
if(__CheckSimpleParamF(&pm_alpha, PARAM_INTERNAL.pm.mean_alpha, 65535))
|
if(__CheckParamU16(&pm_rms_widnow_size, PARAM_INTERNAL.pm.rms_window_size))
|
||||||
{
|
{
|
||||||
for(int i = 0; i < EXP_ALL; i++)
|
for(int i = 0; i < RMS_ALL; i++)
|
||||||
{
|
{
|
||||||
Filter_ReInit(&upp.pm.exp[i], pm_alpha);
|
Filter_ReInit(&upp.pm.rms[i], pm_rms_widnow_size);
|
||||||
|
Filter_Start(&upp.pm.rms[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(__CheckParamF(&pm_rms_exp_alpha, PARAM_INTERNAL.pm.rms_exp_alpha, 65535))
|
||||||
|
{
|
||||||
|
for(int i = 0; i < RMS_EXP_ALL; i++)
|
||||||
|
{
|
||||||
|
Filter_ReInit(&upp.pm.rms_exp[i], pm_rms_exp_alpha);
|
||||||
|
Filter_Start(&upp.pm.rms_exp[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Обновление регулятора угла открытия
|
// Обновление регулятора угла открытия
|
||||||
|
__AngleSetLimit();
|
||||||
if(alpha_update)
|
if(alpha_update)
|
||||||
{
|
{
|
||||||
Angle_SetRange(&upp.hangle, angle_min, angle_max);
|
if(Angle_SetRange(&upp.hangle, angle_min, angle_max) == HAL_OK)
|
||||||
Angle_PID_Init(&upp.hangle, angle_pid_kp, angle_pid_ki, angle_pid_kd, angle_ref_alpha);
|
{
|
||||||
|
if(Angle_PID_Init(&upp.hangle, angle_pid_kp,
|
||||||
|
angle_pid_ki*((float)PM_SLOW_PERIOD_US/1000000),
|
||||||
|
angle_pid_kd,
|
||||||
|
upp.hangle.refFilter.alpha) == HAL_OK)
|
||||||
|
{
|
||||||
|
alpha_update = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ERR_PRIVATE_CNT.angle_reinit_err++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ERR_PRIVATE_CNT.angle_reinit_err++;
|
||||||
}
|
}
|
||||||
// Обновление АЦП конфигов
|
// Обновление АЦП конфигов
|
||||||
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
||||||
@@ -160,7 +261,7 @@ void UPP_Params_ControlInternal(void)
|
|||||||
// Обновление ШИМ конфигов
|
// Обновление ШИМ конфигов
|
||||||
if(pwm_update)
|
if(pwm_update)
|
||||||
{
|
{
|
||||||
if(PWM_SetConfig(&upp.hpwm, pwm_phase_mask, pwm_freq, pwm_pulse_num) == HAL_OK)
|
if(PWM_SetConfig(&upp.hpwm, pwm_phase_mask, pwm_freq, pwm_duty, pwm_pulse_len) == HAL_OK)
|
||||||
{
|
{
|
||||||
pwm_update = 0;
|
pwm_update = 0;
|
||||||
}
|
}
|
||||||
@@ -172,12 +273,134 @@ void UPP_Params_ControlInternal(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Инициализация параметров УПП.
|
||||||
|
* @return HAL Status.
|
||||||
|
*/
|
||||||
|
HAL_StatusTypeDef UPP_Params_Init(void)
|
||||||
|
{
|
||||||
|
/*====== ИНИЦИАЛИЗАЦИЯ МОДУЛЯ angle_control ======*/
|
||||||
|
// Инициализация ПИД
|
||||||
|
if(Angle_PID_Init(&upp.hangle,
|
||||||
|
u2f(PARAM_INTERNAL.angle.PID_Kp, 10000),
|
||||||
|
u2f(PARAM_INTERNAL.angle.PID_Ki, 10000)*((float)PM_SLOW_PERIOD_US/1000000),
|
||||||
|
u2f(PARAM_INTERNAL.angle.PID_Kd, 10000),
|
||||||
|
PUI_Tnt_CalcAlpha(u2f(PARAM_PUI.Tnt, 1000), PM_SLOW_PERIOD_US)) != HAL_OK)
|
||||||
|
return HAL_ERROR;
|
||||||
|
|
||||||
|
// Инициализация углов
|
||||||
|
if(Angle_SetRange(&upp.hangle,
|
||||||
|
u2f(PARAM_INTERNAL.angle.Angle_Min, 65535),
|
||||||
|
u2f(PARAM_INTERNAL.angle.Angle_Max, 65535)) != HAL_OK)
|
||||||
|
return HAL_ERROR;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*===== ИНИЦИАЛИЗАЦИЯ МОДУЛЯ power_monitor ======*/
|
||||||
|
/* Инициализация каналов АЦП */
|
||||||
|
if(ADC_ConfigChannel(&upp.pm.adc, ADC_CHANNEL_UBA,
|
||||||
|
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_UBA],
|
||||||
|
u2f(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_UBA], 10),
|
||||||
|
4095) != HAL_OK)
|
||||||
|
return HAL_ERROR;
|
||||||
|
|
||||||
|
if(ADC_ConfigChannel(&upp.pm.adc, ADC_CHANNEL_UAC,
|
||||||
|
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_UAC],
|
||||||
|
u2f(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_UAC], 10),
|
||||||
|
4095) != HAL_OK)
|
||||||
|
return HAL_ERROR;
|
||||||
|
|
||||||
|
if(ADC_ConfigChannel(&upp.pm.adc, ADC_CHANNEL_IC,
|
||||||
|
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_IC],
|
||||||
|
u2f(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_IC], 10),
|
||||||
|
4095) != HAL_OK)
|
||||||
|
return HAL_ERROR;
|
||||||
|
|
||||||
|
if(ADC_ConfigChannel(&upp.pm.adc, ADC_CHANNEL_IA,
|
||||||
|
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_IA],
|
||||||
|
u2f(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_IA], 10),
|
||||||
|
4095) != HAL_OK)
|
||||||
|
return HAL_ERROR;
|
||||||
|
|
||||||
|
|
||||||
|
/* Инициализация алгоритма перехода через ноль */
|
||||||
|
if(ZC_Init(&upp.pm.zc, 3, u2f(PARAM_INTERNAL.zc.Hysteresis, 100), PARAM_INTERNAL.zc.DebouneCouner) != HAL_OK)
|
||||||
|
return HAL_ERROR;
|
||||||
|
|
||||||
|
|
||||||
|
/* Инициализация RMS фильтра медленного алга */
|
||||||
|
for(int i = 0; i < RMS_ALL; i++)
|
||||||
|
{
|
||||||
|
if(FilterRMS_Init(&upp.pm.rms[i], PARAM_INTERNAL.pm.rms_window_size))
|
||||||
|
return HAL_ERROR;
|
||||||
|
Filter_Start(&upp.pm.rms[i]);
|
||||||
|
}
|
||||||
|
/* Инициализация экпоненциального фильтра медленного алга */
|
||||||
|
for(int i = 0; i < RMS_EXP_ALL; i++)
|
||||||
|
{
|
||||||
|
if(FilterExp_Init(&upp.pm.rms_exp[i], u2f(PARAM_INTERNAL.pm.rms_exp_alpha, 65535)))
|
||||||
|
return HAL_ERROR;
|
||||||
|
Filter_Start(&upp.pm.rms_exp[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*====== ИНИЦИАЛИЗАЦИЯ МОДУЛЯ pwm_thyristors ======*/
|
||||||
|
if(PWM_SetConfig(&upp.hpwm, PARAM_INTERNAL.pwm.PhaseMask,
|
||||||
|
PARAM_INTERNAL.pwm.Frequency,
|
||||||
|
u2f(PARAM_INTERNAL.pwm.Duty, 100),
|
||||||
|
PARAM_INTERNAL.pwm.PulseLength) != HAL_OK)
|
||||||
|
return HAL_ERROR;
|
||||||
|
|
||||||
|
return HAL_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Контроль параметров УПП на корректные значения.
|
* @brief Контроль параметров УПП на корректные значения.
|
||||||
* @return HAL Status.
|
* @return HAL Status.
|
||||||
*/
|
*/
|
||||||
void UPP_Params_Saturate(void)
|
void UPP_Params_Saturate(void)
|
||||||
{
|
{
|
||||||
|
SATURATE_U16(PARAM_PUI.Iref, 100, 500);
|
||||||
|
// SATURATE_U16(PARAM_PUI.Tnt, 50, 5000);
|
||||||
|
SATURATE_U16(PARAM_PUI.Umin, 5, 99);
|
||||||
|
SATURATE_U16(PARAM_PUI.Umax, 100, 120);
|
||||||
|
SATURATE_U16(PARAM_PUI.Imax, 5, 99);
|
||||||
|
SATURATE_U16(PARAM_PUI.Imin, 0, 40);
|
||||||
|
SATURATE_U16(PARAM_PUI.TiMax, 500, 10000);
|
||||||
|
SATURATE_U16(PARAM_PUI.Tdelay, 5, 60);
|
||||||
|
SATURATE_U16(PARAM_PUI.Interlace, 0, 1);
|
||||||
|
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.setpoints.TemperatureWarn, 0, 90);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.setpoints.TemperatureErr, 0, 90);
|
||||||
|
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.nominal.PhaseNumber, 0, 3);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.nominal.U, 0, ADC_U_MAX_V_DEFAULT*10);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.nominal.U_deviation_plus, 0, 100*100);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.nominal.U_deviation_minus, 0, 100*100);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.nominal.F, 40*100, 60*100);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.nominal.F_deviation_plus, 0, 100*100);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.nominal.F_deviation_minus, 0, 100*100);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.nominal.I, 0, ADC_I_MAX_A_DEFAULT*10);
|
||||||
|
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_UBA], 0, 5000*10);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_UAC], 0, 5000*10);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_IC], 0, 1000*10);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_IA], 0, 1000*10);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_UBA], 1848, 2248);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_UAC], 1848, 2248);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_IC], 1848, 2248);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_IA], 1848, 2248);
|
||||||
|
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.pwm.PhaseMask, 0, 7);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.pwm.Frequency, 1000, 40000);
|
||||||
|
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.zc.Hysteresis, 0, 0.1*100);
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.zc.DebouneCouner, 0, 1000);
|
||||||
|
|
||||||
|
|
||||||
|
SATURATE_U16(PARAM_INTERNAL.angle.PulseLengthReserve, 50, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,7 +438,8 @@ void UPP_Params_SetDefault(int pui_default, int internal_default)
|
|||||||
PARAM_INTERNAL.nominal.F_deviation_minus = NOM_F_DEVIATION_MINUS_PERCENT_DEFAULT*100;
|
PARAM_INTERNAL.nominal.F_deviation_minus = NOM_F_DEVIATION_MINUS_PERCENT_DEFAULT*100;
|
||||||
PARAM_INTERNAL.nominal.I = NOM_I_A_DEFAULT*10;
|
PARAM_INTERNAL.nominal.I = NOM_I_A_DEFAULT*10;
|
||||||
|
|
||||||
PARAM_INTERNAL.pm.mean_alpha = CALC_TAU_COEF(PM_EXP_TAU_COEF_DEFAULT,PM_SLOW_PERIOD_US)*65535;
|
PARAM_INTERNAL.pm.rms_window_size = PM_RMS_WINDOW_PERIOD_US_DEFAULT/PM_SLOW_PERIOD_US;
|
||||||
|
PARAM_INTERNAL.pm.rms_exp_alpha = FilterExp_CalcAlpha98(PM_RMS_EXT_TAU_US_DEFAULT, PM_SLOW_PERIOD_US)*65535;
|
||||||
|
|
||||||
PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_UBA] = ADC_U_MAX_V_DEFAULT*10;
|
PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_UBA] = ADC_U_MAX_V_DEFAULT*10;
|
||||||
PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_UAC] = ADC_U_MAX_V_DEFAULT*10;
|
PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_UAC] = ADC_U_MAX_V_DEFAULT*10;
|
||||||
@@ -226,9 +450,10 @@ void UPP_Params_SetDefault(int pui_default, int internal_default)
|
|||||||
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_IC] = ADC_I_ZERO_DEFAULT;
|
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_IC] = ADC_I_ZERO_DEFAULT;
|
||||||
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_IA] = ADC_I_ZERO_DEFAULT;
|
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_IA] = ADC_I_ZERO_DEFAULT;
|
||||||
|
|
||||||
PARAM_INTERNAL.pwm.PhaseMask = 1; // (все три фазы)
|
PARAM_INTERNAL.pwm.PhaseMask = 7; // (все три фазы)
|
||||||
PARAM_INTERNAL.pwm.Frequency = (float)PWM_THYR_FREQUENCY_HZ_DEFAULT;
|
PARAM_INTERNAL.pwm.Frequency = PWM_THYR_FREQUENCY_HZ_DEFAULT;
|
||||||
PARAM_INTERNAL.pwm.PulseNumber = PWM_THYR_PULSE_NUMBER_DEFAULT;
|
PARAM_INTERNAL.pwm.Duty = PWM_THYR_DUTY_PERCENT_DEFAULT*100;
|
||||||
|
PARAM_INTERNAL.pwm.PulseLength = PWM_THYR_PULSE_LENGTH_DEFAULT*65535;
|
||||||
|
|
||||||
PARAM_INTERNAL.zc.Hysteresis = ZERO_CROSS_HYSTERESIS_PERCENT_DEFAULT*100;
|
PARAM_INTERNAL.zc.Hysteresis = ZERO_CROSS_HYSTERESIS_PERCENT_DEFAULT*100;
|
||||||
PARAM_INTERNAL.zc.DebouneCouner = ZERO_CROSS_DEBOUNCE_CNT_DEFAULT;
|
PARAM_INTERNAL.zc.DebouneCouner = ZERO_CROSS_DEBOUNCE_CNT_DEFAULT;
|
||||||
@@ -237,7 +462,6 @@ void UPP_Params_SetDefault(int pui_default, int internal_default)
|
|||||||
PARAM_INTERNAL.angle.PID_Kp = ANGLE_PID_KP_COEF_DEFAULT*10000;
|
PARAM_INTERNAL.angle.PID_Kp = ANGLE_PID_KP_COEF_DEFAULT*10000;
|
||||||
PARAM_INTERNAL.angle.PID_Ki = ANGLE_PID_KI_COEF_DEFAULT*10000;
|
PARAM_INTERNAL.angle.PID_Ki = ANGLE_PID_KI_COEF_DEFAULT*10000;
|
||||||
PARAM_INTERNAL.angle.PID_Kd = ANGLE_PID_KD_COEF_DEFAULT*10000;
|
PARAM_INTERNAL.angle.PID_Kd = ANGLE_PID_KD_COEF_DEFAULT*10000;
|
||||||
PARAM_INTERNAL.angle.PID_ExpAlpha = CALC_TAU_COEF(ANGLE_REF_TAU_COEF_DEFAULT,PM_SLOW_PERIOD_US)*65535;
|
|
||||||
PARAM_INTERNAL.angle.Angle_Max = ANGLE_MAX_PERCENT_DEFAULT*65535;
|
PARAM_INTERNAL.angle.Angle_Max = ANGLE_MAX_PERCENT_DEFAULT*65535;
|
||||||
PARAM_INTERNAL.angle.Angle_Min = ANGLE_MIN_PERCENT_DEFAULT*65535;
|
PARAM_INTERNAL.angle.Angle_Min = ANGLE_MIN_PERCENT_DEFAULT*65535;
|
||||||
PARAM_INTERNAL.angle.PulseLengthReserve = ANGLE_PULSE_LENGTH_RESERVE_PERCENT_DEFAULT*100;
|
PARAM_INTERNAL.angle.PulseLengthReserve = ANGLE_PULSE_LENGTH_RESERVE_PERCENT_DEFAULT*100;
|
||||||
@@ -246,14 +470,15 @@ void UPP_Params_SetDefault(int pui_default, int internal_default)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define ANGLE_PERIOD_MS(_freq_) (((float)1/(_freq_*2))*1000)
|
||||||
|
|
||||||
// Перерасчет максимально допустимого угла
|
// Перерасчет максимально допустимого угла
|
||||||
static void __AngleSetLimit(void)
|
static void __AngleSetLimit(void)
|
||||||
{ // Сколько пачка ипульсов занимает процентов от всего периода
|
{ // Сколько пачка ипульсов занимает процентов от всего периода
|
||||||
float pulses_percent_of_period = (((float)PARAM_INTERNAL.pwm.PulseNumber / PARAM_INTERNAL.pwm.Frequency) * 1000) / ANGLE_PERIOD_MS(upp.pm.measured.final.Fmean);
|
float pulses_percent_of_period = (((float)PARAM_INTERNAL.pwm.PulseLength / PARAM_INTERNAL.pwm.Frequency) * 1000) / ANGLE_PERIOD_MS(upp.pm.measured.final.Fmean);
|
||||||
// Вычитаем этот процент из 1 - получаем максимально безопасный угол
|
// Вычитаем этот процент из 1 - получаем максимально безопасный угол
|
||||||
float angle_limit = 1 - pulses_percent_of_period;
|
float angle_limit = 1;
|
||||||
angle_limit -= pulses_percent_of_period*to_float(PARAM_INTERNAL.angle.PulseLengthReserve, 100); // добавляем запас в PulseLengthReserve процентов от пачки импульсов
|
angle_limit -= pulses_percent_of_period*u2f(PARAM_INTERNAL.angle.PulseLengthReserve, 100); // добавляем запас в PulseLengthReserve процентов от пачки импульсов
|
||||||
Angle_SetLimit(&upp.hangle, angle_limit);
|
Angle_SetLimit(&upp.hangle, angle_limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +491,7 @@ static void __AngleSetLimit(void)
|
|||||||
* @param Coef Коэффициент для приведения float к uint16_t: uint16_t = float*coef, float = uint16_t/coef
|
* @param Coef Коэффициент для приведения float к uint16_t: uint16_t = float*coef, float = uint16_t/coef
|
||||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||||
*/
|
*/
|
||||||
static int __CheckSimpleParamF(float *paramDist, uint16_t paramSrc, float Coef)
|
static int __CheckParamF(float *paramDist, uint16_t paramSrc, float Coef)
|
||||||
{
|
{
|
||||||
if(paramDist == NULL)
|
if(paramDist == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -289,7 +514,7 @@ static int __CheckSimpleParamF(float *paramDist, uint16_t paramSrc, float Coef)
|
|||||||
* @param Coef Коэффициент для приведения uint32_t к uint16_t: uint16_t = uint32_t*coef, uint32_t = uint16_t/coef
|
* @param Coef Коэффициент для приведения uint32_t к uint16_t: uint16_t = uint32_t*coef, uint32_t = uint16_t/coef
|
||||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||||
*/
|
*/
|
||||||
static int __CheckSimpleParamU32(uint32_t *paramDist, uint16_t paramSrc, float Coef)
|
static int __CheckParamU32(uint32_t *paramDist, uint16_t paramSrc, float Coef)
|
||||||
{
|
{
|
||||||
if(paramDist == NULL)
|
if(paramDist == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -311,7 +536,7 @@ static int __CheckSimpleParamU32(uint32_t *paramDist, uint16_t paramSrc, float C
|
|||||||
* @param paramSrc Значение для сравнения с uint16_t параметром
|
* @param paramSrc Значение для сравнения с uint16_t параметром
|
||||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||||
*/
|
*/
|
||||||
static int __CheckSimpleParamU16(uint16_t *paramDist, uint16_t paramSrc)
|
static int __CheckParamU16(uint16_t *paramDist, uint16_t paramSrc)
|
||||||
{
|
{
|
||||||
if(paramDist == NULL)
|
if(paramDist == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -335,7 +560,7 @@ static int __CheckSimpleParamU16(uint16_t *paramDist, uint16_t paramSrc)
|
|||||||
* @param Coef Коэффициент для приведения uint32_t к uint16_t: uint16_t = uint8_t*coef, uint8_t = uint16_t/coef
|
* @param Coef Коэффициент для приведения uint32_t к uint16_t: uint16_t = uint8_t*coef, uint8_t = uint16_t/coef
|
||||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||||
*/
|
*/
|
||||||
static int __CheckSimpleParamU8(uint8_t *paramDist, uint16_t paramSrc, float Coef)
|
static int __CheckParamU8(uint8_t *paramDist, uint16_t paramSrc, float Coef)
|
||||||
{
|
{
|
||||||
if(paramDist == NULL)
|
if(paramDist == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#define _UPP_PARAMS_H
|
#define _UPP_PARAMS_H
|
||||||
#include "upp_defs.h"
|
#include "upp_defs.h"
|
||||||
|
|
||||||
#define to_float(_u16_, _coef_) ((float)_u16_/_coef_)
|
#define u2f(_u16_, _coef_) ((float)_u16_/_coef_)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@@ -49,7 +49,8 @@ typedef struct
|
|||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint16_t mean_alpha; ///< Коэф альфа для усредняющего эксп. фильтра [0..1 x 65535]
|
uint16_t rms_window_size; ///< Размер окна для RMS
|
||||||
|
uint16_t rms_exp_alpha; ///< Постоянная времени для сглаживания RMS
|
||||||
}pm;
|
}pm;
|
||||||
|
|
||||||
UPP_ParamsNominal_t nominal;
|
UPP_ParamsNominal_t nominal;
|
||||||
@@ -65,9 +66,10 @@ typedef struct
|
|||||||
/* Параметры ШИМ */
|
/* Параметры ШИМ */
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint16_t PhaseMask; ///< Битовяя маска на какие фазы подавать ШИМ: 0 бит - a, 1 бит - b, 2 бит - c
|
uint16_t PhaseMask; ///< Битовяя маска на какие фазы подавать ШИМ: 0 бит - a, 1 бит - b, 2 бит - c
|
||||||
uint16_t Frequency; ///< Частота ШИМ для пачки импульсов на тиристоры [Герцы]
|
uint16_t Frequency; ///< Частота ШИМ для пачки импульсов на тиристоры [Герцы]
|
||||||
uint16_t PulseNumber; ///< Количесво импульсов в пачке [Количество]
|
uint16_t Duty; ///< Скважность ШИМ для пачки импульсов на тиристоры [Проценты]
|
||||||
|
uint16_t PulseLength; ///< Количесво импульсов в пачке [Количество]
|
||||||
}pwm;
|
}pwm;
|
||||||
|
|
||||||
/* Параметры Угла */
|
/* Параметры Угла */
|
||||||
@@ -87,16 +89,22 @@ typedef struct
|
|||||||
uint16_t PID_Kp; ///< Пропорциональный коэфициент ПИ регулятора угла [x 10000]
|
uint16_t PID_Kp; ///< Пропорциональный коэфициент ПИ регулятора угла [x 10000]
|
||||||
uint16_t PID_Ki; ///< Интегральный коэфициент ПИ регулятора угла [x 10000]
|
uint16_t PID_Ki; ///< Интегральный коэфициент ПИ регулятора угла [x 10000]
|
||||||
uint16_t PID_Kd; ///< Интегральный коэфициент ПИ регулятора угла [x 10000]
|
uint16_t PID_Kd; ///< Интегральный коэфициент ПИ регулятора угла [x 10000]
|
||||||
uint16_t PID_ExpAlpha; ///< Коэффициент сглаживающего фильтра задания регулятора [0..1 x 65535]
|
|
||||||
}angle;
|
}angle;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}UPP_PrvtParams_t;
|
}UPP_PrvtParams_t;
|
||||||
|
|
||||||
|
/* Контроль параметров УПП. */
|
||||||
|
void UPP_Params_Control(void);
|
||||||
|
/* Контроль параметров от ПУИ. */
|
||||||
|
void UPP_Params_ControlPUI(void);
|
||||||
/* Контроль внутренних параметров УПП. */
|
/* Контроль внутренних параметров УПП. */
|
||||||
void UPP_Params_ControlInternal(void);
|
void UPP_Params_ControlInternal(void);
|
||||||
|
/* Инициализация параметров УПП. */
|
||||||
|
HAL_StatusTypeDef UPP_Params_Init(void);
|
||||||
|
/* Контроль параметров УПП на корректные значения. */
|
||||||
|
void UPP_Params_Saturate(void);
|
||||||
/* Установка параметров на дефолтные значения */
|
/* Установка параметров на дефолтные значения */
|
||||||
void UPP_Params_SetDefault(int pui_default, int internal_default);
|
void UPP_Params_SetDefault(int pui_default, int internal_default);
|
||||||
|
|
||||||
|
|||||||
@@ -322,59 +322,10 @@
|
|||||||
<SetRegEntry>
|
<SetRegEntry>
|
||||||
<Number>0</Number>
|
<Number>0</Number>
|
||||||
<Key>ST-LINKIII-KEIL_SWO</Key>
|
<Key>ST-LINKIII-KEIL_SWO</Key>
|
||||||
<Name>-U005600373433510237363934 -O206 -SF10000 -C0 -A0 -I0 -HNlocalhost -HP7184 -P1 -N00("ARM CoreSight SW-DP (ARM Core") -D00(2BA01477) -L00(0) -TO131123 -TC168000000 -TT10000000 -TP21 -TDS800D -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC1000 -FN1 -FF0STM32F4xx_1024.FLM -FS08000000 -FL0100000 -FP0($$Device:STM32F417ZGTx$CMSIS\Flash\STM32F4xx_1024.FLM) -WA0 -WE0 -WVCE4 -WS2710 -WM0 -WP2</Name>
|
<Name>-U005600373433510237363934 -O206 -SF10000 -C0 -A0 -I0 -HNlocalhost -HP7184 -P1 -N00("ARM CoreSight SW-DP (ARM Core") -D00(2BA01477) -L00(0) -TO131123 -TC168000000 -TT10000000 -TP21 -TDS800D -TDT1 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC1000 -FN1 -FF0STM32F4xx_1024.FLM -FS08000000 -FL0100000 -FP0($$Device:STM32F417ZGTx$CMSIS\Flash\STM32F4xx_1024.FLM) -WA0 -WE0 -WVCE4 -WS2710 -WM0 -WP2</Name>
|
||||||
</SetRegEntry>
|
</SetRegEntry>
|
||||||
</TargetDriverDllRegistry>
|
</TargetDriverDllRegistry>
|
||||||
<Breakpoint>
|
<Breakpoint/>
|
||||||
<Bp>
|
|
||||||
<Number>0</Number>
|
|
||||||
<Type>0</Type>
|
|
||||||
<LineNumber>407</LineNumber>
|
|
||||||
<EnabledFlag>1</EnabledFlag>
|
|
||||||
<Address>134233766</Address>
|
|
||||||
<ByteObject>0</ByteObject>
|
|
||||||
<HtxType>0</HtxType>
|
|
||||||
<ManyObjects>0</ManyObjects>
|
|
||||||
<SizeOfObject>0</SizeOfObject>
|
|
||||||
<BreakByAccess>0</BreakByAccess>
|
|
||||||
<BreakIfRCount>1</BreakIfRCount>
|
|
||||||
<Filename>../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c</Filename>
|
|
||||||
<ExecCommand></ExecCommand>
|
|
||||||
<Expression>\\Debug_F417\../Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c\407</Expression>
|
|
||||||
</Bp>
|
|
||||||
<Bp>
|
|
||||||
<Number>1</Number>
|
|
||||||
<Type>0</Type>
|
|
||||||
<LineNumber>136</LineNumber>
|
|
||||||
<EnabledFlag>1</EnabledFlag>
|
|
||||||
<Address>134256316</Address>
|
|
||||||
<ByteObject>0</ByteObject>
|
|
||||||
<HtxType>0</HtxType>
|
|
||||||
<ManyObjects>0</ManyObjects>
|
|
||||||
<SizeOfObject>0</SizeOfObject>
|
|
||||||
<BreakByAccess>0</BreakByAccess>
|
|
||||||
<BreakIfRCount>1</BreakIfRCount>
|
|
||||||
<Filename>../Core/Src/stm32f4xx_it.c</Filename>
|
|
||||||
<ExecCommand></ExecCommand>
|
|
||||||
<Expression>\\Debug_F417\../Core/Src/stm32f4xx_it.c\136</Expression>
|
|
||||||
</Bp>
|
|
||||||
<Bp>
|
|
||||||
<Number>2</Number>
|
|
||||||
<Type>0</Type>
|
|
||||||
<LineNumber>27</LineNumber>
|
|
||||||
<EnabledFlag>1</EnabledFlag>
|
|
||||||
<Address>0</Address>
|
|
||||||
<ByteObject>0</ByteObject>
|
|
||||||
<HtxType>0</HtxType>
|
|
||||||
<ManyObjects>0</ManyObjects>
|
|
||||||
<SizeOfObject>0</SizeOfObject>
|
|
||||||
<BreakByAccess>0</BreakByAccess>
|
|
||||||
<BreakIfRCount>0</BreakIfRCount>
|
|
||||||
<Filename>.\startup_stm32f417xx.s</Filename>
|
|
||||||
<ExecCommand></ExecCommand>
|
|
||||||
<Expression></Expression>
|
|
||||||
</Bp>
|
|
||||||
</Breakpoint>
|
|
||||||
<WatchWindow1>
|
<WatchWindow1>
|
||||||
<Ww>
|
<Ww>
|
||||||
<count>0</count>
|
<count>0</count>
|
||||||
@@ -404,12 +355,12 @@
|
|||||||
<Ww>
|
<Ww>
|
||||||
<count>5</count>
|
<count>5</count>
|
||||||
<WinNumber>1</WinNumber>
|
<WinNumber>1</WinNumber>
|
||||||
<ItemText>hbt,0x0A</ItemText>
|
<ItemText>upp.pm.measured</ItemText>
|
||||||
</Ww>
|
</Ww>
|
||||||
<Ww>
|
<Ww>
|
||||||
<count>6</count>
|
<count>6</count>
|
||||||
<WinNumber>1</WinNumber>
|
<WinNumber>1</WinNumber>
|
||||||
<ItemText>sysclockfreq,0x0A</ItemText>
|
<ItemText>hbt,0x0A</ItemText>
|
||||||
</Ww>
|
</Ww>
|
||||||
<Ww>
|
<Ww>
|
||||||
<count>7</count>
|
<count>7</count>
|
||||||
@@ -434,7 +385,7 @@
|
|||||||
<Ww>
|
<Ww>
|
||||||
<count>11</count>
|
<count>11</count>
|
||||||
<WinNumber>1</WinNumber>
|
<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>
|
||||||
<Ww>
|
<Ww>
|
||||||
<count>12</count>
|
<count>12</count>
|
||||||
@@ -456,6 +407,21 @@
|
|||||||
<WinNumber>1</WinNumber>
|
<WinNumber>1</WinNumber>
|
||||||
<ItemText>\\Debug_F417\../Core/UPP/upp_io.c\UPP_DIN.Pusk.Sw_FilterDelay</ItemText>
|
<ItemText>\\Debug_F417\../Core/UPP/upp_io.c\UPP_DIN.Pusk.Sw_FilterDelay</ItemText>
|
||||||
</Ww>
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>16</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>hadc3</ItemText>
|
||||||
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>17</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>upp.hangle.Iref</ItemText>
|
||||||
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>18</count>
|
||||||
|
<WinNumber>1</WinNumber>
|
||||||
|
<ItemText>upp.pm.measured.final.U[0]</ItemText>
|
||||||
|
</Ww>
|
||||||
</WatchWindow1>
|
</WatchWindow1>
|
||||||
<WatchWindow2>
|
<WatchWindow2>
|
||||||
<Ww>
|
<Ww>
|
||||||
@@ -466,7 +432,7 @@
|
|||||||
<Ww>
|
<Ww>
|
||||||
<count>1</count>
|
<count>1</count>
|
||||||
<WinNumber>2</WinNumber>
|
<WinNumber>2</WinNumber>
|
||||||
<ItemText>MB_DATA</ItemText>
|
<ItemText>MB_DATA,0x0A</ItemText>
|
||||||
</Ww>
|
</Ww>
|
||||||
<Ww>
|
<Ww>
|
||||||
<count>2</count>
|
<count>2</count>
|
||||||
@@ -523,6 +489,26 @@
|
|||||||
<WinNumber>2</WinNumber>
|
<WinNumber>2</WinNumber>
|
||||||
<ItemText>upp.pm.measured.slow.U[0]</ItemText>
|
<ItemText>upp.pm.measured.slow.U[0]</ItemText>
|
||||||
</Ww>
|
</Ww>
|
||||||
|
<Ww>
|
||||||
|
<count>13</count>
|
||||||
|
<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->CNT-2605346416,0x0A</ItemText>
|
||||||
|
</Ww>
|
||||||
</WatchWindow2>
|
</WatchWindow2>
|
||||||
<Tracepoint>
|
<Tracepoint>
|
||||||
<THDelay>0</THDelay>
|
<THDelay>0</THDelay>
|
||||||
@@ -569,37 +555,17 @@
|
|||||||
<LogicAnalyzers>
|
<LogicAnalyzers>
|
||||||
<Wi>
|
<Wi>
|
||||||
<IntNumber>0</IntNumber>
|
<IntNumber>0</IntNumber>
|
||||||
<FirstString>`upp.pm.zc.Channel[0].HalfWave</FirstString>
|
<FirstString>`upp.pm.measured.final.U[0]</FirstString>
|
||||||
<SecondString>0000000000000000000000000000000000000040000000000000000000000000000000007570702E706D2E7A632E4368616E6E656C5B305D2E48616C66576176650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000001000000000000000000F03F1400000000000000000000000000000000000000FC9E0008</SecondString>
|
<SecondString>008000000000000000000000000000000000F03F000000000000000000000000000000007570702E706D2E6D656173757265642E66696E616C2E555B305D0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000700000001000000000000000000F03F140000000000000000000000000000000000000020B20008</SecondString>
|
||||||
</Wi>
|
</Wi>
|
||||||
</LogicAnalyzers>
|
</LogicAnalyzers>
|
||||||
<SystemViewers>
|
<SystemViewers>
|
||||||
<Entry>
|
<Entry>
|
||||||
<Name>System Viewer\DBG</Name>
|
<Name>System Viewer\ADC3</Name>
|
||||||
<WinId>35902</WinId>
|
|
||||||
</Entry>
|
|
||||||
<Entry>
|
|
||||||
<Name>System Viewer\GPIOG</Name>
|
|
||||||
<WinId>35899</WinId>
|
|
||||||
</Entry>
|
|
||||||
<Entry>
|
|
||||||
<Name>System Viewer\TIM1</Name>
|
|
||||||
<WinId>35901</WinId>
|
|
||||||
</Entry>
|
|
||||||
<Entry>
|
|
||||||
<Name>System Viewer\TIM14</Name>
|
|
||||||
<WinId>35903</WinId>
|
|
||||||
</Entry>
|
|
||||||
<Entry>
|
|
||||||
<Name>System Viewer\TIM2</Name>
|
|
||||||
<WinId>35900</WinId>
|
|
||||||
</Entry>
|
|
||||||
<Entry>
|
|
||||||
<Name>System Viewer\TIM5</Name>
|
|
||||||
<WinId>35905</WinId>
|
<WinId>35905</WinId>
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry>
|
<Entry>
|
||||||
<Name>System Viewer\TIM8</Name>
|
<Name>System Viewer\DMA2</Name>
|
||||||
<WinId>35904</WinId>
|
<WinId>35904</WinId>
|
||||||
</Entry>
|
</Entry>
|
||||||
</SystemViewers>
|
</SystemViewers>
|
||||||
@@ -1223,7 +1189,7 @@
|
|||||||
|
|
||||||
<Group>
|
<Group>
|
||||||
<GroupName>MyLibs</GroupName>
|
<GroupName>MyLibs</GroupName>
|
||||||
<tvExp>0</tvExp>
|
<tvExp>1</tvExp>
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
<cbSel>0</cbSel>
|
<cbSel>0</cbSel>
|
||||||
<RteFlg>0</RteFlg>
|
<RteFlg>0</RteFlg>
|
||||||
@@ -1511,7 +1477,7 @@
|
|||||||
|
|
||||||
<Group>
|
<Group>
|
||||||
<GroupName>PeriphGeneral</GroupName>
|
<GroupName>PeriphGeneral</GroupName>
|
||||||
<tvExp>1</tvExp>
|
<tvExp>0</tvExp>
|
||||||
<tvExpOptDlg>0</tvExpOptDlg>
|
<tvExpOptDlg>0</tvExpOptDlg>
|
||||||
<cbSel>0</cbSel>
|
<cbSel>0</cbSel>
|
||||||
<RteFlg>0</RteFlg>
|
<RteFlg>0</RteFlg>
|
||||||
|
|||||||
@@ -1122,11 +1122,11 @@
|
|||||||
<RunIndependent>0</RunIndependent>
|
<RunIndependent>0</RunIndependent>
|
||||||
<UpdateFlashBeforeDebugging>1</UpdateFlashBeforeDebugging>
|
<UpdateFlashBeforeDebugging>1</UpdateFlashBeforeDebugging>
|
||||||
<Capability>1</Capability>
|
<Capability>1</Capability>
|
||||||
<DriverSelection>4101</DriverSelection>
|
<DriverSelection>4096</DriverSelection>
|
||||||
</Flash1>
|
</Flash1>
|
||||||
<bUseTDR>1</bUseTDR>
|
<bUseTDR>1</bUseTDR>
|
||||||
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
<Flash2>BIN\UL2CM3.DLL</Flash2>
|
||||||
<Flash3></Flash3>
|
<Flash3>"" ()</Flash3>
|
||||||
<Flash4></Flash4>
|
<Flash4></Flash4>
|
||||||
<pFcarmOut></pFcarmOut>
|
<pFcarmOut></pFcarmOut>
|
||||||
<pFcarmGrp></pFcarmGrp>
|
<pFcarmGrp></pFcarmGrp>
|
||||||
@@ -1506,6 +1506,57 @@
|
|||||||
<FileName>power_monitor.c</FileName>
|
<FileName>power_monitor.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\Core\PowerMonitor\power_monitor.c</FilePath>
|
<FilePath>..\Core\PowerMonitor\power_monitor.c</FilePath>
|
||||||
|
<FileOption>
|
||||||
|
<CommonProperty>
|
||||||
|
<UseCPPCompiler>2</UseCPPCompiler>
|
||||||
|
<RVCTCodeConst>0</RVCTCodeConst>
|
||||||
|
<RVCTZI>0</RVCTZI>
|
||||||
|
<RVCTOtherData>0</RVCTOtherData>
|
||||||
|
<ModuleSelection>0</ModuleSelection>
|
||||||
|
<IncludeInBuild>2</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>5</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>
|
||||||
<File>
|
<File>
|
||||||
<FileName>power_monitor.h</FileName>
|
<FileName>power_monitor.h</FileName>
|
||||||
@@ -1516,6 +1567,57 @@
|
|||||||
<FileName>zero_cross.c</FileName>
|
<FileName>zero_cross.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\Core\PowerMonitor\zero_cross.c</FilePath>
|
<FilePath>..\Core\PowerMonitor\zero_cross.c</FilePath>
|
||||||
|
<FileOption>
|
||||||
|
<CommonProperty>
|
||||||
|
<UseCPPCompiler>2</UseCPPCompiler>
|
||||||
|
<RVCTCodeConst>0</RVCTCodeConst>
|
||||||
|
<RVCTZI>0</RVCTZI>
|
||||||
|
<RVCTOtherData>0</RVCTOtherData>
|
||||||
|
<ModuleSelection>0</ModuleSelection>
|
||||||
|
<IncludeInBuild>2</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>5</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>
|
||||||
<File>
|
<File>
|
||||||
<FileName>zero_cross.h</FileName>
|
<FileName>zero_cross.h</FileName>
|
||||||
@@ -1526,6 +1628,57 @@
|
|||||||
<FileName>adc_tools.c</FileName>
|
<FileName>adc_tools.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\Core\PowerMonitor\adc_tools.c</FilePath>
|
<FilePath>..\Core\PowerMonitor\adc_tools.c</FilePath>
|
||||||
|
<FileOption>
|
||||||
|
<CommonProperty>
|
||||||
|
<UseCPPCompiler>2</UseCPPCompiler>
|
||||||
|
<RVCTCodeConst>0</RVCTCodeConst>
|
||||||
|
<RVCTZI>0</RVCTZI>
|
||||||
|
<RVCTOtherData>0</RVCTOtherData>
|
||||||
|
<ModuleSelection>0</ModuleSelection>
|
||||||
|
<IncludeInBuild>2</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>5</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>
|
||||||
<File>
|
<File>
|
||||||
<FileName>adc_tools.h</FileName>
|
<FileName>adc_tools.h</FileName>
|
||||||
@@ -1536,6 +1689,57 @@
|
|||||||
<FileName>phases_transform.c</FileName>
|
<FileName>phases_transform.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\Core\PowerMonitor\phases_transform.c</FilePath>
|
<FilePath>..\Core\PowerMonitor\phases_transform.c</FilePath>
|
||||||
|
<FileOption>
|
||||||
|
<CommonProperty>
|
||||||
|
<UseCPPCompiler>2</UseCPPCompiler>
|
||||||
|
<RVCTCodeConst>0</RVCTCodeConst>
|
||||||
|
<RVCTZI>0</RVCTZI>
|
||||||
|
<RVCTOtherData>0</RVCTOtherData>
|
||||||
|
<ModuleSelection>0</ModuleSelection>
|
||||||
|
<IncludeInBuild>2</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>5</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>
|
||||||
<File>
|
<File>
|
||||||
<FileName>phases_transform.h</FileName>
|
<FileName>phases_transform.h</FileName>
|
||||||
@@ -1666,6 +1870,57 @@
|
|||||||
<FileName>filters.c</FileName>
|
<FileName>filters.c</FileName>
|
||||||
<FileType>1</FileType>
|
<FileType>1</FileType>
|
||||||
<FilePath>..\AllLibs\MyLibs\MyLibs\Src\filters.c</FilePath>
|
<FilePath>..\AllLibs\MyLibs\MyLibs\Src\filters.c</FilePath>
|
||||||
|
<FileOption>
|
||||||
|
<CommonProperty>
|
||||||
|
<UseCPPCompiler>2</UseCPPCompiler>
|
||||||
|
<RVCTCodeConst>0</RVCTCodeConst>
|
||||||
|
<RVCTZI>0</RVCTZI>
|
||||||
|
<RVCTOtherData>0</RVCTOtherData>
|
||||||
|
<ModuleSelection>0</ModuleSelection>
|
||||||
|
<IncludeInBuild>2</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>5</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>
|
||||||
<File>
|
<File>
|
||||||
<FileName>filters.h</FileName>
|
<FileName>filters.h</FileName>
|
||||||
|
|||||||
23
UPP/UPP.ioc
23
UPP/UPP.ioc
@@ -136,14 +136,16 @@ Mcu.Pin61=VP_TIM2_VS_no_output2
|
|||||||
Mcu.Pin62=VP_TIM2_VS_no_output3
|
Mcu.Pin62=VP_TIM2_VS_no_output3
|
||||||
Mcu.Pin63=VP_TIM3_VS_ClockSourceINT
|
Mcu.Pin63=VP_TIM3_VS_ClockSourceINT
|
||||||
Mcu.Pin64=VP_TIM5_VS_ClockSourceINT
|
Mcu.Pin64=VP_TIM5_VS_ClockSourceINT
|
||||||
Mcu.Pin65=VP_TIM8_VS_ClockSourceINT
|
Mcu.Pin65=VP_TIM8_VS_ControllerModeTrigger
|
||||||
Mcu.Pin66=VP_TIM8_VS_OPM
|
Mcu.Pin66=VP_TIM8_VS_ClockSourceINT
|
||||||
Mcu.Pin67=VP_TIM11_VS_ClockSourceINT
|
Mcu.Pin67=VP_TIM8_VS_ClockSourceITR
|
||||||
Mcu.Pin68=VP_TIM12_VS_ClockSourceINT
|
Mcu.Pin68=VP_TIM8_VS_OPM
|
||||||
|
Mcu.Pin69=VP_TIM11_VS_ClockSourceINT
|
||||||
Mcu.Pin7=PC15/OSC32_OUT
|
Mcu.Pin7=PC15/OSC32_OUT
|
||||||
|
Mcu.Pin70=VP_TIM12_VS_ClockSourceINT
|
||||||
Mcu.Pin8=PF6
|
Mcu.Pin8=PF6
|
||||||
Mcu.Pin9=PF7
|
Mcu.Pin9=PF7
|
||||||
Mcu.PinsNb=69
|
Mcu.PinsNb=71
|
||||||
Mcu.ThirdPartyNb=0
|
Mcu.ThirdPartyNb=0
|
||||||
Mcu.UserConstants=angletim,htim2;mb_huart,huart3;mbdbg_htim,htim11;PWM_CHANNEL_1,TIM_CHANNEL_1;PWM_CHANNEL_2,TIM_CHANNEL_2;PWM_CHANNEL_3,TIM_CHANNEL_3;PWM_CHANNEL_4,TIM_CHANNEL_4;mem_hspi,hspi3;ANGLE_CHANNEL_2,TIM_CHANNEL_2;ANGLE_CHANNEL_3,TIM_CHANNEL_3;ANGLE_CHANNEL_1,TIM_CHANNEL_1;PWM_CHANNEL_5,TIM_CHANNEL_3;PWM_CHANNEL_6,TIM_CHANNEL_4;mb_htim,htim12;adc_tim,htim3;usTick,ustim.Instance->CNT;hpwm2,htim8;mb_dbg_huart,huart6;ustim,htim5;hpwm1,htim1
|
Mcu.UserConstants=angletim,htim2;mb_huart,huart3;mbdbg_htim,htim11;PWM_CHANNEL_1,TIM_CHANNEL_1;PWM_CHANNEL_2,TIM_CHANNEL_2;PWM_CHANNEL_3,TIM_CHANNEL_3;PWM_CHANNEL_4,TIM_CHANNEL_4;mem_hspi,hspi3;ANGLE_CHANNEL_2,TIM_CHANNEL_2;ANGLE_CHANNEL_3,TIM_CHANNEL_3;ANGLE_CHANNEL_1,TIM_CHANNEL_1;PWM_CHANNEL_5,TIM_CHANNEL_3;PWM_CHANNEL_6,TIM_CHANNEL_4;mb_htim,htim12;adc_tim,htim3;usTick,ustim.Instance->CNT;hpwm2,htim8;mb_dbg_huart,huart6;ustim,htim5;hpwm1,htim1
|
||||||
Mcu.UserName=STM32F427ZGTx
|
Mcu.UserName=STM32F427ZGTx
|
||||||
@@ -163,6 +165,7 @@ NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false
|
|||||||
NVIC.TIM1_UP_TIM10_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
|
NVIC.TIM1_UP_TIM10_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
|
||||||
NVIC.TIM2_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
|
NVIC.TIM2_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
|
||||||
NVIC.TIM8_TRG_COM_TIM14_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:true
|
NVIC.TIM8_TRG_COM_TIM14_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:true
|
||||||
|
NVIC.TIM8_UP_TIM13_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
|
||||||
NVIC.TimeBase=TIM8_TRG_COM_TIM14_IRQn
|
NVIC.TimeBase=TIM8_TRG_COM_TIM14_IRQn
|
||||||
NVIC.TimeBaseIP=TIM14
|
NVIC.TimeBaseIP=TIM14
|
||||||
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||||
@@ -473,7 +476,7 @@ TIM1.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
|||||||
TIM1.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
|
TIM1.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
|
||||||
TIM1.IPParameters=Prescaler,Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation4 CH4,Channel-PWM Generation3 CH3,TIM_MasterOutputTrigger,RepetitionCounter
|
TIM1.IPParameters=Prescaler,Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation4 CH4,Channel-PWM Generation3 CH3,TIM_MasterOutputTrigger,RepetitionCounter
|
||||||
TIM1.Prescaler=0
|
TIM1.Prescaler=0
|
||||||
TIM1.RepetitionCounter=20
|
TIM1.RepetitionCounter=0
|
||||||
TIM1.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE
|
TIM1.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE
|
||||||
TIM11.IPParameters=Prescaler
|
TIM11.IPParameters=Prescaler
|
||||||
TIM11.Prescaler=180-1
|
TIM11.Prescaler=180-1
|
||||||
@@ -488,7 +491,7 @@ TIM2.OCMode_2=TIM_OCMODE_TIMING
|
|||||||
TIM2.OCMode_3=TIM_OCMODE_TIMING
|
TIM2.OCMode_3=TIM_OCMODE_TIMING
|
||||||
TIM3.IPParameters=TIM_MasterSlaveMode,TIM_MasterOutputTrigger
|
TIM3.IPParameters=TIM_MasterSlaveMode,TIM_MasterOutputTrigger
|
||||||
TIM3.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE
|
TIM3.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE
|
||||||
TIM3.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_ENABLE
|
TIM3.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE
|
||||||
TIM5.IPParameters=Prescaler
|
TIM5.IPParameters=Prescaler
|
||||||
TIM5.Prescaler=90-1
|
TIM5.Prescaler=90-1
|
||||||
TIM8.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
TIM8.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
||||||
@@ -497,7 +500,7 @@ TIM8.IPParameters=Prescaler,Period,TIM_MasterSlaveMode,TIM_MasterOutputTrigger,C
|
|||||||
TIM8.OC4Preload_PWM=ENABLE
|
TIM8.OC4Preload_PWM=ENABLE
|
||||||
TIM8.Period=65535
|
TIM8.Period=65535
|
||||||
TIM8.Prescaler=0
|
TIM8.Prescaler=0
|
||||||
TIM8.RepetitionCounter=20
|
TIM8.RepetitionCounter=0
|
||||||
TIM8.TIM_MasterOutputTrigger=TIM_TRGO_RESET
|
TIM8.TIM_MasterOutputTrigger=TIM_TRGO_RESET
|
||||||
TIM8.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE
|
TIM8.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE
|
||||||
USART3.IPParameters=VirtualMode
|
USART3.IPParameters=VirtualMode
|
||||||
@@ -534,6 +537,10 @@ VP_TIM5_VS_ClockSourceINT.Mode=Internal
|
|||||||
VP_TIM5_VS_ClockSourceINT.Signal=TIM5_VS_ClockSourceINT
|
VP_TIM5_VS_ClockSourceINT.Signal=TIM5_VS_ClockSourceINT
|
||||||
VP_TIM8_VS_ClockSourceINT.Mode=Internal
|
VP_TIM8_VS_ClockSourceINT.Mode=Internal
|
||||||
VP_TIM8_VS_ClockSourceINT.Signal=TIM8_VS_ClockSourceINT
|
VP_TIM8_VS_ClockSourceINT.Signal=TIM8_VS_ClockSourceINT
|
||||||
|
VP_TIM8_VS_ClockSourceITR.Mode=TriggerSource_ITR0
|
||||||
|
VP_TIM8_VS_ClockSourceITR.Signal=TIM8_VS_ClockSourceITR
|
||||||
|
VP_TIM8_VS_ControllerModeTrigger.Mode=Trigger Mode
|
||||||
|
VP_TIM8_VS_ControllerModeTrigger.Signal=TIM8_VS_ControllerModeTrigger
|
||||||
VP_TIM8_VS_OPM.Mode=OPM_bit
|
VP_TIM8_VS_OPM.Mode=OPM_bit
|
||||||
VP_TIM8_VS_OPM.Signal=TIM8_VS_OPM
|
VP_TIM8_VS_OPM.Signal=TIM8_VS_OPM
|
||||||
board=custom
|
board=custom
|
||||||
|
|||||||
12
Информация для программиста (УПП СП СЭД)/CALC/alpha_calc.m
Normal file
12
Информация для программиста (УПП СП СЭД)/CALC/alpha_calc.m
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
open_level = 0:0.01:1; % Степень регулирования выходного напряжения (epsilon) от 0 до 1
|
||||||
|
|
||||||
|
OpenLevelForCos = (open_level.*2)-1;
|
||||||
|
alpha_rad = acos(OpenLevelForCos); % угол в радианах
|
||||||
|
alpha = alpha_rad/pi; % угол открытия тиристора в о.е. от максимально заданного
|
||||||
|
|
||||||
|
plot(alpha, open_level)
|
||||||
|
grid on;
|
||||||
|
xlabel('\alpha, о.е. (от \pi)');
|
||||||
|
ylabel('\epsilon, о.е.');
|
||||||
|
title('Регулировочная характеристика \epsilon');
|
||||||
|
legend('ε = cos(α)');
|
||||||
@@ -2,10 +2,11 @@
|
|||||||
clear all; close all; clc;
|
clear all; close all; clc;
|
||||||
|
|
||||||
%% Параметры моделирования
|
%% Параметры моделирования
|
||||||
Fs = 100000; % Частота дискретизации [Гц]
|
Fs = 1/25e-6; % Частота дискретизации [Гц]
|
||||||
T = 0.5; % Время моделирования [с]
|
T = 0.5; % Время моделирования [с]
|
||||||
t = 0:1/Fs:T-1/Fs; % Временной вектор
|
t = 0:1/Fs:T-1/Fs; % Временной вектор
|
||||||
N = length(t); % Количество отсчетов
|
N = length(t); % Количество отсчетов
|
||||||
|
Fsrez = 50;
|
||||||
|
|
||||||
%% Уровни шума для разных каналов
|
%% Уровни шума для разных каналов
|
||||||
noise_levels.voltage = 0.2; % 2% шума для напряжений
|
noise_levels.voltage = 0.2; % 2% шума для напряжений
|
||||||
@@ -17,28 +18,28 @@ fprintf('=== АВТОМАТИЧЕСКИЙ РАСЧЕТ КОЭФФИЦИЕНТО
|
|||||||
|
|
||||||
% 1. Полосовой фильтр 45-55 Гц для напряжений
|
% 1. Полосовой фильтр 45-55 Гц для напряжений
|
||||||
% [b_bpf, a_bpf, coeffs_bpf] = BiquadFilterDesigner.bpf(20, 10, Fs);
|
% [b_bpf, a_bpf, coeffs_bpf] = BiquadFilterDesigner.bpf(20, 10, Fs);
|
||||||
[b_bpf, a_bpf, coeffs_bpf] = BiquadFilterDesigner.lpf(100, Fs);
|
[b_bpf, a_bpf, coeffs_bpf] = BiquadFilterDesigner.lpf(Fsrez, Fs);
|
||||||
fprintf('1. Полосовой фильтр 45-55 Гц:\n');
|
fprintf('1. Полосовой фильтр 45-55 Гц:\n');
|
||||||
BiquadFilterDesigner.generate_c_code(coeffs_bpf, 'voltage_bpf');
|
BiquadFilterDesigner.generate_c_code(coeffs_bpf, 'voltage_bpf');
|
||||||
|
|
||||||
% 2. ФНЧ 100 Гц для токов
|
% 2. ФНЧ 100 Гц для токов
|
||||||
[b_lpf_current, a_lpf_current, coeffs_lpf_current] = BiquadFilterDesigner.lpf(100, Fs);
|
[b_lpf_current, a_lpf_current, coeffs_lpf_current] = BiquadFilterDesigner.lpf(Fsrez, Fs);
|
||||||
fprintf('2. ФНЧ 100 Гц (токи):\n');
|
fprintf('2. ФНЧ 100 Гц (токи):\n');
|
||||||
BiquadFilterDesigner.generate_c_code(coeffs_lpf_current, 'current_lpf');
|
BiquadFilterDesigner.generate_c_code(coeffs_lpf_current, 'current_lpf');
|
||||||
|
%
|
||||||
% 3. ФНЧ 10 Гц для температур
|
% % 3. ФНЧ 10 Гц для температур
|
||||||
[b_lpf_temp, a_lpf_temp, coeffs_lpf_temp] = BiquadFilterDesigner.lpf(10, Fs);
|
% [b_lpf_temp, a_lpf_temp, coeffs_lpf_temp] = BiquadFilterDesigner.lpf(10, Fs);
|
||||||
fprintf('3. ФНЧ 10 Гц (температуры):\n');
|
% fprintf('3. ФНЧ 10 Гц (температуры):\n');
|
||||||
BiquadFilterDesigner.generate_c_code(coeffs_lpf_temp, 'temperature_lpf');
|
% BiquadFilterDesigner.generate_c_code(coeffs_lpf_temp, 'temperature_lpf');
|
||||||
|
|
||||||
% Вывод коэффициентов в консоль
|
% Вывод коэффициентов в консоль
|
||||||
fprintf('\n=== РАСЧЕТНЫЕ КОЭФФИЦИЕНТЫ ===\n');
|
fprintf('\n=== РАСЧЕТНЫЕ КОЭФФИЦИЕНТЫ ===\n');
|
||||||
fprintf('Напряжение (BPF 45-55 Гц): b = [%.6f, %.6f, %.6f], a = [1, %.6f, %.6f]\n', ...
|
fprintf('Напряжение (BPF 45-55 Гц): b = [%.6f, %.6f, %.6f], a = [1, %.6f, %.6f]\n', ...
|
||||||
b_bpf, a_bpf(2), a_bpf(3));
|
b_bpf, a_bpf(2), a_bpf(3));
|
||||||
fprintf('Ток (LPF 100 Гц): b = [%.6f, %.6f, %.6f], a = [1, %.6f, %.6f]\n', ...
|
% fprintf('Ток (LPF 100 Гц): b = [%.6f, %.6f, %.6f], a = [1, %.6f, %.6f]\n', ...
|
||||||
b_lpf_current, a_lpf_current(2), a_lpf_current(3));
|
% b_lpf_current, a_lpf_current(2), a_lpf_current(3));
|
||||||
fprintf('Температура (LPF 10 Гц): b = [%.6f, %.6f, %.6f], a = [1, %.6f, %.6f]\n\n', ...
|
% fprintf('Температура (LPF 10 Гц): b = [%.6f, %.6f, %.6f], a = [1, %.6f, %.6f]\n\n', ...
|
||||||
b_lpf_temp, a_lpf_temp(2), a_lpf_temp(3));
|
% b_lpf_temp, a_lpf_temp(2), a_lpf_temp(3));
|
||||||
|
|
||||||
%% Генерация тестовых сигналов
|
%% Генерация тестовых сигналов
|
||||||
|
|
||||||
@@ -53,25 +54,25 @@ f_current = 50;
|
|||||||
current_clean = 1 * sin(2*pi*f_current*t); %.* ...
|
current_clean = 1 * sin(2*pi*f_current*t); %.* ...
|
||||||
%(1 + 0.2 * sin(2*pi*2*t)); % амплитудная модуляция 2 Гц
|
%(1 + 0.2 * sin(2*pi*2*t)); % амплитудная модуляция 2 Гц
|
||||||
|
|
||||||
% 3. Температура (медленно меняющийся сигнал)
|
% % 3. Температура (медленно меняющийся сигнал)
|
||||||
temperature_clean = 25 + 2 * sin(2*pi*0.1*t) + ... % медленные колебания 0.1 Гц
|
% temperature_clean = 25 + 2 * sin(2*pi*0.1*t) + ... % медленные колебания 0.1 Гц
|
||||||
0.5 * sin(2*pi*1*t); % быстрые колебания 1 Гц
|
% 0.5 * sin(2*pi*1*t); % быстрые колебания 1 Гц
|
||||||
|
|
||||||
%% Добавление шума
|
%% Добавление шума
|
||||||
voltage_noisy = voltage_clean + noise_levels.voltage * randn(size(t));
|
voltage_noisy = voltage_clean + noise_levels.voltage * randn(size(t));
|
||||||
current_noisy = current_clean + noise_levels.current * randn(size(t));
|
current_noisy = current_clean + noise_levels.current * randn(size(t));
|
||||||
temperature_noisy = temperature_clean + noise_levels.temperature * randn(size(t));
|
% temperature_noisy = temperature_clean + noise_levels.temperature * randn(size(t));
|
||||||
|
|
||||||
%% Фильтрация сигналов
|
%% Фильтрация сигналов
|
||||||
voltage_filtered = filter(b_bpf, a_bpf, voltage_noisy);
|
voltage_filtered = filter(b_bpf, a_bpf, voltage_noisy);
|
||||||
current_filtered = filter(b_lpf_current, a_lpf_current, current_noisy);
|
current_filtered = filter(b_lpf_current, a_lpf_current, current_noisy);
|
||||||
temperature_filtered = filter(b_lpf_temp, a_lpf_temp, temperature_noisy);
|
% temperature_filtered = filter(b_lpf_temp, a_lpf_temp, temperature_noisy);
|
||||||
|
|
||||||
%% НОРМАЛИЗАЦИЯ УСИЛЕНИЯ (важно для правильного SNR)
|
%% НОРМАЛИЗАЦИЯ УСИЛЕНИЯ (важно для правильного SNR)
|
||||||
% Получаем АЧХ для нормализации
|
% Получаем АЧХ для нормализации
|
||||||
[h_bpf, f_bpf] = freqz(b_bpf, a_bpf, 1024, Fs);
|
[h_bpf, f_bpf] = freqz(b_bpf, a_bpf, 1024, Fs);
|
||||||
[h_lpf_curr, f_lpf_curr] = freqz(b_lpf_current, a_lpf_current, 1024, Fs);
|
[h_lpf_curr, f_lpf_curr] = freqz(b_lpf_current, a_lpf_current, 1024, Fs);
|
||||||
[h_lpf_temp, f_lpf_temp] = freqz(b_lpf_temp, a_lpf_temp, 1024, Fs);
|
% [h_lpf_temp, f_lpf_temp] = freqz(b_lpf_temp, a_lpf_temp, 1024, Fs);
|
||||||
|
|
||||||
% Нормализация полосового фильтра на центральной частоте
|
% Нормализация полосового фильтра на центральной частоте
|
||||||
[~, idx_50hz] = min(abs(f_bpf - 50));
|
[~, idx_50hz] = min(abs(f_bpf - 50));
|
||||||
@@ -85,11 +86,11 @@ gain_lpf_current = sum(b_lpf_current) / (1 + sum(a_lpf_current(2:end)));
|
|||||||
if gain_lpf_current > 0
|
if gain_lpf_current > 0
|
||||||
current_filtered = current_filtered / gain_lpf_current;
|
current_filtered = current_filtered / gain_lpf_current;
|
||||||
end
|
end
|
||||||
|
%
|
||||||
gain_lpf_temp = sum(b_lpf_temp) / (1 + sum(a_lpf_temp(2:end)));
|
% gain_lpf_temp = sum(b_lpf_temp) / (1 + sum(a_lpf_temp(2:end)));
|
||||||
if gain_lpf_temp > 0
|
% if gain_lpf_temp > 0
|
||||||
temperature_filtered = temperature_filtered / gain_lpf_temp;
|
% temperature_filtered = temperature_filtered / gain_lpf_temp;
|
||||||
end
|
% end
|
||||||
|
|
||||||
%% ОКНО 1: НАПРЯЖЕНИЕ
|
%% ОКНО 1: НАПРЯЖЕНИЕ
|
||||||
figure('Name', 'Анализ напряжения');
|
figure('Name', 'Анализ напряжения');
|
||||||
@@ -213,68 +214,68 @@ text(0.1, 0.4, sprintf('Улучшение: %.1f дБ', improvement_current), 'F
|
|||||||
text(0.1, 0.2, sprintf('Задержка 50 Гц: %.1f мс', gd_lpf_curr(idx_50hz_curr)/Fs*1000), 'FontSize', 12);
|
text(0.1, 0.2, sprintf('Задержка 50 Гц: %.1f мс', gd_lpf_curr(idx_50hz_curr)/Fs*1000), 'FontSize', 12);
|
||||||
title('Статистика фильтрации тока');
|
title('Статистика фильтрации тока');
|
||||||
axis off;
|
axis off;
|
||||||
|
%
|
||||||
%% ОКНО 3: ТЕМПЕРАТУРА
|
% %% ОКНО 3: ТЕМПЕРАТУРА
|
||||||
figure('Name', 'Анализ температуры');
|
% figure('Name', 'Анализ температуры');
|
||||||
|
%
|
||||||
% Временные характеристики
|
% % Временные характеристики
|
||||||
subplot(2,3,1);
|
% subplot(2,3,1);
|
||||||
plot(t, temperature_noisy, 'b', 'LineWidth', 1); hold on;
|
% plot(t, temperature_noisy, 'b', 'LineWidth', 1); hold on;
|
||||||
plot(t, temperature_filtered, 'r', 'LineWidth', 2);
|
% plot(t, temperature_filtered, 'r', 'LineWidth', 2);
|
||||||
plot(t, temperature_clean, 'g--', 'LineWidth', 1);
|
% plot(t, temperature_clean, 'g--', 'LineWidth', 1);
|
||||||
title('Температура: временная область');
|
% title('Температура: временная область');
|
||||||
legend('С шумом', 'Фильтрованный', 'Идеальный', 'Location', 'best');
|
% legend('С шумом', 'Фильтрованный', 'Идеальный', 'Location', 'best');
|
||||||
xlabel('Время [с]'); ylabel('Температура [°C]');
|
% xlabel('Время [с]'); ylabel('Температура [°C]');
|
||||||
grid on;
|
% grid on;
|
||||||
|
%
|
||||||
% АЧХ фильтра
|
% % АЧХ фильтра
|
||||||
subplot(2,3,2);
|
% subplot(2,3,2);
|
||||||
plot(f_lpf_temp, 20*log10(abs(h_lpf_temp)), 'LineWidth', 2);
|
% plot(f_lpf_temp, 20*log10(abs(h_lpf_temp)), 'LineWidth', 2);
|
||||||
title('АЧХ: ФНЧ 10 Гц');
|
% title('АЧХ: ФНЧ 10 Гц');
|
||||||
xlabel('Частота [Гц]'); ylabel('Усиление [дБ]');
|
% xlabel('Частота [Гц]'); ylabel('Усиление [дБ]');
|
||||||
grid on; xlim([0, 20]);
|
% grid on; xlim([0, 20]);
|
||||||
|
%
|
||||||
% Спектр фильтрованного сигнала
|
% % Спектр фильтрованного сигнала
|
||||||
subplot(2,3,3);
|
% subplot(2,3,3);
|
||||||
[P_temp, f_temp] = pwelch(temperature_filtered, [], [], 1024, Fs);
|
% [P_temp, f_temp] = pwelch(temperature_filtered, [], [], 1024, Fs);
|
||||||
plot(f_temp, 10*log10(P_temp), 'LineWidth', 2);
|
% plot(f_temp, 10*log10(P_temp), 'LineWidth', 2);
|
||||||
title('Спектр фильтрованной температуры');
|
% title('Спектр фильтрованной температуры');
|
||||||
xlabel('Частота [Гц]'); ylabel('Мощность [дБ]');
|
% xlabel('Частота [Гц]'); ylabel('Мощность [дБ]');
|
||||||
grid on; xlim([0, 10]);
|
% grid on; xlim([0, 10]);
|
||||||
|
%
|
||||||
% Групповая задержка
|
% % Групповая задержка
|
||||||
subplot(2,3,4);
|
% subplot(2,3,4);
|
||||||
[gd_lpf_temp, f_gd_temp] = grpdelay(b_lpf_temp, a_lpf_temp, 1024, Fs);
|
% [gd_lpf_temp, f_gd_temp] = grpdelay(b_lpf_temp, a_lpf_temp, 1024, Fs);
|
||||||
plot(f_gd_temp, gd_lpf_temp/Fs*1000, 'LineWidth', 2);
|
% plot(f_gd_temp, gd_lpf_temp/Fs*1000, 'LineWidth', 2);
|
||||||
title('Групповая задержка фильтра');
|
% title('Групповая задержка фильтра');
|
||||||
xlabel('Частота [Гц]'); ylabel('Задержка [мс]');
|
% xlabel('Частота [Гц]'); ylabel('Задержка [мс]');
|
||||||
grid on; xlim([0, 20]);
|
% grid on; xlim([0, 20]);
|
||||||
|
%
|
||||||
% Детальный вид (последне 0.1 секунды)
|
% % Детальный вид (последне 0.1 секунды)
|
||||||
idx_end_temp = max(1, length(t) - 0.1*Fs + 1):length(t); % последние 100 мс
|
% idx_end_temp = max(1, length(t) - 0.1*Fs + 1):length(t); % последние 100 мс
|
||||||
subplot(2,3,5);
|
% subplot(2,3,5);
|
||||||
plot(t(idx_end_temp), temperature_noisy(idx_end_temp), 'b', 'LineWidth', 2); hold on;
|
% plot(t(idx_end_temp), temperature_noisy(idx_end_temp), 'b', 'LineWidth', 2); hold on;
|
||||||
plot(t(idx_end_temp), temperature_filtered(idx_end_temp), 'r', 'LineWidth', 2);
|
% plot(t(idx_end_temp), temperature_filtered(idx_end_temp), 'r', 'LineWidth', 2);
|
||||||
plot(t(idx_end_temp), temperature_clean(idx_end_temp), 'g--', 'LineWidth', 2);
|
% plot(t(idx_end_temp), temperature_clean(idx_end_temp), 'g--', 'LineWidth', 2);
|
||||||
title('Температура: УВЕЛИЧЕННЫЙ ВИД (900-1000 мс)');
|
% title('Температура: УВЕЛИЧЕННЫЙ ВИД (900-1000 мс)');
|
||||||
legend('С шумом', 'Фильтрованный', 'Идеальный', 'Location', 'best');
|
% legend('С шумом', 'Фильтрованный', 'Идеальный', 'Location', 'best');
|
||||||
xlabel('Время [с]'); ylabel('Температура [°C]');
|
% xlabel('Время [с]'); ylabel('Температура [°C]');
|
||||||
grid on;
|
% grid on;
|
||||||
xlim([t(idx_end_temp(1)) t(idx_end_temp(end))]);
|
% xlim([t(idx_end_temp(1)) t(idx_end_temp(end))]);
|
||||||
|
%
|
||||||
% Статистика
|
% % Статистика
|
||||||
subplot(2,3,6);
|
% subplot(2,3,6);
|
||||||
snr_temp_in = snr(temperature_clean, temperature_noisy - temperature_clean);
|
% snr_temp_in = snr(temperature_clean, temperature_noisy - temperature_clean);
|
||||||
snr_temp_out = snr(temperature_clean, temperature_filtered - temperature_clean);
|
% snr_temp_out = snr(temperature_clean, temperature_filtered - temperature_clean);
|
||||||
improvement_temp = snr_temp_out - snr_temp_in;
|
% improvement_temp = snr_temp_out - snr_temp_in;
|
||||||
|
%
|
||||||
[~, idx_1hz] = min(abs(f_gd_temp - 1));
|
% [~, idx_1hz] = min(abs(f_gd_temp - 1));
|
||||||
text(0.1, 0.8, sprintf('SNR вход: %.1f дБ', snr_temp_in), 'FontSize', 12);
|
% text(0.1, 0.8, sprintf('SNR вход: %.1f дБ', snr_temp_in), 'FontSize', 12);
|
||||||
text(0.1, 0.6, sprintf('SNR выход: %.1f дБ', snr_temp_out), 'FontSize', 12);
|
% text(0.1, 0.6, sprintf('SNR выход: %.1f дБ', snr_temp_out), 'FontSize', 12);
|
||||||
text(0.1, 0.4, sprintf('Улучшение: %.1f дБ', improvement_temp), 'FontSize', 12);
|
% text(0.1, 0.4, sprintf('Улучшение: %.1f дБ', improvement_temp), 'FontSize', 12);
|
||||||
text(0.1, 0.2, sprintf('Задержка 1 Гц: %.1f мс', gd_lpf_temp(idx_1hz)/Fs*1000), 'FontSize', 12);
|
% text(0.1, 0.2, sprintf('Задержка 1 Гц: %.1f мс', gd_lpf_temp(idx_1hz)/Fs*1000), 'FontSize', 12);
|
||||||
title('Статистика фильтрации температуры');
|
% title('Статистика фильтрации температуры');
|
||||||
axis off;
|
% axis off;
|
||||||
|
|
||||||
%% Вывод результатов в командное окно
|
%% Вывод результатов в командное окно
|
||||||
fprintf('\n=== ИТОГИ ФИЛЬТРАЦИИ С АВТОРАСЧЕТОМ КОЭФФИЦИЕНТОВ ===\n\n');
|
fprintf('\n=== ИТОГИ ФИЛЬТРАЦИИ С АВТОРАСЧЕТОМ КОЭФФИЦИЕНТОВ ===\n\n');
|
||||||
@@ -288,7 +289,7 @@ fprintf(' SNR вход: %.1f дБ, выход: %.1f дБ, улучшение: %
|
|||||||
snr_current_in, snr_current_out, improvement_current);
|
snr_current_in, snr_current_out, improvement_current);
|
||||||
fprintf(' Задержка на 50 Гц: %.1f мс\n\n', gd_lpf_curr(idx_50hz_curr)/Fs*1000);
|
fprintf(' Задержка на 50 Гц: %.1f мс\n\n', gd_lpf_curr(idx_50hz_curr)/Fs*1000);
|
||||||
|
|
||||||
fprintf('ТЕМПЕРАТУРА (ФНЧ 10 Гц):\n');
|
% fprintf('ТЕМПЕРАТУРА (ФНЧ 10 Гц):\n');
|
||||||
fprintf(' SNR вход: %.1f дБ, выход: %.1f дБ, улучшение: %.1f дБ\n', ...
|
% fprintf(' SNR вход: %.1f дБ, выход: %.1f дБ, улучшение: %.1f дБ\n', ...
|
||||||
snr_temp_in, snr_temp_out, improvement_temp);
|
% snr_temp_in, snr_temp_out, improvement_temp);
|
||||||
fprintf(' Задержка на 1 Гц: %.1f мс\n\n', gd_lpf_temp(idx_1hz)/Fs*1000);
|
% fprintf(' Задержка на 1 Гц: %.1f мс\n\n', gd_lpf_temp(idx_1hz)/Fs*1000);
|
||||||
230
Информация для программиста (УПП СП СЭД)/CALC/calc_filter.m
Normal file
230
Информация для программиста (УПП СП СЭД)/CALC/calc_filter.m
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
%% ===== РАСЧЕТ КОЭФФИЦИЕНТОВ БИКВАДРАТНОГО ФИЛЬТРА 50 Гц =====
|
||||||
|
% Запуск: Ctrl+S (сохранить), потом F5 (запустить)
|
||||||
|
|
||||||
|
clear all; close all; clc;
|
||||||
|
|
||||||
|
%% 1. ПАРАМЕТРЫ (МЕНЯТЬ ЗДЕСЬ)
|
||||||
|
fs = 1/25e-6; % Частота дискретизации (Гц)
|
||||||
|
fc = 100; % Частота среза 50 Гц
|
||||||
|
Q = 0.707; % Добротность (0.707 = Баттерворт)
|
||||||
|
filter_type = 'lpf'; % 'lpf', 'hpf', 'bpf', 'notch'
|
||||||
|
|
||||||
|
test_freq = 55;
|
||||||
|
|
||||||
|
%% 2. РАСЧЕТ КОЭФФИЦИЕНТОВ
|
||||||
|
w0 = 2 * pi * fc / fs;
|
||||||
|
alpha = sin(w0) / (2 * Q);
|
||||||
|
cos_w0 = cos(w0);
|
||||||
|
|
||||||
|
switch filter_type
|
||||||
|
case 'lpf' % ФНЧ
|
||||||
|
b0 = (1 - cos_w0) / 2;
|
||||||
|
b1 = 1 - cos_w0;
|
||||||
|
b2 = b0;
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
a1 = -2 * cos_w0;
|
||||||
|
a2 = 1 - alpha;
|
||||||
|
|
||||||
|
case 'hpf' % ФВЧ
|
||||||
|
b0 = (1 + cos_w0) / 2;
|
||||||
|
b1 = -(1 + cos_w0);
|
||||||
|
b2 = b0;
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
a1 = -2 * cos_w0;
|
||||||
|
a2 = 1 - alpha;
|
||||||
|
|
||||||
|
case 'bpf' % Полосовой
|
||||||
|
b0 = alpha;
|
||||||
|
b1 = 0;
|
||||||
|
b2 = -alpha;
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
a1 = -2 * cos_w0;
|
||||||
|
a2 = 1 - alpha;
|
||||||
|
|
||||||
|
case 'notch' % Режекторный (50 Гц)
|
||||||
|
b0 = 1;
|
||||||
|
b1 = -2 * cos_w0;
|
||||||
|
b2 = 1;
|
||||||
|
a0 = 1 + alpha;
|
||||||
|
a1 = -2 * cos_w0;
|
||||||
|
a2 = 1 - alpha;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Нормализация
|
||||||
|
b = [b0, b1, b2] / a0;
|
||||||
|
a = [1, a1/a0, a2/a0];
|
||||||
|
|
||||||
|
% Проверка полюсов
|
||||||
|
poles = roots([1, a(2), a(3)]);
|
||||||
|
if any(abs(poles) >= 1)
|
||||||
|
error('Фильтр НЕУСТОЙЧИВ! Полюса: %s', mat2str(poles));
|
||||||
|
end
|
||||||
|
%% 3. ВЫВОД РЕЗУЛЬТАТОВ
|
||||||
|
fprintf('\n══════════════════════════════════════════════════\n');
|
||||||
|
fprintf('ПАРАМЕТРЫ ФИЛЬТРА:\n');
|
||||||
|
fprintf('Тип: %s\n', upper(filter_type));
|
||||||
|
fprintf('Частота среза: %.1f Гц\n', fc);
|
||||||
|
fprintf('Частота дискретизации: %.0f Гц\n', fs);
|
||||||
|
fprintf('Добротность Q: %.3f\n', Q);
|
||||||
|
fprintf('══════════════════════════════════════════════════\n');
|
||||||
|
|
||||||
|
fprintf('\nКОЭФФИЦИЕНТЫ ДЛЯ CMSIS-DSP:\n');
|
||||||
|
fprintf('float32_t coeffs[5] = {\n');
|
||||||
|
fprintf(' %ff, // b0\n', b(1));
|
||||||
|
fprintf(' %ff, // b1\n', b(2));
|
||||||
|
fprintf(' %ff, // b2\n', b(3));
|
||||||
|
fprintf(' %ff, // a1\n', a(2));
|
||||||
|
fprintf(' %ff // a2\n', a(3));
|
||||||
|
fprintf('};\n');
|
||||||
|
|
||||||
|
fprintf('\nФОРМАТ ДЛЯ Biquad_InitDirect:\n');
|
||||||
|
fprintf('Biquad_InitDirect(&filter, %.6ff, %.6ff, %.6ff, %.6ff, %.6ff);\n', ...
|
||||||
|
b(1), b(2), b(3), a(2), a(3));
|
||||||
|
|
||||||
|
%% 4. ПРОВЕРКА ЧАСТОТНОЙ ХАРАКТЕРИСТИКИ
|
||||||
|
[h, f] = freqz(b, a, 2048, fs);
|
||||||
|
|
||||||
|
figure();
|
||||||
|
|
||||||
|
% АЧХ
|
||||||
|
subplot(1, 2, 1);
|
||||||
|
plot(f, 20*log10(abs(h)), 'LineWidth', 2);
|
||||||
|
grid on; hold on;
|
||||||
|
xline(fc, '--r', 'Частота среза', 'LineWidth', 1.5);
|
||||||
|
xlim([0, fs/2]);
|
||||||
|
ylim([-60, 5]);
|
||||||
|
xlabel('Частота (Гц)');
|
||||||
|
ylabel('Усиление (дБ)');
|
||||||
|
title(['АЧХ: ' upper(filter_type) ' фильтр ' num2str(fc) ' Гц']);
|
||||||
|
|
||||||
|
% ФЧХ
|
||||||
|
subplot(1, 2, 2);
|
||||||
|
plot(f, angle(h)*180/pi, 'LineWidth', 2);
|
||||||
|
grid on; hold on;
|
||||||
|
xline(fc, '--r', 'Частота среза', 'LineWidth', 1.5);
|
||||||
|
xlim([0, fs/2]);
|
||||||
|
xlabel('Частота (Гц)');
|
||||||
|
ylabel('Фазовый сдвиг (градусы)');
|
||||||
|
title(['ФЧХ: ' upper(filter_type) ' фильтр ' num2str(fc) ' Гц']);
|
||||||
|
|
||||||
|
%% 4b. ГРАФИК ЗАДЕРЖКИ (40-60 Гц)
|
||||||
|
figure();
|
||||||
|
|
||||||
|
% Рассчитываем на нужном диапазоне частот
|
||||||
|
f_range = 40:0.1:60; % Частоты с шагом 0.1 Гц
|
||||||
|
h_range = freqz(b, a, f_range, fs);
|
||||||
|
|
||||||
|
% Групповая задержка (численная производная)
|
||||||
|
phase_unwrapped = unwrap(angle(h_range));
|
||||||
|
w_range = 2*pi*f_range/fs;
|
||||||
|
group_delay = -gradient(phase_unwrapped) ./ gradient(w_range);
|
||||||
|
|
||||||
|
% Фазовая задержка
|
||||||
|
phase_delay = -angle(h_range) ./ w_range;
|
||||||
|
|
||||||
|
% График 1: Групповая задержка
|
||||||
|
subplot(1, 2, 1);
|
||||||
|
plot(f_range, group_delay * 1000, 'LineWidth', 3);
|
||||||
|
grid on; hold on;
|
||||||
|
xline(test_freq, '--r', '50 Гц', 'LineWidth', 2, 'FontSize', 12);
|
||||||
|
xlim([40, 60]);
|
||||||
|
ylim([0, max(group_delay*1000)*1.1]);
|
||||||
|
xlabel('Частота (Гц)', 'FontSize', 12);
|
||||||
|
ylabel('Групповая задержка (мс)', 'FontSize', 12);
|
||||||
|
title(['Групповая задержка: ' upper(filter_type) ' фильтр'], 'FontSize', 14);
|
||||||
|
|
||||||
|
% Значение на 50 Гц
|
||||||
|
idx_50 = find(f_range >= test_freq, 1);
|
||||||
|
if ~isempty(idx_50)
|
||||||
|
delay_50hz = group_delay(idx_50) * 1000;
|
||||||
|
plot(test_freq, delay_50hz, 'ro', 'MarkerSize', 15, 'LineWidth', 3);
|
||||||
|
text(test_freq + 0.5, delay_50hz*1.05, sprintf('%.2f мс', delay_50hz), ...
|
||||||
|
'FontSize', 14, 'FontWeight', 'bold', 'BackgroundColor', 'white');
|
||||||
|
end
|
||||||
|
|
||||||
|
% График 2: Фазовая задержка
|
||||||
|
subplot(1, 2, 2);
|
||||||
|
plot(f_range, phase_delay * 1000, 'LineWidth', 3, 'Color', [0, 0.5, 0]);
|
||||||
|
grid on; hold on;
|
||||||
|
xline(test_freq, '--r', '50 Гц', 'LineWidth', 2, 'FontSize', 12);
|
||||||
|
xlim([40, 60]);
|
||||||
|
xlabel('Частота (Гц)', 'FontSize', 12);
|
||||||
|
ylabel('Фазовая задержка (мс)', 'FontSize', 12);
|
||||||
|
title(['Фазовая задержка: ' upper(filter_type) ' фильтр'], 'FontSize', 14);
|
||||||
|
|
||||||
|
% Значение на 50 Гц
|
||||||
|
if ~isempty(idx_50)
|
||||||
|
phase_delay_50hz = phase_delay(idx_50) * 1000;
|
||||||
|
plot(test_freq, phase_delay_50hz, 'ro', 'MarkerSize', 15, 'LineWidth', 3);
|
||||||
|
text(test_freq + 0.5, phase_delay_50hz*1.05, sprintf('%.2f мс', phase_delay_50hz), ...
|
||||||
|
'FontSize', 14, 'FontWeight', 'bold', 'BackgroundColor', 'white');
|
||||||
|
end
|
||||||
|
|
||||||
|
%% 4c. ГРАФИК УСИЛЕНИЯ (40-60 Гц)
|
||||||
|
figure();
|
||||||
|
|
||||||
|
% Усиление в дБ
|
||||||
|
gain_db = 20*log10(abs(h_range));
|
||||||
|
|
||||||
|
plot(f_range, gain_db, 'LineWidth', 3, 'Color', [0.8, 0, 0]);
|
||||||
|
grid on; hold on;
|
||||||
|
xline(test_freq, '--r', '50 Гц', 'LineWidth', 2, 'FontSize', 12);
|
||||||
|
xlim([40, 60]);
|
||||||
|
ylim([min(gain_db)-1, max(gain_db)+1]);
|
||||||
|
xlabel('Частота (Гц)', 'FontSize', 12);
|
||||||
|
ylabel('Усиление (дБ)', 'FontSize', 12);
|
||||||
|
title(['Усиление: ' upper(filter_type) ' фильтр (40-60 Гц)'], 'FontSize', 14);
|
||||||
|
|
||||||
|
% Значение на 50 Гц
|
||||||
|
if ~isempty(idx_50)
|
||||||
|
gain_50hz = gain_db(idx_50);
|
||||||
|
plot(test_freq, gain_50hz, 'ro', 'MarkerSize', 15, 'LineWidth', 3);
|
||||||
|
text(test_freq +0.5, gain_50hz, sprintf('%.2f дБ', gain_50hz), ...
|
||||||
|
'FontSize', 14, 'FontWeight', 'bold', 'BackgroundColor', 'white');
|
||||||
|
end
|
||||||
|
|
||||||
|
%% 5. ТЕСТОВЫЙ СИГНАЛ
|
||||||
|
t = 0:1/fs:0.2; % 200 мс
|
||||||
|
f_test = test_freq; % Тест на 50 Гц
|
||||||
|
signal = sin(2*pi*f_test*t);
|
||||||
|
|
||||||
|
% Фильтрация
|
||||||
|
filtered = filter(b, a, signal);
|
||||||
|
|
||||||
|
figure();
|
||||||
|
subplot(2, 1, 1);
|
||||||
|
plot(t, signal, 'b', 'LineWidth', 1.5);
|
||||||
|
hold on; grid on;
|
||||||
|
plot(t, filtered, 'r', 'LineWidth', 2);
|
||||||
|
xlabel('Время (с)');
|
||||||
|
ylabel('Амплитуда');
|
||||||
|
legend('Исходный', 'После фильтра', 'Location', 'best');
|
||||||
|
title(['Тест фильтра: ' num2str(f_test) ' Гц']);
|
||||||
|
|
||||||
|
% Спектр
|
||||||
|
subplot(2, 1, 2);
|
||||||
|
[P1, f1] = pwelch(signal, [], [], [], fs);
|
||||||
|
[P2, f2] = pwelch(filtered, [], [], [], fs);
|
||||||
|
plot(f1, 10*log10(P1), 'b', 'LineWidth', 1.5);
|
||||||
|
hold on; grid on;
|
||||||
|
plot(f2, 10*log10(P2), 'r', 'LineWidth', 2);
|
||||||
|
xlim([0, 200]);
|
||||||
|
xlabel('Частота (Гц)');
|
||||||
|
ylabel('Мощность (дБ)');
|
||||||
|
legend('Исходный', 'После фильтра', 'Location', 'best');
|
||||||
|
title('Спектр сигнала');
|
||||||
|
|
||||||
|
|
||||||
|
fprintf('\n══════════════════════════════════════════════════\n');
|
||||||
|
fprintf('ЗНАЧЕНИЯ НА %d Гц:\n', f_test);
|
||||||
|
|
||||||
|
if ~isempty(idx_50)
|
||||||
|
fprintf('Групповая задержка: %.2f мс\n', delay_50hz);
|
||||||
|
fprintf('Фазовая задержка: %.2f мс\n', phase_delay_50hz);
|
||||||
|
fprintf('Усиление: %.2f дБ (%.3f в линейном масштабе)\n', ...
|
||||||
|
gain_50hz, abs(h_range(idx_50)));
|
||||||
|
else
|
||||||
|
fprintf('Не удалось рассчитать значения на 50 Гц\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
fprintf('══════════════════════════════════════════════════\n');
|
||||||
199
Информация для программиста (УПП СП СЭД)/CALC/test_filt.m
Normal file
199
Информация для программиста (УПП СП СЭД)/CALC/test_filt.m
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
%% МОДЕЛИРОВАНИЕ ПОЛОСОВОГО ФИЛЬТРА С ДИФФЕРЕНЦИАТОРОМ
|
||||||
|
clear all; close all; clc;
|
||||||
|
|
||||||
|
%% 1. ПАРАМЕТРЫ ФИЛЬТРА (подставь свои значения)
|
||||||
|
b0 = 0.000392540911;
|
||||||
|
b1 = 0.0;
|
||||||
|
b2 = -0.000392540911;
|
||||||
|
a1 = -1.99915338;
|
||||||
|
a2 = 0.999214947;
|
||||||
|
|
||||||
|
% Или рассчитай новые:
|
||||||
|
center_freq = 50; % Центральная частота (Гц)
|
||||||
|
sample_freq = 40000; % Частота дискретизации (Гц)
|
||||||
|
bandwidth = 5; % Ширина полосы (Гц)
|
||||||
|
|
||||||
|
% %% 2. РАСЧЕТ КОЭФФИЦИЕНТОВ (если нужно)
|
||||||
|
% if 1 % Поставь 0 если используешь готовые коэффициенты выше
|
||||||
|
% % Отношение частот
|
||||||
|
% fc_ratio = center_freq / sample_freq;
|
||||||
|
% bandwidth_ratio = bandwidth / center_freq;
|
||||||
|
%
|
||||||
|
% % Расчет коэффициентов полосового фильтра
|
||||||
|
% w0 = 2 * pi * fc_ratio;
|
||||||
|
% Q = 1 / bandwidth_ratio;
|
||||||
|
% alpha = sin(w0) / (2 * Q);
|
||||||
|
% cos_w0 = cos(w0);
|
||||||
|
%
|
||||||
|
% % Коэффициенты биквадратного полосового фильтра
|
||||||
|
% b0_bp = alpha;
|
||||||
|
% b1_bp = 0;
|
||||||
|
% b2_bp = -alpha;
|
||||||
|
% a0_bp = 1 + alpha;
|
||||||
|
% a1_bp = -2 * cos_w0;
|
||||||
|
% a2_bp = 1 - alpha;
|
||||||
|
%
|
||||||
|
% % Нормализация (a0 = 1)
|
||||||
|
% b0 = b0_bp / a0_bp;
|
||||||
|
% b1 = b1_bp / a0_bp;
|
||||||
|
% b2 = b2_bp / a0_bp;
|
||||||
|
% a1 = a1_bp / a0_bp;
|
||||||
|
% a2 = a2_bp / a0_bp;
|
||||||
|
% end
|
||||||
|
|
||||||
|
fprintf('Коэффициенты фильтра:\n');
|
||||||
|
fprintf('b0 = %.6f\n', b0);
|
||||||
|
fprintf('b1 = %.6f\n', b1);
|
||||||
|
fprintf('b2 = %.6f\n', b2);
|
||||||
|
fprintf('a1 = %.6f\n', a1);
|
||||||
|
fprintf('a2 = %.6f\n', a2);
|
||||||
|
|
||||||
|
%% 3. ПРОВЕРКА УСТОЙЧИВОСТИ
|
||||||
|
poles = roots([1, a1, a2]);
|
||||||
|
fprintf('\nПолюса фильтра:\n');
|
||||||
|
for i = 1:length(poles)
|
||||||
|
fprintf(' pole%d = %.6f %+.6fj (|pole| = %.6f)\n', ...
|
||||||
|
i, real(poles(i)), imag(poles(i)), abs(poles(i)));
|
||||||
|
end
|
||||||
|
|
||||||
|
if any(abs(poles) >= 1)
|
||||||
|
fprintf('⚠️ ВНИМАНИЕ: Фильтр НЕУСТОЙЧИВ!\n');
|
||||||
|
else
|
||||||
|
fprintf('✅ Фильтр устойчив\n');
|
||||||
|
end
|
||||||
|
|
||||||
|
%% 5. ЧАСТОТНАЯ ХАРАКТЕРИСТИКА ПОЛНОГО ФИЛЬТРА (с дифференциатором)
|
||||||
|
% Дифференциатор: H_diff(z) = 1 - z^-1
|
||||||
|
b_diff = [1, -1];
|
||||||
|
a_diff = 1;
|
||||||
|
|
||||||
|
% % Каскадное соединение: дифференциатор + полосовой фильтр
|
||||||
|
% b_total = conv(b_diff, b_bp); % Перемножение полиномов
|
||||||
|
% a_total = conv(a_diff, a_bp);
|
||||||
|
% полосовой фильтр
|
||||||
|
b_total = [b0, b1, b2];
|
||||||
|
a_total = [1, a1, a2];
|
||||||
|
|
||||||
|
[h_total, f_total] = freqz(b_total, a_total, 2048, sample_freq);
|
||||||
|
|
||||||
|
figure();
|
||||||
|
subplot(1,2,1);
|
||||||
|
plot(f_total, 20*log10(abs(h_total)), 'r', 'LineWidth', 2);
|
||||||
|
grid on; hold on;
|
||||||
|
xline(center_freq, '--r', sprintf('%d Гц', center_freq), 'LineWidth', 1.5);
|
||||||
|
xlim([0, sample_freq/2]);
|
||||||
|
ylim([-60, 20]);
|
||||||
|
xlabel('Частота (Гц)');
|
||||||
|
ylabel('Усиление (дБ)');
|
||||||
|
title('АЧХ полного фильтра (дифференциатор + полосовой)');
|
||||||
|
|
||||||
|
subplot(1,2,2);
|
||||||
|
plot(f_total, angle(h_total)*180/pi, 'r', 'LineWidth', 2);
|
||||||
|
grid on; hold on;
|
||||||
|
xline(center_freq, '--r', sprintf('%d Гц', center_freq), 'LineWidth', 1.5);
|
||||||
|
xlim([0, sample_freq/2]);
|
||||||
|
xlabel('Частота (Гц)');
|
||||||
|
ylabel('Фаза (градусы)');
|
||||||
|
title('ФЧХ полного фильтра (дифференциатор + полосовой)');
|
||||||
|
|
||||||
|
%% 6. МОДЕЛИРОВАНИЕ ВО ВРЕМЕННОЙ ОБЛАСТИ
|
||||||
|
% Создаем тестовый сигнал
|
||||||
|
duration = 0.2; % 200 мс
|
||||||
|
t = 0:1/sample_freq:duration;
|
||||||
|
|
||||||
|
% Сигнал 50 Гц + шум
|
||||||
|
signal_freq = 50;
|
||||||
|
signal = sin(2*pi*signal_freq*t) + 0.1*randn(size(t));
|
||||||
|
|
||||||
|
% Имитация работы твоего кода на C
|
||||||
|
% Прямая форма II с дифференциатором
|
||||||
|
x1 = 0; x2 = 0; % Состояния входа фильтра
|
||||||
|
y1 = 0; y2 = 0; % Состояния выхода фильтра
|
||||||
|
prev_input = 0; % Для дифференциатора
|
||||||
|
|
||||||
|
filtered_signal = zeros(size(signal));
|
||||||
|
|
||||||
|
for i = 1:length(signal)
|
||||||
|
% 1. Дифференциатор
|
||||||
|
diff = signal(i);
|
||||||
|
prev_input = signal(i);
|
||||||
|
|
||||||
|
% 2. Полосовой фильтр (прямая форма II)
|
||||||
|
y = b0*diff + b1*x1 + b2*x2 - a1*y1 - a2*y2;
|
||||||
|
|
||||||
|
% 3. Обновление состояний
|
||||||
|
x2 = x1;
|
||||||
|
x1 = diff;
|
||||||
|
y2 = y1;
|
||||||
|
y1 = y;
|
||||||
|
|
||||||
|
filtered_signal(i) = y;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Встроенная функция MATLAB для сравнения
|
||||||
|
filtered_matlab = filter(b_total, a_total, signal);
|
||||||
|
|
||||||
|
figure();
|
||||||
|
|
||||||
|
% Сигнал и выход
|
||||||
|
subplot(2,1,1);
|
||||||
|
plot(t, signal, 'b', 'LineWidth', 1);
|
||||||
|
hold on; grid on;
|
||||||
|
plot(t, filtered_signal, 'r', 'LineWidth', 2);
|
||||||
|
plot(t, filtered_matlab, 'g--', 'LineWidth', 1);
|
||||||
|
xlabel('Время (с)');
|
||||||
|
ylabel('Амплитуда');
|
||||||
|
legend('Исходный сигнал', 'Наш фильтр (имитация C)', 'MATLAB filter()', ...
|
||||||
|
'Location', 'best');
|
||||||
|
title(sprintf('Тестовый сигнал: %d Гц + помеха 150 Гц + шум', signal_freq));
|
||||||
|
|
||||||
|
% Ошибка между нашей реализацией и MATLAB
|
||||||
|
subplot(2,1,2);
|
||||||
|
error = filtered_signal - filtered_matlab;
|
||||||
|
plot(t, error, 'k', 'LineWidth', 1);
|
||||||
|
grid on;
|
||||||
|
xlabel('Время (с)');
|
||||||
|
ylabel('Ошибка');
|
||||||
|
title('Разница между нашей реализацией и MATLAB filter()');
|
||||||
|
fprintf('\nМаксимальная ошибка: %.2e\n', max(abs(error)));
|
||||||
|
|
||||||
|
%% 7. АНАЛИЗ НА ЧАСТОТЕ 50 Гц
|
||||||
|
freq_test = 50;
|
||||||
|
w_test = 2*pi*freq_test/sample_freq;
|
||||||
|
z = exp(1i*w_test);
|
||||||
|
|
||||||
|
% Передаточная функция полного фильтра
|
||||||
|
H_z = (b0 + b1*z^-1 + b2*z^-2) / (1 + a1*z^-1 + a2*z^-2) * (1 - z^-1);
|
||||||
|
|
||||||
|
fprintf('\n══════════════════════════════════════════════════\n');
|
||||||
|
fprintf('АНАЛИЗ НА %d Гц:\n', freq_test);
|
||||||
|
fprintf('Усиление: %.3f (%.2f дБ)\n', abs(H_z), 20*log10(abs(H_z)));
|
||||||
|
fprintf('Фазовый сдвиг: %.1f градусов\n', angle(H_z)*180/pi);
|
||||||
|
fprintf('Задержка: %.2f мс (фазовая)\n', -angle(H_z)*1000/(2*pi*freq_test));
|
||||||
|
fprintf('══════════════════════════════════════════════════\n');
|
||||||
|
|
||||||
|
%% 8. ГРАФИК ПОЛЮСОВ И НУЛЕЙ
|
||||||
|
figure();
|
||||||
|
|
||||||
|
% Единичная окружность
|
||||||
|
theta = linspace(0, 2*pi, 100);
|
||||||
|
plot(cos(theta), sin(theta), 'k--', 'LineWidth', 1);
|
||||||
|
hold on; grid on; axis equal;
|
||||||
|
|
||||||
|
% Полюса (красные кресты)
|
||||||
|
plot(real(poles), imag(poles), 'rx', 'MarkerSize', 15, 'LineWidth', 2);
|
||||||
|
|
||||||
|
% Нули полосового фильтра
|
||||||
|
zeros_bp = roots([b0, b1, b2]);
|
||||||
|
plot(real(zeros_bp), imag(zeros_bp), 'bo', 'MarkerSize', 10, 'LineWidth', 2);
|
||||||
|
|
||||||
|
% Нули дифференциатора (z=1)
|
||||||
|
plot(1, 0, 'go', 'MarkerSize', 10, 'LineWidth', 2);
|
||||||
|
|
||||||
|
xlim([-1.2, 1.2]);
|
||||||
|
ylim([-1.2, 1.2]);
|
||||||
|
xlabel('Re(z)');
|
||||||
|
ylabel('Im(z)');
|
||||||
|
title('Диаграмма полюсов и нулей фильтра');
|
||||||
|
legend('Единичная окружность', 'Полюса', 'Нули полосового фильтра', ...
|
||||||
|
'Нуль дифференциатора (z=1)', 'Location', 'best');
|
||||||
Reference in New Issue
Block a user