Compare commits

...

36 Commits

Author SHA1 Message Date
Razvalyaev
7286f33709 некоторый рефакторинг 2025-12-30 14:50:50 +03:00
Razvalyaev
9b4ccd63b0 добавлена литра по тиристорным регуляторам 2025-12-08 09:33:42 +03:00
Razvalyaev
67be0b2304 коэфи пида вновь приведены к диапзаону 0-6.5535, коэф Ki сделан независимым от dt 2025-12-07 18:12:58 +03:00
Razvalyaev
9234b4508b Токи были странными из-за неправильного определения перехода через ноль и преждевременного открытия тиристоров. Добавлен полосовой фильтр на напряжения, чтобы коммутации тиристоров не смещали переход через ноль
А также:
- общий rms ток считается через сумму rms фаз, а не по векторам
- в установку угла добавлен аргумент коррекции - пока только смщеение между фазными и линейными. Фильтр практически не смещает, но еще посмотрим
- коэф пид приведены к диапзону 0-1
- ПИД надо еще донастраивать. не нравится пока как он работает

И еще не были проверены тайминги. Мб это не будет успевать рассчитываться)))
2025-12-06 18:14:56 +03:00
Razvalyaev
1690cdcb93 триггер режим у второго шим таймера 2025-12-06 07:51:00 +03:00
Razvalyaev
2703f7efda Рефакторинг и фиксы
Вроде сделал управление для трехфазной сети без нулевого провода. В матлабе запускается, но токи странные и регулятор не доделан нормально
2025-12-05 18:36:38 +03:00
Razvalyaev
aa59f84fb7 рефакторинг и вроде бы понял как надо управлять импульсами
надо доделать и проверить
2025-12-04 15:01:55 +03:00
Razvalyaev
c0eea077d9 чет еще попытался но безуспешно 2025-12-02 22:16:06 +03:00
Razvalyaev
2775e0a9b6 Добавлен True RMS фильтр и оптимизации 2025-12-02 18:40:47 +03:00
Razvalyaev
3750d579fa лимит угла теперь не сатурирует, а начинается отсчет от него
плюс всякое по матлаб
2025-12-02 16:26:23 +03:00
Razvalyaev
eb6979aa27 в матлаб всё как у улитовского но не работает... почему...
плюс кучи мелочи по программе
2025-12-01 18:44:24 +03:00
Razvalyaev
7d40322f1e и еще 2025-11-30 21:22:53 +03:00
Razvalyaev
0de4aad4ef рефакторинг to_float->u2f
и всякое декоративное по модели
2025-11-30 21:22:04 +03:00
Razvalyaev
854ea6f6c2 Улушения:
- логики дма (только по полному заполнению)
- фильтров
- расчетов действующих значений
- параметров (сатурация, сделан параметр время нарастания пуска Tnt, добавлен параметр скважность пачки импульсов)
2025-11-28 18:25:05 +03:00
Razvalyaev
5624468d09 изменения под старую плату УПП 2025-11-27 12:17:58 +03:00
Razvalyaev
c26319f832 минор фиксы 2025-11-24 19:01:13 +03:00
Razvalyaev
925bfbe01e Коэфы альфа в дефолтах проставлены чтобы были независимыми от частоты дискретизации и всякое другое 2025-11-21 18:49:57 +03:00
Razvalyaev
21379c6188 фикс сброса угла при инициализайии режима работы и по мелочи 2025-11-21 16:01:43 +03:00
Razvalyaev
f3965db204 Сделано чтобы софтварный режим пачки импульсов выбирался по одному дефайну 2025-11-21 10:23:45 +03:00
Razvalyaev
b21d72b728 моделирование чет непонятное 2025-11-21 00:30:07 +03:00
Razvalyaev
d918ffb860 ШИМ и контроль угла отлажене на 417 более менее
Оптимизированы конфиг дефайны - в мкс и мс, а не тиках
2025-11-20 19:14:21 +03:00
Razvalyaev
2b22c5b0eb TIM3 и TIM8 поменяты местами
плюс по мелочи:
- полряность каналов
- симуляция тока для отладки без тока на АЦП
- регулируемый запас на максимальнйы угол
2025-11-20 10:57:47 +03:00
Razvalyaev
0e950148c5 Добавлен фильтр на частоту сети
Исправлены баги

Кое как работает:
- с периодом АЦП 30 мкс
- с периодом while 600 мкс
2025-11-19 17:06:28 +03:00
Razvalyaev
5090ddfd48 Всякие оптимизации и переделки под отладку на 417
По основному алгу
- расчет частоты сети тепер по всему периоду, а не полупериоду
- добавлены новые параметры: сдвиг синуса от нуля и сдвиг между фазами
2025-11-19 15:29:42 +03:00
Razvalyaev
b61a11b4fe Куча всего
1.В Keil добавлен таргет для тестирования прошивки на STM32F417
2. Матлаб все еще не до конца понятно как имено построить модель чтобы токи не подлетали от малейшего открытия тиристоров
2025-11-19 02:19:30 +03:00
Razvalyaev
5d8dc1183b Ничего не понятно. При регулировании и плавном уменьшении угла ток в какой-то момент резко взлетает и все уходит в колебательный процесс. 2025-11-18 23:45:03 +03:00
Razvalyaev
e1d6f1139d чебля 2025-11-18 22:30:20 +03:00
Razvalyaev
297cf9802e Начата работа над модулем с дискретными входами/выходами 2025-11-18 19:04:29 +03:00
Razvalyaev
6882d6d014 Рефакторинг и доработки 2025-11-18 18:15:37 +03:00
Razvalyaev
edac877616 Была путаница с углом альфа.
Он пидом считается наоборот. 0 -  ничего не подает - 1 полностью открываем
2025-11-18 00:49:16 +03:00
Razvalyaev
b887114510 Чет делал систему управления углом и поломалось всё... Угол неправильно рассчитывается и не в то время включается тиристор 2025-11-17 18:55:21 +03:00
Razvalyaev
e69eb0c8c9 Структуризирован PowerMonitor: сделано разделение на быстрие и медленные обработки
- Быстрые делаются в прерывании и заполняют с fast Напряжениями/Токами
- Медленные делаются в main, с каким-то периодом и работают с slow и mean Напряжениями/Токами/Температурами
2025-11-17 12:38:50 +03:00
Razvalyaev
b236975f9b Какие-то тесты и построение алгоритма. Но ничего прям интересного 2025-11-17 01:38:12 +03:00
Razvalyaev
b0813fb7e8 Полноценно запустилось в матлаб корректно. УПП может плавно открывать тиристоры пачкой импульсов
Начата работа над управлением УПП по командам
2025-11-16 19:40:40 +03:00
Razvalyaev
bb5b9886d7 Работает
Была исправлена симуляция таймеров и его статус регситра
2025-11-16 11:32:32 +03:00
Razvalyaev
115be84ccd Типа запустилось, но все равно есть проблемы с расчетом угла 2025-11-16 00:13:13 +03:00
80 changed files with 7461 additions and 1216 deletions

2
.gitignore vendored
View File

@@ -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

View File

@@ -1,5 +1,9 @@
#include "mcu_wrapper_conf.h"
#ifdef ARM_MATH_LOOPUNROLL
#include "dsp/none.h"
#endif
#define _sqrtf(...) sqrtf(__VA_ARGS__)
#define __disable_irq()

View File

@@ -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.

View File

@@ -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.

View File

@@ -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);
}
/**

View File

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

View File

@@ -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);
}
}

View File

@@ -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
}

View File

@@ -13,37 +13,50 @@ 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
{
// обычный счет
case(TIM_SLAVEMODE_DISABLE):// NORMAL MODE counting
TIMx_Count(TIMx, TIMS);
Channels_Simulation(TIMx, TIMS); // CaptureCompare and PWM channels simulation
Write_TRGO(TIMx, TIMS);
break;
switch (TIMx->SMCR & TIM_SMCR_SMS) // TIMER MODE
{
// обычный счет
case(TIM_SLAVEMODE_DISABLE):// NORMAL MODE counting
TIMx_Count(TIMx, TIMS);
Channels_Simulation(TIMx, TIMS); // CaptureCompare and PWM channels simulation
Write_TRGO(TIMx, TIMS);
break;
// включение слейв таймера по ивенту
case(TIM_SLAVEMODE_TRIGGER): // SLAVE MODE: TRIGGER MODE
Slave_Mode_Check_Source(TIMx, TIMS);
TIMx_Count(TIMx, TIMS);
Channels_Simulation(TIMx, TIMS); // CaptureCompare and PWM channels simulation
Write_TRGO(TIMx, TIMS);
break;
}
// включение слейв таймера по ивенту
case(TIM_SLAVEMODE_TRIGGER): // SLAVE MODE: TRIGGER MODE
Slave_Mode_Check_Source(TIMx, TIMS);
TIMx_Count(TIMx, TIMS);
Channels_Simulation(TIMx, TIMS); // CaptureCompare and PWM channels simulation
Write_TRGO(TIMx, TIMS);
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,18 +70,40 @@ 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->RELOAD = TIMx->ARR; // RELOAD ARR
if (TIMS->tx_cnt > TIMx->ARR) // reset COUNTER
TIMS->tx_cnt -= TIMS->RELOAD + 1;
else if (TIMS->tx_cnt < 0)
TIMS->tx_cnt += TIMS->RELOAD + 1;
if (TIMS->tx_step > TIMS->RELOAD)
TIMS->tx_cnt = 0;
if (!(TIMx->CR1 & TIM_CR1_OPM)) // if no one pulse
{
TIMS->Updated = 1;
TIMS->RELOAD = TIMx->ARR; // RELOAD ARR
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++;
}
}
if (TIMS->tx_cnt > TIMx->ARR) // reset COUNTER
TIMS->tx_cnt -= TIMS->RELOAD+1;
else if (TIMS->tx_cnt < 0)
TIMS->tx_cnt += TIMS->RELOAD+1;
if(TIMS->tx_step > TIMS->RELOAD)
TIMS->tx_cnt = 0;
TIM_Call_IRQHandller(TIMx); // call HANDLER
}
}
}
@@ -131,14 +166,13 @@ void CC_PWM_Ch1_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
}
if (TIMx->DIER & TIM_IT_CC1)
{
TIMx->SR |= TIM_SR_CC1IF;
if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR1) && (TIMS->tx_cnt >= TIMx->CCR1))
{
TIM_Call_IRQHandller(TIMx);
TIMx->SR |= TIM_SR_CC1IF;
}
else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR1) && (TIMS->tx_cnt <= TIMx->CCR1))
{
TIM_Call_IRQHandller(TIMx);
TIMx->SR |= TIM_SR_CC1IF;
}
}
}
@@ -184,20 +218,19 @@ void CC_PWM_Ch2_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
}
if (TIMx->DIER & TIM_IT_CC2)
{
TIMx->SR |= TIM_SR_CC2IF;
if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR2) && (TIMS->tx_cnt >= TIMx->CCR2))
{
TIM_Call_IRQHandller(TIMx);
TIMx->SR |= TIM_SR_CC2IF;
}
else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR2) && (TIMS->tx_cnt <= TIMx->CCR2))
{
TIM_Call_IRQHandller(TIMx);
TIMx->SR |= TIM_SR_CC2IF;
}
}
}
void CC_PWM_Ch3_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{ // определяет режим канала
switch (TIMx->CCMR2 & TIM_CCMR1_OC1M)
switch (TIMx->CCMR2 & TIM_CCMR2_OC3M)
{
case (TIM_OCMODE_ACTIVE): // ACTIVE mode
if (abs(TIMx->CNT - TIMx->CCR3) < 2*TIMS->tx_step)
@@ -237,20 +270,19 @@ void CC_PWM_Ch3_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
}
if (TIMx->DIER & TIM_IT_CC3)
{
TIMx->SR |= TIM_SR_CC3IF;
if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR3) && (TIMS->tx_cnt >= TIMx->CCR3))
{
TIM_Call_IRQHandller(TIMx);
TIMx->SR |= TIM_SR_CC3IF;
}
else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR3) && (TIMS->tx_cnt <= TIMx->CCR3))
{
TIM_Call_IRQHandller(TIMx);
TIMx->SR |= TIM_SR_CC3IF;
}
}
}
void CC_PWM_Ch4_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
{ // определяет режим канала
switch (TIMx->CCMR1 & TIM_CCMR1_OC2M)
switch (TIMx->CCMR2 & TIM_CCMR2_OC4M)
{
case ((TIM_OCMODE_ACTIVE) << (TIM_OCMODE_SECOND_SHIFT)): // ACTIVE mode
if (abs(TIMx->CNT - TIMx->CCR4) < 2*TIMS->tx_step)
@@ -290,14 +322,13 @@ void CC_PWM_Ch4_Simulation(TIM_TypeDef *TIMx, struct TIM_Sim *TIMS)
}
if (TIMx->DIER & TIM_IT_CC4)
{
TIMx->SR |= TIM_SR_CC4IF;
if (((TIMS->tx_cnt - TIMS->tx_step) < TIMx->CCR4) && (TIMS->tx_cnt >= TIMx->CCR4))
{
TIM_Call_IRQHandller(TIMx);
TIMx->SR |= TIM_SR_CC4IF;
}
else if (((TIMS->tx_cnt - TIMS->tx_step) > TIMx->CCR4) && (TIMS->tx_cnt <= TIMx->CCR4))
{
TIM_Call_IRQHandller(TIMx);
TIMx->SR |= TIM_SR_CC4IF;
}
}
}
@@ -452,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)
{
@@ -649,9 +716,13 @@ __weak void TIM8_BRK_TIM12_IRQHandler(void) {}
__weak void TIM8_TRG_COM_TIM14_IRQHandler(void) {}
//#endif
/* Вызов прерывания */
void TIM_Call_IRQHandller(TIM_TypeDef* TIMx)
{ // calling HANDLER
SR_STORE(TIMx, SR);
if ((TIMx == TIM1) || (TIMx == TIM10))
TIM1_UP_TIM10_IRQHandler();
else if (TIMx == TIM2)
@@ -666,15 +737,17 @@ 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);
}
//------------------------------------------------------------------//

