1 Commits

Author SHA1 Message Date
Razvalyaev
f34eb8b900 тест zero cross detected 2025-05-16 08:25:29 +03:00
33 changed files with 67 additions and 386 deletions

View File

@@ -1,3 +1,4 @@
#include "upp.h"
#include "tiristor.h" #include "tiristor.h"
// управление тиристором // управление тиристором
void tiristor_control(TiristorControl_t *ctrl) void tiristor_control(TiristorControl_t *ctrl)
@@ -29,49 +30,37 @@ void tiristor_angle_update(TiristorAngleControl_t *angle)
{ {
uint32_t current_time_ms = HAL_GetTick(); uint32_t current_time_ms = HAL_GetTick();
if ((current_time_ms - angle->last_update_ms) >= angle->Init->sample_time_ms) if ((current_time_ms - angle->last_update_ms) >= angle->sample_time_ms)
{ {
angle->last_update_ms = current_time_ms; angle->last_update_ms = current_time_ms;
if(angle->Init->direction) if (angle->delay_us > angle->delay_min_us)
angle->delay_us += angle->Init->delay_step_us;
else
angle->delay_us -= angle->Init->delay_step_us;
if (angle->delay_us < angle->Init->delay_min_us)
{ {
angle->delay_us = angle->Init->delay_min_us; angle->delay_us -= angle->delay_step_us;
} if (angle->delay_us < angle->delay_min_us)
else if (angle->delay_us > angle->Init->delay_max_us) angle->delay_us = angle->delay_min_us;
{
angle->delay_us = angle->Init->delay_max_us;
} }
} }
} }
void tiristor_angle_control(TiristorControl_t *ctrl) void tiristor_angle_control(TiristorControl_t *ctrl)
{ {
tiristor_angle_update(&ctrl->angle); tiristor_angle_update(&ctrl->angle);
if(ctrl->angle.delay_us != 0) if ((uint16_t)((uint16_t)TIMER->CNT - ctrl->angle.start_delay_us) > ctrl->angle.delay_us)
{ {
if ((uint16_t)((uint16_t)TIMER->CNT - ctrl->angle.start_delay_tick) > ctrl->angle.delay_us) if(ctrl->f.TiristorDone == 0)
{ {
if(ctrl->f.TiristorReady) ctrl->f.EnableTiristor = 1;
{ ctrl->f.TiristorDone = 1;
ctrl->f.EnableTiristor = 1;
ctrl->f.TiristorReady = 0;
}
} }
} }
} }
void tiristor_start_angle_delay(TiristorControl_t *ctrl) void tiristor_start_angle_delay(TiristorControl_t *ctrl)
{ {
ctrl->f.TiristorReady = 1; ctrl->f.TiristorDone = 0;
ctrl->angle.start_delay_tick = TIMER->CNT; ctrl->angle.start_delay_us = TIMER->CNT;
} }
void tiristor_enable(TiristorControl_t *ctrl) void tiristor_enable(TiristorControl_t *ctrl)
@@ -88,17 +77,15 @@ void tiristor_disable(TiristorControl_t *ctrl)
ctrl->f.TiristorIsEnable = 0; ctrl->f.TiristorIsEnable = 0;
} }
void tiristor_angle_reset(TiristorControl_t *ctrl)
{
if(ctrl->angle.Init->direction)
ctrl->angle.delay_us = ctrl->angle.Init->delay_min_us;
else
ctrl->angle.delay_us = ctrl->angle.Init->delay_max_us;
}
void tiristor_init(TiristorControl_t *ctrl, GPIO_TypeDef *gpiox, uint32_t gpio_pin) void tiristor_init(TiristorControl_t *ctrl, GPIO_TypeDef *gpiox, uint32_t gpio_pin)
{ {
ctrl->gpiox = gpiox; ctrl->gpiox = gpiox;
ctrl->gpio_pin = gpio_pin; ctrl->gpio_pin = gpio_pin;
tiristor_angle_reset(ctrl); ctrl->angle.delay_max_us = 8000;
ctrl->angle.delay_min_us = 100;
ctrl->angle.delay_us = 7000;
ctrl->angle.delay_step_us = 500;
ctrl->angle.sample_time_ms = 100;
ctrl->open_time = 1;
TIMER->CR1 |= TIM_CR1_CEN;
} }

View File

