From 8041598cc5bcf1038fd77e05b91ca2ccd3d05ed4 Mon Sep 17 00:00:00 2001 From: Razvalyaev Date: Sat, 15 Nov 2025 19:08:50 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9A=D1=83=D1=83=D1=83=D1=87=D0=B0=20=D0=B2?= =?UTF-8?q?=D1=81=D1=8F=D0=BA=D0=BE=D0=B9=20=D0=BB=D0=BE=D0=B3=D0=B8=D0=BA?= =?UTF-8?q?=D0=B8=20=D0=B4=D0=BB=D1=8F=20=D1=83=D0=BF=D1=80=D0=B0=D0=B2?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D1=82=D0=B8=D1=80=D0=B8=D1=81?= =?UTF-8?q?=D1=82=D0=BE=D1=80=D0=B0=D0=BC=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Запустилось но неправильно пока --- .../Drivers/STM32_SIMULINK/stm32_matlab_tim.c | 370 ++++++++++-------- MATLAB/app_wrapper/app_includes.h | 2 - MATLAB/app_wrapper/app_init.c | 1 + MATLAB/app_wrapper/app_io.c | 18 +- MATLAB/upp_init.m | 8 + MATLAB/upp_r2023.slx | Bin 61888 -> 62859 bytes UPP/AllLibs/MyLibs | 2 +- UPP/AllLibs/PeriphGeneral | 2 +- UPP/Core/Configs/mylibs_config.h | 2 +- UPP/Core/Configs/upp_config.h | 30 +- UPP/Core/Inc/main.h | 8 +- UPP/Core/Inc/stm32f4xx_it.h | 2 + UPP/Core/Inc/tim.h | 3 + UPP/Core/PowerMonitor/adc_tools.c | 12 +- UPP/Core/PowerMonitor/adc_tools.h | 1 + UPP/Core/PowerMonitor/power_monitor.c | 16 +- UPP/Core/PowerMonitor/power_monitor.h | 3 +- UPP/Core/PowerMonitor/zero_cross.c | 126 +++--- UPP/Core/PowerMonitor/zero_cross.h | 46 +-- UPP/Core/Src/main.c | 1 + UPP/Core/Src/stm32f4xx_it.c | 34 +- UPP/Core/Src/tim.c | 119 +++++- UPP/Core/UPP/angle_control.c | 167 ++++++++ UPP/Core/UPP/angle_control.h | 30 ++ UPP/Core/UPP/pwm_thyristors.c | 303 ++++++++++++++ UPP/Core/UPP/pwm_thyristors.h | 114 ++++++ UPP/Core/UPP/upp_main.c | 62 ++- UPP/Core/UPP/upp_main.h | 14 + UPP/MDK-ARM/UPP.uvoptx | 334 +++++++++------- UPP/MDK-ARM/UPP.uvprojx | 23 +- UPP/UPP.ioc | 74 +++- 31 files changed, 1445 insertions(+), 482 deletions(-) create mode 100644 MATLAB/upp_init.m create mode 100644 UPP/Core/UPP/angle_control.c create mode 100644 UPP/Core/UPP/angle_control.h create mode 100644 UPP/Core/UPP/pwm_thyristors.c create mode 100644 UPP/Core/UPP/pwm_thyristors.h diff --git a/MATLAB/MCU_STM32_Matlab/Drivers/STM32_SIMULINK/stm32_matlab_tim.c b/MATLAB/MCU_STM32_Matlab/Drivers/STM32_SIMULINK/stm32_matlab_tim.c index 46b9f21..c8210a1 100644 --- a/MATLAB/MCU_STM32_Matlab/Drivers/STM32_SIMULINK/stm32_matlab_tim.c +++ b/MATLAB/MCU_STM32_Matlab/Drivers/STM32_SIMULINK/stm32_matlab_tim.c @@ -91,167 +91,215 @@ void Channels_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS) /* Выбор режима CaptureCompare или PWM и симуляция для каждого канала */ void CC_PWM_Ch1_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS) { // определяет режим канала -switch (TIMx->CCMR1 & TIM_CCMR1_OC1M) -{ - case (TIM_OCMODE_ACTIVE): // ACTIVE mode - if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step) - TIMS->Channels.OC1REF = 1; - break; + switch (TIMx->CCMR1 & TIM_CCMR1_OC1M) + { + case (TIM_OCMODE_ACTIVE): // ACTIVE mode + if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step) + TIMS->Channels.OC1REF = 1; + break; - case (TIM_OCMODE_INACTIVE): // INACTIVE mode - if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step) - TIMS->Channels.OC1REF = 0; - break; + case (TIM_OCMODE_INACTIVE): // INACTIVE mode + if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step) + TIMS->Channels.OC1REF = 0; + break; - case (TIM_OCMODE_TOGGLE): // TOOGLE mode - if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step) - TIMS->Channels.OC1REF = ~TIMS->Channels.OC1REF; - break; + case (TIM_OCMODE_TOGGLE): // TOOGLE mode + if (abs(TIMx->CNT - TIMx->CCR1) < 2*TIMS->tx_step) + TIMS->Channels.OC1REF = ~TIMS->Channels.OC1REF; + break; - case (TIM_OCMODE_PWM1): // PWM MODE 1 mode - if (TIMx->CNT < TIMx->CCR1) - TIMS->Channels.OC1REF = 1; - else - TIMS->Channels.OC1REF = 0; - break; + case (TIM_OCMODE_PWM1): // PWM MODE 1 mode + if (TIMx->CNT < TIMx->CCR1) + TIMS->Channels.OC1REF = 1; + else + TIMS->Channels.OC1REF = 0; + break; - case (TIM_OCMODE_PWM2): // PWM MODE 2 mode - if (TIMx->CNT < TIMx->CCR1) - TIMS->Channels.OC1REF = 0; - else - TIMS->Channels.OC1REF = 1; - break; + case (TIM_OCMODE_PWM2): // PWM MODE 2 mode + if (TIMx->CNT < TIMx->CCR1) + TIMS->Channels.OC1REF = 0; + else + TIMS->Channels.OC1REF = 1; + break; - case (TIM_OCMODE_FORCED_ACTIVE): // FORCED ACTIVE mode - TIMS->Channels.OC1REF = 1; break; + case (TIM_OCMODE_FORCED_ACTIVE): // FORCED ACTIVE mode + TIMS->Channels.OC1REF = 1; break; - case (TIM_OCMODE_FORCED_INACTIVE): // FORCED INACTIVE mode - TIMS->Channels.OC1REF = 0; break; + case (TIM_OCMODE_FORCED_INACTIVE): // FORCED INACTIVE mode + TIMS->Channels.OC1REF = 0; break; -} + } + if (TIMx->DIER & TIM_IT_CC1) + { + TIMx->SR |= TIM_SR_CC1IF; + if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR1) && (TIMS->tx_cnt >= TIMx->CCR1)) + { + TIM_Call_IRQHandller(TIMx); + } + else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR1) && (TIMS->tx_cnt <= TIMx->CCR1)) + { + TIM_Call_IRQHandller(TIMx); + } + } } void CC_PWM_Ch2_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS) { // определяет режим канала -switch (TIMx->CCMR1 & TIM_CCMR1_OC2M) -{ - case ((TIM_OCMODE_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // ACTIVE mode - if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step) - TIMS->Channels.OC2REF = 1; - break; + switch (TIMx->CCMR1 & TIM_CCMR1_OC2M) + { + case ((TIM_OCMODE_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // ACTIVE mode + if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step) + TIMS->Channels.OC2REF = 1; + break; - case ((TIM_OCMODE_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // INACTIVE mode - if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step) - TIMS->Channels.OC2REF = 0; - break; + case ((TIM_OCMODE_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // INACTIVE mode + if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step) + TIMS->Channels.OC2REF = 0; + break; - case ((TIM_OCMODE_TOGGLE) << (TIM_OCMODE_SECOND_SHIFT)): // Toogle mode - if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step) - TIMS->Channels.OC2REF = ~TIMS->Channels.OC2REF; - break; + case ((TIM_OCMODE_TOGGLE) << (TIM_OCMODE_SECOND_SHIFT)): // Toogle mode + if (abs(TIMx->CNT - TIMx->CCR2) < 2*TIMS->tx_step) + TIMS->Channels.OC2REF = ~TIMS->Channels.OC2REF; + break; - case ((TIM_OCMODE_PWM1) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 1 mode - if (TIMx->CNT < TIMx->CCR2) - TIMS->Channels.OC2REF = 1; - else - TIMS->Channels.OC2REF = 0; - break; + case ((TIM_OCMODE_PWM1) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 1 mode + if (TIMx->CNT < TIMx->CCR2) + TIMS->Channels.OC2REF = 1; + else + TIMS->Channels.OC2REF = 0; + break; - case ((TIM_OCMODE_PWM2) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 2 mode - if (TIMx->CNT < TIMx->CCR2) - TIMS->Channels.OC2REF = 0; - else - TIMS->Channels.OC2REF = 1; - break; + case ((TIM_OCMODE_PWM2) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 2 mode + if (TIMx->CNT < TIMx->CCR2) + TIMS->Channels.OC2REF = 0; + else + TIMS->Channels.OC2REF = 1; + break; - case ((TIM_OCMODE_FORCED_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED ACTIVE mode - TIMS->Channels.OC2REF = 1; break; + case ((TIM_OCMODE_FORCED_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED ACTIVE mode + TIMS->Channels.OC2REF = 1; break; - case ((TIM_OCMODE_FORCED_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED INACTIVE mode - TIMS->Channels.OC2REF = 0; break; + case ((TIM_OCMODE_FORCED_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED INACTIVE mode + TIMS->Channels.OC2REF = 0; break; -} + } + if (TIMx->DIER & TIM_IT_CC2) + { + TIMx->SR |= TIM_SR_CC2IF; + if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR2) && (TIMS->tx_cnt >= TIMx->CCR2)) + { + TIM_Call_IRQHandller(TIMx); + } + else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR2) && (TIMS->tx_cnt <= TIMx->CCR2)) + { + TIM_Call_IRQHandller(TIMx); + } + } } void CC_PWM_Ch3_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS) { // определяет режим канала -switch (TIMx->CCMR2 & TIM_CCMR1_OC1M) -{ - case (TIM_OCMODE_ACTIVE): // ACTIVE mode - if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step) - TIMS->Channels.OC3REF = 1; - break; + switch (TIMx->CCMR2 & TIM_CCMR1_OC1M) + { + case (TIM_OCMODE_ACTIVE): // ACTIVE mode + if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step) + TIMS->Channels.OC3REF = 1; + break; - case (TIM_OCMODE_INACTIVE): // INACTIVE mode - if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step) - TIMS->Channels.OC3REF = 0; - break; + case (TIM_OCMODE_INACTIVE): // INACTIVE mode + if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step) + TIMS->Channels.OC3REF = 0; + break; - case (TIM_OCMODE_TOGGLE): // Toogle mode - if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step) - TIMS->Channels.OC3REF = ~TIMS->Channels.OC3REF; - break; + case (TIM_OCMODE_TOGGLE): // Toogle mode + if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step) + TIMS->Channels.OC3REF = ~TIMS->Channels.OC3REF; + break; - case (TIM_OCMODE_PWM1): // PWM mode 1 mode - if (TIMx->CNT < TIMx->CCR3) - TIMS->Channels.OC3REF = 1; - else - TIMS->Channels.OC3REF = 0; - break; + case (TIM_OCMODE_PWM1): // PWM mode 1 mode + if (TIMx->CNT < TIMx->CCR3) + TIMS->Channels.OC3REF = 1; + else + TIMS->Channels.OC3REF = 0; + break; - case (TIM_OCMODE_PWM2): // PWM mode 2 mode - if (TIMx->CNT < TIMx->CCR3) - TIMS->Channels.OC3REF = 0; - else - TIMS->Channels.OC3REF = 1; - break; + case (TIM_OCMODE_PWM2): // PWM mode 2 mode + if (TIMx->CNT < TIMx->CCR3) + TIMS->Channels.OC3REF = 0; + else + TIMS->Channels.OC3REF = 1; + break; - case (TIM_OCMODE_FORCED_ACTIVE): // FORCED ACTIVE mode - TIMS->Channels.OC3REF = 1; break; + case (TIM_OCMODE_FORCED_ACTIVE): // FORCED ACTIVE mode + TIMS->Channels.OC3REF = 1; break; - case (TIM_OCMODE_FORCED_INACTIVE): // FORCED INACTIVE mode - TIMS->Channels.OC3REF = 0; break; + case (TIM_OCMODE_FORCED_INACTIVE): // FORCED INACTIVE mode + TIMS->Channels.OC3REF = 0; break; -} + } + if (TIMx->DIER & TIM_IT_CC3) + { + TIMx->SR |= TIM_SR_CC3IF; + if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR3) && (TIMS->tx_cnt >= TIMx->CCR3)) + { + TIM_Call_IRQHandller(TIMx); + } + else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR3) && (TIMS->tx_cnt <= TIMx->CCR3)) + { + TIM_Call_IRQHandller(TIMx); + } + } } void CC_PWM_Ch4_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS) { // определяет режим канала -switch (TIMx->CCMR1 & TIM_CCMR1_OC2M) -{ - case ((TIM_OCMODE_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // ACTIVE mode - if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step) - TIMS->Channels.OC4REF = 1; - break; + switch (TIMx->CCMR1 & TIM_CCMR1_OC2M) + { + case ((TIM_OCMODE_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // ACTIVE mode + if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step) + TIMS->Channels.OC4REF = 1; + break; - case ((TIM_OCMODE_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // INACTIVE mode - if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step) - TIMS->Channels.OC4REF = 0; - break; + case ((TIM_OCMODE_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // INACTIVE mode + if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step) + TIMS->Channels.OC4REF = 0; + break; - case ((TIM_OCMODE_TOGGLE) << (TIM_OCMODE_SECOND_SHIFT)): // Toogle mode - if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step) - TIMS->Channels.OC4REF = ~TIMS->Channels.OC4REF; - break; + case ((TIM_OCMODE_TOGGLE) << (TIM_OCMODE_SECOND_SHIFT)): // Toogle mode + if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step) + TIMS->Channels.OC4REF = ~TIMS->Channels.OC4REF; + break; - case ((TIM_OCMODE_PWM1) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 1 mode - if (TIMx->CNT < TIMx->CCR4) - TIMS->Channels.OC4REF = 1; - else - TIMS->Channels.OC4REF = 0; - break; + case ((TIM_OCMODE_PWM1) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 1 mode + if (TIMx->CNT < TIMx->CCR4) + TIMS->Channels.OC4REF = 1; + else + TIMS->Channels.OC4REF = 0; + break; - case ((TIM_OCMODE_PWM2) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 2 mode - if (TIMx->CNT < TIMx->CCR4) - TIMS->Channels.OC4REF = 0; - else - TIMS->Channels.OC4REF = 1; - break; + case ((TIM_OCMODE_PWM2) << (TIM_OCMODE_SECOND_SHIFT)): // PWM mode 2 mode + if (TIMx->CNT < TIMx->CCR4) + TIMS->Channels.OC4REF = 0; + else + TIMS->Channels.OC4REF = 1; + break; - case ((TIM_OCMODE_FORCED_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED ACTIVE mode - TIMS->Channels.OC4REF = 1; break; + case ((TIM_OCMODE_FORCED_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED ACTIVE mode + TIMS->Channels.OC4REF = 1; break; - case ((TIM_OCMODE_FORCED_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED INACTIVE mode - TIMS->Channels.OC4REF = 0; break; + case ((TIM_OCMODE_FORCED_INACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // FORCED INACTIVE mode + TIMS->Channels.OC4REF = 0; break; -} + } + if (TIMx->DIER & TIM_IT_CC4) + { + TIMx->SR |= TIM_SR_CC4IF; + if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR4) && (TIMS->tx_cnt >= TIMx->CCR4)) + { + TIM_Call_IRQHandller(TIMx); + } + else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR4) && (TIMS->tx_cnt <= TIMx->CCR4)) + { + TIM_Call_IRQHandller(TIMx); + } + } } /* Запись каналов таймера в порты GPIO */ void Write_OC_to_GPIO(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS) @@ -565,70 +613,68 @@ void TIM_SIM_DEINIT(void) // Т.к. в MSVC нет понятия weak function, необходимо объявить все колбеки // И если какой-то колбек не используется, его надо определить //#ifndef USE_TIM1_UP_TIM10_HANDLER -//void TIM1_UP_TIM10_IRQHandler(void) {} +__weak void TIM1_UP_TIM10_IRQHandler(void) {} //#endif //#ifndef USE_TIM2_HANDLER -//void TIM2_IRQHandler(void) {} +__weak void TIM2_IRQHandler(void) {} //#endif //#ifndef USE_TIM3_HANDLER -//void TIM3_IRQHandler(void) {} +__weak void TIM3_IRQHandler(void) {} //#endif //#ifndef USE_TIM4_HANDLER -//void TIM4_IRQHandler(void) {} +__weak void TIM4_IRQHandler(void) {} //#endif //#ifndef USE_TIM5_HANDLER -//void TIM5_IRQHandler(void) {} +__weak void TIM5_IRQHandler(void) {} //#endif //#ifndef USE_TIM6_HANDLER -//void TIM6_DAC_IRQHandler(void) {} +__weak void TIM6_DAC_IRQHandler(void) {} //#endif //#ifndef USE_TIM7_HANDLER -//void TIM7_IRQHandler(void) {} +__weak void TIM7_IRQHandler(void) {} //#endif //#ifndef USE_TIM8_UP_TIM13_HANDLER -//void TIM8_UP_TIM13_IRQHandler(void) {} +__weak void TIM8_UP_TIM13_IRQHandler(void) {} //#endif //#ifndef USE_TIM1_BRK_TIM9_HANDLER -//void TIM1_BRK_TIM9_IRQHandler(void) {} +__weak void TIM1_BRK_TIM9_IRQHandler(void) {} //#endif //#ifndef USE_TIM1_TRG_COM_TIM11_HANDLER -//void TIM1_TRG_COM_TIM11_IRQHandler(void) {} +__weak void TIM1_TRG_COM_TIM11_IRQHandler(void) {} //#endif //#ifndef USE_TIM8_BRK_TIM12_HANDLER -//void TIM8_BRK_TIM12_IRQHandler(void) {} +__weak void TIM8_BRK_TIM12_IRQHandler(void) {} //#endif //#ifndef USE_TIM8_TRG_COM_TIM14_HANDLER -//void TIM8_TRG_COM_TIM14_IRQHandler(void) {} +__weak void TIM8_TRG_COM_TIM14_IRQHandler(void) {} //#endif /* Вызов прерывания */ void TIM_Call_IRQHandller(TIM_TypeDef* TIMx) { // calling HANDLER - //if (TIMx == TIM1) - // TIM1_UP_IRQHandler(); - //if ((TIMx == TIM1) || (TIMx == TIM10)) - // TIM1_UP_TIM10_IRQHandler(); - //else if (TIMx == TIM2) - // TIM2_IRQHandler(); - //else if (TIMx == TIM3) - // TIM3_IRQHandler(); - //else if (TIMx == TIM4) - // TIM4_IRQHandler(); - //else if (TIMx == TIM5) - // TIM5_IRQHandler(); - //else if (TIMx == TIM6) - // TIM6_DAC_IRQHandler(); - //else if (TIMx == TIM7) - // TIM7_IRQHandler(); - //else if ((TIMx == TIM8) || (TIMx == TIM13)) - // TIM8_UP_TIM13_IRQHandler(); - //else if ((TIMx == TIM1) || (TIMx == TIM9)) - // TIM1_BRK_TIM9_IRQHandler(); - //else if ((TIMx == TIM1) || (TIMx == TIM11)) - // TIM1_TRG_COM_TIM11_IRQHandler(); - //else if ((TIMx == TIM8) || (TIMx == TIM12)) - // TIM8_BRK_TIM12_IRQHandler(); - //else if ((TIMx == TIM8) || (TIMx == TIM14)) - // TIM8_TRG_COM_TIM14_IRQHandler(); + if ((TIMx == TIM1) || (TIMx == TIM10)) + TIM1_UP_TIM10_IRQHandler(); + else if (TIMx == TIM2) + TIM2_IRQHandler(); + else if (TIMx == TIM3) + TIM3_IRQHandler(); + else if (TIMx == TIM4) + TIM4_IRQHandler(); + else if (TIMx == TIM5) + TIM5_IRQHandler(); + else if (TIMx == TIM6) + TIM6_DAC_IRQHandler(); + else if (TIMx == TIM7) + TIM7_IRQHandler(); + else if ((TIMx == TIM8) || (TIMx == TIM13)) + TIM8_UP_TIM13_IRQHandler(); + else if ((TIMx == TIM1) || (TIMx == TIM9)) + TIM1_BRK_TIM9_IRQHandler(); + else if ((TIMx == TIM1) || (TIMx == TIM11)) + TIM1_TRG_COM_TIM11_IRQHandler(); + else if ((TIMx == TIM8) || (TIMx == TIM12)) + TIM8_BRK_TIM12_IRQHandler(); + else if ((TIMx == TIM8) || (TIMx == TIM14)) + TIM8_TRG_COM_TIM14_IRQHandler(); } //------------------------------------------------------------------// diff --git a/MATLAB/app_wrapper/app_includes.h b/MATLAB/app_wrapper/app_includes.h index 7f49c25..785ac41 100644 --- a/MATLAB/app_wrapper/app_includes.h +++ b/MATLAB/app_wrapper/app_includes.h @@ -14,8 +14,6 @@ #include "tim.h" #include "adc.h" #include "upp_main.h" -#include "adc_tools.h" -#include "power_monitor.h" // INCLUDES END #endif //_APP_INCLUDES_H_ \ No newline at end of file diff --git a/MATLAB/app_wrapper/app_init.c b/MATLAB/app_wrapper/app_init.c index 176d679..705b1e2 100644 --- a/MATLAB/app_wrapper/app_init.c +++ b/MATLAB/app_wrapper/app_init.c @@ -19,6 +19,7 @@ void app_init(void) { HAL_Init(); MX_DMA_Init(); MX_TIM1_Init(); + MX_TIM2_Init(); MX_TIM3_Init(); MX_TIM8_Init(); MX_TIM5_Init(); diff --git a/MATLAB/app_wrapper/app_io.c b/MATLAB/app_wrapper/app_io.c index f8400cd..8b6e497 100644 --- a/MATLAB/app_wrapper/app_io.c +++ b/MATLAB/app_wrapper/app_io.c @@ -31,23 +31,23 @@ void Write_PowerMonitor(real_T* Buffer, int ind_port) int nn = 0; for (int i = 0; i < 3; i++) { - WriteOutputArray(pm.U[i], ind_port, nn++); + WriteOutputArray(upp.pm.U[i], ind_port, nn++); } for (int i = 0; i < 3; i++) { - WriteOutputArray(pm.ZC_Detected[i], ind_port, nn++); + WriteOutputArray(upp.pm.zc.Channel[i].HalfWave, ind_port, nn++); } for (int i = 0; i < 3; i++) { - WriteOutputArray(pm.F[i], ind_port, nn++); + WriteOutputArray(upp.pm.F[i], ind_port, nn++); } for (int i = 0; i < 3; i++) { - WriteOutputArray(pm.I[i], ind_port, nn++); + WriteOutputArray(upp.pm.I[i], ind_port, nn++); } for (int i = 0; i < 2; i++) { - WriteOutputArray(pm.T[i], ind_port, nn++); + WriteOutputArray(upp.pm.T[i], ind_port, nn++); } } /** @@ -63,6 +63,7 @@ void app_readInputs(const real_T* Buffer) { ADC_Set_Channel_Value(ADC3, 8, ReadInputArray(0,4)); ADC_Set_Channel_Value(ADC3, 10, ReadInputArray(0,5)); + alpha_dbg = ReadInputArray(1, 0); // USER APP INPUT END } @@ -73,13 +74,12 @@ void app_readInputs(const real_T* Buffer) { */ void app_writeOutputBuffer(real_T* Buffer) { // USER APP OUTPUT START - //ThyristorWrite(Buffer, 0); + Write_Thyristors(Buffer, 0); Write_PowerMonitor(Buffer, 1); - WriteOutputArray(hmcu.dSFuncPeriod, 2, 12); - WriteOutputArray(hmcu.dSFuncTime, 2, 13); - WriteOutputArray(hmcu.dMCUStepTime, 2, 14); + WriteOutputArray(TIM2->CNT, 2, 0); + WriteOutputArray(TIM2->CCR1, 2, 1); // USER APP OUTPUT END } \ No newline at end of file diff --git a/MATLAB/upp_init.m b/MATLAB/upp_init.m new file mode 100644 index 0000000..7618676 --- /dev/null +++ b/MATLAB/upp_init.m @@ -0,0 +1,8 @@ +clear all + +Ts = 5e-6; +Vnom = 380; +Fnom = 50; + +Temperature1 = 2.22; % 20 градусов +Temperature2 = 2.99; % 34 градусов \ No newline at end of file diff --git a/MATLAB/upp_r2023.slx b/MATLAB/upp_r2023.slx index 9b886b6f9ea7d7ab3731af359b9e5477395669a5..857c6841b6b5a40f3d430ce41d5bf79562826c4a 100644 GIT binary patch delta 45131 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 P3yQy?gT6lhSLgo$;rd^J delta 44092 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 diff --git a/UPP/AllLibs/MyLibs b/UPP/AllLibs/MyLibs index 606058e..99652a9 160000 --- a/UPP/AllLibs/MyLibs +++ b/UPP/AllLibs/MyLibs @@ -1 +1 @@ -Subproject commit 606058ef552c6341c965bc76d3eda6929ca58e13 +Subproject commit 99652a9ad5ea0686ad9242b165508a9d92ac80a1 diff --git a/UPP/AllLibs/PeriphGeneral b/UPP/AllLibs/PeriphGeneral index 50c07cd..b3f118b 160000 --- a/UPP/AllLibs/PeriphGeneral +++ b/UPP/AllLibs/PeriphGeneral @@ -1 +1 @@ -Subproject commit 50c07cd0911d11106670d25d1457c45735eaa4fa +Subproject commit b3f118b074951fa827e5a692e9da7637b5397a98 diff --git a/UPP/Core/Configs/mylibs_config.h b/UPP/Core/Configs/mylibs_config.h index c87e783..cbc013d 100644 --- a/UPP/Core/Configs/mylibs_config.h +++ b/UPP/Core/Configs/mylibs_config.h @@ -131,7 +131,7 @@ #define INCLUDE_BIT_ACCESS_LIB ///< Подключить библиотеку с typedef с битовыми полями #define INCLUDE_TRACKERS_LIB ///< Подключить библиотеку с трекерами //#define INCLUDE_TRACE_LIB ///< Подключить библиотеку с трейсами -//#define INCLUDE_GENERAL_PERIPH_LIBS ///< Подключить библиотеку с периферией +#define INCLUDE_GENERAL_PERIPH_LIBS ///< Подключить библиотеку с периферией //#define INCLUDE_BENCH_TIME ///< Подключить библиотеку с бенчмарком времени #define INCLUDE_FILTERS ///< Подключить библиотеку с фильтрами diff --git a/UPP/Core/Configs/upp_config.h b/UPP/Core/Configs/upp_config.h index 5c60f54..1208474 100644 --- a/UPP/Core/Configs/upp_config.h +++ b/UPP/Core/Configs/upp_config.h @@ -14,7 +14,10 @@ #define _UPP_CONFIG_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 @@ -24,14 +27,39 @@ #define TEMP_1 0 #define TEMP_2 1 +/* Дефайны для базовых величин */ #define PM_U_BASE 1216.0 #define PM_I_BASE 53.0 + +/* Дефайны для настройки мониторинга питания */ #define PM_ADC_PERIOD_MKS 10 #define PM_ZERO_CROSS_HYSTERESIS_V 10 #define PM_ZERO_CROSS_DEBOUNCE_10US 2.5*100 // (2.5 * 100 = 2.5 мс) -// Рассчитанные дефайны + + +/* Рассчитанные дефайны */ #define PM_ADC_PERIOD (180*PM_ADC_PERIOD_MKS)-1 + +/* Общие для всего проекта структуры*/ +/** + * @brief Состояния полуволны + */ +typedef enum { + UPP_WAVE_UNKNOWED = 0, + UPP_WAVE_POSITIVE, + UPP_WAVE_NEGATIVE +} UPP_HalfWave_t; +/** + * @brief Названия Фаз + */ +typedef enum { + UPP_PHASE_A = 0, + UPP_PHASE_B = 1, + UPP_PHASE_C = 2, + UPP_PHASE_UNKNOWN = 3 +} UPP_Phase_t; + #endif //_UPP_CONFIG_H_ diff --git a/UPP/Core/Inc/main.h b/UPP/Core/Inc/main.h index a2211ec..704767c 100644 --- a/UPP/Core/Inc/main.h +++ b/UPP/Core/Inc/main.h @@ -71,11 +71,15 @@ extern __IO uint32_t micros; #define PWM_CHANNEL_6 TIM_CHANNEL_4 #define mb_htim htim12 #define adc_tim htim8 -#define hpwm2 htim2 +#define usTick ustim.Instance->CNT +#define hpwm2 htim3 #define mb_dbg_huart huart6 #define ustim htim5 #define hpwm1 htim1 -#define usTick ustim.Instance->CNT +#define ANGLE_CHANNEL_1 TIM_CHANNEL_1 +#define ANGLE_CHANNEL_2 TIM_CHANNEL_2 +#define ANGLE_CHANNEL_3 TIM_CHANNEL_3 +#define angletim htim2 #define UM_LED_GREEN2_Pin GPIO_PIN_2 #define UM_LED_GREEN2_GPIO_Port GPIOE #define CEN_O_Pin GPIO_PIN_3 diff --git a/UPP/Core/Inc/stm32f4xx_it.h b/UPP/Core/Inc/stm32f4xx_it.h index 52044da..a95542f 100644 --- a/UPP/Core/Inc/stm32f4xx_it.h +++ b/UPP/Core/Inc/stm32f4xx_it.h @@ -55,6 +55,8 @@ void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); +void TIM1_UP_TIM10_IRQHandler(void); +void TIM2_IRQHandler(void); void TIM8_TRG_COM_TIM14_IRQHandler(void); void DMA2_Stream0_IRQHandler(void); /* USER CODE BEGIN EFP */ diff --git a/UPP/Core/Inc/tim.h b/UPP/Core/Inc/tim.h index 6a9d43b..2b501c6 100644 --- a/UPP/Core/Inc/tim.h +++ b/UPP/Core/Inc/tim.h @@ -34,6 +34,8 @@ extern "C" { extern TIM_HandleTypeDef htim1; +extern TIM_HandleTypeDef htim2; + extern TIM_HandleTypeDef htim3; extern TIM_HandleTypeDef htim5; @@ -49,6 +51,7 @@ extern TIM_HandleTypeDef htim12; /* USER CODE END Private defines */ void MX_TIM1_Init(void); +void MX_TIM2_Init(void); void MX_TIM3_Init(void); void MX_TIM5_Init(void); void MX_TIM8_Init(void); diff --git a/UPP/Core/PowerMonitor/adc_tools.c b/UPP/Core/PowerMonitor/adc_tools.c index dbd81d7..5129c70 100644 --- a/UPP/Core/PowerMonitor/adc_tools.c +++ b/UPP/Core/PowerMonitor/adc_tools.c @@ -32,8 +32,6 @@ static float coefs_biquad_T[5] = { -1.98f, // a1 0.980f // a2 }; -// Проверка корректности структуры АЦП -#define assert_adc(_adc_) check_null_ptr_2(_adc_, (_adc_)->f.Initialized) static void ADC_EnableAllFilters(ADC_Periodic_t *adc) { @@ -100,7 +98,7 @@ HAL_StatusTypeDef ADC_Init(ADC_Periodic_t *adc, TIM_HandleTypeDef *htim, ADC_Han HAL_StatusTypeDef ADC_ConfigChannel(ADC_Periodic_t *adc, int ChNumb, uint16_t levelZero, float valueMax, uint16_t levelMax) { HAL_StatusTypeDef res; - if(assert_adc(adc)) + if(assert_upp(adc)) return HAL_ERROR; if((valueMax == 0) || (levelMax == 0)) return HAL_ERROR; @@ -121,7 +119,7 @@ HAL_StatusTypeDef ADC_ConfigChannel(ADC_Periodic_t *adc, int ChNumb, uint16_t le HAL_StatusTypeDef ADC_Start(ADC_Periodic_t *adc, uint16_t Period) { HAL_StatusTypeDef res; - if(assert_adc(adc)) + if(assert_upp(adc)) return HAL_ERROR; if(Period == 0) return HAL_ERROR; @@ -154,7 +152,7 @@ HAL_StatusTypeDef ADC_Start(ADC_Periodic_t *adc, uint16_t Period) */ HAL_StatusTypeDef ADC_Stop(ADC_Periodic_t *adc) { - if(assert_adc(adc)) + if(assert_upp(adc)) return HAL_ERROR; // Запускаем таймер который будет запускать опрос АЦП @@ -170,7 +168,7 @@ HAL_StatusTypeDef ADC_Stop(ADC_Periodic_t *adc) */ HAL_StatusTypeDef ADC_Handle(ADC_Periodic_t *adc) { - if(assert_adc(adc)) + if(assert_upp(adc)) return HAL_ERROR; ADC_Coefs_t *coefs = adc->Coefs; @@ -219,7 +217,7 @@ void ADC_UpdateStatistics(ADC_Periodic_t *adc, uint8_t channel, ADC_StatLevel_t { if (level < ADC_LEVEL_BASE) return; - if(assert_adc(adc)) + if(assert_upp(adc)) return; if (channel >= ADC_NUMB_OF_REGULAR_CHANNELS) return; diff --git a/UPP/Core/PowerMonitor/adc_tools.h b/UPP/Core/PowerMonitor/adc_tools.h index 12da5ae..e61e16b 100644 --- a/UPP/Core/PowerMonitor/adc_tools.h +++ b/UPP/Core/PowerMonitor/adc_tools.h @@ -126,6 +126,7 @@ HAL_StatusTypeDef ADC_ConfigChannel(ADC_Periodic_t *adc, int ChNumb, uint16_t le HAL_StatusTypeDef ADC_Start(ADC_Periodic_t *adc, uint16_t Period); /* Остановка АЦП. */ HAL_StatusTypeDef ADC_Stop(ADC_Periodic_t *adc); + /* Обработка АЦП после получения данных. */ HAL_StatusTypeDef ADC_Handle(ADC_Periodic_t *adc); diff --git a/UPP/Core/PowerMonitor/power_monitor.c b/UPP/Core/PowerMonitor/power_monitor.c index 53f5f3e..f4dcf07 100644 --- a/UPP/Core/PowerMonitor/power_monitor.c +++ b/UPP/Core/PowerMonitor/power_monitor.c @@ -43,7 +43,7 @@ HAL_StatusTypeDef PowerMonitor_Start(PowerMonitor_t *hpm) { if(ADC_Start(&hpm->adc, PM_ADC_PERIOD) != HAL_OK) return HAL_ERROR; - + return HAL_OK; } @@ -51,8 +51,7 @@ HAL_StatusTypeDef PowerMonitor_Start(PowerMonitor_t *hpm) void PowerMonitor_Handle(PowerMonitor_t *hpm) { - - static uint32_t last_zc_state[ADC_NUMB_OF_U_CHANNELS] = {0}; + static uint32_t last_zc_cnt[ADC_NUMB_OF_U_CHANNELS] = {0}; ADC_Handle(&hpm->adc); hpm->U[U_BA] = hpm->adc.Data[ADC_CHANNEL_UBA]; @@ -69,14 +68,7 @@ void PowerMonitor_Handle(PowerMonitor_t *hpm) ZC_ProcessAllChannels(&hpm->zc, hpm->U, usTick); for(int i = 0; i < 3; i++) { - if(last_zc_state[i] != ZC_GetStableState(&hpm->zc, i)) - { - last_zc_state[i] = ZC_GetStableState(&hpm->zc, i); - hpm->ZC_Detected[i] = !hpm->ZC_Detected[i]; - } + + hpm->F[i] = ZC_GetFrequency(&hpm->zc, i) / 2; } - - hpm->F[U_BA] = (hpm->zc.Channel[U_BA].Frequency) / 2; - hpm->F[U_AC] = (hpm->zc.Channel[U_AC].Frequency) / 2; - hpm->F[U_BC] = (hpm->zc.Channel[U_BC].Frequency) / 2; } \ No newline at end of file diff --git a/UPP/Core/PowerMonitor/power_monitor.h b/UPP/Core/PowerMonitor/power_monitor.h index 54ac6e6..56bf1cd 100644 --- a/UPP/Core/PowerMonitor/power_monitor.h +++ b/UPP/Core/PowerMonitor/power_monitor.h @@ -10,11 +10,12 @@ #include "adc_tools.h" #include "zero_cross.h" + typedef struct { ADC_Periodic_t adc; ZeroCross_Handle_t zc; - uint32_t ZC_Detected[3]; + UPP_HalfWave_t CurrentHalfWave[3]; float U[3]; float F[3]; diff --git a/UPP/Core/PowerMonitor/zero_cross.c b/UPP/Core/PowerMonitor/zero_cross.c index e6ae71f..d587251 100644 --- a/UPP/Core/PowerMonitor/zero_cross.c +++ b/UPP/Core/PowerMonitor/zero_cross.c @@ -38,7 +38,6 @@ HAL_StatusTypeDef ZC_Init(ZeroCross_Handle_t *zc, uint8_t num_channels, zc->Channel[i].LastValue = 0.0f; zc->Channel[i].CurrentValue = 0.0f; zc->Channel[i].DebounceCounter = 0; - zc->Channel[i].StableState = 0; zc->Channel[i].LastCrossTime = 0; zc->Channel[i].Period = 0; zc->Channel[i].Frequency = 0.0f; @@ -61,10 +60,9 @@ HAL_StatusTypeDef ZC_Init(ZeroCross_Handle_t *zc, uint8_t num_channels, HAL_StatusTypeDef ZC_ConfigChannel(ZeroCross_Handle_t *zc, uint8_t channel, ZC_EdgeType_t edgeType) { - if (zc == NULL || !zc->f.Initialized) { + if (assert_upp(zc)){ return HAL_ERROR; } - if (channel >= zc->NumChannels) { return HAL_ERROR; } @@ -74,7 +72,6 @@ HAL_StatusTypeDef ZC_ConfigChannel(ZeroCross_Handle_t *zc, uint8_t channel, // Сброс состояния канала при реконфигурации zc->Channel[channel].LastValue = 0.0f; zc->Channel[channel].DebounceCounter = 0; - zc->Channel[channel].StableState = 0; zc->Channel[channel].LastCrossTime = 0; zc->Channel[channel].Period = 0; zc->Channel[channel].Frequency = 0.0f; @@ -91,7 +88,10 @@ HAL_StatusTypeDef ZC_ConfigChannel(ZeroCross_Handle_t *zc, uint8_t channel, */ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uint32_t timestamp) { - if (zc == NULL || !zc->f.Initialized || !zc->f.Monitoring) { + if (assert_upp(zc)){ + return; + } + if (!zc->f.Monitoring) { return; } if (channel >= zc->NumChannels) { @@ -147,9 +147,9 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin if(zc_detected) { - zc_ch->StableState = zc_detected == 1? 1:0; - - uint32_t RealTimeShift = zc->DebounceSamples*(timestamp - zc->LastTick); // коло-во тиков * период вызова функции + zc_ch->HalfWave = zc_detected == 1 ? UPP_WAVE_POSITIVE : UPP_WAVE_NEGATIVE; + zc_ch->Occurred = 1; + uint32_t RealTimeShift = 0;//zc->DebounceSamples*(timestamp - zc->LastTick); // коло-во тиков * период вызова функции // Переход подтвержден сразу uint32_t RealTimestamp = timestamp-RealTimeShift; @@ -180,7 +180,11 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin */ void ZC_ProcessAllChannels(ZeroCross_Handle_t *zc, float *values, uint32_t timestamp) { - if (zc == NULL || !zc->f.Initialized || !zc->f.Monitoring || values == NULL) { + if (assert_upp(zc)){ + return; + } + + if (!zc->f.Monitoring || values == NULL) { return; } @@ -191,6 +195,38 @@ void ZC_ProcessAllChannels(ZeroCross_Handle_t *zc, float *values, uint32_t times zc->LastTick = timestamp; } + +/** + * @brief Полученить флаг - переход произошел. + * @param zc Указатель на хендл детектора нуля + * @param channel Номер канала + * @return 1 - переход произошел, 0 - перехода не было. + */ +int ZC_isOccurred(ZeroCross_Handle_t *zc, uint8_t channel) +{ + if (assert_upp(zc)){ + return 0; + } + int occurred = zc->Channel[channel].Occurred; + zc->Channel[channel].Occurred = 0; + return occurred; +} + +/** + * @brief Получение полуволны (после последнего zero-cross). + * @param zc Указатель на хендл детектора нуля + * @param channel Номер канала + * @return Текущая полуволна @ref UPP_HalfWave_t. + */ +UPP_HalfWave_t ZC_GetHalfWave(ZeroCross_Handle_t *zc, uint8_t channel) +{ + if (assert_upp(zc)){ + return UPP_WAVE_UNKNOWED; + } + + return zc->Channel[channel].HalfWave; +} + /** * @brief Получение частоты сигнала. * @param zc Указатель на хендл детектора нуля @@ -199,73 +235,16 @@ void ZC_ProcessAllChannels(ZeroCross_Handle_t *zc, float *values, uint32_t times */ float ZC_GetFrequency(ZeroCross_Handle_t *zc, uint8_t channel) { - if (zc == NULL || !zc->f.Initialized || channel >= zc->NumChannels) { + if (assert_upp(zc)){ + return 0.0f; + } + if (channel >= zc->NumChannels) { return 0.0f; } return zc->Channel[channel].Frequency; } -/** - * @brief Получение периода сигнала. - * @param zc Указатель на хендл детектора нуля - * @param channel Номер канала - * @return Период в тактах таймера. - */ -uint32_t ZC_GetPeriod(ZeroCross_Handle_t *zc, uint8_t channel) -{ - if (zc == NULL || !zc->f.Initialized || channel >= zc->NumChannels) { - return 0; - } - - return zc->Channel[channel].Period; -} - -/** - * @brief Получение счетчика переходов. - * @param zc Указатель на хендл детектора нуля - * @param channel Номер канала - * @return Количество переходов. - */ -uint32_t ZC_GetCrossCount(ZeroCross_Handle_t *zc, uint8_t channel) -{ - if (zc == NULL || !zc->f.Initialized || channel >= zc->NumChannels) { - return 0; - } - - return zc->Channel[channel].CrossCount; -} - -/** - * @brief Получение текущего состояния канала. - * @param zc Указатель на хендл детектора нуля - * @param channel Номер канала - * @return Состояние (0 - отрицательное, 1 - положительное). - */ -uint8_t ZC_GetStableState(ZeroCross_Handle_t *zc, uint8_t channel) -{ - if (zc == NULL || !zc->f.Initialized || channel >= zc->NumChannels) { - return 0; - } - - return zc->Channel[channel].StableState; -} - -/** - * @brief Получение текущего значения канала. - * @param zc Указатель на хендл детектора нуля - * @param channel Номер канала - * @return Текущее значение сигнала. - */ -float ZC_GetCurrentValue(ZeroCross_Handle_t *zc, uint8_t channel) -{ - if (zc == NULL || !zc->f.Initialized || channel >= zc->NumChannels) { - return 0.0f; - } - - return zc->Channel[channel].CurrentValue; -} - /** * @brief Включение/выключение мониторинга. * @param zc Указатель на хендл детектора нуля @@ -273,6 +252,9 @@ float ZC_GetCurrentValue(ZeroCross_Handle_t *zc, uint8_t channel) */ void ZC_EnableMonitoring(ZeroCross_Handle_t *zc, uint8_t enable) { + if (assert_upp(zc)){ + return; + } if (zc == NULL || !zc->f.Initialized) { return; } @@ -287,7 +269,7 @@ void ZC_EnableMonitoring(ZeroCross_Handle_t *zc, uint8_t enable) */ void ZC_Reset(ZeroCross_Handle_t *zc, uint8_t channel) { - if (zc == NULL || !zc->f.Initialized) { + if (assert_upp(zc)){ return; } @@ -295,7 +277,6 @@ void ZC_Reset(ZeroCross_Handle_t *zc, uint8_t channel) zc->Channel[channel].LastValue = 0.0f; zc->Channel[channel].CurrentValue = 0.0f; zc->Channel[channel].DebounceCounter = 0; - zc->Channel[channel].StableState = 0; zc->Channel[channel].LastCrossTime = 0; zc->Channel[channel].Period = 0; zc->Channel[channel].Frequency = 0.0f; @@ -307,7 +288,6 @@ void ZC_Reset(ZeroCross_Handle_t *zc, uint8_t channel) zc->Channel[i].LastValue = 0.0f; zc->Channel[i].CurrentValue = 0.0f; zc->Channel[i].DebounceCounter = 0; - zc->Channel[i].StableState = 0; zc->Channel[i].LastCrossTime = 0; zc->Channel[i].Period = 0; zc->Channel[i].Frequency = 0.0f; diff --git a/UPP/Core/PowerMonitor/zero_cross.h b/UPP/Core/PowerMonitor/zero_cross.h index fc91202..ba22f79 100644 --- a/UPP/Core/PowerMonitor/zero_cross.h +++ b/UPP/Core/PowerMonitor/zero_cross.h @@ -88,15 +88,16 @@ typedef enum { * @brief Структура канала детектора нуля */ typedef struct { - uint32_t CrossCount; ///< Счетчик переходов - float LastValue; ///< Предыдущее значение - float CurrentValue; ///< Текущее значение - uint16_t DebounceCounter; ///< Счетчик антидребезга - uint8_t StableState; ///< Стабильное состояние (0=отриц, 1=полож) - uint32_t LastCrossTime; ///< Время последнего перехода - uint32_t Period; ///< Период сигнала (в тактах таймера) - float Frequency; ///< Частота - ZC_EdgeType_t EdgeType; ///< Тип детектируемого перехода + uint8_t Occurred; ///< Флаг что пересечение нуля произошло + uint32_t CrossCount; ///< Счетчик переходов + float LastValue; ///< Предыдущее значение + float CurrentValue; ///< Текущее значение + uint16_t DebounceCounter; ///< Счетчик антидребезга + uint32_t LastCrossTime; ///< Время последнего перехода + uint32_t Period; ///< Период сигнала (в тактах таймера) + float Frequency; ///< Частота + UPP_HalfWave_t HalfWave; ///< Текущая полуволна + ZC_EdgeType_t EdgeType; ///< Тип детектируемого перехода } ZC_Channel_t; /** @@ -132,36 +133,17 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, void ZC_ProcessAllChannels(ZeroCross_Handle_t *zc, float *values, uint32_t timestamp); +/* Полученить флаг - переход произошел. */ +int ZC_isOccurred(ZeroCross_Handle_t *zc, uint8_t channel); /* Получение частоты сигнала */ float ZC_GetFrequency(ZeroCross_Handle_t *zc, uint8_t channel); - -/* Получение периода сигнала */ -uint32_t ZC_GetPeriod(ZeroCross_Handle_t *zc, uint8_t channel); - -/* Получение счетчика переходов */ -uint32_t ZC_GetCrossCount(ZeroCross_Handle_t *zc, uint8_t channel); - -/* Получение текущего состояния канала */ -uint8_t ZC_GetStableState(ZeroCross_Handle_t *zc, uint8_t channel); - -/* Получение текущего значения канала */ -float ZC_GetCurrentValue(ZeroCross_Handle_t *zc, uint8_t channel); - +/* Получение полуволны (после последнего zero-cross) */ +UPP_HalfWave_t ZC_GetHalfWave(ZeroCross_Handle_t *zc, uint8_t channel); /* Включение/выключение мониторинга */ void ZC_EnableMonitoring(ZeroCross_Handle_t *zc, uint8_t enable); - /* Сброс статистики канала */ void ZC_Reset(ZeroCross_Handle_t *zc, uint8_t channel); -/* Установка гистерезиса для хендла */ -void ZC_SetHysteresis(ZeroCross_Handle_t *zc, float hysteresis); - -/* Установка дебаунс samples для хендла */ -void ZC_SetDebounceSamples(ZeroCross_Handle_t *zc, uint8_t debounce_samples); - -/* Получение количества каналов хендла */ -uint8_t ZC_GetNumChannels(ZeroCross_Handle_t *zc); - #endif /* _ZERO_CROSS_H_ */ /** diff --git a/UPP/Core/Src/main.c b/UPP/Core/Src/main.c index 16e30e8..9096b23 100644 --- a/UPP/Core/Src/main.c +++ b/UPP/Core/Src/main.c @@ -107,6 +107,7 @@ int main(void) MX_TIM12_Init(); MX_TIM8_Init(); MX_TIM5_Init(); + MX_TIM2_Init(); /* USER CODE BEGIN 2 */ #else //MATLAB #endif //MATLAB diff --git a/UPP/Core/Src/stm32f4xx_it.c b/UPP/Core/Src/stm32f4xx_it.c index ceef07b..f151479 100644 --- a/UPP/Core/Src/stm32f4xx_it.c +++ b/UPP/Core/Src/stm32f4xx_it.c @@ -23,6 +23,8 @@ /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "upp_main.h" +#include "pwm_thyristors.h" +#include "angle_control.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -57,6 +59,8 @@ /* External variables --------------------------------------------------------*/ extern DMA_HandleTypeDef hdma_adc3; +extern TIM_HandleTypeDef htim1; +extern TIM_HandleTypeDef htim2; extern TIM_HandleTypeDef htim8; extern TIM_HandleTypeDef htim14; @@ -202,13 +206,41 @@ void SysTick_Handler(void) /* please refer to the startup file (startup_stm32f4xx.s). */ /******************************************************************************/ +/** + * @brief This function handles TIM1 update interrupt and TIM10 global interrupt. + */ +void TIM1_UP_TIM10_IRQHandler(void) +{ + /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 0 */ + + /* USER CODE END TIM1_UP_TIM10_IRQn 0 */ + HAL_TIM_IRQHandler(&htim1); + /* USER CODE BEGIN TIM1_UP_TIM10_IRQn 1 */ + UPP_PWM_Handle(); + /* USER CODE END TIM1_UP_TIM10_IRQn 1 */ +} + +/** + * @brief This function handles TIM2 global interrupt. + */ +void TIM2_IRQHandler(void) +{ + /* USER CODE BEGIN TIM2_IRQn 0 */ + + /* USER CODE END TIM2_IRQn 0 */ + HAL_TIM_IRQHandler(&htim2); + /* USER CODE BEGIN TIM2_IRQn 1 */ + //UPP_Angle_Handle(); + /* USER CODE END TIM2_IRQn 1 */ +} + /** * @brief This function handles TIM8 trigger and commutation interrupts and TIM14 global interrupt. */ void TIM8_TRG_COM_TIM14_IRQHandler(void) { /* USER CODE BEGIN TIM8_TRG_COM_TIM14_IRQn 0 */ -#ifndef MATLAB +#ifndef MATLAB // в матлабе нет htim14, т.к. это систем тики /* USER CODE END TIM8_TRG_COM_TIM14_IRQn 0 */ HAL_TIM_IRQHandler(&htim8); HAL_TIM_IRQHandler(&htim14); diff --git a/UPP/Core/Src/tim.c b/UPP/Core/Src/tim.c index a9cc642..85caab9 100644 --- a/UPP/Core/Src/tim.c +++ b/UPP/Core/Src/tim.c @@ -25,6 +25,7 @@ /* USER CODE END 0 */ TIM_HandleTypeDef htim1; +TIM_HandleTypeDef htim2; TIM_HandleTypeDef htim3; TIM_HandleTypeDef htim5; TIM_HandleTypeDef htim8; @@ -48,7 +49,7 @@ void MX_TIM1_Init(void) /* USER CODE END TIM1_Init 1 */ htim1.Instance = TIM1; - htim1.Init.Prescaler = 180-1; + htim1.Init.Prescaler = 0; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 65535; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; @@ -67,7 +68,11 @@ void MX_TIM1_Init(void) { Error_Handler(); } - sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + if (HAL_TIM_OnePulse_Init(&htim1, TIM_OPMODE_SINGLE) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) { @@ -112,6 +117,67 @@ void MX_TIM1_Init(void) /* USER CODE END TIM1_Init 2 */ HAL_TIM_MspPostInit(&htim1); +} +/* TIM2 init function */ +void MX_TIM2_Init(void) +{ + + /* USER CODE BEGIN TIM2_Init 0 */ + + /* USER CODE END TIM2_Init 0 */ + + TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_MasterConfigTypeDef sMasterConfig = {0}; + TIM_OC_InitTypeDef sConfigOC = {0}; + + /* USER CODE BEGIN TIM2_Init 1 */ + + /* USER CODE END TIM2_Init 1 */ + htim2.Instance = TIM2; + htim2.Init.Prescaler = 0; + htim2.Init.CounterMode = TIM_COUNTERMODE_UP; + htim2.Init.Period = 4294967295; + htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + if (HAL_TIM_Base_Init(&htim2) != HAL_OK) + { + Error_Handler(); + } + sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; + if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_OC_Init(&htim2) != HAL_OK) + { + Error_Handler(); + } + sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) + { + Error_Handler(); + } + sConfigOC.OCMode = TIM_OCMODE_TIMING; + sConfigOC.Pulse = 0; + sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; + sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; + if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) + { + Error_Handler(); + } + if (HAL_TIM_OC_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN TIM2_Init 2 */ + + /* USER CODE END TIM2_Init 2 */ + } /* TIM3 init function */ void MX_TIM3_Init(void) @@ -122,6 +188,7 @@ void MX_TIM3_Init(void) /* USER CODE END TIM3_Init 0 */ TIM_ClockConfigTypeDef sClockSourceConfig = {0}; + TIM_SlaveConfigTypeDef sSlaveConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; TIM_OC_InitTypeDef sConfigOC = {0}; @@ -147,8 +214,18 @@ void MX_TIM3_Init(void) { Error_Handler(); } + if (HAL_TIM_OnePulse_Init(&htim3, TIM_OPMODE_SINGLE) != HAL_OK) + { + Error_Handler(); + } + sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER; + sSlaveConfig.InputTrigger = TIM_TS_ITR0; + if (HAL_TIM_SlaveConfigSynchro(&htim3, &sSlaveConfig) != HAL_OK) + { + Error_Handler(); + } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; - sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) { Error_Handler(); @@ -325,10 +402,29 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) /* USER CODE END TIM1_MspInit 0 */ /* TIM1 clock enable */ __HAL_RCC_TIM1_CLK_ENABLE(); + + /* TIM1 interrupt Init */ + HAL_NVIC_SetPriority(TIM1_UP_TIM10_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(TIM1_UP_TIM10_IRQn); /* USER CODE BEGIN TIM1_MspInit 1 */ /* USER CODE END TIM1_MspInit 1 */ } + else if(tim_baseHandle->Instance==TIM2) + { + /* USER CODE BEGIN TIM2_MspInit 0 */ + + /* USER CODE END TIM2_MspInit 0 */ + /* TIM2 clock enable */ + __HAL_RCC_TIM2_CLK_ENABLE(); + + /* TIM2 interrupt Init */ + HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(TIM2_IRQn); + /* USER CODE BEGIN TIM2_MspInit 1 */ + + /* USER CODE END TIM2_MspInit 1 */ + } else if(tim_baseHandle->Instance==TIM3) { /* USER CODE BEGIN TIM3_MspInit 0 */ @@ -469,10 +565,27 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) /* USER CODE END TIM1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM1_CLK_DISABLE(); + + /* TIM1 interrupt Deinit */ + HAL_NVIC_DisableIRQ(TIM1_UP_TIM10_IRQn); /* USER CODE BEGIN TIM1_MspDeInit 1 */ /* USER CODE END TIM1_MspDeInit 1 */ } + else if(tim_baseHandle->Instance==TIM2) + { + /* USER CODE BEGIN TIM2_MspDeInit 0 */ + + /* USER CODE END TIM2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_TIM2_CLK_DISABLE(); + + /* TIM2 interrupt Deinit */ + HAL_NVIC_DisableIRQ(TIM2_IRQn); + /* USER CODE BEGIN TIM2_MspDeInit 1 */ + + /* USER CODE END TIM2_MspDeInit 1 */ + } else if(tim_baseHandle->Instance==TIM3) { /* USER CODE BEGIN TIM3_MspDeInit 0 */ diff --git a/UPP/Core/UPP/angle_control.c b/UPP/Core/UPP/angle_control.c new file mode 100644 index 0000000..de0ee4f --- /dev/null +++ b/UPP/Core/UPP/angle_control.c @@ -0,0 +1,167 @@ +/** +****************************************************************************** +* @file pwm_thyristors.c +* @brief Модуль для управления тиристорами +****************************************************************************** +* @details +******************************************************************************/ +#include "angle_control.h" +#include "tim.h" + + +/** + * @brief Инициализация ШИМ тиристоров. + * @param hangle Указатель на таймер + * @return HAL Status. + */ +HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle, float AngleMin, float AngleMax) +{ + if(hangle == NULL) + return HAL_ERROR; + if(AngleMax < 0 || AngleMax > 1) + return HAL_ERROR; + if(AngleMin < 0 || AngleMin > 1) + return HAL_ERROR; + + hangle->htim = &angletim; + hangle->AngleMax = AngleMax; + hangle->AngleMin = AngleMin; + + + HAL_TIM_OC_Start_IT(hangle->htim, ANGLE_CHANNEL_1); + HAL_TIM_OC_Start_IT(hangle->htim, ANGLE_CHANNEL_2); + HAL_TIM_OC_Start_IT(hangle->htim, ANGLE_CHANNEL_3); + + Angle_Reset(hangle, UPP_PHASE_A); + Angle_Reset(hangle, UPP_PHASE_B); + Angle_Reset(hangle, UPP_PHASE_C); + + return HAL_OK; +} + +/** + * @brief Хендл таймера для рассчета угла открытия. + * @param hangle Указатель на таймер + * @return HAL Status. + */ +UPP_Phase_t Angle_Handle(Angle_Handle_t *hangle) +{ + if(hangle == NULL) + return UPP_PHASE_UNKNOWN; + + + switch(hangle->htim->Channel) + { + case HAL_TIM_ACTIVE_CHANNEL_1: + return UPP_PHASE_A; + break; + + case HAL_TIM_ACTIVE_CHANNEL_2: + return UPP_PHASE_B; + break; + + case HAL_TIM_ACTIVE_CHANNEL_3: + return UPP_PHASE_C; + break; + + default: + return UPP_PHASE_UNKNOWN; + break; + } + + + return UPP_PHASE_UNKNOWN; +} + +/** + * @brief Установка угла открытия в таймер. + * @param hangle Указатель на таймер + * @param Phase Для какой фазы надо установить угол открытия + * @return HAL Status. + */ +HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float Angle, float Freq) +{ + if(hangle == NULL) + return HAL_ERROR; + + // Если канал дурацкий - возвращаем ошибку + if(Phase >= 3) + { + return HAL_ERROR; + } + if(Angle > hangle->AngleMax) + { + Angle = hangle->AngleMax; + } + if(Angle < hangle->AngleMin) + { + Angle = hangle->AngleMin; + } + + uint32_t timer_ticks = TIM_FreqToTick(Freq/Angle, ANGLE_TIM2_FREQ_MHZ); + uint32_t ccr_ticks = __HAL_TIM_GET_COUNTER(hangle->htim) + timer_ticks; + + switch(Phase) + { + case UPP_PHASE_A: + __HAL_TIM_ENABLE_IT(hangle->htim, TIM_IT_CC1); + __HAL_TIM_SET_COMPARE(hangle->htim, ANGLE_CHANNEL_1, ccr_ticks); + break; + + case UPP_PHASE_B: + __HAL_TIM_ENABLE_IT(hangle->htim, TIM_IT_CC2); + __HAL_TIM_SET_COMPARE(hangle->htim, ANGLE_CHANNEL_2, ccr_ticks); + break; + + case UPP_PHASE_C: + __HAL_TIM_ENABLE_IT(hangle->htim, TIM_IT_CC3); + __HAL_TIM_SET_COMPARE(hangle->htim, ANGLE_CHANNEL_3, ccr_ticks); + break; + + case UPP_PHASE_UNKNOWN: + // ПОКА ХЗ + break; + + + } + + return HAL_OK; +} + +/** + * @brief Сброс угла открытия у таймера. + * @param hangle Указатель на таймер + * @param Phase Для какой фазы надо сбросить угол открытия + * @return HAL Status. + */ +HAL_StatusTypeDef Angle_Reset(Angle_Handle_t *hangle, UPP_Phase_t Phase) +{ + if(hangle == NULL) + return HAL_ERROR; + + // Если канал дурацкий - возвращаем ошибку + if(Phase >= 3) + { + return HAL_ERROR; + } + + switch(Phase) + { + case UPP_PHASE_A: + __HAL_TIM_DISABLE_IT(hangle->htim, TIM_IT_CC1); + break; + + case UPP_PHASE_B: + __HAL_TIM_DISABLE_IT(hangle->htim, TIM_IT_CC2); + break; + + case UPP_PHASE_C: + __HAL_TIM_DISABLE_IT(hangle->htim, TIM_IT_CC3); + break; + + case UPP_PHASE_UNKNOWN: + // ПОКА ХЗ + break; + } + return HAL_OK; +} \ No newline at end of file diff --git a/UPP/Core/UPP/angle_control.h b/UPP/Core/UPP/angle_control.h new file mode 100644 index 0000000..4da20e1 --- /dev/null +++ b/UPP/Core/UPP/angle_control.h @@ -0,0 +1,30 @@ +/** +****************************************************************************** +* @file pwm_thyristors.h +* @brief Модуль для управления тиристорами (объединённый 6-канальный) +****************************************************************************** +*/ +#ifndef _ANGLE_CONTROL_H_ +#define _ANGLE_CONTROL_H_ +#include "main.h" + +#define ANGLE_TIM2_FREQ_MHZ 90 + +typedef struct +{ + TIM_HandleTypeDef *htim; + + float AngleMin; + float AngleMax; +}Angle_Handle_t; + +/* Инициализация Таймера для рассчета угла открытия. */ +HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle, float AngleMin, float AngleMax); +/* Установка угла открытия в таймер. */ +HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float Angle, float Freq); +/* Сброс угла открытия у таймера. */ +HAL_StatusTypeDef Angle_Reset(Angle_Handle_t *hangle, UPP_Phase_t Phase); + +/* Хендл таймера для рассчета угла открытия. */ +UPP_Phase_t Angle_Handle(Angle_Handle_t *hangle); +#endif /* _ANGLE_CONTROL_H_ */ diff --git a/UPP/Core/UPP/pwm_thyristors.c b/UPP/Core/UPP/pwm_thyristors.c new file mode 100644 index 0000000..fc6c643 --- /dev/null +++ b/UPP/Core/UPP/pwm_thyristors.c @@ -0,0 +1,303 @@ +/** +****************************************************************************** +* @file pwm_thyristors.c +* @brief Модуль для управления тиристорами +****************************************************************************** +* @details +******************************************************************************/ +#include "pwm_thyristors.h" +#include "angle_control.h" +#include "tim.h" + +static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint32_t state); + +/** + * @brief Инициализация ШИМ тиристоров. + * @param hpwm Указатель на хендл ШИМ тиристоров + * @return HAL Status. + */ +HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm) +{ + if(hpwm == NULL) + return HAL_ERROR; + + // Фаза A + hpwm->AllPhases[PHASE_A_POS].State = PWM_THYR_DISABLED; + hpwm->AllPhases[PHASE_A_POS].ChMask = PWM_CHANNEL_1; + hpwm->AllPhases[PHASE_A_POS].htim = &hpwm1; + hpwm->AllPhases[PHASE_A_NEG].State = PWM_THYR_DISABLED; + hpwm->AllPhases[PHASE_A_NEG].ChMask = PWM_CHANNEL_2; + hpwm->AllPhases[PHASE_A_NEG].htim = &hpwm1; + + // Фаза B + hpwm->AllPhases[PHASE_B_POS].State = PWM_THYR_DISABLED; + hpwm->AllPhases[PHASE_B_POS].ChMask = PWM_CHANNEL_3; + hpwm->AllPhases[PHASE_B_POS].htim = &hpwm1; + hpwm->AllPhases[PHASE_B_NEG].State = PWM_THYR_DISABLED; + hpwm->AllPhases[PHASE_B_NEG].ChMask = PWM_CHANNEL_4; + hpwm->AllPhases[PHASE_B_NEG].htim = &hpwm1; + + // Фаза C + hpwm->AllPhases[PHASE_C_POS].State = PWM_THYR_DISABLED; + hpwm->AllPhases[PHASE_C_POS].ChMask = PWM_CHANNEL_5; + hpwm->AllPhases[PHASE_C_POS].htim = &hpwm2; + hpwm->AllPhases[PHASE_C_NEG].State = PWM_THYR_DISABLED; + hpwm->AllPhases[PHASE_C_NEG].ChMask = PWM_CHANNEL_6; + hpwm->AllPhases[PHASE_C_NEG].htim = &hpwm2; + + // Фаза неизвестная (чтобы не был указатель в никуда, а был на эту структуру) + hpwm->AllPhases[PHASE_UNKNOWN].State = PWM_THYR_DISABLED; + hpwm->AllPhases[PHASE_UNKNOWN].ChMask = 0; + hpwm->AllPhases[PHASE_UNKNOWN].htim = NULL; + hpwm->f.Initialized = 1; + + // Инициализируем ничем. Потом когда словим сеть - поставим конкретные тиристоры + PWM_SetHalfWave(hpwm, UPP_PHASE_A, UPP_WAVE_UNKNOWED); + PWM_SetHalfWave(hpwm, UPP_PHASE_B, UPP_WAVE_UNKNOWED); + PWM_SetHalfWave(hpwm, UPP_PHASE_C, UPP_WAVE_UNKNOWED); + + PWM_SetFrequency(hpwm, hpwm->Config.Frequency); + + HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_1); + HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_2); + HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_3); + HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_4); + HAL_TIM_PWM_Start(&hpwm2, PWM_CHANNEL_5); + HAL_TIM_PWM_Start(&hpwm2, PWM_CHANNEL_6); + HAL_TIM_Base_Start_IT(&hpwm1); + + return HAL_OK; +} + +/** + * @brief Запуск ШИМ. + * @param hpwm Указатель на хендл ШИМ тиристоров + * @param Phase На какой фазе надо запустить ШИМ + * @return HAL Status. + */ +HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase) +{ + if(assert_upp(hpwm)) + return HAL_ERROR; + if (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN]) + return HAL_ERROR; + // Если канал дурацкий - возвращаем ошибку + if(Phase >= 3) + { + return HAL_ERROR; + } + + + switch(hpwm->Phase[Phase]->State) + { + case PWM_THYR_TIM_START: + case PWM_THYR_TIM_ACTIVE: + case PWM_THYR_TIM_DONE: + return HAL_BUSY; + + case PWM_THYR_DISABLED: + case PWM_THYR_TIM_WAIT_ZERO: + // переходим в состояние старта ШИМ + hpwm->Phase[Phase]->State = PWM_THYR_TIM_START; + return HAL_OK; + + default: + return HAL_ERROR;; + } + + return HAL_ERROR; +} + +/** + * @brief Остановить ШИМ. + * @param hpwm Указатель на хендл ШИМ тиристоров + * @param Phase На какой фазе надо остановить ШИМ + * @return HAL Status. + */ +HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_stop) +{ + if(assert_upp(hpwm)) + return HAL_ERROR; + if (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN]) + return HAL_ERROR; + // Если канал дурацкий - возвращаем ошибку + if(Phase >= 3) + { + return HAL_ERROR; + } + + hpwm->Phase[Phase]->State = PWM_THYR_TIM_WAIT_ZERO; + + if(force_stop) + { + __PWM_SetOutputState(hpwm, Phase, PWM_DISABLE); + } + + return HAL_ERROR; +} +/** + * @brief Хендл ШИМ тиристоров. + * @param hpwm Указатель на хендл ШИМ тиристоров + * @return HAL Status. + */ +HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm) +{ + if(assert_upp(hpwm)) + return HAL_ERROR; + + for(int phase = 0; phase < 3; phase++) + { + if(!read_bit(hpwm->Config.PhaseMask.all, phase)) + continue; + if (hpwm->Phase[phase] == NULL || hpwm->Phase[phase] == &hpwm->AllPhases[PHASE_UNKNOWN]) + continue; + + switch(hpwm->Phase[phase]->State) + { + case PWM_THYR_DISABLED: + __PWM_SetOutputState(hpwm, phase, PWM_DISABLE); + break; + + case PWM_THYR_TIM_WAIT_ZERO: + __PWM_SetOutputState(hpwm, phase, PWM_DISABLE); + break; + + case PWM_THYR_TIM_START: + __PWM_SetOutputState(hpwm, phase, PWM_ENABLE); + hpwm->Phase[phase]->PulseCnt = hpwm->Config.PulseNumber; + hpwm->Phase[phase]->State = PWM_THYR_TIM_ACTIVE; + break; + + case PWM_THYR_TIM_ACTIVE: + hpwm->Phase[phase]->PulseCnt--; + if(hpwm->Phase[phase]->PulseCnt <= 0) + { + hpwm->Phase[phase]->PulseCnt = 0; + hpwm->Phase[phase]->State = PWM_THYR_TIM_DONE; + } + break; + + case PWM_THYR_TIM_DONE: + hpwm->Phase[phase]->State = PWM_THYR_TIM_WAIT_ZERO; + break; + + default: + __PWM_SetOutputState(hpwm, phase, PWM_DISABLE); + break; + } + } + return HAL_OK; +} + +/** + * @brief Установка полуволны для слежения. + * @param hpwm Указатель на хендл ШИМ тиристоров + * @param Phase Для какой фазы надо установить полуволну + * @param halfwave Какую полуволну установить + * @return HAL Status. + */ +HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_HalfWave_t halfwave) +{ + if(assert_upp(hpwm)) + return HAL_ERROR; + + + // Сбрасываем текущий канал + __PWM_SetOutputState(hpwm, Phase, PWM_DISABLE); + // Если канал дурацкий - выставляем заглушку + if(Phase >= 3) + { + hpwm->Phase[Phase] = &hpwm->AllPhases[PHASE_UNKNOWN]; + return HAL_ERROR; + } + // Выставляем канал + switch(halfwave) + { + case UPP_WAVE_POSITIVE: + hpwm->Phase[Phase] = &hpwm->AllPhases[Phase]; + return HAL_OK; + + case UPP_WAVE_NEGATIVE: + hpwm->Phase[Phase] = &hpwm->AllPhases[Phase+3]; + return HAL_OK; + + default: + hpwm->Phase[Phase] = &hpwm->AllPhases[PHASE_UNKNOWN]; + return HAL_ERROR; + } +} + +/** + * @brief Установка режима для канала ШИМ. + * @param hpwm Указатель на хендл ШИМ тиристоров + * @param Phase Для какой фазы надо установить состояние + * @param state Какое состояние установить + * @return HAL Status. + */ +static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint32_t state) +{ + if(hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN]) + return HAL_ERROR; + + uint32_t ch_mode = state; + + + switch(hpwm->Phase[Phase]->ChMask) + { + case TIM_CHANNEL_1: + hpwm->Phase[Phase]->htim->Instance->CCMR1 &= ~TIM_OCMODE_PWM2; + hpwm->Phase[Phase]->htim->Instance->CCMR1 |= ch_mode; + break; + case TIM_CHANNEL_2: + hpwm->Phase[Phase]->htim->Instance->CCMR1 &= ~(TIM_OCMODE_PWM2 << 8); + hpwm->Phase[Phase]->htim->Instance->CCMR1 |= (ch_mode << 8); + break; + case TIM_CHANNEL_3: + hpwm->Phase[Phase]->htim->Instance->CCMR2 &= ~TIM_OCMODE_PWM2; + hpwm->Phase[Phase]->htim->Instance->CCMR2 |= ch_mode; + break; + case TIM_CHANNEL_4: + hpwm->Phase[Phase]->htim->Instance->CCMR2 &= ~(TIM_OCMODE_PWM2 << 8); + hpwm->Phase[Phase]->htim->Instance->CCMR2 |= (ch_mode << 8); + break; + default: + break; + } + return HAL_OK; +} + + +/** + * @brief Установка полуволны для слежения. + * @param hpwm Указатель на хендл ШИМ тиристоров + * @param Phase Для какой фазы надо установить полуволну + * @param halfwave Какую полуволну установить + * @return HAL Status. + */ +UPP_HalfWave_t PWM_GetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase) +{ + if(assert_upp(hpwm)) + return UPP_WAVE_UNKNOWED; + if (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN]) + return UPP_WAVE_UNKNOWED; + + // Если канал дурацкий - возвращаем UNKNOWED + if(Phase >= 3) + { + return UPP_WAVE_UNKNOWED; + } + + // Выставляем канал + if(hpwm->Phase[Phase] == &hpwm->AllPhases[Phase]) + { + return UPP_WAVE_POSITIVE; + } + else if(hpwm->Phase[Phase] == &hpwm->AllPhases[Phase+3]) + { + return UPP_WAVE_NEGATIVE; + } + else + { + return UPP_WAVE_UNKNOWED; + } +} \ No newline at end of file diff --git a/UPP/Core/UPP/pwm_thyristors.h b/UPP/Core/UPP/pwm_thyristors.h new file mode 100644 index 0000000..008f930 --- /dev/null +++ b/UPP/Core/UPP/pwm_thyristors.h @@ -0,0 +1,114 @@ +/** +****************************************************************************** +* @file pwm_thyristors.h +* @brief Модуль для управления тиристорами (объединённый 6-канальный) +****************************************************************************** +*/ +#ifndef _PWM_THYRISTORS_H +#define _PWM_THYRISTORS_H +#include "main.h" + + + + + +#define PWM_TIM1_FREQ_MHZ 180 +#define PWM_TIM3_FREQ_MHZ 90 + +#define PWM_ENABLE TIM_OCMODE_PWM1 +#define PWM_DISABLE TIM_OCMODE_FORCED_ACTIVE + + +#define PWM_SetFrequency(_hpwm_, _freq_) \ +do { _hpwm_->Config.Frequency = _freq_; \ + __HAL_TIM_SET_AUTORELOAD(&hpwm1, TIM_FreqToTick(_freq_, PWM_TIM1_FREQ_MHZ)); \ + __HAL_TIM_SET_AUTORELOAD(&hpwm2, TIM_FreqToTick(_freq_, PWM_TIM3_FREQ_MHZ)); \ + __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); }while(0); + + +// Индексы для структур каналов @ref PWM_Handle_t +#define PHASE_A_POS 0 +#define PHASE_B_POS 1 +#define PHASE_C_POS 2 +#define PHASE_A_NEG 3 +#define PHASE_B_NEG 4 +#define PHASE_C_NEG 5 +#define PHASE_UNKNOWN 6 + + +/** + * @brief Состояния канала + */ +typedef enum { + PWM_THYR_DISABLED = 0, ///< Канал отключен + PWM_THYR_TIM_WAIT_ZERO, ///< Таймер ждет пересечения нуля + PWM_THYR_TIM_START, ///< Запуск таймера для ШИМ + PWM_THYR_TIM_ACTIVE, ///< Таймер активен и формирует ШИМ + PWM_THYR_TIM_DONE ///< Таймер закончил свою работу в полупериоде +} PWM_State_t; + +/** + * @brief Канал PWM (один тиристор) + */ +typedef struct { + PWM_State_t State; ///< Состояние тиристора + TIM_HandleTypeDef *htim; ///< указатель на соответствующий TIM (hpwm1 или hpwm2) + uint32_t PulseCnt; ///< Счетчик кол-ва импульсов. Инициализируется из структуры @ref PWM_ThyrConfig_t + uint32_t ChMask; ///< TIM_CHANNEL_x + + struct { + unsigned Ready:1; ///< Флаг готовности тиристора к работе + } f; +} PWM_Channel_t; + +/** + * @brief Канал PWM (один тиристор) + */ +typedef struct { + union + { + uint8_t all; + struct + { + uint8_t phA:1; + uint8_t phB:1; + uint8_t phC:1; + }; + }PhaseMask; ///< Какими каналами управлять + uint8_t PulseNumber; ///< Сколько импульсов отправить в пакете для открытия тиристоров + uint32_t Frequency; ///< Частота импульсов +} PWM_ThyrConfig_t; + +/** + * @brief Хендл управляюзщий тиристорами */ +typedef struct { + PWM_ThyrConfig_t Config; + PWM_Channel_t *Phase[3]; ///< Текущие каналы для фаз + PWM_Channel_t AllPhases[7]; ///< Все каналы для фаз (+1 для деинициализированного канала) + + struct { + unsigned Initialized : 1; + unsigned Running : 1; ///< true если оба таймера запущены + } f; +} PWM_Handle_t; + +/* ---- API ---- */ +/* Инициализация ШИМ тиристоров. */ +HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm); +/* Запуск ШИМ. */ +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); +/* Установка полуволны для слежения. */ +HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_HalfWave_t halfwave); +/* Установка полуволны для слежения. */ +UPP_HalfWave_t PWM_GetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase); + +/* Хендл ШИМ тиристоров. */ +HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm); +#endif /* _PWM_THYRISTORS_H */ diff --git a/UPP/Core/UPP/upp_main.c b/UPP/Core/UPP/upp_main.c index 052684c..729fb6c 100644 --- a/UPP/Core/UPP/upp_main.c +++ b/UPP/Core/UPP/upp_main.c @@ -6,9 +6,9 @@ * @details ******************************************************************************/ #include "upp_main.h" // всё остальное по работе с УПП -#include "power_monitor.h" // статистика сети и АЦП - -PowerMonitor_t pm; +UPP_t upp; +float alpha_dbg = 0.5; +// ОСНОВНОЙ ЦИКЛ main.c /** * @brief Инициализация УПП. @@ -17,7 +17,11 @@ PowerMonitor_t pm; int UPP_Init(void) { HAL_TIM_Base_Start(&ustim); - PowerMonitor_Init(&pm); + PowerMonitor_Init(&upp.pm); + upp.hpwm.Config.Frequency = 20000; + upp.hpwm.Config.PulseNumber = 20; + PWM_Init(&upp.hpwm); + Angle_Init(&upp.hangle, 0, 0.8); return 0; } @@ -27,7 +31,8 @@ int UPP_Init(void) */ int UPP_PreWhile(void) { - PowerMonitor_Start(&pm); + PowerMonitor_Start(&upp.pm); + upp.hpwm.Config.PhaseMask.all = 0x7; return 0; } @@ -41,7 +46,52 @@ int UPP_While(void) return 0; } +// ПРЕРЫВАНИЯ stm32f4xx_it.c + void UPP_ADC_Handle(void) { - PowerMonitor_Handle(&pm); + PowerMonitor_Handle(&upp.pm); + + for(int phase = 0; phase < 3; phase++) + { + // Если произошел Zero Cross + if(ZC_isOccurred(&upp.pm.zc, phase)) + { + // Меняем полуволну тиристора + UPP_HalfWave_t curr_halfwave = ZC_GetHalfWave(&upp.pm.zc, phase); + PWM_SetHalfWave(&upp.hpwm, phase, curr_halfwave); + Angle_Start(&upp.hangle, phase, alpha_dbg, upp.hpwm.Config.Frequency); + } + } +} +void UPP_PWM_Handle(void) +{ + PWM_Handle(&upp.hpwm); +} + +void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim) +{ + if (htim == upp.hangle.htim) + { + UPP_Angle_Handle(); + } +} + +void UPP_Angle_Handle(void) +{ + UPP_Phase_t phase = Angle_Handle(&upp.hangle); + switch(phase) + { + case UPP_PHASE_A: + PWM_Start(&upp.hpwm, UPP_PHASE_A); + break; + case UPP_PHASE_B: + PWM_Start(&upp.hpwm, UPP_PHASE_B); + break; + case UPP_PHASE_C: + PWM_Start(&upp.hpwm, UPP_PHASE_C); + break; + default: + break; + } } \ No newline at end of file diff --git a/UPP/Core/UPP/upp_main.h b/UPP/Core/UPP/upp_main.h index 5ba7672..54b3f56 100644 --- a/UPP/Core/UPP/upp_main.h +++ b/UPP/Core/UPP/upp_main.h @@ -11,7 +11,19 @@ #include "main.h" // либы из AllLibs и вербальные имена из CubeMX #include "upp_config.h" +#include "power_monitor.h" // статистика сети и АЦП +#include "pwm_thyristors.h" // Управление тиристорами +#include "angle_control.h" // Управление углом открытия +extern float alpha_dbg; + +typedef struct +{ + PowerMonitor_t pm; + PWM_Handle_t hpwm; + Angle_Handle_t hangle; +}UPP_t; +extern UPP_t upp; /* Инициализация УПП */ @@ -22,4 +34,6 @@ int UPP_PreWhile(void); int UPP_While(void); void UPP_ADC_Handle(void); +void UPP_PWM_Handle(void); +void UPP_Angle_Handle(void); #endif //_UPP_MAIN_H \ No newline at end of file diff --git a/UPP/MDK-ARM/UPP.uvoptx b/UPP/MDK-ARM/UPP.uvoptx index ba12a47..7736db4 100644 --- a/UPP/MDK-ARM/UPP.uvoptx +++ b/UPP/MDK-ARM/UPP.uvoptx @@ -327,6 +327,54 @@ 0 0 + + 2 + 12 + 1 + 0 + 0 + 0 + ..\Core\UPP\pwm_thyristors.c + pwm_thyristors.c + 0 + 0 + + + 2 + 13 + 5 + 0 + 0 + 0 + ..\Core\UPP\pwm_thyristors.h + pwm_thyristors.h + 0 + 0 + + + 2 + 14 + 1 + 0 + 0 + 0 + ..\Core\UPP\angle_control.c + angle_control.c + 0 + 0 + + + 2 + 15 + 5 + 0 + 0 + 0 + ..\Core\UPP\angle_control.h + angle_control.h + 0 + 0 + @@ -337,7 +385,7 @@ 0 3 - 12 + 16 1 0 0 @@ -349,7 +397,7 @@ 3 - 13 + 17 5 0 0 @@ -361,7 +409,7 @@ 3 - 14 + 18 1 0 0 @@ -373,7 +421,7 @@ 3 - 15 + 19 5 0 0 @@ -385,7 +433,7 @@ 3 - 16 + 20 1 0 0 @@ -397,7 +445,7 @@ 3 - 17 + 21 5 0 0 @@ -409,14 +457,6 @@ - - Thyristors - 0 - 0 - 0 - 0 - - Application/User/Core 1 @@ -424,8 +464,8 @@ 0 0 - 5 - 18 + 4 + 22 1 0 0 @@ -436,8 +476,8 @@ 0 - 5 - 19 + 4 + 23 1 0 0 @@ -448,8 +488,8 @@ 0 - 5 - 20 + 4 + 24 1 0 0 @@ -460,8 +500,8 @@ 0 - 5 - 21 + 4 + 25 1 0 0 @@ -472,8 +512,8 @@ 0 - 5 - 22 + 4 + 26 1 0 0 @@ -484,8 +524,8 @@ 0 - 5 - 23 + 4 + 27 1 0 0 @@ -496,8 +536,8 @@ 0 - 5 - 24 + 4 + 28 1 0 0 @@ -508,8 +548,8 @@ 0 - 5 - 25 + 4 + 29 1 0 0 @@ -520,8 +560,8 @@ 0 - 5 - 26 + 4 + 30 1 0 0 @@ -532,8 +572,8 @@ 0 - 5 - 27 + 4 + 31 1 0 0 @@ -544,8 +584,8 @@ 0 - 5 - 28 + 4 + 32 1 0 0 @@ -556,8 +596,8 @@ 0 - 5 - 29 + 4 + 33 1 0 0 @@ -568,8 +608,8 @@ 0 - 5 - 30 + 4 + 34 1 0 0 @@ -588,8 +628,8 @@ 0 0 - 6 - 31 + 5 + 35 5 0 0 @@ -600,8 +640,8 @@ 0 - 6 - 32 + 5 + 36 5 0 0 @@ -612,8 +652,8 @@ 0 - 6 - 33 + 5 + 37 5 0 0 @@ -624,8 +664,8 @@ 0 - 6 - 34 + 5 + 38 5 0 0 @@ -636,8 +676,8 @@ 0 - 6 - 35 + 5 + 39 5 0 0 @@ -648,8 +688,8 @@ 0 - 6 - 36 + 5 + 40 5 0 0 @@ -660,8 +700,8 @@ 0 - 6 - 37 + 5 + 41 1 0 0 @@ -672,8 +712,8 @@ 0 - 6 - 38 + 5 + 42 5 0 0 @@ -692,8 +732,8 @@ 0 0 - 7 - 39 + 6 + 43 1 0 0 @@ -704,8 +744,8 @@ 0 - 7 - 40 + 6 + 44 1 0 0 @@ -716,8 +756,8 @@ 0 - 7 - 41 + 6 + 45 1 0 0 @@ -728,8 +768,8 @@ 0 - 7 - 42 + 6 + 46 1 0 0 @@ -740,8 +780,8 @@ 0 - 7 - 43 + 6 + 47 1 0 0 @@ -752,8 +792,8 @@ 0 - 7 - 44 + 6 + 48 1 0 0 @@ -764,8 +804,8 @@ 0 - 7 - 45 + 6 + 49 1 0 0 @@ -776,8 +816,8 @@ 0 - 7 - 46 + 6 + 50 1 0 0 @@ -788,8 +828,8 @@ 0 - 7 - 47 + 6 + 51 1 0 0 @@ -800,8 +840,8 @@ 0 - 7 - 48 + 6 + 52 1 0 0 @@ -812,8 +852,8 @@ 0 - 7 - 49 + 6 + 53 1 0 0 @@ -824,8 +864,8 @@ 0 - 7 - 50 + 6 + 54 1 0 0 @@ -844,8 +884,8 @@ 0 0 - 8 - 51 + 7 + 55 1 0 0 @@ -856,8 +896,8 @@ 0 - 8 - 52 + 7 + 56 1 0 0 @@ -871,13 +911,13 @@ PeriphGeneral - 0 + 1 0 0 0 - 9 - 53 + 8 + 57 1 0 0 @@ -888,8 +928,8 @@ 0 - 9 - 54 + 8 + 58 1 0 0 @@ -900,8 +940,8 @@ 0 - 9 - 55 + 8 + 59 1 0 0 @@ -912,8 +952,8 @@ 0 - 9 - 56 + 8 + 60 1 0 0 @@ -924,8 +964,8 @@ 0 - 9 - 57 + 8 + 61 1 0 0 @@ -944,8 +984,8 @@ 0 0 - 10 - 58 + 9 + 62 1 0 0 @@ -956,8 +996,8 @@ 0 - 10 - 59 + 9 + 63 1 0 0 @@ -968,8 +1008,8 @@ 0 - 10 - 60 + 9 + 64 1 0 0 @@ -980,8 +1020,8 @@ 0 - 10 - 61 + 9 + 65 1 0 0 @@ -992,8 +1032,8 @@ 0 - 10 - 62 + 9 + 66 1 0 0 @@ -1004,8 +1044,8 @@ 0 - 10 - 63 + 9 + 67 1 0 0 @@ -1016,8 +1056,8 @@ 0 - 10 - 64 + 9 + 68 1 0 0 @@ -1028,8 +1068,8 @@ 0 - 10 - 65 + 9 + 69 1 0 0 @@ -1040,8 +1080,8 @@ 0 - 10 - 66 + 9 + 70 1 0 0 @@ -1052,8 +1092,8 @@ 0 - 10 - 67 + 9 + 71 1 0 0 @@ -1064,8 +1104,8 @@ 0 - 10 - 68 + 9 + 72 1 0 0 @@ -1076,8 +1116,8 @@ 0 - 10 - 69 + 9 + 73 1 0 0 @@ -1088,8 +1128,8 @@ 0 - 10 - 70 + 9 + 74 1 0 0 @@ -1100,8 +1140,8 @@ 0 - 10 - 71 + 9 + 75 1 0 0 @@ -1112,8 +1152,8 @@ 0 - 10 - 72 + 9 + 76 1 0 0 @@ -1124,8 +1164,8 @@ 0 - 10 - 73 + 9 + 77 1 0 0 @@ -1136,8 +1176,8 @@ 0 - 10 - 74 + 9 + 78 1 0 0 @@ -1148,8 +1188,8 @@ 0 - 10 - 75 + 9 + 79 1 0 0 @@ -1160,8 +1200,8 @@ 0 - 10 - 76 + 9 + 80 1 0 0 @@ -1172,8 +1212,8 @@ 0 - 10 - 77 + 9 + 81 1 0 0 @@ -1184,8 +1224,8 @@ 0 - 10 - 78 + 9 + 82 1 0 0 @@ -1196,8 +1236,8 @@ 0 - 10 - 79 + 9 + 83 1 0 0 @@ -1208,8 +1248,8 @@ 0 - 10 - 80 + 9 + 84 1 0 0 @@ -1220,8 +1260,8 @@ 0 - 10 - 81 + 9 + 85 1 0 0 @@ -1240,8 +1280,8 @@ 0 0 - 11 - 82 + 10 + 86 1 0 0 @@ -1260,8 +1300,8 @@ 0 0 - 12 - 83 + 11 + 87 2 0 0 diff --git a/UPP/MDK-ARM/UPP.uvprojx b/UPP/MDK-ARM/UPP.uvprojx index 6284731..585e041 100644 --- a/UPP/MDK-ARM/UPP.uvprojx +++ b/UPP/MDK-ARM/UPP.uvprojx @@ -445,6 +445,26 @@ 5 ..\Core\UPP\upp_main.h + + pwm_thyristors.c + 1 + ..\Core\UPP\pwm_thyristors.c + + + pwm_thyristors.h + 5 + ..\Core\UPP\pwm_thyristors.h + + + angle_control.c + 1 + ..\Core\UPP\angle_control.c + + + angle_control.h + 5 + ..\Core\UPP\angle_control.h + @@ -482,9 +502,6 @@ - - Thyristors - Application/User/Core diff --git a/UPP/UPP.ioc b/UPP/UPP.ioc index af2d530..5ed5897 100644 --- a/UPP/UPP.ioc +++ b/UPP/UPP.ioc @@ -54,13 +54,14 @@ Mcu.CPN=STM32F427ZGT6 Mcu.Family=STM32F4 Mcu.IP0=ADC3 Mcu.IP1=CAN1 -Mcu.IP10=TIM3 -Mcu.IP11=TIM5 -Mcu.IP12=TIM8 -Mcu.IP13=TIM11 -Mcu.IP14=TIM12 -Mcu.IP15=USART3 -Mcu.IP16=USART6 +Mcu.IP10=TIM2 +Mcu.IP11=TIM3 +Mcu.IP12=TIM5 +Mcu.IP13=TIM8 +Mcu.IP14=TIM11 +Mcu.IP15=TIM12 +Mcu.IP16=USART3 +Mcu.IP17=USART6 Mcu.IP2=DMA Mcu.IP3=IWDG Mcu.IP4=NVIC @@ -69,7 +70,7 @@ Mcu.IP6=RTC Mcu.IP7=SPI3 Mcu.IP8=SYS Mcu.IP9=TIM1 -Mcu.IPNb=17 +Mcu.IPNb=18 Mcu.Name=STM32F427Z(G-I)Tx Mcu.Package=LQFP144 Mcu.Pin0=PE2 @@ -127,17 +128,25 @@ Mcu.Pin55=VP_RTC_VS_RTC_Activate Mcu.Pin56=VP_RTC_VS_RTC_Calendar Mcu.Pin57=VP_SYS_VS_tim14 Mcu.Pin58=VP_TIM1_VS_ClockSourceINT -Mcu.Pin59=VP_TIM3_VS_ClockSourceINT +Mcu.Pin59=VP_TIM1_VS_OPM Mcu.Pin6=PC14/OSC32_IN -Mcu.Pin60=VP_TIM8_VS_ClockSourceINT -Mcu.Pin61=VP_TIM11_VS_ClockSourceINT -Mcu.Pin62=VP_TIM12_VS_ClockSourceINT +Mcu.Pin60=VP_TIM2_VS_ClockSourceINT +Mcu.Pin61=VP_TIM2_VS_no_output1 +Mcu.Pin62=VP_TIM2_VS_no_output2 +Mcu.Pin63=VP_TIM2_VS_no_output3 +Mcu.Pin64=VP_TIM3_VS_ControllerModeTrigger +Mcu.Pin65=VP_TIM3_VS_ClockSourceINT +Mcu.Pin66=VP_TIM3_VS_ClockSourceITR +Mcu.Pin67=VP_TIM3_VS_OPM +Mcu.Pin68=VP_TIM8_VS_ClockSourceINT +Mcu.Pin69=VP_TIM11_VS_ClockSourceINT Mcu.Pin7=PC15/OSC32_OUT +Mcu.Pin70=VP_TIM12_VS_ClockSourceINT Mcu.Pin8=PF6 Mcu.Pin9=PF7 -Mcu.PinsNb=63 +Mcu.PinsNb=71 Mcu.ThirdPartyNb=0 -Mcu.UserConstants=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;PWM_CHANNEL_5,TIM_CHANNEL_3;PWM_CHANNEL_6,TIM_CHANNEL_4;mb_htim,htim12;adc_tim,htim8;hpwm2,htim2;mb_dbg_huart,huart6;ustim,htim5;hpwm1,htim1;usTick,ustim.Instance->CNT +Mcu.UserConstants=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;PWM_CHANNEL_5,TIM_CHANNEL_3;PWM_CHANNEL_6,TIM_CHANNEL_4;mb_htim,htim12;adc_tim,htim8;usTick,ustim.Instance->CNT;hpwm2,htim3;mb_dbg_huart,huart6;ustim,htim5;hpwm1,htim1;ANGLE_CHANNEL_1,TIM_CHANNEL_1;ANGLE_CHANNEL_2,TIM_CHANNEL_2;ANGLE_CHANNEL_3,TIM_CHANNEL_3;angletim,htim2 Mcu.UserName=STM32F427ZGTx MxCube.Version=6.12.1 MxDb.Version=DB.6.0.121 @@ -152,6 +161,8 @@ NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false 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.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.TimeBase=TIM8_TRG_COM_TIM14_IRQn NVIC.TimeBaseIP=TIM14 @@ -395,7 +406,7 @@ ProjectManager.ToolChainLocation= ProjectManager.UAScriptAfterPath= ProjectManager.UAScriptBeforePath= ProjectManager.UnderRoot=false -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-true-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_ADC3_Init-ADC3-false-HAL-true,5-MX_USART3_UART_Init-USART3-false-HAL-true,6-MX_CAN1_Init-CAN1-false-HAL-true,7-MX_IWDG_Init-IWDG-false-HAL-true,8-MX_TIM13_Init-TIM13-false-HAL-true,8-MX_RTC_Init-RTC-false-HAL-true,9-MX_TIM1_Init-TIM1-false-HAL-true,10-MX_TIM3_Init-TIM3-false-HAL-true,11-MX_USART6_UART_Init-USART6-false-HAL-true,12-MX_SPI3_Init-SPI3-false-HAL-true,13-MX_TIM11_Init-TIM11-false-HAL-true,14-MX_TIM12_Init-TIM12-false-HAL-true,15-MX_TIM8_Init-TIM8-false-HAL-true +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-true-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_ADC3_Init-ADC3-false-HAL-true,5-MX_USART3_UART_Init-USART3-false-HAL-true,6-MX_CAN1_Init-CAN1-false-HAL-true,7-MX_IWDG_Init-IWDG-false-HAL-true,8-MX_RTC_Init-RTC-false-HAL-true,9-MX_TIM1_Init-TIM1-false-HAL-true,10-MX_TIM3_Init-TIM3-false-HAL-true,11-MX_USART6_UART_Init-USART6-false-HAL-true,12-MX_SPI3_Init-SPI3-false-HAL-true,13-MX_TIM11_Init-TIM11-false-HAL-true,14-MX_TIM12_Init-TIM12-false-HAL-true,15-MX_TIM8_Init-TIM8-false-HAL-true,16-MX_TIM5_Init-TIM5-false-HAL-true,17-MX_TIM2_Init-TIM2-false-HAL-true RCC.48MHZClocksFreq_Value=90000000 RCC.AHBFreq_Value=180000000 RCC.APB1CLKDivider=RCC_HCLK_DIV4 @@ -461,19 +472,30 @@ SPI3.Direction=SPI_DIRECTION_2LINES SPI3.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate SPI3.Mode=SPI_MODE_MASTER SPI3.VirtualType=VM_MASTER +TIM1.Channel-Output\ Compare2\ CH2=TIM_CHANNEL_2 TIM1.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 TIM1.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 TIM1.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 TIM1.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4 -TIM1.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4,Prescaler -TIM1.Prescaler=180-1 +TIM1.IPParameters=Prescaler,Channel-Output Compare2 CH2,Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation4 CH4,Channel-PWM Generation3 CH3,TIM_MasterOutputTrigger +TIM1.Prescaler=0 +TIM1.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE TIM11.IPParameters=Prescaler TIM11.Prescaler=180-1 TIM12.IPParameters=Prescaler TIM12.Prescaler=90-1 +TIM2.Channel-Output\ Compare1\ No\ Output=TIM_CHANNEL_1 +TIM2.Channel-Output\ Compare2\ No\ Output=TIM_CHANNEL_2 +TIM2.Channel-Output\ Compare3\ No\ Output=TIM_CHANNEL_3 +TIM2.IPParameters=Channel-Output Compare2 No Output,Channel-Output Compare1 No Output,Channel-Output Compare3 No Output,OCMode_1,OCMode_2,OCMode_3 +TIM2.OCMode_1=TIM_OCMODE_TIMING +TIM2.OCMode_2=TIM_OCMODE_TIMING +TIM2.OCMode_3=TIM_OCMODE_TIMING TIM3.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 TIM3.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4 -TIM3.IPParameters=Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4 +TIM3.IPParameters=Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4,TIM_MasterSlaveMode,TIM_MasterOutputTrigger +TIM3.TIM_MasterOutputTrigger=TIM_TRGO_RESET +TIM3.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_ENABLE TIM5.Channel-Input_Capture1_from_TI1=TIM_CHANNEL_1 TIM5.IPParameters=Channel-Input_Capture1_from_TI1,Prescaler TIM5.Prescaler=90-1 @@ -500,8 +522,24 @@ VP_TIM12_VS_ClockSourceINT.Mode=Internal VP_TIM12_VS_ClockSourceINT.Signal=TIM12_VS_ClockSourceINT VP_TIM1_VS_ClockSourceINT.Mode=Internal VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT +VP_TIM1_VS_OPM.Mode=OPM_bit +VP_TIM1_VS_OPM.Signal=TIM1_VS_OPM +VP_TIM2_VS_ClockSourceINT.Mode=Internal +VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT +VP_TIM2_VS_no_output1.Mode=Output Compare1 No Output +VP_TIM2_VS_no_output1.Signal=TIM2_VS_no_output1 +VP_TIM2_VS_no_output2.Mode=Output Compare2 No Output +VP_TIM2_VS_no_output2.Signal=TIM2_VS_no_output2 +VP_TIM2_VS_no_output3.Mode=Output Compare3 No Output +VP_TIM2_VS_no_output3.Signal=TIM2_VS_no_output3 VP_TIM3_VS_ClockSourceINT.Mode=Internal VP_TIM3_VS_ClockSourceINT.Signal=TIM3_VS_ClockSourceINT +VP_TIM3_VS_ClockSourceITR.Mode=TriggerSource_ITR0 +VP_TIM3_VS_ClockSourceITR.Signal=TIM3_VS_ClockSourceITR +VP_TIM3_VS_ControllerModeTrigger.Mode=Trigger Mode +VP_TIM3_VS_ControllerModeTrigger.Signal=TIM3_VS_ControllerModeTrigger +VP_TIM3_VS_OPM.Mode=OPM_bit +VP_TIM3_VS_OPM.Signal=TIM3_VS_OPM VP_TIM8_VS_ClockSourceINT.Mode=Internal VP_TIM8_VS_ClockSourceINT.Signal=TIM8_VS_ClockSourceINT board=custom