View File

@@ -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);
//------------------------------------------------------------------//

View File

@@ -16,6 +16,7 @@ MCU_CortexMemoryTypeDef MCU_CORTEX_MEM;
// MCU PERIPH INIT
void Initialize_Periph_Sim(void)
{
uwTick = hmcu.SystemClock / (MCU_CORE_CLOCK / 1000);
Init_TIM_SIM();
Init_ADC_SIM();
}
@@ -25,6 +26,7 @@ void Simulate_Periph_Sim(void)
{
Simulate_TIMs();
Simulate_ADCs();
Simulate_GPIO_BSRR();
}
// MCU PERIPH DEINIT
@@ -43,8 +45,10 @@ void deInitialize_MCU(void)
memset(&MCU_CORTEX_MEM, 0, sizeof(MCU_CORTEX_MEM));
memset(&htim1, 0, sizeof(htim1));
ClearStruct(upp);
ClearStruct(htim1);
ClearStruct(htim2);
ClearStruct(htim3);
ClearStruct(htim8);
ClearStruct(htim11);
@@ -107,7 +111,7 @@ struct TIM_Sim tim14s;
void Init_TIM_SIM(void)
{
#ifdef USE_TIM1
memset(&tim1s, 0, sizeof(tim1s));
memset(&tim1s, 0, sizeof(tim1s));
tim1s.tx_cnt = TIM1->CNT;
tim1s.tx_step = hmcu.sSimSampleTime * ABP2_TIMS_Value;
@@ -121,7 +125,7 @@ void Init_TIM_SIM(void)
tim1s.Channels.OC4_PIN_SHIFT = 11;
#endif
#ifdef USE_TIM2
memset(&tim2s, 0, sizeof(tim2s));
memset(&tim2s, 0, sizeof(tim2s));
tim2s.tx_cnt = TIM2->CNT;
tim2s.tx_step = hmcu.sSimSampleTime * ABP1_TIMS_Value;
@@ -135,7 +139,7 @@ void Init_TIM_SIM(void)
tim2s.Channels.OC4_PIN_SHIFT = 3;
#endif
#ifdef USE_TIM3
memset(&tim3s, 0, sizeof(tim3s));
memset(&tim3s, 0, sizeof(tim3s));
tim3s.tx_cnt = TIM3->CNT;
tim3s.tx_step = hmcu.sSimSampleTime * ABP1_TIMS_Value;
@@ -149,7 +153,7 @@ void Init_TIM_SIM(void)
tim3s.Channels.OC4_PIN_SHIFT = 9;
#endif
#ifdef USE_TIM4
memset(&tim4s, 0, sizeof(tim4s));
memset(&tim4s, 0, sizeof(tim4s));
tim4s.tx_cnt = TIM4->CNT;
tim4s.tx_step = hmcu.sSimSampleTime * ABP1_TIMS_Value;
@@ -163,7 +167,7 @@ void Init_TIM_SIM(void)
tim4s.Channels.OC4_PIN_SHIFT = 9;
#endif
#ifdef USE_TIM5
memset(&tim5s, 0, sizeof(tim5s));
memset(&tim5s, 0, sizeof(tim5s));
tim5s.tx_cnt = TIM5->CNT;
tim5s.tx_step = hmcu.sSimSampleTime * ABP1_TIMS_Value;
@@ -177,7 +181,7 @@ void Init_TIM_SIM(void)
tim5s.Channels.OC4_PIN_SHIFT = 3;
#endif
#ifdef USE_TIM6
memset(&tim6s, 0, sizeof(tim6s));
memset(&tim6s, 0, sizeof(tim6s));
tim6s.tx_cnt = TIM6->CNT;
tim6s.tx_step = hmcu.sSimSampleTime * ABP1_TIMS_Value;
@@ -213,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));

View File

@@ -147,4 +147,14 @@ static void ADC_SIM_DEINIT() {}
//-----------------------------------------------------------------------//
#define SR_STORE(periph, srname) \
uint32_t sr_origin = periph->srname; \
uint32_t sr_new = periph->srname;
#define SR_PROCESS(periph, srname) \
sr_new = sr_origin & periph->srname; \
periph->srname = sr_new;
#endif // _MATLAB_SETUP_H_

View File

@@ -15,7 +15,6 @@
"Initialize_Periph_Sim()"
],
"PeriphSimulation": [
"uwTick = hmcu.SystemClock / (MCU_CORE_CLOCK / 1000)",
"Simulate_Periph_Sim()"
],
"PeriphDeinit": [

View File

@@ -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

View File

@@ -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 1
#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 16
#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
@@ -79,7 +82,7 @@
* @param _arr_ind_ Индекс выходного порта
* @param _val_ind_ Индекс элемента в выходном массиве
*/
#define WriteOutputArray(_var_, _arr_ind_, _val_ind_) __WriteOutputArray(Buffer, (float)_var_, _arr_ind_, _val_ind_)
#define WriteOutputArray(_var_, _arr_ind_, _val_ind_) __WriteOutputArray(Buffer, (float)(_var_), _arr_ind_, _val_ind_)
/** @brief Считывает значение из входного массива блока S-Function
* @param _var_ Значение, которое необходимо записать (будет преобразовано в float)
@@ -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

View File

@@ -88,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^

View File

@@ -18,14 +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_Init();
UPP_Params_SetDefault(1, 1);
UPP_App_Init();
UPP_PreWhile();
UPP_DO.CEN(DISABLE);
// USER APP INIT END
}

View File

@@ -6,50 +6,139 @@
#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);
}
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);
}
void Write_PowerMonitor(real_T* Buffer, int ind_port)
{
int nn = 0;
for (int i = 0; i < 3; i++)
{
WriteOutputArray(upp.pm.U[i], ind_port, nn++);
{ //0-2
WriteOutputArray(upp.pm.measured.fast.U[i], ind_port, nn++);
}
for (int i = 0; i < 3; i++)
{
{ //3-5
WriteOutputArray(upp.pm.zc.Channel[i].HalfWave, ind_port, nn++);
}
for (int i = 0; i < 3; i++)
{
WriteOutputArray(upp.pm.F[i], ind_port, nn++);
{ //6-8
WriteOutputArray(upp.pm.measured.final.F[i], ind_port, nn++);
}
for (int i = 0; i < 3; i++)
{
WriteOutputArray(upp.pm.I[i], ind_port, nn++);
{ //9-11
WriteOutputArray(upp.pm.measured.fast.I[i], ind_port, nn++);
}
for (int i = 0; i < 2; i++)
{
WriteOutputArray(upp.pm.T[i], ind_port, nn++);
{ //12-13
WriteOutputArray(upp.pm.measured.final.T[i], 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 - массив входных значений
@@ -63,7 +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, 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
}
@@ -74,12 +194,24 @@ void app_readInputs(const real_T* Buffer) {
*/
void app_writeOutputBuffer(real_T* Buffer) {
// USER APP OUTPUT START
Write_Thyristors(Buffer, 0);
Write_PowerMonitor(Buffer, 1);
Write_UPP_Outputs(Buffer, 0);
Write_PowerMonitor(Buffer, 2);
WriteOutputArray(TIM2->CNT, 2, 0);
WriteOutputArray(TIM2->CCR1, 2, 1);
Write_AngleControl(Buffer, 3);
int nn = 0;
//WriteOutputArray(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++);
// USER APP OUTPUT END
}

View File

@@ -9,7 +9,22 @@
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();
static uint32_t uwTickPrev = 0;
if (uwTickPrev != uwTick)
{
uwTickPrev = uwTick;
UPP_Tick();
}
// USER APP STEP END
}

23
MATLAB/calc_pi.m Normal file
View 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);

Binary file not shown.

View File

@@ -1,8 +1,14 @@
clear all
IadcMax = 200;%50;
VadcMax = 1216;
Ts = 5e-6;
Vnom = 380;
Vnom = 400;
Inom = 30;%4.2;
Fnom = 50;
Temperature1 = 2.22; % 20 градусов
Temperature2 = 2.99; % 34 градусов
Temperature2 = 2.99; % 34 градусов

Binary file not shown.

View File

@@ -16,7 +16,7 @@
******************************************************************************/
#ifndef __SPI_MEMORY_CONFIG_H_
#define __SPI_MEMORY_CONFIG_H_
#include "upp_config.h"
#include "upp_defs.h"
/////////////////////////---USER SETTINGS---/////////////////////////

View File

@@ -19,7 +19,8 @@
******************************************************************************/
#ifndef _MODBUS_CONFIG_H_
#define _MODBUS_CONFIG_H_
#include "upp_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

View File