@@ -15,24 +15,20 @@ typedef struct
{ {
unsigned EnableTiristor:1; unsigned EnableTiristor:1;
unsigned TiristorIsEnable:1; unsigned TiristorIsEnable:1;
unsigned TiristorReady:1; unsigned TiristorDone:1;
}TiristorControlFlags; }TiristorControlFlags;
typedef struct
{
uint32_t delay_min_us; // Минимальная задержка (максимальное открытие тиристора)
uint32_t delay_max_us; // Начальная задержка (практически закрыт)
uint32_t delay_step_us; // Шаг уменьшения задержки
uint32_t sample_time_ms; // Интервал между шагами (например, 200 мс)
unsigned direction; // Направление разгон/торможение
}AngleInit_t;
typedef struct typedef struct
{ {
AngleInit_t *Init;
uint32_t last_update_ms; // Время последнего обновления
uint32_t delay_us; // Текущая задержка (в микросекундах) uint32_t delay_us; // Текущая задержка (в микросекундах)
uint16_t start_delay_tick; uint32_t delay_min_us; // Минимальная задержка (максимальное открытие тиристора)
uint32_t delay_max_us; // Начальная задержка (практически закрыт)
uint32_t delay_step_us; // Шаг уменьшения задержки
uint32_t last_update_ms; // Время последнего обновления
uint32_t sample_time_ms; // Интервал между шагами (например, 200 мс)
uint16_t start_delay_us;
}TiristorAngleControl_t; }TiristorAngleControl_t;
typedef struct TiristorControl_t TiristorControl_t; typedef struct TiristorControl_t TiristorControl_t;
@@ -52,7 +48,6 @@ void tiristor_control(TiristorControl_t *ctrl);
void tiristor_angle_update(TiristorAngleControl_t *angle); void tiristor_angle_update(TiristorAngleControl_t *angle);
void tiristor_angle_control(TiristorControl_t *ctrl); void tiristor_angle_control(TiristorControl_t *ctrl);
void tiristor_start_angle_delay(TiristorControl_t* ctrl); void tiristor_start_angle_delay(TiristorControl_t* ctrl);
void tiristor_angle_reset(TiristorControl_t *ctrl);
void tiristor_enable(TiristorControl_t *ctrl); void tiristor_enable(TiristorControl_t *ctrl);
void tiristor_disable(TiristorControl_t *ctrl); void tiristor_disable(TiristorControl_t *ctrl);
void tiristor_init(TiristorControl_t *ctrl, GPIO_TypeDef *gpiox, uint32_t gpio_pin); void tiristor_init(TiristorControl_t *ctrl, GPIO_TypeDef *gpiox, uint32_t gpio_pin);

View File

