Добавлены комменты
This commit is contained in:
parent
416260c9e1
commit
95a022d6c1
@ -1,35 +1,63 @@
|
||||
#include "adc_filter.h"
|
||||
|
||||
/**
|
||||
* @brief Привязка структуры фильтра к конкретному АЦП
|
||||
* @param hfilter Указатель на структуру ADCFilter_t
|
||||
* @param hadc Указатель на структуру HAL АЦП
|
||||
*/
|
||||
void adc_Attach(ADCFilter_t *hfilter, ADC_HandleTypeDef *hadc)
|
||||
{
|
||||
// Связываем фильтр с конкретным аппаратным АЦП для чтения данных
|
||||
hfilter->hadc = hadc;
|
||||
}
|
||||
// фильтрация
|
||||
|
||||
/**
|
||||
* @brief Обновление и фильтрация новых данных АЦП методом усреднения
|
||||
* @param hfilter Указатель на структуру ADCFilter_t
|
||||
* @return int Возвращает 1, если произведено обновление отфильтрованных данных, иначе 0
|
||||
*/
|
||||
int adc_filterring(ADCFilter_t *hfilter)
|
||||
{
|
||||
// Добавляем текущее значение из регистра данных АЦП в сумму
|
||||
hfilter->sum += hfilter->hadc->Instance->DR;
|
||||
// Увеличиваем счётчик накопленных выборок
|
||||
hfilter->count++;
|
||||
|
||||
// Если набрано достаточное количество выборок для усреднения
|
||||
if (hfilter->count >= hfilter->bufferSize)
|
||||
{
|
||||
// Вычисляем среднее значение и сохраняем как отфильтрованный результат
|
||||
hfilter->AdcResult = hfilter->sum / hfilter->bufferSize;
|
||||
// Сбрасываем сумму и счётчик для следующего цикла
|
||||
hfilter->sum = 0;
|
||||
hfilter->count = 0;
|
||||
hfilter->f.DataUpdated = 1;
|
||||
// Отмечаем, что новые данные отфильтрованы и готовы к чтению
|
||||
hfilter->f.DataUpdated = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Если ещё недостаточно данных, возвращаем 0 — фильтрация не завершена
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Чтение последнего отфильтрованного значения АЦП
|
||||
* @param hfilter Указатель на структуру ADCFilter_t
|
||||
* @return uint16_t Последнее отфильтрованное значение
|
||||
*/
|
||||
uint16_t adc_read_data(ADCFilter_t *hfilter)
|
||||
{
|
||||
hfilter->f.DataUpdated = 0;
|
||||
return hfilter->AdcResult;
|
||||
// После чтения сбрасываем флаг обновления данных
|
||||
hfilter->f.DataUpdated = 0;
|
||||
return hfilter->AdcResult;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Проверка, обновились ли данные АЦП после фильтрации
|
||||
* @param hfilter Указатель на структуру ADCFilter_t
|
||||
* @return int Возвращает 1, если данные были обновлены, иначе 0
|
||||
*/
|
||||
int adc_is_data_updated(ADCFilter_t *hfilter)
|
||||
{
|
||||
return hfilter->f.DataUpdated;
|
||||
}
|
||||
return hfilter->f.DataUpdated;
|
||||
}
|
||||
|
@ -3,25 +3,37 @@
|
||||
|
||||
#include "main.h"
|
||||
|
||||
/**
|
||||
* @brief Флаги состояния фильтра АЦП
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
unsigned DataUpdated:1;
|
||||
}AdcFilterFlags;
|
||||
unsigned DataUpdated : 1; /**< Флаг обновления данных */
|
||||
} AdcFilterFlags;
|
||||
|
||||
// структура для ацп
|
||||
/**
|
||||
* @brief Структура фильтрации данных АЦП
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
AdcFilterFlags f;
|
||||
uint16_t AdcResult;
|
||||
ADC_HandleTypeDef *hadc;
|
||||
uint32_t sum;
|
||||
uint16_t count;
|
||||
uint16_t bufferSize;
|
||||
AdcFilterFlags f; /**< Флаги состояния */
|
||||
uint16_t AdcResult; /**< Отфильтрованное значение АЦП */
|
||||
ADC_HandleTypeDef *hadc; /**< Указатель на структуру HAL АЦП */
|
||||
uint32_t sum; /**< Сумма накопленных значений для усреднения */
|
||||
uint16_t count; /**< Текущий счётчик накопленных значений */
|
||||
uint16_t bufferSize; /**< Размер буфера для усреднения (число выборок) */
|
||||
} ADCFilter_t;
|
||||
|
||||
/** Привязка структуры фильтра к конкретному АЦП */
|
||||
void adc_Attach(ADCFilter_t *hfilter, ADC_HandleTypeDef *hadc);
|
||||
|
||||
/** Обновление и фильтрация нового значения АЦП */
|
||||
int adc_filterring(ADCFilter_t *hfilter);
|
||||
|
||||
/** Чтение последнего отфильтрованного значения АЦП */
|
||||
uint16_t adc_read_data(ADCFilter_t *hfilter);
|
||||
|
||||
/** Проверка, обновились ли данные АЦП после фильтрации */
|
||||
int adc_is_data_updated(ADCFilter_t *hfilter);
|
||||
|
||||
#endif //__ADC_FILTER_H
|
||||
#endif //__ADC_FILTER_H
|
||||
|
@ -1,104 +1,142 @@
|
||||
#include "tiristor.h"
|
||||
// управление тиристором
|
||||
|
||||
/**
|
||||
* @brief Управление состоянием тиристора (включение/выключение) по флагам и времени открытия
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
void tiristor_control(TiristorControl_t *ctrl)
|
||||
{
|
||||
if(ctrl->f.EnableTiristor)
|
||||
{
|
||||
if(ctrl->f.TiristorIsEnable == 0)
|
||||
{
|
||||
tiristor_enable(ctrl);
|
||||
ctrl->enable_start_tick = HAL_GetTick();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(HAL_GetTick() - ctrl->enable_start_tick > ctrl->open_time)
|
||||
{
|
||||
tiristor_disable(ctrl);
|
||||
ctrl->f.EnableTiristor = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ctrl->f.TiristorIsEnable)
|
||||
tiristor_disable(ctrl);
|
||||
}
|
||||
if(ctrl->f.EnableTiristor) // Если разрешено включить тиристор
|
||||
{
|
||||
if(ctrl->f.TiristorIsEnable == 0) // Если тиристор еще выключен
|
||||
{
|
||||
tiristor_enable(ctrl); // Включить тиристор
|
||||
ctrl->enable_start_tick = HAL_GetTick(); // Запомнить время включения для отсчёта длительности открытия
|
||||
}
|
||||
else
|
||||
{
|
||||
// Если время с момента включения превысило заданное время открытия
|
||||
if(HAL_GetTick() - ctrl->enable_start_tick > ctrl->open_time)
|
||||
{
|
||||
tiristor_disable(ctrl); // Выключить тиристор
|
||||
ctrl->f.EnableTiristor = 0; // Снять разрешение на включение, чтобы не включался снова без команды
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Если тиристор не должен быть включен
|
||||
{
|
||||
if(ctrl->f.TiristorIsEnable) // Если тиристор включен
|
||||
tiristor_disable(ctrl); // Выключить тиристор
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обновление значения задержки угла открытия тиристора в соответствии с направлением и шагом
|
||||
* @param angle Указатель на структуру управления углом тиристора
|
||||
*/
|
||||
void tiristor_angle_update(TiristorAngleControl_t *angle)
|
||||
{
|
||||
uint32_t current_time_ms = HAL_GetTick();
|
||||
|
||||
if ((current_time_ms - angle->last_update_ms) >= angle->Init->sample_time_ms)
|
||||
{
|
||||
angle->last_update_ms = current_time_ms;
|
||||
{
|
||||
uint32_t current_time_ms = HAL_GetTick(); // Текущее время в миллисекундах
|
||||
|
||||
if(angle->Init->direction)
|
||||
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;
|
||||
}
|
||||
else if (angle->delay_us > angle->Init->delay_max_us)
|
||||
{
|
||||
angle->delay_us = angle->Init->delay_max_us;
|
||||
}
|
||||
}
|
||||
// Проверяем, прошло ли нужное время с последнего обновления
|
||||
if ((current_time_ms - angle->last_update_ms) >= angle->Init->sample_time_ms)
|
||||
{
|
||||
angle->last_update_ms = current_time_ms; // Обновляем время последнего изменения задержки
|
||||
|
||||
// Изменяем задержку в зависимости от направления (разгон или торможение)
|
||||
if(angle->Init->direction)
|
||||
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;
|
||||
}
|
||||
else if (angle->delay_us > angle->Init->delay_max_us)
|
||||
{
|
||||
angle->delay_us = angle->Init->delay_max_us;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Контроль угла открытия тиристора с проверкой таймера и флага готовности
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
void tiristor_angle_control(TiristorControl_t *ctrl)
|
||||
{
|
||||
tiristor_angle_update(&ctrl->angle);
|
||||
|
||||
if(ctrl->angle.delay_us != 0)
|
||||
{
|
||||
if ((uint16_t)((uint16_t)TIMER->CNT - ctrl->angle.start_delay_tick) > ctrl->angle.delay_us)
|
||||
{
|
||||
if(ctrl->f.TiristorReady)
|
||||
{
|
||||
ctrl->f.EnableTiristor = 1;
|
||||
ctrl->f.TiristorReady = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
tiristor_angle_update(&ctrl->angle); // Обновляем задержку угла открытия
|
||||
|
||||
if(ctrl->angle.delay_us != 0) // Если задержка не нулевая
|
||||
{
|
||||
// Проверяем, прошла ли задержка с момента старта отсчёта таймера
|
||||
if ((uint16_t)((uint16_t)TIMER->CNT - ctrl->angle.start_delay_tick) > ctrl->angle.delay_us)
|
||||
{
|
||||
if(ctrl->f.TiristorReady) // Если тиристор готов к включению
|
||||
{
|
||||
ctrl->f.EnableTiristor = 1; // Разрешаем включение тиристора
|
||||
ctrl->f.TiristorReady = 0; // Снимаем флаг готовности, чтобы не включать повторно сразу
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Запуск отсчёта задержки для открытия тиристора
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
void tiristor_start_angle_delay(TiristorControl_t *ctrl)
|
||||
{
|
||||
ctrl->f.TiristorReady = 1;
|
||||
ctrl->angle.start_delay_tick = TIMER->CNT;
|
||||
ctrl->f.TiristorReady = 1; // Устанавливаем флаг готовности тиристора к включению
|
||||
ctrl->angle.start_delay_tick = TIMER->CNT; // Запоминаем текущее значение счётчика таймера
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Включение тиристора путём установки GPIO в состояние открытия
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
void tiristor_enable(TiristorControl_t *ctrl)
|
||||
{
|
||||
//HAL_GPIO_WritePin(ctrl->gpiox, ctrl->gpio_pin, GPIO_TIRISTOR_OPEN);
|
||||
ctrl->gpiox->ODR |= ctrl->gpio_pin;
|
||||
ctrl->f.TiristorIsEnable = 1;
|
||||
// Открываем тиристор, установив соответствующий пин в высокое состояние
|
||||
ctrl->gpiox->ODR |= ctrl->gpio_pin;
|
||||
ctrl->f.TiristorIsEnable = 1; // Устанавливаем флаг, что тиристор включен
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Выключение тиристора путём установки GPIO в состояние закрытия
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
void tiristor_disable(TiristorControl_t *ctrl)
|
||||
{
|
||||
ctrl->gpiox->ODR &= ~ctrl->gpio_pin;
|
||||
//HAL_GPIO_WritePin(ctrl->gpiox, ctrl->gpio_pin, GPIO_TIRISTOR_CLOSE);
|
||||
ctrl->f.TiristorIsEnable = 0;
|
||||
// Закрываем тиристор, сбросив соответствующий пин в низкое состояние
|
||||
ctrl->gpiox->ODR &= ~ctrl->gpio_pin;
|
||||
ctrl->f.TiristorIsEnable = 0; // Снимаем флаг включения тиристора
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Сброс значения задержки угла открытия тиристора к начальному в зависимости от направления
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
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;
|
||||
// В зависимости от направления устанавливаем задержку на минимальное или максимальное значение
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация структуры управления тиристором, установка GPIO и сброс угла открытия
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
* @param gpiox Указатель на порт GPIO
|
||||
* @param gpio_pin Номер пина GPIO
|
||||
*/
|
||||
void tiristor_init(TiristorControl_t *ctrl, GPIO_TypeDef *gpiox, uint32_t gpio_pin)
|
||||
{
|
||||
ctrl->gpiox = gpiox;
|
||||
ctrl->gpio_pin = gpio_pin;
|
||||
tiristor_angle_reset(ctrl);
|
||||
}
|
||||
ctrl->gpiox = gpiox; // Сохраняем порт GPIO
|
||||
ctrl->gpio_pin = gpio_pin; // Сохраняем номер пина GPIO
|
||||
tiristor_angle_reset(ctrl); // Сбрасываем угол открытия тиристора на начальное значение
|
||||
}
|
||||
|
@ -5,55 +5,108 @@
|
||||
#include "tim.h"
|
||||
|
||||
|
||||
#define GPIO_TIRISTOR_OPEN GPIO_PIN_SET
|
||||
#define GPIO_TIRISTOR_CLOSE GPIO_PIN_RESET
|
||||
#define GPIO_TIRISTOR_OPEN GPIO_PIN_SET /**< Состояние GPIO для открытия тиристора */
|
||||
#define GPIO_TIRISTOR_CLOSE GPIO_PIN_RESET /**< Состояние GPIO для закрытия тиристора */
|
||||
|
||||
#define TIMER TIM2 /**< Таймер, используемый для управления тиристором */
|
||||
|
||||
#define TIMER TIM2
|
||||
|
||||
/**
|
||||
* @brief Флаги состояния управления тиристором
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
unsigned EnableTiristor:1;
|
||||
unsigned TiristorIsEnable:1;
|
||||
unsigned TiristorReady:1;
|
||||
}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;
|
||||
unsigned EnableTiristor:1; /**< Флаг разрешения управления тиристором */
|
||||
unsigned TiristorIsEnable:1; /**< Флаг, указывающий, что тиристор включен */
|
||||
unsigned TiristorReady:1; /**< Флаг готовности тиристора к работе */
|
||||
} TiristorControlFlags;
|
||||
|
||||
/**
|
||||
* @brief Параметры инициализации угла открытия тиристора
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
AngleInit_t *Init;
|
||||
|
||||
uint32_t last_update_ms; // Время последнего обновления
|
||||
uint32_t delay_us; // Текущая задержка (в микросекундах)
|
||||
uint16_t start_delay_tick;
|
||||
}TiristorAngleControl_t;
|
||||
uint32_t delay_min_us; /**< Минимальная задержка (микросекунды), соответствует максимальному открытию тиристора */
|
||||
uint32_t delay_max_us; /**< Начальная задержка (микросекунды), соответствует практически закрытому тиристору */
|
||||
uint32_t delay_step_us; /**< Шаг уменьшения задержки (микросекунды) */
|
||||
uint32_t sample_time_ms; /**< Интервал времени между шагами регулировки (миллисекунды) */
|
||||
unsigned direction; /**< Направление регулировки: разгон (увеличение открытого угла) или торможение */
|
||||
} AngleInit_t;
|
||||
|
||||
/**
|
||||
* @brief Структура управления углом открытия тиристора
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
AngleInit_t *Init; /**< Указатель на структуру параметров инициализации угла */
|
||||
uint32_t last_update_ms; /**< Время последнего обновления (миллисекунды) */
|
||||
uint32_t delay_us; /**< Текущая задержка (микросекунды) */
|
||||
uint16_t start_delay_tick; /**< Значение таймера при старте задержки */
|
||||
} TiristorAngleControl_t;
|
||||
|
||||
typedef struct TiristorControl_t TiristorControl_t;
|
||||
|
||||
/**
|
||||
* @brief Основная структура управления тиристором
|
||||
*/
|
||||
struct TiristorControl_t
|
||||
{
|
||||
TiristorControlFlags f;
|
||||
TiristorAngleControl_t angle;
|
||||
GPIO_TypeDef *gpiox;
|
||||
uint32_t gpio_pin;
|
||||
uint32_t open_time;
|
||||
uint32_t enable_start_tick;
|
||||
|
||||
void (*start_delay)(TiristorControl_t *ctrl); // Указатель на функцию запуска задержки включения
|
||||
TiristorControlFlags f; /**< Флаги состояния тиристора */
|
||||
TiristorAngleControl_t angle; /**< Управление углом открытия */
|
||||
GPIO_TypeDef *gpiox; /**< Порт GPIO для управления тиристором */
|
||||
uint32_t gpio_pin; /**< Номер пина GPIO */
|
||||
uint32_t open_time; /**< Время открытия тиристора */
|
||||
uint32_t enable_start_tick; /**< Время включения тиристора по таймеру */
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Управление состоянием тиристора (включение/выключение)
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
void tiristor_control(TiristorControl_t *ctrl);
|
||||
|
||||
/**
|
||||
* @brief Обновление угла открытия тиристора согласно параметрам
|
||||
* @param angle Указатель на структуру управления углом тиристора
|
||||
*/
|
||||
void tiristor_angle_update(TiristorAngleControl_t *angle);
|
||||
|
||||
/**
|
||||
* @brief Контроль угла открытия тиристора, включая обновление состояния
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
void tiristor_angle_control(TiristorControl_t *ctrl);
|
||||
|
||||
/**
|
||||
* @brief Запуск задержки открытия тиристора
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
void tiristor_start_angle_delay(TiristorControl_t* ctrl);
|
||||
|
||||
/**
|
||||
* @brief Сброс угла открытия тиристора к начальному состоянию
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
void tiristor_angle_reset(TiristorControl_t *ctrl);
|
||||
|
||||
/**
|
||||
* @brief Включение тиристора
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
void tiristor_enable(TiristorControl_t *ctrl);
|
||||
|
||||
/**
|
||||
* @brief Выключение тиристора
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
*/
|
||||
void tiristor_disable(TiristorControl_t *ctrl);
|
||||
|
||||
/**
|
||||
* @brief Инициализация структуры управления тиристором
|
||||
* @param ctrl Указатель на структуру управления тиристором
|
||||
* @param gpiox Указатель на GPIO порт
|
||||
* @param gpio_pin Номер GPIO пина
|
||||
*/
|
||||
void tiristor_init(TiristorControl_t *ctrl, GPIO_TypeDef *gpiox, uint32_t gpio_pin);
|
||||
#endif //__TIRISTORS_H
|
||||
|
||||
#endif //__TIRISTORS_H
|
||||
|
@ -1,207 +1,299 @@
|
||||
#include "upp.h"
|
||||
|
||||
Phase_t phase_A;
|
||||
Phase_t phase_B;
|
||||
Phase_t phase_C;
|
||||
UPP_Control_t Upp;
|
||||
// главная функция
|
||||
void upp_main(void)
|
||||
Phase_t phase_A; /*< Фаза управления тиристорами A */
|
||||
Phase_t phase_B; /*< Фаза управления тиристорами B */
|
||||
Phase_t phase_C; /*< Фаза управления тиристорами C */
|
||||
UPP_Control_t Upp; /*< Структура управления УПП */
|
||||
|
||||
/**
|
||||
* @brief Главная функция управления УПП
|
||||
*
|
||||
* @details Выполняет основную логику управления пускателем:
|
||||
* инициализация углов, безопасный запуск,
|
||||
* проверка флагов остановки/отключения,
|
||||
* управление фазами и тиристорами.
|
||||
*/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;
|
||||
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();
|
||||
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;
|
||||
Upp.Go = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
// Если работа разрешена (флаг Go)
|
||||
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;
|
||||
}
|
||||
|
||||
// если все фазы дошли до минимума в режиме разгона, то выставляем флаг на отключение упп (прямая подача питания на двигатель)
|
||||
// Проверяем условие достижения минимального угла (минимальная задержка) во время запуска (direction == 0)
|
||||
// Это значит, что тиристоры открыты максимально рано — можно перейти на прямое питание двигателя
|
||||
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;
|
||||
Upp.GoDisconnect = 1; // Флаг для отключения УПП и подачи питания напрямую
|
||||
}
|
||||
else
|
||||
{
|
||||
Upp.GoDisconnect = 0;
|
||||
}
|
||||
|
||||
// если все фазы дошли до максимума в режиме торможения, то выставляем флаг на остановку упп (выключения питания на двигателе)
|
||||
// Проверяем условие достижения максимального угла (максимальная задержка) во время торможения (direction == 1)
|
||||
// Это значит, что тиристоры максимально закрыты — нужно остановить питание двигателя
|
||||
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;
|
||||
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
|
||||
{
|
||||
// Если флаг Go не установлен, сбрасываем углы управления тиристорами для всех фаз
|
||||
tiristor_angle_reset(&phase_A.ctrl);
|
||||
tiristor_angle_reset(&phase_B.ctrl);
|
||||
tiristor_angle_reset(&phase_C.ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Функция безопасного запуска УПП
|
||||
*
|
||||
* @details Следит за изменениями флага GoSafe и запускает или останавливает пускатель,
|
||||
* сбрасывая угол задержки тиристоров в зависимости от направления.
|
||||
*/
|
||||
void upp_safe_go(void)
|
||||
{
|
||||
static int prev_gosafe;
|
||||
|
||||
static int prev_gosafe; // Статическая переменная для хранения предыдущего значения флага GoSafe
|
||||
|
||||
// Если текущее значение GoSafe больше предыдущего — это сигнал о старте в режиме запуска (направление 0)
|
||||
if(Upp.GoSafe > prev_gosafe)
|
||||
{
|
||||
Upp.angleInit.direction = 0;
|
||||
Upp.Prepare = 1;
|
||||
Upp.Go = 1;
|
||||
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);
|
||||
}
|
||||
// Если текущее значение GoSafe меньше предыдущего — это сигнал о старте в режиме торможения (направление 1)
|
||||
else if (Upp.GoSafe < prev_gosafe)
|
||||
{
|
||||
Upp.angleInit.direction = 1;
|
||||
Upp.Prepare = 1;
|
||||
Upp.Go = 1;
|
||||
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);
|
||||
}
|
||||
|
||||
// Обновляем сохранённое предыдущее значение GoSafe для отслеживания изменений в следующем вызове
|
||||
prev_gosafe = Upp.GoSafe;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Отключение питания УПП (разрыв всех фаз)
|
||||
*
|
||||
* @details Если тиристор готов, вызывает макросы отключения фаз,
|
||||
* после чего выставляет соответствующие флаги состояния.
|
||||
*/
|
||||
void disconnect_upp(void)
|
||||
{
|
||||
if(phase_A.ctrl.f.TiristorReady)
|
||||
{
|
||||
disconnect_phase(&phase_A);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
// Если тиристоры фазы A открыты, подключаем фазу напрямую
|
||||
if(phase_A.ctrl.f.TiristorReady)
|
||||
{
|
||||
disconnect_phase(&phase_A);
|
||||
}
|
||||
|
||||
// Аналогично для фазы B
|
||||
if(phase_B.ctrl.f.TiristorReady)
|
||||
{
|
||||
disconnect_phase(&phase_B);
|
||||
}
|
||||
|
||||
// Аналогично для фазы C
|
||||
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; // Прекращаем работу УПП
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Подключение питания УПП (соединение всех фаз)
|
||||
*
|
||||
* @details Вызывает отключение тиристоров и макросы подключения фаз,
|
||||
* сбрасывает флаг отключения.
|
||||
*/
|
||||
void connect_upp(void)
|
||||
{
|
||||
tiristor_disable(&phase_A.ctrl);
|
||||
tiristor_disable(&phase_B.ctrl);
|
||||
tiristor_disable(&phase_C.ctrl);
|
||||
// Отключаем управление тиристорами для всех фаз
|
||||
tiristor_disable(&phase_A.ctrl);
|
||||
tiristor_disable(&phase_B.ctrl);
|
||||
tiristor_disable(&phase_C.ctrl);
|
||||
|
||||
connect_phase(&phase_A);
|
||||
connect_phase(&phase_B);
|
||||
connect_phase(&phase_C);
|
||||
|
||||
Upp.Disconnected = 0;
|
||||
// Подключаем УПП к каждой фазе)
|
||||
connect_phase(&phase_A);
|
||||
connect_phase(&phase_B);
|
||||
connect_phase(&phase_C);
|
||||
|
||||
// Сбрасываем флаг, указывающий на то, что УПП было отключено
|
||||
Upp.Disconnected = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Управление одной фазой УПП
|
||||
* @param phase Указатель на структуру фазы Phase_t
|
||||
*
|
||||
* @details Контролирует угол и включает/отключает тиристор для данной фазы.
|
||||
*/
|
||||
void upp_phase_control(Phase_t *phase)
|
||||
{
|
||||
tiristor_angle_control(&phase->ctrl);
|
||||
tiristor_control(&phase->ctrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Обработка фазы при каждом нулевом переходе синусоиды
|
||||
* @param phase Указатель на структуру фазы Phase_t
|
||||
*
|
||||
* @details Обновляет состояние детектора нулевого перехода,
|
||||
* запускает задержку угла тиристора,
|
||||
* отключает тиристор, если он был включен.
|
||||
*/
|
||||
void upp_phase_routine(Phase_t *phase)
|
||||
{
|
||||
// Обновляем детектор нулевого перехода по текущему состоянию входного сигнала
|
||||
zero_cross_update(&phase->zc_detector);
|
||||
|
||||
// Если обнаружен нулевой переход (синусоида пересекла 0)
|
||||
if(is_zero_cross(&phase->zc_detector))
|
||||
{
|
||||
// Запускаем отсчёт задержки до открытия тиристора (по углу)
|
||||
tiristor_start_angle_delay(&phase->ctrl);
|
||||
|
||||
// Если тиристор был включён в предыдущем полупериоде — отключаем его
|
||||
if (phase->ctrl.f.TiristorIsEnable)
|
||||
tiristor_disable(&phase->ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Расчёт параметров угла запуска тиристора
|
||||
* @param angle Указатель на структуру AngleInit_t для записи параметров
|
||||
* @return int 1, если произошли изменения параметров, иначе 0
|
||||
*
|
||||
* @details Проверяет изменения в параметрах управления и при необходимости
|
||||
* пересчитывает максимальные и минимальные задержки, шаг изменения угла,
|
||||
* а также изменяет прескалер таймера.
|
||||
*/
|
||||
int GetAngleInit(AngleInit_t *angle)
|
||||
{
|
||||
static float sine_freq_old = 0;
|
||||
@ -209,7 +301,7 @@ int GetAngleInit(AngleInit_t *angle)
|
||||
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) )
|
||||
@ -218,64 +310,73 @@ int GetAngleInit(AngleInit_t *angle)
|
||||
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; // полупериод в мкс - время открытия тиристоры
|
||||
// Расчёт длительности полупериода в микросекундах (с учётом вычета резерва на открытие тиристора)
|
||||
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);
|
||||
|
||||
// Проверка, помещаются ли значения задержек в 16-битный таймер
|
||||
if((angle->delay_max_us > 0xFFFF) || (angle->delay_min_us > 0xFFFF))
|
||||
{
|
||||
// увеличение прескалера в 10 раз (с 1мкс до 10мкс, с 7Гц до 0.7Гц)
|
||||
// Если нет — увеличиваем прескалер в 10 раз (точность 10 мкс)
|
||||
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 Гц)
|
||||
// Если всё ещё не помещается — ещё в 10 раз (точность 0.1 мс)
|
||||
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
|
||||
{
|
||||
// Задержки помещаются — устанавливаем стандартный прескалер (1 мкс)
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Инициализация УПП и связанных структур
|
||||
*
|
||||
* @details Настраивает параметры управления, GPIO для фаз,
|
||||
* инициализирует тиристоры, запускает таймер и настраивает детектор нулевого перехода.
|
||||
*/
|
||||
void upp_init(void)
|
||||
{
|
||||
Upp.max_duty = 0.9;
|
||||
|
@ -9,46 +9,69 @@
|
||||
#include "zero_cross.h"
|
||||
#include "tiristor.h"
|
||||
|
||||
#define hadc hadc1
|
||||
#define ADC_INITIAL_ZERO_LEVEL 2048
|
||||
/**
|
||||
* @brief Определение используемого ADC
|
||||
*/
|
||||
#define hadc hadc1
|
||||
|
||||
#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;}
|
||||
/**
|
||||
* @brief Начальный уровень отсчёта для определения нуля в ADC (обычно середина диапазона)
|
||||
*/
|
||||
#define ADC_INITIAL_ZERO_LEVEL 2048
|
||||
|
||||
/**
|
||||
* @brief Макрос для разрыва (отключения) фазы — устанавливает GPIO в высокий уровень и флаг Disconnected
|
||||
* @param _ph_ Указатель на структуру фазы Phase_t
|
||||
*/
|
||||
#define disconnect_phase(_ph_) { (_ph_)->disconnect.gpiox->ODR |= (_ph_)->disconnect.gpio_pin; (_ph_)->disconnect.Disconnected = 1;}
|
||||
|
||||
/**
|
||||
* @brief Макрос для подключения фазы — сбрасывает GPIO в низкий уровень и флаг Disconnected
|
||||
* @param _ph_ Указатель на структуру фазы Phase_t
|
||||
*/
|
||||
#define connect_phase(_ph_) { (_ph_)->disconnect.gpiox->ODR &= ~(_ph_)->disconnect.gpio_pin; (_ph_)->disconnect.Disconnected = 0;}
|
||||
|
||||
/**
|
||||
* @struct Phase_t
|
||||
* @brief Структура, описывающая одну фазу с состоянием тиристора и детектом нуля
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned Disconnected:1;
|
||||
GPIO_TypeDef *gpiox;
|
||||
uint32_t gpio_pin;
|
||||
}disconnect;
|
||||
|
||||
ZeroCrossDetector_t zc_detector;
|
||||
TiristorControl_t ctrl;
|
||||
} Phase_t; // структура для фазы
|
||||
struct
|
||||
{
|
||||
unsigned Disconnected:1; /**< Флаг разрыва фазы */
|
||||
GPIO_TypeDef *gpiox; /**< Порт GPIO для разрыва */
|
||||
uint32_t gpio_pin; /**< Пин GPIO для разрыва */
|
||||
}disconnect;
|
||||
|
||||
ZeroCrossDetector_t zc_detector; /**< Детектор пересечения нуля */
|
||||
TiristorControl_t ctrl; /**< Управление тиристором */
|
||||
} Phase_t;
|
||||
|
||||
|
||||
/**
|
||||
* @struct UPP_Control_t
|
||||
* @brief Основная структура управления устройством плавного пуска
|
||||
*/
|
||||
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;
|
||||
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;
|
||||
@ -56,14 +79,28 @@ extern Phase_t phase_B;
|
||||
extern Phase_t phase_C;
|
||||
extern UPP_Control_t Upp;
|
||||
|
||||
/** Основной цикл работы устройства плавного пуска */
|
||||
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_control(Phase_t *phase);
|
||||
|
||||
/** Получение настроек угла открытия тиристора */
|
||||
int GetAngleInit(AngleInit_t *angle);
|
||||
|
||||
/** Инициализация устройства плавного пуска */
|
||||
void upp_init(void);
|
||||
|
||||
|
||||
#endif //__UPP_H
|
||||
#endif //__UPP_H
|
||||
|
@ -2,55 +2,92 @@
|
||||
|
||||
ADCFilter_t AdcFilter;
|
||||
|
||||
/**
|
||||
* @brief Инициализация структуры детектора перехода через ноль
|
||||
* @param zc Указатель на структуру ZeroCrossDetector_t
|
||||
* @param zeroLevel Значение уровня АЦП, соответствующее нулю (mid-scale)
|
||||
*/
|
||||
void zero_cross_Init(ZeroCrossDetector_t *zc, uint16_t zeroLevel)
|
||||
{
|
||||
zc->lastSample = 0;
|
||||
zc->f.ZeroCrossDetected = 0;
|
||||
zc->zeroLevel = zeroLevel;
|
||||
// Обнуляем последнее измеренное значение сдвига относительно нуля
|
||||
zc->lastSample = 0;
|
||||
|
||||
// Сбрасываем флаг обнаружения перехода через ноль
|
||||
zc->f.ZeroCrossDetected = 0;
|
||||
|
||||
// Запоминаем уровень, соответствующий нулю (обычно mid-scale АЦП)
|
||||
zc->zeroLevel = zeroLevel;
|
||||
}
|
||||
// апдейт флага зерокросс детектед
|
||||
|
||||
/**
|
||||
* @brief Обновление флага перехода через ноль
|
||||
* @param zc Указатель на структуру ZeroCrossDetector_t
|
||||
* @details Если аппаратный детектор включен, просто переносим флаг EXTI.
|
||||
* Иначе — анализируем разницу между текущим и предыдущим значением АЦП,
|
||||
* чтобы определить, произошёл ли переход через ноль.
|
||||
*/
|
||||
void zero_cross_update(ZeroCrossDetector_t *zc)
|
||||
{
|
||||
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
||||
zc->f.ZeroCrossDetected = zc->f.EXTIZeroCrossDetected;
|
||||
// Используем флаг аппаратного прерывания EXTI для установки флага перехода через ноль
|
||||
zc->f.ZeroCrossDetected = zc->f.EXTIZeroCrossDetected;
|
||||
#else
|
||||
uint16_t adcValue;
|
||||
if(adc_is_data_updated(&zc->AdcFilter))
|
||||
{
|
||||
adcValue = adc_read_data(&zc->AdcFilter);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
zc->currSample = (int16_t)adcValue - (int16_t)zc->zeroLevel;
|
||||
uint16_t adcValue;
|
||||
|
||||
if ((zc->lastSample < 0 && zc->currSample >= 0) ||
|
||||
(zc->lastSample > 0 && zc->currSample <= 0))
|
||||
{
|
||||
zc->f.ZeroCrossDetected = 1;
|
||||
}
|
||||
// Проверяем, обновились ли данные АЦП (фильтр)
|
||||
if(adc_is_data_updated(&zc->AdcFilter))
|
||||
{
|
||||
adcValue = adc_read_data(&zc->AdcFilter);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Нет новых данных — выход из функции
|
||||
return;
|
||||
}
|
||||
|
||||
zc->lastSample = zc->currSample;
|
||||
// Вычисляем смещение текущей выборки относительно нуля
|
||||
zc->currSample = (int16_t)adcValue - (int16_t)zc->zeroLevel;
|
||||
|
||||
// Проверяем, произошёл ли переход через ноль между предыдущей и текущей выборками
|
||||
if ((zc->lastSample < 0 && zc->currSample >= 0) ||
|
||||
(zc->lastSample > 0 && zc->currSample <= 0))
|
||||
{
|
||||
// Устанавливаем флаг обнаружения перехода через ноль
|
||||
zc->f.ZeroCrossDetected = 1;
|
||||
}
|
||||
|
||||
// Сохраняем текущее значение для следующего сравнения
|
||||
zc->lastSample = zc->currSample;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Проверка наличия перехода через ноль и сброс флагов
|
||||
* @param zc Указатель на структуру ZeroCrossDetector_t
|
||||
* @return int 1 — переход через ноль обнаружен, 0 — нет
|
||||
* @details Если переход обнаружен, сбрасываем флаги и возвращаем 1,
|
||||
* иначе возвращаем 0.
|
||||
*/
|
||||
int is_zero_cross(ZeroCrossDetector_t *zc)
|
||||
{
|
||||
if(zc->f.ZeroCrossDetected)
|
||||
{
|
||||
zc->f.ZeroCrossDetected = 0;
|
||||
zc->f.EXTIZeroCrossDetected = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
if(zc->f.ZeroCrossDetected)
|
||||
{
|
||||
// Сброс флагов после обнаружения
|
||||
zc->f.ZeroCrossDetected = 0;
|
||||
zc->f.EXTIZeroCrossDetected = 0;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
||||
/**
|
||||
* @brief Обработчик прерывания EXTI для аппаратного детектора перехода через ноль
|
||||
* @param zc Указатель на структуру ZeroCrossDetector_t
|
||||
* @details Устанавливает флаг аппаратного перехода через ноль.
|
||||
*/
|
||||
void zero_cross_update_EXTI(ZeroCrossDetector_t *zc)
|
||||
{
|
||||
zc->f.EXTIZeroCrossDetected = 1;
|
||||
zc->f.EXTIZeroCrossDetected = 1;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -4,38 +4,43 @@
|
||||
#include "main.h"
|
||||
#include "adc_filter.h"
|
||||
|
||||
#define hadc hadc1
|
||||
#define hadc hadc1
|
||||
|
||||
#define HARDWARE_ZERO_CROSS_DETECT // аппаратный детект zero cross (альтернатива — считывание через АЦП)
|
||||
|
||||
|
||||
#define HARDWARE_ZERO_CROSS_DETECT // аппаратный детект зеро кросс (альтернатива - считывая через ацп)
|
||||
|
||||
/**
|
||||
* @brief Флаги состояния детектора нуля
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
unsigned WaitForZeroCrossDetected : 1;
|
||||
unsigned WaitForZeroCrossDetected : 1; /**< Ожидание обнаружения перехода через ноль */
|
||||
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
||||
unsigned EXTIZeroCrossDetected:1;
|
||||
unsigned EXTIZeroCrossDetected : 1; /**< Флаг обнаружения нуля аппаратным прерыванием EXTI */
|
||||
#endif
|
||||
unsigned ZeroCrossDetected:1;
|
||||
}ZeroCrossFlags;
|
||||
|
||||
unsigned ZeroCrossDetected : 1; /**< Флаг обнаружения перехода через ноль */
|
||||
} ZeroCrossFlags;
|
||||
|
||||
/**
|
||||
* @brief Структура детектора перехода через ноль
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
ZeroCrossFlags f;
|
||||
int currSample;
|
||||
int16_t lastSample; // предыдущее значение (относительно нуля)
|
||||
uint16_t zeroLevel; // уровень, соответствующий "нулю", обычно mid-scale
|
||||
ADCFilter_t AdcFilter;
|
||||
ZeroCrossFlags f; /**< Флаги состояния детектора */
|
||||
int currSample; /**< Текущее значение выборки */
|
||||
int16_t lastSample; /**< Предыдущее значение выборки (относительно нуля) */
|
||||
uint16_t zeroLevel; /**< Уровень, соответствующий "нулю", обычно mid-scale АЦП */
|
||||
ADCFilter_t AdcFilter; /**< Фильтр АЦП для сглаживания входных данных */
|
||||
} ZeroCrossDetector_t;
|
||||
|
||||
|
||||
/** Инициализация структуры детектора перехода через ноль */
|
||||
void zero_cross_Init(ZeroCrossDetector_t *zc, uint16_t zeroLevel);
|
||||
/** Обновление состояния детектора перехода через ноль (через АЦП или аппаратный метод) */
|
||||
void zero_cross_update(ZeroCrossDetector_t *zc);
|
||||
/** Проверка, был ли обнаружен переход через ноль */
|
||||
int is_zero_cross(ZeroCrossDetector_t *zc);
|
||||
|
||||
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
||||
/** Обновление состояния детектора перехода через ноль при аппаратном прерывании EXTI*/
|
||||
void zero_cross_update_EXTI(ZeroCrossDetector_t *zc);
|
||||
#endif
|
||||
|
||||
#endif //__ZERO_CROSS_H
|
||||
#endif //__ZERO_CROSS_H
|
||||
|
File diff suppressed because one or more lines are too long
@ -128,7 +128,24 @@
|
||||
<Name>-U-O142 -O2254 -S0 -C0 -N00("ARM CoreSight SW-DP") -D00(2BA01477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC800 -FN1 -FF0STM32F10x_128 -FS08000000 -FL08000 -FP0($$Device:STM32F103C6$Flash\STM32F10x_128.FLM)</Name>
|
||||
</SetRegEntry>
|
||||
</TargetDriverDllRegistry>
|
||||
<Breakpoint/>
|
||||
<Breakpoint>
|
||||
<Bp>
|
||||
<Number>0</Number>
|
||||
<Type>0</Type>
|
||||
<LineNumber>62</LineNumber>
|
||||
<EnabledFlag>1</EnabledFlag>
|
||||
<Address>0</Address>
|
||||
<ByteObject>0</ByteObject>
|
||||
<HtxType>0</HtxType>
|
||||
<ManyObjects>0</ManyObjects>
|
||||
<SizeOfObject>0</SizeOfObject>
|
||||
<BreakByAccess>0</BreakByAccess>
|
||||
<BreakIfRCount>0</BreakIfRCount>
|
||||
<Filename>..\Core\upp\tiristor.c</Filename>
|
||||
<ExecCommand></ExecCommand>
|
||||
<Expression></Expression>
|
||||
</Bp>
|
||||
</Breakpoint>
|
||||
<Tracepoint>
|
||||
<THDelay>0</THDelay>
|
||||
</Tracepoint>
|
||||
|
Loading…
Reference in New Issue
Block a user