@@ -21,7 +21,11 @@
#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
MB_DataInternalTypeDef MB_INTERNAL;
/**
* @brief Check is address valid for certain array.
@@ -63,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
}
@@ -78,6 +88,10 @@ MB_ExceptionTypeDef MB_DefineRegistersAddress(uint16_t **pRegs, uint16_t Addr, u
{
*pRegs = MB_Set_Register_Ptr(&MB_DATA.HoldRegs, Addr - R_HOLDING_ADDR); // указатель на выбранный по Addr регистр
}
else if(MB_Check_Address_For_Arr(Addr, Qnt, R_HOLDING_PRVT_PARAMS_ADR, R_HOLDING_PRVT_PARAMS_QNT) == ET_NO_ERRORS)
{
*pRegs = MB_Set_Register_Ptr(&MB_INTERNAL, Addr - R_HOLDING_PRVT_PARAMS_ADR); // указатель на выбранный по Addr регистр
}
// if address doesnt match any array - return illegal data address response
else
{
@@ -118,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)
{

View File

@@ -50,20 +50,24 @@
#ifndef _MODBUS_DATA_H_
#define _MODBUS_DATA_H_
#include "upp_defs.h"
#include "upp_params.h"
#include "stdint.h"
//--------------SIZES OF DATA---------------
#define R_HOLDING_PRVT_PARAMS_ADR 555
#define R_HOLDING_PRVT_PARAMS_QNT (sizeof(UPP_PrvtParams_t)/sizeof(uint16_t))
// DEFINES FOR INPUT REGISTERS ARRAYS
#define R_INPUT_ADDR 0 ///< Начальный адрес входных регистров
#define R_INPUT_QNT 16 ///< Количество входных регистров
#define R_INPUT_QNT (sizeof(UPP_PUI_Values_t)/sizeof(uint16_t)) ///< Количество входных регистров
// DEFINES FOR HOLDING REGISTERS ARRAYS
#define R_HOLDING_ADDR 0 ///< Начальный адрес регистров хранения
#define R_HOLDING_QNT 16 ///< Количество регистров хранения
#define R_HOLDING_QNT (sizeof(UPP_PUI_Params_t)/sizeof(uint16_t)) ///< Количество регистров хранения
// DEFINES FOR COIL ARRAYS
#define C_COILS_ADDR 0 ///< Начальный адрес коилов
@@ -89,7 +93,7 @@
*/
typedef struct //MB_DataInRegsTypeDef
{
uint16_t in[16];
UPP_PUI_Values_t pui;
}MB_DataInRegsTypeDef;
@@ -98,7 +102,7 @@ typedef struct //MB_DataInRegsTypeDef
*/
typedef struct //MB_DataInRegsTypeDef
{
uint16_t out[16];
UPP_PUI_Params_t pui_params;
}MB_DataHoldRegsTypeDef;
@@ -153,6 +157,13 @@ typedef struct // tester modbus data
extern MB_DataStructureTypeDef MB_DATA;
typedef struct
{
UPP_FuncCalls_t FuncCalls;
UPP_PrvtParams_t param;
}MB_DataInternalTypeDef;
extern MB_DataInternalTypeDef MB_INTERNAL;
#endif //_MODBUS_DATA_H_
/////////////////////////////////////////////////////////////

View File

@@ -10,7 +10,7 @@
*************************************************************************/
#ifndef __MYLIBS_CONFIG_H_
#define __MYLIBS_CONFIG_H_
#include "upp_config.h"
#include "upp_defs.h"
// user includes
/**
@@ -65,7 +65,7 @@
//#define FILTER_MEDIAN_MAX_SIZE ///< Максимальный размер окна медианного фильтра (по умолчанию 5)
//#define FILTER_AVERAGE_MAX_SIZE ///< Максимальный размер окна усредняющего фильтра (по умолчанию 8)
//#define FILTER_POLY_MAX_ORDER ///< Максимальный порядок полинома (по умолчанию 4)
#define FILTERS_DISABLE_MOVING_AVERAGE
/** GEN_CONFIG
* @}
*/
@@ -96,9 +96,15 @@
*/
//#define BENCH_TIME_ENABLE ///< Включить бенч времени
#define BENCH_TIME_MAX_CHANNELS 16 ///< Максимальное количество каналов измерения
#define BENCH_TIME_ENABLE ///< Включить бенч времени
#define BENCH_TIME_MAX_CHANNELS 6 ///< Максимальное количество каналов измерения
#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
* @}
*/
@@ -126,13 +132,14 @@
#else
extern float dbg[16];
#define local_time() uwTick ///< Локальное время
//#define INCLUDE_GEN_OPTIMIZER ///< Подключить библиотеку для оптимизации параметров
#define INCLUDE_BIT_ACCESS_LIB ///< Подключить библиотеку с typedef с битовыми полями
#define INCLUDE_TRACKERS_LIB ///< Подключить библиотеку с трекерами
//#define INCLUDE_TRACE_LIB ///< Подключить библиотеку с трейсами
#define INCLUDE_GENERAL_PERIPH_LIBS ///< Подключить библиотеку с периферией
//#define INCLUDE_BENCH_TIME ///< Подключить библиотеку с бенчмарком времени
#define INCLUDE_BENCH_TIME ///< Подключить библиотеку с бенчмарком времени
#define INCLUDE_FILTERS ///< Подключить библиотеку с фильтрами
#endif //MATLAB

View File

@@ -14,52 +14,166 @@
#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
/* Дефайны для базовых величин */
#define PM_U_BASE 1216.0
#define PM_I_BASE 53.0
/* Дефайны для настройки мониторинга питания */
#define PM_ADC_PERIOD_MKS 10
#define PM_ZERO_CROSS_HYSTERESIS_V 10
#define PM_ZERO_CROSS_DEBOUNCE_10US 2.5*100 // (2.5 * 100 = 2.5 мс)
/* Рассчитанные дефайны */
#define PM_ADC_PERIOD (180*PM_ADC_PERIOD_MKS)-1
/* Общие для всего проекта структуры*/
/**
* @brief Состояния полуволны
/**
* @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_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 Дефолтные параметры для внешней памяти. Они применятся по команде или по ошибке
* @{
*/
typedef enum {
UPP_WAVE_UNKNOWED = 0,
UPP_WAVE_POSITIVE,
UPP_WAVE_NEGATIVE
} UPP_HalfWave_t;
/**
* @brief Названия Фаз
*/
typedef enum {
UPP_PHASE_A = 0,
UPP_PHASE_B = 1,
UPP_PHASE_C = 2,
UPP_PHASE_UNKNOWN = 3
} UPP_Phase_t;
/* Уставки по температурам */
#define SETPOINT_TEMP_WARN 70
#define SETPOINT_TEMP_ERR 85
/* Номинальные параметры */
#define NOM_PHASE_NUMB 3
#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 10
#define NOM_F_DEVIATION_MINUS_PERCENT_DEFAULT 10
#define NOM_I_A_DEFAULT 5
/* Параметры ПУИ */
#define PUI_Iref_PERCENT_DEFAULT 1.5
#define PUI_Tnt_MS_DEFAULT 300
#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
#define ADC_U_ZERO_DEFAULT 2048
#define ADC_I_ZERO_DEFAULT 2048
/* Параметры определения перехода через ноль */
#define ZERO_CROSS_HYSTERESIS_PERCENT_DEFAULT 2.0
#define ZERO_CROSS_DEBOUNCE_CNT_DEFAULT 2*100 // (2.5 * 100 = 2.5 мс)
/* Параметры ШИМ для тиристоров */
#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_PARAMS_DEFAULT
* @}
*/
// ===== ОТЛАДОЧНЫЕ ШТУКИ ДЛЯ 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_

217
UPP/Core/Configs/upp_defs.h Normal file
View File

@@ -0,0 +1,217 @@
/**
******************************************************************************
* @file upp_defs.h
* @brief Общие дефайны УПП
******************************************************************************
@addtogroup UPP_DEFS UPP defines
@ingroup UPP_MAIN
@brief Общие дефайны для всего проекта УПП
@{
******************************************************************************
* @details
******************************************************************************/
#ifndef _UPP_DEFS_H_
#define _UPP_DEFS_H_
#include "upp_config.h"
/**
* @addtogroup UPP_HIGHLEVEL Defines for high-level
* @ingroup UPP_DEFS
* @brief Дефайны УПП которые определяют коды ошибок и параметры для общения с верхним уровнем
* @{
*/
/**
* @brief Список аварий УПП
*/
typedef enum {
UPP_Init = 0, ///< УПП не инициализирован
UPP_Ready = 1, ///< УПП в готовности
UPP_Work = 2, ///< УПП в работе, управляет тиристорами
UPP_Error = 3, ///< УПП в аварии
// WM_Done = 3, ///< УПП закончил свою работу
} UPP_WorkModeType_t;
/**
* @brief Список аварий УПП
*/
typedef enum {
Err_None = 0, ///< Неисправность отсутствует
/* Програмные ошибки */
Err_Internal_1 = 1, ///< Внутренняя неисправность УПП 1
Err_Internal_2 = 2, ///< Внутренняя неисправность УПП 2
Err_Internal_3 = 3, ///< Внутренняя неисправность УПП 3
Err_Internal_4 = 4, ///< Внутренняя неисправность УПП 4
Err_Internal_5 = 5, ///< Внутренняя неисправность УПП 5
Err_Internal_6 = 6, ///< Внутренняя неисправность УПП 6
/* Ошибки по питанию */
Err_Power_Digit_5V = 7, ///< Неисправность цифрового источника питания (5 В)
Err_Power_24V = 8, ///< Неисправность источника питания 24 В
Err_Power_Analog_5V = 9, ///< Неисправность аналогового источника питания микроконтроллера (± 5 В)
Err_Power_SCI_5V = 10, ///< Неисправность источника питания последовательных интерфейсов микроконтроллера (5 В)
Err_Power_DIO_24V = 11, ///< Неисправность источника питания дискретных входов/выходов (24 В)
/* Ошибки по допустимым пределам Наряжений/Токов/Температуры */
Err_OverCurrent = 12, ///< Ток выше допустимого (см. Imax и TiMax в @ref UPP_PUI_Params_t)
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)
Err_LossPhaseA = 17, ///< Обрыв фазы A (см. Imin в @ref UPP_PUI_Params_t)
Err_LossPhaseB = 18, ///< Обрыв фазы B (см. Imin в @ref UPP_PUI_Params_t)
Err_LossPhaseC = 19, ///< Обрыв фазы C (см. Imin в @ref UPP_PUI_Params_t)
/* Другие ошибки */
Err_LongStart = 20, ///< Затянутый пуск (ток не спадает за установленное время) (см. Tdelay в @ref UPP_PUI_Params_t)
Err_Interlace = 21, ///< Неправильный порядок чередования фаз (см. Interlace в @ref UPP_PUI_Params_t)
} UPP_ErrorType_t;
/**
* @brief Структура данных от УПП передаваемых в ПУИ
*/
typedef struct {
uint16_t Error; /** @brief Текущая авария
@details В случае срабатывания защиты */
uint16_t WorkMode; /** @brief Режим работы
@details «Готовность» или «Работа» */
uint16_t Voltage; /** @brief Напряжение на входе УПП, Вольты */
uint16_t Current; /** @brief Ток на входе УПП, Амперы */
uint16_t Frequency; /** @brief Частота напряжения на входе УПП */
uint16_t Temperature; /** @brief Температура радиатора тиристоров, Градусы Цельсия */
} UPP_PUI_Values_t;
/**
* @brief Структура параметров УПП от ПУИ
* @details Параметры по умолчанию приведены в @ref UPP_PARAMS_DEFAULT
* @note Защиты №X приведены в @ref UPP_ErrorType_t
*/
typedef struct {
uint16_t Iref; /** @brief Уставка ограничения тока УПП
@details В диапазоне от 100 % до 500 % от Iн = 5 А
По умолчанию @ref PUI_Iref_PERCENT_DEFAULT */
uint16_t Tnt; /** @brief Уставка времени нарастания заданного тока
@details В диапазоне от 50 до 5000 мс.
По умолчанию @ref PUI_Tnt_MS_DEFAULT */
uint16_t Umin; /** @brief Уставка защиты №15 от понижения напряжения входной сети
@details В диапазоне от 5% до 99 % от Uн = 690 В.
По умолчанию @ref PUI_Umin_PERCENT_DEFAULT */
uint16_t Umax; /** @brief Уставка защиты №13 от повышения напряжения входной сети
@details В диапазоне от 100% до 120 % от Uн = 690 В.
По умолчанию @ref PUI_Umax_PERCENT_DEFAULT */
uint16_t Imax; /** @brief Уставка защиты №12 по току
@details В диапазоне от 5 % до 99 % от 50 А.
По умолчанию @ref PUI_Imax_PERCENT_DEFAULT */
uint16_t Imin; /** @brief Уставка защит № 16 №19 от обрыва фаз(ы)
@details В диапазоне от 0 % до 40 % от Iн = 5 А. При задании нуля эти защиты отключаются.
По умолчанию @ref PUI_Imin_PERCENT_DEFAULT */
uint16_t TiMax; /** @brief Выдержка времени на срабатывание защиты № 12 по току
@details В диапазоне от 500 до 10000 мкс.
По умолчанию @ref PUI_TiMax_US_DEFAULT */
uint16_t Tdelay; /** @brief Выдержка времени защиты № 20 от затянутого пуска
@details В диапазоне от 5 до 60 с.
По умолчанию @ref PUI_Tdelay_SECONDS_DEFAULT */
uint16_t Interlace; /** @brief Разрешение защиты № 21 от обратного порядка чередования фаз;
@details 0 нет защиты, 1 есть защита.
По умолчанию @ref PUI_Interlace_EN_DEFAULT */
} UPP_PUI_Params_t;
/** //UPP_HIGHLEVEL
* @}
*/
/**
* @addtogroup UPP_INTERNAL_DEFS Defines for internal use
* @ingroup UPP_DEFS
* @brief Дефайны УПП которые используютяс исключительно внутри программы
* @{
*/
// Проверка корректности структуры
#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 Состояния полуволны
*/
typedef enum {
UPP_WAVE_UNKNOWED = 0,
UPP_WAVE_POSITIVE,
UPP_WAVE_NEGATIVE
} UPP_HalfWave_t;
/**
* @brief Названия Фаз
*/
typedef enum {
UPP_PHASE_A = 0,
UPP_PHASE_C = 1,
UPP_PHASE_B = 2,
UPP_PHASE_UNKNOWN = 3
} UPP_Phase_t;
/** //UPP_INTERNAL_DEFS
* @}
*/
#endif //_UPP_DEFS_H_
/** //UPP_DEFS
* @}
*/