@@ -3,184 +3,16 @@
Phase_t phase_A; Phase_t phase_A;
Phase_t phase_B; Phase_t phase_B;
Phase_t phase_C; Phase_t phase_C;
UPP_Control_t Upp;
// главная функция // главная функция
void upp_main(void) void upp_main(void)
{
if(GetAngleInit(&Upp.angleInit))
{
tiristor_angle_reset(&phase_A.ctrl);
tiristor_angle_reset(&phase_B.ctrl);
tiristor_angle_reset(&phase_C.ctrl);
}
// безопасный запуск
upp_safe_go();
// останавливаем УПП (убираем питание с выхода упп) если выставлен флаг
if(Upp.ForceStop)
{
Upp.Go = 0;
connect_upp();
return;
}
if(Upp.ForceDisconnect)
{
phase_A.ctrl.f.TiristorReady = 1;
phase_B.ctrl.f.TiristorReady = 1;
phase_C.ctrl.f.TiristorReady = 1;
Upp.Go = 0;
disconnect_upp();
return;
}
// отключаем упп если выставлен флаг
if(Upp.GoDisconnect)
{
phase_A.ctrl.f.TiristorReady = 1;
phase_B.ctrl.f.TiristorReady = 1;
phase_C.ctrl.f.TiristorReady = 1;
disconnect_upp();
}
// останавливаем упп если выставлен флаг
if(Upp.GoStop)
{
Upp.Go = 0;
connect_upp();
}
if(Upp.Prepare)
{
if(Upp.Disconnected)
{
connect_upp();
}
upp_phase_routine(&phase_A);
upp_phase_routine(&phase_B);
upp_phase_routine(&phase_C);
}
if(Upp.Go)
{
if(Upp.Prepare)
{
if(phase_A.ctrl.f.TiristorReady && phase_B.ctrl.f.TiristorReady && phase_C.ctrl.f.TiristorReady)
{
Upp.Prepare = 0;
}
else
{
return;
}
}
if(Upp.Disconnected)
{
Upp.ForceStop = 1;
return;
}
// если все фазы дошли до минимума в режиме разгона, то выставляем флаг на отключение упп (прямая подача питания на двигатель)
if( (phase_A.ctrl.angle.delay_us == phase_A.ctrl.angle.Init->delay_min_us) &&
(phase_B.ctrl.angle.delay_us == phase_B.ctrl.angle.Init->delay_min_us) &&
(phase_C.ctrl.angle.delay_us == phase_C.ctrl.angle.Init->delay_min_us) && (Upp.angleInit.direction == 0))
{
Upp.GoDisconnect = 1;
}
else
{
Upp.GoDisconnect = 0;
}
// если все фазы дошли до максимума в режиме торможения, то выставляем флаг на остановку упп (выключения питания на двигателе)
if( (phase_A.ctrl.angle.delay_us == phase_A.ctrl.angle.Init->delay_max_us) &&
(phase_B.ctrl.angle.delay_us == phase_B.ctrl.angle.Init->delay_max_us) &&
(phase_C.ctrl.angle.delay_us == phase_C.ctrl.angle.Init->delay_max_us) && (Upp.angleInit.direction == 1))
{
Upp.GoStop = 1;
}
else
{
Upp.GoStop = 0;
}
upp_phase_routine(&phase_A);
upp_phase_routine(&phase_B);
upp_phase_routine(&phase_C);
upp_phase_control(&phase_A);
upp_phase_control(&phase_B);
upp_phase_control(&phase_C);
}
else
{
tiristor_angle_reset(&phase_A.ctrl);
tiristor_angle_reset(&phase_B.ctrl);
tiristor_angle_reset(&phase_C.ctrl);
}
}
void upp_safe_go(void)
{
static int prev_gosafe;
if(Upp.GoSafe > prev_gosafe)
{
Upp.angleInit.direction = 0;
Upp.Prepare = 1;
Upp.Go = 1;
tiristor_angle_reset(&phase_A.ctrl);
tiristor_angle_reset(&phase_B.ctrl);
tiristor_angle_reset(&phase_C.ctrl);
}
else if (Upp.GoSafe < prev_gosafe)
{
Upp.angleInit.direction = 1;
Upp.Prepare = 1;
Upp.Go = 1;
tiristor_angle_reset(&phase_A.ctrl);
tiristor_angle_reset(&phase_B.ctrl);
tiristor_angle_reset(&phase_C.ctrl);
}
prev_gosafe = Upp.GoSafe;
}
void disconnect_upp(void)
{ {
if(phase_A.ctrl.f.TiristorReady) upp_phase_routine(&phase_A);
{ upp_phase_routine(&phase_B);
disconnect_phase(&phase_A); upp_phase_routine(&phase_C);
}
if(phase_B.ctrl.f.TiristorReady)
{
disconnect_phase(&phase_B);
}
if(phase_C.ctrl.f.TiristorReady)
{
disconnect_phase(&phase_C);
}
if(phase_A.disconnect.Disconnected && phase_B.disconnect.Disconnected && phase_C.disconnect.Disconnected)
{
Upp.Disconnected = 1;
Upp.GoDisconnect = 0;
Upp.Go = 0;
}
}
void connect_upp(void)
{
tiristor_disable(&phase_A.ctrl);
tiristor_disable(&phase_B.ctrl);
tiristor_disable(&phase_C.ctrl);
connect_phase(&phase_A); // upp_phase_control(&phase_A);
connect_phase(&phase_B); // upp_phase_control(&phase_B);
connect_phase(&phase_C); // upp_phase_control(&phase_C);
Upp.Disconnected = 0;
} }
void upp_phase_control(Phase_t *phase) void upp_phase_control(Phase_t *phase)
@@ -194,116 +26,20 @@ void upp_phase_routine(Phase_t *phase)
zero_cross_update(&phase->zc_detector); zero_cross_update(&phase->zc_detector);
if(is_zero_cross(&phase->zc_detector)) if(is_zero_cross(&phase->zc_detector))
{ {
tiristor_start_angle_delay(&phase->ctrl); phase->ctrl.gpiox->ODR ^= phase->ctrl.gpio_pin;
// tiristor_start_angle_delay(&phase->ctrl);
if (phase->ctrl.f.TiristorIsEnable) // if (phase->ctrl.f.TiristorIsEnable)
tiristor_disable(&phase->ctrl); // tiristor_disable(&phase->ctrl);
} }
} }
int GetAngleInit(AngleInit_t *angle)
{
static float sine_freq_old = 0;
static float Duration_old = 0;
static float max_duty_old = 0, min_duty_old = 0; // Задаются в процентах
int update = 0;
if( (Upp.sine_freq != sine_freq_old) &&
(Upp.max_duty != max_duty_old) &&
(Upp.min_duty != min_duty_old) )
{
update = 1;
min_duty_old = Upp.min_duty;
max_duty_old = Upp.max_duty;
sine_freq_old = Upp.sine_freq;
}
if(Upp.Duration != Duration_old)
{
update = 1;
Duration_old = Upp.Duration;
}
if(update)
{
// max/min duty
uint32_t half_period_us = (500000.0f / Upp.sine_freq) - 1000; // полупериод в мкс - время открытия тиристоры
angle->delay_max_us = (uint32_t)(Upp.max_duty * half_period_us);
angle->delay_min_us = (uint32_t)(Upp.min_duty * half_period_us);
if((angle->delay_max_us > 0xFFFF) || (angle->delay_min_us > 0xFFFF))
{
// увеличение прескалера в 10 раз (с 1мкс до 10мкс, с 7Гц до 0.7Гц)
angle->delay_max_us /= 10;
angle->delay_min_us /= 10;
TIMER->PSC = 719;
if((angle->delay_max_us > 0xFFFF) || (angle->delay_min_us > 0xFFFF))
{
// увеличение прескалера в 10 раз (с 10мкс до 0,1мс, с 0.7Гц до 0.07 Гц)
angle->delay_max_us /= 10;
angle->delay_min_us /= 10;
TIMER->PSC = 7299;
if ((angle->delay_max_us > 0xFFFF) || (angle->delay_min_us > 0xFFFF))
{
// если все еще переполнение то выключаем всё
Upp.ForceStop = 1;
}
}
}
else
{
TIMER->PSC = 71;
}
// duration
float duration_ms = Duration_old * 1000.0f;
uint32_t steps = duration_ms / angle->sample_time_ms;
if (steps == 0) steps = 1;
if (angle->delay_max_us > angle->delay_min_us)
angle->delay_step_us = (angle->delay_max_us - angle->delay_min_us) / steps;
else
angle->delay_step_us = 0;
}
return update;
}
void upp_init(void) void upp_init(void)
{ {
Upp.max_duty = 0.9;
Upp.min_duty = 0.1;
Upp.angleInit.sample_time_ms = 100;
phase_A.disconnect.gpiox = GPIOA;
phase_A.disconnect.gpio_pin = GPIO_PIN_5;
phase_B.disconnect.gpiox = GPIOA;
phase_B.disconnect.gpio_pin = GPIO_PIN_6;
phase_C.disconnect.gpiox = GPIOA;
phase_C.disconnect.gpio_pin = GPIO_PIN_7;
phase_A.ctrl.angle.Init = &Upp.angleInit;
phase_B.ctrl.angle.Init = &Upp.angleInit;
phase_C.ctrl.angle.Init = &Upp.angleInit;
tiristor_init(&phase_A.ctrl, GPIOB, GPIO_PIN_12); tiristor_init(&phase_A.ctrl, GPIOB, GPIO_PIN_12);
tiristor_init(&phase_B.ctrl, GPIOB, GPIO_PIN_13); tiristor_init(&phase_B.ctrl, GPIOB, GPIO_PIN_13);
tiristor_init(&phase_C.ctrl, GPIOB, GPIO_PIN_14); tiristor_init(&phase_C.ctrl, GPIOB, GPIO_PIN_14);
TIMER->CR1 |= TIM_CR1_CEN;
tiristor_angle_reset(&phase_A.ctrl);
tiristor_angle_reset(&phase_B.ctrl);
tiristor_angle_reset(&phase_C.ctrl);
#ifndef HARDWARE_ZERO_CROSS_DETECT #ifndef HARDWARE_ZERO_CROSS_DETECT
adc_Attach(&phase_A.zc_detector.AdcFilter, &hadc); adc_Attach(&phase_A.zc_detector.AdcFilter, &hadc);
zero_cross_Init(&phase_A.zc_detector, ADC_INITIAL_ZERO_LEVEL); zero_cross_Init(&phase_A.zc_detector, ADC_INITIAL_ZERO_LEVEL);
@@ -311,6 +47,5 @@ void upp_init(void)
adc_Attach(&phase_A.zc_detector.AdcFilter, &hadc); adc_Attach(&phase_A.zc_detector.AdcFilter, &hadc);
zero_cross_Init(&phase_A.zc_detector, ADC_INITIAL_ZERO_LEVEL); zero_cross_Init(&phase_A.zc_detector, ADC_INITIAL_ZERO_LEVEL);
#endif #endif
//Upp.GoSafe = 1;
} }

