Добавлены комменты
This commit is contained in:
parent
416260c9e1
commit
95a022d6c1
@ -1,35 +1,63 @@
|
|||||||
#include "adc_filter.h"
|
#include "adc_filter.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Привязка структуры фильтра к конкретному АЦП
|
||||||
|
* @param hfilter Указатель на структуру ADCFilter_t
|
||||||
|
* @param hadc Указатель на структуру HAL АЦП
|
||||||
|
*/
|
||||||
void adc_Attach(ADCFilter_t *hfilter, ADC_HandleTypeDef *hadc)
|
void adc_Attach(ADCFilter_t *hfilter, ADC_HandleTypeDef *hadc)
|
||||||
{
|
{
|
||||||
|
// Связываем фильтр с конкретным аппаратным АЦП для чтения данных
|
||||||
hfilter->hadc = hadc;
|
hfilter->hadc = hadc;
|
||||||
}
|
}
|
||||||
// фильтрация
|
|
||||||
|
/**
|
||||||
|
* @brief Обновление и фильтрация новых данных АЦП методом усреднения
|
||||||
|
* @param hfilter Указатель на структуру ADCFilter_t
|
||||||
|
* @return int Возвращает 1, если произведено обновление отфильтрованных данных, иначе 0
|
||||||
|
*/
|
||||||
int adc_filterring(ADCFilter_t *hfilter)
|
int adc_filterring(ADCFilter_t *hfilter)
|
||||||
{
|
{
|
||||||
|
// Добавляем текущее значение из регистра данных АЦП в сумму
|
||||||
hfilter->sum += hfilter->hadc->Instance->DR;
|
hfilter->sum += hfilter->hadc->Instance->DR;
|
||||||
|
// Увеличиваем счётчик накопленных выборок
|
||||||
hfilter->count++;
|
hfilter->count++;
|
||||||
|
|
||||||
|
// Если набрано достаточное количество выборок для усреднения
|
||||||
if (hfilter->count >= hfilter->bufferSize)
|
if (hfilter->count >= hfilter->bufferSize)
|
||||||
{
|
{
|
||||||
|
// Вычисляем среднее значение и сохраняем как отфильтрованный результат
|
||||||
hfilter->AdcResult = hfilter->sum / hfilter->bufferSize;
|
hfilter->AdcResult = hfilter->sum / hfilter->bufferSize;
|
||||||
|
// Сбрасываем сумму и счётчик для следующего цикла
|
||||||
hfilter->sum = 0;
|
hfilter->sum = 0;
|
||||||
hfilter->count = 0;
|
hfilter->count = 0;
|
||||||
hfilter->f.DataUpdated = 1;
|
// Отмечаем, что новые данные отфильтрованы и готовы к чтению
|
||||||
|
hfilter->f.DataUpdated = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Если ещё недостаточно данных, возвращаем 0 — фильтрация не завершена
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Чтение последнего отфильтрованного значения АЦП
|
||||||
|
* @param hfilter Указатель на структуру ADCFilter_t
|
||||||
|
* @return uint16_t Последнее отфильтрованное значение
|
||||||
|
*/
|
||||||
uint16_t adc_read_data(ADCFilter_t *hfilter)
|
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)
|
int adc_is_data_updated(ADCFilter_t *hfilter)
|
||||||
{
|
{
|
||||||
return hfilter->f.DataUpdated;
|
return hfilter->f.DataUpdated;
|
||||||
}
|
}
|
||||||
|
@ -3,25 +3,37 @@
|
|||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Флаги состояния фильтра АЦП
|
||||||
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned DataUpdated:1;
|
unsigned DataUpdated : 1; /**< Флаг обновления данных */
|
||||||
}AdcFilterFlags;
|
} AdcFilterFlags;
|
||||||
|
|
||||||
// структура для ацп
|
/**
|
||||||
|
* @brief Структура фильтрации данных АЦП
|
||||||
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
AdcFilterFlags f;
|
AdcFilterFlags f; /**< Флаги состояния */
|
||||||
uint16_t AdcResult;
|
uint16_t AdcResult; /**< Отфильтрованное значение АЦП */
|
||||||
ADC_HandleTypeDef *hadc;
|
ADC_HandleTypeDef *hadc; /**< Указатель на структуру HAL АЦП */
|
||||||
uint32_t sum;
|
uint32_t sum; /**< Сумма накопленных значений для усреднения */
|
||||||
uint16_t count;
|
uint16_t count; /**< Текущий счётчик накопленных значений */
|
||||||
uint16_t bufferSize;
|
uint16_t bufferSize; /**< Размер буфера для усреднения (число выборок) */
|
||||||
} ADCFilter_t;
|
} ADCFilter_t;
|
||||||
|
|
||||||
|
/** Привязка структуры фильтра к конкретному АЦП */
|
||||||
void adc_Attach(ADCFilter_t *hfilter, ADC_HandleTypeDef *hadc);
|
void adc_Attach(ADCFilter_t *hfilter, ADC_HandleTypeDef *hadc);
|
||||||
|
|
||||||
|
/** Обновление и фильтрация нового значения АЦП */
|
||||||
int adc_filterring(ADCFilter_t *hfilter);
|
int adc_filterring(ADCFilter_t *hfilter);
|
||||||
|
|
||||||
|
/** Чтение последнего отфильтрованного значения АЦП */
|
||||||
uint16_t adc_read_data(ADCFilter_t *hfilter);
|
uint16_t adc_read_data(ADCFilter_t *hfilter);
|
||||||
|
|
||||||
|
/** Проверка, обновились ли данные АЦП после фильтрации */
|
||||||
int adc_is_data_updated(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"
|
#include "tiristor.h"
|
||||||
// управление тиристором
|
|
||||||
|
/**
|
||||||
|
* @brief Управление состоянием тиристора (включение/выключение) по флагам и времени открытия
|
||||||
|
* @param ctrl Указатель на структуру управления тиристором
|
||||||
|
*/
|
||||||
void tiristor_control(TiristorControl_t *ctrl)
|
void tiristor_control(TiristorControl_t *ctrl)
|
||||||
{
|
{
|
||||||
if(ctrl->f.EnableTiristor)
|
if(ctrl->f.EnableTiristor) // Если разрешено включить тиристор
|
||||||
{
|
{
|
||||||
if(ctrl->f.TiristorIsEnable == 0)
|
if(ctrl->f.TiristorIsEnable == 0) // Если тиристор еще выключен
|
||||||
{
|
{
|
||||||
tiristor_enable(ctrl);
|
tiristor_enable(ctrl); // Включить тиристор
|
||||||
ctrl->enable_start_tick = HAL_GetTick();
|
ctrl->enable_start_tick = HAL_GetTick(); // Запомнить время включения для отсчёта длительности открытия
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(HAL_GetTick() - ctrl->enable_start_tick > ctrl->open_time)
|
// Если время с момента включения превысило заданное время открытия
|
||||||
{
|
if(HAL_GetTick() - ctrl->enable_start_tick > ctrl->open_time)
|
||||||
tiristor_disable(ctrl);
|
{
|
||||||
ctrl->f.EnableTiristor = 0;
|
tiristor_disable(ctrl); // Выключить тиристор
|
||||||
}
|
ctrl->f.EnableTiristor = 0; // Снять разрешение на включение, чтобы не включался снова без команды
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
{
|
else // Если тиристор не должен быть включен
|
||||||
if(ctrl->f.TiristorIsEnable)
|
{
|
||||||
tiristor_disable(ctrl);
|
if(ctrl->f.TiristorIsEnable) // Если тиристор включен
|
||||||
}
|
tiristor_disable(ctrl); // Выключить тиристор
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Обновление значения задержки угла открытия тиристора в соответствии с направлением и шагом
|
||||||
|
* @param angle Указатель на структуру управления углом тиристора
|
||||||
|
*/
|
||||||
void tiristor_angle_update(TiristorAngleControl_t *angle)
|
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)
|
|
||||||
{
|
|
||||||
angle->last_update_ms = current_time_ms;
|
|
||||||
|
|
||||||
if(angle->Init->direction)
|
// Проверяем, прошло ли нужное время с последнего обновления
|
||||||
angle->delay_us += angle->Init->delay_step_us;
|
if ((current_time_ms - angle->last_update_ms) >= angle->Init->sample_time_ms)
|
||||||
else
|
{
|
||||||
angle->delay_us -= angle->Init->delay_step_us;
|
angle->last_update_ms = current_time_ms; // Обновляем время последнего изменения задержки
|
||||||
|
|
||||||
|
// Изменяем задержку в зависимости от направления (разгон или торможение)
|
||||||
if (angle->delay_us < angle->Init->delay_min_us)
|
if(angle->Init->direction)
|
||||||
{
|
angle->delay_us += angle->Init->delay_step_us; // Увеличиваем задержку (увеличиваем угол)
|
||||||
angle->delay_us = angle->Init->delay_min_us;
|
else
|
||||||
}
|
angle->delay_us -= angle->Init->delay_step_us; // Уменьшаем задержку (уменьшаем угол)
|
||||||
else if (angle->delay_us > angle->Init->delay_max_us)
|
|
||||||
{
|
// Ограничиваем задержку в пределах минимального и максимального значения
|
||||||
angle->delay_us = angle->Init->delay_max_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)
|
void tiristor_angle_control(TiristorControl_t *ctrl)
|
||||||
{
|
{
|
||||||
tiristor_angle_update(&ctrl->angle);
|
tiristor_angle_update(&ctrl->angle); // Обновляем задержку угла открытия
|
||||||
|
|
||||||
if(ctrl->angle.delay_us != 0)
|
if(ctrl->angle.delay_us != 0) // Если задержка не нулевая
|
||||||
{
|
{
|
||||||
if ((uint16_t)((uint16_t)TIMER->CNT - ctrl->angle.start_delay_tick) > ctrl->angle.delay_us)
|
// Проверяем, прошла ли задержка с момента старта отсчёта таймера
|
||||||
{
|
if ((uint16_t)((uint16_t)TIMER->CNT - ctrl->angle.start_delay_tick) > ctrl->angle.delay_us)
|
||||||
if(ctrl->f.TiristorReady)
|
{
|
||||||
{
|
if(ctrl->f.TiristorReady) // Если тиристор готов к включению
|
||||||
ctrl->f.EnableTiristor = 1;
|
{
|
||||||
ctrl->f.TiristorReady = 0;
|
ctrl->f.EnableTiristor = 1; // Разрешаем включение тиристора
|
||||||
}
|
ctrl->f.TiristorReady = 0; // Снимаем флаг готовности, чтобы не включать повторно сразу
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Запуск отсчёта задержки для открытия тиристора
|
||||||
|
* @param ctrl Указатель на структуру управления тиристором
|
||||||
|
*/
|
||||||
void tiristor_start_angle_delay(TiristorControl_t *ctrl)
|
void tiristor_start_angle_delay(TiristorControl_t *ctrl)
|
||||||
{
|
{
|
||||||
ctrl->f.TiristorReady = 1;
|
ctrl->f.TiristorReady = 1; // Устанавливаем флаг готовности тиристора к включению
|
||||||
ctrl->angle.start_delay_tick = TIMER->CNT;
|
ctrl->angle.start_delay_tick = TIMER->CNT; // Запоминаем текущее значение счётчика таймера
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Включение тиристора путём установки GPIO в состояние открытия
|
||||||
|
* @param ctrl Указатель на структуру управления тиристором
|
||||||
|
*/
|
||||||
void tiristor_enable(TiristorControl_t *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->gpiox->ODR |= ctrl->gpio_pin;
|
||||||
ctrl->f.TiristorIsEnable = 1;
|
ctrl->f.TiristorIsEnable = 1; // Устанавливаем флаг, что тиристор включен
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Выключение тиристора путём установки GPIO в состояние закрытия
|
||||||
|
* @param ctrl Указатель на структуру управления тиристором
|
||||||
|
*/
|
||||||
void tiristor_disable(TiristorControl_t *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->gpiox->ODR &= ~ctrl->gpio_pin;
|
||||||
ctrl->f.TiristorIsEnable = 0;
|
ctrl->f.TiristorIsEnable = 0; // Снимаем флаг включения тиристора
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Сброс значения задержки угла открытия тиристора к начальному в зависимости от направления
|
||||||
|
* @param ctrl Указатель на структуру управления тиристором
|
||||||
|
*/
|
||||||
void tiristor_angle_reset(TiristorControl_t *ctrl)
|
void tiristor_angle_reset(TiristorControl_t *ctrl)
|
||||||
{
|
{
|
||||||
if(ctrl->angle.Init->direction)
|
// В зависимости от направления устанавливаем задержку на минимальное или максимальное значение
|
||||||
ctrl->angle.delay_us = ctrl->angle.Init->delay_min_us;
|
if(ctrl->angle.Init->direction)
|
||||||
else
|
ctrl->angle.delay_us = ctrl->angle.Init->delay_min_us;
|
||||||
ctrl->angle.delay_us = ctrl->angle.Init->delay_max_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)
|
void tiristor_init(TiristorControl_t *ctrl, GPIO_TypeDef *gpiox, uint32_t gpio_pin)
|
||||||
{
|
{
|
||||||
ctrl->gpiox = gpiox;
|
ctrl->gpiox = gpiox; // Сохраняем порт GPIO
|
||||||
ctrl->gpio_pin = gpio_pin;
|
ctrl->gpio_pin = gpio_pin; // Сохраняем номер пина GPIO
|
||||||
tiristor_angle_reset(ctrl);
|
tiristor_angle_reset(ctrl); // Сбрасываем угол открытия тиристора на начальное значение
|
||||||
}
|
}
|
||||||
|
@ -5,55 +5,108 @@
|
|||||||
#include "tim.h"
|
#include "tim.h"
|
||||||
|
|
||||||
|
|
||||||
#define GPIO_TIRISTOR_OPEN GPIO_PIN_SET
|
#define GPIO_TIRISTOR_OPEN GPIO_PIN_SET /**< Состояние GPIO для открытия тиристора */
|
||||||
#define GPIO_TIRISTOR_CLOSE GPIO_PIN_RESET
|
#define GPIO_TIRISTOR_CLOSE GPIO_PIN_RESET /**< Состояние GPIO для закрытия тиристора */
|
||||||
|
|
||||||
|
#define TIMER TIM2 /**< Таймер, используемый для управления тиристором */
|
||||||
|
|
||||||
#define TIMER TIM2
|
/**
|
||||||
|
* @brief Флаги состояния управления тиристором
|
||||||
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned EnableTiristor:1;
|
unsigned EnableTiristor:1; /**< Флаг разрешения управления тиристором */
|
||||||
unsigned TiristorIsEnable:1;
|
unsigned TiristorIsEnable:1; /**< Флаг, указывающий, что тиристор включен */
|
||||||
unsigned TiristorReady:1;
|
unsigned TiristorReady: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;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Параметры инициализации угла открытия тиристора
|
||||||
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
AngleInit_t *Init;
|
uint32_t delay_min_us; /**< Минимальная задержка (микросекунды), соответствует максимальному открытию тиристора */
|
||||||
|
uint32_t delay_max_us; /**< Начальная задержка (микросекунды), соответствует практически закрытому тиристору */
|
||||||
uint32_t last_update_ms; // Время последнего обновления
|
uint32_t delay_step_us; /**< Шаг уменьшения задержки (микросекунды) */
|
||||||
uint32_t delay_us; // Текущая задержка (в микросекундах)
|
uint32_t sample_time_ms; /**< Интервал времени между шагами регулировки (миллисекунды) */
|
||||||
uint16_t start_delay_tick;
|
unsigned direction; /**< Направление регулировки: разгон (увеличение открытого угла) или торможение */
|
||||||
}TiristorAngleControl_t;
|
} 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;
|
typedef struct TiristorControl_t TiristorControl_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Основная структура управления тиристором
|
||||||
|
*/
|
||||||
struct TiristorControl_t
|
struct TiristorControl_t
|
||||||
{
|
{
|
||||||
TiristorControlFlags f;
|
TiristorControlFlags f; /**< Флаги состояния тиристора */
|
||||||
TiristorAngleControl_t angle;
|
TiristorAngleControl_t angle; /**< Управление углом открытия */
|
||||||
GPIO_TypeDef *gpiox;
|
GPIO_TypeDef *gpiox; /**< Порт GPIO для управления тиристором */
|
||||||
uint32_t gpio_pin;
|
uint32_t gpio_pin; /**< Номер пина GPIO */
|
||||||
uint32_t open_time;
|
uint32_t open_time; /**< Время открытия тиристора */
|
||||||
uint32_t enable_start_tick;
|
uint32_t enable_start_tick; /**< Время включения тиристора по таймеру */
|
||||||
|
|
||||||
void (*start_delay)(TiristorControl_t *ctrl); // Указатель на функцию запуска задержки включения
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Управление состоянием тиристора (включение/выключение)
|
||||||
|
* @param ctrl Указатель на структуру управления тиристором
|
||||||
|
*/
|
||||||
void tiristor_control(TiristorControl_t *ctrl);
|
void tiristor_control(TiristorControl_t *ctrl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Обновление угла открытия тиристора согласно параметрам
|
||||||
|
* @param angle Указатель на структуру управления углом тиристора
|
||||||
|
*/
|
||||||
void tiristor_angle_update(TiristorAngleControl_t *angle);
|
void tiristor_angle_update(TiristorAngleControl_t *angle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Контроль угла открытия тиристора, включая обновление состояния
|
||||||
|
* @param ctrl Указатель на структуру управления тиристором
|
||||||
|
*/
|
||||||
void tiristor_angle_control(TiristorControl_t *ctrl);
|
void tiristor_angle_control(TiristorControl_t *ctrl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Запуск задержки открытия тиристора
|
||||||
|
* @param ctrl Указатель на структуру управления тиристором
|
||||||
|
*/
|
||||||
void tiristor_start_angle_delay(TiristorControl_t* ctrl);
|
void tiristor_start_angle_delay(TiristorControl_t* ctrl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Сброс угла открытия тиристора к начальному состоянию
|
||||||
|
* @param ctrl Указатель на структуру управления тиристором
|
||||||
|
*/
|
||||||
void tiristor_angle_reset(TiristorControl_t *ctrl);
|
void tiristor_angle_reset(TiristorControl_t *ctrl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Включение тиристора
|
||||||
|
* @param ctrl Указатель на структуру управления тиристором
|
||||||
|
*/
|
||||||
void tiristor_enable(TiristorControl_t *ctrl);
|
void tiristor_enable(TiristorControl_t *ctrl);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Выключение тиристора
|
||||||
|
* @param ctrl Указатель на структуру управления тиристором
|
||||||
|
*/
|
||||||
void tiristor_disable(TiristorControl_t *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);
|
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"
|
#include "upp.h"
|
||||||
|
|
||||||
Phase_t phase_A;
|
Phase_t phase_A; /*< Фаза управления тиристорами A */
|
||||||
Phase_t phase_B;
|
Phase_t phase_B; /*< Фаза управления тиристорами B */
|
||||||
Phase_t phase_C;
|
Phase_t phase_C; /*< Фаза управления тиристорами C */
|
||||||
UPP_Control_t Upp;
|
UPP_Control_t Upp; /*< Структура управления УПП */
|
||||||
// главная функция
|
|
||||||
void upp_main(void)
|
/**
|
||||||
|
* @brief Главная функция управления УПП
|
||||||
|
*
|
||||||
|
* @details Выполняет основную логику управления пускателем:
|
||||||
|
* инициализация углов, безопасный запуск,
|
||||||
|
* проверка флагов остановки/отключения,
|
||||||
|
* управление фазами и тиристорами.
|
||||||
|
*/void upp_main(void)
|
||||||
{
|
{
|
||||||
|
// Проверяем необходимость обновления параметров угла управления тиристорами
|
||||||
if(GetAngleInit(&Upp.angleInit))
|
if(GetAngleInit(&Upp.angleInit))
|
||||||
{
|
{
|
||||||
|
// Если параметры изменились, сбрасываем углы для всех фаз
|
||||||
tiristor_angle_reset(&phase_A.ctrl);
|
tiristor_angle_reset(&phase_A.ctrl);
|
||||||
tiristor_angle_reset(&phase_B.ctrl);
|
tiristor_angle_reset(&phase_B.ctrl);
|
||||||
tiristor_angle_reset(&phase_C.ctrl);
|
tiristor_angle_reset(&phase_C.ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// безопасный запуск
|
// Выполняем безопасный запуск (обработка изменения направления и стартового состояния)
|
||||||
upp_safe_go();
|
upp_safe_go();
|
||||||
|
|
||||||
// останавливаем УПП (убираем питание с выхода упп) если выставлен флаг
|
// Если установлен флаг принудительной остановки, выключаем питание УПП и подключаем выход
|
||||||
if(Upp.ForceStop)
|
if(Upp.ForceStop)
|
||||||
{
|
{
|
||||||
Upp.Go = 0;
|
Upp.Go = 0; // Останавливаем работу
|
||||||
connect_upp();
|
connect_upp(); // Подключаем УПП (прямое питание)
|
||||||
return;
|
return; // Выход из функции, дальнейшая логика не выполняется
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Если установлен флаг принудительного отключения, выставляем готовность тиристоров и отключаем УПП
|
||||||
if(Upp.ForceDisconnect)
|
if(Upp.ForceDisconnect)
|
||||||
{
|
{
|
||||||
phase_A.ctrl.f.TiristorReady = 1;
|
phase_A.ctrl.f.TiristorReady = 1;
|
||||||
phase_B.ctrl.f.TiristorReady = 1;
|
phase_B.ctrl.f.TiristorReady = 1;
|
||||||
phase_C.ctrl.f.TiristorReady = 1;
|
phase_C.ctrl.f.TiristorReady = 1;
|
||||||
Upp.Go = 0;
|
Upp.Go = 0; // Останавливаем работу
|
||||||
disconnect_upp();
|
disconnect_upp(); // Отключаем УПП (снимаем питание с выхода)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// отключаем упп если выставлен флаг
|
// Если установлен флаг плавного отключения УПП, готовим тиристоры и отключаем УПП
|
||||||
if(Upp.GoDisconnect)
|
if(Upp.GoDisconnect)
|
||||||
{
|
{
|
||||||
phase_A.ctrl.f.TiristorReady = 1;
|
phase_A.ctrl.f.TiristorReady = 1;
|
||||||
phase_B.ctrl.f.TiristorReady = 1;
|
phase_B.ctrl.f.TiristorReady = 1;
|
||||||
phase_C.ctrl.f.TiristorReady = 1;
|
phase_C.ctrl.f.TiristorReady = 1;
|
||||||
|
Upp.Go = 0;
|
||||||
disconnect_upp();
|
disconnect_upp();
|
||||||
}
|
}
|
||||||
// останавливаем упп если выставлен флаг
|
|
||||||
|
// Если установлен флаг остановки, останавливаем работу и подключаем УПП (прямое питание)
|
||||||
if(Upp.GoStop)
|
if(Upp.GoStop)
|
||||||
{
|
{
|
||||||
Upp.Go = 0;
|
Upp.Go = 0;
|
||||||
connect_upp();
|
connect_upp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Если в режиме подготовки (запуска)
|
||||||
if(Upp.Prepare)
|
if(Upp.Prepare)
|
||||||
{
|
{
|
||||||
|
// Если УПП в состоянии отключения, подключаем его (готовим к работе)
|
||||||
if(Upp.Disconnected)
|
if(Upp.Disconnected)
|
||||||
{
|
{
|
||||||
connect_upp();
|
connect_upp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Обрабатываем каждую фазу (детектирование нуля, управление углом тиристора)
|
||||||
upp_phase_routine(&phase_A);
|
upp_phase_routine(&phase_A);
|
||||||
upp_phase_routine(&phase_B);
|
upp_phase_routine(&phase_B);
|
||||||
upp_phase_routine(&phase_C);
|
upp_phase_routine(&phase_C);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Если работа разрешена (флаг Go)
|
||||||
if(Upp.Go)
|
if(Upp.Go)
|
||||||
{
|
{
|
||||||
|
// Если всё ещё в подготовке, проверяем готовность тиристоров
|
||||||
if(Upp.Prepare)
|
if(Upp.Prepare)
|
||||||
{
|
{
|
||||||
|
// Если все тиристоры готовы — снимаем флаг подготовки и продолжаем работу
|
||||||
if(phase_A.ctrl.f.TiristorReady && phase_B.ctrl.f.TiristorReady && phase_C.ctrl.f.TiristorReady)
|
if(phase_A.ctrl.f.TiristorReady && phase_B.ctrl.f.TiristorReady && phase_C.ctrl.f.TiristorReady)
|
||||||
{
|
{
|
||||||
Upp.Prepare = 0;
|
Upp.Prepare = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Если хоть один тиристор не готов — выходим, не продолжая управление
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Если во время работы произошло отключение УПП — ставим флаг принудительной остановки
|
||||||
if(Upp.Disconnected)
|
if(Upp.Disconnected)
|
||||||
{
|
{
|
||||||
Upp.ForceStop = 1;
|
Upp.ForceStop = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// если все фазы дошли до минимума в режиме разгона, то выставляем флаг на отключение упп (прямая подача питания на двигатель)
|
// Проверяем условие достижения минимального угла (минимальная задержка) во время запуска (direction == 0)
|
||||||
|
// Это значит, что тиристоры открыты максимально рано — можно перейти на прямое питание двигателя
|
||||||
if( (phase_A.ctrl.angle.delay_us == phase_A.ctrl.angle.Init->delay_min_us) &&
|
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_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))
|
(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
|
else
|
||||||
{
|
{
|
||||||
Upp.GoDisconnect = 0;
|
Upp.GoDisconnect = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// если все фазы дошли до максимума в режиме торможения, то выставляем флаг на остановку упп (выключения питания на двигателе)
|
// Проверяем условие достижения максимального угла (максимальная задержка) во время торможения (direction == 1)
|
||||||
|
// Это значит, что тиристоры максимально закрыты — нужно остановить питание двигателя
|
||||||
if( (phase_A.ctrl.angle.delay_us == phase_A.ctrl.angle.Init->delay_max_us) &&
|
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_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))
|
(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
|
else
|
||||||
{
|
{
|
||||||
Upp.GoStop = 0;
|
Upp.GoStop = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Продолжаем обработку фаз — обновляем состояние и проверяем условия управления тиристорами
|
||||||
upp_phase_routine(&phase_A);
|
upp_phase_routine(&phase_A);
|
||||||
upp_phase_routine(&phase_B);
|
upp_phase_routine(&phase_B);
|
||||||
upp_phase_routine(&phase_C);
|
upp_phase_routine(&phase_C);
|
||||||
|
|
||||||
|
// Управляем тиристорами каждой фазы с помощью функций контроля угла и самого тиристора
|
||||||
upp_phase_control(&phase_A);
|
upp_phase_control(&phase_A);
|
||||||
upp_phase_control(&phase_B);
|
upp_phase_control(&phase_B);
|
||||||
upp_phase_control(&phase_C);
|
upp_phase_control(&phase_C);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Если флаг Go не установлен, сбрасываем углы управления тиристорами для всех фаз
|
||||||
tiristor_angle_reset(&phase_A.ctrl);
|
tiristor_angle_reset(&phase_A.ctrl);
|
||||||
tiristor_angle_reset(&phase_B.ctrl);
|
tiristor_angle_reset(&phase_B.ctrl);
|
||||||
tiristor_angle_reset(&phase_C.ctrl);
|
tiristor_angle_reset(&phase_C.ctrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Функция безопасного запуска УПП
|
||||||
|
*
|
||||||
|
* @details Следит за изменениями флага GoSafe и запускает или останавливает пускатель,
|
||||||
|
* сбрасывая угол задержки тиристоров в зависимости от направления.
|
||||||
|
*/
|
||||||
void upp_safe_go(void)
|
void upp_safe_go(void)
|
||||||
{
|
{
|
||||||
static int prev_gosafe;
|
static int prev_gosafe; // Статическая переменная для хранения предыдущего значения флага GoSafe
|
||||||
|
|
||||||
|
|
||||||
|
// Если текущее значение GoSafe больше предыдущего — это сигнал о старте в режиме запуска (направление 0)
|
||||||
if(Upp.GoSafe > prev_gosafe)
|
if(Upp.GoSafe > prev_gosafe)
|
||||||
{
|
{
|
||||||
Upp.angleInit.direction = 0;
|
Upp.angleInit.direction = 0; // Устанавливаем направление пуска (разгон)
|
||||||
Upp.Prepare = 1;
|
Upp.Prepare = 1; // Включаем режим подготовки
|
||||||
Upp.Go = 1;
|
Upp.Go = 1; // Включаем основной флаг запуска работы УПП
|
||||||
|
|
||||||
|
// Сбрасываем углы управления тиристорами для всех фаз — начинаем с начального состояния
|
||||||
tiristor_angle_reset(&phase_A.ctrl);
|
tiristor_angle_reset(&phase_A.ctrl);
|
||||||
tiristor_angle_reset(&phase_B.ctrl);
|
tiristor_angle_reset(&phase_B.ctrl);
|
||||||
tiristor_angle_reset(&phase_C.ctrl);
|
tiristor_angle_reset(&phase_C.ctrl);
|
||||||
}
|
}
|
||||||
|
// Если текущее значение GoSafe меньше предыдущего — это сигнал о старте в режиме торможения (направление 1)
|
||||||
else if (Upp.GoSafe < prev_gosafe)
|
else if (Upp.GoSafe < prev_gosafe)
|
||||||
{
|
{
|
||||||
Upp.angleInit.direction = 1;
|
Upp.angleInit.direction = 1; // Устанавливаем направление торможения
|
||||||
Upp.Prepare = 1;
|
Upp.Prepare = 1; // Включаем режим подготовки
|
||||||
Upp.Go = 1;
|
Upp.Go = 1; // Включаем основной флаг запуска работы УПП
|
||||||
|
|
||||||
|
// Сбрасываем углы управления тиристорами для всех фаз — начинаем с начального состояния
|
||||||
tiristor_angle_reset(&phase_A.ctrl);
|
tiristor_angle_reset(&phase_A.ctrl);
|
||||||
tiristor_angle_reset(&phase_B.ctrl);
|
tiristor_angle_reset(&phase_B.ctrl);
|
||||||
tiristor_angle_reset(&phase_C.ctrl);
|
tiristor_angle_reset(&phase_C.ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Обновляем сохранённое предыдущее значение GoSafe для отслеживания изменений в следующем вызове
|
||||||
prev_gosafe = Upp.GoSafe;
|
prev_gosafe = Upp.GoSafe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Отключение питания УПП (разрыв всех фаз)
|
||||||
|
*
|
||||||
|
* @details Если тиристор готов, вызывает макросы отключения фаз,
|
||||||
|
* после чего выставляет соответствующие флаги состояния.
|
||||||
|
*/
|
||||||
void disconnect_upp(void)
|
void disconnect_upp(void)
|
||||||
{
|
{
|
||||||
if(phase_A.ctrl.f.TiristorReady)
|
// Если тиристоры фазы A открыты, подключаем фазу напрямую
|
||||||
{
|
if(phase_A.ctrl.f.TiristorReady)
|
||||||
disconnect_phase(&phase_A);
|
{
|
||||||
}
|
disconnect_phase(&phase_A);
|
||||||
|
}
|
||||||
if(phase_B.ctrl.f.TiristorReady)
|
|
||||||
{
|
// Аналогично для фазы B
|
||||||
disconnect_phase(&phase_B);
|
if(phase_B.ctrl.f.TiristorReady)
|
||||||
}
|
{
|
||||||
|
disconnect_phase(&phase_B);
|
||||||
if(phase_C.ctrl.f.TiristorReady)
|
}
|
||||||
{
|
|
||||||
disconnect_phase(&phase_C);
|
// Аналогично для фазы C
|
||||||
}
|
if(phase_C.ctrl.f.TiristorReady)
|
||||||
|
{
|
||||||
if(phase_A.disconnect.Disconnected && phase_B.disconnect.Disconnected && phase_C.disconnect.Disconnected)
|
disconnect_phase(&phase_C);
|
||||||
{
|
}
|
||||||
Upp.Disconnected = 1;
|
|
||||||
Upp.GoDisconnect = 0;
|
// Если УПП на всех трех фазах отключены
|
||||||
Upp.Go = 0;
|
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)
|
void connect_upp(void)
|
||||||
{
|
{
|
||||||
tiristor_disable(&phase_A.ctrl);
|
// Отключаем управление тиристорами для всех фаз
|
||||||
tiristor_disable(&phase_B.ctrl);
|
tiristor_disable(&phase_A.ctrl);
|
||||||
tiristor_disable(&phase_C.ctrl);
|
tiristor_disable(&phase_B.ctrl);
|
||||||
|
tiristor_disable(&phase_C.ctrl);
|
||||||
|
|
||||||
connect_phase(&phase_A);
|
// Подключаем УПП к каждой фазе)
|
||||||
connect_phase(&phase_B);
|
connect_phase(&phase_A);
|
||||||
connect_phase(&phase_C);
|
connect_phase(&phase_B);
|
||||||
|
connect_phase(&phase_C);
|
||||||
Upp.Disconnected = 0;
|
|
||||||
|
// Сбрасываем флаг, указывающий на то, что УПП было отключено
|
||||||
|
Upp.Disconnected = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Управление одной фазой УПП
|
||||||
|
* @param phase Указатель на структуру фазы Phase_t
|
||||||
|
*
|
||||||
|
* @details Контролирует угол и включает/отключает тиристор для данной фазы.
|
||||||
|
*/
|
||||||
void upp_phase_control(Phase_t *phase)
|
void upp_phase_control(Phase_t *phase)
|
||||||
{
|
{
|
||||||
tiristor_angle_control(&phase->ctrl);
|
tiristor_angle_control(&phase->ctrl);
|
||||||
tiristor_control(&phase->ctrl);
|
tiristor_control(&phase->ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Обработка фазы при каждом нулевом переходе синусоиды
|
||||||
|
* @param phase Указатель на структуру фазы Phase_t
|
||||||
|
*
|
||||||
|
* @details Обновляет состояние детектора нулевого перехода,
|
||||||
|
* запускает задержку угла тиристора,
|
||||||
|
* отключает тиристор, если он был включен.
|
||||||
|
*/
|
||||||
void upp_phase_routine(Phase_t *phase)
|
void upp_phase_routine(Phase_t *phase)
|
||||||
{
|
{
|
||||||
|
// Обновляем детектор нулевого перехода по текущему состоянию входного сигнала
|
||||||
zero_cross_update(&phase->zc_detector);
|
zero_cross_update(&phase->zc_detector);
|
||||||
|
|
||||||
|
// Если обнаружен нулевой переход (синусоида пересекла 0)
|
||||||
if(is_zero_cross(&phase->zc_detector))
|
if(is_zero_cross(&phase->zc_detector))
|
||||||
{
|
{
|
||||||
|
// Запускаем отсчёт задержки до открытия тиристора (по углу)
|
||||||
tiristor_start_angle_delay(&phase->ctrl);
|
tiristor_start_angle_delay(&phase->ctrl);
|
||||||
|
|
||||||
|
// Если тиристор был включён в предыдущем полупериоде — отключаем его
|
||||||
if (phase->ctrl.f.TiristorIsEnable)
|
if (phase->ctrl.f.TiristorIsEnable)
|
||||||
tiristor_disable(&phase->ctrl);
|
tiristor_disable(&phase->ctrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Расчёт параметров угла запуска тиристора
|
||||||
|
* @param angle Указатель на структуру AngleInit_t для записи параметров
|
||||||
|
* @return int 1, если произошли изменения параметров, иначе 0
|
||||||
|
*
|
||||||
|
* @details Проверяет изменения в параметрах управления и при необходимости
|
||||||
|
* пересчитывает максимальные и минимальные задержки, шаг изменения угла,
|
||||||
|
* а также изменяет прескалер таймера.
|
||||||
|
*/
|
||||||
int GetAngleInit(AngleInit_t *angle)
|
int GetAngleInit(AngleInit_t *angle)
|
||||||
{
|
{
|
||||||
static float sine_freq_old = 0;
|
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; // Задаются в процентах
|
static float max_duty_old = 0, min_duty_old = 0; // Задаются в процентах
|
||||||
int update = 0;
|
int update = 0;
|
||||||
|
|
||||||
|
// Проверка, изменились ли параметры: частота, скважности
|
||||||
if( (Upp.sine_freq != sine_freq_old) &&
|
if( (Upp.sine_freq != sine_freq_old) &&
|
||||||
(Upp.max_duty != max_duty_old) &&
|
(Upp.max_duty != max_duty_old) &&
|
||||||
(Upp.min_duty != min_duty_old) )
|
(Upp.min_duty != min_duty_old) )
|
||||||
@ -218,64 +310,73 @@ int GetAngleInit(AngleInit_t *angle)
|
|||||||
min_duty_old = Upp.min_duty;
|
min_duty_old = Upp.min_duty;
|
||||||
max_duty_old = Upp.max_duty;
|
max_duty_old = Upp.max_duty;
|
||||||
sine_freq_old = Upp.sine_freq;
|
sine_freq_old = Upp.sine_freq;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Проверка, изменились ли длительность
|
||||||
if(Upp.Duration != Duration_old)
|
if(Upp.Duration != Duration_old)
|
||||||
{
|
{
|
||||||
update = 1;
|
update = 1;
|
||||||
Duration_old = Upp.Duration;
|
Duration_old = Upp.Duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(update)
|
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_max_us = (uint32_t)(Upp.max_duty * half_period_us);
|
||||||
angle->delay_min_us = (uint32_t)(Upp.min_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))
|
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_max_us /= 10;
|
||||||
angle->delay_min_us /= 10;
|
angle->delay_min_us /= 10;
|
||||||
TIMER->PSC = 719;
|
TIMER->PSC = 719;
|
||||||
|
|
||||||
if((angle->delay_max_us > 0xFFFF) || (angle->delay_min_us > 0xFFFF))
|
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_max_us /= 10;
|
||||||
angle->delay_min_us /= 10;
|
angle->delay_min_us /= 10;
|
||||||
TIMER->PSC = 7299;
|
TIMER->PSC = 7299;
|
||||||
|
|
||||||
if ((angle->delay_max_us > 0xFFFF) || (angle->delay_min_us > 0xFFFF))
|
if ((angle->delay_max_us > 0xFFFF) || (angle->delay_min_us > 0xFFFF))
|
||||||
{
|
{
|
||||||
// если все еще переполнение то выключаем всё
|
// Если даже при этом переполнение — аварийная остановка
|
||||||
Upp.ForceStop = 1;
|
Upp.ForceStop = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Задержки помещаются — устанавливаем стандартный прескалер (1 мкс)
|
||||||
TIMER->PSC = 71;
|
TIMER->PSC = 71;
|
||||||
}
|
}
|
||||||
|
|
||||||
// duration
|
// Перевод длительности разгона/торможения из секунд в миллисекунды
|
||||||
float duration_ms = Duration_old * 1000.0f;
|
float duration_ms = Duration_old * 1000.0f;
|
||||||
uint32_t steps = duration_ms / angle->sample_time_ms;
|
uint32_t steps = duration_ms / angle->sample_time_ms;
|
||||||
if (steps == 0) steps = 1;
|
if (steps == 0) steps = 1;
|
||||||
|
|
||||||
|
// Вычисление шага изменения задержки на каждом шаге
|
||||||
if (angle->delay_max_us > angle->delay_min_us)
|
if (angle->delay_max_us > angle->delay_min_us)
|
||||||
angle->delay_step_us = (angle->delay_max_us - angle->delay_min_us) / steps;
|
angle->delay_step_us = (angle->delay_max_us - angle->delay_min_us) / steps;
|
||||||
else
|
else
|
||||||
angle->delay_step_us = 0;
|
angle->delay_step_us = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return update;
|
return update;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Инициализация УПП и связанных структур
|
||||||
|
*
|
||||||
|
* @details Настраивает параметры управления, GPIO для фаз,
|
||||||
|
* инициализирует тиристоры, запускает таймер и настраивает детектор нулевого перехода.
|
||||||
|
*/
|
||||||
void upp_init(void)
|
void upp_init(void)
|
||||||
{
|
{
|
||||||
Upp.max_duty = 0.9;
|
Upp.max_duty = 0.9;
|
||||||
|
@ -9,46 +9,69 @@
|
|||||||
#include "zero_cross.h"
|
#include "zero_cross.h"
|
||||||
#include "tiristor.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
|
typedef struct
|
||||||
{
|
{
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
unsigned Disconnected:1;
|
unsigned Disconnected:1; /**< Флаг разрыва фазы */
|
||||||
GPIO_TypeDef *gpiox;
|
GPIO_TypeDef *gpiox; /**< Порт GPIO для разрыва */
|
||||||
uint32_t gpio_pin;
|
uint32_t gpio_pin; /**< Пин GPIO для разрыва */
|
||||||
}disconnect;
|
}disconnect;
|
||||||
|
|
||||||
ZeroCrossDetector_t zc_detector;
|
ZeroCrossDetector_t zc_detector; /**< Детектор пересечения нуля */
|
||||||
TiristorControl_t ctrl;
|
TiristorControl_t ctrl; /**< Управление тиристором */
|
||||||
} Phase_t; // структура для фазы
|
} Phase_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @struct UPP_Control_t
|
||||||
|
* @brief Основная структура управления устройством плавного пуска
|
||||||
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned GoSafe:1;
|
unsigned GoSafe:1; /**< Флаг безопасного запуска */
|
||||||
unsigned Go:1;
|
unsigned Go:1; /**< Флаг запуска */
|
||||||
unsigned GoStop:1;
|
unsigned GoStop:1; /**< Флаг остановки */
|
||||||
unsigned Prepare:1;
|
unsigned Prepare:1; /**< Флаг подготовки */
|
||||||
unsigned Disconnected:1;
|
unsigned Disconnected:1; /**< Флаг разрыва */
|
||||||
unsigned GoDisconnect:1;
|
unsigned GoDisconnect:1; /**< Флаг отключения */
|
||||||
unsigned ForceStop:1;
|
unsigned ForceStop:1; /**< Флаг форсированной остановки */
|
||||||
unsigned ForceDisconnect:1;
|
unsigned ForceDisconnect:1; /**< Флаг форсированного отключения */
|
||||||
unsigned PreGoDone:1;
|
unsigned PreGoDone:1; /**< Флаг завершения подготовки */
|
||||||
|
|
||||||
|
float Duration; /**< Время нарастания и спада напряжение через УПП */
|
||||||
float Duration;
|
float sine_freq; /**< Частота сети */
|
||||||
float sine_freq;
|
float max_duty; /**< Максимальная скважность угла открытия */
|
||||||
float max_duty;
|
float min_duty; /**< Минимальная скважность угла открытия */
|
||||||
float min_duty;
|
|
||||||
|
AngleInit_t angleInit; /**< Настройки угла открытия тиристора */
|
||||||
AngleInit_t angleInit;
|
} UPP_Control_t;
|
||||||
}UPP_Control_t;
|
|
||||||
|
|
||||||
|
|
||||||
extern Phase_t phase_A;
|
extern Phase_t phase_A;
|
||||||
@ -56,14 +79,28 @@ extern Phase_t phase_B;
|
|||||||
extern Phase_t phase_C;
|
extern Phase_t phase_C;
|
||||||
extern UPP_Control_t Upp;
|
extern UPP_Control_t Upp;
|
||||||
|
|
||||||
|
/** Основной цикл работы устройства плавного пуска */
|
||||||
void upp_main(void);
|
void upp_main(void);
|
||||||
|
|
||||||
|
/** Выполнение безопасного запуска устройства */
|
||||||
void upp_safe_go(void);
|
void upp_safe_go(void);
|
||||||
|
|
||||||
|
/** Отключение устройства плавного пуска (разрыв фаз) */
|
||||||
void disconnect_upp(void);
|
void disconnect_upp(void);
|
||||||
|
|
||||||
|
/** Подключение устройства плавного пуска (восстановление фаз) */
|
||||||
void connect_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);
|
int GetAngleInit(AngleInit_t *angle);
|
||||||
|
|
||||||
|
/** Инициализация устройства плавного пуска */
|
||||||
void upp_init(void);
|
void upp_init(void);
|
||||||
|
|
||||||
|
#endif //__UPP_H
|
||||||
#endif //__UPP_H
|
|
||||||
|
@ -2,55 +2,92 @@
|
|||||||
|
|
||||||
ADCFilter_t AdcFilter;
|
ADCFilter_t AdcFilter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Инициализация структуры детектора перехода через ноль
|
||||||
|
* @param zc Указатель на структуру ZeroCrossDetector_t
|
||||||
|
* @param zeroLevel Значение уровня АЦП, соответствующее нулю (mid-scale)
|
||||||
|
*/
|
||||||
void zero_cross_Init(ZeroCrossDetector_t *zc, uint16_t zeroLevel)
|
void zero_cross_Init(ZeroCrossDetector_t *zc, uint16_t zeroLevel)
|
||||||
{
|
{
|
||||||
zc->lastSample = 0;
|
// Обнуляем последнее измеренное значение сдвига относительно нуля
|
||||||
zc->f.ZeroCrossDetected = 0;
|
zc->lastSample = 0;
|
||||||
zc->zeroLevel = zeroLevel;
|
|
||||||
|
// Сбрасываем флаг обнаружения перехода через ноль
|
||||||
|
zc->f.ZeroCrossDetected = 0;
|
||||||
|
|
||||||
|
// Запоминаем уровень, соответствующий нулю (обычно mid-scale АЦП)
|
||||||
|
zc->zeroLevel = zeroLevel;
|
||||||
}
|
}
|
||||||
// апдейт флага зерокросс детектед
|
|
||||||
|
/**
|
||||||
|
* @brief Обновление флага перехода через ноль
|
||||||
|
* @param zc Указатель на структуру ZeroCrossDetector_t
|
||||||
|
* @details Если аппаратный детектор включен, просто переносим флаг EXTI.
|
||||||
|
* Иначе — анализируем разницу между текущим и предыдущим значением АЦП,
|
||||||
|
* чтобы определить, произошёл ли переход через ноль.
|
||||||
|
*/
|
||||||
void zero_cross_update(ZeroCrossDetector_t *zc)
|
void zero_cross_update(ZeroCrossDetector_t *zc)
|
||||||
{
|
{
|
||||||
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
||||||
zc->f.ZeroCrossDetected = zc->f.EXTIZeroCrossDetected;
|
// Используем флаг аппаратного прерывания EXTI для установки флага перехода через ноль
|
||||||
|
zc->f.ZeroCrossDetected = zc->f.EXTIZeroCrossDetected;
|
||||||
#else
|
#else
|
||||||
uint16_t adcValue;
|
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;
|
|
||||||
|
|
||||||
if ((zc->lastSample < 0 && zc->currSample >= 0) ||
|
// Проверяем, обновились ли данные АЦП (фильтр)
|
||||||
(zc->lastSample > 0 && zc->currSample <= 0))
|
if(adc_is_data_updated(&zc->AdcFilter))
|
||||||
{
|
{
|
||||||
zc->f.ZeroCrossDetected = 1;
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Проверка наличия перехода через ноль и сброс флагов
|
||||||
|
* @param zc Указатель на структуру ZeroCrossDetector_t
|
||||||
|
* @return int 1 — переход через ноль обнаружен, 0 — нет
|
||||||
|
* @details Если переход обнаружен, сбрасываем флаги и возвращаем 1,
|
||||||
|
* иначе возвращаем 0.
|
||||||
|
*/
|
||||||
int is_zero_cross(ZeroCrossDetector_t *zc)
|
int is_zero_cross(ZeroCrossDetector_t *zc)
|
||||||
{
|
{
|
||||||
if(zc->f.ZeroCrossDetected)
|
if(zc->f.ZeroCrossDetected)
|
||||||
{
|
{
|
||||||
zc->f.ZeroCrossDetected = 0;
|
// Сброс флагов после обнаружения
|
||||||
zc->f.EXTIZeroCrossDetected = 0;
|
zc->f.ZeroCrossDetected = 0;
|
||||||
return 1;
|
zc->f.EXTIZeroCrossDetected = 0;
|
||||||
}
|
return 1;
|
||||||
return 0;
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
||||||
|
/**
|
||||||
|
* @brief Обработчик прерывания EXTI для аппаратного детектора перехода через ноль
|
||||||
|
* @param zc Указатель на структуру ZeroCrossDetector_t
|
||||||
|
* @details Устанавливает флаг аппаратного перехода через ноль.
|
||||||
|
*/
|
||||||
void zero_cross_update_EXTI(ZeroCrossDetector_t *zc)
|
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 "main.h"
|
||||||
#include "adc_filter.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
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned WaitForZeroCrossDetected : 1;
|
unsigned WaitForZeroCrossDetected : 1; /**< Ожидание обнаружения перехода через ноль */
|
||||||
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
||||||
unsigned EXTIZeroCrossDetected:1;
|
unsigned EXTIZeroCrossDetected : 1; /**< Флаг обнаружения нуля аппаратным прерыванием EXTI */
|
||||||
#endif
|
#endif
|
||||||
unsigned ZeroCrossDetected:1;
|
unsigned ZeroCrossDetected : 1; /**< Флаг обнаружения перехода через ноль */
|
||||||
}ZeroCrossFlags;
|
} ZeroCrossFlags;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Структура детектора перехода через ноль
|
||||||
|
*/
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
ZeroCrossFlags f;
|
ZeroCrossFlags f; /**< Флаги состояния детектора */
|
||||||
int currSample;
|
int currSample; /**< Текущее значение выборки */
|
||||||
int16_t lastSample; // предыдущее значение (относительно нуля)
|
int16_t lastSample; /**< Предыдущее значение выборки (относительно нуля) */
|
||||||
uint16_t zeroLevel; // уровень, соответствующий "нулю", обычно mid-scale
|
uint16_t zeroLevel; /**< Уровень, соответствующий "нулю", обычно mid-scale АЦП */
|
||||||
ADCFilter_t AdcFilter;
|
ADCFilter_t AdcFilter; /**< Фильтр АЦП для сглаживания входных данных */
|
||||||
} ZeroCrossDetector_t;
|
} ZeroCrossDetector_t;
|
||||||
|
|
||||||
|
/** Инициализация структуры детектора перехода через ноль */
|
||||||
void zero_cross_Init(ZeroCrossDetector_t *zc, uint16_t zeroLevel);
|
void zero_cross_Init(ZeroCrossDetector_t *zc, uint16_t zeroLevel);
|
||||||
|
/** Обновление состояния детектора перехода через ноль (через АЦП или аппаратный метод) */
|
||||||
void zero_cross_update(ZeroCrossDetector_t *zc);
|
void zero_cross_update(ZeroCrossDetector_t *zc);
|
||||||
|
/** Проверка, был ли обнаружен переход через ноль */
|
||||||
int is_zero_cross(ZeroCrossDetector_t *zc);
|
int is_zero_cross(ZeroCrossDetector_t *zc);
|
||||||
|
|
||||||
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
#ifdef HARDWARE_ZERO_CROSS_DETECT
|
||||||
|
/** Обновление состояния детектора перехода через ноль при аппаратном прерывании EXTI*/
|
||||||
void zero_cross_update_EXTI(ZeroCrossDetector_t *zc);
|
void zero_cross_update_EXTI(ZeroCrossDetector_t *zc);
|
||||||
#endif
|
#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>
|
<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>
|
</SetRegEntry>
|
||||||
</TargetDriverDllRegistry>
|
</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>
|
<Tracepoint>
|
||||||
<THDelay>0</THDelay>
|
<THDelay>0</THDelay>
|
||||||
</Tracepoint>
|
</Tracepoint>
|
||||||
|
Loading…
Reference in New Issue
Block a user