View File

@@ -31,11 +31,13 @@ extern "C" {
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "upp_config.h"
/* Общее по УПП */
#include "upp_defs.h"
#include "upp_io.h"
#include "upp_errors.h"
/* Общие библиотеки */
#include "mylibs_include.h"
#ifndef MATLAB
#include "modbus.h"
#endif
/* USER CODE END Includes */
/* Exported types ------------------------------------------------------------*/
@@ -56,10 +58,11 @@ extern "C" {
void Error_Handler(void);
/* USER CODE BEGIN EFP */
extern __IO uint32_t micros;
/* USER CODE END EFP */
/* Private defines -----------------------------------------------------------*/
#define angletim htim2
#define mb_huart huart3
#define mbdbg_htim htim11
#define PWM_CHANNEL_1 TIM_CHANNEL_1
@@ -67,23 +70,22 @@ extern __IO uint32_t micros;
#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
@@ -173,6 +175,30 @@ extern __IO uint32_t micros;
/* 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

View File

@@ -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 */

View File

@@ -7,61 +7,49 @@
******************************************************************************/
#include "adc_tools.h"
//Полосовой фильтр 45-55 Гц
static float coefs_biquad_U[5] = {
0.000010f, // b0
0.000020f, // b1
0.000010f, // b2
-1.900000f, // a1
0.950000f // a2
};
// ФНЧ 100 Гц
static float coefs_biquad_I[5] = {
0.000010f, // b0
0.000020f, // b1
0.000010f, // b2
-1.900000f, // a1
0.950000f // a2
};
// ФНЧ 10 Гц
static float coefs_biquad_T[5] = {
0.0002f, // b0
0.0004f, // b1
0.0002f, // b2
-1.98f, // a1
0.980f // a2
};
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);
FilterBandPassDerivative_Init(&adc->u_fltr[i], (50.0f*PM_FAST_PERIOD_US/1000000), 0.1);
FilterMedianInt_Init(&adc->i_fltr[I_C], 5, 2048);
FilterLUT_Init(&adc->temp_map[i],
(float *)adc_temp_quants,
(float *)adc_temp_vals,
numbof(adc_temp_quants), 1);
}
// Запуск фильтров
for(int i = 0; i < 2; i++)
{
Filter_Start(&adc->u_fltr[i]);
Filter_Start(&adc->i_fltr[i]);
Filter_Start(&adc->temp_map[i]);
}
FilterLUT_Init(&adc->temp_map[0],
(float *)adc_temp_quants,
(float *)adc_temp_vals,
numbof(adc_temp_quants), 1);
FilterLUT_Init(&adc->temp_map[1],
(float *)adc_temp_quants,
(float *)adc_temp_vals,
numbof(adc_temp_quants), 1);
}
__STATIC_FORCEINLINE void ADC_FilterRaw(ADC_Periodic_t *adc, int ch_start, int ch_end)
{
}
/**
* @brief Инициализация периодического АЦП.
* @param adc Указатель на кастомный хендл АЦП
@@ -106,6 +94,7 @@ HAL_StatusTypeDef ADC_ConfigChannel(ADC_Periodic_t *adc, int ChNumb, uint16_t le
adc->Coefs[ChNumb].lMax = levelMax;
adc->Coefs[ChNumb].vMax = valueMax;
adc->Coefs[ChNumb].lZero = levelZero;
return HAL_OK;
}
@@ -116,32 +105,32 @@ HAL_StatusTypeDef ADC_ConfigChannel(ADC_Periodic_t *adc, int ChNumb, uint16_t le
* @return HAL Status.
* @details Запускает АЦП с частотой дискретизации на которую настроен таймер adc_tim.
*/
HAL_StatusTypeDef ADC_Start(ADC_Periodic_t *adc, uint16_t Period)
HAL_StatusTypeDef ADC_Start(ADC_Periodic_t *adc, float PeriodUs)
{
HAL_StatusTypeDef res;
if(assert_upp(adc))
return HAL_ERROR;
if(Period == 0)
if(PeriodUs == 0)
return HAL_ERROR;
// Остановить перед перенастройкой
HAL_TIM_Base_Stop(adc->htim);
// Запускаем таймер который будет запускать опрос АЦП с заданным периодом
__HAL_TIM_SET_AUTORELOAD(adc->htim, Period);
__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;
}
/**
@@ -159,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;
@@ -175,97 +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);
}
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;
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)
float *data = adc->Data;
uint16_t *raw = adc->RawData;
// Преобразования температуры по таблице
for (int i = ADC_TEMP_CHANNELS_START; i < ADC_TEMP_CHANNELS_END; i++)
{
return;
}
// Накопление для Avg/RMS
stat->Sum += 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;
}
data[i] = Filter_Process(&adc->temp_map[i-ADC_TEMP_CHANNELS_START], raw[i]);
}
return HAL_OK;
}
/**
* @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));
}
}

View File

@@ -18,12 +18,19 @@
#define ADC_CHANNEL_TEMP2 5
#define ADC_NUMB_OF_CHANNELS 6
#define ADC_NUMB_OF_U_CHANNELS 2
#define ADC_NUMB_OF_I_CHANNELS 2
#define ADC_NUMB_OF_T_CHANNELS 2
#define ADC_NUMB_OF_CHANNELS 6
#define ADC_NUMB_OF_U_CHANNELS 2
#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, \
@@ -50,11 +57,7 @@
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 Коэфициенты канала АЦП для пересчета в единицы измерения
*/
@@ -67,7 +70,7 @@ typedef struct
typedef enum
{
ADC_LEVEL_DISABLE=0, ///< Базовая статистика - Max/Min
ADC_LEVEL_DISABLE=0, ///< Статистика отключена
ADC_LEVEL_BASE, ///< Базовая статистика - Max/Min
ADC_LEVEL_AC, ///< Статистика для переменных сигналов - AVG, RMS
}ADC_StatLevel_t;
@@ -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
{
@@ -123,16 +125,12 @@ HAL_StatusTypeDef ADC_Init(ADC_Periodic_t *adc, TIM_HandleTypeDef *htim, ADC_Han
/* Конфигуарция канала АЦП. */
HAL_StatusTypeDef ADC_ConfigChannel(ADC_Periodic_t *adc, int ChNumb, uint16_t levelZero, float valueMax, uint16_t levelMax);
/* Запуск АЦП. */
HAL_StatusTypeDef ADC_Start(ADC_Periodic_t *adc, uint16_t Period);
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_

View 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
}

View 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_ */

View File

@@ -6,69 +6,301 @@
* @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)
return HAL_ERROR;
/* Инициализация АЦП */
if(ADC_Init(&hpm->adc, &adc_tim, &hadc3) != HAL_OK)
return HAL_ERROR;
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_UBA, 2048, PM_U_BASE, 4095) != HAL_OK)
return HAL_ERROR;
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_UAC, 2048, PM_U_BASE, 4095) != HAL_OK)
return HAL_ERROR;
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_IC, 2048, PM_I_BASE, 4095) != HAL_OK)
return HAL_ERROR;
if(ADC_ConfigChannel(&hpm->adc, ADC_CHANNEL_IA, 2048, PM_I_BASE, 4095) != HAL_OK)
return HAL_ERROR;
if(ZC_Init(&hpm->zc, 3, PM_ZERO_CROSS_HYSTERESIS_V, PM_ZERO_CROSS_DEBOUNCE_10US) != 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 < ADC_NUMB_OF_REGULAR_CHANNELS; i++)
{
if(FilterAverage_Init(&hpm->avg[i], PM_SLOW_PERIOD_CNT, FILTER_MODE_DEFAULT))
return HAL_ERROR;
Filter_Start(&hpm->avg[i]);
}
/* Инициализация среднего фильтра для температур */
for(int i = 0; i < ADC_NUMB_OF_T_CHANNELS; i++)
{
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->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(ADC_Start(&hpm->adc, PM_ADC_PERIOD) != HAL_OK)
return HAL_ERROR;
if(hpm == NULL)
return HAL_ERROR;
if(ADC_Start(&hpm->adc, PM_FAST_PERIOD_US) != HAL_OK)
return HAL_ERROR;
return HAL_OK;
}
void PowerMonitor_Handle(PowerMonitor_t *hpm)
/**
* @brief Медленные расчеты АЦП.
* @param hpm Указатель на структуру мониторинга сети
* @details Вызывается в main после накопления @ref PM_SLOW_PERIOD_CNT выборок АЦП.
* Делаются всякие расчеты для более подробного мониторинга сети и защит.
* Сам АЦП считывается в @ref PowerMonitor_FastCalc
*/
void PowerMonitor_SlowCalc(PowerMonitor_t *hpm)
{
static uint32_t last_zc_cnt[ADC_NUMB_OF_U_CHANNELS] = {0};
ADC_Handle(&hpm->adc);
hpm->U[U_BA] = hpm->adc.Data[ADC_CHANNEL_UBA];
hpm->U[U_AC] = hpm->adc.Data[ADC_CHANNEL_UAC];
hpm->U[U_BC] = -hpm->U[U_BA] - hpm->U[U_AC];
hpm->I[I_C] = hpm->adc.Data[ADC_CHANNEL_IC];
hpm->I[I_A] = hpm->adc.Data[ADC_CHANNEL_IA];
hpm->I[I_B] = -hpm->I[I_A] - hpm->I[I_C];
hpm->T[TEMP_1] = hpm->adc.Data[ADC_CHANNEL_TEMP1];
hpm->T[TEMP_2] = hpm->adc.Data[ADC_CHANNEL_TEMP2];
ZC_ProcessAllChannels(&hpm->zc, hpm->U, usTick);
if(hpm == NULL)
return;
PowerMonitor_Measured_t *meas = &hpm->measured;
/* Обработка температур */
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);
/* Расчет третьей фазы */
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++)
{
/* Получение частоты фазы */
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];
/* Средниее напряжение фазы */
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->F[i] = ZC_GetFrequency(&hpm->zc, i) / 2;
hpm->slow_cnt++;
}
/**
* @brief Считывание АЦП и быстрые расчеты.
* @param hpm Указатель на структуру мониторинга сети
* @details Вызывается в прерывании АЦП по получению данных.
* Далее данные считываются и делаются базовые преобразования
* Более подробные расчеты в @ref PowerMonitor_SlowCalc
*/
void PowerMonitor_FastCalc(PowerMonitor_t *hpm)
{
if(hpm == NULL)
return;
float u_base = u2f(PARAM_INTERNAL.nominal.U, 10);
float i_base = u2f(PARAM_INTERNAL.nominal.I, 10);
PowerMonitor_Measured_t *meas = &hpm->measured;
/* Считываем АЦП с пересчетами и медианой фильтрацией от выбросов */
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->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]);
/* Запускаем медленную обработку через slow_period прерываний */
// if(hpm->isr_cnt == PM_SLOW_PERIOD_CNT)
/* Запускаем медленную когда фильтры среднего зациклились */
/* Берем 0 фильтр, просто так, потому что они все должны работать синхронно */
if(Filter_isDataReady(&hpm->avg[0]))
{
hpm->isr_cnt = 0;
if(!hpm->f.runSlow)
{
hpm->f.runSlow = 1;
}
else // если уже запущена - ставим overrun slow calc
{
ERR_PRIVATE.overrun_slow_calc = 1;
ERR_PRIVATE_CNT.overrun_slow_calc++;
}
}
else
{
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]);
}
}
}