View File

@@ -11,58 +11,20 @@
#define hadc hadc1 #define hadc hadc1
#define ADC_INITIAL_ZERO_LEVEL 2048 #define ADC_INITIAL_ZERO_LEVEL 2048
#define disconnect_phase(_ph_) { (_ph_)->disconnect.gpiox->ODR |= (_ph_)->disconnect.gpio_pin; (_ph_)->disconnect.Disconnected = 1;}
#define connect_phase(_ph_) { (_ph_)->disconnect.gpiox->ODR &= ~(_ph_)->disconnect.gpio_pin; (_ph_)->disconnect.Disconnected = 0;}
typedef struct typedef struct
{ {
struct
{
unsigned Disconnected:1;
GPIO_TypeDef *gpiox;
uint32_t gpio_pin;
}disconnect;
ZeroCrossDetector_t zc_detector; ZeroCrossDetector_t zc_detector;
TiristorControl_t ctrl; TiristorControl_t ctrl;
} Phase_t; // структура для фазы } Phase_t; // структура для фазы
typedef struct
{
unsigned GoSafe:1;
unsigned Go:1;
unsigned GoStop:1;
unsigned Prepare:1;
unsigned Disconnected:1;
unsigned GoDisconnect:1;
unsigned ForceStop:1;
unsigned ForceDisconnect:1;
unsigned PreGoDone:1;
float Duration;
float sine_freq;
float max_duty;
float min_duty;
AngleInit_t angleInit;
}UPP_Control_t;
extern Phase_t phase_A; extern Phase_t phase_A;
extern Phase_t phase_B; extern Phase_t phase_B;
extern Phase_t phase_C; extern Phase_t phase_C;
extern UPP_Control_t Upp;
void upp_main(void); void upp_main(void);
void upp_safe_go(void);
void disconnect_upp(void);
void connect_upp(void);
void upp_phase_routine(Phase_t *phase); void upp_phase_routine(Phase_t *phase);
void upp_phase_control(Phase_t *phase); void upp_phase_control(Phase_t *phase);
int GetAngleInit(AngleInit_t *angle);
void upp_init(void); void upp_init(void);

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
upp/tiristor.o: ..\Core\upp\tiristor.c ..\Core\upp\tiristor.h \ upp/tiristor.o: ..\Core\upp\tiristor.c ..\Core\upp\upp.h \
..\Core\Inc\main.h ..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal.h \ ..\Core\Inc\main.h ..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal.h \
..\Core\Inc\stm32f1xx_hal_conf.h \ ..\Core\Inc\stm32f1xx_hal_conf.h \
..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_rcc.h \ ..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_rcc.h \
@@ -30,4 +30,6 @@ upp/tiristor.o: ..\Core\upp\tiristor.c ..\Core\upp\tiristor.h \
..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_tim.h \ ..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_tim.h \
..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_tim_ex.h \ ..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_tim_ex.h \
..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_uart.h \ ..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_uart.h \
..\Core\Inc\tim.h ..\Core\Inc\adc.h ..\Core\Inc\tim.h ..\Core\Inc\usart.h \
..\Core\Inc\gpio.h ..\Core\upp\zero_cross.h ..\Core\upp\adc_filter.h \
..\Core\upp\tiristor.h

Binary file not shown.