Compare commits
32 Commits
b236975f9b
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7286f33709 | ||
|
|
9b4ccd63b0 | ||
|
|
67be0b2304 | ||
|
|
9234b4508b | ||
|
|
1690cdcb93 | ||
|
|
2703f7efda | ||
|
|
aa59f84fb7 | ||
|
|
c0eea077d9 | ||
|
|
2775e0a9b6 | ||
|
|
3750d579fa | ||
|
|
eb6979aa27 | ||
|
|
7d40322f1e | ||
|
|
0de4aad4ef | ||
|
|
854ea6f6c2 | ||
|
|
5624468d09 | ||
|
|
c26319f832 | ||
|
|
925bfbe01e | ||
|
|
21379c6188 | ||
|
|
f3965db204 | ||
|
|
b21d72b728 | ||
|
|
d918ffb860 | ||
|
|
2b22c5b0eb | ||
|
|
0e950148c5 | ||
|
|
5090ddfd48 | ||
|
|
b61a11b4fe | ||
|
|
5d8dc1183b | ||
|
|
e1d6f1139d | ||
|
|
297cf9802e | ||
|
|
6882d6d014 | ||
|
|
edac877616 | ||
|
|
b887114510 | ||
|
|
e69eb0c8c9 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -62,3 +62,5 @@ JLinkLog.txt
|
||||
/MATLAB/MCU.lib
|
||||
/MATLAB/MCU.mexw64.manifest
|
||||
/MATLAB/upp_r2023.slx.autosave
|
||||
/UPP/MDK-ARM/DebugConfig/
|
||||
/UPP/MDK-ARM/Debug_F417
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "dsp/none.h"
|
||||
#endif
|
||||
|
||||
#define _sqrtf(...) sqrtf(__VA_ARGS__)
|
||||
|
||||
#define __disable_irq()
|
||||
|
||||
#ifndef __ASM
|
||||
|
||||
@@ -1247,7 +1247,7 @@ typedef void (*pTIM_CallbackTypeDef)(TIM_HandleTypeDef *htim); /*!< pointer to
|
||||
* @arg TIM_IT_BREAK: Break interrupt
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TIM_CLEAR_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->SR = ~(__INTERRUPT__))
|
||||
#define __HAL_TIM_CLEAR_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->SR &= ~(__INTERRUPT__))
|
||||
|
||||
/**
|
||||
* @brief Indicates whether or not the TIM Counter is used as downcounter.
|
||||
|
||||
@@ -1254,7 +1254,7 @@ typedef void (*pTIM_CallbackTypeDef)(TIM_HandleTypeDef *htim); /*!< pointer to
|
||||
* @arg TIM_IT_BREAK: Break interrupt
|
||||
* @retval None
|
||||
*/
|
||||
#define __HAL_TIM_CLEAR_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->SR = ~(__INTERRUPT__))
|
||||
#define __HAL_TIM_CLEAR_IT(__HANDLE__, __INTERRUPT__) ((__HANDLE__)->Instance->SR &= ~(__INTERRUPT__))
|
||||
|
||||
/**
|
||||
* @brief Indicates whether or not the TIM Counter is used as downcounter.
|
||||
|
||||
@@ -421,6 +421,7 @@ void HAL_GPIO_WritePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState Pin
|
||||
{
|
||||
GPIOx->BSRR = (uint32_t)GPIO_Pin << 16U;
|
||||
}
|
||||
__GPIO_BSRR_Sim(GPIOx);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -442,6 +443,7 @@ void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
|
||||
|
||||
/* Set selected pins that were at low level, and reset ones that were high */
|
||||
GPIOx->BSRR = ((odr & GPIO_Pin) << GPIO_NUMBER) | (~odr & GPIO_Pin);
|
||||
__GPIO_BSRR_Sim(GPIOx);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -95,16 +95,76 @@ void DMA_Sim_Transfer(DMA_TypeDef* DMAx, uint32_t stream)
|
||||
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) {
|
||||
// Полное заполнение - выставляем флаг TCIF
|
||||
if (stream < 4) {
|
||||
*lisr_reg |= tcif_mask; // Потоки 0-3 в LISR
|
||||
}
|
||||
else {
|
||||
*hisr_reg |= tcif_mask; // Потоки 4-7 в HISR
|
||||
}
|
||||
|
||||
stream_sim->transfer_complete = 1;
|
||||
|
||||
if (stream_sim->circular_mode) {
|
||||
stream_sim->current_index = 0;
|
||||
} else {
|
||||
// В циклическом режиме не сбрасываем флаги - они должны быть сброшены программно
|
||||
}
|
||||
else {
|
||||
stream_sim->transfer_enabled = 0;
|
||||
stream_sim->enabled = 0;
|
||||
DMA_Call_IRQHandller(DMAx, stream);
|
||||
}
|
||||
|
||||
// Вызываем обработчик прерывания
|
||||
DMA_Call_IRQHandller(DMAx, stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,18 @@ void Simulate_GPIO_BSRR(void)
|
||||
#ifdef GPIOD
|
||||
__GPIO_BSRR_Sim(GPIOD);
|
||||
#endif
|
||||
#ifdef GPIOE
|
||||
__GPIO_BSRR_Sim(GPIOE);
|
||||
#endif
|
||||
#ifdef GPIOF
|
||||
__GPIO_BSRR_Sim(GPIOF);
|
||||
#endif
|
||||
#ifdef GPIOG
|
||||
__GPIO_BSRR_Sim(GPIOG);
|
||||
#endif
|
||||
#ifdef GPIOH
|
||||
__GPIO_BSRR_Sim(GPIOH);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,10 +13,14 @@ void TIM_Call_IRQHandller(TIM_TypeDef* TIMx);
|
||||
/* Базовая функция для симуляции таймера: она вызывается каждый шаг симуляции */
|
||||
void TIM_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
|
||||
{
|
||||
if (!(TIMx->CR1 & TIM_CR1_CEN)) // таймер не включен - возврат
|
||||
{
|
||||
TIMS->RepititiveCnt = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
Overflow_Check(TIMx, TIMS);
|
||||
|
||||
|
||||
|
||||
// Выбор режима работы таймера
|
||||
switch (TIMx->SMCR & TIM_SMCR_SMS) // TIMER MODE
|
||||
{
|
||||
@@ -37,13 +41,22 @@ switch (TIMx->SMCR & TIM_SMCR_SMS) // TIMER MODE
|
||||
break;
|
||||
}
|
||||
|
||||
// EGR
|
||||
TIM_EGR_Simulation(TIMx);
|
||||
|
||||
// Прерывание если какое-то выставлено
|
||||
if (TIMx->SR & (TIM_SR_UIF | TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF))
|
||||
{
|
||||
TIM_Call_IRQHandller(TIMx); // call HANDLER
|
||||
}
|
||||
|
||||
}
|
||||
/* Счет таймера за один такт */
|
||||
void TIMx_Count(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
|
||||
{
|
||||
if ((TIMx->CR1 & TIM_CR1_DIR) && TIMx->CR1) // up COUNTER and COUNTER ENABLE
|
||||
if ((TIMx->CR1 & TIM_CR1_DIR)) // up COUNTER ENABLE
|
||||
TIMS->tx_cnt -= TIMS->tx_step / (TIMx->PSC + 1);
|
||||
else if (((TIMx->CR1 & TIM_CR1_DIR) == 0) && TIMx->CR1) // down COUNTER and COUNTER ENABLE
|
||||
else if (((TIMx->CR1 & TIM_CR1_DIR) == 0)) // down COUNTER ENABLE
|
||||
TIMS->tx_cnt += TIMS->tx_step / (TIMx->PSC + 1);
|
||||
TIMx->CNT = (uint32_t)TIMS->tx_cnt;
|
||||
}
|
||||
@@ -57,7 +70,6 @@ void Overflow_Check(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
|
||||
if ((TIMx->CR1 & TIM_CR1_ARPE) == 0) TIMS->RELOAD = TIMx->ARR; // PRELOAD disable - update ARR every itteration
|
||||
if (TIMS->tx_cnt > TIMS->RELOAD || TIMS->tx_cnt < 0) // OVERFLOW
|
||||
{
|
||||
TIMS->Updated = 1;
|
||||
TIMS->RELOAD = TIMx->ARR; // RELOAD ARR
|
||||
|
||||
if (TIMS->tx_cnt > TIMx->ARR) // reset COUNTER
|
||||
@@ -68,7 +80,30 @@ void Overflow_Check(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
|
||||
if (TIMS->tx_step > TIMS->RELOAD)
|
||||
TIMS->tx_cnt = 0;
|
||||
|
||||
TIM_Call_IRQHandller(TIMx); // call HANDLER
|
||||
if (!(TIMx->CR1 & TIM_CR1_OPM)) // if no one pulse
|
||||
{
|
||||
TIMS->Updated = 1;
|
||||
if (TIMx->DIER & TIM_DIER_UIE) {
|
||||
TIMx->SR |= TIM_SR_UIF;
|
||||
}
|
||||
}
|
||||
else // if one pulse mode enabled
|
||||
{
|
||||
if (TIMS->RepititiveCnt >= TIMx->RCR)
|
||||
{
|
||||
TIMS->RepititiveCnt = 0;
|
||||
TIMS->Updated = 1;
|
||||
TIMx->CR1 &= ~TIM_CR1_CEN;
|
||||
if (TIMx->DIER & TIM_DIER_UIE) {
|
||||
TIMx->SR |= TIM_SR_UIF;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TIMS->RepititiveCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,12 +169,10 @@ void CC_PWM_Ch1_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
|
||||
if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR1) && (TIMS->tx_cnt >= TIMx->CCR1))
|
||||
{
|
||||
TIMx->SR |= TIM_SR_CC1IF;
|
||||
TIM_Call_IRQHandller(TIMx);
|
||||
}
|
||||
else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR1) && (TIMS->tx_cnt <= TIMx->CCR1))
|
||||
{
|
||||
TIMx->SR |= TIM_SR_CC1IF;
|
||||
TIM_Call_IRQHandller(TIMx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -188,12 +221,10 @@ void CC_PWM_Ch2_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
|
||||
if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR2) && (TIMS->tx_cnt >= TIMx->CCR2))
|
||||
{
|
||||
TIMx->SR |= TIM_SR_CC2IF;
|
||||
TIM_Call_IRQHandller(TIMx);
|
||||
}
|
||||
else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR2) && (TIMS->tx_cnt <= TIMx->CCR2))
|
||||
{
|
||||
TIMx->SR |= TIM_SR_CC2IF;
|
||||
TIM_Call_IRQHandller(TIMx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -242,12 +273,10 @@ void CC_PWM_Ch3_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
|
||||
if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR3) && (TIMS->tx_cnt >= TIMx->CCR3))
|
||||
{
|
||||
TIMx->SR |= TIM_SR_CC3IF;
|
||||
TIM_Call_IRQHandller(TIMx);
|
||||
}
|
||||
else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR3) && (TIMS->tx_cnt <= TIMx->CCR3))
|
||||
{
|
||||
TIMx->SR |= TIM_SR_CC3IF;
|
||||
TIM_Call_IRQHandller(TIMx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -296,12 +325,10 @@ void CC_PWM_Ch4_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
|
||||
if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR4) && (TIMS->tx_cnt >= TIMx->CCR4))
|
||||
{
|
||||
TIMx->SR |= TIM_SR_CC4IF;
|
||||
TIM_Call_IRQHandller(TIMx);
|
||||
}
|
||||
else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR4) && (TIMS->tx_cnt <= TIMx->CCR4))
|
||||
{
|
||||
TIMx->SR |= TIM_SR_CC4IF;
|
||||
TIM_Call_IRQHandller(TIMx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -456,6 +483,42 @@ void Write_TRGO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
|
||||
|
||||
|
||||
//--------------------MISC (temporary) FUNCTIONS--------------------//
|
||||
void TIM_EGR_Simulation(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
|
||||
{
|
||||
// Update
|
||||
if (TIMx->EGR & TIM_EGR_UG) {
|
||||
TIMx->EGR &= ~TIM_EGR_UG;
|
||||
if (TIMx->DIER & TIM_DIER_UIE) {
|
||||
TIMx->SR |= TIM_SR_UIF;
|
||||
}
|
||||
}
|
||||
// Channels
|
||||
if (TIMx->EGR & TIM_EGR_CC1G) {
|
||||
TIMx->EGR &= ~TIM_EGR_CC1G;
|
||||
if (TIMx->DIER & TIM_IT_CC1) {
|
||||
TIMx->SR |= TIM_SR_CC1IF;
|
||||
}
|
||||
}
|
||||
if (TIMx->EGR & TIM_EGR_CC2G) {
|
||||
TIMx->EGR &= ~TIM_EGR_CC2G;
|
||||
if (TIMx->DIER & TIM_IT_CC2) {
|
||||
TIMx->SR |= TIM_SR_CC2IF;
|
||||
}
|
||||
}
|
||||
if (TIMx->EGR & TIM_EGR_CC3G) {
|
||||
TIMx->EGR &= ~TIM_EGR_CC3G;
|
||||
if (TIMx->DIER & TIM_IT_CC3) {
|
||||
TIMx->SR |= TIM_SR_CC3IF;
|
||||
}
|
||||
}
|
||||
if (TIMx->EGR & TIM_EGR_CC4G) {
|
||||
TIMx->EGR &= ~TIM_EGR_CC4G;
|
||||
if (TIMx->DIER & TIM_IT_CC4) {
|
||||
TIMx->SR |= TIM_SR_CC4IF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Определение источника для запуска таймера в SLAVE MODE */
|
||||
void Slave_Mode_Check_Source(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS)
|
||||
{
|
||||
@@ -674,15 +737,15 @@ void TIM_Call_IRQHandller(TIM_TypeDef* TIMx)
|
||||
TIM6_DAC_IRQHandler();
|
||||
else if (TIMx == TIM7)
|
||||
TIM7_IRQHandler();
|
||||
else if ((TIMx == TIM8) || (TIMx == TIM13))
|
||||
else if (((TIMx == TIM8) && (TIM8->SR & TIM_SR_UIF)) || (TIMx == TIM13))
|
||||
TIM8_UP_TIM13_IRQHandler();
|
||||
else if ((TIMx == TIM1) || (TIMx == TIM9))
|
||||
else if (((TIMx == TIM1) && 0) || (TIMx == TIM9))
|
||||
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();
|
||||
else if ((TIMx == TIM8) || (TIMx == TIM12))
|
||||
else if (((TIMx == TIM8) && 0) || (TIMx == TIM12))
|
||||
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();
|
||||
|
||||
SR_PROCESS(TIMx, SR);
|
||||
|
||||
@@ -73,6 +73,7 @@ struct TIM_Sim
|
||||
double tx_cnt; // счетчик таймера
|
||||
double tx_step; // шаг счета за один шаг симуляции
|
||||
long long RELOAD; // буфер, если PRELOAD = 1
|
||||
long long RepititiveCnt; // буфер, если PRELOAD = 1
|
||||
struct Channels_Sim Channels; // структура для симуляции каналов
|
||||
};
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@@ -108,6 +109,8 @@ void Write_TRGO(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
|
||||
|
||||
|
||||
//--------------------MISC (temporary) FUNCTIONS--------------------//
|
||||
|
||||
void TIM_Call_IRQHandller(TIM_TypeDef* TIMx);
|
||||
/* Определение источника для запуска таймера в SLAVE MODE */
|
||||
void Slave_Mode_Check_Source(TIM_TypeDef* TIMx, struct TIM_Sim* TIMS);
|
||||
//------------------------------------------------------------------//
|
||||
|
||||
@@ -26,6 +26,7 @@ void Simulate_Periph_Sim(void)
|
||||
{
|
||||
Simulate_TIMs();
|
||||
Simulate_ADCs();
|
||||
Simulate_GPIO_BSRR();
|
||||
}
|
||||
|
||||
// MCU PERIPH DEINIT
|
||||
@@ -216,10 +217,10 @@ void Init_TIM_SIM(void)
|
||||
tim8s.Channels.OC1_PIN_SHIFT = 0;
|
||||
tim8s.Channels.OC2_GPIOx = GPIOA;
|
||||
tim8s.Channels.OC2_PIN_SHIFT = 0;
|
||||
tim8s.Channels.OC3_GPIOx = GPIOA;
|
||||
tim8s.Channels.OC3_PIN_SHIFT = 0;
|
||||
tim8s.Channels.OC4_GPIOx = GPIOA;
|
||||
tim8s.Channels.OC4_PIN_SHIFT = 0;
|
||||
tim8s.Channels.OC3_GPIOx = GPIOC;
|
||||
tim8s.Channels.OC3_PIN_SHIFT = 8;
|
||||
tim8s.Channels.OC4_GPIOx = GPIOC;
|
||||
tim8s.Channels.OC4_PIN_SHIFT = 9;
|
||||
#endif
|
||||
#ifdef USE_TIM9
|
||||
memset(&tim9s, 0, sizeof(tim9s));
|
||||
|
||||
@@ -22,14 +22,16 @@ SIM__MCUHandleTypeDef hmcu; ///< Хендл для управления
|
||||
*/
|
||||
const int inLengths[IN_PORT_NUMB] = {
|
||||
ADC_PORT_1_WIDTH,
|
||||
IN_PORT_2_WIDTH
|
||||
PUI_PORT_2_WIDTH,
|
||||
INTERNAL_PORT_3_WIDTH
|
||||
};
|
||||
/**
|
||||
* @brief Таблица смещений в выходном массиве IN
|
||||
*/
|
||||
const int inOffsets[IN_PORT_NUMB] = {
|
||||
OFFSET_IN_ARRAY_1,
|
||||
OFFSET_IN_ARRAY_2
|
||||
OFFSET_IN_ARRAY_2,
|
||||
OFFSET_IN_ARRAY_3
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -37,8 +39,10 @@ const int inOffsets[IN_PORT_NUMB] = {
|
||||
*/
|
||||
const int outLengths[OUT_PORT_NUMB] = {
|
||||
THYR_PORT_1_WIDTH,
|
||||
PM_PORT_2_WIDTH,
|
||||
OUT_PORT_3_WIDTH
|
||||
DO_PORT_2_WIDTH,
|
||||
PM_PORT_3_WIDTH,
|
||||
ANGLE_PORT_4_WIDTH,
|
||||
OUT_PORT_5_WIDTH
|
||||
};
|
||||
/**
|
||||
* @brief Таблица смещений в выходном массиве OUT
|
||||
@@ -46,7 +50,9 @@ const int outLengths[OUT_PORT_NUMB] = {
|
||||
const int outOffsets[OUT_PORT_NUMB] = {
|
||||
OFFSET_OUT_ARRAY_1,
|
||||
OFFSET_OUT_ARRAY_2,
|
||||
OFFSET_OUT_ARRAY_3
|
||||
OFFSET_OUT_ARRAY_3,
|
||||
OFFSET_OUT_ARRAY_4,
|
||||
OFFSET_OUT_ARRAY_5
|
||||
};
|
||||
|
||||
// INPUT/OUTPUTS AUTO-PARAMS END
|
||||
|
||||
@@ -53,14 +53,17 @@
|
||||
|
||||
// Parameters of S_Function
|
||||
// INPUT/OUTPUTS PARAMS START
|
||||
#define IN_PORT_NUMB 2
|
||||
#define IN_PORT_NUMB 3
|
||||
#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 3
|
||||
#define OUT_PORT_NUMB 5
|
||||
#define THYR_PORT_1_WIDTH 6
|
||||
#define PM_PORT_2_WIDTH 32
|
||||
#define OUT_PORT_3_WIDTH 16
|
||||
#define DO_PORT_2_WIDTH 3
|
||||
#define PM_PORT_3_WIDTH 32
|
||||
#define ANGLE_PORT_4_WIDTH 16
|
||||
#define OUT_PORT_5_WIDTH 16
|
||||
|
||||
// INPUT/OUTPUTS PARAMS END
|
||||
/** WRAPPER_CONF
|
||||
@@ -92,19 +95,22 @@
|
||||
|
||||
// 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_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 + PM_PORT_2_WIDTH + OUT_PORT_3_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 OFFSET_OUT_ARRAY_1 0
|
||||
#define OFFSET_OUT_ARRAY_2 (OFFSET_OUT_ARRAY_1 + THYR_PORT_1_WIDTH)
|
||||
#define OFFSET_OUT_ARRAY_3 (OFFSET_OUT_ARRAY_2 + PM_PORT_2_WIDTH)
|
||||
#define OFFSET_OUT_ARRAY_3 (OFFSET_OUT_ARRAY_2 + DO_PORT_2_WIDTH)
|
||||
#define OFFSET_OUT_ARRAY_4 (OFFSET_OUT_ARRAY_3 + PM_PORT_3_WIDTH)
|
||||
#define OFFSET_OUT_ARRAY_5 (OFFSET_OUT_ARRAY_4 + ANGLE_PORT_4_WIDTH)
|
||||
|
||||
// INPUT/OUTPUTS AUTO-PARAMS END
|
||||
|
||||
|
||||
@@ -54,6 +54,33 @@ set code_PERIPH=.\MCU_STM32_Matlab\stm32_matlab_conf.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32_SIMULINK\stm32_matlab_gpio.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32_SIMULINK\stm32_matlab_dma.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32_SIMULINK\stm32_periph_registers.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\BasicMathFunctions\BasicMathFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\BasicMathFunctions\BasicMathFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\BayesFunctions\BayesFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\BayesFunctions\BayesFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\CommonTables\CommonTables.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\CommonTables\CommonTablesF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\ComplexMathFunctions\ComplexMathFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\ComplexMathFunctions\ComplexMathFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\ControllerFunctions\ControllerFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\DistanceFunctions\DistanceFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\FastMathFunctions\FastMathFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\FastMathFunctions\FastMathFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\FilteringFunctions\FilteringFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\FilteringFunctions\FilteringFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\InterpolationFunctions\InterpolationFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\InterpolationFunctions\InterpolationFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\MatrixFunctions\MatrixFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\MatrixFunctions\MatrixFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\QuaternionMathFunctions\QuaternionMathFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\StatisticsFunctions\StatisticsFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\StatisticsFunctions\StatisticsFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\SupportFunctions\SupportFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\SupportFunctions\SupportFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\SVMFunctions\SVMFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\SVMFunctions\SVMFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\TransformFunctions\TransformFunctions.c^
|
||||
.\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\TransformFunctions\TransformFunctionsF16.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_adc.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_adc_ex.c^
|
||||
@@ -61,6 +88,7 @@ set code_PERIPH=.\MCU_STM32_Matlab\stm32_matlab_conf.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_dma.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_exti.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_gpio.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_iwdg.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_pwr_ex.c^
|
||||
.\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Src\stm32f4xx_hal_rcc.c^
|
||||
@@ -75,7 +103,24 @@ set includes_PERIPH=-I".\MCU_STM32_Matlab\."^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\Device\STM32F4xx"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Inc"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Inc\Legacy"
|
||||
-I".\MCU_STM32_Matlab\Drivers\STM32F4xx_HAL_Driver\Inc\Legacy"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Include"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\PrivateInclude"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\BasicMathFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\BayesFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\CommonTables"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\ComplexMathFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\ControllerFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\DistanceFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\FastMathFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\FilteringFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\InterpolationFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\MatrixFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\QuaternionMathFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\StatisticsFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\SupportFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\SVMFunctions"^
|
||||
-I".\MCU_STM32_Matlab\Drivers\CMSIS\DSP\Source\TransformFunctions"
|
||||
:: PERIPH BAT END
|
||||
::-------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -18,15 +18,17 @@ void app_init(void) {
|
||||
// если не используется отдельный поток для main().
|
||||
HAL_Init();
|
||||
MX_DMA_Init();
|
||||
MX_IWDG_Init();
|
||||
MX_TIM1_Init();
|
||||
MX_TIM2_Init();
|
||||
MX_TIM3_Init();
|
||||
MX_TIM8_Init();
|
||||
MX_TIM5_Init();
|
||||
MX_ADC3_Init();
|
||||
UPP_SetDefault(1, 1);
|
||||
UPP_Init();
|
||||
UPP_Params_SetDefault(1, 1);
|
||||
UPP_App_Init();
|
||||
UPP_PreWhile();
|
||||
UPP_DO.CEN(DISABLE);
|
||||
|
||||
// USER APP INIT END
|
||||
}
|
||||
|
||||
@@ -6,26 +6,82 @@
|
||||
#include "mcu_wrapper_conf.h"
|
||||
#include "app_wrapper.h"
|
||||
|
||||
float dbg_err_limit = 0;
|
||||
float dbg[16];
|
||||
|
||||
#define PIN_READ(_verbname_) (_verbname_##_GPIO_Port->ODR & (_verbname_##_Pin)) ? 1 : 0
|
||||
|
||||
void Write_Thyristors(real_T* Buffer, int ind_port)
|
||||
void pwm_wtf(PWM_State_t state1, PWM_State_t state2, int* pwm_pin)
|
||||
{
|
||||
int pwm1_pin = PIN_READ(PWM1);
|
||||
int pwm2_pin = PIN_READ(PWM2);
|
||||
int pwm3_pin = PIN_READ(PWM3);
|
||||
int pwm4_pin = PIN_READ(PWM4);
|
||||
int pwm5_pin = PIN_READ(PWM5);
|
||||
int pwm6_pin = PIN_READ(PWM6);
|
||||
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)
|
||||
{
|
||||
//int pwm1_pin = PIN_READ(PWM1);
|
||||
//int pwm2_pin = PIN_READ(PWM2);
|
||||
//int pwm3_pin = PIN_READ(PWM3);
|
||||
//int pwm4_pin = PIN_READ(PWM4);
|
||||
//int pwm5_pin = PIN_READ(PWM5);
|
||||
//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 work = PIN_READ(RDO2);
|
||||
int ready = upp.errors->common;
|
||||
|
||||
if (CEN_GPIO_Port->ODR & CEN_Pin)
|
||||
{
|
||||
WriteOutputArray(0, ind_port, 0);
|
||||
WriteOutputArray(0, ind_port, 1);
|
||||
WriteOutputArray(0, ind_port, 2);
|
||||
WriteOutputArray(0, ind_port, 3);
|
||||
WriteOutputArray(0, ind_port, 4);
|
||||
WriteOutputArray(0, ind_port, 5);
|
||||
|
||||
|
||||
WriteOutputArray(0, ind_port+1, 0);
|
||||
WriteOutputArray(0, ind_port+1, 1);
|
||||
WriteOutputArray(0, ind_port+1, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteOutputArray(pwm1_pin, ind_port, 0);
|
||||
WriteOutputArray(pwm2_pin, ind_port, 1);
|
||||
WriteOutputArray(pwm3_pin, ind_port, 2);
|
||||
WriteOutputArray(pwm4_pin, ind_port, 3);
|
||||
WriteOutputArray(pwm5_pin, ind_port, 4);
|
||||
WriteOutputArray(pwm6_pin, ind_port, 5);
|
||||
|
||||
WriteOutputArray(ready, ind_port+1, 0);
|
||||
WriteOutputArray(work, ind_port+1, 1);
|
||||
WriteOutputArray(err, ind_port+1, 2);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Write_PowerMonitor(real_T* Buffer, int ind_port)
|
||||
@@ -33,7 +89,7 @@ void Write_PowerMonitor(real_T* Buffer, int ind_port)
|
||||
int nn = 0;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{ //0-2
|
||||
WriteOutputArray(upp.pm.measured.Ureal[i], ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.measured.fast.U[i], ind_port, nn++);
|
||||
}
|
||||
for (int i = 0; i < 3; i++)
|
||||
{ //3-5
|
||||
@@ -41,23 +97,48 @@ void Write_PowerMonitor(real_T* Buffer, int ind_port)
|
||||
}
|
||||
for (int i = 0; i < 3; i++)
|
||||
{ //6-8
|
||||
WriteOutputArray(upp.pm.measured.F[i], ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.measured.final.F[i], ind_port, nn++);
|
||||
}
|
||||
for (int i = 0; i < 3; i++)
|
||||
{ //9-11
|
||||
WriteOutputArray(upp.pm.measured.Ireal[i], ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.measured.fast.I[i], ind_port, nn++);
|
||||
}
|
||||
for (int i = 0; i < 2; i++)
|
||||
{ //12-13
|
||||
WriteOutputArray(upp.pm.measured.T[i], ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.measured.final.T[i], ind_port, nn++);
|
||||
}
|
||||
{ //14-16
|
||||
WriteOutputArray(upp.pm.measured.U_mean, ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.measured.I_mean, ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.measured.F_mean, ind_port, nn++);
|
||||
{ //14-19
|
||||
WriteOutputArray(upp.pm.measured.final.Uamp, ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.measured.final.Iamp, ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.measured.final.I[0], ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.measured.final.I[1], ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.measured.final.I[2], ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.measured.final.Fmean, ind_port, nn++);
|
||||
}
|
||||
|
||||
{ //20-21
|
||||
WriteOutputArray(upp.pm.isr_cnt, ind_port, nn++);
|
||||
WriteOutputArray(upp.pm.slow_cnt%PM_SLOW_PERIOD_CNT, ind_port, nn++);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Write_AngleControl(real_T* Buffer, int ind_port)
|
||||
{
|
||||
int nn = 0;
|
||||
|
||||
WriteOutputArray(upp.hangle.Iref, ind_port, nn++);
|
||||
WriteOutputArray(upp.hangle.Imeas, ind_port, nn++);
|
||||
WriteOutputArray(upp.hangle.alpha, ind_port, nn++);
|
||||
|
||||
|
||||
WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR1) - upp.hangle.htim->Instance->CNT, ind_port, nn++);
|
||||
WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR2) - upp.hangle.htim->Instance->CNT, ind_port, nn++);
|
||||
WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR3) - upp.hangle.htim->Instance->CNT, ind_port, nn++);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Функция для записи входов в приложение МК
|
||||
* @param u - массив входных значений
|
||||
@@ -71,8 +152,38 @@ 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);
|
||||
upp.call->go = ReadInputArray(1, 1);
|
||||
upp.call->go = ReadInputArray(1, 0);
|
||||
|
||||
if (upp.workmode != UPP_Work)
|
||||
{
|
||||
MB_DATA.HoldRegs.pui_params.Iref = ReadInputArray(1, 1);
|
||||
MB_DATA.HoldRegs.pui_params.Tnt = ReadInputArray(1, 2);
|
||||
MB_DATA.HoldRegs.pui_params.Umin = ReadInputArray(1, 3);
|
||||
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.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
|
||||
}
|
||||
|
||||
@@ -83,26 +194,24 @@ void app_readInputs(const real_T* Buffer) {
|
||||
*/
|
||||
void app_writeOutputBuffer(real_T* Buffer) {
|
||||
// USER APP OUTPUT START
|
||||
Write_Thyristors(Buffer, 0);
|
||||
Write_UPP_Outputs(Buffer, 0);
|
||||
|
||||
Write_PowerMonitor(Buffer, 1);
|
||||
Write_PowerMonitor(Buffer, 2);
|
||||
|
||||
Write_AngleControl(Buffer, 3);
|
||||
|
||||
int nn = 0;
|
||||
//WriteOutputArray(upp.hangle.htim->Instance->CNT, 2, nn++);
|
||||
WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR1) - upp.hangle.htim->Instance->CNT, 2, nn++);
|
||||
WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR2) - upp.hangle.htim->Instance->CNT, 2, nn++);
|
||||
WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR3) - upp.hangle.htim->Instance->CNT, 2, nn++);
|
||||
|
||||
//WriteOutputArray(dbg[0], 2, nn++);
|
||||
//WriteOutputArray(dbg[1], 2, nn++);
|
||||
//WriteOutputArray(dbg[2], 2, nn++);
|
||||
|
||||
WriteOutputArray(upp.hpwm.AllPhases[PHASE_A_POS].State, 2, nn++);
|
||||
WriteOutputArray(upp.hpwm.AllPhases[PHASE_A_NEG].State, 2, nn++);
|
||||
WriteOutputArray(upp.hpwm.AllPhases[PHASE_B_POS].State, 2, nn++);
|
||||
WriteOutputArray(upp.hpwm.AllPhases[PHASE_B_NEG].State, 2, nn++);
|
||||
WriteOutputArray(upp.hpwm.AllPhases[PHASE_C_POS].State, 2, nn++);
|
||||
WriteOutputArray(upp.hpwm.AllPhases[PHASE_C_NEG].State, 2, nn++);
|
||||
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_A_POS].State, 2, nn++);
|
||||
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_A_NEG].State, 2, nn++);
|
||||
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_B_POS].State, 2, nn++);
|
||||
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_B_NEG].State, 2, nn++);
|
||||
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_C_POS].State, 2, nn++);
|
||||
//WriteOutputArray(upp.hpwm.AllPhases[PHASE_C_NEG].State, 2, nn++);
|
||||
// USER APP OUTPUT END
|
||||
}
|
||||
@@ -9,6 +9,13 @@
|
||||
void app_step(void)
|
||||
{
|
||||
// USER APP STEP START
|
||||
static int first_step = 0;
|
||||
if(first_step == 0)
|
||||
{
|
||||
first_step = 1;
|
||||
UPP_DO.CEN(ENABLE);
|
||||
}
|
||||
|
||||
UPP_While();
|
||||
|
||||
|
||||
|
||||
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,8 +1,14 @@
|
||||
clear all
|
||||
|
||||
IadcMax = 200;%50;
|
||||
VadcMax = 1216;
|
||||
|
||||
Ts = 5e-6;
|
||||
Vnom = 690;
|
||||
Vnom = 400;
|
||||
Inom = 30;%4.2;
|
||||
Fnom = 50;
|
||||
|
||||
Temperature1 = 2.22; % 20 градусов
|
||||
Temperature2 = 2.99; % 34 градусов
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Submodule UPP/AllLibs/Modbus updated: e0ce0e6dbf...df3f71cdff
Submodule UPP/AllLibs/MyLibs updated: 9bff9ad44d...795ebbd220
Submodule UPP/AllLibs/PeriphGeneral updated: 272642b310...c0733a1d31
@@ -20,6 +20,7 @@
|
||||
#ifndef _MODBUS_CONFIG_H_
|
||||
#define _MODBUS_CONFIG_H_
|
||||
#include "upp_defs.h"
|
||||
#include "upp_io.h"
|
||||
|
||||
// Общие параметры
|
||||
#define MODBUS_DEVICE_ID 1 ///< Адрес устройства в сети Modbus
|
||||
@@ -40,8 +41,8 @@
|
||||
// Периферия (опционально)
|
||||
//#define mb_huart huart1 ///< Удобный дефайн для модбасовского uart
|
||||
//#define mb_htim htim3 ///< Удобный дефайн для модбасовского таймера
|
||||
//#define RS_EnableReceive() ///< Функция изменения направления передачи на ПРИЕМ для RS-485
|
||||
//#define RS_EnableTransmit() ///< Функция изменения направления передачи на ПЕРЕДАЧУ для RS-485
|
||||
#define RS_EnableReceive() UPP_UART1_SetDirection(GPIO_PIN_RESET) ///< Функция изменения направления передачи на ПРИЕМ для RS-485
|
||||
#define RS_EnableTransmit() UPP_UART1_SetDirection(GPIO_PIN_RESET) ///< Функция изменения направления передачи на ПЕРЕДАЧУ для RS-485
|
||||
|
||||
|
||||
// Модули modbus
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "modbus_holdregs.h"
|
||||
#include "modbus_inputregs.h"
|
||||
#include "modbus_devid.h"
|
||||
#include "upp_main.h"
|
||||
|
||||
/* DEFINE DATA FOR MODBUS */
|
||||
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 Определение адреса начального регистра.
|
||||
* @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 */
|
||||
if (Qnt > DATA_SIZE)
|
||||
if (Qnt > MbData_size)
|
||||
{
|
||||
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)
|
||||
{
|
||||
/* В режиме работа ничего не записываем */
|
||||
if(upp.workmode == UPP_Work)
|
||||
{
|
||||
return ET_ILLEGAL_FUNCTION;
|
||||
}
|
||||
|
||||
/* check quantity error */
|
||||
if (Qnt > 2000)
|
||||
{
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
#define _MODBUS_DATA_H_
|
||||
|
||||
#include "upp_defs.h"
|
||||
#include "upp_control.h"
|
||||
#include "upp_params.h"
|
||||
#include "stdint.h"
|
||||
|
||||
|
||||
|
||||
@@ -97,11 +97,14 @@
|
||||
|
||||
|
||||
#define BENCH_TIME_ENABLE ///< Включить бенч времени
|
||||
#define BENCH_TIME_MAX_CHANNELS 5 ///< Максимальное количество каналов измерения
|
||||
#define BENCH_TIME_MAX_CHANNELS 6 ///< Максимальное количество каналов измерения
|
||||
|
||||
#define BT_ADC 0
|
||||
#define BT_PWM 1
|
||||
#define BT_SYSTICK 2
|
||||
#define BT_SLOWCALC_PRD 0
|
||||
#define BT_SLOWCALC 1
|
||||
#define BT_ADC 2
|
||||
#define BT_ADC_PRD 3
|
||||
#define BT_PWM 4
|
||||
#define BT_SYSTICK 5
|
||||
/** GEN_CONFIG
|
||||
* @}
|
||||
*/
|
||||
|
||||
@@ -14,50 +14,108 @@
|
||||
#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
|
||||
#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_SIMULATE_I ///< Симулировт токи (Iref/2) а не брать с АЦП
|
||||
#define UPP_DISABLE_PROTECT_BOARDPOWER ///< Отключить проверки питания плат (+24, +5 В)
|
||||
#define UPP_DISABLE_PROTECT_LOSS_PHASE ///< Отключить проверки на потерянные фазы
|
||||
|
||||
#define ZC_DISABLE_HYSTERESIS_DEBOUNCE ///< Отключить гиситерезис и дребезг на определении перехода через ноль
|
||||
|
||||
/** //UPP_PARAMS_TEST
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup UPP_DEFAULT_PARAMS Default params for external flash
|
||||
* @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
|
||||
* @ingroup UPP_CONFIG
|
||||
* @brief Дефолтные параметры для внешней памяти. Они применятся по команде или по ошибке
|
||||
* @{
|
||||
*/
|
||||
/* Параметри мониторинга сети */
|
||||
#define PM_EXP_ALPHA_COEF_DEFAULT 0.01
|
||||
|
||||
|
||||
/* Уставки по температурам */
|
||||
#define SETPOINT_TEMP_WARN 70
|
||||
#define SETPOINT_TEMP_ERR 85
|
||||
|
||||
/* Номинальные параметры */
|
||||
#define NOM_PHASE_NUMB 3
|
||||
#define NOM_U_V_DEFAULT 690
|
||||
#define NOM_U_V_DEFAULT 380
|
||||
#define NOM_U_DEVIATION_PLUS_PERCENT_DEFAULT 6
|
||||
#define NOM_U_DEVIATION_MINUS_PERCENT_DEFAULT 10
|
||||
#define NOM_F_HZ_DEFAULT 50
|
||||
#define NOM_F_DEVIATION_PLUS_PERCENT_DEFAULT 5
|
||||
#define NOM_F_DEVIATION_MINUS_PERCENT_DEFAULT 5
|
||||
#define NOM_F_DEVIATION_PLUS_PERCENT_DEFAULT 10
|
||||
#define NOM_F_DEVIATION_MINUS_PERCENT_DEFAULT 10
|
||||
#define NOM_I_A_DEFAULT 5
|
||||
|
||||
/* Параметры ПУИ */
|
||||
#define PUI_Iref_PERCENT_DEFAULT 150
|
||||
#define PUI_Iref_PERCENT_DEFAULT 1.5
|
||||
#define PUI_Tnt_MS_DEFAULT 300
|
||||
#define PUI_Umin_PERCENT_DEFAULT 80
|
||||
#define PUI_Umax_PERCENT_DEFAULT 120
|
||||
#define PUI_Imax_PERCENT_DEFAULT 99
|
||||
#define PUI_Imin_PERCENT_DEFAULT 7
|
||||
#define PUI_Tnt_CalcAlpha(...) FilterExp_CalcAlpha95(__VA_ARGS__) ///< Уровень в процентах, до куда нарастет ток за время Tnt
|
||||
#define PUI_Umin_PERCENT_DEFAULT 0.8
|
||||
#define PUI_Umax_PERCENT_DEFAULT 1.2
|
||||
#define PUI_Imax_PERCENT_DEFAULT 0.99
|
||||
#define PUI_Imin_PERCENT_DEFAULT 0.07
|
||||
#define PUI_TiMax_US_DEFAULT 5000
|
||||
#define PUI_Tdelay_SECONDS_DEFAULT 30
|
||||
#define PUI_Interlace_EN_DEFAULT 5000
|
||||
|
||||
/* Время задержки перед выставлением ошибки */
|
||||
#define ERRORS_DELAY_MS_UAMP_ERR 1500 // todo
|
||||
#define ERRORS_DELAY_MS_F_ERR 5000
|
||||
#define ERRORS_DELAY_MS_DEFAULT 0.1f
|
||||
|
||||
|
||||
/* Параметры регулятора угла */
|
||||
#define ANGLE_PULSE_LENGTH_RESERVE_PERCENT_DEFAULT 1.0
|
||||
#define ANGLE_MAX_PERCENT_DEFAULT 1
|
||||
#define ANGLE_MIN_PERCENT_DEFAULT 0.1
|
||||
#define ANGLE_PID_KP_COEF_DEFAULT 0.0001
|
||||
#define ANGLE_PID_KI_COEF_DEFAULT 0.0001
|
||||
#define ANGLE_PID_KD_COEF_DEFAULT 0
|
||||
|
||||
/* Параметри мониторинга сети */
|
||||
#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_I_MAX_A_DEFAULT 53.0
|
||||
@@ -66,32 +124,56 @@
|
||||
|
||||
/* Параметры определения перехода через ноль */
|
||||
#define ZERO_CROSS_HYSTERESIS_PERCENT_DEFAULT 2.0
|
||||
#define ZERO_CROSS_DEBOUNCE_10US_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_PULSE_NUMBER_DEFAULT 20
|
||||
#define PWM_THYR_FREQUENCY_HZ_DEFAULT 16000
|
||||
#define PWM_THYR_DUTY_PERCENT_DEFAULT 0.5
|
||||
#define PWM_THYR_PULSE_LENGTH_DEFAULT (60.0/180.0)
|
||||
|
||||
/** //UPP_DEFAULT_PARAMS
|
||||
/** //UPP_PARAMS_DEFAULT
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup UPP_COMPILED_PARAMS Fixed params
|
||||
* @ingroup UPP_CONFIG
|
||||
* @brief Параметры устанавливаемые на этапе компиляции. Без перепрошивки их не поменять
|
||||
* @{
|
||||
*/
|
||||
/* Периоды вызова всякого */
|
||||
#define PM_ADC_PERIOD_US 10 ///< Период опроса АЦП в мкс
|
||||
#define PM_SLOW_PERIOD_10US 50 ///< Период обновление медленных расчетов в 10мкс
|
||||
#define PM_TEMP_PERIOD_10US 5000 ///< Период обновление датчиков температуры в 10мкс
|
||||
|
||||
/* Частоты таймеров в МГц*/
|
||||
#define ADC_TIM8_FREQ_MZH 180 ///< Частота тиков таймера АЦП
|
||||
#define PWM_TIM1_FREQ_MHZ 180 ///< Частота тиков таймера ШИМ (1-4 каналы)
|
||||
#define PWM_TIM3_FREQ_MHZ 90 ///< Частота тиков таймера ШИМ (5-6 каналы)
|
||||
#define ANGLE_TIM2_FREQ_MHZ 90 ///< Частота тиков таймера отсчета угла открытия тиристоров
|
||||
|
||||
// ===== ОТЛАДОЧНЫЕ ШТУКИ ДЛЯ 417 ======
|
||||
#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_TIM8_FREQ_MHZ
|
||||
#undef US_TIM5_FREQ_MHZ
|
||||
#undef ADC_TIM3_FREQ_MZH
|
||||
#undef ANGLE_TIM2_FREQ_MHZ
|
||||
|
||||
#define PWM_TIM1_FREQ_MHZ 168 ///< Частота тиков таймера ШИМ (1-4 каналы)
|
||||
#define PWM_TIM8_FREQ_MHZ 168 ///< Частота тиков таймера ШИМ (5-6 каналы)
|
||||
#define US_TIM5_FREQ_MHZ 84 ///< Частота тиков микросекундного таймера
|
||||
#define ADC_TIM3_FREQ_MZH 84 ///< Частота тиков таймера АЦП
|
||||
#define ANGLE_TIM2_FREQ_MHZ 84 ///< Частота тиков таймера отсчета угла открытия тиристоров
|
||||
|
||||
#define HAL_PWREx_EnableOverDrive() HAL_ERROR
|
||||
|
||||
#endif //defined(STM32F417xx)
|
||||
|
||||
// ===== ОТЛАДОЧНЫЕ ШТУКИ ДЛЯ MATLAB ======
|
||||
#if defined(MATLAB)
|
||||
#undef UPP_INIT_BEFORE_READY_MS
|
||||
|
||||
|
||||
#define UPP_INIT_BEFORE_READY_MS 100 ///< Сколько сканировать сеть, перед выставлением состояния готовности
|
||||
|
||||
|
||||
#endif //defined(MATLAB)
|
||||
#endif //_UPP_CONFIG_H_
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#define _UPP_DEFS_H_
|
||||
#include "upp_config.h"
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup UPP_HIGHLEVEL Defines for high-level
|
||||
* @ingroup UPP_DEFS
|
||||
@@ -26,11 +27,11 @@
|
||||
* @brief Список аварий УПП
|
||||
*/
|
||||
typedef enum {
|
||||
WM_Not_Init = 0, ///< УПП не инициализирован
|
||||
WM_Ready = 1, ///< УПП в готовности
|
||||
WM_Running = 2, ///< УПП в работе, управляет тиристорами
|
||||
WM_Done = 3, ///< УПП закончил свою работу
|
||||
WM_Error = 4, ///< УПП в аварии
|
||||
UPP_Init = 0, ///< УПП не инициализирован
|
||||
UPP_Ready = 1, ///< УПП в готовности
|
||||
UPP_Work = 2, ///< УПП в работе, управляет тиристорами
|
||||
UPP_Error = 3, ///< УПП в аварии
|
||||
// WM_Done = 3, ///< УПП закончил свою работу
|
||||
} UPP_WorkModeType_t;
|
||||
|
||||
/**
|
||||
@@ -59,6 +60,8 @@ typedef enum {
|
||||
Err_OverVoltage = 13, ///< Напряжение сети выше допустимого (см. Umах в @ref UPP_PUI_Params_t)
|
||||
Err_OverTemperature = 14, ///< Температура выше допустимой (плюс 85 °C)
|
||||
Err_UnderVoltage = 15, ///< Напряжение сети ниже допустимого (см. Umin в @ref UPP_PUI_Params_t)
|
||||
Err_OverFrequency = 22, ///< Частота сети выше допустимой
|
||||
Err_UnderFrequency = 23, ///< Частота сети ниже допустимой
|
||||
|
||||
/* Ошибки по обрывам фаз */
|
||||
Err_LossPhaseAll = 16, ///< Обрыв трёх фаз (см. Imin в @ref UPP_PUI_Params_t)
|
||||
@@ -69,8 +72,6 @@ typedef enum {
|
||||
/* Другие ошибки */
|
||||
Err_LongStart = 20, ///< Затянутый пуск (ток не спадает за установленное время) (см. Tdelay в @ref UPP_PUI_Params_t)
|
||||
Err_Interlace = 21, ///< Неправильный порядок чередования фаз (см. Interlace в @ref UPP_PUI_Params_t)
|
||||
Err_OverFrequency = 22, ///< Частота сети выше допустимой
|
||||
Err_UnderFrequency = 23, ///< Частота сети ниже допустимой
|
||||
} UPP_ErrorType_t;
|
||||
|
||||
|
||||
@@ -95,7 +96,7 @@ typedef struct {
|
||||
|
||||
/**
|
||||
* @brief Структура параметров УПП от ПУИ
|
||||
* @details Параметры по умолчанию приведены в @ref UPP_DEFAULT_PARAMS
|
||||
* @details Параметры по умолчанию приведены в @ref UPP_PARAMS_DEFAULT
|
||||
* @note Защиты №X приведены в @ref UPP_ErrorType_t
|
||||
*/
|
||||
typedef struct {
|
||||
@@ -148,8 +149,44 @@ typedef struct {
|
||||
* @brief Дефайны УПП которые используютяс исключительно внутри программы
|
||||
* @{
|
||||
*/
|
||||
#define ANGLE_PERIOD_MS(_freq_) (((float)1/(_freq_*2))*1000)
|
||||
|
||||
// Проверка корректности структуры
|
||||
#define assert_upp(_struct_) check_null_ptr_2(_struct_, (_struct_)->f.Initialized)
|
||||
// Проверка корректности структуры и фазы
|
||||
#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 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 PARAM_INTERNAL MB_INTERNAL.param
|
||||
#define PARAM_PUI MB_DATA.HoldRegs.pui_params
|
||||
#define ERR_PUI errors.pui.err
|
||||
#define ERR_PRIVATE errors.prvt.f.err
|
||||
#define ERR_PRIVATE_CNT errors.prvt.cnt
|
||||
|
||||
/* Enum'ы УПП */
|
||||
/**
|
||||
* @brief Состояния полуволны
|
||||
*/
|
||||
@@ -164,8 +201,8 @@ typedef enum {
|
||||
*/
|
||||
typedef enum {
|
||||
UPP_PHASE_A = 0,
|
||||
UPP_PHASE_B = 1,
|
||||
UPP_PHASE_C = 2,
|
||||
UPP_PHASE_C = 1,
|
||||
UPP_PHASE_B = 2,
|
||||
UPP_PHASE_UNKNOWN = 3
|
||||
} UPP_Phase_t;
|
||||
|
||||
|
||||
@@ -31,8 +31,11 @@ extern "C" {
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
/* Общее по УПП */
|
||||
#include "upp_defs.h"
|
||||
#include "upp_io.h"
|
||||
#include "upp_errors.h"
|
||||
/* Общие библиотеки */
|
||||
#include "mylibs_include.h"
|
||||
#include "modbus.h"
|
||||
/* USER CODE END Includes */
|
||||
@@ -59,6 +62,7 @@ void Error_Handler(void);
|
||||
/* USER CODE END EFP */
|
||||
|
||||
/* Private defines -----------------------------------------------------------*/
|
||||
#define angletim htim2
|
||||
#define mb_huart huart3
|
||||
#define mbdbg_htim htim11
|
||||
#define PWM_CHANNEL_1 TIM_CHANNEL_1
|
||||
@@ -66,23 +70,22 @@ void Error_Handler(void);
|
||||
#define PWM_CHANNEL_3 TIM_CHANNEL_3
|
||||
#define PWM_CHANNEL_4 TIM_CHANNEL_4
|
||||
#define mem_hspi hspi3
|
||||
#define ANGLE_CHANNEL_2 TIM_CHANNEL_2
|
||||
#define ANGLE_CHANNEL_3 TIM_CHANNEL_3
|
||||
#define ANGLE_CHANNEL_1 TIM_CHANNEL_1
|
||||
#define PWM_CHANNEL_5 TIM_CHANNEL_3
|
||||
#define PWM_CHANNEL_6 TIM_CHANNEL_4
|
||||
#define mb_htim htim12
|
||||
#define adc_tim htim8
|
||||
#define adc_tim htim3
|
||||
#define usTick ustim.Instance->CNT
|
||||
#define hpwm2 htim3
|
||||
#define hpwm2 htim8
|
||||
#define mb_dbg_huart huart6
|
||||
#define ustim htim5
|
||||
#define hpwm1 htim1
|
||||
#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
|
||||
#define CEN_O_GPIO_Port GPIOE
|
||||
#define CEN_Pin GPIO_PIN_3
|
||||
#define CEN_GPIO_Port GPIOE
|
||||
#define UM_ERR_5VD_Pin GPIO_PIN_4
|
||||
#define UM_ERR_5VD_GPIO_Port GPIOE
|
||||
#define DO2_Pin GPIO_PIN_5
|
||||
@@ -172,6 +175,30 @@ void Error_Handler(void);
|
||||
|
||||
/* USER CODE BEGIN Private defines */
|
||||
extern TIM_HandleTypeDef ustim;
|
||||
void SystemClock_Config_STM32F417(void);
|
||||
#if defined(STM32F417xx)
|
||||
|
||||
|
||||
/* Ремап входного дискрета Пуск */
|
||||
#undef ERR_24V_GPIO_Port
|
||||
#undef ERR_24V_Pin
|
||||
#undef DIN1_GPIO_Port
|
||||
#undef DIN1_Pin
|
||||
#define ERR_24V_Pin GPIO_PIN_15
|
||||
#define ERR_24V_GPIO_Port GPIOG
|
||||
#define DIN1_Pin GPIO_PIN_12
|
||||
#define DIN1_GPIO_Port GPIOG
|
||||
|
||||
/* Ремап выходного дискрета В работе */
|
||||
#undef RDO2_GPIO_Port
|
||||
#undef RDO2_Pin
|
||||
#undef SCIDE1_GPIO_Port
|
||||
#undef SCIDE1_Pin
|
||||
#define RDO2_Pin GPIO_PIN_6
|
||||
#define RDO2_GPIO_Port GPIOB
|
||||
#define SCIDE1_Pin GPIO_PIN_7
|
||||
#define SCIDE1_GPIO_Port GPIOB
|
||||
#endif
|
||||
/* USER CODE END Private defines */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -57,6 +57,7 @@ void PendSV_Handler(void);
|
||||
void SysTick_Handler(void);
|
||||
void TIM1_UP_TIM10_IRQHandler(void);
|
||||
void TIM2_IRQHandler(void);
|
||||
void TIM8_UP_TIM13_IRQHandler(void);
|
||||
void TIM8_TRG_COM_TIM14_IRQHandler(void);
|
||||
void DMA2_Stream0_IRQHandler(void);
|
||||
/* USER CODE BEGIN EFP */
|
||||
|
||||
@@ -7,35 +7,49 @@
|
||||
******************************************************************************/
|
||||
#include "adc_tools.h"
|
||||
|
||||
static void ADC_EnableAllFilters(ADC_Periodic_t *adc)
|
||||
{
|
||||
for(int i = 0; i < ADC_NUMB_OF_CHANNELS; i++)
|
||||
{
|
||||
Filter_Start(&adc->filter[i]);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
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],
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
__STATIC_FORCEINLINE void ADC_FilterRaw(ADC_Periodic_t *adc, int ch_start, int ch_end)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация периодического АЦП.
|
||||
* @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].lZero = levelZero;
|
||||
|
||||
ADC_ResetStatistics(adc, ChNumb);
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
@@ -100,24 +113,24 @@ HAL_StatusTypeDef ADC_Start(ADC_Periodic_t *adc, float PeriodUs)
|
||||
if(PeriodUs == 0)
|
||||
return HAL_ERROR;
|
||||
|
||||
// Остановить перед перенастройкой
|
||||
HAL_TIM_Base_Stop(adc->htim);
|
||||
|
||||
// Запускаем таймер который будет запускать опрос АЦП с заданным периодом
|
||||
__HAL_TIM_SET_AUTORELOAD(adc->htim, TIM_MicrosToTick(PeriodUs, ADC_TIM8_FREQ_MZH));
|
||||
__HAL_TIM_SET_AUTORELOAD_FORCE(adc->htim, TIM_MicrosToTick(PeriodUs, ADC_TIM3_FREQ_MZH));
|
||||
|
||||
res = HAL_TIM_Base_Start(adc->htim);
|
||||
if(res != HAL_OK)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
// Запускаем АЦП который будет перекидывать данные в ADC_DMA_Buffer
|
||||
res = HAL_ADC_Start_DMA(adc->hadc, (uint32_t*)adc->RawData, 6); // Затем АЦП с DMA
|
||||
// Запускаем АЦП который будет перекидывать данные в DMA буфер RawData
|
||||
res = HAL_ADC_Start_DMA(adc->hadc, (uint32_t*)adc->RawData, 6);
|
||||
if(res != HAL_OK)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
ADC_EnableAllFilters(adc);
|
||||
Filter_Start(&adc->temp_map[0]);
|
||||
Filter_Start(&adc->temp_map[1]);
|
||||
|
||||
return res;
|
||||
}
|
||||
/**
|
||||
@@ -135,14 +148,11 @@ HAL_StatusTypeDef ADC_Stop(ADC_Periodic_t *adc)
|
||||
return HAL_TIM_Base_Stop(adc->htim);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Обработка АЦП.
|
||||
* @brief Обновление напряжений АЦП.
|
||||
* @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))
|
||||
return HAL_ERROR;
|
||||
@@ -151,93 +161,45 @@ HAL_StatusTypeDef ADC_Handle(ADC_Periodic_t *adc)
|
||||
uint16_t *raw = adc->RawData;
|
||||
float *data = adc->Data;
|
||||
|
||||
// Фильтрация от импульсных шумов каналов токов (напряжения позже фильтруются полосовым фильтром)
|
||||
for(int i = 0; i < 2; i++)
|
||||
{
|
||||
int u_ind = ADC_U_CHANNELS_START + i;
|
||||
int i_ind = ADC_I_CHANNELS_START + i;
|
||||
// заменяем сырые данные на отфильтрованные данные
|
||||
raw[u_ind] = Filter_Process(&adc->u_fltr[i], raw[u_ind]);
|
||||
raw[i_ind] = Filter_Process(&adc->i_fltr[i], raw[i_ind]);
|
||||
}
|
||||
|
||||
// Перерасчеты Напряжений/Токов в единицы измерения
|
||||
for(int i = 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];
|
||||
data[i] = ((float)(raw[i])-coefs->lZero) * coefs->vMax / (coefs->lMax-coefs->lZero);
|
||||
// ADC_UpdateStatistics(adc, i, ADC_LEVEL_AC);
|
||||
}
|
||||
|
||||
// Фильтрация от шумов для всех каналов
|
||||
for(int i = 0; i < ADC_NUMB_OF_CHANNELS; i++)
|
||||
{
|
||||
if(Filter_isEnable(&adc->filter[i]))
|
||||
{
|
||||
// заменяем данные на отфильтрованные данные
|
||||
data[i] = Filter_Process(&adc->filter[i], data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Преобразования температуры по таблице
|
||||
for (int i = ADC_TEMP_CHANNELS_START; i < ADC_NUMB_OF_CHANNELS; i++)
|
||||
{
|
||||
data[i] = Filter_Process(&adc->temp_map[i-ADC_TEMP_CHANNELS_START], raw[i]);
|
||||
// ADC_UpdateStatistics(adc, i, ADC_LEVEL_BASE);
|
||||
}
|
||||
|
||||
if(Filter_isDataReady(&adc->filter[0]))
|
||||
adc->f.DataReady = 1;
|
||||
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))
|
||||
return;
|
||||
if (channel >= ADC_NUMB_OF_REGULAR_CHANNELS)
|
||||
return;
|
||||
return HAL_ERROR;
|
||||
|
||||
float *data = adc->Data;
|
||||
uint16_t *raw = adc->RawData;
|
||||
|
||||
ADC_Statistics *stat = &adc->Stat[channel];
|
||||
float value = adc->Data[channel];
|
||||
|
||||
// Первая инициализация
|
||||
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)
|
||||
// Преобразования температуры по таблице
|
||||
for (int i = ADC_TEMP_CHANNELS_START; i < ADC_TEMP_CHANNELS_END; i++)
|
||||
{
|
||||
return;
|
||||
data[i] = Filter_Process(&adc->temp_map[i-ADC_TEMP_CHANNELS_START], raw[i]);
|
||||
}
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
// Накопление для Avg/RMS
|
||||
stat->Sum += ABS(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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,14 @@
|
||||
#define ADC_NUMB_OF_I_CHANNELS 2
|
||||
#define ADC_NUMB_OF_T_CHANNELS 2
|
||||
#define ADC_NUMB_OF_REGULAR_CHANNELS (ADC_NUMB_OF_U_CHANNELS+ADC_NUMB_OF_I_CHANNELS)
|
||||
#define ADC_TEMP_CHANNELS_START ADC_NUMB_OF_REGULAR_CHANNELS
|
||||
|
||||
#define ADC_U_CHANNELS_START 0
|
||||
#define ADC_U_CHANNELS_END 1
|
||||
#define ADC_I_CHANNELS_START 2
|
||||
#define ADC_I_CHANNELS_END 3
|
||||
#define ADC_TEMP_CHANNELS_START 4
|
||||
#define ADC_TEMP_CHANNELS_END 5
|
||||
|
||||
|
||||
#define ADC_TEMPERATURES_QUANTS \
|
||||
{ 2188, 2197, 2206, 2216, 2226, 2236, 2247, 2259, 2271, 2283, \
|
||||
@@ -51,10 +58,6 @@
|
||||
static const float adc_temp_vals[] = ADC_TEMPERATURES;
|
||||
static const float adc_temp_quants[] = ADC_TEMPERATURES_QUANTS;
|
||||
|
||||
#define Filter_t FilterMedian_t
|
||||
#define Filter_Init FilterMedian_Init
|
||||
#define Filter_Initializator 5
|
||||
|
||||
/**
|
||||
* @brief Коэфициенты канала АЦП для пересчета в единицы измерения
|
||||
*/
|
||||
@@ -100,12 +103,11 @@ typedef struct
|
||||
uint16_t RawData[ADC_NUMB_OF_CHANNELS]; ///< Сырые значения АЦП
|
||||
ADC_Coefs_t Coefs[ADC_NUMB_OF_REGULAR_CHANNELS]; ///< Коэффициенты @ref ADC_Coefs_t для регулярных каналов (не температуры)
|
||||
|
||||
Filter_t filter[ADC_NUMB_OF_CHANNELS]; ///< Фильтр от шумов АЦП
|
||||
|
||||
FilterLUT_t temp_map[2]; ///< Коррекция нелинейности датчиков температуры
|
||||
FilterBandPassDerivative_t u_fltr[ADC_NUMB_OF_U_CHANNELS]; ///< Полосовой Фильтр Напряжений от шумов
|
||||
FilterMedianInt_t i_fltr[ADC_NUMB_OF_I_CHANNELS]; ///< Медианный Фильтр Токов от шумов
|
||||
FilterLUT_t temp_map[ADC_NUMB_OF_T_CHANNELS]; ///< Коррекция нелинейности датчиков температуры
|
||||
|
||||
float Data[ADC_NUMB_OF_CHANNELS]; ///< Пересчитанные значения АЦП (в Вольтах/Амперах)
|
||||
ADC_Statistics Stat[ADC_NUMB_OF_REGULAR_CHANNELS]; ///< Статистика для регулярных каналов (не температуры)
|
||||
|
||||
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_Stop(ADC_Periodic_t *adc);
|
||||
|
||||
/* Обновление температур АЦП. */
|
||||
HAL_StatusTypeDef ADC_UpdateTemperatures(ADC_Periodic_t *adc);
|
||||
/* Обработка АЦП после получения данных. */
|
||||
HAL_StatusTypeDef ADC_Handle(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);
|
||||
HAL_StatusTypeDef ADC_UpdateRegular(ADC_Periodic_t *adc);
|
||||
|
||||
#endif //_ADC_TOOLS_H_
|
||||
|
||||
83
UPP/Core/PowerMonitor/phases_transform.c
Normal file
83
UPP/Core/PowerMonitor/phases_transform.c
Normal file
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file phases_transform.c
|
||||
* @brief Функции для преобразования напряжений/токов в многофазных системах
|
||||
******************************************************************************
|
||||
* @details
|
||||
******************************************************************************/
|
||||
#include "phases_transform.h"
|
||||
#define SQRT3 1.7320508
|
||||
|
||||
/**
|
||||
* @brief Рассчитать результирующий вектор трехфазной системы по фазным величинам.
|
||||
* @return Длина вектора (модуль).
|
||||
*/
|
||||
float vector_abs_phase_calc(float phase1, float phase2)
|
||||
{
|
||||
/* Двухвазная система координат x-y */
|
||||
float x = phase1;
|
||||
float y = (-phase1 - 2*phase2)/SQRT3;
|
||||
float V = 0;
|
||||
arm_status res = arm_sqrt_f32(x*x + y*y, &V);
|
||||
|
||||
if(res == ARM_MATH_SUCCESS)
|
||||
return V;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Рассчитать результирующий вектор трехфазной системы по линейным величинам.
|
||||
* @return Длина вектора (модуль).
|
||||
*/
|
||||
float vector_abs_linear_calc(float phase1, float phase2)
|
||||
{
|
||||
/* Двухвазная система координат x-y */
|
||||
float x = (phase1 - phase2)/SQRT3;
|
||||
float y = -phase1 - phase2;
|
||||
float V = 0;
|
||||
arm_status res = arm_sqrt_f32(x*x + y*y, &V);
|
||||
|
||||
if(res == ARM_MATH_SUCCESS)
|
||||
return V;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Рассчитать фазные напряжения из линейных (звезда)
|
||||
* @param Ulin Линейные напряжения [Uba Uac Ubc]
|
||||
* @param Uph Фазные напряжения [Ua Ub Uc]
|
||||
*/
|
||||
void linear_to_phase_star(float *Ulin, float *Uph)
|
||||
{
|
||||
if(Ulin == NULL || Uph == NULL)
|
||||
return;
|
||||
|
||||
// Соответствие макросам: Ulin[0] = UBA, Ulin[1] = UAC, Ulin[2] = UBC
|
||||
float Uba = Ulin[0];
|
||||
float Uac = Ulin[1];
|
||||
float Ubc = Ulin[2];
|
||||
|
||||
// Формулы для звезды (сумма фаз = 0)
|
||||
Uph[0] = (Uba - Ubc)/3.0f; // Ua
|
||||
Uph[1] = (Ubc - Uac)/3.0f; // Ub
|
||||
Uph[2] = (Uac - Uba)/3.0f; // Uc
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Рассчитать фазные напряжения из линейных (треугольник)
|
||||
* @param Ulin Линейные напряжения [Uba Uac Ubc]
|
||||
* @param Uph Фазные напряжения [Ua Ub Uc]
|
||||
*/
|
||||
void linear_to_phase_delta(float *Ulin, float *Uph)
|
||||
{
|
||||
if(Ulin == NULL || Uph == NULL)
|
||||
return;
|
||||
|
||||
// Соответствие макросам: Ulin[0] = UBA, Ulin[1] = UAC, Ulin[2] = UBC
|
||||
// Для треугольника фазные напряжения равны линейным
|
||||
Uph[0] = Ulin[0]; // Ua = Uba
|
||||
Uph[1] = Ulin[2]; // Ub = Ubc
|
||||
Uph[2] = Ulin[1]; // Uc = Uac
|
||||
}
|
||||
19
UPP/Core/PowerMonitor/phases_transform.h
Normal file
19
UPP/Core/PowerMonitor/phases_transform.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file phases_transform.h
|
||||
* @brief Функции для преобразования напряжений/токов в многофазных системах
|
||||
******************************************************************************
|
||||
*****************************************************************************/
|
||||
#ifndef _PHASES_TRANSFORM_H_
|
||||
#define _PHASES_TRANSFORM_H_
|
||||
#include "main.h"
|
||||
|
||||
/* Рассчитать результирующий вектор трехфазной системы по фазным величинам. */
|
||||
float vector_abs_phase_calc(float phase1, float phase2);
|
||||
/* Рассчитать результирующий вектор трехфазной системы по линейным величинам. */
|
||||
float vector_abs_linear_calc(float phase1, float phase2);
|
||||
/* Рассчитать фазные напряжения из линейных (звезда) */
|
||||
void linear_to_phase_star(float *Ulin, float *UphUc);
|
||||
/* Рассчитать фазные напряжения из линейных (треугольник) */
|
||||
void linear_to_phase_delta(float *Ulin, float *Uph);
|
||||
#endif /* _PHASES_TRANSFORM_H_ */
|
||||
@@ -6,10 +6,21 @@
|
||||
* @details
|
||||
******************************************************************************/
|
||||
#include "power_monitor.h"
|
||||
#include "power_protect.h"
|
||||
#include "phases_transform.h"
|
||||
#include "adc.h"
|
||||
#include "tim.h"
|
||||
|
||||
#define U_BC_calc(_uab_, _uca_) (-((_uab_) + (_uca_)))
|
||||
#define I_B_calc(_ia_, _ic_) (-((_ia_) + (_ic_)))
|
||||
|
||||
static void __SynchAvgFilters(PowerMonitor_t *hpm);
|
||||
|
||||
/**
|
||||
* @brief Инициализация мониторинга сети.
|
||||
* @param hpm Указатель на структуру мониторинга сети
|
||||
* @details Инициализирует: АЦП, Алгоритм перехода через ноль, Фильтры
|
||||
*/
|
||||
HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
|
||||
{
|
||||
if(hpm == NULL)
|
||||
@@ -19,160 +30,200 @@ HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm)
|
||||
if(ADC_Init(&hpm->adc, &adc_tim, &hadc3) != HAL_OK)
|
||||
return HAL_ERROR;
|
||||
|
||||
/* Инициализация каналов АЦП */
|
||||
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_UBA,
|
||||
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_UBA],
|
||||
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UBA],
|
||||
4095) != HAL_OK)
|
||||
return HAL_ERROR;
|
||||
|
||||
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_UAC,
|
||||
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_UAC],
|
||||
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UAC],
|
||||
4095) != HAL_OK)
|
||||
return HAL_ERROR;
|
||||
|
||||
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_IC,
|
||||
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_IC],
|
||||
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_IC],
|
||||
4095) != HAL_OK)
|
||||
return HAL_ERROR;
|
||||
|
||||
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_IA,
|
||||
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_IA],
|
||||
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_IA],
|
||||
4095) != HAL_OK)
|
||||
return HAL_ERROR;
|
||||
|
||||
|
||||
/* Инициализация алгоритма перехода через ноль */
|
||||
if(ZC_Init(&hpm->zc, 3, (float)MB_INTERNAL.param.zc.Hysteresis/100, MB_INTERNAL.param.zc.DebouneCouner) != HAL_OK)
|
||||
if(ZC_Init(&hpm->zc, 3, 0, 0) != HAL_OK)
|
||||
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;
|
||||
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;
|
||||
if(ZC_ConfigChannel(&hpm->zc, U_BC, ZC_BOTH_EDGES) != HAL_OK)
|
||||
return HAL_ERROR;
|
||||
|
||||
|
||||
/* Инициализация экпоненциального фильтра медленного алга */
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
if(FilterExp_Init(&hpm->measured.exp[i], (float)MB_INTERNAL.param.pm.mean_alpha/65535))
|
||||
return HAL_ERROR;
|
||||
Filter_Start(&hpm->measured.exp[i]);
|
||||
}
|
||||
|
||||
/* Инициализация среднего фильтра медленного алга */
|
||||
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
||||
{
|
||||
if(FilterAverage_Init(&hpm->measured.avg[i], PM_SLOW_PERIOD_10US, FILTER_MODE_DEFAULT))
|
||||
if(FilterAverage_Init(&hpm->avg[i], PM_SLOW_PERIOD_CNT, FILTER_MODE_DEFAULT))
|
||||
return HAL_ERROR;
|
||||
|
||||
Filter_Start(&hpm->measured.avg[i]);
|
||||
Filter_Start(&hpm->avg[i]);
|
||||
}
|
||||
/* Инициализация среднего фильтра для температур */
|
||||
for(int i = 0; i < ADC_NUMB_OF_T_CHANNELS; i++)
|
||||
{
|
||||
if(FilterAverage_Init(&hpm->measured.avg[ADC_TEMP_CHANNELS_START+i], PM_TEMP_PERIOD_10US, FILTER_MODE_DEFAULT))
|
||||
if(FilterAverage_Init(&hpm->avg[AVG_TEMP1+i], MS_TO_SLOW_TICKS(PM_TEMP_SLOW_PERIOD_MS), FILTER_MODE_DEFAULT))
|
||||
return HAL_ERROR;
|
||||
|
||||
Filter_Start(&hpm->measured.avg[ADC_TEMP_CHANNELS_START+i]);
|
||||
Filter_Start(&hpm->avg[ADC_TEMP_CHANNELS_START+i]);
|
||||
}
|
||||
/* Инициализация среднего фильтра для частот */
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
if(FilterAverage_Init(&hpm->avg[AVG_FAB+i], MS_TO_SLOW_TICKS(PM_F_SLOW_PERIOD_MS), FILTER_MODE_DEFAULT))
|
||||
return HAL_ERROR;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Запустить мониторинг сети.
|
||||
* @param hpm Указатель на структуру мониторинга сети
|
||||
* @details Запускает АЦП с периодом @ref PM_FAST_PERIOD_US
|
||||
*/
|
||||
HAL_StatusTypeDef PowerMonitor_Start(PowerMonitor_t *hpm)
|
||||
{
|
||||
if(hpm == NULL)
|
||||
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_OK;
|
||||
}
|
||||
|
||||
|
||||
void PowerMonitor_SlowHandle(PowerMonitor_t *hpm)
|
||||
/**
|
||||
* @brief Медленные расчеты АЦП.
|
||||
* @param hpm Указатель на структуру мониторинга сети
|
||||
* @details Вызывается в main после накопления @ref PM_SLOW_PERIOD_CNT выборок АЦП.
|
||||
* Делаются всякие расчеты для более подробного мониторинга сети и защит.
|
||||
* Сам АЦП считывается в @ref PowerMonitor_FastCalc
|
||||
*/
|
||||
void PowerMonitor_SlowCalc(PowerMonitor_t *hpm)
|
||||
{
|
||||
if(hpm == NULL)
|
||||
return;
|
||||
if(!hpm->f.runSlow)
|
||||
return;
|
||||
hpm->f.runSlow = 0;
|
||||
PowerMonitor_Measured_t *meas = &hpm->measured;
|
||||
|
||||
meas->Uslow[U_BC] = -meas->Uslow[U_BA] - meas->Uslow[U_AC];
|
||||
meas->Islow[I_B] = -meas->Islow[I_A] - meas->Islow[I_C];
|
||||
/* Обработка температур */
|
||||
ADC_UpdateTemperatures(&hpm->adc);
|
||||
float t1 = hpm->adc.Data[ADC_CHANNEL_TEMP1];
|
||||
float t2 = hpm->adc.Data[ADC_CHANNEL_TEMP2];
|
||||
meas->final.T[TEMP_1] = Filter_Process(&hpm->avg[AVG_TEMP1], t1);
|
||||
meas->final.T[TEMP_2] = Filter_Process(&hpm->avg[AVG_TEMP2], t2);
|
||||
|
||||
float umean = 0;
|
||||
float imean = 0;
|
||||
float fmean = 0;
|
||||
/* Расчет третьей фазы */
|
||||
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]);
|
||||
|
||||
/* Расчет всякого для трех фаз отдельно */
|
||||
float fmean = 0; // средняя частота по трем фазам
|
||||
float umean = 0; // средний напряжение по трем фазам
|
||||
float imean = 0; // средний ток по трем фазам
|
||||
float iphase_mean = 0; // средний ток каждой фазы
|
||||
float uphase_mean = 0; // среднее напряжение каждой фазы
|
||||
// Дополнительно посчитаем значения в реальных Вольтах/Амперах
|
||||
float u_base = u2f(PARAM_INTERNAL.nominal.U, 10);
|
||||
float i_base = u2f(PARAM_INTERNAL.nominal.I, 10);
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
umean += ABS(meas->Uslow[i]);
|
||||
imean += ABS(meas->Islow[i]);
|
||||
fmean += ABS(meas->F[i]);
|
||||
}
|
||||
umean /=3;
|
||||
imean /=3;
|
||||
fmean /=3;
|
||||
/* Получение частоты фазы */
|
||||
meas->final.F[i] = Filter_Process(&hpm->avg[AVG_F+i], ZC_GetFrequency(&hpm->zc, i));
|
||||
// meas->final.Offset[i] = ZC_GetOffset(&hpm->zc, i);
|
||||
fmean += meas->final.F[i];
|
||||
|
||||
meas->U_mean = Filter_Process(&meas->exp[0], umean);
|
||||
meas->I_mean = Filter_Process(&meas->exp[1], imean);
|
||||
meas->F_mean = Filter_Process(&meas->exp[2], fmean);
|
||||
/* Средниее напряжение фазы */
|
||||
uphase_mean = Filter_Process(&hpm->rms[RMS_U+i], meas->slow.U[i]);
|
||||
meas->final.U[i] = Filter_Process(&hpm->rms_exp[RMS_U+i], uphase_mean);
|
||||
|
||||
/* Средний ток фазы */
|
||||
iphase_mean = Filter_Process(&hpm->rms[RMS_I+i], meas->slow.I[i]);
|
||||
meas->final.I[i] = Filter_Process(&hpm->rms_exp[RMS_I+i], iphase_mean);
|
||||
imean += meas->final.I[i];
|
||||
|
||||
/* Реальные единицы измерения (Вольты/Амперы) */
|
||||
meas->real.I[i] = meas->final.I[i]*i_base;
|
||||
meas->real.U[i] = meas->final.U[i]*u_base;
|
||||
}
|
||||
/* Получение средней частоты по трем фазам */
|
||||
meas->final.Fmean = fmean / 3;
|
||||
// /* Оределение сдвига фаз */
|
||||
// static uint32_t prev_tick_phase_a = 0;
|
||||
// if(prev_tick_phase_a != hpm->zc.Channel[0].PeriodStartTime)
|
||||
// { // Определяем только когда начался новый период фазы A
|
||||
// prev_tick_phase_a = hpm->zc.Channel[0].PeriodStartTime;
|
||||
// meas->final.Phase[0] = 0;
|
||||
// meas->final.Phase[1] = ZC_GetPhaseShift(&hpm->zc, 0, 1);
|
||||
// meas->final.Phase[2] = ZC_GetPhaseShift(&hpm->zc, 0, 2);
|
||||
// }
|
||||
|
||||
|
||||
/* Расчет амплитуд трехфазной сети */
|
||||
// float uamp = vector_abs_linear_calc(meas->slow.U[U_AB], meas->slow.U[U_CA])/SQRT2; /* SQRT2 - получить действующее */
|
||||
// float iamp = vector_abs_phase_calc(meas->slow.I[I_A], meas->slow.I[I_C]);
|
||||
float uamp = umean / 3;
|
||||
float iamp = imean / 3;
|
||||
meas->final.Uamp = 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++;
|
||||
}
|
||||
|
||||
void PowerMonitor_Handle(PowerMonitor_t *hpm)
|
||||
/**
|
||||
* @brief Считывание АЦП и быстрые расчеты.
|
||||
* @param hpm Указатель на структуру мониторинга сети
|
||||
* @details Вызывается в прерывании АЦП по получению данных.
|
||||
* Далее данные считываются и делаются базовые преобразования
|
||||
* Более подробные расчеты в @ref PowerMonitor_SlowCalc
|
||||
*/
|
||||
void PowerMonitor_FastCalc(PowerMonitor_t *hpm)
|
||||
{
|
||||
if(hpm == NULL)
|
||||
return;
|
||||
/* Считываем АЦП */
|
||||
ADC_Handle(&hpm->adc);
|
||||
|
||||
|
||||
/* Заполняем величины */
|
||||
float u_base = u2f(PARAM_INTERNAL.nominal.U, 10);
|
||||
float i_base = u2f(PARAM_INTERNAL.nominal.I, 10);
|
||||
PowerMonitor_Measured_t *meas = &hpm->measured;
|
||||
meas->Ureal[U_BA] = hpm->adc.Data[ADC_CHANNEL_UBA];
|
||||
meas->Ureal[U_AC] = hpm->adc.Data[ADC_CHANNEL_UAC];
|
||||
meas->Ureal[U_BC] = -meas->Ureal[U_BA] - meas->Ureal[U_AC];
|
||||
meas->Ireal[I_C] = hpm->adc.Data[ADC_CHANNEL_IC];
|
||||
meas->Ireal[I_A] = hpm->adc.Data[ADC_CHANNEL_IA];
|
||||
meas->Ireal[I_B] = -meas->Ireal[I_A] - meas->Ireal[I_C];
|
||||
meas->T[TEMP_1] = hpm->adc.Data[ADC_CHANNEL_TEMP1];
|
||||
meas->T[TEMP_2] = hpm->adc.Data[ADC_CHANNEL_TEMP2];
|
||||
|
||||
/* Преобразуем в относительные единицы (о.е.) */
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
meas->U[i] = 10*meas->Ureal[i]/MB_INTERNAL.param.nominal.U;
|
||||
meas->I[i] = 10*meas->Ireal[i]/MB_INTERNAL.param.nominal.I;
|
||||
}
|
||||
/* Считываем АЦП с пересчетами и медианой фильтрацией от выбросов */
|
||||
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_A] = hpm->adc.Data[ADC_CHANNEL_IA]/i_base;
|
||||
meas->fast.I[I_B] = I_B_calc(meas->fast.I[I_A], meas->fast.I[I_C]);
|
||||
|
||||
/* Ищем переход через ноль */
|
||||
ZC_ProcessAllChannels(&hpm->zc, meas->U, usTick);
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
meas->F[i] = ZC_GetFrequency(&hpm->zc, i) / 2;
|
||||
}
|
||||
ZC_ProcessAllChannels(&hpm->zc, meas->fast.U, usTick);
|
||||
|
||||
/* Вообще фильтры должны рабтоать синхронно, но на всякий синхронизация */
|
||||
//__SynchAvgFilters(hpm);
|
||||
|
||||
/* Average для медленной фильтрации */
|
||||
meas->slow.U[U_AB] = Filter_Process(&hpm->avg[AVG_UAB], meas->fast.U[U_AB]);
|
||||
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_A] = Filter_Process(&hpm->avg[AVG_IA], meas->fast.I[I_A]);
|
||||
|
||||
/* Накопление Average для медленной фильтрации */
|
||||
meas->Uslow[U_BA] = Filter_Process(&meas->avg[0], meas->U[U_BA]);
|
||||
meas->Uslow[U_AC] = Filter_Process(&meas->avg[1], meas->U[U_AC]);
|
||||
meas->Islow[I_C] = Filter_Process(&meas->avg[2], meas->I[I_C]);
|
||||
meas->Islow[I_A] = Filter_Process(&meas->avg[3], meas->I[I_A]);
|
||||
meas->T[TEMP_1] = Filter_Process(&meas->avg[4], meas->T[TEMP_1]);
|
||||
meas->T[TEMP_2] = Filter_Process(&meas->avg[5], meas->T[TEMP_2]);
|
||||
|
||||
/* Запускаем медленную обработку через slow_period прерываний */
|
||||
// if(hpm->isr_cnt == PM_SLOW_PERIOD_10US)
|
||||
// if(hpm->isr_cnt == PM_SLOW_PERIOD_CNT)
|
||||
/* Запускаем медленную когда фильтры среднего зациклились */
|
||||
if(Filter_isDataReady(&meas->avg[0]))
|
||||
/* Берем 0 фильтр, просто так, потому что они все должны работать синхронно */
|
||||
if(Filter_isDataReady(&hpm->avg[0]))
|
||||
{
|
||||
hpm->isr_cnt = 0;
|
||||
if(!hpm->f.runSlow)
|
||||
@@ -181,8 +232,8 @@ void PowerMonitor_Handle(PowerMonitor_t *hpm)
|
||||
}
|
||||
else // если уже запущена - ставим overrun slow calc
|
||||
{
|
||||
errors.prvt.f.err.slow_calc_overrun = 1;
|
||||
errors.prvt.cnt.slow_calc_overrun++;
|
||||
ERR_PRIVATE.overrun_slow_calc = 1;
|
||||
ERR_PRIVATE_CNT.overrun_slow_calc++;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -190,3 +241,66 @@ void PowerMonitor_Handle(PowerMonitor_t *hpm)
|
||||
hpm->isr_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Проверяет защиты питания и температур.
|
||||
* @param measure Указатель на структуру с измеренными значениями
|
||||
* @param Running Флаг для защит по току:
|
||||
* - 1 - УПП в работе, проверяем токи
|
||||
* - 0 - УПП ожидает команды, не смотрим токи
|
||||
* @return 1 - была обнаружена ощибка, 0 - все ок
|
||||
*/
|
||||
int PowerMonitor_Protect(PowerMonitor_t *hpm, uint8_t Running)
|
||||
{
|
||||
if(hpm == NULL)
|
||||
return 1;
|
||||
|
||||
PowerMonitor_Measured_t *measure = &hpm->measured;
|
||||
UPP_PUI_Params_t *protect = &PARAM_PUI;
|
||||
UPP_ParamsNominal_t *nominal = &PARAM_INTERNAL.nominal;
|
||||
|
||||
/*=============== ЗАЩИТЫ ПО НАПРЯЖЕНИЮ ==================*/
|
||||
hpm->f.isU = Protect_Voltages(measure, protect, nominal);
|
||||
|
||||
/* Если УПП в работе */
|
||||
if(Running)
|
||||
{
|
||||
/*=============== ЗАЩИТЫ ПО ТОКУ ==================*/
|
||||
hpm->f.isI = Protect_Currents(measure, protect, nominal);
|
||||
}
|
||||
|
||||
/*=============== ЗАЩИТЫ ВСЯКИЕ ДРУГИЕ ==================*/
|
||||
Protect_Misc(measure, protect, nominal);
|
||||
|
||||
|
||||
if(errors.prvt.f.all)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Синхронизация фильтров. Но вообще не должна никогда отрабатывать */
|
||||
static void __SynchAvgFilters(PowerMonitor_t *hpm)
|
||||
{
|
||||
uint8_t counts_equal = 1;
|
||||
uint32_t first_count = hpm->avg[0].count;
|
||||
for (int i = 1; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
||||
{
|
||||
if (hpm->avg[i].count != first_count)
|
||||
{
|
||||
counts_equal = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!counts_equal)
|
||||
{
|
||||
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
||||
{
|
||||
Filter_ReInit(&hpm->avg[i], hpm->avg[i].size, FILTER_MODE_DEFAULT);
|
||||
Filter_Start(&hpm->avg[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,8 @@
|
||||
* @file power_monitor.h
|
||||
* @brief Модуль мониторящий сеть: Напряжение, Токи, Температуры
|
||||
******************************************************************************
|
||||
* @addtogroup POWER_MONITOR Power Monitoring
|
||||
* @brief Модуль для слежения за сетью и температурами (крч все что от АЦП)
|
||||
*****************************************************************************/
|
||||
#ifndef _POWER_MONITOR_H_
|
||||
#define _POWER_MONITOR_H_
|
||||
@@ -10,66 +12,122 @@
|
||||
#include "adc_tools.h"
|
||||
#include "zero_cross.h"
|
||||
|
||||
/* Индексы RMS фильтров */
|
||||
#define RMS_ALL 6
|
||||
#define RMS_U 0
|
||||
#define RMS_UAB 0
|
||||
#define RMS_UCA 1
|
||||
#define RMS_UBC 2
|
||||
#define RMS_I 3
|
||||
#define RMS_IC 3
|
||||
#define RMS_IA 4
|
||||
#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_UAB 0
|
||||
#define AVG_UCA 1
|
||||
#define AVG_IC 2
|
||||
#define AVG_IA 3
|
||||
#define AVG_TEMP1 4
|
||||
#define AVG_TEMP2 5
|
||||
#define AVG_F 6
|
||||
#define AVG_FAB 6
|
||||
#define AVG_FCA 7
|
||||
#define AVG_FBC 8
|
||||
|
||||
/**
|
||||
* @brief Флаги Мониторинга сети
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
unsigned inIsr:1; ///< Флаг что мы в прерывании
|
||||
unsigned runSlow:1; ///< Запустить медленный алгоритм в while(1)
|
||||
|
||||
unsigned isU:1; ///< Есть ли напряжение
|
||||
unsigned isI:1; ///< Есть ли ток
|
||||
|
||||
unsigned protectUmax:1; ///< Отработка защиты по макс. напряжению
|
||||
unsigned protectUmin:1; ///< Отработка защиты по мак с. напряжению
|
||||
unsigned protectImax:1; ///< Отработка защиты по макс. току
|
||||
unsigned protectImin:1; ///< Отработка защиты по мин. току
|
||||
}PowerMonitor_Flags_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Измеренные и приведенные значения с АЦП
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
float U_mean; ///< Среднее Напряжение по трем фазам
|
||||
float I_mean; ///< Средний Ток по трем фазам
|
||||
float F_mean; ///< Средняя Частота по трем фазам
|
||||
float Uslow[3]; ///< Напряжение от АЦП (в о.е.)
|
||||
float Islow[3]; ///< Ток от АЦП (в о.е.)
|
||||
/** @brief Усредненные величины (о.е.) */
|
||||
struct
|
||||
{
|
||||
float Uamp; ///< Результирующий вектор Напряжения по трем фазам
|
||||
float Iamp; ///< Результирующий вектор Тока по трем фазам
|
||||
float U[3]; ///< Среднее Наряжение по трем фазам
|
||||
float I[3]; ///< Средний Ток по трем фазам
|
||||
float Fmean; ///< Средняя Частота по трем фазам
|
||||
float F[3]; ///< Частота от Zero Cross (обновляется в main)
|
||||
float Phase[3]; ///< Фазовое смещение по отношению к фазе A
|
||||
float Offset[3]; ///< Смещение синуса относителньо нуля (определяется по отношению полупериодов)
|
||||
float T[2]; ///< Температура (обновляется в main)
|
||||
}final;
|
||||
|
||||
/** @brief Быстрые величины (в о.е.) - обновляются в каждом прерывании АЦП @ref PowerMonitor_FastCalc */
|
||||
struct
|
||||
{
|
||||
float U[3]; ///< Напряжение
|
||||
float I[3]; ///< Ток
|
||||
}fast;
|
||||
|
||||
float U[3]; ///< Напряжение от АЦП (в о.е.)
|
||||
float I[3]; ///< Ток от АЦП (в о.е.)
|
||||
float F[3]; ///< Частота от Zero Cross
|
||||
float T[2]; ///< Температура от АЦП
|
||||
/** @brief Медленные величины (в о.е.) - обновляются в main в @ref PowerMonitor_SlowCalc */
|
||||
struct
|
||||
{
|
||||
float U[3]; ///< Напряжение
|
||||
float I[3]; ///< Ток
|
||||
}slow;
|
||||
|
||||
/** @brief Реальные величины - обновляются в main в @ref PowerMonitor_SlowCalc, и содержат значения в В/А */
|
||||
struct
|
||||
{
|
||||
float U[3]; ///< Напряжение (Действующее)
|
||||
float I[3]; ///< Ток (Действующее)
|
||||
}real;
|
||||
|
||||
float Ureal[3]; ///< Напряжение от АЦП
|
||||
float Ireal[3]; ///< Ток от АЦП
|
||||
|
||||
FilterExp_t exp[3]; ///< Фильтры для mean
|
||||
FilterAverage_t avg[6]; ///< Фильтры для avg
|
||||
}PowerMonitor_Measured_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
}PowerMonitor_Filters_t;
|
||||
|
||||
/**
|
||||
* @brief Структура для мониторинга сети
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ADC_Periodic_t adc; ///< Хендл периодического АЦП
|
||||
ZeroCross_Handle_t zc; ///< Хендл перехода через ноль
|
||||
PowerMonitor_Filters_t fltr;
|
||||
|
||||
PowerMonitor_Measured_t measured; ///< Измеренные/рассчитанные величины
|
||||
|
||||
FilterBandPassDerivative_t ufltr[2]; ///< Фильтры для сглаживаний напряжений в синусы
|
||||
FilterRMS_t rms[RMS_ALL]; ///< Фильтры для расчета действующего значения Напряжения/Токов
|
||||
FilterExp_t rms_exp[RMS_EXP_ALL]; ///< Фильтры для сглаживания действующего значения Напряжения/Токов +2 для результируюзих U, I
|
||||
FilterAverage_t avg[AVG_ALL]; ///< Фильтры для сглаживания медленных величин АЦП
|
||||
|
||||
PowerMonitor_Flags_t f; ///< Флаги мониторинга
|
||||
|
||||
|
||||
uint32_t slow_period;
|
||||
uint32_t isr_cnt;
|
||||
uint32_t slow_cnt;
|
||||
}PowerMonitor_t;
|
||||
extern PowerMonitor_t pm;
|
||||
|
||||
|
||||
// ====== ИНИЦИАЛИЗАЦИЯ ==========
|
||||
/* Инициализация мониторинга сети */
|
||||
HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm);
|
||||
/* Запустить мониторинг сети */
|
||||
HAL_StatusTypeDef PowerMonitor_Start(PowerMonitor_t *hpm);
|
||||
|
||||
void PowerMonitor_SlowHandle(PowerMonitor_t *hpm);
|
||||
void PowerMonitor_Handle(PowerMonitor_t *hpm);
|
||||
// ====== РАСЧЕТЫ ==========
|
||||
/* Медленные расчеты АЦП */
|
||||
void PowerMonitor_SlowCalc(PowerMonitor_t *hpm);
|
||||
/* Считывание АЦП и быстрые расчеты */
|
||||
void PowerMonitor_FastCalc(PowerMonitor_t *hpm);
|
||||
/* Проверяет защиты питания и температур */
|
||||
int PowerMonitor_Protect(PowerMonitor_t *hpm, uint8_t Running);
|
||||
|
||||
#endif /* _POWER_MONITOR_H_ */
|
||||
|
||||
203
UPP/Core/PowerMonitor/power_protect.c
Normal file
203
UPP/Core/PowerMonitor/power_protect.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file power_protect.c
|
||||
* @brief Модуль реализующий защиты по Напряжению/Токам/Температуре
|
||||
******************************************************************************
|
||||
* @details
|
||||
******************************************************************************/
|
||||
#include "power_protect.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief Проверяет защиты по напряжению.
|
||||
* @note Заполняет флаги prvt ошибок (приватные).
|
||||
* Потом в @ref UPP_ErrorsHandle исходя из них заполняются ошибки для ПУИ
|
||||
* @return 1 - напряжение есть, 0 - напряжения нет
|
||||
*/
|
||||
int Protect_Voltages(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal)
|
||||
{
|
||||
/* Переводим уставки ПУИ в удобный вид */
|
||||
float lUmin = u2f(protect->Umin, 100)/**u2f(nominal->U, 10)*/;
|
||||
float lUmax = u2f(protect->Umax, 100)/**u2f(nominal->U, 10)*/;
|
||||
float lPhaseSequence = u2f(nominal->PhaseSequence, 100);
|
||||
|
||||
/* Общее напряжение */
|
||||
if(measure->final.Uamp > lUmax)
|
||||
{
|
||||
ERR_PRIVATE.uamp_max = 1;
|
||||
}
|
||||
else if (measure->final.Uamp < lUmin)
|
||||
{
|
||||
ERR_PRIVATE.uamp_min = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_PRIVATE.uamp_max = 0;
|
||||
ERR_PRIVATE.uamp_min = 0;
|
||||
}
|
||||
|
||||
/* Последовательность фаз */
|
||||
int realPhaseSequence = 0;
|
||||
if(realPhaseSequence != lPhaseSequence)
|
||||
{
|
||||
ERR_PRIVATE.interlance = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_PRIVATE.interlance = 0;
|
||||
}
|
||||
|
||||
return (ERR_PRIVATE.uamp_min == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверяет защиты по току.
|
||||
* @note Заполняет флаги prvt ошибок (приватные).
|
||||
* Потом в @ref UPP_ErrorsHandle исходя из них заполняются ошибки для ПУИ
|
||||
*/
|
||||
int Protect_Currents(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal)
|
||||
{
|
||||
/* Переводим уставки ПУИ в удобный вид */
|
||||
float lIref = u2f(protect->Iref, 100)/**u2f(nominal->I, 10)*/;
|
||||
float lImin = u2f(protect->Imin, 100)/**u2f(nominal->I, 10)*/;
|
||||
float lImax = u2f(protect->Imax, 100) * 50 / u2f(nominal->I, 10); // Imax процентов от 50 А, в о.е. от номинального
|
||||
|
||||
/* Общий ток */
|
||||
if(measure->final.Iamp > lImax)
|
||||
{
|
||||
ERR_PRIVATE.iamp_max = 1;
|
||||
}
|
||||
else if (measure->final.Iamp < lImin)
|
||||
{
|
||||
ERR_PRIVATE.iamp_min = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_PRIVATE.iamp_max = 0;
|
||||
ERR_PRIVATE.iamp_min = 0;
|
||||
}
|
||||
|
||||
/* Ток по фазам */
|
||||
if(measure->final.I[I_A] > lImax)
|
||||
{
|
||||
ERR_PRIVATE.ia_max = 1;
|
||||
}
|
||||
else if (measure->final.I[I_A] < lImin)
|
||||
{
|
||||
ERR_PRIVATE.ia_min = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_PRIVATE.ia_max = 0;
|
||||
ERR_PRIVATE.ia_min = 0;
|
||||
}
|
||||
|
||||
if(measure->final.I[I_B] > lImax)
|
||||
{
|
||||
ERR_PRIVATE.ib_max = 1;
|
||||
}
|
||||
else if (measure->final.I[I_B] < lImin)
|
||||
{
|
||||
ERR_PRIVATE.ib_min = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_PRIVATE.ib_max = 0;
|
||||
ERR_PRIVATE.ib_min = 0;
|
||||
}
|
||||
|
||||
if(measure->final.I[I_C] > lImax)
|
||||
{
|
||||
ERR_PRIVATE.ic_max = 1;
|
||||
}
|
||||
else if (measure->final.I[I_C] < lImin)
|
||||
{
|
||||
ERR_PRIVATE.ic_min = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_PRIVATE.ic_max = 0;
|
||||
ERR_PRIVATE.ic_min = 0;
|
||||
}
|
||||
|
||||
return (ERR_PRIVATE.iamp_min == 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Проверяет всякие другие защиты (частота, температура).
|
||||
* @note Заполняет флаги prvt ошибок (приватные).
|
||||
* Потом в @ref UPP_ErrorsHandle исходя из них заполняются ошибки для ПУИ
|
||||
*/
|
||||
void Protect_Misc(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal)
|
||||
{
|
||||
/* Переводим внутренние уставки в удобный вид */
|
||||
float lFnom = u2f(PARAM_INTERNAL.nominal.F, 100);
|
||||
float lFmin = lFnom - lFnom*u2f(PARAM_INTERNAL.nominal.F_deviation_minus, 10000);
|
||||
float lFmax = lFnom + lFnom*u2f(PARAM_INTERNAL.nominal.F_deviation_plus, 10000);
|
||||
|
||||
float lTwarn = u2f(PARAM_INTERNAL.setpoints.TemperatureWarn, 100);
|
||||
float lTerr = u2f(PARAM_INTERNAL.setpoints.TemperatureWarn, 100);
|
||||
|
||||
|
||||
/*=============== ЗАЩИТЫ ПО ЧАСТОТЕ ==================*/
|
||||
if(measure->final.F[U_CA] > lFmax)
|
||||
{
|
||||
ERR_PRIVATE.fac_max = 1;
|
||||
}
|
||||
else if (measure->final.F[U_CA] < lFmin)
|
||||
{
|
||||
ERR_PRIVATE.fac_min = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_PRIVATE.fac_max = 0;
|
||||
ERR_PRIVATE.fac_min = 0;
|
||||
}
|
||||
|
||||
if(measure->final.F[U_AB] > lFmax)
|
||||
{
|
||||
ERR_PRIVATE.fba_max = 1;
|
||||
}
|
||||
else if (measure->final.F[U_AB] < lFmin)
|
||||
{
|
||||
ERR_PRIVATE.fba_min = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_PRIVATE.fba_max = 0;
|
||||
ERR_PRIVATE.fba_min = 0;
|
||||
}
|
||||
|
||||
if(measure->final.F[U_BC] > lFmax)
|
||||
{
|
||||
ERR_PRIVATE.fbc_max = 1;
|
||||
}
|
||||
else if (measure->final.F[U_BC] < lFmin)
|
||||
{
|
||||
ERR_PRIVATE.fbc_min = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_PRIVATE.fbc_max = 0;
|
||||
ERR_PRIVATE.fbc_min = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*=============== ЗАЩИТЫ ПО ТЕМПЕРАТУРЕ ==================*/
|
||||
if(measure->final.T[TEMP_1] > lTerr)
|
||||
{
|
||||
ERR_PRIVATE.temp_err = 1;
|
||||
}
|
||||
else if (measure->final.T[TEMP_1] > lTwarn)
|
||||
{
|
||||
ERR_PRIVATE.temp_warn = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR_PRIVATE.temp_err = 0;
|
||||
ERR_PRIVATE.temp_warn = 0;
|
||||
}
|
||||
}
|
||||
18
UPP/Core/PowerMonitor/power_protect.h
Normal file
18
UPP/Core/PowerMonitor/power_protect.h
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file power_monitor.h
|
||||
* @brief Модуль реализующий защиты по Напряжению/Токам/Температуре
|
||||
******************************************************************************
|
||||
*****************************************************************************/
|
||||
#ifndef _POWER_PROTECT_H_
|
||||
#define _POWER_PROTECT_H_
|
||||
#include "power_monitor.h"
|
||||
|
||||
|
||||
/* Проверяет защиты по напряжению. */
|
||||
int Protect_Voltages(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal);
|
||||
/* Проверяет защиты по току. */
|
||||
int Protect_Currents(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal);
|
||||
/* Проверяет всякие другие защиты (частота, температура). */
|
||||
void Protect_Misc(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *protect, UPP_ParamsNominal_t *nominal);
|
||||
#endif /* _POWER_PROTECT_H_ */
|
||||
@@ -103,6 +103,7 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin
|
||||
zc_ch->CurrentValue = value;
|
||||
|
||||
|
||||
#ifndef ZC_DISABLE_HYSTERESIS_DEBOUNCE
|
||||
// Фильтрация дребезга
|
||||
if(zc_ch->DebounceCounter > 0)
|
||||
{
|
||||
@@ -144,6 +145,25 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin
|
||||
zc_detected = -1;
|
||||
}
|
||||
}
|
||||
#else //ZC_DISABLE_HYSTERESIS_DEBOUNCE
|
||||
// Детектирование rising edge (отрицательное -> положительное)
|
||||
if ((zc_ch->LastValue < 0) &&
|
||||
(value > 0))
|
||||
{
|
||||
|
||||
if (zc_ch->EdgeType == ZC_RISING_EDGE || zc_ch->EdgeType == ZC_BOTH_EDGES) {
|
||||
zc_detected = 1;
|
||||
}
|
||||
}
|
||||
// Детектирование falling edge (положительное -> отрицательное)
|
||||
else if ((zc_ch->LastValue > 0) &&
|
||||
(value < 0))
|
||||
{
|
||||
if (zc_ch->EdgeType == ZC_FALLING_EDGE || zc_ch->EdgeType == ZC_BOTH_EDGES) {
|
||||
zc_detected = -1;
|
||||
}
|
||||
}
|
||||
#endif //ZC_DISABLE_HYSTERESIS_DEBOUNCE
|
||||
|
||||
if(zc_detected)
|
||||
{
|
||||
@@ -155,21 +175,32 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin
|
||||
uint32_t RealTimestamp = timestamp-RealTimeShift;
|
||||
if (zc_ch->LastCrossTime != 0) {
|
||||
// Расчет периода и частоты
|
||||
zc_ch->Period = RealTimestamp - zc_ch->LastCrossTime;
|
||||
if (zc_ch->Period > 0) {
|
||||
float curr_half_period = RealTimestamp - zc_ch->LastCrossTime;
|
||||
if (curr_half_period > 0) {
|
||||
if(zc_ch->HalfWave == UPP_WAVE_POSITIVE)
|
||||
{
|
||||
zc_ch->PeriodStartTime = RealTimestamp;
|
||||
zc_ch->Period = zc_ch->halfPeriod + curr_half_period;
|
||||
zc_ch->Frequency = 1000000.0f / zc_ch->Period;
|
||||
zc_ch->FrequencyOffset = (float)zc_ch->halfPeriod / curr_half_period;
|
||||
}
|
||||
}
|
||||
zc_ch->halfPeriod = curr_half_period;
|
||||
}
|
||||
|
||||
zc_ch->LastCrossTime = RealTimestamp;
|
||||
zc_ch->CrossCount++;
|
||||
}
|
||||
|
||||
#ifndef ZC_DISABLE_HYSTERESIS_DEBOUNCE
|
||||
// Сохраняем текущее значение для следующей итерации в случае если оно не в мертвой зоне
|
||||
if((value > zc->Config.Hysteresis) || (value < -zc->Config.Hysteresis))
|
||||
{
|
||||
zc_ch->LastValue = value;
|
||||
}
|
||||
#else //ZC_DISABLE_HYSTERESIS_DEBOUNCE
|
||||
zc_ch->LastValue = value;
|
||||
#endif //ZC_DISABLE_HYSTERESIS_DEBOUNCE
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,6 +276,54 @@ float ZC_GetFrequency(ZeroCross_Handle_t *zc, uint8_t channel)
|
||||
return zc->Channel[channel].Frequency;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Получение смещение частот полупериода сигнала.
|
||||
* @param zc Указатель на хендл детектора нуля
|
||||
* @param channel Номер канала
|
||||
* @return Отношение длительности первой полуволны к второй полуволне.
|
||||
*/
|
||||
float ZC_GetOffset(ZeroCross_Handle_t *zc, uint8_t channel)
|
||||
{
|
||||
if (assert_upp(zc)){
|
||||
return 0.0f;
|
||||
}
|
||||
if (channel >= zc->Config.NumChannels) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return zc->Channel[channel].FrequencyOffset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Получить сдвиг между двумя фазами.
|
||||
* @param zc Указатель на хендл детектора нуля
|
||||
* @param channel Номер канала от которого считать сдвиг
|
||||
* @param channe2 Номер канала для которого расчитать сдвиг
|
||||
* @return Фазовый сдвиг в процентах от периода от 1 до 2 канала
|
||||
*/
|
||||
float ZC_GetPhaseShift(ZeroCross_Handle_t *zc, uint8_t channel1, uint8_t channel2)
|
||||
{
|
||||
if (assert_upp(zc)){
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if ((channel1 >= zc->Config.NumChannels) || (channel2 >= zc->Config.NumChannels)){
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float delta_time = 0;
|
||||
if(zc->Channel[channel1].PeriodStartTime >= zc->Channel[channel2].PeriodStartTime)
|
||||
delta_time = (zc->Channel[channel1].PeriodStartTime - zc->Channel[channel2].PeriodStartTime);
|
||||
else
|
||||
delta_time = (zc->Channel[channel2].PeriodStartTime - zc->Channel[channel1].PeriodStartTime);
|
||||
|
||||
|
||||
float phase_ratio = delta_time/zc->Channel[channel1].Period;
|
||||
return phase_ratio;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Включение/выключение мониторинга.
|
||||
* @param zc Указатель на хендл детектора нуля
|
||||
|
||||
@@ -94,8 +94,11 @@ typedef struct {
|
||||
float CurrentValue; ///< Текущее значение
|
||||
uint16_t DebounceCounter; ///< Счетчик антидребезга
|
||||
uint32_t LastCrossTime; ///< Время последнего перехода
|
||||
float halfPeriod; ///< Длительность полупериода (в тактах таймера)
|
||||
uint32_t PeriodStartTime; ///< Время начала периода (в тактах таймера)
|
||||
uint32_t Period; ///< Период сигнала (в тактах таймера)
|
||||
float Frequency; ///< Частота
|
||||
float FrequencyOffset; ///< Смещение частот полупериода - насколько сигнал смещен
|
||||
UPP_HalfWave_t HalfWave; ///< Текущая полуволна
|
||||
ZC_EdgeType_t EdgeType; ///< Тип детектируемого перехода
|
||||
} ZC_Channel_t;
|
||||
@@ -124,33 +127,41 @@ typedef struct {
|
||||
uint32_t LastTick; ///< Послднее время вызова
|
||||
} ZeroCross_Handle_t;
|
||||
|
||||
// ====== ИНИЦИАЛИЗАЦИЯ ==========
|
||||
/* Инициализация детектора нуля с индивидуальными настройками */
|
||||
HAL_StatusTypeDef ZC_Init(ZeroCross_Handle_t *zc, uint8_t num_channels,
|
||||
float hysteresis, uint16_t debounce_samples);
|
||||
|
||||
/* Настройка канала детектора */
|
||||
HAL_StatusTypeDef ZC_ConfigChannel(ZeroCross_Handle_t *zc, uint8_t channel,
|
||||
ZC_EdgeType_t edgeType);
|
||||
|
||||
/* Обработка значения отдельного канала */
|
||||
void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value,
|
||||
uint32_t timestamp);
|
||||
|
||||
/* Пакетная обработка всех каналов */
|
||||
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);
|
||||
/* Получение полуволны (после последнего 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_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value,
|
||||
uint32_t timestamp);
|
||||
/* Пакетная обработка всех каналов */
|
||||
void ZC_ProcessAllChannels(ZeroCross_Handle_t *zc, float *values,
|
||||
uint32_t timestamp);
|
||||
|
||||
// ====== API ==========
|
||||
/* Полученить флаг - переход произошел. */
|
||||
int ZC_isOccurred(ZeroCross_Handle_t *zc, uint8_t channel);
|
||||
/* Получение частоты сигнала */
|
||||
float ZC_GetFrequency(ZeroCross_Handle_t *zc, uint8_t channel);
|
||||
/* Получение смещение частот полупериода сигнала */
|
||||
float ZC_GetOffset(ZeroCross_Handle_t *zc, uint8_t channel);
|
||||
/* Получить сдвиг между двумя фазами. */
|
||||
float ZC_GetPhaseShift(ZeroCross_Handle_t *zc, uint8_t channel1, uint8_t channel2);
|
||||
/* Получение полуволны (после последнего zero-cross) */
|
||||
UPP_HalfWave_t ZC_GetHalfWave(ZeroCross_Handle_t *zc, uint8_t channel);
|
||||
|
||||
#endif /* _ZERO_CROSS_H_ */
|
||||
|
||||
/**
|
||||
|
||||
55
UPP/Core/Src/DBG_stm32f417_support.c
Normal file
55
UPP/Core/Src/DBG_stm32f417_support.c
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file DBG_stm32f417_support.c
|
||||
* @brief Модуль для запуска кода на STM32F417
|
||||
******************************************************************************
|
||||
* @details
|
||||
******************************************************************************/
|
||||
#include "main.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief System Clock Configuration
|
||||
* @retval None
|
||||
*/
|
||||
void SystemClock_Config_STM32F417(void)
|
||||
{
|
||||
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
||||
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
||||
|
||||
/** Configure the main internal regulator output voltage
|
||||
*/
|
||||
__HAL_RCC_PWR_CLK_ENABLE();
|
||||
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
|
||||
|
||||
/** Initializes the RCC Oscillators according to the specified parameters
|
||||
* in the RCC_OscInitTypeDef structure.
|
||||
*/
|
||||
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
|
||||
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
|
||||
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
|
||||
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
||||
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
|
||||
RCC_OscInitStruct.PLL.PLLM = 8;
|
||||
RCC_OscInitStruct.PLL.PLLN = 168;
|
||||
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
|
||||
RCC_OscInitStruct.PLL.PLLQ = 4;
|
||||
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
|
||||
/** Initializes the CPU, AHB and APB buses clocks
|
||||
*/
|
||||
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|
||||
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
||||
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
||||
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
||||
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
|
||||
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
|
||||
|
||||
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
}
|
||||
@@ -50,10 +50,10 @@ void MX_ADC3_Init(void)
|
||||
hadc3.Init.ContinuousConvMode = DISABLE;
|
||||
hadc3.Init.DiscontinuousConvMode = DISABLE;
|
||||
hadc3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
|
||||
hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T8_TRGO;
|
||||
hadc3.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T3_TRGO;
|
||||
hadc3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
|
||||
hadc3.Init.NbrOfConversion = 6;
|
||||
hadc3.Init.DMAContinuousRequests = DISABLE;
|
||||
hadc3.Init.DMAContinuousRequests = ENABLE;
|
||||
hadc3.Init.EOCSelection = ADC_EOC_SEQ_CONV;
|
||||
if (HAL_ADC_Init(&hadc3) != HAL_OK)
|
||||
{
|
||||
@@ -162,7 +162,7 @@ void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
|
||||
hdma_adc3.Init.MemInc = DMA_MINC_ENABLE;
|
||||
hdma_adc3.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
|
||||
hdma_adc3.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
|
||||
hdma_adc3.Init.Mode = DMA_NORMAL;
|
||||
hdma_adc3.Init.Mode = DMA_CIRCULAR;
|
||||
hdma_adc3.Init.Priority = DMA_PRIORITY_LOW;
|
||||
hdma_adc3.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
|
||||
if (HAL_DMA_Init(&hdma_adc3) != HAL_OK)
|
||||
|
||||
@@ -55,20 +55,20 @@ void MX_GPIO_Init(void)
|
||||
__HAL_RCC_GPIOD_CLK_ENABLE();
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOE, UM_LED_GREEN2_Pin|CEN_O_Pin|RDO3_Pin|UM_LED_RED_Pin
|
||||
HAL_GPIO_WritePin(GPIOE, UM_LED_GREEN2_Pin|CEN_Pin|RDO3_Pin|UM_LED_RED_Pin
|
||||
|UM_LED_GREEN1_Pin, GPIO_PIN_SET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(DO2_GPIO_Port, DO2_Pin, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(DO3_GPIO_Port, DO3_Pin, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(DO3_GPIO_Port, DO3_Pin, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(DO5_GPIO_Port, DO5_Pin, GPIO_PIN_RESET);
|
||||
HAL_GPIO_WritePin(GPIOA, DO5_Pin|DO4_Pin, GPIO_PIN_RESET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOA, DO4_Pin|RDO4_Pin, GPIO_PIN_SET);
|
||||
HAL_GPIO_WritePin(RDO4_GPIO_Port, RDO4_Pin, GPIO_PIN_SET);
|
||||
|
||||
/*Configure GPIO pin Output Level */
|
||||
HAL_GPIO_WritePin(GPIOB, DO1_Pin|RDO1_Pin|SCIDE2_Pin|SCIDE1_Pin
|
||||
@@ -86,7 +86,7 @@ void MX_GPIO_Init(void)
|
||||
|
||||
/*Configure GPIO pins : PEPin PEPin PEPin PEPin
|
||||
PEPin */
|
||||
GPIO_InitStruct.Pin = CEN_O_Pin|DO2_Pin|RDO3_Pin|UM_LED_RED_Pin
|
||||
GPIO_InitStruct.Pin = CEN_Pin|DO2_Pin|RDO3_Pin|UM_LED_RED_Pin
|
||||
|UM_LED_GREEN1_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
@@ -147,11 +147,17 @@ void MX_GPIO_Init(void)
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pins : PGPin PGPin */
|
||||
GPIO_InitStruct.Pin = ERR_24V_Pin|DIN1_Pin;
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = ERR_24V_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
|
||||
HAL_GPIO_Init(ERR_24V_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
/*Configure GPIO pin : PtPin */
|
||||
GPIO_InitStruct.Pin = DIN1_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
|
||||
GPIO_InitStruct.Pull = GPIO_PULLUP;
|
||||
HAL_GPIO_Init(DIN1_GPIO_Port, &GPIO_InitStruct);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
#include "can.h"
|
||||
#include "dma.h"
|
||||
#include "iwdg.h"
|
||||
#include "rtc.h"
|
||||
#include "spi.h"
|
||||
#include "tim.h"
|
||||
#include "usart.h"
|
||||
#include "gpio.h"
|
||||
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
@@ -72,7 +72,15 @@ int main(void)
|
||||
{
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
__HAL_FREEZE_IWDG_DBGMCU();
|
||||
__HAL_FREEZE_TIM1_DBGMCU();
|
||||
__HAL_FREEZE_TIM2_DBGMCU();
|
||||
__HAL_FREEZE_TIM3_DBGMCU();
|
||||
__HAL_FREEZE_TIM5_DBGMCU();
|
||||
__HAL_FREEZE_TIM8_DBGMCU();
|
||||
__HAL_FREEZE_TIM11_DBGMCU();
|
||||
__HAL_FREEZE_TIM12_DBGMCU();
|
||||
__HAL_FREEZE_TIM14_DBGMCU();
|
||||
/* USER CODE END 1 */
|
||||
|
||||
/* MCU Configuration--------------------------------------------------------*/
|
||||
@@ -83,22 +91,25 @@ int main(void)
|
||||
/* USER CODE BEGIN Init */
|
||||
|
||||
#ifndef MATLAB
|
||||
#if defined(STM32F427xx)
|
||||
/* USER CODE END Init */
|
||||
|
||||
/* Configure the system clock */
|
||||
SystemClock_Config();
|
||||
|
||||
/* USER CODE BEGIN SysInit */
|
||||
|
||||
#elif defined(STM32F417xx)
|
||||
SystemClock_Config_STM32F417();
|
||||
#endif //defined(STM32F417xx)
|
||||
/* USER CODE END SysInit */
|
||||
|
||||
/* Initialize all configured peripherals */
|
||||
MX_GPIO_Init();
|
||||
MX_DMA_Init();
|
||||
MX_ADC3_Init();
|
||||
MX_USART3_UART_Init();
|
||||
MX_CAN1_Init();
|
||||
MX_IWDG_Init();
|
||||
MX_RTC_Init();
|
||||
MX_TIM1_Init();
|
||||
MX_TIM3_Init();
|
||||
MX_USART6_UART_Init();
|
||||
@@ -109,9 +120,15 @@ int main(void)
|
||||
MX_TIM5_Init();
|
||||
MX_TIM2_Init();
|
||||
/* USER CODE BEGIN 2 */
|
||||
// меняем прескалер на частоту по дефайну
|
||||
__HAL_TIM_SET_PRESCALER_FORCE(&ustim, US_TIM5_FREQ_MHZ-1);
|
||||
#if defined(STM32F417xx)
|
||||
// т.к. нет епромки выставляем дефолтные
|
||||
UPP_Params_SetDefault(1, 1);
|
||||
#endif //defined(STM32F417xx)
|
||||
#else //MATLAB
|
||||
#endif //MATLAB
|
||||
UPP_Init();
|
||||
UPP_App_Init();
|
||||
/* USER CODE END 2 */
|
||||
|
||||
/* Infinite loop */
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
/* Private includes ----------------------------------------------------------*/
|
||||
/* USER CODE BEGIN Includes */
|
||||
#include "upp_main.h"
|
||||
#include "pwm_thyristors.h"
|
||||
#include "angle_control.h"
|
||||
/* USER CODE END Includes */
|
||||
|
||||
/* Private typedef -----------------------------------------------------------*/
|
||||
@@ -216,7 +214,7 @@ void TIM1_UP_TIM10_IRQHandler(void)
|
||||
/* USER CODE END TIM1_UP_TIM10_IRQn 0 */
|
||||
HAL_TIM_IRQHandler(&htim1);
|
||||
/* USER CODE BEGIN TIM1_UP_TIM10_IRQn 1 */
|
||||
UPP_PWM_Handle();
|
||||
//UPP_PWM_Handle();
|
||||
/* USER CODE END TIM1_UP_TIM10_IRQn 1 */
|
||||
}
|
||||
|
||||
@@ -234,19 +232,33 @@ void TIM2_IRQHandler(void)
|
||||
/* 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.
|
||||
*/
|
||||
void TIM8_TRG_COM_TIM14_IRQHandler(void)
|
||||
{
|
||||
/* USER CODE BEGIN TIM8_TRG_COM_TIM14_IRQn 0 */
|
||||
|
||||
#ifndef MATLAB // в матлабе нет htim14, т.к. это систем тики
|
||||
/* USER CODE END TIM8_TRG_COM_TIM14_IRQn 0 */
|
||||
HAL_TIM_IRQHandler(&htim8);
|
||||
HAL_TIM_IRQHandler(&htim14);
|
||||
/* USER CODE BEGIN TIM8_TRG_COM_TIM14_IRQn 1 */
|
||||
#endif
|
||||
UPP_Tick();
|
||||
/* USER CODE END TIM8_TRG_COM_TIM14_IRQn 1 */
|
||||
}
|
||||
|
||||
@@ -256,11 +268,14 @@ void TIM8_TRG_COM_TIM14_IRQHandler(void)
|
||||
void DMA2_Stream0_IRQHandler(void)
|
||||
{
|
||||
/* 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 */
|
||||
HAL_DMA_IRQHandler(&hdma_adc3);
|
||||
/* USER CODE BEGIN DMA2_Stream0_IRQn 1 */
|
||||
UPP_ADC_Handle();
|
||||
|
||||
/* USER CODE END DMA2_Stream0_IRQn 1 */
|
||||
}
|
||||
|
||||
|
||||
@@ -188,9 +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};
|
||||
|
||||
/* USER CODE BEGIN TIM3_Init 1 */
|
||||
|
||||
@@ -210,42 +208,15 @@ void MX_TIM3_Init(void)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
|
||||
{
|
||||
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_ENABLE;
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
|
||||
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM1;
|
||||
sConfigOC.Pulse = 0;
|
||||
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
|
||||
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN TIM3_Init 2 */
|
||||
|
||||
/* USER CODE END TIM3_Init 2 */
|
||||
HAL_TIM_MspPostInit(&htim3);
|
||||
|
||||
}
|
||||
/* TIM5 init function */
|
||||
@@ -256,8 +227,8 @@ void MX_TIM5_Init(void)
|
||||
|
||||
/* USER CODE END TIM5_Init 0 */
|
||||
|
||||
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
|
||||
TIM_MasterConfigTypeDef sMasterConfig = {0};
|
||||
TIM_IC_InitTypeDef sConfigIC = {0};
|
||||
|
||||
/* USER CODE BEGIN TIM5_Init 1 */
|
||||
|
||||
@@ -268,7 +239,12 @@ void MX_TIM5_Init(void)
|
||||
htim5.Init.Period = 4294967295;
|
||||
htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||
if (HAL_TIM_IC_Init(&htim5) != HAL_OK)
|
||||
if (HAL_TIM_Base_Init(&htim5) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
|
||||
if (HAL_TIM_ConfigClockSource(&htim5, &sClockSourceConfig) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
@@ -278,14 +254,6 @@ void MX_TIM5_Init(void)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
|
||||
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
|
||||
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
|
||||
sConfigIC.ICFilter = 0;
|
||||
if (HAL_TIM_IC_ConfigChannel(&htim5, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN TIM5_Init 2 */
|
||||
|
||||
/* USER CODE END TIM5_Init 2 */
|
||||
@@ -300,7 +268,10 @@ void MX_TIM8_Init(void)
|
||||
/* USER CODE END TIM8_Init 0 */
|
||||
|
||||
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
|
||||
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
|
||||
TIM_MasterConfigTypeDef sMasterConfig = {0};
|
||||
TIM_OC_InitTypeDef sConfigOC = {0};
|
||||
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
|
||||
|
||||
/* USER CODE BEGIN TIM8_Init 1 */
|
||||
|
||||
@@ -308,7 +279,7 @@ void MX_TIM8_Init(void)
|
||||
htim8.Instance = TIM8;
|
||||
htim8.Init.Prescaler = 0;
|
||||
htim8.Init.CounterMode = TIM_COUNTERMODE_UP;
|
||||
htim8.Init.Period = 1800-1;
|
||||
htim8.Init.Period = 65535;
|
||||
htim8.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
|
||||
htim8.Init.RepetitionCounter = 0;
|
||||
htim8.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
|
||||
@@ -321,15 +292,56 @@ void MX_TIM8_Init(void)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
|
||||
if (HAL_TIM_PWM_Init(&htim8) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
if (HAL_TIM_OnePulse_Init(&htim8, TIM_OPMODE_SINGLE) != HAL_OK)
|
||||
{
|
||||
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.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
|
||||
if (HAL_TIMEx_MasterConfigSynchronization(&htim8, &sMasterConfig) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
sConfigOC.OCMode = TIM_OCMODE_PWM1;
|
||||
sConfigOC.Pulse = 0;
|
||||
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
|
||||
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
|
||||
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
|
||||
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
|
||||
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
if (HAL_TIM_PWM_ConfigChannel(&htim8, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
|
||||
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
|
||||
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
|
||||
sBreakDeadTimeConfig.DeadTime = 0;
|
||||
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
|
||||
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
|
||||
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
|
||||
if (HAL_TIMEx_ConfigBreakDeadTime(&htim8, &sBreakDeadTimeConfig) != HAL_OK)
|
||||
{
|
||||
Error_Handler();
|
||||
}
|
||||
/* USER CODE BEGIN TIM8_Init 2 */
|
||||
|
||||
/* USER CODE END TIM8_Init 2 */
|
||||
HAL_TIM_MspPostInit(&htim8);
|
||||
|
||||
}
|
||||
/* TIM11 init function */
|
||||
@@ -436,6 +448,17 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
|
||||
|
||||
/* USER CODE END TIM3_MspInit 1 */
|
||||
}
|
||||
else if(tim_baseHandle->Instance==TIM5)
|
||||
{
|
||||
/* USER CODE BEGIN TIM5_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM5_MspInit 0 */
|
||||
/* TIM5 clock enable */
|
||||
__HAL_RCC_TIM5_CLK_ENABLE();
|
||||
/* USER CODE BEGIN TIM5_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM5_MspInit 1 */
|
||||
}
|
||||
else if(tim_baseHandle->Instance==TIM8)
|
||||
{
|
||||
/* USER CODE BEGIN TIM8_MspInit 0 */
|
||||
@@ -445,6 +468,8 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
|
||||
__HAL_RCC_TIM8_CLK_ENABLE();
|
||||
|
||||
/* 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_EnableIRQ(TIM8_TRG_COM_TIM14_IRQn);
|
||||
/* USER CODE BEGIN TIM8_MspInit 1 */
|
||||
@@ -474,35 +499,6 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
|
||||
/* USER CODE END TIM12_MspInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_TIM_IC_MspInit(TIM_HandleTypeDef* tim_icHandle)
|
||||
{
|
||||
|
||||
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
||||
if(tim_icHandle->Instance==TIM5)
|
||||
{
|
||||
/* USER CODE BEGIN TIM5_MspInit 0 */
|
||||
|
||||
/* USER CODE END TIM5_MspInit 0 */
|
||||
/* TIM5 clock enable */
|
||||
__HAL_RCC_TIM5_CLK_ENABLE();
|
||||
|
||||
__HAL_RCC_GPIOA_CLK_ENABLE();
|
||||
/**TIM5 GPIO Configuration
|
||||
PA0/WKUP ------> TIM5_CH1
|
||||
*/
|
||||
GPIO_InitStruct.Pin = GPIO_PIN_0;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF2_TIM5;
|
||||
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN TIM5_MspInit 1 */
|
||||
|
||||
/* USER CODE END TIM5_MspInit 1 */
|
||||
}
|
||||
}
|
||||
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
|
||||
{
|
||||
|
||||
@@ -530,27 +526,27 @@ void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
|
||||
|
||||
/* USER CODE END TIM1_MspPostInit 1 */
|
||||
}
|
||||
else if(timHandle->Instance==TIM3)
|
||||
else if(timHandle->Instance==TIM8)
|
||||
{
|
||||
/* USER CODE BEGIN TIM3_MspPostInit 0 */
|
||||
/* USER CODE BEGIN TIM8_MspPostInit 0 */
|
||||
|
||||
/* USER CODE END TIM3_MspPostInit 0 */
|
||||
/* USER CODE END TIM8_MspPostInit 0 */
|
||||
|
||||
__HAL_RCC_GPIOC_CLK_ENABLE();
|
||||
/**TIM3 GPIO Configuration
|
||||
PC8 ------> TIM3_CH3
|
||||
PC9 ------> TIM3_CH4
|
||||
/**TIM8 GPIO Configuration
|
||||
PC8 ------> TIM8_CH3
|
||||
PC9 ------> TIM8_CH4
|
||||
*/
|
||||
GPIO_InitStruct.Pin = PWM5_Pin|PWM6_Pin;
|
||||
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
|
||||
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
||||
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
|
||||
GPIO_InitStruct.Alternate = GPIO_AF3_TIM8;
|
||||
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
|
||||
|
||||
/* USER CODE BEGIN TIM3_MspPostInit 1 */
|
||||
/* USER CODE BEGIN TIM8_MspPostInit 1 */
|
||||
|
||||
/* USER CODE END TIM3_MspPostInit 1 */
|
||||
/* USER CODE END TIM8_MspPostInit 1 */
|
||||
}
|
||||
|
||||
}
|
||||
@@ -597,6 +593,17 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
|
||||
|
||||
/* USER CODE END TIM3_MspDeInit 1 */
|
||||
}
|
||||
else if(tim_baseHandle->Instance==TIM5)
|
||||
{
|
||||
/* USER CODE BEGIN TIM5_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM5_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM5_CLK_DISABLE();
|
||||
/* USER CODE BEGIN TIM5_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM5_MspDeInit 1 */
|
||||
}
|
||||
else if(tim_baseHandle->Instance==TIM8)
|
||||
{
|
||||
/* USER CODE BEGIN TIM8_MspDeInit 0 */
|
||||
@@ -606,6 +613,7 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
|
||||
__HAL_RCC_TIM8_CLK_DISABLE();
|
||||
|
||||
/* TIM8 interrupt Deinit */
|
||||
HAL_NVIC_DisableIRQ(TIM8_UP_TIM13_IRQn);
|
||||
HAL_NVIC_DisableIRQ(TIM8_TRG_COM_TIM14_IRQn);
|
||||
/* USER CODE BEGIN TIM8_MspDeInit 1 */
|
||||
|
||||
@@ -635,28 +643,6 @@ void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_TIM_IC_MspDeInit(TIM_HandleTypeDef* tim_icHandle)
|
||||
{
|
||||
|
||||
if(tim_icHandle->Instance==TIM5)
|
||||
{
|
||||
/* USER CODE BEGIN TIM5_MspDeInit 0 */
|
||||
|
||||
/* USER CODE END TIM5_MspDeInit 0 */
|
||||
/* Peripheral clock disable */
|
||||
__HAL_RCC_TIM5_CLK_DISABLE();
|
||||
|
||||
/**TIM5 GPIO Configuration
|
||||
PA0/WKUP ------> TIM5_CH1
|
||||
*/
|
||||
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0);
|
||||
|
||||
/* USER CODE BEGIN TIM5_MspDeInit 1 */
|
||||
|
||||
/* USER CODE END TIM5_MspDeInit 1 */
|
||||
}
|
||||
}
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
|
||||
@@ -22,151 +22,202 @@ HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle)
|
||||
hangle->htim = &angletim;
|
||||
|
||||
|
||||
// Инициализация каналов
|
||||
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);
|
||||
|
||||
|
||||
hangle->f.Initialized = 1;
|
||||
hangle->Config.PeriodLimit = 1;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инициализация углов открытия.
|
||||
* @brief Инициализация ПИД регулятора.
|
||||
* @param hangle Указатель на таймер
|
||||
* @param AngleLimit Лимит AngleMax, рассчитывается от параметров ШИМ
|
||||
* @param AngleMin Минимально возможный угол открытия
|
||||
* @param AngleMax Максимально возможный угол открытия
|
||||
* @return HAL Status.
|
||||
* @param kp, ki kd Коэффициенты регулятора
|
||||
*/
|
||||
HAL_StatusTypeDef Angle_SetRange(Angle_Handle_t *hangle, float AngleMin, float AngleMax)
|
||||
HAL_StatusTypeDef Angle_PID_Init(Angle_Handle_t *hangle, float kp, float ki, float kd, float alpha)
|
||||
{
|
||||
if(assert_upp(hangle))
|
||||
return HAL_ERROR;
|
||||
if(hangle->f.Running)
|
||||
return HAL_BUSY;
|
||||
if(AngleMax < 0 || AngleMax > 1)
|
||||
return HAL_ERROR;
|
||||
if(AngleMin < 0 || AngleMin > 1)
|
||||
return HAL_ERROR;
|
||||
|
||||
if(AngleMax > hangle->Config.AngleLimit)
|
||||
AngleMax = hangle->Config.AngleLimit;
|
||||
if(AngleMin > hangle->Config.AngleLimit)
|
||||
AngleMin = hangle->Config.AngleLimit;
|
||||
// Сам ПИД регулятор
|
||||
hangle->pid.Kp = kp;
|
||||
hangle->pid.Ki = ki;
|
||||
hangle->pid.Kd = kd;
|
||||
arm_pid_init_f32(&hangle->pid, 1);
|
||||
|
||||
if(AngleMin >= AngleMax)
|
||||
return HAL_ERROR;
|
||||
|
||||
hangle->Config.AngleMax = AngleMax;
|
||||
hangle->Config.AngleMin = AngleMin;
|
||||
// Сглаживающий фильтр для задания ПИД регулятора
|
||||
FilterExp_Init(&hangle->refFilter, alpha);
|
||||
Filter_Start(&hangle->refFilter);
|
||||
Filter_Process(&hangle->refFilter, 0);
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация предельного угла открытия.
|
||||
* @brief Управление углом через ПИД регулятор.
|
||||
* @param hangle Указатель на таймер
|
||||
* @param AngleLimit Лимит AngleMax, рассчитывается от параметров ШИМ
|
||||
* @param AngleMin Минимально возможный угол открытия
|
||||
* @param AngleMax Максимально возможный угол открытия
|
||||
* @param setpoint Уставка куда регулировать
|
||||
* @param measurement Измеренные регулируемые величины
|
||||
*/
|
||||
void Angle_PID(Angle_Handle_t *hangle, float setpoint, float measurement, float Correction)
|
||||
{
|
||||
if(assert_upp(hangle))
|
||||
return;
|
||||
|
||||
/* Плавное нарастание уставки */
|
||||
hangle->Iref = Filter_Process(&hangle->refFilter, setpoint);
|
||||
hangle->Imeas = measurement;
|
||||
/* Ошибка регулирования = уставка - измеренное */
|
||||
float err = hangle->Iref - hangle->Imeas;
|
||||
|
||||
/* ПИД регулирование */
|
||||
float open_level = arm_pid_f32(&hangle->pid, err); // 0 - открыть максимально поздно, 1 - открыть макситмально рано
|
||||
|
||||
|
||||
/* Ограничиваем диапазон */
|
||||
if (open_level > 1)
|
||||
{
|
||||
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_SetAlpha(hangle, alpha, Correction);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Сброс ПИД регулятора.
|
||||
* @param hangle Указатель на таймер
|
||||
*/
|
||||
void Angle_PID_Reset(Angle_Handle_t *hangle)
|
||||
{
|
||||
if(assert_upp(hangle))
|
||||
return;
|
||||
|
||||
hangle->Iref = 0;
|
||||
hangle->Imeas = 0;
|
||||
|
||||
/* Вычисляем выход PID */
|
||||
arm_pid_reset_f32(&hangle->pid);
|
||||
|
||||
Filter_ReInit(&hangle->refFilter, hangle->refFilter.alpha);
|
||||
Filter_Start(&hangle->refFilter);
|
||||
Filter_Process(&hangle->refFilter, 0);
|
||||
|
||||
Angle_SetAlpha(hangle, 1, 30); // максимально закрываем
|
||||
|
||||
Angle_Reset(hangle, UPP_PHASE_A);
|
||||
Angle_Reset(hangle, UPP_PHASE_B);
|
||||
Angle_Reset(hangle, UPP_PHASE_C);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Выставление степени открытия тиристоров.
|
||||
* @param hangle Указатель на таймер
|
||||
* @param Alpha Угол открытия тиристора в о.е. от 180 градусов:
|
||||
- 0 - максимально закрыт,
|
||||
- 1 - максимально открыт
|
||||
* @param Коррекция угла в градусах
|
||||
* @return HAL Status.
|
||||
*/
|
||||
HAL_StatusTypeDef Angle_SetLimit(Angle_Handle_t *hangle, float AngleLimit)
|
||||
HAL_StatusTypeDef Angle_SetAlpha(Angle_Handle_t *hangle, float Alpha, float Correction)
|
||||
{
|
||||
if(assert_upp(hangle))
|
||||
return HAL_ERROR;
|
||||
if(hangle->f.Running)
|
||||
return HAL_BUSY;
|
||||
|
||||
if(AngleLimit < 0 || AngleLimit > 1)
|
||||
return HAL_ERROR;
|
||||
|
||||
hangle->Config.AngleLimit = AngleLimit;
|
||||
|
||||
if(Alpha > hangle->Config.AngleMax)
|
||||
Alpha = hangle->Config.AngleMax;
|
||||
if(Alpha < hangle->Config.AngleMin)
|
||||
Alpha = hangle->Config.AngleMin;
|
||||
|
||||
// сколько надо выжидать исходя из заданного угла
|
||||
hangle->alpha_real = Alpha + (Correction/180.0);
|
||||
hangle->alpha = Alpha;
|
||||
|
||||
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
/**
|
||||
* @brief Хендл таймера для рассчета угла открытия.
|
||||
* @param hangle Указатель на таймер
|
||||
* @return HAL Status.
|
||||
*/
|
||||
UPP_Phase_t Angle_Handle(Angle_Handle_t *hangle)
|
||||
{
|
||||
if(assert_upp(hangle))
|
||||
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 Установка угла открытия в таймер.
|
||||
* @brief Запуск отсчета угла открытия.
|
||||
* @param hangle Указатель на таймер
|
||||
* @param Phase Для какой фазы надо установить угол открытия
|
||||
* @return HAL Status.
|
||||
*/
|
||||
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float Angle, float PeriodMs)
|
||||
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float PeriodMs)
|
||||
{
|
||||
if(assert_upp(hangle))
|
||||
if(assert_upp_phase(hangle, Phase))
|
||||
return HAL_ERROR;
|
||||
|
||||
// Если канал дурацкий - возвращаем ошибку
|
||||
if(Phase >= 3)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
if(Angle > hangle->Config.AngleMax)
|
||||
{
|
||||
Angle = hangle->Config.AngleMax;
|
||||
}
|
||||
if(Angle < hangle->Config.AngleMin)
|
||||
{
|
||||
Angle = hangle->Config.AngleMin;
|
||||
}
|
||||
|
||||
uint32_t timer_ticks = TIM_MillisToTick(PeriodMs*Angle, ANGLE_TIM2_FREQ_MHZ);
|
||||
// сколько тиков надо выждать для угла
|
||||
uint32_t timer_ticks = TIM_MillisToTick(PeriodMs*hangle->alpha_real, ANGLE_TIM2_FREQ_MHZ);
|
||||
// сколько тиков будет в таймере когда угол отсчитается (пойдет в CCRx регистр)
|
||||
uint32_t ccr_ticks = __HAL_TIM_GET_COUNTER(hangle->htim) + timer_ticks;
|
||||
|
||||
// Выставялем
|
||||
switch(Phase)
|
||||
{
|
||||
case UPP_PHASE_A:
|
||||
__HAL_TIM_CLEAR_IT(hangle->htim, TIM_IT_CC1); // очищаем флаг навсякий
|
||||
__HAL_TIM_SET_COMPARE(hangle->htim, ANGLE_CHANNEL_1, ccr_ticks);
|
||||
// Если слишком маленький timer_tick и счетчик уже перевалил за ccr, но не сгенерил прервыание:
|
||||
if (__HAL_TIM_GET_COMPARE(hangle->htim, ANGLE_CHANNEL_1) <= __HAL_TIM_GET_COUNTER(hangle->htim))
|
||||
{
|
||||
// включаем прерывание вручную
|
||||
HAL_TIM_GenerateEvent(hangle->htim, TIM_EVENTSOURCE_CC1);
|
||||
}
|
||||
|
||||
__HAL_TIM_ENABLE_IT(hangle->htim, TIM_IT_CC1);
|
||||
hangle->f.Running++;
|
||||
break;
|
||||
|
||||
case UPP_PHASE_B:
|
||||
__HAL_TIM_CLEAR_IT(hangle->htim, TIM_IT_CC2); // очищаем флаг навсякий
|
||||
__HAL_TIM_SET_COMPARE(hangle->htim, ANGLE_CHANNEL_2, ccr_ticks);
|
||||
// Если слишком маленький timer_tick и счетчик уже перевалил за ccr, но не сгенерил прервыание:
|
||||
if (__HAL_TIM_GET_COMPARE(hangle->htim, ANGLE_CHANNEL_2) <= __HAL_TIM_GET_COUNTER(hangle->htim))
|
||||
{
|
||||
// включаем прерывание вручную
|
||||
HAL_TIM_GenerateEvent(hangle->htim, TIM_EVENTSOURCE_CC2);
|
||||
}
|
||||
__HAL_TIM_ENABLE_IT(hangle->htim, TIM_IT_CC2);
|
||||
hangle->f.Running++;
|
||||
break;
|
||||
|
||||
case UPP_PHASE_C:
|
||||
__HAL_TIM_CLEAR_IT(hangle->htim, TIM_IT_CC3); // очищаем флаг навсякий
|
||||
__HAL_TIM_SET_COMPARE(hangle->htim, ANGLE_CHANNEL_3, ccr_ticks);
|
||||
// Если слишком маленький timer_tick и счетчик уже перевалил за ccr, но не сгенерил прервыание:
|
||||
if (__HAL_TIM_GET_COMPARE(hangle->htim, ANGLE_CHANNEL_3) <= __HAL_TIM_GET_COUNTER(hangle->htim))
|
||||
{
|
||||
// включаем прерывание вручную
|
||||
HAL_TIM_GenerateEvent(hangle->htim, TIM_EVENTSOURCE_CC3);
|
||||
}
|
||||
__HAL_TIM_ENABLE_IT(hangle->htim, TIM_IT_CC3);
|
||||
hangle->f.Running++;
|
||||
break;
|
||||
@@ -189,15 +240,9 @@ HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float A
|
||||
*/
|
||||
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;
|
||||
|
||||
// Если канал дурацкий - возвращаем ошибку
|
||||
if(Phase >= 3)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
switch(Phase)
|
||||
{
|
||||
case UPP_PHASE_A:
|
||||
@@ -224,3 +269,93 @@ HAL_StatusTypeDef Angle_Reset(Angle_Handle_t *hangle, UPP_Phase_t Phase)
|
||||
}
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инициализация предельного угла открытия.
|
||||
* @param hangle Указатель на таймер
|
||||
* @param PeriodLimit Лимит AngleMax, рассчитывается от параметров ШИМ
|
||||
* @param AngleMin Минимально возможный угол открытия
|
||||
* @param AngleMax Максимально возможный угол открытия
|
||||
* @return HAL Status.
|
||||
*/
|
||||
HAL_StatusTypeDef Angle_SetLimit(Angle_Handle_t *hangle, float PeriodLimit)
|
||||
{
|
||||
if(assert_upp(hangle))
|
||||
return HAL_ERROR;
|
||||
if(hangle->f.Running)
|
||||
return HAL_BUSY;
|
||||
|
||||
if(PeriodLimit <= 0 || PeriodLimit > 1)
|
||||
return HAL_ERROR;
|
||||
|
||||
hangle->Config.PeriodLimit = PeriodLimit;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инициализация углов открытия.
|
||||
* @param hangle Указатель на таймер
|
||||
* @param PeriodLimit Лимит AngleMax, рассчитывается от параметров ШИМ
|
||||
* @param AngleMin Минимально возможный угол открытия
|
||||
* @param AngleMax Максимально возможный угол открытия
|
||||
* @return HAL Status.
|
||||
*/
|
||||
HAL_StatusTypeDef Angle_SetRange(Angle_Handle_t *hangle, float AngleMin, float AngleMax)
|
||||
{
|
||||
if(assert_upp(hangle))
|
||||
return HAL_ERROR;
|
||||
if(hangle->f.Running)
|
||||
return HAL_BUSY;
|
||||
if(AngleMax < 0 || AngleMax > 1)
|
||||
return HAL_ERROR;
|
||||
if(AngleMin < 0 || AngleMin > 1)
|
||||
return HAL_ERROR;
|
||||
|
||||
if(AngleMin >= AngleMax)
|
||||
return HAL_ERROR;
|
||||
|
||||
hangle->Config.AngleMax = AngleMax;
|
||||
hangle->Config.AngleMin = AngleMin;
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Хендл таймера для рассчета угла открытия.
|
||||
* @param hangle Указатель на таймер
|
||||
* @return HAL Status.
|
||||
* @details Просто возвращает фазу, у которой закончился отсчет угла
|
||||
*/
|
||||
UPP_Phase_t Angle_Handle(Angle_Handle_t *hangle)
|
||||
{
|
||||
if(assert_upp(hangle))
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -8,35 +8,68 @@
|
||||
#define _ANGLE_CONTROL_H_
|
||||
#include "main.h"
|
||||
|
||||
/**
|
||||
* @brief Конфигурация алгоритма управления углом открытия
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
float AngleLimit; ///< Лимит AngleMax, рассчитывается от параметров ШИМ
|
||||
float PeriodLimit; ///< Лимит периода, выше которого нельзя выставить рассчитывается от параметров ШИМ
|
||||
float AngleMin; ///< Минимально возможный угол открытия
|
||||
float AngleMax; ///< Максимально возможный угол открытия
|
||||
}Angle_Config_t;
|
||||
|
||||
/**
|
||||
* @brief Структура для управления углом открытия
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
TIM_HandleTypeDef *htim;
|
||||
Angle_Config_t Config;
|
||||
TIM_HandleTypeDef *htim; ///< Указатель на таймер для расчета угла
|
||||
Angle_Config_t Config; ///< Конфигурации алгоритма расчета угла открытия тиристоров
|
||||
|
||||
float Iref; ///< текущее задание тока в о.е. [0..1]
|
||||
float Imeas; ///< измеренное значение тока в о.е. [0..1]
|
||||
float alpha; ///< текущий угол открытия в о.е. [0..1] от 180 градусов
|
||||
|
||||
|
||||
float alpha_real; /*!< @brief Фактический отсчитываемый угол открытия в о.е. [0..1] от 180 градусов
|
||||
@details Этот угол отличается от @ref alpha дополнительными задержками и компенсациями:
|
||||
- 30 градусов - смещение между линейными и фазными напряжение (мы смотрим линейные, а коммутируем фазные) */
|
||||
|
||||
arm_pid_instance_f32 pid; ///< ПИД регулятор для управления углом
|
||||
FilterExp_t refFilter; ///< Фильтр для плавного нарастания регулирования
|
||||
|
||||
struct {
|
||||
unsigned Initialized : 1;
|
||||
unsigned Initialized : 1; ///< Структура инициализирована
|
||||
unsigned Running : 3; ///< Сколько каналов запущено сейчас
|
||||
} f;
|
||||
} f; ///< Флаги
|
||||
}Angle_Handle_t;
|
||||
|
||||
|
||||
// ====== ИНИЦИАЛИЗАЦИЯ ==========
|
||||
/* Инициализация Таймера для рассчета угла открытия. */
|
||||
HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle);
|
||||
/* Инициализация углов открытия. */
|
||||
HAL_StatusTypeDef Angle_SetRange(Angle_Handle_t *hangle, float AngleMin, float AngleMax);
|
||||
/* Инициализация предельного угла открытия. */
|
||||
HAL_StatusTypeDef Angle_SetLimit(Angle_Handle_t *hangle, float AngleLimit);
|
||||
/* Инициализация ПИД регулятора. */
|
||||
HAL_StatusTypeDef Angle_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, float Correction);
|
||||
/* Выставление текущего угла открытия тиристоров. */
|
||||
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 Angle, float PeriodMs);
|
||||
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float PeriodMs);
|
||||
|
||||
// ====== СБРОС ==========
|
||||
/* Сброс угла открытия у таймера. */
|
||||
HAL_StatusTypeDef Angle_Reset(Angle_Handle_t *hangle, UPP_Phase_t Phase);
|
||||
/* Сброс ПИД регулятора. */
|
||||
void Angle_PID_Reset(Angle_Handle_t *hangle);
|
||||
|
||||
// ====== СЕРВИС ==========
|
||||
/* Инициализация предельного угла открытия. */
|
||||
HAL_StatusTypeDef Angle_SetLimit(Angle_Handle_t *hangle, float PeriodLimit);
|
||||
/* Инициализация углов открытия. */
|
||||
HAL_StatusTypeDef Angle_SetRange(Angle_Handle_t *hangle, float AngleMin, float AngleMax);
|
||||
/* Хендл таймера для рассчета угла открытия. */
|
||||
UPP_Phase_t Angle_Handle(Angle_Handle_t *hangle);
|
||||
#endif /* _ANGLE_CONTROL_H_ */
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
* @details
|
||||
******************************************************************************/
|
||||
#include "pwm_thyristors.h"
|
||||
#include "angle_control.h"
|
||||
#include "tim.h"
|
||||
|
||||
static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Channel_t *hCh, uint32_t state);
|
||||
static HAL_StatusTypeDef __PWM_ReConfigToSoftwarePulses(void);
|
||||
|
||||
/**
|
||||
* @brief Инициализация ШИМ тиристоров.
|
||||
@@ -59,16 +59,16 @@ HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm)
|
||||
PWM_SetHalfWave(hpwm, UPP_PHASE_B, UPP_WAVE_UNKNOWED);
|
||||
PWM_SetHalfWave(hpwm, UPP_PHASE_C, UPP_WAVE_UNKNOWED);
|
||||
|
||||
PWM_SetConfig(hpwm, MB_INTERNAL.param.pwm.PhaseMask, MB_INTERNAL.param.pwm.Frequency, MB_INTERNAL.param.pwm.PulseNumber);
|
||||
|
||||
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);
|
||||
PWM_Stop(hpwm, 0, 1);
|
||||
|
||||
__PWM_ReConfigToSoftwarePulses();
|
||||
HAL_TIM_Base_Start(&hpwm1);
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
@@ -78,20 +78,16 @@ HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm)
|
||||
* @param hpwm Указатель на хендл ШИМ тиристоров
|
||||
* @param Phase На какой фазе надо запустить ШИМ
|
||||
* @return HAL Status.
|
||||
* @details Переводит автомат канала ШИМ в состояние запуска ШИМ.
|
||||
*/
|
||||
HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
|
||||
{
|
||||
if(assert_upp(hpwm))
|
||||
if(assert_upp_phase(hpwm, Phase))
|
||||
return HAL_ERROR;
|
||||
// Если канал дурацкий - возвращаем ошибку
|
||||
if(Phase >= 3)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
if (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN])
|
||||
return HAL_ERROR;
|
||||
|
||||
if(!(hpwm->Config.PhaseMask.all&(1<<Phase)))
|
||||
return HAL_ERROR;
|
||||
|
||||
switch(hpwm->Phase[Phase]->State)
|
||||
{
|
||||
@@ -110,7 +106,6 @@ HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
|
||||
default:
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
return HAL_ERROR;
|
||||
}
|
||||
|
||||
@@ -120,46 +115,145 @@ HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
|
||||
* @param Phase На какой фазе надо остановить ШИМ
|
||||
* @param force_stop_all Принудительно остановить ВЕСЬ ШИМ
|
||||
* @return HAL Status.
|
||||
* @details Переводит автомат канала ШИМ в состояние отключенного ШИМ и
|
||||
* включает канал в режим форсированного неактивного выхода.
|
||||
* При передаче 1 в force_stop_all, отключаются все каналы ШИМ и выдается дискрет на запрет ШИМ
|
||||
* @details Включает канал в режим форсированного неактивного выхода.
|
||||
* При передаче 1 в force_stop_all, отключаются MOE (Main Output Enable) и все каналы ШИМ
|
||||
*/
|
||||
HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_stop_all)
|
||||
{
|
||||
if(assert_upp(hpwm))
|
||||
return HAL_ERROR;
|
||||
// Если канал дурацкий - возвращаем ошибку
|
||||
if(Phase >= 3)
|
||||
{
|
||||
return HAL_ERROR;
|
||||
}
|
||||
if (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN])
|
||||
if(assert_upp_phase(hpwm, Phase))
|
||||
return HAL_ERROR;
|
||||
|
||||
hpwm->Phase[Phase]->State = PWM_THYR_DISABLED;
|
||||
|
||||
// Если не force_stop_all - сбрасываем только текущий канал
|
||||
if (!force_stop_all)
|
||||
{
|
||||
__PWM_SetOutputState(hpwm->Phase[Phase], PWM_DISABLE);
|
||||
}
|
||||
// Если force_stop_all - сбрасываем ВСЕ КАНАЛЫ
|
||||
else {
|
||||
if(force_stop_all)
|
||||
{
|
||||
// в первую очередь выключаем канал, потом выставим режим каналов
|
||||
__HAL_TIM_MOE_DISABLE(&hpwm1);
|
||||
__HAL_TIM_MOE_DISABLE(&hpwm2);
|
||||
|
||||
|
||||
// выставляем все каналы в FORCE MODE
|
||||
for(int ch = 0; ch < 6; ch++)
|
||||
{
|
||||
__PWM_SetOutputState(&hpwm->AllPhases[ch], PWM_DISABLE);
|
||||
}
|
||||
}
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
// Если НЕ force_stop_all - сбрасываем ТОЛЬКО заданный канал
|
||||
else
|
||||
{
|
||||
// Если не force_stop_all - сбрасываем только текущий канал
|
||||
__PWM_SetOutputState(hpwm->Phase[Phase], PWM_DISABLE);
|
||||
return HAL_OK;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Установка полуволны для слежения.
|
||||
* @param hpwm Указатель на хендл ШИМ тиристоров
|
||||
* @param Phase Для какой фазы надо установить полуволну
|
||||
* @param halfwave Какую полуволну установить
|
||||
* @return HAL Status.
|
||||
* @details Меняет указатель канала фазы на канал соответствующей полуволны
|
||||
*/
|
||||
HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_HalfWave_t halfwave)
|
||||
{
|
||||
if(assert_upp_phase(hpwm, Phase))
|
||||
return HAL_ERROR;
|
||||
|
||||
// Выставляем текущий активную полуволну
|
||||
switch(halfwave)
|
||||
{
|
||||
case UPP_WAVE_POSITIVE:
|
||||
hpwm->Phase[Phase] = &hpwm->AllPhases[Phase];
|
||||
hpwm->Phase[Phase]->State = PWM_THYR_TIM_WAIT;
|
||||
return HAL_OK;
|
||||
|
||||
case UPP_WAVE_NEGATIVE:
|
||||
hpwm->Phase[Phase] = &hpwm->AllPhases[Phase+3];
|
||||
hpwm->Phase[Phase]->State = PWM_THYR_TIM_WAIT;
|
||||
return HAL_OK;
|
||||
|
||||
default:
|
||||
hpwm->Phase[Phase] = &hpwm->AllPhases[PHASE_UNKNOWN];
|
||||
return HAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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 Установка полярности шим.
|
||||
* @param hpwm Указатель на хендл ШИМ тиристоров
|
||||
* @param polarity Какая полярность: состяоние бита CCxP
|
||||
* @return HAL Status.
|
||||
*/
|
||||
HAL_StatusTypeDef PWM_SetPolarity(PWM_Handle_t *hpwm, int polarity)
|
||||
{
|
||||
if(assert_upp(hpwm))
|
||||
return HAL_ERROR;
|
||||
|
||||
if(polarity)
|
||||
{
|
||||
hpwm1.Instance->CCER |= TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P | TIM_CCER_CC4P;
|
||||
hpwm2.Instance->CCER |= TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P | TIM_CCER_CC4P;
|
||||
}
|
||||
else
|
||||
{
|
||||
hpwm1.Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P | TIM_CCER_CC4P);
|
||||
hpwm2.Instance->CCER &= ~(TIM_CCER_CC1P | TIM_CCER_CC2P | TIM_CCER_CC3P | TIM_CCER_CC4P);
|
||||
}
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Хендл ШИМ тиристоров.
|
||||
* @param hpwm Указатель на хендл ШИМ тиристоров
|
||||
* @return HAL Status.
|
||||
* @details Автомат состояний, который определяет поведение каналов ШИМ
|
||||
*/
|
||||
HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
|
||||
HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm, float PeriodMs)
|
||||
{
|
||||
if(assert_upp(hpwm))
|
||||
return HAL_ERROR;
|
||||
@@ -185,14 +279,14 @@ HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
|
||||
|
||||
case PWM_THYR_TIM_START: // начать ШИМ (пачка импульсов)
|
||||
__PWM_SetOutputState(hPhase, PWM_ENABLE);
|
||||
hPhase->PulseCnt = hpwm->Config.PulseNumber;
|
||||
hPhase->PulseCnt = MS_TO_FAST_TICKS(PeriodMs*hpwm->Config.PulseLength) - 1; // 1 импульс уже прошел
|
||||
hPhase->State = PWM_THYR_TIM_ACTIVE;
|
||||
hpwm->f.Running++;
|
||||
break;
|
||||
|
||||
case PWM_THYR_TIM_ACTIVE: // управление пачкой импульсов ШИМ
|
||||
hPhase->PulseCnt--;
|
||||
if (hPhase->PulseCnt <= 0)
|
||||
if (hPhase->PulseCnt <= 1) // если остался один импльс в след раз идем в PWM_THYR_TIM_DONE
|
||||
{
|
||||
hPhase->PulseCnt = 0;
|
||||
hPhase->State = PWM_THYR_TIM_DONE;
|
||||
@@ -213,85 +307,8 @@ HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
|
||||
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));
|
||||
__HAL_TIM_SET_AUTORELOAD(&hpwm2, TIM_FreqToTick(Frequency, PWM_TIM3_FREQ_MHZ));
|
||||
// Скважности 50/50
|
||||
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_1, __HAL_TIM_GET_AUTORELOAD(&hpwm1)/2);
|
||||
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_2, __HAL_TIM_GET_AUTORELOAD(&hpwm1)/2);
|
||||
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_3, __HAL_TIM_GET_AUTORELOAD(&hpwm1)/2);
|
||||
__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);
|
||||
return HAL_TIM_Base_Start_IT(&hpwm1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Установка полуволны для слежения.
|
||||
* @param hpwm Указатель на хендл ШИМ тиристоров
|
||||
* @param Phase Для какой фазы надо установить полуволну
|
||||
* @param halfwave Какую полуволну установить
|
||||
* @return HAL Status.
|
||||
* @details Меняет указатель канала фазы на канал соответствующей полуволны
|
||||
*/
|
||||
HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_HalfWave_t halfwave)
|
||||
{
|
||||
if(assert_upp(hpwm))
|
||||
return HAL_ERROR;
|
||||
|
||||
// Сбрасываем текущий канал
|
||||
PWM_Stop(hpwm, Phase, 0);
|
||||
|
||||
// Если канал дурацкий - выставляем заглушку
|
||||
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];
|
||||
hpwm->Phase[Phase]->State = PWM_THYR_TIM_WAIT;
|
||||
return HAL_OK;
|
||||
|
||||
case UPP_WAVE_NEGATIVE:
|
||||
hpwm->Phase[Phase] = &hpwm->AllPhases[Phase+3];
|
||||
hpwm->Phase[Phase]->State = PWM_THYR_TIM_WAIT;
|
||||
return HAL_OK;
|
||||
|
||||
default:
|
||||
hpwm->Phase[Phase] = &hpwm->AllPhases[PHASE_UNKNOWN];
|
||||
return HAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
//================ ВНУТРЕННИЕ ФУНКЦИИ ===================
|
||||
/**
|
||||
* @brief Установка режима для канала ШИМ.
|
||||
* @param hpwm Указатель на хендл ШИМ тиристоров
|
||||
@@ -306,29 +323,54 @@ static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Channel_t *hCh, uint32_t state
|
||||
if (hCh->htim == NULL)
|
||||
return HAL_ERROR;
|
||||
|
||||
// Если режим уже выставлен
|
||||
if(hCh->CurrentMode == state)
|
||||
{
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
uint32_t ch_mode = state;
|
||||
hCh->CurrentMode = state;
|
||||
|
||||
// выставляем режим каналов
|
||||
switch(hCh->ChMask)
|
||||
{
|
||||
case TIM_CHANNEL_1:
|
||||
hCh->htim->Instance->CCMR1 &= ~TIM_OCMODE_PWM2;
|
||||
hCh->htim->Instance->CCMR1 |= ch_mode;
|
||||
hCh->htim->Instance->CCMR1 |= state;
|
||||
break;
|
||||
case TIM_CHANNEL_2:
|
||||
hCh->htim->Instance->CCMR1 &= ~(TIM_OCMODE_PWM2 << 8);
|
||||
hCh->htim->Instance->CCMR1 |= (ch_mode << 8);
|
||||
hCh->htim->Instance->CCMR1 |= (state << 8);
|
||||
break;
|
||||
case TIM_CHANNEL_3:
|
||||
hCh->htim->Instance->CCMR2 &= ~TIM_OCMODE_PWM2;
|
||||
hCh->htim->Instance->CCMR2 |= ch_mode;
|
||||
hCh->htim->Instance->CCMR2 |= state;
|
||||
break;
|
||||
case TIM_CHANNEL_4:
|
||||
hCh->htim->Instance->CCMR2 &= ~(TIM_OCMODE_PWM2 << 8);
|
||||
hCh->htim->Instance->CCMR2 |= (ch_mode << 8);
|
||||
hCh->htim->Instance->CCMR2 |= (state << 8);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return HAL_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Переконфигурация таймером для софтварного формирования пачки импульсов.
|
||||
* @return HAL Status.
|
||||
*/
|
||||
static HAL_StatusTypeDef __PWM_ReConfigToSoftwarePulses(void)
|
||||
{
|
||||
/* One Pulse и Repetitive не используем */
|
||||
hpwm1.Instance->RCR = 0;
|
||||
hpwm1.Instance->CR1 &= ~TIM_CR1_OPM;
|
||||
hpwm2.Instance->RCR = 0;
|
||||
hpwm2.Instance->CR1 &= ~TIM_CR1_OPM;
|
||||
/* Настраиваем Slave на втором таймере*/
|
||||
TIM_SlaveConfigTypeDef sSlaveConfig = {0};
|
||||
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_TRIGGER;
|
||||
sSlaveConfig.InputTrigger = TIM_TS_ITR0;
|
||||
return HAL_TIM_SlaveConfigSynchro(&htim8, &sSlaveConfig);
|
||||
}
|
||||
@@ -9,8 +9,12 @@
|
||||
#include "main.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Вкоючить хардварный способ формирования пачки импульсов
|
||||
* @note При отключении сильно возрастет нагрузка на контроллер из-за прерываний ШИМ!
|
||||
* Они поак работают всегда, независимо от того есть импулсь или нет
|
||||
*/
|
||||
#define PWM_HARDWARE_IMPULSES_CONTROL
|
||||
|
||||
|
||||
#define PWM_ENABLE TIM_OCMODE_PWM2
|
||||
@@ -21,14 +25,16 @@
|
||||
|
||||
// Индексы для структур каналов @ref PWM_Handle_t
|
||||
#define PHASE_A_POS 0
|
||||
#define PHASE_B_POS 1
|
||||
#define PHASE_C_POS 2
|
||||
#define PHASE_C_POS 1
|
||||
#define PHASE_B_POS 2
|
||||
#define PHASE_A_NEG 3
|
||||
#define PHASE_B_NEG 4
|
||||
#define PHASE_C_NEG 5
|
||||
#define PHASE_C_NEG 4
|
||||
#define PHASE_B_NEG 5
|
||||
#define PHASE_UNKNOWN 6
|
||||
|
||||
|
||||
#define PWM_PulseLengthToCnt(_length_, _period_) ((_length_)*(_period_)/
|
||||
|
||||
/**
|
||||
* @brief Состояния канала
|
||||
*/
|
||||
@@ -48,6 +54,7 @@ typedef struct {
|
||||
TIM_HandleTypeDef *htim; ///< указатель на соответствующий TIM (hpwm1 или hpwm2)
|
||||
uint32_t PulseCnt; ///< Счетчик кол-ва импульсов. Инициализируется из структуры @ref PWM_ThyrConfig_t
|
||||
uint32_t ChMask; ///< TIM_CHANNEL_x
|
||||
uint32_t CurrentMode; ///< Текущий режим канала
|
||||
|
||||
struct {
|
||||
unsigned Ready:1; ///< Флаг готовности тиристора к работе
|
||||
@@ -68,15 +75,16 @@ typedef struct {
|
||||
uint8_t phC:1;
|
||||
};
|
||||
}PhaseMask; ///< Какими каналами управлять
|
||||
uint8_t PulseNumber; ///< Сколько импульсов отправить в пакете для открытия тиристоров
|
||||
float PulseLength; ///< Длина импульса в о.е. от 180 градусов
|
||||
uint16_t Frequency; ///< Частота импульсов
|
||||
float Duty; ///< Скважность импульсов
|
||||
} PWM_ThyrConfig_t;
|
||||
|
||||
/**
|
||||
* @brief Хендл управляюзщий тиристорами */
|
||||
typedef struct {
|
||||
PWM_ThyrConfig_t Config;
|
||||
PWM_Channel_t *Phase[3]; ///< Текущие каналы для фаз
|
||||
PWM_ThyrConfig_t Config; ///< Конфигурации ШИМ
|
||||
PWM_Channel_t *Phase[3]; ///< Каналы для активной в данный момент фазы
|
||||
PWM_Channel_t AllPhases[7]; ///< Все каналы для фаз (+1 для деинициализированного канала)
|
||||
|
||||
struct {
|
||||
@@ -85,18 +93,23 @@ typedef struct {
|
||||
} 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_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_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 */
|
||||
|
||||
@@ -1,289 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file upp_control.c
|
||||
* @brief Модуль определябщий поведение УПП
|
||||
******************************************************************************
|
||||
* @details
|
||||
******************************************************************************/
|
||||
#include "upp_main.h" // всё остальное по работе с УПП
|
||||
|
||||
|
||||
static int __CheckSimpleParamF(float *paramDist, uint16_t paramSrc, float Coef);
|
||||
static int __CheckSimpleParamU32(uint32_t *paramDist, uint16_t paramSrc, float Coef);
|
||||
static int __CheckSimpleParamU16(uint16_t *paramDist, uint16_t paramSrc);
|
||||
static int __CheckSimpleParamU8(uint8_t *paramDist, uint16_t paramSrc, float Coef);
|
||||
static void __AngleSetLimit(void);
|
||||
|
||||
/**
|
||||
* @brief Контроль внутренних параметров УПП.
|
||||
* @return HAL Status.
|
||||
*/
|
||||
void UPP_Control_InternalParams(void)
|
||||
{
|
||||
if(upp.call->go) // при запущеном УПП ничего не меняем
|
||||
return;
|
||||
|
||||
// флаги обновились ли конфиги
|
||||
static int adc_channel_update[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
|
||||
static int zc_update = 0;
|
||||
static int pwm_update = 0;
|
||||
|
||||
// временная переменная для параметров каналов АЦП
|
||||
float adc_channel_max[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
|
||||
uint16_t adc_channel_zero[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
|
||||
// временная переменная для параметров перехода через ноль
|
||||
float zc_hysteresis = upp.pm.zc.Config.Hysteresis;
|
||||
uint16_t zc_debounce = upp.pm.zc.Config.DebounceSamples;
|
||||
// временная переменная для параметров ШИМ
|
||||
uint8_t pwm_phase_mask = upp.hpwm.Config.PhaseMask.all;
|
||||
uint16_t pwm_freq = upp.hpwm.Config.Frequency;
|
||||
uint8_t pwm_pulse_num = upp.hpwm.Config.PulseNumber;
|
||||
// временная переменная для параметров Мониторинга сети
|
||||
float pm_alpha = upp.pm.measured.exp[0].alpha;
|
||||
|
||||
|
||||
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
||||
{
|
||||
adc_channel_max[i] = upp.pm.adc.Coefs[i].vMax;
|
||||
adc_channel_zero[i] = upp.pm.adc.Coefs[i].lZero;
|
||||
|
||||
// Максимальное измеряемое напряжение
|
||||
if(__CheckSimpleParamF(&adc_channel_max[i], MB_INTERNAL.param.adc.ADC_Max[i], 10))
|
||||
{
|
||||
adc_channel_update[i] = 1;
|
||||
}
|
||||
// Значение АЦП при нулевом входе
|
||||
if(__CheckSimpleParamU16(&adc_channel_zero[i], MB_INTERNAL.param.adc.ADC_Zero[i]))
|
||||
{
|
||||
adc_channel_update[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Параметры алгоритма перехода через ноль
|
||||
if(__CheckSimpleParamF(&zc_hysteresis, MB_INTERNAL.param.zc.Hysteresis, 10000))
|
||||
{
|
||||
zc_update = 1;
|
||||
}
|
||||
if(__CheckSimpleParamU16(&zc_debounce, MB_INTERNAL.param.zc.DebouneCouner))
|
||||
{
|
||||
zc_update = 1;
|
||||
}
|
||||
|
||||
// Параметры ШИМ токов
|
||||
if(__CheckSimpleParamU8(&pwm_phase_mask, MB_INTERNAL.param.pwm.PhaseMask, 1))
|
||||
{
|
||||
pwm_update = 1;
|
||||
}
|
||||
if(__CheckSimpleParamU16(&pwm_freq, MB_INTERNAL.param.pwm.Frequency))
|
||||
{
|
||||
pwm_update = 1;
|
||||
}
|
||||
if(__CheckSimpleParamU8(&pwm_pulse_num, MB_INTERNAL.param.pwm.PulseNumber, 1))
|
||||
{
|
||||
pwm_update = 1;
|
||||
}
|
||||
// Параметры мониторинга
|
||||
if(__CheckSimpleParamF(&pm_alpha, MB_INTERNAL.param.pm.mean_alpha, 65535))
|
||||
{
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
Filter_ReInit(&upp.pm.measured.exp[i], pm_alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Обновление АЦП конфигов
|
||||
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
||||
{
|
||||
if(adc_channel_update[i])
|
||||
{
|
||||
if(ADC_ConfigChannel(&upp.pm.adc, i, adc_channel_zero[i], adc_channel_max[i], 4095) == HAL_OK)
|
||||
adc_channel_update[i] = 0;
|
||||
else
|
||||
errors.prvt.cnt.adc_reinit_err++;
|
||||
}
|
||||
}
|
||||
// Обновление Zero-Cross конфигов
|
||||
if(zc_update)
|
||||
{
|
||||
if(ZC_Init(&upp.pm.zc, upp.pm.zc.Config.NumChannels, zc_hysteresis, zc_debounce) == HAL_OK)
|
||||
zc_update = 0;
|
||||
else
|
||||
errors.prvt.cnt.zc_reinit_err++;
|
||||
}
|
||||
// Обновление ШИМ конфигов
|
||||
if(pwm_update)
|
||||
{
|
||||
if(PWM_SetConfig(&upp.hpwm, pwm_phase_mask, pwm_freq, pwm_pulse_num) == HAL_OK)
|
||||
{
|
||||
pwm_update = 0;
|
||||
__AngleSetLimit();
|
||||
}
|
||||
else
|
||||
errors.prvt.cnt.pwm_reinit_err++;
|
||||
}
|
||||
if (upp.hangle.Config.AngleLimit == 0)
|
||||
{
|
||||
__AngleSetLimit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Установка параметров на дефолтные значения @ref UPP_DEFAULT_PARAMS.
|
||||
* @param pui_default Сбросить параметры ПУИ
|
||||
* @param internal_default Сбросить внутренние параметры
|
||||
* @return HAL Status.
|
||||
*/
|
||||
void UPP_SetDefault(int pui_default, int internal_default)
|
||||
{
|
||||
if(pui_default)
|
||||
{
|
||||
MB_DATA.HoldRegs.pui_params.Iref = PUI_Iref_PERCENT_DEFAULT;
|
||||
MB_DATA.HoldRegs.pui_params.Tnt = PUI_Tnt_MS_DEFAULT;
|
||||
MB_DATA.HoldRegs.pui_params.Umin = PUI_Umin_PERCENT_DEFAULT;
|
||||
MB_DATA.HoldRegs.pui_params.Umax = PUI_Umax_PERCENT_DEFAULT;
|
||||
MB_DATA.HoldRegs.pui_params.Imax = PUI_Imax_PERCENT_DEFAULT;
|
||||
MB_DATA.HoldRegs.pui_params.Imin = PUI_Imin_PERCENT_DEFAULT;
|
||||
MB_DATA.HoldRegs.pui_params.TiMax = PUI_TiMax_US_DEFAULT;
|
||||
MB_DATA.HoldRegs.pui_params.Tdelay = PUI_Tdelay_SECONDS_DEFAULT;
|
||||
MB_DATA.HoldRegs.pui_params.Interlace = PUI_Interlace_EN_DEFAULT;
|
||||
}
|
||||
|
||||
if(internal_default)
|
||||
{
|
||||
MB_INTERNAL.param.nominal.PhaseNumber = NOM_PHASE_NUMB;
|
||||
MB_INTERNAL.param.nominal.U = NOM_U_V_DEFAULT*10;
|
||||
MB_INTERNAL.param.nominal.U_deviation_plus = NOM_U_DEVIATION_PLUS_PERCENT_DEFAULT*100;
|
||||
MB_INTERNAL.param.nominal.U_deviation_minus = NOM_U_DEVIATION_MINUS_PERCENT_DEFAULT*100;
|
||||
MB_INTERNAL.param.nominal.F = NOM_F_HZ_DEFAULT*100;
|
||||
MB_INTERNAL.param.nominal.F_deviation_plus = NOM_F_DEVIATION_PLUS_PERCENT_DEFAULT*100;
|
||||
MB_INTERNAL.param.nominal.F_deviation_minus = NOM_F_DEVIATION_MINUS_PERCENT_DEFAULT*100;
|
||||
MB_INTERNAL.param.nominal.I = NOM_I_A_DEFAULT*10;
|
||||
|
||||
MB_INTERNAL.param.pm.mean_alpha = PM_EXP_ALPHA_COEF_DEFAULT*65535;
|
||||
|
||||
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UBA] = ADC_U_MAX_V_DEFAULT*10;
|
||||
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_UAC] = ADC_U_MAX_V_DEFAULT*10;
|
||||
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_IC] = ADC_I_MAX_A_DEFAULT*10;
|
||||
MB_INTERNAL.param.adc.ADC_Max[ADC_CHANNEL_IA] = ADC_I_MAX_A_DEFAULT*10;
|
||||
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_UBA] = ADC_U_ZERO_DEFAULT;
|
||||
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_UAC] = ADC_U_ZERO_DEFAULT;
|
||||
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_IC] = ADC_I_ZERO_DEFAULT;
|
||||
MB_INTERNAL.param.adc.ADC_Zero[ADC_CHANNEL_IA] = ADC_I_ZERO_DEFAULT;
|
||||
|
||||
MB_INTERNAL.param.pwm.PhaseMask = 0x7; // (все три фазы)
|
||||
MB_INTERNAL.param.pwm.Frequency = (float)PWM_THYR_FREQUENCY_HZ_DEFAULT;
|
||||
MB_INTERNAL.param.pwm.PulseNumber = PWM_THYR_PULSE_NUMBER_DEFAULT;
|
||||
|
||||
MB_INTERNAL.param.zc.Hysteresis = ZERO_CROSS_HYSTERESIS_PERCENT_DEFAULT*100;
|
||||
MB_INTERNAL.param.zc.DebouneCouner = ZERO_CROSS_DEBOUNCE_10US_DEFAULT;
|
||||
//__AngleSetLimit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void __AngleSetLimit(void)
|
||||
{
|
||||
// Перерасчет максимально допустимого угла
|
||||
float pulses_percent_of_period = ((MB_INTERNAL.param.pwm.PulseNumber / MB_INTERNAL.param.pwm.Frequency) * 1000) / ANGLE_PERIOD_MS(NOM_F_HZ_DEFAULT);
|
||||
float angle_limit = 1 - pulses_percent_of_period;
|
||||
Angle_SetLimit(&upp.hangle, angle_limit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Сверить и обновить float параметр из uint16_t.
|
||||
* @param paramDist Указатель на float параметр
|
||||
* @param paramSrc Значение для сравнения с float параметром
|
||||
* @param Coef Коэффициент для приведения float к uint16_t: uint16_t = float*coef, float = uint16_t/coef
|
||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||
*/
|
||||
static int __CheckSimpleParamF(float *paramDist, uint16_t paramSrc, float Coef)
|
||||
{
|
||||
if(paramDist == NULL)
|
||||
return 0;
|
||||
|
||||
uint16_t expected_mb_param = *paramDist*Coef;
|
||||
if(expected_mb_param != paramSrc)
|
||||
{
|
||||
*paramDist = (float)paramSrc/Coef;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Сверить и обновить uint32_t параметр из uint16_t.
|
||||
* @param paramDist Указатель на uint32_t параметр
|
||||
* @param paramSrc Значение для сравнения с uint32_t параметром
|
||||
* @param Coef Коэффициент для приведения uint32_t к uint16_t: uint16_t = uint32_t*coef, uint32_t = uint16_t/coef
|
||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||
*/
|
||||
static int __CheckSimpleParamU32(uint32_t *paramDist, uint16_t paramSrc, float Coef)
|
||||
{
|
||||
if(paramDist == NULL)
|
||||
return 0;
|
||||
|
||||
uint16_t expected_mb_param = *paramDist*Coef;
|
||||
if(expected_mb_param != paramSrc)
|
||||
{
|
||||
*paramDist = (uint32_t)paramSrc/Coef;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Сверить и обновить uint16_t параметр из uint16_t.
|
||||
* @param paramDist Указатель на uint16_t параметр
|
||||
* @param paramSrc Значение для сравнения с uint16_t параметром
|
||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||
*/
|
||||
static int __CheckSimpleParamU16(uint16_t *paramDist, uint16_t paramSrc)
|
||||
{
|
||||
if(paramDist == NULL)
|
||||
return 0;
|
||||
|
||||
uint16_t expected_mb_param = *paramDist;
|
||||
if(expected_mb_param != paramSrc)
|
||||
{
|
||||
*paramDist = (uint16_t)paramSrc;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Сверить и обновить uint8_t параметр из uint16_t.
|
||||
* @param paramDist Указатель на uint8_t параметр
|
||||
* @param paramSrc Значение для сравнения с uint32_t параметром
|
||||
* @param Coef Коэффициент для приведения uint32_t к uint16_t: uint16_t = uint8_t*coef, uint8_t = uint16_t/coef
|
||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||
*/
|
||||
static int __CheckSimpleParamU8(uint8_t *paramDist, uint16_t paramSrc, float Coef)
|
||||
{
|
||||
if(paramDist == NULL)
|
||||
return 0;
|
||||
|
||||
uint16_t expected_mb_param = *paramDist*Coef;
|
||||
if(expected_mb_param != paramSrc)
|
||||
{
|
||||
*paramDist = (uint8_t)paramSrc/Coef;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file upp_control.h
|
||||
* @brief Модуль определябщий поведение УПП
|
||||
******************************************************************************
|
||||
* @details
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _UPP_CONTROL_H
|
||||
#define _UPP_CONTROL_H
|
||||
#include "upp_defs.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned set_default_pui:1; ///< Выставить настройки ПУИ в дефолтные
|
||||
unsigned set_default_internal:1;///< Выставить внутренние настройки в дефолтные
|
||||
unsigned go:1; ///< Запустить УПП
|
||||
unsigned stop:1; ///< Выставить внутренние настройки в дефолтные
|
||||
|
||||
|
||||
unsigned reserved:11;
|
||||
unsigned reset_mcu:1;
|
||||
}UPP_FuncCalls_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t mean_alpha; ///< Коэф альфа x10000 для эксп. фильтра Umean, Imean, Fmean
|
||||
}pm;
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t PhaseNumber; ///< Количество
|
||||
uint16_t U; ///< В x 10
|
||||
uint16_t U_deviation_plus; ///< Проценты x 100
|
||||
uint16_t U_deviation_minus; ///< Проценты x 100
|
||||
uint16_t F; ///< Гц x 100
|
||||
uint16_t F_deviation_plus; ///< Проценты x 100
|
||||
uint16_t F_deviation_minus; ///< Проценты x 100
|
||||
uint16_t I; ///< Амперы x 10
|
||||
}nominal;
|
||||
|
||||
/* Параметры АЦП */
|
||||
struct
|
||||
{
|
||||
uint16_t ADC_Max[4]; ///< В x 10
|
||||
uint16_t ADC_Zero[4]; ///< Кванты АЦП
|
||||
}adc;
|
||||
|
||||
/* Параметры ШИМ */
|
||||
struct
|
||||
{
|
||||
uint16_t PhaseMask; ///< Битовяя маска на какие фазы подавать ШИМ: 0 бит - a, 1 бит - b, 2 бит - c
|
||||
uint16_t Frequency; ///< Частота ШИМ для пачки импульсов на тиристоры
|
||||
uint16_t PulseNumber; ///< Количесво импульсов в пачке
|
||||
}pwm;
|
||||
|
||||
/* Параметры Угла */
|
||||
struct
|
||||
{
|
||||
uint16_t Hysteresis; ///< Гистерезис для определения перехода через ноль
|
||||
uint16_t DebouneCouner; ///< Защита от дребезга: через сколько тактов снова начать фиксировать переход через ноль
|
||||
}zc;
|
||||
|
||||
/* Параметры Угла */
|
||||
struct
|
||||
{
|
||||
uint16_t Angle_Max; ///< Максимальный угол открытия тиристора
|
||||
uint16_t Angle_Min; ///< Минимальный угол открытия тиристора
|
||||
}angle;
|
||||
|
||||
|
||||
|
||||
}UPP_PrvtParams_t;
|
||||
|
||||
|
||||
/* Контроль внутренних параметров УПП. */
|
||||
void UPP_Control_InternalParams(void);
|
||||
/* Установка параметров на дефолтные значения */
|
||||
void UPP_SetDefault(int pui_default, int internal_default);
|
||||
|
||||
#endif //_UPP_CONTROL_H
|
||||
@@ -1,13 +1,199 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file upp_errors.c
|
||||
* @brief Ошибки УПП и их обработка
|
||||
* @brief Формирование ошибок в ПУИ
|
||||
******************************************************************************
|
||||
* @details
|
||||
Общая логика:
|
||||
В программе выставляются всякие внутренние флаги ошибок: ERR_PRIVATE
|
||||
В этом модуле смотрятся какие флаги выставились и переносят эти флаги
|
||||
в структуру ошибок ПУИ ERR_PUI.
|
||||
|
||||
Исключение: Программные ошибки и ошибки питания плат,
|
||||
они пишутся напрямую в ERR_PUI.
|
||||
|
||||
Также реализована защита от дребезга и в целом задержка на выставление ошибок.
|
||||
******************************************************************************/
|
||||
#include "upp_main.h" // УПП
|
||||
#include "upp_errors.h" // всё остальное по работе с УПП
|
||||
UPP_Errors_t errors;
|
||||
|
||||
static UPP_ErrorType_t UPP_SelectCommonError(void);
|
||||
__STATIC_FORCEINLINE int setError(int condition, int flag, int *timer, int delay);
|
||||
void UPP_Errors_Program(void);
|
||||
void UPP_Errors_Power(void);
|
||||
void UPP_Errors_Ranges(void);
|
||||
void UPP_Errors_LossPhase(void);
|
||||
void UPP_Errors_Other(void);
|
||||
|
||||
|
||||
|
||||
void UPP_Errors_Handle(void)
|
||||
{
|
||||
/*====== Программные ошибки ======*/
|
||||
UPP_Errors_Program();
|
||||
/*====== Ошибки питания плат ======*/
|
||||
#ifndef UPP_DISABLE_PROTECT_BOARDPOWER
|
||||
UPP_Errors_Power();
|
||||
#endif
|
||||
/*====== Ошибки выхода за допустимые пределы ======*/
|
||||
UPP_Errors_Ranges();
|
||||
/*====== Потери фазы ======*/
|
||||
#ifndef UPP_DISABLE_PROTECT_LOSS_PHASE
|
||||
UPP_Errors_LossPhase();
|
||||
#endif
|
||||
/*====== Остальные ======*/
|
||||
UPP_Errors_Other();
|
||||
|
||||
|
||||
|
||||
errors.common = UPP_SelectCommonError();
|
||||
}
|
||||
|
||||
void UPP_Errors_Program(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void UPP_Errors_Power(void)
|
||||
{
|
||||
static int error_latch_ticks = 0;
|
||||
int error_latch_timeout = 5000;
|
||||
|
||||
/* Считывание неисправностей источников питания */
|
||||
int err_24Vdio = GPIO_Read_Switch(&UPP_DIN.err_24Vdio);
|
||||
int err_24V = GPIO_Read_Switch(&UPP_DIN.err_24V);
|
||||
int err_5Vd = GPIO_Read_Switch(&UPP_DIN.err_5Vd);
|
||||
int err_5Vsi = GPIO_Read_Switch(&UPP_DIN.err_5Vsi);
|
||||
int err_Va = GPIO_Read_Switch(&UPP_DIN.err_Va);
|
||||
|
||||
ERR_PUI.Power_DIO_24V = err_24Vdio;
|
||||
ERR_PUI.Power_24V = err_24V;
|
||||
ERR_PUI.Power_Digit_5V = err_5Vd;
|
||||
ERR_PUI.Power_SCI_5V = err_5Vsi;
|
||||
ERR_PUI.Power_Analog_5V = err_Va;
|
||||
}
|
||||
|
||||
void UPP_Errors_Ranges(void)
|
||||
{
|
||||
/* Преобразуем уставки в нормальные тики */
|
||||
float ticksTiMax = u2f(PARAM_PUI.TiMax, 1)/PM_SLOW_PERIOD_US;
|
||||
/* Счетчики для отсчитывания задержки выставления ошибки */
|
||||
static int IMaxCnt = 0;
|
||||
static int UMaxCnt = 0;
|
||||
static int UMinCnt = 0;
|
||||
static int FMaxCnt = 0;
|
||||
static int FMinCnt = 0;
|
||||
static int TMaxCnt = 0;
|
||||
|
||||
/* Напряжения */
|
||||
ERR_PUI.OverVoltage = setError(ERR_PRIVATE.uamp_max,
|
||||
ERR_PUI.OverVoltage,
|
||||
&UMaxCnt,
|
||||
MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_UAMP_ERR));
|
||||
ERR_PUI.UnderVoltage = setError(ERR_PRIVATE.uamp_min,
|
||||
ERR_PUI.UnderVoltage,
|
||||
&UMinCnt,
|
||||
MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_UAMP_ERR));
|
||||
|
||||
|
||||
/* Токи */
|
||||
int i_max = ( ERR_PRIVATE.iamp_max ||
|
||||
ERR_PRIVATE.ia_max ||
|
||||
ERR_PRIVATE.ib_max ||
|
||||
ERR_PRIVATE.ic_max);
|
||||
ERR_PUI.OverCurrent = setError(i_max,
|
||||
ERR_PUI.OverCurrent,
|
||||
&IMaxCnt,
|
||||
ticksTiMax);
|
||||
|
||||
|
||||
/* Частота */
|
||||
int f_max = ( ERR_PRIVATE.fac_max ||
|
||||
ERR_PRIVATE.fba_max ||
|
||||
ERR_PRIVATE.fbc_max);
|
||||
int f_min = ( ERR_PRIVATE.fac_min ||
|
||||
ERR_PRIVATE.fba_min ||
|
||||
ERR_PRIVATE.fbc_min);
|
||||
ERR_PUI.OverFrequency = setError(f_max,
|
||||
ERR_PUI.OverFrequency,
|
||||
&FMaxCnt,
|
||||
MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_F_ERR));
|
||||
|
||||
ERR_PUI.UnderFrequency = setError( f_min,
|
||||
ERR_PUI.UnderFrequency,
|
||||
&FMinCnt,
|
||||
MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_F_ERR));
|
||||
|
||||
|
||||
/* Температуры */
|
||||
ERR_PUI.OverTemperature = setError(ERR_PRIVATE.temp_err,
|
||||
ERR_PUI.OverTemperature,
|
||||
&TMaxCnt,
|
||||
MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_DEFAULT));
|
||||
}
|
||||
|
||||
void UPP_Errors_LossPhase(void)
|
||||
{
|
||||
/* Счетчики для отсчитывания задержки выставления ошибки */
|
||||
static int LossPhaseAllCnt = 0;
|
||||
static int LossPhaseACnt = 0;
|
||||
static int LossPhaseBCnt = 0;
|
||||
static int LossPhaseCCnt = 0;
|
||||
|
||||
int loss_phases_all = ( ERR_PRIVATE.ia_min &&
|
||||
ERR_PRIVATE.ib_min &&
|
||||
ERR_PRIVATE.ic_min );
|
||||
|
||||
ERR_PUI.LossPhaseAll = setError( loss_phases_all,
|
||||
ERR_PUI.LossPhaseAll,
|
||||
&LossPhaseAllCnt,
|
||||
MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_DEFAULT));
|
||||
|
||||
/* Если хотя бы одна фаза есть проверяем фазы отдельно */
|
||||
if(!ERR_PUI.LossPhaseAll)
|
||||
{
|
||||
ERR_PUI.LossPhaseA = setError( ERR_PRIVATE.ia_min,
|
||||
ERR_PUI.LossPhaseA,
|
||||
&LossPhaseACnt,
|
||||
MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_DEFAULT));
|
||||
|
||||
ERR_PUI.LossPhaseB = setError( ERR_PRIVATE.ib_min,
|
||||
ERR_PUI.LossPhaseB,
|
||||
&LossPhaseBCnt,
|
||||
MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_DEFAULT));
|
||||
|
||||
ERR_PUI.LossPhaseC = setError( ERR_PRIVATE.ic_min,
|
||||
ERR_PUI.LossPhaseC,
|
||||
&LossPhaseCCnt,
|
||||
MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_DEFAULT));
|
||||
}
|
||||
/* Если всех фаз нет, то отдельные не смотрим */
|
||||
else
|
||||
{
|
||||
ERR_PUI.LossPhaseA = 0;
|
||||
ERR_PUI.LossPhaseB = 0;
|
||||
ERR_PUI.LossPhaseC = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void UPP_Errors_Other(void)
|
||||
{
|
||||
static int InterlaceCnt = 0;
|
||||
|
||||
|
||||
if(ERR_PRIVATE.longstart)
|
||||
ERR_PUI.LongStart = 1;
|
||||
else
|
||||
ERR_PUI.LongStart = 0;
|
||||
|
||||
ERR_PUI.Interlace = setError(ERR_PRIVATE.interlance,
|
||||
ERR_PUI.Interlace,
|
||||
&InterlaceCnt,
|
||||
MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_DEFAULT));
|
||||
//Interlance
|
||||
}
|
||||
|
||||
static UPP_ErrorType_t UPP_SelectCommonError(void)
|
||||
{
|
||||
// Пока нет ошибки
|
||||
@@ -38,7 +224,20 @@ static UPP_ErrorType_t UPP_SelectCommonError(void)
|
||||
return best;
|
||||
}
|
||||
|
||||
void UPP_ErrorsHandle(void)
|
||||
|
||||
__STATIC_FORCEINLINE int setError(int condition, int flag, int *timer, int delay)
|
||||
{
|
||||
errors.common = UPP_SelectCommonError();
|
||||
if (condition) {
|
||||
if (*timer < delay)
|
||||
(*timer)++;
|
||||
else
|
||||
flag = 1;
|
||||
} else {
|
||||
if (*timer > 0)
|
||||
(*timer)--;
|
||||
else
|
||||
flag = 0;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
@@ -64,36 +64,37 @@ typedef struct
|
||||
struct
|
||||
{
|
||||
/* Програмные ошибки */
|
||||
unsigned Internal_1:1; ///< Внутренняя неисправность УПП 1
|
||||
unsigned Internal_2:1; ///< Внутренняя неисправность УПП 2
|
||||
unsigned Internal_3:1; ///< Внутренняя неисправность УПП 3
|
||||
unsigned Internal_4:1; ///< Внутренняя неисправность УПП 4
|
||||
unsigned Internal_5:1; ///< Внутренняя неисправность УПП 5
|
||||
unsigned Internal_6:1; ///< Внутренняя неисправность УПП 6
|
||||
unsigned Internal_1:1; ///< Ошибка 1: Внутренняя неисправность УПП 1
|
||||
unsigned Internal_2:1; ///< Ошибка 2: Внутренняя неисправность УПП 2
|
||||
unsigned Internal_3:1; ///< Ошибка 3: Внутренняя неисправность УПП 3
|
||||
unsigned Internal_4:1; ///< Ошибка 4: Внутренняя неисправность УПП 4
|
||||
unsigned Internal_5:1; ///< Ошибка 5: Внутренняя неисправность УПП 5
|
||||
unsigned Internal_6:1; ///< Ошибка 6: Внутренняя неисправность УПП 6
|
||||
|
||||
/* Ошибки по питанию */
|
||||
unsigned Power_Digit_5V:1; ///< Неисправность цифрового источника питания (5 В)
|
||||
unsigned Power_24V:1; ///< Неисправность источника питания 24 В
|
||||
unsigned Power_Analog_5V:1; ///< Неисправность аналогового источника питания микроконтроллера (± 5 В)
|
||||
unsigned Power_SCI_5V:1; ///< Неисправность источника питания последовательных интерфейсов микроконтроллера (5 В)
|
||||
unsigned Power_DIO_24V:1; ///< Неисправность источника питания дискретных входов/выходов (24 В)
|
||||
unsigned Power_Digit_5V:1; ///< Ошибка 7: Неисправность цифрового источника питания (5 В)
|
||||
unsigned Power_24V:1; ///< Ошибка 8: Неисправность источника питания 24 В
|
||||
unsigned Power_Analog_5V:1; ///< Ошибка 9: Неисправность аналогового источника питания микроконтроллера (± 5 В)
|
||||
unsigned Power_SCI_5V:1; ///< Ошибка 10: Неисправность источника питания последовательных интерфейсов микроконтроллера (5 В)
|
||||
unsigned Power_DIO_24V:1; ///< Ошибка 11: Неисправность источника питания дискретных входов/выходов (24 В)
|
||||
|
||||
/* Ошибки по допустимым пределам Наряжений/Токов/Температуры */
|
||||
unsigned OverCurrent:1; ///< Ток выше допустимого (см. Imax и TiMax в @ref UPP_PUI_Params_t)
|
||||
unsigned OverVoltage:1; ///< Напряжение сети выше допустимого (см. Umах в @ref UPP_PUI_Params_t)
|
||||
unsigned OverTemperature:1; ///< Температура выше допустимой (плюс 85 °C)
|
||||
unsigned UnderVoltage:1; ///< Напряжение сети ниже допустимого (см. Umin в @ref UPP_PUI_Params_t)
|
||||
unsigned OverCurrent:1; ///< Ошибка 12: Ток выше допустимого (см. Imax и TiMax в @ref UPP_PUI_Params_t)
|
||||
unsigned OverVoltage:1; ///< Ошибка 13: Напряжение сети выше допустимого (см. Umах в @ref UPP_PUI_Params_t)
|
||||
unsigned OverTemperature:1; ///< Ошибка 14: Температура выше допустимой (плюс 85 °C)
|
||||
unsigned UnderVoltage:1; ///< Ошибка 15: Напряжение сети ниже допустимого (см. Umin в @ref UPP_PUI_Params_t)
|
||||
|
||||
/* Ошибки по обрывам фаз */
|
||||
unsigned LossPhaseA:1; ///< Обрыв фазы A (см. Imin в @ref UPP_PUI_Params_t)
|
||||
unsigned LossPhaseB:1; ///< Обрыв фазы B (см. Imin в @ref UPP_PUI_Params_t)
|
||||
unsigned LossPhaseC:1; ///< Обрыв фазы C (см. Imin в @ref UPP_PUI_Params_t)
|
||||
unsigned LossPhaseAll:1; ///< Ошибка 16: Обрыв трёх фаз (см. Imin в @ref UPP_PUI_Params_t)
|
||||
unsigned LossPhaseA:1; ///< Ошибка 17: Обрыв фазы A (см. Imin в @ref UPP_PUI_Params_t)
|
||||
unsigned LossPhaseB:1; ///< Ошибка 18: Обрыв фазы B (см. Imin в @ref UPP_PUI_Params_t)
|
||||
unsigned LossPhaseC:1; ///< Ошибка 19: Обрыв фазы C (см. Imin в @ref UPP_PUI_Params_t)
|
||||
|
||||
/* Другие ошибки */
|
||||
unsigned LongStart:1; ///< Затянутый пуск (ток не спадает за установленное время) (см. Tdelay в @ref UPP_PUI_Params_t)
|
||||
unsigned Interlace:1; ///< Неправильный порядок чередования фаз (см. Interlace в @ref UPP_PUI_Params_t)
|
||||
unsigned OverFrequency:1; ///< Частота сети выше допустимой
|
||||
unsigned UnderFrequency:1; ///< Частота сети ниже допустимой
|
||||
unsigned LongStart:1; ///< Ошибка 20: Затянутый пуск (ток не спадает за установленное время) (см. Tdelay в @ref UPP_PUI_Params_t)
|
||||
unsigned Interlace:1; ///< Ошибка 21: Неправильный порядок чередования фаз (см. Interlace в @ref UPP_PUI_Params_t)
|
||||
unsigned OverFrequency:1; ///< Ошибка 22: Частота сети выше допустимой
|
||||
unsigned UnderFrequency:1; ///< Ошибка 23: Частота сети ниже допустимой
|
||||
}err;
|
||||
}pui;
|
||||
|
||||
@@ -104,22 +105,58 @@ typedef struct
|
||||
uint64_t all;
|
||||
struct
|
||||
{
|
||||
unsigned slow_calc_overrun:1;
|
||||
unsigned uamp_max:1;
|
||||
unsigned uamp_min:1;
|
||||
unsigned iamp_max:1;
|
||||
unsigned iamp_min:1;
|
||||
|
||||
unsigned ic_max:1;
|
||||
unsigned ic_min:1;
|
||||
unsigned ib_max:1;
|
||||
unsigned ib_min:1;
|
||||
unsigned ia_max:1;
|
||||
unsigned ia_min:1;
|
||||
|
||||
unsigned uba_max:1;
|
||||
unsigned uba_min:1;
|
||||
unsigned uac_max:1;
|
||||
unsigned uac_min:1;
|
||||
unsigned ubc_max:1;
|
||||
unsigned ubc_min:1;
|
||||
|
||||
unsigned fba_max:1;
|
||||
unsigned fba_min:1;
|
||||
unsigned fac_max:1;
|
||||
unsigned fac_min:1;
|
||||
unsigned fbc_max:1;
|
||||
unsigned fbc_min:1;
|
||||
|
||||
|
||||
unsigned temp_warn:1;
|
||||
unsigned temp_err:1;
|
||||
|
||||
unsigned longstart:1;
|
||||
unsigned interlance:3;
|
||||
|
||||
unsigned overrun_slow_calc:1;
|
||||
unsigned overrun_fast_calc:1;
|
||||
}err;
|
||||
}f;
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t angle_reinit_err;
|
||||
uint16_t adc_reinit_err;
|
||||
uint16_t zc_reinit_err;
|
||||
uint16_t pwm_reinit_err;
|
||||
uint16_t slow_calc_overrun;
|
||||
uint16_t overrun_slow_calc;
|
||||
uint16_t overrun_fast_calc;
|
||||
}cnt;
|
||||
|
||||
}prvt; ///< Приватные ошибки, не идущие напрямую в ПУИ
|
||||
}UPP_Errors_t;
|
||||
extern UPP_Errors_t errors;
|
||||
|
||||
void UPP_ErrorsHandle(void);
|
||||
void UPP_Errors_Handle(void);
|
||||
|
||||
#endif //_UPP_ERRORS_H
|
||||
143
UPP/Core/UPP/upp_io.c
Normal file
143
UPP/Core/UPP/upp_io.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file upp_io.c
|
||||
* @brief Входы/выходы УПП
|
||||
******************************************************************************
|
||||
* @details
|
||||
******************************************************************************/
|
||||
#include "upp_io.h"
|
||||
#include "main.h"
|
||||
UPP_LEDs_t UPP_LEDS;
|
||||
UPP_DiscreteInputs_t UPP_DIN;
|
||||
UPP_DiscreteOutputs_t UPP_DO;
|
||||
|
||||
static void UPP_CEN_Write(int state);
|
||||
static void UPP_RDO1_Write(int state);
|
||||
static void UPP_RDO2_Write(int state);
|
||||
static void UPP_RDO3_Write(int state);
|
||||
static void UPP_RDO4_Write(int state);
|
||||
static void UPP_DO1_Write(int state);
|
||||
static void UPP_DO2_Write(int state);
|
||||
static void UPP_DO3_Write(int state);
|
||||
static void UPP_DO4_Write(int state);
|
||||
static void UPP_DO5_Write(int state);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Инициализация дискретных входов/выходов УПП
|
||||
*/
|
||||
void UPP_IO_Init(void)
|
||||
{
|
||||
/* Дискретные выходы */
|
||||
UPP_DO.CEN = &UPP_CEN_Write;
|
||||
UPP_DO.Ready = &UPP_RDO3_Write;
|
||||
UPP_DO.Work = &UPP_RDO2_Write;
|
||||
UPP_DO.Error = &UPP_RDO1_Write;
|
||||
UPP_DO.RDO4 = &UPP_RDO4_Write;
|
||||
UPP_DO.DO1 = &UPP_DO1_Write;
|
||||
UPP_DO.DO2 = &UPP_DO2_Write;
|
||||
UPP_DO.DO3 = &UPP_DO3_Write;
|
||||
UPP_DO.DO4 = &UPP_DO4_Write;
|
||||
UPP_DO.DO5 = &UPP_DO5_Write;
|
||||
|
||||
|
||||
/* Дискретные входы */
|
||||
GPIO_Switch_Init(&UPP_DIN.Pusk, DIN1_GPIO_Port, DIN1_Pin, 0);
|
||||
UPP_DIN.Pusk.Sw_FilterDelay = 100;
|
||||
GPIO_Switch_Init(&UPP_DIN.MestDist, DIN2_GPIO_Port, DIN2_Pin, 0);
|
||||
UPP_DIN.MestDist.Sw_FilterDelay = 100;
|
||||
GPIO_Switch_Init(&UPP_DIN.DIN3, DIN3_GPIO_Port, DIN3_Pin, 0);
|
||||
GPIO_Switch_Init(&UPP_DIN.err_24Vdio, ERR_24VDIO_GPIO_Port, ERR_24VDIO_Pin, 1);
|
||||
GPIO_Switch_Init(&UPP_DIN.err_24V, ERR_24V_GPIO_Port, ERR_24V_Pin, 1);
|
||||
GPIO_Switch_Init(&UPP_DIN.err_5Vsi, ERR_5VSI_GPIO_Port, ERR_5VSI_Pin, 0);
|
||||
|
||||
/* Дискретные входы платы УМ */
|
||||
GPIO_Switch_Init(&UPP_DIN.err_5Vd, UM_ERR_5VD_GPIO_Port, UM_ERR_5VD_Pin, 0);
|
||||
GPIO_Switch_Init(&UPP_DIN.err_Va, UM_ERR_VA_GPIO_Port, UM_ERR_VA_Pin, 1);
|
||||
|
||||
/* Светодиоды платы УМ */
|
||||
GPIO_LED_Init(&UPP_LEDS.green1, UM_LED_GREEN1_GPIO_Port, UM_LED_GREEN1_Pin, 0);
|
||||
GPIO_LED_Init(&UPP_LEDS.green2, UM_LED_GREEN2_GPIO_Port, UM_LED_GREEN2_Pin, 0);
|
||||
GPIO_LED_Init(&UPP_LEDS.red, UM_LED_RED_GPIO_Port, UM_LED_RED_Pin, 0);
|
||||
|
||||
|
||||
/* Очищаем выходы */
|
||||
UPP_DO.CEN(DISABLE);
|
||||
UPP_DO.Error(DISABLE);
|
||||
UPP_DO.Work(DISABLE);
|
||||
UPP_DO.Ready(DISABLE);
|
||||
UPP_DO.RDO4(DISABLE);
|
||||
UPP_DO.DO1(DISABLE);
|
||||
UPP_DO.DO2(DISABLE);
|
||||
UPP_DO.DO3(DISABLE);
|
||||
UPP_DO.DO4(DISABLE);
|
||||
UPP_DO.DO5(DISABLE);
|
||||
GPIO_LED_Off(&UPP_LEDS.green1);
|
||||
GPIO_LED_Off(&UPP_LEDS.green2);
|
||||
GPIO_LED_Off(&UPP_LEDS.red);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Выставить направление UART1 (STM USART2)
|
||||
*/
|
||||
void UPP_UART1_SetDirection(int state)
|
||||
{
|
||||
HAL_GPIO_WritePin(SCIDE1_GPIO_Port, SCIDE1_Pin, state);
|
||||
}
|
||||
/**
|
||||
* @brief Выставить направление UART2 (STM USART5)
|
||||
*/
|
||||
void UPP_UART2_SetDirection(int state)
|
||||
{
|
||||
HAL_GPIO_WritePin(SCIDE2_GPIO_Port, SCIDE2_Pin, state);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void UPP_CEN_Write(int state)
|
||||
{
|
||||
#if !defined(STM32F417xx)
|
||||
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)
|
||||
{
|
||||
HAL_GPIO_WritePin(RDO1_GPIO_Port, RDO1_Pin, state);
|
||||
}
|
||||
static void UPP_RDO2_Write(int state)
|
||||
{
|
||||
HAL_GPIO_WritePin(RDO2_GPIO_Port, RDO2_Pin, state);
|
||||
}
|
||||
static void UPP_RDO3_Write(int state)
|
||||
{
|
||||
HAL_GPIO_WritePin(RDO3_GPIO_Port, RDO3_Pin, state);
|
||||
}
|
||||
static void UPP_RDO4_Write(int state)
|
||||
{
|
||||
HAL_GPIO_WritePin(RDO4_GPIO_Port, RDO4_Pin, state);
|
||||
}
|
||||
static void UPP_DO1_Write(int state)
|
||||
{
|
||||
HAL_GPIO_WritePin(DO1_GPIO_Port, DO1_Pin, state);
|
||||
}
|
||||
static void UPP_DO2_Write(int state)
|
||||
{
|
||||
HAL_GPIO_WritePin(DO2_GPIO_Port, DO2_Pin, state);
|
||||
}
|
||||
static void UPP_DO3_Write(int state)
|
||||
{
|
||||
HAL_GPIO_WritePin(DO3_GPIO_Port, DO3_Pin, state);
|
||||
}
|
||||
static void UPP_DO4_Write(int state)
|
||||
{
|
||||
HAL_GPIO_WritePin(DO4_GPIO_Port, DO4_Pin, state);
|
||||
}
|
||||
static void UPP_DO5_Write(int state)
|
||||
{
|
||||
HAL_GPIO_WritePin(DO5_GPIO_Port, DO5_Pin, state);
|
||||
}
|
||||
66
UPP/Core/UPP/upp_io.h
Normal file
66
UPP/Core/UPP/upp_io.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file upp_io.h
|
||||
* @brief Входы/выходы УПП
|
||||
******************************************************************************
|
||||
* @details
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _UPP_IO_H
|
||||
#define _UPP_IO_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
|
||||
{
|
||||
/* Отладочные светодиоды */
|
||||
GPIO_LEDTypeDef green1;
|
||||
GPIO_LEDTypeDef green2;
|
||||
GPIO_LEDTypeDef red;
|
||||
}UPP_LEDs_t;
|
||||
extern UPP_LEDs_t UPP_LEDS;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GPIO_SwitchTypeDef Pusk; ///< Команда «ПУСК»
|
||||
GPIO_SwitchTypeDef MestDist; ///< Мест/дист управление
|
||||
GPIO_SwitchTypeDef DIN3; ///< Резерв
|
||||
|
||||
GPIO_SwitchTypeDef err_24Vdio;///< Сигнал ошибки источника питания цифровых входов/выходов
|
||||
GPIO_SwitchTypeDef err_24V; ///< Сигнал ошибки основного источника питания 24В
|
||||
GPIO_SwitchTypeDef err_5Vsi; ///< Сигнал ошибки источника питания цифровых интерфейсов
|
||||
GPIO_SwitchTypeDef err_5Vd; ///< Вход сигнала неисправности цифрового источника питания 5В(+5Vd) микроконтроллера и микросхем ввода-вывода (5 В).
|
||||
GPIO_SwitchTypeDef err_Va; ///< Вход обобщенного сигнала неисправности аналоговых источников питания +3,3В(+3Va), 5В(+5Vа), +15В(+15Va).
|
||||
}UPP_DiscreteInputs_t;
|
||||
extern UPP_DiscreteInputs_t UPP_DIN;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void (*CEN)(int state);
|
||||
|
||||
void (*Error)(int state);
|
||||
void (*Work)(int state);
|
||||
void (*Ready)(int state);
|
||||
void (*RDO4)(int state);
|
||||
|
||||
|
||||
void (*DO1)(int state);
|
||||
void (*DO2)(int state);
|
||||
void (*DO3)(int state);
|
||||
void (*DO4)(int state);
|
||||
void (*DO5)(int state);
|
||||
}UPP_DiscreteOutputs_t;
|
||||
extern UPP_DiscreteOutputs_t UPP_DO;
|
||||
|
||||
/* Инициализация дискретных входов/выходов УПП */
|
||||
void UPP_IO_Init(void);
|
||||
|
||||
/* Выставить направление UART1 (STM USART2) */
|
||||
void UPP_UART1_SetDirection(int state);
|
||||
/* Выставить направление UART2 (STM USART5) */
|
||||
void UPP_UART2_SetDirection(int state);
|
||||
#endif //_UPP_IO_H
|
||||
@@ -1,36 +1,60 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file upp_main.c
|
||||
* @brief Инициализация и самые базовые вещи по работе УПП
|
||||
* @brief Главный файл по работе УПП
|
||||
******************************************************************************
|
||||
* @details
|
||||
Работа УПП состоит из нескольких модулей:
|
||||
- @ref POWER_MONITOR - Считывание и фильтрация данных от АЦП и выставление защит по этим данным
|
||||
- @ref PWM_THYRISTORS - Формирование пачки импульсов
|
||||
- @ref ANGLE_CONTROL - Формирование и регулирование угла открытия тиристора
|
||||
******************************************************************************/
|
||||
#include "upp_main.h" // всё остальное по работе с УПП
|
||||
#include "tim.h"
|
||||
#include "iwdg.h"
|
||||
|
||||
UPP_t upp;
|
||||
float alpha_dbg = 0.5;
|
||||
// ОСНОВНОЙ ЦИКЛ main.c
|
||||
HAL_StatusTypeDef res; // сюда сохраняется результат от выполения всяких функций
|
||||
int dbg_polarity = 1;
|
||||
|
||||
/**
|
||||
* @brief Инициализация УПП.
|
||||
* @return 0 - если ОК, >1 если ошибка.
|
||||
*/
|
||||
int UPP_Init(void)
|
||||
int UPP_App_Init(void)
|
||||
{
|
||||
upp.workmode = UPP_Init;
|
||||
/* Очищаем входы */
|
||||
UPP_IO_Init();
|
||||
|
||||
BenchTime_Init();
|
||||
// Подключение указателей
|
||||
upp.errors = &errors;
|
||||
upp.PUI.params = &MB_DATA.HoldRegs.pui_params;
|
||||
upp.PUI.params = &PARAM_PUI;
|
||||
upp.PUI.values = &MB_DATA.InRegs.pui;
|
||||
upp.call = &MB_INTERNAL.FuncCalls;
|
||||
|
||||
HAL_TIM_Base_Start(&ustim);
|
||||
PowerMonitor_Init(&upp.pm);
|
||||
PWM_Init(&upp.hpwm);
|
||||
Angle_Init(&upp.hangle);
|
||||
if(HAL_TIM_Base_Start(&ustim) != HAL_OK)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if(PowerMonitor_Init(&upp.pm) != HAL_OK)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if(PWM_Init(&upp.hpwm) != HAL_OK)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if(Angle_Init(&upp.hangle) != HAL_OK)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
upp.workmode = WM_Ready;
|
||||
if(UPP_Params_Init() != HAL_OK)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -40,9 +64,16 @@ int UPP_Init(void)
|
||||
*/
|
||||
int UPP_PreWhile(void)
|
||||
{
|
||||
UPP_Control_InternalParams();
|
||||
Angle_SetRange(&upp.hangle, 0.0, 0.8);
|
||||
PowerMonitor_Start(&upp.pm);
|
||||
UPP_Params_Control();
|
||||
|
||||
if(PowerMonitor_Start(&upp.pm) != HAL_OK)
|
||||
return 1;
|
||||
|
||||
#ifdef MATLAB
|
||||
dbg_polarity = 0;
|
||||
#endif
|
||||
|
||||
UPP_DO.CEN(ENABLE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -52,74 +83,157 @@ int UPP_PreWhile(void)
|
||||
*/
|
||||
int UPP_While(void)
|
||||
{
|
||||
PWM_SetPolarity(&upp.hpwm, dbg_polarity);
|
||||
int retval = 0;
|
||||
if(upp.pm.f.runSlow)
|
||||
{
|
||||
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);
|
||||
res = HAL_IWDG_Refresh(&hiwdg); // если не вызываются медленные расчеты - что-то не то сбрасываемся по watchdog
|
||||
// Медленные расчеты
|
||||
PowerMonitor_SlowCalc(&upp.pm);
|
||||
|
||||
int razgon_done = (fabsf(upp.hangle.Iref - u2f(PARAM_PUI.Iref, 100)) < 0.1);
|
||||
|
||||
#ifdef UPP_SIMULATE_I // симулируем токи
|
||||
upp.pm.measured.final.Iamp = upp.hangle.Iref/2;
|
||||
// При симуляции тока не включаем его проверку
|
||||
razgon_done = 0;
|
||||
#endif
|
||||
|
||||
// Защиты // Определенные защиты по току включаем только после разгона
|
||||
PowerMonitor_Protect(&upp.pm, razgon_done);
|
||||
// Обрабока ошибок и выставление итоговой Ошибки
|
||||
UPP_Errors_Handle();
|
||||
// Контроль парамеров
|
||||
UPP_Params_Control();
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef UPP_DISABLE_ERROR_BLOCK
|
||||
// если ошибка вызываем СТОП
|
||||
if(errors.pui.all)
|
||||
{
|
||||
upp.call->stop = 1;
|
||||
}
|
||||
// иначе снимаем СТОП
|
||||
else
|
||||
{
|
||||
upp.call->stop = 0;
|
||||
}
|
||||
upp.call->stop = (errors.common != Err_None);
|
||||
#endif
|
||||
|
||||
// Сброс на дефолтные по запросу
|
||||
if(upp.call->set_default_pui)
|
||||
if(upp.call->set_default_pui || upp.call->set_default_internal)
|
||||
{
|
||||
UPP_SetDefault(1, 0);
|
||||
}
|
||||
if(upp.call->set_default_internal)
|
||||
{
|
||||
UPP_SetDefault(0, 1);
|
||||
UPP_Params_SetDefault(upp.call->set_default_pui, upp.call->set_default_internal);
|
||||
upp.call->set_default_pui = 0;
|
||||
upp.call->set_default_internal = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PowerMonitor_SlowHandle(&upp.pm);
|
||||
// Если СТОП - переходим в ошибку
|
||||
if (upp.call->stop)
|
||||
upp.workmode = WM_Error;
|
||||
upp.workmode = UPP_Error;
|
||||
// Автомат состояний УПП
|
||||
switch(upp.workmode)
|
||||
{
|
||||
case WM_Ready:
|
||||
/*======= Состояние Инициализация =========*/
|
||||
case UPP_Init:
|
||||
res = PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
|
||||
// Индикация
|
||||
UPP_DO.Ready(DISABLE);
|
||||
UPP_DO.Work(DISABLE);
|
||||
UPP_DO.Error(DISABLE);
|
||||
if(slow_cnt == 0)
|
||||
{ // начало инициализации - сбрасываем флаги
|
||||
memset(&ERR_PRIVATE, 0, sizeof(ERR_PRIVATE));
|
||||
memset(&ERR_PUI, 0, sizeof(ERR_PUI));
|
||||
}
|
||||
|
||||
if(slow_cnt > MS_TO_SLOW_TICKS(UPP_INIT_BEFORE_READY_MS))
|
||||
{ // конец инициализации - сбрасываем чтобы потом еще раз инициализироватся
|
||||
slow_cnt = 0;
|
||||
upp.workmode = UPP_Ready;
|
||||
}
|
||||
else
|
||||
{ // инициализация в процессе
|
||||
slow_cnt++;
|
||||
}
|
||||
break;
|
||||
|
||||
/*======= Состояние Готовность =========*/
|
||||
case UPP_Ready:
|
||||
res = PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
|
||||
// Индикация
|
||||
UPP_DO.Ready(ENABLE);
|
||||
UPP_DO.Work(DISABLE);
|
||||
UPP_DO.Error(DISABLE);
|
||||
|
||||
// если пришла команда на запуск
|
||||
if (upp.call->go)
|
||||
{
|
||||
upp.workmode = WM_Running;
|
||||
upp.workmode = UPP_Work;
|
||||
Angle_PID_Reset(&upp.hangle);
|
||||
upp.StartTick = local_time();
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_Running:
|
||||
/*======= Состояние В работе =========*/
|
||||
case UPP_Work:
|
||||
// Разрешаем выход ШИМ
|
||||
__HAL_TIM_MOE_ENABLE(&hpwm1);
|
||||
__HAL_TIM_MOE_ENABLE(&hpwm2);
|
||||
// Индикация
|
||||
UPP_DO.Ready(DISABLE);
|
||||
UPP_DO.Work(ENABLE);
|
||||
UPP_DO.Error(DISABLE);
|
||||
// если пришла команда на остановку
|
||||
if (!upp.call->go)
|
||||
upp.workmode = WM_Ready;
|
||||
upp.workmode = UPP_Init;
|
||||
|
||||
// Коррекция для отсчета угла открытия
|
||||
// 30 градусов - сдвиг между линейными и фазными напряжениями
|
||||
// 30 градусов - фазовое смщеение эксп. фильтра АЦП для сглаживания напряжений
|
||||
float Correction = 30 + 0;
|
||||
|
||||
// Регулирование тиристоров
|
||||
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))
|
||||
{
|
||||
errors.pui.err.LongStart = 1;
|
||||
ERR_PRIVATE.longstart = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_Error:
|
||||
if(errors.common == Err_None)
|
||||
upp.workmode = WM_Ready;
|
||||
|
||||
PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
|
||||
break;
|
||||
|
||||
case WM_Done:
|
||||
PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
|
||||
break;
|
||||
/*======= Состояние Работа завершена =========*/
|
||||
// case WM_Done:
|
||||
// // Индикация
|
||||
// UPP_DO.Ready(DISABLE);
|
||||
// UPP_DO.Work(DISABLE);
|
||||
// UPP_DO.Error(DISABLE);
|
||||
// PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
|
||||
// break;
|
||||
|
||||
/*======= Состояние Ошибка/Неизвестно =========*/
|
||||
case UPP_Error:
|
||||
default:
|
||||
PWM_Stop(&upp.hpwm, 0, 1); // Останавливаем ВЕСЬ ШИМ
|
||||
// Индикация
|
||||
UPP_DO.Ready(DISABLE);
|
||||
UPP_DO.Work(DISABLE);
|
||||
UPP_DO.Error(ENABLE);
|
||||
// Находимся до тех пор пока ошибки не будет устранена
|
||||
if(errors.common == Err_None)
|
||||
upp.workmode = UPP_Init;
|
||||
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
upp.pm.f.runSlow = 0;
|
||||
upp.Timings.slow_calc_us = BenchTime_End(BT_SLOWCALC, angletim.Instance->CNT)/ANGLE_TIM2_FREQ_MHZ;
|
||||
}//if(upp.pm.f.runSlow)
|
||||
else
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
@@ -129,21 +243,42 @@ int UPP_While(void)
|
||||
*/
|
||||
void UPP_Tick(void)
|
||||
{
|
||||
if(upp.workmode == WM_Not_Init)
|
||||
// Начинаем все проверять только после того как уйдем из режима инициализации
|
||||
if(upp.workmode == UPP_Init)
|
||||
return;
|
||||
UPP_ErrorsHandle();
|
||||
UPP_Control_InternalParams();
|
||||
|
||||
|
||||
if(GPIO_Read_Switch(&UPP_DIN.Pusk))
|
||||
{
|
||||
upp.call->go = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
upp.call->go = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ПРЕРЫВАНИЯ stm32f4xx_it.c
|
||||
|
||||
//================ ПРЕРЫВАНИЯ stm32f4xx_it.c ===================
|
||||
/**
|
||||
* @brief @ref DMA2_Stream0_IRQHandler
|
||||
*/
|
||||
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);
|
||||
|
||||
PowerMonitor_Handle(&upp.pm);
|
||||
|
||||
if(upp.pm.f.inIsr)
|
||||
{
|
||||
ERR_PRIVATE.overrun_fast_calc = 1;
|
||||
ERR_PRIVATE_CNT.overrun_fast_calc++;
|
||||
return;
|
||||
}
|
||||
upp.pm.f.inIsr = 1;
|
||||
|
||||
PowerMonitor_FastCalc(&upp.pm);
|
||||
|
||||
for(int phase = 0; phase < 3; phase++)
|
||||
{
|
||||
@@ -151,58 +286,72 @@ void UPP_ADC_Handle(void)
|
||||
if(ZC_isOccurred(&upp.pm.zc, phase))
|
||||
{
|
||||
// Если УПП в работе
|
||||
if(upp.workmode == WM_Running)
|
||||
if(upp.workmode == UPP_Work)
|
||||
{
|
||||
// Меняем полуволну тиристора
|
||||
UPP_HalfWave_t curr_halfwave = ZC_GetHalfWave(&upp.pm.zc, phase);
|
||||
PWM_SetHalfWave(&upp.hpwm, phase, curr_halfwave);
|
||||
res = PWM_SetHalfWave(&upp.hpwm, phase, curr_halfwave);
|
||||
// Начинаем отсчитывать угол
|
||||
Angle_Start(&upp.hangle, phase, alpha_dbg, 10);
|
||||
res = Angle_Start(&upp.hangle, phase, UPP_HALFWAVE_PERIOD);
|
||||
if(res != HAL_OK)
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Проверяем на ошибки
|
||||
// ШИМим ключи
|
||||
res = PWM_Handle(&upp.hpwm, UPP_HALFWAVE_PERIOD);
|
||||
|
||||
upp.Timings.isr_adc = BenchTime_End(BT_ADC, angletim.Instance->CNT);
|
||||
}
|
||||
void UPP_PWM_Handle(void)
|
||||
{
|
||||
BenchTime_Start(BT_PWM, angletim.Instance->CNT, HAL_MAX_DELAY);
|
||||
PWM_Handle(&upp.hpwm);
|
||||
upp.Timings.isr_pwm = BenchTime_End(BT_PWM, angletim.Instance->CNT);
|
||||
upp.Timings.isr_adc_us = BenchTime_End(BT_ADC, angletim.Instance->CNT)/ANGLE_TIM2_FREQ_MHZ;
|
||||
upp.pm.f.inIsr = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief @ref HAL_TIM_OC_DelayElapsedCallback
|
||||
*/
|
||||
void UPP_Angle_Handle(void)
|
||||
{
|
||||
UPP_Phase_t phase = Angle_Handle(&upp.hangle);
|
||||
Angle_Reset(&upp.hangle, phase);
|
||||
res = Angle_Reset(&upp.hangle, phase);
|
||||
// Если УПП в работе
|
||||
if(upp.workmode == WM_Running)
|
||||
if(upp.workmode == UPP_Work)
|
||||
{
|
||||
switch(phase)
|
||||
{
|
||||
case UPP_PHASE_A:
|
||||
PWM_Start(&upp.hpwm, UPP_PHASE_A);
|
||||
res = PWM_Start(&upp.hpwm, UPP_PHASE_A);
|
||||
break;
|
||||
case UPP_PHASE_B:
|
||||
PWM_Start(&upp.hpwm, UPP_PHASE_B);
|
||||
res = PWM_Start(&upp.hpwm, UPP_PHASE_B);
|
||||
break;
|
||||
case UPP_PHASE_C:
|
||||
PWM_Start(&upp.hpwm, UPP_PHASE_C);
|
||||
res = PWM_Start(&upp.hpwm, UPP_PHASE_C);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if(res != HAL_OK)
|
||||
__NOP();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Callback по совпадению CCRx c CNT
|
||||
*/
|
||||
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef* htim)
|
||||
{
|
||||
if (htim == upp.hangle.htim)
|
||||
{
|
||||
BenchTime_Start(BT_SYSTICK, angletim.Instance->CNT, HAL_MAX_DELAY);
|
||||
UPP_Angle_Handle();
|
||||
upp.Timings.isr_systick = BenchTime_End(BT_SYSTICK, angletim.Instance->CNT);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief @ref HAL_TIM_PeriodElapsedCallback
|
||||
*/
|
||||
void HAL_IncTick(void)
|
||||
{
|
||||
BenchTime_Start(BT_SYSTICK, angletim.Instance->CNT, HAL_MAX_DELAY);
|
||||
uwTick += uwTickFreq;
|
||||
UPP_Tick();
|
||||
upp.Timings.isr_systick_us = BenchTime_End(BT_SYSTICK, angletim.Instance->CNT)/ANGLE_TIM2_FREQ_MHZ;
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file upp_main.h
|
||||
* @brief Определения структур данных Modbus устройства
|
||||
* @brief Определения структур для работы УПП
|
||||
******************************************************************************
|
||||
* @details
|
||||
******************************************************************************/
|
||||
@@ -15,9 +15,7 @@
|
||||
#include "angle_control.h" // Управление углом открытия
|
||||
|
||||
#include "upp_status.h" // статус упп
|
||||
#include "upp_control.h" // управление упп
|
||||
|
||||
extern float alpha_dbg;
|
||||
#include "upp_params.h" // управление упп
|
||||
|
||||
|
||||
typedef struct
|
||||
@@ -41,16 +39,19 @@ typedef struct
|
||||
|
||||
struct
|
||||
{
|
||||
uint32_t isr_adc;
|
||||
uint32_t isr_pwm;
|
||||
uint32_t isr_systick;
|
||||
uint32_t slow_calc_prd_us;
|
||||
uint32_t slow_calc_us;
|
||||
uint32_t isr_adc_prd_us;
|
||||
uint32_t isr_adc_us;
|
||||
uint32_t isr_pwm_us;
|
||||
uint32_t isr_systick_us;
|
||||
}Timings;
|
||||
}UPP_t;
|
||||
extern UPP_t upp;
|
||||
|
||||
|
||||
/* Инициализация УПП */
|
||||
int UPP_Init(void);
|
||||
int UPP_App_Init(void);
|
||||
/* Инициализация основного цикла УПП. */
|
||||
int UPP_PreWhile(void);
|
||||
/* Основной цикл УПП. */
|
||||
|
||||
578
UPP/Core/UPP/upp_params.c
Normal file
578
UPP/Core/UPP/upp_params.c
Normal file
@@ -0,0 +1,578 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file upp_params.c
|
||||
* @brief Модуль проверяющий параметры УПП
|
||||
******************************************************************************
|
||||
* @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" // всё остальное по работе с УПП
|
||||
|
||||
#define SATURATE_U16(value, min, max) \
|
||||
value = ((value) < (min) ? (min) : ((value) > (max) ? (max) : (value)))
|
||||
|
||||
static int __CheckParamF(float *paramDist, uint16_t paramSrc, float Coef);
|
||||
static int __CheckParamU32(uint32_t *paramDist, uint16_t paramSrc, float Coef);
|
||||
static int __CheckParamU16(uint16_t *paramDist, uint16_t paramSrc);
|
||||
static int __CheckParamU8(uint8_t *paramDist, uint16_t paramSrc, float Coef);
|
||||
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 Контроль внутренних параметров УПП.
|
||||
* @return HAL Status.
|
||||
*/
|
||||
void UPP_Params_ControlInternal(void)
|
||||
{
|
||||
if(upp.call->go) // при запущеном УПП ничего не меняем
|
||||
return;
|
||||
|
||||
// флаги обновились ли конфиги
|
||||
static int alpha_update = 0;
|
||||
static int adc_channel_update[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
|
||||
static int zc_update = 0;
|
||||
static int pwm_update = 0;
|
||||
|
||||
// временная переменная для параметров Мониторинга сети
|
||||
float angle_max = upp.hangle.Config.AngleMax;
|
||||
float angle_min = upp.hangle.Config.AngleMin;
|
||||
float angle_pid_kp = upp.hangle.pid.Kp;
|
||||
float angle_pid_ki = upp.hangle.pid.Ki/((float)PM_SLOW_PERIOD_US/1000000);
|
||||
float angle_pid_kd = upp.hangle.pid.Kd;
|
||||
// временная переменная для параметров каналов АЦП
|
||||
float adc_channel_max[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
|
||||
uint16_t adc_channel_zero[ADC_NUMB_OF_REGULAR_CHANNELS] = {0};
|
||||
// временная переменная для параметров перехода через ноль
|
||||
float zc_hysteresis = upp.pm.zc.Config.Hysteresis;
|
||||
uint16_t zc_debounce = upp.pm.zc.Config.DebounceSamples;
|
||||
// временная переменная для параметров ШИМ
|
||||
uint8_t pwm_phase_mask = upp.hpwm.Config.PhaseMask.all;
|
||||
uint16_t pwm_freq = upp.hpwm.Config.Frequency;
|
||||
float pwm_duty = upp.hpwm.Config.Duty;
|
||||
float pwm_pulse_len = upp.hpwm.Config.PulseLength;
|
||||
// временная переменная для параметров Мониторинга сети
|
||||
uint16_t pm_rms_widnow_size = upp.pm.rms[0].window_size;
|
||||
float pm_rms_exp_alpha = upp.pm.rms_exp[0].alpha;
|
||||
|
||||
|
||||
|
||||
// Параметры регулятора Угла открытия
|
||||
if(__CheckParamF(&angle_max, PARAM_INTERNAL.angle.Angle_Max, 65535))
|
||||
{
|
||||
alpha_update = 1;
|
||||
}
|
||||
if(__CheckParamF(&angle_min, PARAM_INTERNAL.angle.Angle_Min, 65535))
|
||||
{
|
||||
alpha_update = 1;
|
||||
}
|
||||
if(__CheckParamF(&angle_pid_kp, PARAM_INTERNAL.angle.PID_Kp, 10000))
|
||||
{
|
||||
alpha_update = 1;
|
||||
}
|
||||
if(__CheckParamF(&angle_pid_ki, PARAM_INTERNAL.angle.PID_Ki, 10000))
|
||||
{
|
||||
alpha_update = 1;
|
||||
}
|
||||
if(__CheckParamF(&angle_pid_kd, PARAM_INTERNAL.angle.PID_Kd, 10000))
|
||||
{
|
||||
alpha_update = 1;
|
||||
}
|
||||
|
||||
|
||||
// Параметры АЦП
|
||||
for(int i = 0; i < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
|
||||
{
|
||||
adc_channel_max[i] = upp.pm.adc.Coefs[i].vMax;
|
||||
adc_channel_zero[i] = upp.pm.adc.Coefs[i].lZero;
|
||||
|
||||
// Максимальное измеряемое напряжение
|
||||
if(__CheckParamF(&adc_channel_max[i], PARAM_INTERNAL.adc.ADC_Max[i], 10))
|
||||
{
|
||||
adc_channel_update[i] = 1;
|
||||
}
|
||||
// Значение АЦП при нулевом входе
|
||||
if(__CheckParamU16(&adc_channel_zero[i], PARAM_INTERNAL.adc.ADC_Zero[i]))
|
||||
{
|
||||
adc_channel_update[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Параметры алгоритма перехода через ноль
|
||||
if(__CheckParamF(&zc_hysteresis, PARAM_INTERNAL.zc.Hysteresis, 10000))
|
||||
{
|
||||
zc_update = 1;
|
||||
}
|
||||
if(__CheckParamU16(&zc_debounce, PARAM_INTERNAL.zc.DebouneCouner))
|
||||
{
|
||||
zc_update = 1;
|
||||
}
|
||||
|
||||
// Параметры ШИМ
|
||||
if(__CheckParamU8(&pwm_phase_mask, PARAM_INTERNAL.pwm.PhaseMask, 1))
|
||||
{
|
||||
pwm_update = 1;
|
||||
}
|
||||
if(__CheckParamU16(&pwm_freq, PARAM_INTERNAL.pwm.Frequency))
|
||||
{
|
||||
pwm_update = 1;
|
||||
}
|
||||
if(__CheckParamF(&pwm_duty, PARAM_INTERNAL.pwm.Duty, 100))
|
||||
{
|
||||
pwm_update = 1;
|
||||
}
|
||||
if(__CheckParamF(&pwm_pulse_len, PARAM_INTERNAL.pwm.PulseLength, 65535))
|
||||
{
|
||||
pwm_update = 1;
|
||||
}
|
||||
|
||||
// Параметры мониторинга
|
||||
if(__CheckParamU16(&pm_rms_widnow_size, PARAM_INTERNAL.pm.rms_window_size))
|
||||
{
|
||||
for(int i = 0; i < RMS_ALL; i++)
|
||||
{
|
||||
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(Angle_SetRange(&upp.hangle, angle_min, angle_max) == HAL_OK)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
if(adc_channel_update[i])
|
||||
{
|
||||
if(ADC_ConfigChannel(&upp.pm.adc, i, adc_channel_zero[i], adc_channel_max[i], 4095) == HAL_OK)
|
||||
adc_channel_update[i] = 0;
|
||||
else
|
||||
ERR_PRIVATE_CNT.adc_reinit_err++;
|
||||
}
|
||||
}
|
||||
// Обновление Zero-Cross конфигов
|
||||
if(zc_update)
|
||||
{
|
||||
if(ZC_Init(&upp.pm.zc, upp.pm.zc.Config.NumChannels, zc_hysteresis, zc_debounce) == HAL_OK)
|
||||
zc_update = 0;
|
||||
else
|
||||
ERR_PRIVATE_CNT.zc_reinit_err++;
|
||||
}
|
||||
// Обновление ШИМ конфигов
|
||||
if(pwm_update)
|
||||
{
|
||||
if(PWM_SetConfig(&upp.hpwm, pwm_phase_mask, pwm_freq, pwm_duty, pwm_pulse_len) == HAL_OK)
|
||||
{
|
||||
pwm_update = 0;
|
||||
}
|
||||
else
|
||||
ERR_PRIVATE_CNT.pwm_reinit_err++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @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 Контроль параметров УПП на корректные значения.
|
||||
* @return HAL Status.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Установка параметров на дефолтные значения @ref UPP_PARAMS_DEFAULT.
|
||||
* @param pui_default Сбросить параметры ПУИ
|
||||
* @param internal_default Сбросить внутренние параметры
|
||||
* @return HAL Status.
|
||||
*/
|
||||
void UPP_Params_SetDefault(int pui_default, int internal_default)
|
||||
{
|
||||
if(pui_default)
|
||||
{
|
||||
PARAM_PUI.Iref = PUI_Iref_PERCENT_DEFAULT*100;
|
||||
PARAM_PUI.Tnt = PUI_Tnt_MS_DEFAULT;
|
||||
PARAM_PUI.Umin = PUI_Umin_PERCENT_DEFAULT*100;
|
||||
PARAM_PUI.Umax = PUI_Umax_PERCENT_DEFAULT*100;
|
||||
PARAM_PUI.Imax = PUI_Imax_PERCENT_DEFAULT*100;
|
||||
PARAM_PUI.Imin = PUI_Imin_PERCENT_DEFAULT*100;
|
||||
PARAM_PUI.TiMax = PUI_TiMax_US_DEFAULT;
|
||||
PARAM_PUI.Tdelay = PUI_Tdelay_SECONDS_DEFAULT;
|
||||
PARAM_PUI.Interlace = PUI_Interlace_EN_DEFAULT;
|
||||
}
|
||||
|
||||
if(internal_default)
|
||||
{
|
||||
PARAM_INTERNAL.setpoints.TemperatureWarn = SETPOINT_TEMP_WARN*10;
|
||||
PARAM_INTERNAL.setpoints.TemperatureErr = SETPOINT_TEMP_ERR*10;
|
||||
|
||||
PARAM_INTERNAL.nominal.PhaseNumber = NOM_PHASE_NUMB;
|
||||
PARAM_INTERNAL.nominal.U = NOM_U_V_DEFAULT*10;
|
||||
PARAM_INTERNAL.nominal.U_deviation_plus = NOM_U_DEVIATION_PLUS_PERCENT_DEFAULT*100;
|
||||
PARAM_INTERNAL.nominal.U_deviation_minus = NOM_U_DEVIATION_MINUS_PERCENT_DEFAULT*100;
|
||||
PARAM_INTERNAL.nominal.F = NOM_F_HZ_DEFAULT*100;
|
||||
PARAM_INTERNAL.nominal.F_deviation_plus = NOM_F_DEVIATION_PLUS_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.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_UAC] = ADC_U_MAX_V_DEFAULT*10;
|
||||
PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_IC] = ADC_I_MAX_A_DEFAULT*10;
|
||||
PARAM_INTERNAL.adc.ADC_Max[ADC_CHANNEL_IA] = ADC_I_MAX_A_DEFAULT*10;
|
||||
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_UBA] = ADC_U_ZERO_DEFAULT;
|
||||
PARAM_INTERNAL.adc.ADC_Zero[ADC_CHANNEL_UAC] = ADC_U_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.pwm.PhaseMask = 7; // (все три фазы)
|
||||
PARAM_INTERNAL.pwm.Frequency = PWM_THYR_FREQUENCY_HZ_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.DebouneCouner = ZERO_CROSS_DEBOUNCE_CNT_DEFAULT;
|
||||
|
||||
|
||||
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_Kd = ANGLE_PID_KD_COEF_DEFAULT*10000;
|
||||
PARAM_INTERNAL.angle.Angle_Max = ANGLE_MAX_PERCENT_DEFAULT*65535;
|
||||
PARAM_INTERNAL.angle.Angle_Min = ANGLE_MIN_PERCENT_DEFAULT*65535;
|
||||
PARAM_INTERNAL.angle.PulseLengthReserve = ANGLE_PULSE_LENGTH_RESERVE_PERCENT_DEFAULT*100;
|
||||
//__AngleSetLimit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define ANGLE_PERIOD_MS(_freq_) (((float)1/(_freq_*2))*1000)
|
||||
|
||||
// Перерасчет максимально допустимого угла
|
||||
static void __AngleSetLimit(void)
|
||||
{ // Сколько пачка ипульсов занимает процентов от всего периода
|
||||
float pulses_percent_of_period = (((float)PARAM_INTERNAL.pwm.PulseLength / PARAM_INTERNAL.pwm.Frequency) * 1000) / ANGLE_PERIOD_MS(upp.pm.measured.final.Fmean);
|
||||
// Вычитаем этот процент из 1 - получаем максимально безопасный угол
|
||||
float angle_limit = 1;
|
||||
angle_limit -= pulses_percent_of_period*u2f(PARAM_INTERNAL.angle.PulseLengthReserve, 100); // добавляем запас в PulseLengthReserve процентов от пачки импульсов
|
||||
Angle_SetLimit(&upp.hangle, angle_limit);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Сверить и обновить float параметр из uint16_t.
|
||||
* @param paramDist Указатель на float параметр
|
||||
* @param paramSrc Значение для сравнения с float параметром
|
||||
* @param Coef Коэффициент для приведения float к uint16_t: uint16_t = float*coef, float = uint16_t/coef
|
||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||
*/
|
||||
static int __CheckParamF(float *paramDist, uint16_t paramSrc, float Coef)
|
||||
{
|
||||
if(paramDist == NULL)
|
||||
return 0;
|
||||
|
||||
uint16_t expected_mb_param = *paramDist*Coef;
|
||||
if(expected_mb_param != paramSrc)
|
||||
{
|
||||
*paramDist = (float)paramSrc/Coef;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Сверить и обновить uint32_t параметр из uint16_t.
|
||||
* @param paramDist Указатель на uint32_t параметр
|
||||
* @param paramSrc Значение для сравнения с uint32_t параметром
|
||||
* @param Coef Коэффициент для приведения uint32_t к uint16_t: uint16_t = uint32_t*coef, uint32_t = uint16_t/coef
|
||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||
*/
|
||||
static int __CheckParamU32(uint32_t *paramDist, uint16_t paramSrc, float Coef)
|
||||
{
|
||||
if(paramDist == NULL)
|
||||
return 0;
|
||||
|
||||
uint16_t expected_mb_param = *paramDist*Coef;
|
||||
if(expected_mb_param != paramSrc)
|
||||
{
|
||||
*paramDist = (uint32_t)paramSrc/Coef;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Сверить и обновить uint16_t параметр из uint16_t.
|
||||
* @param paramDist Указатель на uint16_t параметр
|
||||
* @param paramSrc Значение для сравнения с uint16_t параметром
|
||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||
*/
|
||||
static int __CheckParamU16(uint16_t *paramDist, uint16_t paramSrc)
|
||||
{
|
||||
if(paramDist == NULL)
|
||||
return 0;
|
||||
|
||||
uint16_t expected_mb_param = *paramDist;
|
||||
if(expected_mb_param != paramSrc)
|
||||
{
|
||||
*paramDist = (uint16_t)paramSrc;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Сверить и обновить uint8_t параметр из uint16_t.
|
||||
* @param paramDist Указатель на uint8_t параметр
|
||||
* @param paramSrc Значение для сравнения с uint32_t параметром
|
||||
* @param Coef Коэффициент для приведения uint32_t к uint16_t: uint16_t = uint8_t*coef, uint8_t = uint16_t/coef
|
||||
* @return 0 - параметры совпадают, 1 - параметр был обновлен на paramSrc.
|
||||
*/
|
||||
static int __CheckParamU8(uint8_t *paramDist, uint16_t paramSrc, float Coef)
|
||||
{
|
||||
if(paramDist == NULL)
|
||||
return 0;
|
||||
|
||||
uint16_t expected_mb_param = *paramDist*Coef;
|
||||
if(expected_mb_param != paramSrc)
|
||||
{
|
||||
*paramDist = (uint8_t)paramSrc/Coef;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
111
UPP/Core/UPP/upp_params.h
Normal file
111
UPP/Core/UPP/upp_params.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file upp_params.h
|
||||
* @brief Модуль определябщий поведение УПП
|
||||
******************************************************************************
|
||||
* @details
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _UPP_PARAMS_H
|
||||
#define _UPP_PARAMS_H
|
||||
#include "upp_defs.h"
|
||||
|
||||
#define u2f(_u16_, _coef_) ((float)_u16_/_coef_)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned set_default_pui:1; ///< Выставить настройки ПУИ в дефолтные
|
||||
unsigned set_default_internal:1;///< Выставить внутренние настройки в дефолтные
|
||||
unsigned go:1; ///< Запустить УПП
|
||||
unsigned stop:1; ///< Остановка УПП (авария)
|
||||
|
||||
|
||||
unsigned reserved:11;
|
||||
unsigned reset_mcu:1;
|
||||
}UPP_FuncCalls_t;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t PhaseSequence; ///< Последовательность фаз todo
|
||||
uint16_t PhaseNumber; ///< [Количество]
|
||||
uint16_t U; ///< [В x 10]
|
||||
uint16_t U_deviation_plus; ///< [Проценты x 100]
|
||||
uint16_t U_deviation_minus; ///< [Проценты x 100]
|
||||
uint16_t F; ///< [Гц x 100]
|
||||
uint16_t F_deviation_plus; ///< [Проценты x 100]
|
||||
uint16_t F_deviation_minus; ///< [Проценты x 100]
|
||||
uint16_t I; ///< [Амперы x 10]
|
||||
}UPP_ParamsNominal_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t TemperatureWarn; ///< Предупредительный порог температуры [Градусы x 100]
|
||||
uint16_t TemperatureErr; ///< Аварийный порог температуры [Градусы x 100]
|
||||
}UPP_ParamsSetpoints_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
struct
|
||||
{
|
||||
uint16_t rms_window_size; ///< Размер окна для RMS
|
||||
uint16_t rms_exp_alpha; ///< Постоянная времени для сглаживания RMS
|
||||
}pm;
|
||||
|
||||
UPP_ParamsNominal_t nominal;
|
||||
UPP_ParamsSetpoints_t setpoints;
|
||||
|
||||
/* Параметры АЦП */
|
||||
struct
|
||||
{
|
||||
uint16_t ADC_Max[4]; ///< Величина в единицах измерения при АЦП = 4095 [В или А x 10]
|
||||
uint16_t ADC_Zero[4]; ///< Кванты АЦП когда на входе ноль
|
||||
}adc;
|
||||
|
||||
/* Параметры ШИМ */
|
||||
struct
|
||||
{
|
||||
uint16_t PhaseMask; ///< Битовяя маска на какие фазы подавать ШИМ: 0 бит - a, 1 бит - b, 2 бит - c
|
||||
uint16_t Frequency; ///< Частота ШИМ для пачки импульсов на тиристоры [Герцы]
|
||||
uint16_t Duty; ///< Скважность ШИМ для пачки импульсов на тиристоры [Проценты]
|
||||
uint16_t PulseLength; ///< Количесво импульсов в пачке [Количество]
|
||||
}pwm;
|
||||
|
||||
/* Параметры Угла */
|
||||
struct
|
||||
{
|
||||
uint16_t Hysteresis; ///< Гистерезис для определения перехода через ноль [Проценты x 100]
|
||||
uint16_t DebouneCouner; ///< Защита от дребезга: через сколько тактов снова начать фиксировать переход через ноль [Количество]
|
||||
}zc;
|
||||
|
||||
/* Параметры Угла */
|
||||
struct
|
||||
{
|
||||
uint16_t PulseLengthReserve;/*!< @brief Сколько запаса закладывать на длительность пачки импульсов [Проценты] @ref __AngleSetLimit
|
||||
@details Пример: 100% - будет запас в одну пачку импульсов */
|
||||
uint16_t Angle_Max; ///< Максимальный угол открытия тиристора [0..1 x 65535]
|
||||
uint16_t Angle_Min; ///< Минимальный угол открытия тиристора [0..1 x 65535]
|
||||
uint16_t PID_Kp; ///< Пропорциональный коэфициент ПИ регулятора угла [x 10000]
|
||||
uint16_t PID_Ki; ///< Интегральный коэфициент ПИ регулятора угла [x 10000]
|
||||
uint16_t PID_Kd; ///< Интегральный коэфициент ПИ регулятора угла [x 10000]
|
||||
}angle;
|
||||
|
||||
|
||||
|
||||
}UPP_PrvtParams_t;
|
||||
|
||||
/* Контроль параметров УПП. */
|
||||
void UPP_Params_Control(void);
|
||||
/* Контроль параметров от ПУИ. */
|
||||
void UPP_Params_ControlPUI(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);
|
||||
|
||||
#endif //_UPP_PARAMS_H
|
||||
9
UPP/MDK-ARM/EventRecorderStub.scvd
Normal file
9
UPP/MDK-ARM/EventRecorderStub.scvd
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<component_viewer schemaVersion="0.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="Component_Viewer.xsd">
|
||||
|
||||
<component name="EventRecorderStub" version="1.0.0"/> <!--name and version of the component-->
|
||||
<events>
|
||||
</events>
|
||||
|
||||
</component_viewer>
|
||||
24
UPP/MDK-ARM/RTE/_Debug_F417/RTE_Components.h
Normal file
24
UPP/MDK-ARM/RTE/_Debug_F417/RTE_Components.h
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
/*
|
||||
* Auto generated Run-Time-Environment Configuration File
|
||||
* *** Do not modify ! ***
|
||||
*
|
||||
* Project: 'UPP'
|
||||
* Target: 'Debug_F417'
|
||||
*/
|
||||
|
||||
#ifndef RTE_COMPONENTS_H
|
||||
#define RTE_COMPONENTS_H
|
||||
|
||||
|
||||
/*
|
||||
* Define the Device Header File:
|
||||
*/
|
||||
#define CMSIS_device_header "stm32f4xx.h"
|
||||
|
||||
/* Keil.ARM Compiler::Compiler:I/O:STDOUT:ITM:1.2.0 */
|
||||
#define RTE_Compiler_IO_STDOUT /* Compiler I/O: STDOUT */
|
||||
#define RTE_Compiler_IO_STDOUT_ITM /* Compiler I/O: STDOUT ITM */
|
||||
|
||||
|
||||
#endif /* RTE_COMPONENTS_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
424
UPP/MDK-ARM/startup_stm32f417xx.s
Normal file
424
UPP/MDK-ARM/startup_stm32f417xx.s
Normal file
@@ -0,0 +1,424 @@
|
||||
;*******************************************************************************
|
||||
;* File Name : startup_stm32f417xx.s
|
||||
;* Author : MCD Application Team
|
||||
;* Description : STM32F417xx devices vector table for MDK-ARM toolchain.
|
||||
;* This module performs:
|
||||
;* - Set the initial SP
|
||||
;* - Set the initial PC == Reset_Handler
|
||||
;* - Set the vector table entries with the exceptions ISR address
|
||||
;* - Branches to __main in the C library (which eventually
|
||||
;* calls main()).
|
||||
;* After Reset the CortexM4 processor is in Thread mode,
|
||||
;* priority is Privileged, and the Stack is set to Main.
|
||||
;*******************************************************************************
|
||||
;* @attention
|
||||
;*
|
||||
;* Copyright (c) 2017 STMicroelectronics.
|
||||
;* All rights reserved.
|
||||
;*
|
||||
;* This software is licensed under terms that can be found in the LICENSE file
|
||||
;* in the root directory of this software component.
|
||||
;* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
;*
|
||||
;*******************************************************************************
|
||||
;* <<< Use Configuration Wizard in Context Menu >>>
|
||||
;
|
||||
; Amount of memory (in bytes) allocated for Stack
|
||||
; Tailor this value to your application needs
|
||||
; <h> Stack Configuration
|
||||
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
||||
; </h>
|
||||
|
||||
Stack_Size EQU 0x400
|
||||
|
||||
AREA STACK, NOINIT, READWRITE, ALIGN=3
|
||||
Stack_Mem SPACE Stack_Size
|
||||
__initial_sp
|
||||
|
||||
|
||||
; <h> Heap Configuration
|
||||
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
||||
; </h>
|
||||
|
||||
Heap_Size EQU 0x400
|
||||
|
||||
AREA HEAP, NOINIT, READWRITE, ALIGN=3
|
||||
__heap_base
|
||||
Heap_Mem SPACE Heap_Size
|
||||
__heap_limit
|
||||
|
||||
PRESERVE8
|
||||
THUMB
|
||||
|
||||
|
||||
; Vector Table Mapped to Address 0 at Reset
|
||||
AREA RESET, DATA, READONLY
|
||||
EXPORT __Vectors
|
||||
EXPORT __Vectors_End
|
||||
EXPORT __Vectors_Size
|
||||
|
||||
__Vectors DCD __initial_sp ; Top of Stack
|
||||
DCD Reset_Handler ; Reset Handler
|
||||
DCD NMI_Handler ; NMI Handler
|
||||
DCD HardFault_Handler ; Hard Fault Handler
|
||||
DCD MemManage_Handler ; MPU Fault Handler
|
||||
DCD BusFault_Handler ; Bus Fault Handler
|
||||
DCD UsageFault_Handler ; Usage Fault Handler
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD 0 ; Reserved
|
||||
DCD SVC_Handler ; SVCall Handler
|
||||
DCD DebugMon_Handler ; Debug Monitor Handler
|
||||
DCD 0 ; Reserved
|
||||
DCD PendSV_Handler ; PendSV Handler
|
||||
DCD SysTick_Handler ; SysTick Handler
|
||||
|
||||
; External Interrupts
|
||||
DCD WWDG_IRQHandler ; Window WatchDog
|
||||
DCD PVD_IRQHandler ; PVD through EXTI Line detection
|
||||
DCD TAMP_STAMP_IRQHandler ; Tamper and TimeStamps through the EXTI line
|
||||
DCD RTC_WKUP_IRQHandler ; RTC Wakeup through the EXTI line
|
||||
DCD FLASH_IRQHandler ; FLASH
|
||||
DCD RCC_IRQHandler ; RCC
|
||||
DCD EXTI0_IRQHandler ; EXTI Line0
|
||||
DCD EXTI1_IRQHandler ; EXTI Line1
|
||||
DCD EXTI2_IRQHandler ; EXTI Line2
|
||||
DCD EXTI3_IRQHandler ; EXTI Line3
|
||||
DCD EXTI4_IRQHandler ; EXTI Line4
|
||||
DCD DMA1_Stream0_IRQHandler ; DMA1 Stream 0
|
||||
DCD DMA1_Stream1_IRQHandler ; DMA1 Stream 1
|
||||
DCD DMA1_Stream2_IRQHandler ; DMA1 Stream 2
|
||||
DCD DMA1_Stream3_IRQHandler ; DMA1 Stream 3
|
||||
DCD DMA1_Stream4_IRQHandler ; DMA1 Stream 4
|
||||
DCD DMA1_Stream5_IRQHandler ; DMA1 Stream 5
|
||||
DCD DMA1_Stream6_IRQHandler ; DMA1 Stream 6
|
||||
DCD ADC_IRQHandler ; ADC1, ADC2 and ADC3s
|
||||
DCD CAN1_TX_IRQHandler ; CAN1 TX
|
||||
DCD CAN1_RX0_IRQHandler ; CAN1 RX0
|
||||
DCD CAN1_RX1_IRQHandler ; CAN1 RX1
|
||||
DCD CAN1_SCE_IRQHandler ; CAN1 SCE
|
||||
DCD EXTI9_5_IRQHandler ; External Line[9:5]s
|
||||
DCD TIM1_BRK_TIM9_IRQHandler ; TIM1 Break and TIM9
|
||||
DCD TIM1_UP_TIM10_IRQHandler ; TIM1 Update and TIM10
|
||||
DCD TIM1_TRG_COM_TIM11_IRQHandler ; TIM1 Trigger and Commutation and TIM11
|
||||
DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare
|
||||
DCD TIM2_IRQHandler ; TIM2
|
||||
DCD TIM3_IRQHandler ; TIM3
|
||||
DCD TIM4_IRQHandler ; TIM4
|
||||
DCD I2C1_EV_IRQHandler ; I2C1 Event
|
||||
DCD I2C1_ER_IRQHandler ; I2C1 Error
|
||||
DCD I2C2_EV_IRQHandler ; I2C2 Event
|
||||
DCD I2C2_ER_IRQHandler ; I2C2 Error
|
||||
DCD SPI1_IRQHandler ; SPI1
|
||||
DCD SPI2_IRQHandler ; SPI2
|
||||
DCD USART1_IRQHandler ; USART1
|
||||
DCD USART2_IRQHandler ; USART2
|
||||
DCD USART3_IRQHandler ; USART3
|
||||
DCD EXTI15_10_IRQHandler ; External Line[15:10]s
|
||||
DCD RTC_Alarm_IRQHandler ; RTC Alarm (A and B) through EXTI Line
|
||||
DCD OTG_FS_WKUP_IRQHandler ; USB OTG FS Wakeup through EXTI line
|
||||
DCD TIM8_BRK_TIM12_IRQHandler ; TIM8 Break and TIM12
|
||||
DCD TIM8_UP_TIM13_IRQHandler ; TIM8 Update and TIM13
|
||||
DCD TIM8_TRG_COM_TIM14_IRQHandler ; TIM8 Trigger and Commutation and TIM14
|
||||
DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare
|
||||
DCD DMA1_Stream7_IRQHandler ; DMA1 Stream7
|
||||
DCD FMC_IRQHandler ; FMC
|
||||
DCD SDIO_IRQHandler ; SDIO
|
||||
DCD TIM5_IRQHandler ; TIM5
|
||||
DCD SPI3_IRQHandler ; SPI3
|
||||
DCD UART4_IRQHandler ; UART4
|
||||
DCD UART5_IRQHandler ; UART5
|
||||
DCD TIM6_DAC_IRQHandler ; TIM6 and DAC1&2 underrun errors
|
||||
DCD TIM7_IRQHandler ; TIM7
|
||||
DCD DMA2_Stream0_IRQHandler ; DMA2 Stream 0
|
||||
DCD DMA2_Stream1_IRQHandler ; DMA2 Stream 1
|
||||
DCD DMA2_Stream2_IRQHandler ; DMA2 Stream 2
|
||||
DCD DMA2_Stream3_IRQHandler ; DMA2 Stream 3
|
||||
DCD DMA2_Stream4_IRQHandler ; DMA2 Stream 4
|
||||
DCD ETH_IRQHandler ; Ethernet
|
||||
DCD ETH_WKUP_IRQHandler ; Ethernet Wakeup through EXTI line
|
||||
DCD CAN2_TX_IRQHandler ; CAN2 TX
|
||||
DCD CAN2_RX0_IRQHandler ; CAN2 RX0
|
||||
DCD CAN2_RX1_IRQHandler ; CAN2 RX1
|
||||
DCD CAN2_SCE_IRQHandler ; CAN2 SCE
|
||||
DCD OTG_FS_IRQHandler ; USB OTG FS
|
||||
DCD DMA2_Stream5_IRQHandler ; DMA2 Stream 5
|
||||
DCD DMA2_Stream6_IRQHandler ; DMA2 Stream 6
|
||||
DCD DMA2_Stream7_IRQHandler ; DMA2 Stream 7
|
||||
DCD USART6_IRQHandler ; USART6
|
||||
DCD I2C3_EV_IRQHandler ; I2C3 event
|
||||
DCD I2C3_ER_IRQHandler ; I2C3 error
|
||||
DCD OTG_HS_EP1_OUT_IRQHandler ; USB OTG HS End Point 1 Out
|
||||
DCD OTG_HS_EP1_IN_IRQHandler ; USB OTG HS End Point 1 In
|
||||
DCD OTG_HS_WKUP_IRQHandler ; USB OTG HS Wakeup through EXTI
|
||||
DCD OTG_HS_IRQHandler ; USB OTG HS
|
||||
DCD DCMI_IRQHandler ; DCMI
|
||||
DCD CRYP_IRQHandler ; CRYPTO
|
||||
DCD HASH_RNG_IRQHandler ; Hash and Rng
|
||||
DCD FPU_IRQHandler ; FPU
|
||||
|
||||
|
||||
__Vectors_End
|
||||
|
||||
__Vectors_Size EQU __Vectors_End - __Vectors
|
||||
|
||||
AREA |.text|, CODE, READONLY
|
||||
|
||||
; Reset handler
|
||||
Reset_Handler PROC
|
||||
EXPORT Reset_Handler [WEAK]
|
||||
IMPORT SystemInit
|
||||
IMPORT __main
|
||||
|
||||
LDR R0, =SystemInit
|
||||
BLX R0
|
||||
LDR R0, =__main
|
||||
BX R0
|
||||
ENDP
|
||||
|
||||
; Dummy Exception Handlers (infinite loops which can be modified)
|
||||
|
||||
NMI_Handler PROC
|
||||
EXPORT NMI_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
HardFault_Handler\
|
||||
PROC
|
||||
EXPORT HardFault_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
MemManage_Handler\
|
||||
PROC
|
||||
EXPORT MemManage_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
BusFault_Handler\
|
||||
PROC
|
||||
EXPORT BusFault_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
UsageFault_Handler\
|
||||
PROC
|
||||
EXPORT UsageFault_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
SVC_Handler PROC
|
||||
EXPORT SVC_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
DebugMon_Handler\
|
||||
PROC
|
||||
EXPORT DebugMon_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
PendSV_Handler PROC
|
||||
EXPORT PendSV_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
SysTick_Handler PROC
|
||||
EXPORT SysTick_Handler [WEAK]
|
||||
B .
|
||||
ENDP
|
||||
|
||||
Default_Handler PROC
|
||||
|
||||
EXPORT WWDG_IRQHandler [WEAK]
|
||||
EXPORT PVD_IRQHandler [WEAK]
|
||||
EXPORT TAMP_STAMP_IRQHandler [WEAK]
|
||||
EXPORT RTC_WKUP_IRQHandler [WEAK]
|
||||
EXPORT FLASH_IRQHandler [WEAK]
|
||||
EXPORT RCC_IRQHandler [WEAK]
|
||||
EXPORT EXTI0_IRQHandler [WEAK]
|
||||
EXPORT EXTI1_IRQHandler [WEAK]
|
||||
EXPORT EXTI2_IRQHandler [WEAK]
|
||||
EXPORT EXTI3_IRQHandler [WEAK]
|
||||
EXPORT EXTI4_IRQHandler [WEAK]
|
||||
EXPORT DMA1_Stream0_IRQHandler [WEAK]
|
||||
EXPORT DMA1_Stream1_IRQHandler [WEAK]
|
||||
EXPORT DMA1_Stream2_IRQHandler [WEAK]
|
||||
EXPORT DMA1_Stream3_IRQHandler [WEAK]
|
||||
EXPORT DMA1_Stream4_IRQHandler [WEAK]
|
||||
EXPORT DMA1_Stream5_IRQHandler [WEAK]
|
||||
EXPORT DMA1_Stream6_IRQHandler [WEAK]
|
||||
EXPORT ADC_IRQHandler [WEAK]
|
||||
EXPORT CAN1_TX_IRQHandler [WEAK]
|
||||
EXPORT CAN1_RX0_IRQHandler [WEAK]
|
||||
EXPORT CAN1_RX1_IRQHandler [WEAK]
|
||||
EXPORT CAN1_SCE_IRQHandler [WEAK]
|
||||
EXPORT EXTI9_5_IRQHandler [WEAK]
|
||||
EXPORT TIM1_BRK_TIM9_IRQHandler [WEAK]
|
||||
EXPORT TIM1_UP_TIM10_IRQHandler [WEAK]
|
||||
EXPORT TIM1_TRG_COM_TIM11_IRQHandler [WEAK]
|
||||
EXPORT TIM1_CC_IRQHandler [WEAK]
|
||||
EXPORT TIM2_IRQHandler [WEAK]
|
||||
EXPORT TIM3_IRQHandler [WEAK]
|
||||
EXPORT TIM4_IRQHandler [WEAK]
|
||||
EXPORT I2C1_EV_IRQHandler [WEAK]
|
||||
EXPORT I2C1_ER_IRQHandler [WEAK]
|
||||
EXPORT I2C2_EV_IRQHandler [WEAK]
|
||||
EXPORT I2C2_ER_IRQHandler [WEAK]
|
||||
EXPORT SPI1_IRQHandler [WEAK]
|
||||
EXPORT SPI2_IRQHandler [WEAK]
|
||||
EXPORT USART1_IRQHandler [WEAK]
|
||||
EXPORT USART2_IRQHandler [WEAK]
|
||||
EXPORT USART3_IRQHandler [WEAK]
|
||||
EXPORT EXTI15_10_IRQHandler [WEAK]
|
||||
EXPORT RTC_Alarm_IRQHandler [WEAK]
|
||||
EXPORT OTG_FS_WKUP_IRQHandler [WEAK]
|
||||
EXPORT TIM8_BRK_TIM12_IRQHandler [WEAK]
|
||||
EXPORT TIM8_UP_TIM13_IRQHandler [WEAK]
|
||||
EXPORT TIM8_TRG_COM_TIM14_IRQHandler [WEAK]
|
||||
EXPORT TIM8_CC_IRQHandler [WEAK]
|
||||
EXPORT DMA1_Stream7_IRQHandler [WEAK]
|
||||
EXPORT FMC_IRQHandler [WEAK]
|
||||
EXPORT SDIO_IRQHandler [WEAK]
|
||||
EXPORT TIM5_IRQHandler [WEAK]
|
||||
EXPORT SPI3_IRQHandler [WEAK]
|
||||
EXPORT UART4_IRQHandler [WEAK]
|
||||
EXPORT UART5_IRQHandler [WEAK]
|
||||
EXPORT TIM6_DAC_IRQHandler [WEAK]
|
||||
EXPORT TIM7_IRQHandler [WEAK]
|
||||
EXPORT DMA2_Stream0_IRQHandler [WEAK]
|
||||
EXPORT DMA2_Stream1_IRQHandler [WEAK]
|
||||
EXPORT DMA2_Stream2_IRQHandler [WEAK]
|
||||
EXPORT DMA2_Stream3_IRQHandler [WEAK]
|
||||
EXPORT DMA2_Stream4_IRQHandler [WEAK]
|
||||
EXPORT ETH_IRQHandler [WEAK]
|
||||
EXPORT ETH_WKUP_IRQHandler [WEAK]
|
||||
EXPORT CAN2_TX_IRQHandler [WEAK]
|
||||
EXPORT CAN2_RX0_IRQHandler [WEAK]
|
||||
EXPORT CAN2_RX1_IRQHandler [WEAK]
|
||||
EXPORT CAN2_SCE_IRQHandler [WEAK]
|
||||
EXPORT OTG_FS_IRQHandler [WEAK]
|
||||
EXPORT DMA2_Stream5_IRQHandler [WEAK]
|
||||
EXPORT DMA2_Stream6_IRQHandler [WEAK]
|
||||
EXPORT DMA2_Stream7_IRQHandler [WEAK]
|
||||
EXPORT USART6_IRQHandler [WEAK]
|
||||
EXPORT I2C3_EV_IRQHandler [WEAK]
|
||||
EXPORT I2C3_ER_IRQHandler [WEAK]
|
||||
EXPORT OTG_HS_EP1_OUT_IRQHandler [WEAK]
|
||||
EXPORT OTG_HS_EP1_IN_IRQHandler [WEAK]
|
||||
EXPORT OTG_HS_WKUP_IRQHandler [WEAK]
|
||||
EXPORT OTG_HS_IRQHandler [WEAK]
|
||||
EXPORT DCMI_IRQHandler [WEAK]
|
||||
EXPORT CRYP_IRQHandler [WEAK]
|
||||
EXPORT HASH_RNG_IRQHandler [WEAK]
|
||||
EXPORT FPU_IRQHandler [WEAK]
|
||||
|
||||
WWDG_IRQHandler
|
||||
PVD_IRQHandler
|
||||
TAMP_STAMP_IRQHandler
|
||||
RTC_WKUP_IRQHandler
|
||||
FLASH_IRQHandler
|
||||
RCC_IRQHandler
|
||||
EXTI0_IRQHandler
|
||||
EXTI1_IRQHandler
|
||||
EXTI2_IRQHandler
|
||||
EXTI3_IRQHandler
|
||||
EXTI4_IRQHandler
|
||||
DMA1_Stream0_IRQHandler
|
||||
DMA1_Stream1_IRQHandler
|
||||
DMA1_Stream2_IRQHandler
|
||||
DMA1_Stream3_IRQHandler
|
||||
DMA1_Stream4_IRQHandler
|
||||
DMA1_Stream5_IRQHandler
|
||||
DMA1_Stream6_IRQHandler
|
||||
ADC_IRQHandler
|
||||
CAN1_TX_IRQHandler
|
||||
CAN1_RX0_IRQHandler
|
||||
CAN1_RX1_IRQHandler
|
||||
CAN1_SCE_IRQHandler
|
||||
EXTI9_5_IRQHandler
|
||||
TIM1_BRK_TIM9_IRQHandler
|
||||
TIM1_UP_TIM10_IRQHandler
|
||||
TIM1_TRG_COM_TIM11_IRQHandler
|
||||
TIM1_CC_IRQHandler
|
||||
TIM2_IRQHandler
|
||||
TIM3_IRQHandler
|
||||
TIM4_IRQHandler
|
||||
I2C1_EV_IRQHandler
|
||||
I2C1_ER_IRQHandler
|
||||
I2C2_EV_IRQHandler
|
||||
I2C2_ER_IRQHandler
|
||||
SPI1_IRQHandler
|
||||
SPI2_IRQHandler
|
||||
USART1_IRQHandler
|
||||
USART2_IRQHandler
|
||||
USART3_IRQHandler
|
||||
EXTI15_10_IRQHandler
|
||||
RTC_Alarm_IRQHandler
|
||||
OTG_FS_WKUP_IRQHandler
|
||||
TIM8_BRK_TIM12_IRQHandler
|
||||
TIM8_UP_TIM13_IRQHandler
|
||||
TIM8_TRG_COM_TIM14_IRQHandler
|
||||
TIM8_CC_IRQHandler
|
||||
DMA1_Stream7_IRQHandler
|
||||
FMC_IRQHandler
|
||||
SDIO_IRQHandler
|
||||
TIM5_IRQHandler
|
||||
SPI3_IRQHandler
|
||||
UART4_IRQHandler
|
||||
UART5_IRQHandler
|
||||
TIM6_DAC_IRQHandler
|
||||
TIM7_IRQHandler
|
||||
DMA2_Stream0_IRQHandler
|
||||
DMA2_Stream1_IRQHandler
|
||||
DMA2_Stream2_IRQHandler
|
||||
DMA2_Stream3_IRQHandler
|
||||
DMA2_Stream4_IRQHandler
|
||||
ETH_IRQHandler
|
||||
ETH_WKUP_IRQHandler
|
||||
CAN2_TX_IRQHandler
|
||||
CAN2_RX0_IRQHandler
|
||||
CAN2_RX1_IRQHandler
|
||||
CAN2_SCE_IRQHandler
|
||||
OTG_FS_IRQHandler
|
||||
DMA2_Stream5_IRQHandler
|
||||
DMA2_Stream6_IRQHandler
|
||||
DMA2_Stream7_IRQHandler
|
||||
USART6_IRQHandler
|
||||
I2C3_EV_IRQHandler
|
||||
I2C3_ER_IRQHandler
|
||||
OTG_HS_EP1_OUT_IRQHandler
|
||||
OTG_HS_EP1_IN_IRQHandler
|
||||
OTG_HS_WKUP_IRQHandler
|
||||
OTG_HS_IRQHandler
|
||||
DCMI_IRQHandler
|
||||
CRYP_IRQHandler
|
||||
HASH_RNG_IRQHandler
|
||||
FPU_IRQHandler
|
||||
|
||||
B .
|
||||
|
||||
ENDP
|
||||
|
||||
ALIGN
|
||||
|
||||
;*******************************************************************************
|
||||
; User Stack and Heap initialization
|
||||
;*******************************************************************************
|
||||
IF :DEF:__MICROLIB
|
||||
|
||||
EXPORT __initial_sp
|
||||
EXPORT __heap_base
|
||||
EXPORT __heap_limit
|
||||
|
||||
ELSE
|
||||
|
||||
IMPORT __use_two_region_memory
|
||||
EXPORT __user_initial_stackheap
|
||||
|
||||
__user_initial_stackheap
|
||||
|
||||
LDR R0, = Heap_Mem
|
||||
LDR R1, =(Stack_Mem + Stack_Size)
|
||||
LDR R2, = (Heap_Mem + Heap_Size)
|
||||
LDR R3, = Stack_Mem
|
||||
BX LR
|
||||
|
||||
ALIGN
|
||||
|
||||
ENDIF
|
||||
|
||||
END
|
||||
185
UPP/UPP.ioc
185
UPP/UPP.ioc
@@ -5,9 +5,10 @@ ADC3.Channel-17\#ChannelRegularConversion=ADC_CHANNEL_6
|
||||
ADC3.Channel-18\#ChannelRegularConversion=ADC_CHANNEL_7
|
||||
ADC3.Channel-19\#ChannelRegularConversion=ADC_CHANNEL_8
|
||||
ADC3.Channel-20\#ChannelRegularConversion=ADC_CHANNEL_10
|
||||
ADC3.DMAContinuousRequests=ENABLE
|
||||
ADC3.EOCSelection=ADC_EOC_SEQ_CONV
|
||||
ADC3.ExternalTrigConv=ADC_EXTERNALTRIGCONV_T8_TRGO
|
||||
ADC3.IPParameters=Rank-15\#ChannelRegularConversion,Channel-15\#ChannelRegularConversion,SamplingTime-15\#ChannelRegularConversion,NbrOfConversionFlag,NbrOfConversion,ScanConvMode,Rank-16\#ChannelRegularConversion,Channel-16\#ChannelRegularConversion,SamplingTime-16\#ChannelRegularConversion,Rank-17\#ChannelRegularConversion,Channel-17\#ChannelRegularConversion,SamplingTime-17\#ChannelRegularConversion,Rank-18\#ChannelRegularConversion,Channel-18\#ChannelRegularConversion,SamplingTime-18\#ChannelRegularConversion,Rank-19\#ChannelRegularConversion,Channel-19\#ChannelRegularConversion,SamplingTime-19\#ChannelRegularConversion,Rank-20\#ChannelRegularConversion,Channel-20\#ChannelRegularConversion,SamplingTime-20\#ChannelRegularConversion,ExternalTrigConv,EOCSelection
|
||||
ADC3.ExternalTrigConv=ADC_EXTERNALTRIGCONV_T3_TRGO
|
||||
ADC3.IPParameters=Rank-15\#ChannelRegularConversion,Channel-15\#ChannelRegularConversion,SamplingTime-15\#ChannelRegularConversion,NbrOfConversionFlag,NbrOfConversion,ScanConvMode,Rank-16\#ChannelRegularConversion,Channel-16\#ChannelRegularConversion,SamplingTime-16\#ChannelRegularConversion,Rank-17\#ChannelRegularConversion,Channel-17\#ChannelRegularConversion,SamplingTime-17\#ChannelRegularConversion,Rank-18\#ChannelRegularConversion,Channel-18\#ChannelRegularConversion,SamplingTime-18\#ChannelRegularConversion,Rank-19\#ChannelRegularConversion,Channel-19\#ChannelRegularConversion,SamplingTime-19\#ChannelRegularConversion,Rank-20\#ChannelRegularConversion,Channel-20\#ChannelRegularConversion,SamplingTime-20\#ChannelRegularConversion,ExternalTrigConv,EOCSelection,DMAContinuousRequests
|
||||
ADC3.NbrOfConversion=6
|
||||
ADC3.NbrOfConversionFlag=1
|
||||
ADC3.Rank-15\#ChannelRegularConversion=1
|
||||
@@ -38,7 +39,7 @@ Dma.ADC3.0.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.ADC3.0.Instance=DMA2_Stream0
|
||||
Dma.ADC3.0.MemDataAlignment=DMA_MDATAALIGN_HALFWORD
|
||||
Dma.ADC3.0.MemInc=DMA_MINC_ENABLE
|
||||
Dma.ADC3.0.Mode=DMA_NORMAL
|
||||
Dma.ADC3.0.Mode=DMA_CIRCULAR
|
||||
Dma.ADC3.0.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD
|
||||
Dma.ADC3.0.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.ADC3.0.Priority=DMA_PRIORITY_LOW
|
||||
@@ -81,64 +82,64 @@ Mcu.Pin12=PF10
|
||||
Mcu.Pin13=PH0/OSC_IN
|
||||
Mcu.Pin14=PH1/OSC_OUT
|
||||
Mcu.Pin15=PC0
|
||||
Mcu.Pin16=PA0/WKUP
|
||||
Mcu.Pin17=PA4
|
||||
Mcu.Pin18=PA5
|
||||
Mcu.Pin19=PA6
|
||||
Mcu.Pin16=PA4
|
||||
Mcu.Pin17=PA5
|
||||
Mcu.Pin18=PA6
|
||||
Mcu.Pin19=PB0
|
||||
Mcu.Pin2=PE4
|
||||
Mcu.Pin20=PB0
|
||||
Mcu.Pin21=PB1
|
||||
Mcu.Pin22=PF11
|
||||
Mcu.Pin23=PB10
|
||||
Mcu.Pin24=PB11
|
||||
Mcu.Pin25=PB13
|
||||
Mcu.Pin26=PG6
|
||||
Mcu.Pin27=PC6
|
||||
Mcu.Pin28=PC7
|
||||
Mcu.Pin29=PC8
|
||||
Mcu.Pin20=PB1
|
||||
Mcu.Pin21=PF11
|
||||
Mcu.Pin22=PB10
|
||||
Mcu.Pin23=PB11
|
||||
Mcu.Pin24=PB13
|
||||
Mcu.Pin25=PG6
|
||||
Mcu.Pin26=PC6
|
||||
Mcu.Pin27=PC7
|
||||
Mcu.Pin28=PC8
|
||||
Mcu.Pin29=PC9
|
||||
Mcu.Pin3=PE5
|
||||
Mcu.Pin30=PC9
|
||||
Mcu.Pin31=PA8
|
||||
Mcu.Pin32=PA9
|
||||
Mcu.Pin33=PA10
|
||||
Mcu.Pin34=PA11
|
||||
Mcu.Pin35=PA12
|
||||
Mcu.Pin36=PA13
|
||||
Mcu.Pin37=PA14
|
||||
Mcu.Pin38=PA15
|
||||
Mcu.Pin39=PC10
|
||||
Mcu.Pin30=PA8
|
||||
Mcu.Pin31=PA9
|
||||
Mcu.Pin32=PA10
|
||||
Mcu.Pin33=PA11
|
||||
Mcu.Pin34=PA12
|
||||
Mcu.Pin35=PA13
|
||||
Mcu.Pin36=PA14
|
||||
Mcu.Pin37=PA15
|
||||
Mcu.Pin38=PC10
|
||||
Mcu.Pin39=PC11
|
||||
Mcu.Pin4=PE6
|
||||
Mcu.Pin40=PC11
|
||||
Mcu.Pin41=PC12
|
||||
Mcu.Pin42=PD2
|
||||
Mcu.Pin43=PD3
|
||||
Mcu.Pin44=PD6
|
||||
Mcu.Pin45=PG12
|
||||
Mcu.Pin46=PG15
|
||||
Mcu.Pin47=PB3
|
||||
Mcu.Pin48=PB6
|
||||
Mcu.Pin49=PB7
|
||||
Mcu.Pin40=PC12
|
||||
Mcu.Pin41=PD2
|
||||
Mcu.Pin42=PD3
|
||||
Mcu.Pin43=PD6
|
||||
Mcu.Pin44=PG12
|
||||
Mcu.Pin45=PG15
|
||||
Mcu.Pin46=PB3
|
||||
Mcu.Pin47=PB6
|
||||
Mcu.Pin48=PB7
|
||||
Mcu.Pin49=PB8
|
||||
Mcu.Pin5=PC13
|
||||
Mcu.Pin50=PB8
|
||||
Mcu.Pin51=PB9
|
||||
Mcu.Pin52=PE0
|
||||
Mcu.Pin53=PE1
|
||||
Mcu.Pin54=VP_IWDG_VS_IWDG
|
||||
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_TIM1_VS_OPM
|
||||
Mcu.Pin50=PB9
|
||||
Mcu.Pin51=PE0
|
||||
Mcu.Pin52=PE1
|
||||
Mcu.Pin53=VP_IWDG_VS_IWDG
|
||||
Mcu.Pin54=VP_RTC_VS_RTC_Activate
|
||||
Mcu.Pin55=VP_RTC_VS_RTC_Calendar
|
||||
Mcu.Pin56=VP_SYS_VS_tim14
|
||||
Mcu.Pin57=VP_TIM1_VS_ClockSourceINT
|
||||
Mcu.Pin58=VP_TIM1_VS_OPM
|
||||
Mcu.Pin59=VP_TIM2_VS_ClockSourceINT
|
||||
Mcu.Pin6=PC14/OSC32_IN
|
||||
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.Pin60=VP_TIM2_VS_no_output1
|
||||
Mcu.Pin61=VP_TIM2_VS_no_output2
|
||||
Mcu.Pin62=VP_TIM2_VS_no_output3
|
||||
Mcu.Pin63=VP_TIM3_VS_ClockSourceINT
|
||||
Mcu.Pin64=VP_TIM5_VS_ClockSourceINT
|
||||
Mcu.Pin65=VP_TIM8_VS_ControllerModeTrigger
|
||||
Mcu.Pin66=VP_TIM8_VS_ClockSourceINT
|
||||
Mcu.Pin67=VP_TIM8_VS_ClockSourceITR
|
||||
Mcu.Pin68=VP_TIM8_VS_OPM
|
||||
Mcu.Pin69=VP_TIM11_VS_ClockSourceINT
|
||||
Mcu.Pin7=PC15/OSC32_OUT
|
||||
Mcu.Pin70=VP_TIM12_VS_ClockSourceINT
|
||||
@@ -146,7 +147,7 @@ Mcu.Pin8=PF6
|
||||
Mcu.Pin9=PF7
|
||||
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;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.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
|
||||
MxCube.Version=6.12.1
|
||||
MxDb.Version=DB.6.0.121
|
||||
@@ -164,10 +165,10 @@ 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.TIM8_UP_TIM13_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true
|
||||
NVIC.TimeBase=TIM8_TRG_COM_TIM14_IRQn
|
||||
NVIC.TimeBaseIP=TIM14
|
||||
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false
|
||||
PA0/WKUP.Signal=S_TIM5_CH1
|
||||
PA10.GPIOParameters=GPIO_Label
|
||||
PA10.GPIO_Label=PWM3
|
||||
PA10.Locked=true
|
||||
@@ -193,7 +194,7 @@ PA4.Signal=GPIO_Output
|
||||
PA5.GPIOParameters=PinState,GPIO_Label
|
||||
PA5.GPIO_Label=DO4
|
||||
PA5.Locked=true
|
||||
PA5.PinState=GPIO_PIN_SET
|
||||
PA5.PinState=GPIO_PIN_RESET
|
||||
PA5.Signal=GPIO_Output
|
||||
PA6.GPIOParameters=PinState,GPIO_Label
|
||||
PA6.GPIO_Label=RDO4
|
||||
@@ -263,10 +264,9 @@ PC12.GPIOParameters=GPIO_Label
|
||||
PC12.GPIO_Label=UM_SPI_MOSI
|
||||
PC12.Mode=Full_Duplex_Master
|
||||
PC12.Signal=SPI3_MOSI
|
||||
PC13.GPIOParameters=PinState,GPIO_Label
|
||||
PC13.GPIOParameters=GPIO_Label
|
||||
PC13.GPIO_Label=DO3
|
||||
PC13.Locked=true
|
||||
PC13.PinState=GPIO_PIN_SET
|
||||
PC13.Signal=GPIO_Output
|
||||
PC14/OSC32_IN.Mode=LSE-External-Oscillator
|
||||
PC14/OSC32_IN.Signal=RCC_OSC32_IN
|
||||
@@ -278,16 +278,15 @@ PC6.Mode=Asynchronous
|
||||
PC6.Signal=USART6_TX
|
||||
PC7.GPIOParameters=GPIO_Label
|
||||
PC7.GPIO_Label=SCIR2
|
||||
PC7.Locked=true
|
||||
PC7.Mode=Asynchronous
|
||||
PC7.Signal=USART6_RX
|
||||
PC8.GPIOParameters=GPIO_Label
|
||||
PC8.GPIO_Label=PWM5
|
||||
PC8.Locked=true
|
||||
PC8.Signal=S_TIM3_CH3
|
||||
PC8.Signal=S_TIM8_CH3
|
||||
PC9.GPIOParameters=GPIO_Label
|
||||
PC9.GPIO_Label=PWM6
|
||||
PC9.Locked=true
|
||||
PC9.Signal=S_TIM3_CH4
|
||||
PC9.Signal=S_TIM8_CH4
|
||||
PD2.GPIOParameters=GPIO_Label
|
||||
PD2.GPIO_Label=DIN3
|
||||
PD2.Locked=true
|
||||
@@ -317,7 +316,7 @@ PE2.Locked=true
|
||||
PE2.PinState=GPIO_PIN_SET
|
||||
PE2.Signal=GPIO_Output
|
||||
PE3.GPIOParameters=PinState,GPIO_Label
|
||||
PE3.GPIO_Label=CEN_O
|
||||
PE3.GPIO_Label=CEN
|
||||
PE3.Locked=true
|
||||
PE3.PinState=GPIO_PIN_SET
|
||||
PE3.Signal=GPIO_Output
|
||||
@@ -362,8 +361,9 @@ PG12.GPIOParameters=GPIO_Label
|
||||
PG12.GPIO_Label=ERR_24V
|
||||
PG12.Locked=true
|
||||
PG12.Signal=GPIO_Input
|
||||
PG15.GPIOParameters=GPIO_Label
|
||||
PG15.GPIOParameters=GPIO_PuPd,GPIO_Label
|
||||
PG15.GPIO_Label=DIN1
|
||||
PG15.GPIO_PuPd=GPIO_PULLUP
|
||||
PG15.Locked=true
|
||||
PG15.Signal=GPIO_Input
|
||||
PG6.GPIOParameters=GPIO_PuPd,GPIO_Label
|
||||
@@ -406,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_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
|
||||
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-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-true-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,24 +461,22 @@ SH.S_TIM1_CH3.0=TIM1_CH3,PWM Generation3 CH3
|
||||
SH.S_TIM1_CH3.ConfNb=1
|
||||
SH.S_TIM1_CH4.0=TIM1_CH4,PWM Generation4 CH4
|
||||
SH.S_TIM1_CH4.ConfNb=1
|
||||
SH.S_TIM3_CH3.0=TIM3_CH3,PWM Generation3 CH3
|
||||
SH.S_TIM3_CH3.ConfNb=1
|
||||
SH.S_TIM3_CH4.0=TIM3_CH4,PWM Generation4 CH4
|
||||
SH.S_TIM3_CH4.ConfNb=1
|
||||
SH.S_TIM5_CH1.0=TIM5_CH1,Input_Capture1_from_TI1
|
||||
SH.S_TIM5_CH1.ConfNb=1
|
||||
SH.S_TIM8_CH3.0=TIM8_CH3,PWM Generation3 CH3
|
||||
SH.S_TIM8_CH3.ConfNb=1
|
||||
SH.S_TIM8_CH4.0=TIM8_CH4,PWM Generation4 CH4
|
||||
SH.S_TIM8_CH4.ConfNb=1
|
||||
SPI3.CalculateBaudRate=22.5 MBits/s
|
||||
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=Prescaler,Channel-Output Compare2 CH2,Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation4 CH4,Channel-PWM Generation3 CH3,TIM_MasterOutputTrigger
|
||||
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.RepetitionCounter=0
|
||||
TIM1.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE
|
||||
TIM11.IPParameters=Prescaler
|
||||
TIM11.Prescaler=180-1
|
||||
@@ -491,18 +489,19 @@ TIM2.IPParameters=Channel-Output Compare2 No Output,Channel-Output Compare1 No O
|
||||
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,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
|
||||
TIM3.IPParameters=TIM_MasterSlaveMode,TIM_MasterOutputTrigger
|
||||
TIM3.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE
|
||||
TIM3.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE
|
||||
TIM5.IPParameters=Prescaler
|
||||
TIM5.Prescaler=90-1
|
||||
TIM8.IPParameters=Prescaler,Period,TIM_MasterSlaveMode,TIM_MasterOutputTrigger
|
||||
TIM8.Period=1800-1
|
||||
TIM8.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
||||
TIM8.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
|
||||
TIM8.IPParameters=Prescaler,Period,TIM_MasterSlaveMode,TIM_MasterOutputTrigger,Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4,OC4Preload_PWM,RepetitionCounter
|
||||
TIM8.OC4Preload_PWM=ENABLE
|
||||
TIM8.Period=65535
|
||||
TIM8.Prescaler=0
|
||||
TIM8.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE
|
||||
TIM8.RepetitionCounter=0
|
||||
TIM8.TIM_MasterOutputTrigger=TIM_TRGO_RESET
|
||||
TIM8.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE
|
||||
USART3.IPParameters=VirtualMode
|
||||
USART3.VirtualMode=VM_ASYNC
|
||||
@@ -534,12 +533,14 @@ 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_TIM5_VS_ClockSourceINT.Mode=Internal
|
||||
VP_TIM5_VS_ClockSourceINT.Signal=TIM5_VS_ClockSourceINT
|
||||
VP_TIM8_VS_ClockSourceINT.Mode=Internal
|
||||
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.Signal=TIM8_VS_OPM
|
||||
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;
|
||||
|
||||
%% Параметры моделирования
|
||||
Fs = 100000; % Частота дискретизации [Гц]
|
||||
Fs = 1/25e-6; % Частота дискретизации [Гц]
|
||||
T = 0.5; % Время моделирования [с]
|
||||
t = 0:1/Fs:T-1/Fs; % Временной вектор
|
||||
N = length(t); % Количество отсчетов
|
||||
Fsrez = 50;
|
||||
|
||||
%% Уровни шума для разных каналов
|
||||
noise_levels.voltage = 0.2; % 2% шума для напряжений
|
||||
@@ -17,28 +18,28 @@ fprintf('=== АВТОМАТИЧЕСКИЙ РАСЧЕТ КОЭФФИЦИЕНТО
|
||||
|
||||
% 1. Полосовой фильтр 45-55 Гц для напряжений
|
||||
% [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');
|
||||
BiquadFilterDesigner.generate_c_code(coeffs_bpf, 'voltage_bpf');
|
||||
|
||||
% 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');
|
||||
BiquadFilterDesigner.generate_c_code(coeffs_lpf_current, 'current_lpf');
|
||||
|
||||
% 3. ФНЧ 10 Гц для температур
|
||||
[b_lpf_temp, a_lpf_temp, coeffs_lpf_temp] = BiquadFilterDesigner.lpf(10, Fs);
|
||||
fprintf('3. ФНЧ 10 Гц (температуры):\n');
|
||||
BiquadFilterDesigner.generate_c_code(coeffs_lpf_temp, 'temperature_lpf');
|
||||
%
|
||||
% % 3. ФНЧ 10 Гц для температур
|
||||
% [b_lpf_temp, a_lpf_temp, coeffs_lpf_temp] = BiquadFilterDesigner.lpf(10, Fs);
|
||||
% fprintf('3. ФНЧ 10 Гц (температуры):\n');
|
||||
% BiquadFilterDesigner.generate_c_code(coeffs_lpf_temp, 'temperature_lpf');
|
||||
|
||||
% Вывод коэффициентов в консоль
|
||||
fprintf('\n=== РАСЧЕТНЫЕ КОЭФФИЦИЕНТЫ ===\n');
|
||||
fprintf('Напряжение (BPF 45-55 Гц): b = [%.6f, %.6f, %.6f], a = [1, %.6f, %.6f]\n', ...
|
||||
b_bpf, a_bpf(2), a_bpf(3));
|
||||
fprintf('Ток (LPF 100 Гц): b = [%.6f, %.6f, %.6f], a = [1, %.6f, %.6f]\n', ...
|
||||
b_lpf_current, a_lpf_current(2), a_lpf_current(3));
|
||||
fprintf('Температура (LPF 10 Гц): b = [%.6f, %.6f, %.6f], a = [1, %.6f, %.6f]\n\n', ...
|
||||
b_lpf_temp, a_lpf_temp(2), a_lpf_temp(3));
|
||||
% fprintf('Ток (LPF 100 Гц): b = [%.6f, %.6f, %.6f], a = [1, %.6f, %.6f]\n', ...
|
||||
% b_lpf_current, a_lpf_current(2), a_lpf_current(3));
|
||||
% fprintf('Температура (LPF 10 Гц): b = [%.6f, %.6f, %.6f], a = [1, %.6f, %.6f]\n\n', ...
|
||||
% 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); %.* ...
|
||||
%(1 + 0.2 * sin(2*pi*2*t)); % амплитудная модуляция 2 Гц
|
||||
|
||||
% 3. Температура (медленно меняющийся сигнал)
|
||||
temperature_clean = 25 + 2 * sin(2*pi*0.1*t) + ... % медленные колебания 0.1 Гц
|
||||
0.5 * sin(2*pi*1*t); % быстрые колебания 1 Гц
|
||||
% % 3. Температура (медленно меняющийся сигнал)
|
||||
% temperature_clean = 25 + 2 * sin(2*pi*0.1*t) + ... % медленные колебания 0.1 Гц
|
||||
% 0.5 * sin(2*pi*1*t); % быстрые колебания 1 Гц
|
||||
|
||||
%% Добавление шума
|
||||
voltage_noisy = voltage_clean + noise_levels.voltage * 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);
|
||||
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)
|
||||
% Получаем АЧХ для нормализации
|
||||
[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_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));
|
||||
@@ -85,11 +86,11 @@ gain_lpf_current = sum(b_lpf_current) / (1 + sum(a_lpf_current(2:end)));
|
||||
if gain_lpf_current > 0
|
||||
current_filtered = current_filtered / gain_lpf_current;
|
||||
end
|
||||
|
||||
gain_lpf_temp = sum(b_lpf_temp) / (1 + sum(a_lpf_temp(2:end)));
|
||||
if gain_lpf_temp > 0
|
||||
temperature_filtered = temperature_filtered / gain_lpf_temp;
|
||||
end
|
||||
%
|
||||
% gain_lpf_temp = sum(b_lpf_temp) / (1 + sum(a_lpf_temp(2:end)));
|
||||
% if gain_lpf_temp > 0
|
||||
% temperature_filtered = temperature_filtered / gain_lpf_temp;
|
||||
% end
|
||||
|
||||
%% ОКНО 1: НАПРЯЖЕНИЕ
|
||||
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);
|
||||
title('Статистика фильтрации тока');
|
||||
axis off;
|
||||
|
||||
%% ОКНО 3: ТЕМПЕРАТУРА
|
||||
figure('Name', 'Анализ температуры');
|
||||
|
||||
% Временные характеристики
|
||||
subplot(2,3,1);
|
||||
plot(t, temperature_noisy, 'b', 'LineWidth', 1); hold on;
|
||||
plot(t, temperature_filtered, 'r', 'LineWidth', 2);
|
||||
plot(t, temperature_clean, 'g--', 'LineWidth', 1);
|
||||
title('Температура: временная область');
|
||||
legend('С шумом', 'Фильтрованный', 'Идеальный', 'Location', 'best');
|
||||
xlabel('Время [с]'); ylabel('Температура [°C]');
|
||||
grid on;
|
||||
|
||||
% АЧХ фильтра
|
||||
subplot(2,3,2);
|
||||
plot(f_lpf_temp, 20*log10(abs(h_lpf_temp)), 'LineWidth', 2);
|
||||
title('АЧХ: ФНЧ 10 Гц');
|
||||
xlabel('Частота [Гц]'); ylabel('Усиление [дБ]');
|
||||
grid on; xlim([0, 20]);
|
||||
|
||||
% Спектр фильтрованного сигнала
|
||||
subplot(2,3,3);
|
||||
[P_temp, f_temp] = pwelch(temperature_filtered, [], [], 1024, Fs);
|
||||
plot(f_temp, 10*log10(P_temp), 'LineWidth', 2);
|
||||
title('Спектр фильтрованной температуры');
|
||||
xlabel('Частота [Гц]'); ylabel('Мощность [дБ]');
|
||||
grid on; xlim([0, 10]);
|
||||
|
||||
% Групповая задержка
|
||||
subplot(2,3,4);
|
||||
[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);
|
||||
title('Групповая задержка фильтра');
|
||||
xlabel('Частота [Гц]'); ylabel('Задержка [мс]');
|
||||
grid on; xlim([0, 20]);
|
||||
|
||||
% Детальный вид (последне 0.1 секунды)
|
||||
idx_end_temp = max(1, length(t) - 0.1*Fs + 1):length(t); % последние 100 мс
|
||||
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_filtered(idx_end_temp), 'r', 'LineWidth', 2);
|
||||
plot(t(idx_end_temp), temperature_clean(idx_end_temp), 'g--', 'LineWidth', 2);
|
||||
title('Температура: УВЕЛИЧЕННЫЙ ВИД (900-1000 мс)');
|
||||
legend('С шумом', 'Фильтрованный', 'Идеальный', 'Location', 'best');
|
||||
xlabel('Время [с]'); ylabel('Температура [°C]');
|
||||
grid on;
|
||||
xlim([t(idx_end_temp(1)) t(idx_end_temp(end))]);
|
||||
|
||||
% Статистика
|
||||
subplot(2,3,6);
|
||||
snr_temp_in = snr(temperature_clean, temperature_noisy - temperature_clean);
|
||||
snr_temp_out = snr(temperature_clean, temperature_filtered - temperature_clean);
|
||||
improvement_temp = snr_temp_out - snr_temp_in;
|
||||
|
||||
[~, 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.6, sprintf('SNR выход: %.1f дБ', snr_temp_out), '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);
|
||||
title('Статистика фильтрации температуры');
|
||||
axis off;
|
||||
%
|
||||
% %% ОКНО 3: ТЕМПЕРАТУРА
|
||||
% figure('Name', 'Анализ температуры');
|
||||
%
|
||||
% % Временные характеристики
|
||||
% subplot(2,3,1);
|
||||
% plot(t, temperature_noisy, 'b', 'LineWidth', 1); hold on;
|
||||
% plot(t, temperature_filtered, 'r', 'LineWidth', 2);
|
||||
% plot(t, temperature_clean, 'g--', 'LineWidth', 1);
|
||||
% title('Температура: временная область');
|
||||
% legend('С шумом', 'Фильтрованный', 'Идеальный', 'Location', 'best');
|
||||
% xlabel('Время [с]'); ylabel('Температура [°C]');
|
||||
% grid on;
|
||||
%
|
||||
% % АЧХ фильтра
|
||||
% subplot(2,3,2);
|
||||
% plot(f_lpf_temp, 20*log10(abs(h_lpf_temp)), 'LineWidth', 2);
|
||||
% title('АЧХ: ФНЧ 10 Гц');
|
||||
% xlabel('Частота [Гц]'); ylabel('Усиление [дБ]');
|
||||
% grid on; xlim([0, 20]);
|
||||
%
|
||||
% % Спектр фильтрованного сигнала
|
||||
% subplot(2,3,3);
|
||||
% [P_temp, f_temp] = pwelch(temperature_filtered, [], [], 1024, Fs);
|
||||
% plot(f_temp, 10*log10(P_temp), 'LineWidth', 2);
|
||||
% title('Спектр фильтрованной температуры');
|
||||
% xlabel('Частота [Гц]'); ylabel('Мощность [дБ]');
|
||||
% grid on; xlim([0, 10]);
|
||||
%
|
||||
% % Групповая задержка
|
||||
% subplot(2,3,4);
|
||||
% [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);
|
||||
% title('Групповая задержка фильтра');
|
||||
% xlabel('Частота [Гц]'); ylabel('Задержка [мс]');
|
||||
% grid on; xlim([0, 20]);
|
||||
%
|
||||
% % Детальный вид (последне 0.1 секунды)
|
||||
% idx_end_temp = max(1, length(t) - 0.1*Fs + 1):length(t); % последние 100 мс
|
||||
% 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_filtered(idx_end_temp), 'r', 'LineWidth', 2);
|
||||
% plot(t(idx_end_temp), temperature_clean(idx_end_temp), 'g--', 'LineWidth', 2);
|
||||
% title('Температура: УВЕЛИЧЕННЫЙ ВИД (900-1000 мс)');
|
||||
% legend('С шумом', 'Фильтрованный', 'Идеальный', 'Location', 'best');
|
||||
% xlabel('Время [с]'); ylabel('Температура [°C]');
|
||||
% grid on;
|
||||
% xlim([t(idx_end_temp(1)) t(idx_end_temp(end))]);
|
||||
%
|
||||
% % Статистика
|
||||
% subplot(2,3,6);
|
||||
% snr_temp_in = snr(temperature_clean, temperature_noisy - temperature_clean);
|
||||
% snr_temp_out = snr(temperature_clean, temperature_filtered - temperature_clean);
|
||||
% improvement_temp = snr_temp_out - snr_temp_in;
|
||||
%
|
||||
% [~, 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.6, sprintf('SNR выход: %.1f дБ', snr_temp_out), '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);
|
||||
% title('Статистика фильтрации температуры');
|
||||
% axis off;
|
||||
|
||||
%% Вывод результатов в командное окно
|
||||
fprintf('\n=== ИТОГИ ФИЛЬТРАЦИИ С АВТОРАСЧЕТОМ КОЭФФИЦИЕНТОВ ===\n\n');
|
||||
@@ -288,7 +289,7 @@ fprintf(' SNR вход: %.1f дБ, выход: %.1f дБ, улучшение: %
|
||||
snr_current_in, snr_current_out, improvement_current);
|
||||
fprintf(' Задержка на 50 Гц: %.1f мс\n\n', gd_lpf_curr(idx_50hz_curr)/Fs*1000);
|
||||
|
||||
fprintf('ТЕМПЕРАТУРА (ФНЧ 10 Гц):\n');
|
||||
fprintf(' SNR вход: %.1f дБ, выход: %.1f дБ, улучшение: %.1f дБ\n', ...
|
||||
snr_temp_in, snr_temp_out, improvement_temp);
|
||||
fprintf(' Задержка на 1 Гц: %.1f мс\n\n', gd_lpf_temp(idx_1hz)/Fs*1000);
|
||||
% fprintf('ТЕМПЕРАТУРА (ФНЧ 10 Гц):\n');
|
||||
% fprintf(' SNR вход: %.1f дБ, выход: %.1f дБ, улучшение: %.1f дБ\n', ...
|
||||
% snr_temp_in, snr_temp_out, improvement_temp);
|
||||
% 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');
|
||||
11
Информация для программиста (УПП СП СЭД)/CALC/untitled.m
Normal file
11
Информация для программиста (УПП СП СЭД)/CALC/untitled.m
Normal file
@@ -0,0 +1,11 @@
|
||||
clc
|
||||
clear all
|
||||
|
||||
|
||||
alpha = 0.01
|
||||
ts = 500;
|
||||
|
||||
tau = (ts/1000000) * (1-alpha)/alpha
|
||||
|
||||
|
||||
alpha2 = ts/1000000 / (ts/1000000 + tau )
|
||||
Binary file not shown.
Reference in New Issue
Block a user