View File

@@ -3,6 +3,8 @@
* @file power_monitor.h
* @brief Модуль мониторящий сеть: Напряжение, Токи, Температуры
******************************************************************************
* @addtogroup POWER_MONITOR Power Monitoring
* @brief Модуль для слежения за сетью и температурами (крч все что от АЦП)
*****************************************************************************/
#ifndef _POWER_MONITOR_H_
#define _POWER_MONITOR_H_
@@ -10,24 +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
{
ADC_Periodic_t adc;
ZeroCross_Handle_t zc;
UPP_HalfWave_t CurrentHalfWave[3];
unsigned inIsr:1; ///< Флаг что мы в прерывании
unsigned runSlow:1; ///< Запустить медленный алгоритм в while(1)
float U[3];
float F[3];
float I[3];
float T[2];
unsigned isU:1; ///< Есть ли напряжение
unsigned isI:1; ///< Есть ли ток
}PowerMonitor_Flags_t;
/**
* @brief Измеренные и приведенные значения с АЦП
*/
typedef struct
{
/** @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;
/** @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;
}PowerMonitor_Measured_t;
/**
* @brief Структура для мониторинга сети
*/
typedef struct
{
ADC_Periodic_t adc; ///< Хендл периодического АЦП
ZeroCross_Handle_t zc; ///< Хендл перехода через ноль
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 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_Handle(PowerMonitor_t *hpm);
// ====== РАСЧЕТЫ ==========
/* Медленные расчеты АЦП */
void PowerMonitor_SlowCalc(PowerMonitor_t *hpm);
/* Считывание АЦП и быстрые расчеты */
void PowerMonitor_FastCalc(PowerMonitor_t *hpm);
/* Проверяет защиты питания и температур */
int PowerMonitor_Protect(PowerMonitor_t *hpm, uint8_t Running);
#endif /* _POWER_MONITOR_H_ */

View File

@@ -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;
}
}

View 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_ */

View File

@@ -28,9 +28,9 @@ HAL_StatusTypeDef ZC_Init(ZeroCross_Handle_t *zc, uint8_t num_channels,
memset(zc, 0, sizeof(ZeroCross_Handle_t));
// Установка параметров хендла
zc->NumChannels = num_channels;
zc->Hysteresis = hysteresis;
zc->DebounceSamples = debounce_samples;
zc->Config.NumChannels = num_channels;
zc->Config.Hysteresis = hysteresis;
zc->Config.DebounceSamples = debounce_samples;
// Инициализация каналов
for (int i = 0; i < num_channels; i++) {
@@ -63,7 +63,7 @@ HAL_StatusTypeDef ZC_ConfigChannel(ZeroCross_Handle_t *zc, uint8_t channel,
if (assert_upp(zc)){
return HAL_ERROR;
}
if (channel >= zc->NumChannels) {
if (channel >= zc->Config.NumChannels) {
return HAL_ERROR;
}
@@ -94,7 +94,7 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin
if (!zc->f.Monitoring) {
return;
}
if (channel >= zc->NumChannels) {
if (channel >= zc->Config.NumChannels) {
return;
}
int zc_detected = 0;
@@ -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)
{
@@ -111,16 +112,16 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin
}
// Детектирование rising edge (отрицательное -> положительное)
if ((zc_ch->LastValue <= -zc->Hysteresis) &&
(value >= zc->Hysteresis))
if ((zc_ch->LastValue <= -zc->Config.Hysteresis) &&
(value >= zc->Config.Hysteresis))
{
if (zc_ch->EdgeType == ZC_RISING_EDGE || zc_ch->EdgeType == ZC_BOTH_EDGES) {
if(zc->DebounceSamples)
if(zc->Config.DebounceSamples)
{
if(zc_ch->DebounceCounter == 0)
{
zc_ch->DebounceCounter = zc->DebounceSamples;
zc_ch->DebounceCounter = zc->Config.DebounceSamples;
}
}
@@ -128,48 +129,78 @@ void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uin
}
}
// Детектирование falling edge (положительное -> отрицательное)
else if ((zc_ch->LastValue >= zc->Hysteresis) &&
(value <= -zc->Hysteresis))
else if ((zc_ch->LastValue >= zc->Config.Hysteresis) &&
(value <= -zc->Config.Hysteresis))
{
if (zc_ch->EdgeType == ZC_FALLING_EDGE || zc_ch->EdgeType == ZC_BOTH_EDGES) {
if(zc->DebounceSamples)
if(zc->Config.DebounceSamples)
{
if(zc_ch->DebounceCounter == 0)
{
zc_ch->DebounceCounter = zc->DebounceSamples;
zc_ch->DebounceCounter = zc->Config.DebounceSamples;
}
}
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)
{
zc_ch->HalfWave = zc_detected == 1 ? UPP_WAVE_POSITIVE : UPP_WAVE_NEGATIVE;
zc_ch->Occurred = 1;
uint32_t RealTimeShift = 0;//zc->DebounceSamples*(timestamp - zc->LastTick); // коло-во тиков * период вызова функции
uint32_t RealTimeShift = 0;//zc->Config.DebounceSamples*(timestamp - zc->LastTick); // коло-во тиков * период вызова функции
// Переход подтвержден сразу
uint32_t RealTimestamp = timestamp-RealTimeShift;
if (zc_ch->LastCrossTime != 0) {
// Расчет периода и частоты
zc_ch->Period = RealTimestamp - zc_ch->LastCrossTime;
if (zc_ch->Period > 0) {
zc_ch->Frequency = 1000000.0f / zc_ch->Period;
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->Hysteresis) || (value < -zc->Hysteresis))
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
}
/**
@@ -188,7 +219,7 @@ void ZC_ProcessAllChannels(ZeroCross_Handle_t *zc, float *values, uint32_t times
return;
}
for (int ch = 0; ch < zc->NumChannels; ch++) {
for (int ch = 0; ch < zc->Config.NumChannels; ch++) {
ZC_ProcessChannel(zc, ch, values[ch], timestamp);
}
@@ -238,13 +269,61 @@ float ZC_GetFrequency(ZeroCross_Handle_t *zc, uint8_t channel)
if (assert_upp(zc)){
return 0.0f;
}
if (channel >= zc->NumChannels) {
if (channel >= zc->Config.NumChannels) {
return 0.0f;
}
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 Указатель на хендл детектора нуля
@@ -273,7 +352,7 @@ void ZC_Reset(ZeroCross_Handle_t *zc, uint8_t channel)
return;
}
if (channel < zc->NumChannels) {
if (channel < zc->Config.NumChannels) {
zc->Channel[channel].LastValue = 0.0f;
zc->Channel[channel].CurrentValue = 0.0f;
zc->Channel[channel].DebounceCounter = 0;
@@ -284,7 +363,7 @@ void ZC_Reset(ZeroCross_Handle_t *zc, uint8_t channel)
}
else {
// Сброс всех каналов
for (int i = 0; i < zc->NumChannels; i++) {
for (int i = 0; i < zc->Config.NumChannels; i++) {
zc->Channel[i].LastValue = 0.0f;
zc->Channel[i].CurrentValue = 0.0f;
zc->Channel[i].DebounceCounter = 0;

View File

@@ -94,21 +94,31 @@ 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;
/**
* @brief Параметры перехода через ноль
*/
typedef struct {
uint8_t NumChannels; ///< Количество используемых каналов для этого хендла
float Hysteresis; ///< Гистерезис для избежания дребезга
uint16_t DebounceSamples; ///< Количество samples для антидребезга
} ZC_Config_t;
/**
* @brief Хендл детектора нуля
*/
typedef struct {
ZC_Channel_t Channel[ZC_MAX_CHANNELS]; ///< Каналы @ref ZC_Channel_t
uint8_t NumChannels; ///< Количество используемых каналов для этого хендла
float Hysteresis; ///< Гистерезис для избежания дребезга
uint16_t DebounceSamples; ///< Количество samples для антидребезга
ZC_Channel_t Channel[ZC_MAX_CHANNELS]; ///< Каналы @ref ZC_Channel_t
ZC_Config_t Config;
struct {
unsigned Initialized:1; ///< Флаг инициализации
unsigned Monitoring:1; ///< Флаг активности мониторинга
@@ -117,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_ */
/**

View 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();
}
}

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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 */
@@ -34,7 +34,7 @@
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
__IO uint32_t micros;
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
@@ -72,33 +72,44 @@ 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--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* 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 */
@@ -204,7 +221,7 @@ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
HAL_IncTick();
}
/* USER CODE BEGIN Callback 1 */
/* USER CODE END Callback 1 */
}

View File

@@ -23,8 +23,6 @@
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "upp_main.h"
#include "pwm_thyristors.h"
#include "angle_control.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@@ -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,12 +232,27 @@ 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);
@@ -255,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 */
}

View File

@@ -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 */

View File

@@ -1,7 +1,7 @@
/**
******************************************************************************
* @file pwm_thyristors.c
* @brief Модуль для управления тиристорами
* @file angle_control.c
* @brief Модуль для формирования и отсчитывания угла открытия
******************************************************************************
* @details
******************************************************************************/
@@ -10,112 +10,216 @@
/**
* @brief Инициализация ШИМ тиристоров.
* @brief Инициализация таймера для расчета угла открытия.
* @param hangle Указатель на таймер
* @return HAL Status.
*/
HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle, float AngleMin, float AngleMax)
HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle)
{
if(hangle == NULL)
return HAL_ERROR;
if(AngleMax < 0 || AngleMax > 1)
return HAL_ERROR;
if(AngleMin < 0 || AngleMin > 1)
return HAL_ERROR;
hangle->htim = &angletim;
hangle->AngleMax = AngleMax;
hangle->AngleMin = AngleMin;
// Инициализация каналов
HAL_TIM_OC_Start_IT(hangle->htim, ANGLE_CHANNEL_1);
HAL_TIM_OC_Start_IT(hangle->htim, ANGLE_CHANNEL_2);
HAL_TIM_OC_Start_IT(hangle->htim, ANGLE_CHANNEL_3);
// Сброс всех каналов
Angle_Reset(hangle, UPP_PHASE_A);
Angle_Reset(hangle, UPP_PHASE_B);
Angle_Reset(hangle, UPP_PHASE_C);
hangle->f.Initialized = 1;
hangle->Config.PeriodLimit = 1;
return HAL_OK;
}
/**
* @brief Инициализация ПИД регулятора.
* @param hangle Указатель на таймер
* @param kp, ki kd Коэффициенты регулятора
*/
HAL_StatusTypeDef Angle_PID_Init(Angle_Handle_t *hangle, float kp, float ki, float kd, float alpha)
{
if(assert_upp(hangle))
return HAL_ERROR;
// Сам ПИД регулятор
hangle->pid.Kp = kp;
hangle->pid.Ki = ki;
hangle->pid.Kd = kd;
arm_pid_init_f32(&hangle->pid, 1);
// Сглаживающий фильтр для задания ПИД регулятора
FilterExp_Init(&hangle->refFilter, alpha);
Filter_Start(&hangle->refFilter);
Filter_Process(&hangle->refFilter, 0);
return HAL_OK;
}
/**
* @brief Хендл таймера для рассчета угла открытия.
* @param hangle Указатель на таймер
* @return HAL Status.
* @brief Управление углом через ПИД регулятор.
* @param hangle Указатель на таймер
* @param setpoint Уставка куда регулировать
* @param measurement Измеренные регулируемые величины
*/
UPP_Phase_t Angle_Handle(Angle_Handle_t *hangle)
void Angle_PID(Angle_Handle_t *hangle, float setpoint, float measurement, float Correction)
{
if(hangle == NULL)
return UPP_PHASE_UNKNOWN;
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 - открыть макситмально рано
switch(hangle->htim->Channel)
/* Ограничиваем диапазон */
if (open_level > 1)
{
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;
open_level = 1;
}
if(open_level < 0)
{
open_level = 0;
}
/* Приводим уровень открытия к косинусу [-1:1]*/
float OpenLevelForCos = (open_level*2)-1;
return UPP_PHASE_UNKNOWN;
float alpha_rad = acosf(OpenLevelForCos); // угол в радианах
float alpha = alpha_rad/PI*hangle->Config.AngleMax; // угол открытия тиристора в о.е. от максимально заданного
/* Выставляем заданный уровень открытия */
Angle_SetAlpha(hangle, alpha, Correction);
}
/**
* @brief Установка угла открытия в таймер.
* @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_SetAlpha(Angle_Handle_t *hangle, float Alpha, float Correction)
{
if(assert_upp(hangle))
return HAL_ERROR;
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 Указатель на таймер
* @param Phase Для какой фазы надо установить угол открытия
* @return HAL Status.
*/
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float Angle, float Freq)
HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float PeriodMs)
{
if(hangle == NULL)
if(assert_upp_phase(hangle, Phase))
return HAL_ERROR;
// Если канал дурацкий - возвращаем ошибку
if(Phase >= 3)
{
return HAL_ERROR;
}
if(Angle > hangle->AngleMax)
{
Angle = hangle->AngleMax;
}
if(Angle < hangle->AngleMin)
{
Angle = hangle->AngleMin;
}
uint32_t timer_ticks = TIM_FreqToTick(Freq/Angle, ANGLE_TIM2_FREQ_MHZ);
// сколько тиков надо выждать для угла
uint32_t 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_ENABLE_IT(hangle->htim, TIM_IT_CC1);
__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_ENABLE_IT(hangle->htim, TIM_IT_CC2);
__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_ENABLE_IT(hangle->htim, TIM_IT_CC3);
__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;
case UPP_PHASE_UNKNOWN:
@@ -136,27 +240,27 @@ 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(hangle == NULL)
if(assert_upp_phase(hangle, Phase))
return HAL_ERROR;
// Если канал дурацкий - возвращаем ошибку
if(Phase >= 3)
{
return HAL_ERROR;
}
switch(Phase)
{
case UPP_PHASE_A:
__HAL_TIM_DISABLE_IT(hangle->htim, TIM_IT_CC1);
if(hangle->f.Running)
hangle->f.Running--;
break;
case UPP_PHASE_B:
__HAL_TIM_DISABLE_IT(hangle->htim, TIM_IT_CC2);
if(hangle->f.Running)
hangle->f.Running--;
break;
case UPP_PHASE_C:
__HAL_TIM_DISABLE_IT(hangle->htim, TIM_IT_CC3);
if(hangle->f.Running)
hangle->f.Running--;
break;
case UPP_PHASE_UNKNOWN:
@@ -164,4 +268,94 @@ HAL_StatusTypeDef Angle_Reset(Angle_Handle_t *hangle, UPP_Phase_t Phase)
break;
}
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;
}

View File

@@ -1,30 +1,75 @@
/**
******************************************************************************
* @file pwm_thyristors.h
* @brief Модуль для управления тиристорами (объединённый 6-канальный)
* @file angle_control.h
* @brief Модуль для формирования и отсчитывания угла открытия
******************************************************************************
*/
#ifndef _ANGLE_CONTROL_H_
#define _ANGLE_CONTROL_H_
#include "main.h"
#define ANGLE_TIM2_FREQ_MHZ 90
/**
* @brief Конфигурация алгоритма управления углом открытия
*/
typedef struct
{
TIM_HandleTypeDef *htim;
float PeriodLimit; ///< Лимит периода, выше которого нельзя выставить рассчитывается от параметров ШИМ
float AngleMin; ///< Минимально возможный угол открытия
float AngleMax; ///< Максимально возможный угол открытия
}Angle_Config_t;
/**
* @brief Структура для управления углом открытия
*/
typedef struct
{
TIM_HandleTypeDef *htim; ///< Указатель на таймер для расчета угла
Angle_Config_t Config; ///< Конфигурации алгоритма расчета угла открытия тиристоров
float AngleMin;
float AngleMax;
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 Running : 3; ///< Сколько каналов запущено сейчас
} f; ///< Флаги
}Angle_Handle_t;
// ====== ИНИЦИАЛИЗАЦИЯ ==========
/* Инициализация Таймера для рассчета угла открытия. */
HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle, float AngleMin, float AngleMax);
HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle);
/* Инициализация ПИД регулятора. */
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 Freq);
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_ */

View File

@@ -6,15 +6,18 @@
* @details
******************************************************************************/
#include "pwm_thyristors.h"
#include "angle_control.h"
#include "tim.h"
static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint32_t state);
static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Channel_t *hCh, uint32_t state);
static HAL_StatusTypeDef __PWM_ReConfigToSoftwarePulses(void);
/**
* @brief Инициализация ШИМ тиристоров.
* @param hpwm Указатель на хендл ШИМ тиристоров
* @return HAL Status.
* @details Инициализируется 6 структур на каждый канал ШИМ для тиристора.
* И одна dummy структура для безопасной инициализации неизвестной фазы.
* В конце запускаются все каналы ШИМ (с запрещенным выходом).
*/
HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm)
{
@@ -56,15 +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_SetFrequency(hpwm, hpwm->Config.Frequency);
HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_1);
HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_2);
HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_3);
HAL_TIM_PWM_Start(&hpwm1, PWM_CHANNEL_4);
HAL_TIM_PWM_Start(&hpwm2, PWM_CHANNEL_5);
HAL_TIM_PWM_Start(&hpwm2, PWM_CHANNEL_6);
HAL_TIM_Base_Start_IT(&hpwm1);
PWM_Stop(hpwm, 0, 1);
__PWM_ReConfigToSoftwarePulses();
HAL_TIM_Base_Start(&hpwm1);
return HAL_OK;
}
@@ -77,34 +81,31 @@ HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm)
*/
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 (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN])
return HAL_ERROR;
// Если канал дурацкий - возвращаем ошибку
if(Phase >= 3)
{
return HAL_ERROR;
}
if(!(hpwm->Config.PhaseMask.all&(1<<Phase)))
return HAL_ERROR;
switch(hpwm->Phase[Phase]->State)
{
// Если мы НЕ в режиме ожидание - ошибка
case PWM_THYR_DISABLED:
case PWM_THYR_TIM_START:
case PWM_THYR_TIM_ACTIVE:
case PWM_THYR_TIM_DONE:
return HAL_BUSY;
case PWM_THYR_DISABLED:
case PWM_THYR_TIM_WAIT_ZERO:
// переходим в состояние старта ШИМ
// Запуск только если таймер в режиме ожидания
case PWM_THYR_TIM_WAIT:
hpwm->Phase[Phase]->State = PWM_THYR_TIM_START;
return HAL_OK;
return HAL_OK;
default:
return HAL_ERROR;;
return HAL_ERROR;
}
return HAL_ERROR;
}
@@ -112,113 +113,63 @@ HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
* @brief Остановить ШИМ.
* @param hpwm Указатель на хендл ШИМ тиристоров
* @param Phase На какой фазе надо остановить ШИМ
* @param force_stop_all Принудительно остановить ВЕСЬ ШИМ
* @return HAL Status.
* @details Включает канал в режим форсированного неактивного выхода.
* При передаче 1 в force_stop_all, отключаются MOE (Main Output Enable) и все каналы ШИМ
*/
HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_stop)
HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_stop_all)
{
if(assert_upp(hpwm))
if(assert_upp_phase(hpwm, Phase))
return HAL_ERROR;
if (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN])
return HAL_ERROR;
// Если канал дурацкий - возвращаем ошибку
if(Phase >= 3)
{
return HAL_ERROR;
}
hpwm->Phase[Phase]->State = PWM_THYR_TIM_WAIT_ZERO;
// Если force_stop_all - сбрасываем ВСЕ КАНАЛЫ
if(force_stop_all)
{
// в первую очередь выключаем канал, потом выставим режим каналов
__HAL_TIM_MOE_DISABLE(&hpwm1);
__HAL_TIM_MOE_DISABLE(&hpwm2);
if(force_stop)
{
__PWM_SetOutputState(hpwm, Phase, PWM_DISABLE);
}
return HAL_ERROR;
}
/**
* @brief Хендл ШИМ тиристоров.
* @param hpwm Указатель на хендл ШИМ тиристоров
* @return HAL Status.
*/
HAL_StatusTypeDef PWM_Handle(PWM_Handle_t *hpwm)
{
if(assert_upp(hpwm))
return HAL_ERROR;
for(int phase = 0; phase < 3; phase++)
{
if(!read_bit(hpwm->Config.PhaseMask.all, phase))
continue;
if (hpwm->Phase[phase] == NULL || hpwm->Phase[phase] == &hpwm->AllPhases[PHASE_UNKNOWN])
continue;
switch(hpwm->Phase[phase]->State)
// выставляем все каналы в FORCE MODE
for(int ch = 0; ch < 6; ch++)
{
case PWM_THYR_DISABLED:
__PWM_SetOutputState(hpwm, phase, PWM_DISABLE);
break;
case PWM_THYR_TIM_WAIT_ZERO:
__PWM_SetOutputState(hpwm, phase, PWM_DISABLE);
break;
case PWM_THYR_TIM_START:
__PWM_SetOutputState(hpwm, phase, PWM_ENABLE);
hpwm->Phase[phase]->PulseCnt = hpwm->Config.PulseNumber;
hpwm->Phase[phase]->State = PWM_THYR_TIM_ACTIVE;
break;
case PWM_THYR_TIM_ACTIVE:
hpwm->Phase[phase]->PulseCnt--;
if(hpwm->Phase[phase]->PulseCnt <= 0)
{
hpwm->Phase[phase]->PulseCnt = 0;
hpwm->Phase[phase]->State = PWM_THYR_TIM_DONE;
}
break;
case PWM_THYR_TIM_DONE:
hpwm->Phase[phase]->State = PWM_THYR_TIM_WAIT_ZERO;
break;
default:
__PWM_SetOutputState(hpwm, phase, PWM_DISABLE);
break;
__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;
}
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(hpwm))
if(assert_upp_phase(hpwm, Phase))
return HAL_ERROR;
// Сбрасываем текущий канал
__PWM_SetOutputState(hpwm, Phase, PWM_DISABLE);
// Если канал дурацкий - выставляем заглушку
if(Phase >= 3)
{
hpwm->Phase[Phase] = &hpwm->AllPhases[PHASE_UNKNOWN];
return HAL_ERROR;
}
// Выставляем канал
// Выставляем текущий активную полуволну
switch(halfwave)
{
case UPP_WAVE_POSITIVE:
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:
@@ -227,77 +178,199 @@ HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_Hal
}
}
/**
* @brief Установка параметров ШИМ.
* @param hpwm Указатель на хендл ШИМ тиристоров
* @param Frequency Частота в ГЦ
* @return HAL Status.
*/
HAL_StatusTypeDef PWM_SetConfig(PWM_Handle_t *hpwm, uint8_t PhaseMask, uint16_t Frequency, float Duty, float PulseLength)
{
if(assert_upp(hpwm))
return HAL_ERROR;
if(hpwm->f.Running) // Если есть активные каналы - ниче не меняем
return HAL_BUSY;
// Остановка таймера
HAL_TIM_Base_Stop(&hpwm1);
hpwm->Config.PhaseMask.all = PhaseMask;
hpwm->Config.PulseLength = PulseLength;
hpwm->Config.Frequency = Frequency;
hpwm->Config.Duty = Duty;
// Высставление периодов
__HAL_TIM_SET_AUTORELOAD(&hpwm1, TIM_FreqToTick(Frequency, PWM_TIM1_FREQ_MHZ-1));
__HAL_TIM_SET_AUTORELOAD(&hpwm2, TIM_FreqToTick(Frequency, PWM_TIM8_FREQ_MHZ-1));
// Скважности
uint32_t pwm1_duty_ccr = (float)__HAL_TIM_GET_AUTORELOAD(&hpwm1)*(1-Duty);
uint32_t pwm2_duty_ccr = (float)__HAL_TIM_GET_AUTORELOAD(&hpwm2)*(1-Duty);
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_1, pwm1_duty_ccr);
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_2, pwm1_duty_ccr);
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_3, pwm1_duty_ccr);
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_4, pwm1_duty_ccr);
__HAL_TIM_SET_COMPARE(&hpwm2, PWM_CHANNEL_5, pwm2_duty_ccr);
__HAL_TIM_SET_COMPARE(&hpwm2, PWM_CHANNEL_6, pwm2_duty_ccr);
// Сброс счетчиков таймера и запуск заного
__HAL_TIM_SET_COUNTER(&hpwm1, 0);
__HAL_TIM_SET_COUNTER(&hpwm2, 0);
PWM_Stop(hpwm, 0, 1);
return HAL_TIM_Base_Start(&hpwm1);
}
/**
* @brief Установка полярности шим.
* @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, float PeriodMs)
{
if(assert_upp(hpwm))
return HAL_ERROR;
uint8_t phase = 0;
PWM_Channel_t *hPhase = NULL;
for(int ch = 0; ch < 6; ch++)
{
hPhase = &hpwm->AllPhases[ch];
if (hPhase->htim == NULL)
continue;
switch (hPhase->State)
{
case PWM_THYR_DISABLED: // канал отключен
__PWM_SetOutputState(hPhase, PWM_DISABLE);
break;
case PWM_THYR_TIM_WAIT: // канал ожидает команды
__PWM_SetOutputState(hPhase, PWM_DISABLE);
break;
case PWM_THYR_TIM_START: // начать ШИМ (пачка импульсов)
__PWM_SetOutputState(hPhase, PWM_ENABLE);
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 <= 1) // если остался один импльс в след раз идем в PWM_THYR_TIM_DONE
{
hPhase->PulseCnt = 0;
hPhase->State = PWM_THYR_TIM_DONE;
}
break;
case PWM_THYR_TIM_DONE: // пачка импульсов отправлена - отключение
hPhase->State = PWM_THYR_TIM_WAIT;
if(hpwm->f.Running)
hpwm->f.Running--;
break;
default: // чзх
__PWM_SetOutputState(hPhase, PWM_DISABLE);
break;
}
}
return HAL_OK;
}
//================ ВНУТРЕННИЕ ФУНКЦИИ ===================
/**
* @brief Установка режима для канала ШИМ.
* @param hpwm Указатель на хендл ШИМ тиристоров
* @param Phase Для какой фазы надо установить состояние
* @param state Какое состояние установить
* @return HAL Status.
*/
static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint32_t state)
static HAL_StatusTypeDef __PWM_SetOutputState(PWM_Channel_t *hCh, uint32_t state)
{
if(hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN])
if(hCh == NULL)
return HAL_ERROR;
if (hCh->htim == NULL)
return HAL_ERROR;
uint32_t ch_mode = state;
// Если режим уже выставлен
if(hCh->CurrentMode == state)
{
return HAL_OK;
}
hCh->CurrentMode = state;
switch(hpwm->Phase[Phase]->ChMask)
// выставляем режим каналов
switch(hCh->ChMask)
{
case TIM_CHANNEL_1:
hpwm->Phase[Phase]->htim->Instance->CCMR1 &= ~TIM_OCMODE_PWM2;
hpwm->Phase[Phase]->htim->Instance->CCMR1 |= ch_mode;
hCh->htim->Instance->CCMR1 &= ~TIM_OCMODE_PWM2;
hCh->htim->Instance->CCMR1 |= state;
break;
case TIM_CHANNEL_2:
hpwm->Phase[Phase]->htim->Instance->CCMR1 &= ~(TIM_OCMODE_PWM2 << 8);
hpwm->Phase[Phase]->htim->Instance->CCMR1 |= (ch_mode << 8);
hCh->htim->Instance->CCMR1 &= ~(TIM_OCMODE_PWM2 << 8);
hCh->htim->Instance->CCMR1 |= (state << 8);
break;
case TIM_CHANNEL_3:
hpwm->Phase[Phase]->htim->Instance->CCMR2 &= ~TIM_OCMODE_PWM2;
hpwm->Phase[Phase]->htim->Instance->CCMR2 |= ch_mode;
hCh->htim->Instance->CCMR2 &= ~TIM_OCMODE_PWM2;
hCh->htim->Instance->CCMR2 |= state;
break;
case TIM_CHANNEL_4:
hpwm->Phase[Phase]->htim->Instance->CCMR2 &= ~(TIM_OCMODE_PWM2 << 8);
hpwm->Phase[Phase]->htim->Instance->CCMR2 |= (ch_mode << 8);
hCh->htim->Instance->CCMR2 &= ~(TIM_OCMODE_PWM2 << 8);
hCh->htim->Instance->CCMR2 |= (state << 8);
break;
default:
break;
}
return HAL_OK;
}
/**
* @brief Установка полуволны для слежения.
* @param hpwm Указатель на хендл ШИМ тиристоров
* @param Phase Для какой фазы надо установить полуволну
* @param halfwave Какую полуволну установить
/**
* @brief Переконфигурация таймером для софтварного формирования пачки импульсов.
* @return HAL Status.
*/
UPP_HalfWave_t PWM_GetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase)
static HAL_StatusTypeDef __PWM_ReConfigToSoftwarePulses(void)
{
if(assert_upp(hpwm))
return UPP_WAVE_UNKNOWED;
if (hpwm->Phase[Phase] == NULL || hpwm->Phase[Phase] == &hpwm->AllPhases[PHASE_UNKNOWN])
return UPP_WAVE_UNKNOWED;
// Если канал дурацкий - возвращаем UNKNOWED
if(Phase >= 3)
{
return UPP_WAVE_UNKNOWED;
}
// Выставляем канал
if(hpwm->Phase[Phase] == &hpwm->AllPhases[Phase])
{
return UPP_WAVE_POSITIVE;
}
else if(hpwm->Phase[Phase] == &hpwm->AllPhases[Phase+3])
{
return UPP_WAVE_NEGATIVE;
}
else
{
return UPP_WAVE_UNKNOWED;
}
/* 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);
}

View File

@@ -1,7 +1,7 @@
/**
******************************************************************************
* @file pwm_thyristors.h
* @brief Модуль для управления тиристорами (объединённый 6-канальный)
* @brief Модуль для управления тиристорами
******************************************************************************
*/
#ifndef _PWM_THYRISTORS_H
@@ -9,44 +9,38 @@
#include "main.h"
#define PWM_TIM1_FREQ_MHZ 180
#define PWM_TIM3_FREQ_MHZ 90
#define PWM_ENABLE TIM_OCMODE_PWM1
#define PWM_DISABLE TIM_OCMODE_FORCED_ACTIVE
/**
* @brief Вкоючить хардварный способ формирования пачки импульсов
* @note При отключении сильно возрастет нагрузка на контроллер из-за прерываний ШИМ!
* Они поак работают всегда, независимо от того есть импулсь или нет
*/
#define PWM_HARDWARE_IMPULSES_CONTROL
#define PWM_ENABLE TIM_OCMODE_PWM2
#define PWM_DISABLE TIM_OCMODE_FORCED_INACTIVE
#define PWM_SetFrequency(_hpwm_, _freq_) \
do { _hpwm_->Config.Frequency = _freq_; \
__HAL_TIM_SET_AUTORELOAD(&hpwm1, TIM_FreqToTick(_freq_, PWM_TIM1_FREQ_MHZ)); \
__HAL_TIM_SET_AUTORELOAD(&hpwm2, TIM_FreqToTick(_freq_, PWM_TIM3_FREQ_MHZ)); \
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_1, __HAL_TIM_GET_AUTORELOAD(&hpwm1)/2); \
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_2, __HAL_TIM_GET_AUTORELOAD(&hpwm1)/2); \
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_3, __HAL_TIM_GET_AUTORELOAD(&hpwm1)/2); \
__HAL_TIM_SET_COMPARE(&hpwm1, PWM_CHANNEL_4, __HAL_TIM_GET_AUTORELOAD(&hpwm1)/2); \
__HAL_TIM_SET_COMPARE(&hpwm2, PWM_CHANNEL_5, __HAL_TIM_GET_AUTORELOAD(&hpwm2)/2); \
__HAL_TIM_SET_COMPARE(&hpwm2, PWM_CHANNEL_6, __HAL_TIM_GET_AUTORELOAD(&hpwm2)/2); }while(0);
// Индексы для структур каналов @ref PWM_Handle_t
#define PHASE_A_POS 0
#define PHASE_B_POS 1
#define PHASE_C_POS 2
#define PHASE_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 Состояния канала
*/
typedef enum {
PWM_THYR_DISABLED = 0, ///< Канал отключен
PWM_THYR_TIM_WAIT_ZERO, ///< Таймер ждет пересечения нуля
PWM_THYR_TIM_WAIT, ///< Таймер ждет команды
PWM_THYR_TIM_START, ///< Запуск таймера для ШИМ
PWM_THYR_TIM_ACTIVE, ///< Таймер активен и формирует ШИМ
PWM_THYR_TIM_DONE ///< Таймер закончил свою работу в полупериоде
@@ -60,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; ///< Флаг готовности тиристора к работе
@@ -67,7 +62,7 @@ typedef struct {
} PWM_Channel_t;
/**
* @brief Канал PWM (один тиристор)
* @brief Параметры ШИМ
*/
typedef struct {
union
@@ -80,35 +75,41 @@ typedef struct {
uint8_t phC:1;
};
}PhaseMask; ///< Какими каналами управлять
uint8_t PulseNumber; ///< Сколько импульсов отправить в пакете для открытия тиристоров
uint32_t Frequency; ///< Частота импульсов
float PulseLength; ///< Длина импульса в о.е. от 180 градусов
uint16_t Frequency; ///< Частота импульсов
float Duty; ///< Скважность импульсов
} PWM_ThyrConfig_t;
/**
* @brief Хендл управляюзщий тиристорами */
typedef struct {
PWM_ThyrConfig_t Config;
PWM_Channel_t *Phase[3]; ///< Текущие каналы для фаз
PWM_Channel_t AllPhases[7]; ///< Все каналы для фаз (+1 для деинициализированного канала)
PWM_ThyrConfig_t Config; ///< Конфигурации ШИМ
PWM_Channel_t *Phase[3]; ///< Каналы для активной в данный момент фазы
PWM_Channel_t AllPhases[7]; ///< Все каналы для фаз (+1 для деинициализированного канала)
struct {
unsigned Initialized : 1;
unsigned Running : 1; ///< true если оба таймера запущены
unsigned Running : 3; ///< Сколько каналов запущено сейчас
} f;
} PWM_Handle_t;
/* ---- API ---- */
// ====== ИНИЦИАЛИЗАЦИЯ ==========
/* Инициализация ШИМ тиристоров. */
HAL_StatusTypeDef PWM_Init(PWM_Handle_t *hpwm);
// ====== УПРАВЛЕНИЕ ==========
/* Запуск ШИМ. */
HAL_StatusTypeDef PWM_Start(PWM_Handle_t *hpwm, UPP_Phase_t Phase);
/* Остановить ШИМ. */
HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_stop);
HAL_StatusTypeDef PWM_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, float Duty, float PulseLength);
/* Установка полуволны для слежения. */
HAL_StatusTypeDef PWM_SetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase, UPP_HalfWave_t halfwave);
/* Установка полуволны для слежения. */
UPP_HalfWave_t PWM_GetHalfWave(PWM_Handle_t *hpwm, UPP_Phase_t Phase);
/* Установка полярности шим. */
HAL_StatusTypeDef PWM_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 */

243
UPP/Core/UPP/upp_errors.c Normal file
View File

@@ -0,0 +1,243 @@
/**
******************************************************************************
* @file upp_errors.c
* @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)
{
// Пока нет ошибки
UPP_ErrorType_t best = Err_None;
// Приоритет отсутствия ошибок
uint8_t best_prio = UPP_ErrorPriority[Err_None];
// Перебираем все возможные ошибки по enum
for (int e = Err_None + 1; e <= Err_UnderFrequency; e++)
{
// Проверяем: установлен ли соответствующий бит в pui.all
// e-1, потому что ошибка №1 = бит 0, ошибка №2 = бит 1 и т.д.
if (errors.pui.all & (1u << (e - 1)))
{
// Получаем приоритет этой ошибки
uint8_t pr = UPP_ErrorPriority[e];
// Если её приоритет лучше (меньше число) — запоминаем
if (pr < best_prio)
{
best_prio = pr;
best = (UPP_ErrorType_t)e;
}
}
}
// Возвращаем самую важную (наивысшего приоритета) ошибку
return best;
}
__STATIC_FORCEINLINE int setError(int condition, int flag, int *timer, int delay)
{
if (condition) {
if (*timer < delay)
(*timer)++;
else
flag = 1;
} else {
if (*timer > 0)
(*timer)--;
else
flag = 0;
}
return flag;
}

162
UPP/Core/UPP/upp_errors.h Normal file
View File

@@ -0,0 +1,162 @@
/**
******************************************************************************
* @file upp_errors.h
* @brief Ошибки УПП и их обработка
******************************************************************************
* @details
******************************************************************************/
#ifndef _UPP_ERRORS_H
#define _UPP_ERRORS_H
#include "upp_defs.h"
/**
* @brief Приоритет ПУИ ошибок
*/
static const uint8_t UPP_ErrorPriority[] =
{
[Err_None] = 255,
/* Фатальные ошибки */
[Err_LossPhaseAll] = 1,
[Err_OverCurrent] = 2,
[Err_OverVoltage] = 3,
[Err_OverTemperature] = 4,
[Err_Power_24V] = 5,
[Err_Power_Digit_5V] = 6,
[Err_Power_DIO_24V] = 7,
[Err_Power_Analog_5V] = 8,
/* Критичные */
[Err_LossPhaseA] = 10,
[Err_LossPhaseB] = 11,
[Err_LossPhaseC] = 12,
[Err_LongStart] = 13,
[Err_Interlace] = 14,
/* Пограничные параметры */
[Err_UnderVoltage] = 20,
[Err_OverFrequency] = 21,
[Err_UnderFrequency] = 22,
/* Внутренние */
[Err_Internal_1] = 40,
[Err_Internal_2] = 41,
[Err_Internal_3] = 42,
[Err_Internal_4] = 43,
[Err_Internal_5] = 44,
[Err_Internal_6] = 45,
};
/**
* @brief Структура с всеми ошибками УПП
*/
typedef struct
{
UPP_ErrorType_t common; ///< Общая ошибка @ref UPP_ErrorType_t;
union
{
uint32_t all;
struct
{
/* Програмные ошибки */
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; ///< Ошибка 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; ///< Ошибка 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 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; ///< Ошибка 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;
struct
{
union
{
uint64_t all;
struct
{
unsigned uamp_max:1;
unsigned uamp_min:1;
unsigned iamp_max:1;
unsigned iamp_min:1;
unsigned ic_max:1;
unsigned ic_min:1;
unsigned ib_max:1;
unsigned ib_min:1;
unsigned ia_max:1;
unsigned ia_min:1;
unsigned uba_max:1;
unsigned uba_min:1;
unsigned uac_max:1;
unsigned uac_min:1;
unsigned ubc_max:1;
unsigned ubc_min:1;
unsigned fba_max:1;
unsigned fba_min:1;
unsigned fac_max:1;
unsigned fac_min:1;
unsigned fbc_max:1;
unsigned fbc_min:1;
unsigned temp_warn:1;
unsigned temp_err:1;
unsigned longstart:1;
unsigned interlance:3;
unsigned 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 overrun_slow_calc;
uint16_t overrun_fast_calc;
}cnt;
}prvt; ///< Приватные ошибки, не идущие напрямую в ПУИ
}UPP_Errors_t;
extern UPP_Errors_t errors;
void UPP_Errors_Handle(void);
#endif //_UPP_ERRORS_H

143
UPP/Core/UPP/upp_io.c Normal file
View 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
View 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

View File

@@ -1,27 +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)
{
HAL_TIM_Base_Start(&ustim);
PowerMonitor_Init(&upp.pm);
upp.hpwm.Config.Frequency = 20000;
upp.hpwm.Config.PulseNumber = 20;
PWM_Init(&upp.hpwm);
Angle_Init(&upp.hangle, 0, 0.8);
upp.workmode = UPP_Init;
/* Очищаем входы */
UPP_IO_Init();
BenchTime_Init();
// Подключение указателей
upp.errors = &errors;
upp.PUI.params = &PARAM_PUI;
upp.PUI.values = &MB_DATA.InRegs.pui;
upp.call = &MB_INTERNAL.FuncCalls;
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;
}
if(UPP_Params_Init() != HAL_OK)
{
return 1;
}
return 0;
}
@@ -30,9 +63,17 @@ int UPP_Init(void)
* @return 0 - если ОК, >1 если ошибка.
*/
int UPP_PreWhile(void)
{
PowerMonitor_Start(&upp.pm);
upp.hpwm.Config.PhaseMask.all = 0x7;
{
UPP_Params_Control();
if(PowerMonitor_Start(&upp.pm) != HAL_OK)
return 1;
#ifdef MATLAB
dbg_polarity = 0;
#endif
UPP_DO.CEN(ENABLE);
return 0;
}
@@ -41,57 +82,276 @@ int UPP_PreWhile(void)
* @return 0 - если ОК, >1 если ошибка.
*/
int UPP_While(void)
{
return 0;
{
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
// если ошибка вызываем СТОП
upp.call->stop = (errors.common != Err_None);
#endif
// Сброс на дефолтные по запросу
if(upp.call->set_default_pui || upp.call->set_default_internal)
{
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;
}
// Если СТОП - переходим в ошибку
if (upp.call->stop)
upp.workmode = UPP_Error;
// Автомат состояний УПП
switch(upp.workmode)
{
/*======= Состояние Инициализация =========*/
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 = UPP_Work;
Angle_PID_Reset(&upp.hangle);
upp.StartTick = local_time();
}
break;
/*======= Состояние В работе =========*/
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 = 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))
{
ERR_PRIVATE.longstart = 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 retval;
}
// ПРЕРЫВАНИЯ stm32f4xx_it.c
/**
* @brief Всякое что будет делатся каждую 1 мс.
*/
void UPP_Tick(void)
{
// Начинаем все проверять только после того как уйдем из режима инициализации
if(upp.workmode == UPP_Init)
return;
if(GPIO_Read_Switch(&UPP_DIN.Pusk))
{
upp.call->go = 1;
}
else
{
upp.call->go = 0;
}
}
//================ ПРЕРЫВАНИЯ stm32f4xx_it.c ===================
/**
* @brief @ref DMA2_Stream0_IRQHandler
*/
void UPP_ADC_Handle(void)
{
PowerMonitor_Handle(&upp.pm);
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);
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++)
{
// Если произошел Zero Cross
if(ZC_isOccurred(&upp.pm.zc, phase))
{
// Меняем полуволну тиристора
UPP_HalfWave_t curr_halfwave = ZC_GetHalfWave(&upp.pm.zc, phase);
PWM_SetHalfWave(&upp.hpwm, phase, curr_halfwave);
Angle_Start(&upp.hangle, phase, alpha_dbg, upp.hpwm.Config.Frequency);
// Если УПП в работе
if(upp.workmode == UPP_Work)
{
// Меняем полуволну тиристора
UPP_HalfWave_t curr_halfwave = ZC_GetHalfWave(&upp.pm.zc, phase);
res = PWM_SetHalfWave(&upp.hpwm, phase, curr_halfwave);
// Начинаем отсчитывать угол
res = Angle_Start(&upp.hangle, phase, UPP_HALFWAVE_PERIOD);
if(res != HAL_OK)
__NOP();
}
}
}
}
void UPP_PWM_Handle(void)
{
PWM_Handle(&upp.hpwm);
// ШИМим ключи
res = PWM_Handle(&upp.hpwm, UPP_HALFWAVE_PERIOD);
upp.Timings.isr_adc_us = BenchTime_End(BT_ADC, angletim.Instance->CNT)/ANGLE_TIM2_FREQ_MHZ;
upp.pm.f.inIsr = 0;
}
/**
* @brief @ref HAL_TIM_OC_DelayElapsedCallback
*/
void UPP_Angle_Handle(void)
{
UPP_Phase_t phase = Angle_Handle(&upp.hangle);
res = Angle_Reset(&upp.hangle, phase);
// Если УПП в работе
if(upp.workmode == UPP_Work)
{
switch(phase)
{
case UPP_PHASE_A:
res = PWM_Start(&upp.hpwm, UPP_PHASE_A);
break;
case UPP_PHASE_B:
res = PWM_Start(&upp.hpwm, UPP_PHASE_B);
break;
case 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)
{
UPP_Angle_Handle();
}
}
void UPP_Angle_Handle(void)
{
UPP_Phase_t phase = Angle_Handle(&upp.hangle);
switch(phase)
if (htim == upp.hangle.htim)
{
case UPP_PHASE_A:
PWM_Start(&upp.hpwm, UPP_PHASE_A);
break;
case UPP_PHASE_B:
PWM_Start(&upp.hpwm, UPP_PHASE_B);
break;
case UPP_PHASE_C:
PWM_Start(&upp.hpwm, UPP_PHASE_C);
break;
default:
break;
UPP_Angle_Handle();
}
}
/**
* @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;
}

View File

@@ -1,7 +1,7 @@
/**
******************************************************************************
* @file modbus_data.h
* @brief Определения структур данных Modbus устройства
* @file upp_main.h
* @brief Определения структур для работы УПП
******************************************************************************
* @details
******************************************************************************/
@@ -9,30 +9,57 @@
#ifndef _UPP_MAIN_H
#define _UPP_MAIN_H
#include "main.h" // либы из AllLibs и вербальные имена из CubeMX
#include "upp_config.h"
#include "main.h" // общие библиотеки, конфигурации и вербальные имена из CubeMX
#include "power_monitor.h" // статистика сети и АЦП
#include "pwm_thyristors.h" // Управление тиристорами
#include "angle_control.h" // Управление углом открытия
extern float alpha_dbg;
#include "upp_status.h" // статус упп
#include "upp_params.h" // управление упп
typedef struct
{
PowerMonitor_t pm;
PWM_Handle_t hpwm;
Angle_Handle_t hangle;
UPP_WorkModeType_t workmode; ///< Режим УПП
UPP_FuncCalls_t *call; ///< Вызов функций УПП
PowerMonitor_t pm; ///< Мониторинг сети
PWM_Handle_t hpwm; ///< Хендл ШИМ тиристоров
Angle_Handle_t hangle; ///< Хендл отсчитывания угла открытия
struct
{
UPP_PUI_Params_t *params; ///< Параметры от ПУИ
UPP_PUI_Values_t *values; ///< Данные для ПУИ
} PUI; ///< Общение с ПУИ
UPP_Errors_t *errors; ///< Ошибки УПП
uint32_t StartTick;
struct
{
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);
/* Основной цикл УПП. */
int UPP_While(void);
/* Всякое что будет делатся каждую 1 мс. */
void UPP_Tick(void);
// Прерывания
void UPP_ADC_Handle(void);
void UPP_PWM_Handle(void);
void UPP_Angle_Handle(void);

578
UPP/Core/UPP/upp_params.c Normal file
View 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
View 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

12
UPP/Core/UPP/upp_status.c Normal file
View File

@@ -0,0 +1,12 @@
/**
******************************************************************************
* @file upp_status.c
* @brief Модуль определяющий состояние УПП
******************************************************************************
* @details
******************************************************************************/
#include "upp_main.h" // всё остальное по работе с УПП
void UPP_Status_Handler(void)
{
}

13
UPP/Core/UPP/upp_status.h Normal file
View File

@@ -0,0 +1,13 @@
/**
******************************************************************************
* @file upp_status.h
* @brief Модуль определяющий состояние УПП
******************************************************************************
* @details
******************************************************************************/
#ifndef _UPP_STATUS_H
#define _UPP_STATUS_H
#endif //_UPP_STATUS_H

View 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>

View 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

View 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

View File

@@ -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

View 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(α)');

View File

@@ -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);

View 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');

View 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');

View 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 )