2 Commits

Author SHA1 Message Date
Razvalyaev
bfcd696ccd тест тиристоров 2025-05-16 08:51:00 +03:00
Razvalyaev
f34eb8b900 тест zero cross detected 2025-05-16 08:25:29 +03:00
109 changed files with 357 additions and 12102 deletions

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -55,9 +55,6 @@ void SVC_Handler(void);
void DebugMon_Handler(void);
void PendSV_Handler(void);
void SysTick_Handler(void);
void EXTI0_IRQHandler(void);
void EXTI1_IRQHandler(void);
void EXTI2_IRQHandler(void);
/* USER CODE BEGIN EFP */
/* USER CODE END EFP */

View File

@@ -32,19 +32,14 @@ extern "C" {
/* USER CODE END Includes */
extern TIM_HandleTypeDef htim1;
extern TIM_HandleTypeDef htim2;
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_TIM1_Init(void);
void MX_TIM2_Init(void);
void HAL_TIM_MspPostInit(TIM_HandleTypeDef *htim);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */

View File

@@ -42,59 +42,10 @@
void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14, GPIO_PIN_RESET);
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pins : PA5 PA6 PA7 */
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : PB0 PB1 PB2 */
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pins : PB12 PB13 PB14 */
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* EXTI interrupt init*/
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
HAL_NVIC_SetPriority(EXTI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
}

View File

@@ -18,7 +18,7 @@
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
//#include "adc.h"
#include "adc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
@@ -89,15 +89,11 @@ int main(void)
/* Initialize all configured peripherals */
MX_GPIO_Init();
//MX_ADC1_Init();
MX_ADC1_Init();
MX_TIM2_Init();
//MX_USART1_UART_Init();
//MX_TIM1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
upp_init();
//HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
//Upp.Duration = 8;
//Upp.sine_freq = 50;
/* USER CODE END 2 */
/* Infinite loop */
@@ -118,49 +114,48 @@ int main(void)
*/
void SystemClock_Config(void)
{
//RCC_OscInitTypeDef RCC_OscInitStruct = {0};
//RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
//RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
///** Initializes the RCC Oscillators according to the specified parameters
//* in the RCC_OscInitTypeDef structure.
//*/
//RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
//RCC_OscInitStruct.HSEState = RCC_HSE_ON;
//RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
//RCC_OscInitStruct.HSIState = RCC_HSI_ON;
//RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
//RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
//RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
//if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
//{
// Error_Handler();
//}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
///** Initializes the CPU, AHB and APB buses clocks
//*/
//RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
// |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
//RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
//RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
//RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
//RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
//if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
//{
// Error_Handler();
//}
//PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
//PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
//if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
//{
// Error_Handler();
//}
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
uint32_t HAL_RCCEx_GetPeriphCLKFreq(uint32_t PeriphClk) {}
/* USER CODE END 4 */
/**

View File

@@ -22,7 +22,6 @@
#include "stm32f1xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "upp.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
@@ -199,48 +198,6 @@ void SysTick_Handler(void)
/* please refer to the startup file (startup_stm32f1xx.s). */
/******************************************************************************/
/**
* @brief This function handles EXTI line0 interrupt.
*/
void EXTI0_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_IRQn 0 */
/* USER CODE END EXTI0_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
/* USER CODE BEGIN EXTI0_IRQn 1 */
zero_cross_update_EXTI(&phase_A.zc_detector);
/* USER CODE END EXTI0_IRQn 1 */
}
/**
* @brief This function handles EXTI line1 interrupt.
*/
void EXTI1_IRQHandler(void)
{
/* USER CODE BEGIN EXTI1_IRQn 0 */
/* USER CODE END EXTI1_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
/* USER CODE BEGIN EXTI1_IRQn 1 */
zero_cross_update_EXTI(&phase_B.zc_detector);
/* USER CODE END EXTI1_IRQn 1 */
}
/**
* @brief This function handles EXTI line2 interrupt.
*/
void EXTI2_IRQHandler(void)
{
/* USER CODE BEGIN EXTI2_IRQn 0 */
/* USER CODE END EXTI2_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2);
/* USER CODE BEGIN EXTI2_IRQn 1 */
zero_cross_update_EXTI(&phase_C.zc_detector);
/* USER CODE END EXTI2_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */

View File

@@ -24,79 +24,8 @@
/* USER CODE END 0 */
TIM_HandleTypeDef htim1;
TIM_HandleTypeDef htim2;
/* TIM1 init function */
void MX_TIM1_Init(void)
{
/* USER CODE BEGIN TIM1_Init 0 */
/* USER CODE END TIM1_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/* USER CODE BEGIN TIM1_Init 1 */
/* USER CODE END TIM1_Init 1 */
htim1.Instance = TIM1;
htim1.Init.Prescaler = 72-1;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 20000;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 10000;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM1_Init 2 */
/* USER CODE END TIM1_Init 2 */
HAL_TIM_MspPostInit(&htim1);
}
/* TIM2 init function */
void MX_TIM2_Init(void)
{
@@ -141,18 +70,7 @@ void MX_TIM2_Init(void)
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM1)
{
/* USER CODE BEGIN TIM1_MspInit 0 */
/* USER CODE END TIM1_MspInit 0 */
/* TIM1 clock enable */
__HAL_RCC_TIM1_CLK_ENABLE();
/* USER CODE BEGIN TIM1_MspInit 1 */
/* USER CODE END TIM1_MspInit 1 */
}
else if(tim_baseHandle->Instance==TIM2)
if(tim_baseHandle->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspInit 0 */
@@ -164,47 +82,11 @@ void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
/* USER CODE END TIM2_MspInit 1 */
}
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM1)
{
/* USER CODE BEGIN TIM1_MspPostInit 0 */
/* USER CODE END TIM1_MspPostInit 0 */
__HAL_RCC_GPIOA_CLK_ENABLE();
/**TIM1 GPIO Configuration
PA8 ------> TIM1_CH1
*/
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN TIM1_MspPostInit 1 */
/* USER CODE END TIM1_MspPostInit 1 */
}
}
void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{
if(tim_baseHandle->Instance==TIM1)
{
/* USER CODE BEGIN TIM1_MspDeInit 0 */
/* USER CODE END TIM1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_TIM1_CLK_DISABLE();
/* USER CODE BEGIN TIM1_MspDeInit 1 */
/* USER CODE END TIM1_MspDeInit 1 */
}
else if(tim_baseHandle->Instance==TIM2)
if(tim_baseHandle->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspDeInit 0 */

View File

@@ -1,63 +1,35 @@
#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;
}

View File

@@ -3,37 +3,25 @@
#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; /**< Указатель на структуру HAL АЦП */
uint32_t sum; /**< Сумма накопленных значений для усреднения */
uint16_t count; /**< Текущий счётчик накопленных значений */
uint16_t bufferSize; /**< Размер буфера для усреднения (число выборок) */
AdcFilterFlags f;
uint16_t AdcResult;
ADC_HandleTypeDef *hadc;
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

View File

@@ -1,143 +1,97 @@
#include "upp.h"
#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(); // Текущее время в миллисекундах
{
uint32_t current_time_ms = HAL_GetTick();
if ((current_time_ms - angle->last_update_ms) >= angle->sample_time_ms)
{
angle->last_update_ms = current_time_ms;
// Проверяем, прошло ли нужное время с последнего обновления
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;
}
}
if (angle->delay_us > angle->delay_min_us)
{
angle->delay_us -= angle->delay_step_us;
if (angle->delay_us < angle->delay_min_us)
angle->delay_us = angle->delay_min_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 ((uint16_t)((uint16_t)TIMER->CNT - ctrl->angle.start_delay_us) > ctrl->angle.delay_us)
{
#ifndef DISABLE_TIRISTOR_READY
if(ctrl->f.TiristorDone == 0)
{
ctrl->f.EnableTiristor = 1;
ctrl->f.TiristorDone = 1;
}
#else
ctrl->f.EnableTiristor = 1;
#endif
}
}
/**
* @brief Запуск отсчёта задержки для открытия тиристора
* @param ctrl Указатель на структуру управления тиристором
*/
void tiristor_start_angle_delay(TiristorControl_t *ctrl)
{
ctrl->f.TiristorReady = 1; // Устанавливаем флаг готовности тиристора к включению
ctrl->angle.start_delay_tick = TIMER->CNT; // Запоминаем текущее значение счётчика таймера
#ifndef DISABLE_TIRISTOR_READY
ctrl->f.TiristorDone = 0;
#endif
ctrl->angle.start_delay_us = TIMER->CNT;
}
/**
* @brief Включение тиристора путём установки GPIO в состояние открытия
* @param ctrl Указатель на структуру управления тиристором
*/
void tiristor_enable(TiristorControl_t *ctrl)
{
// Открываем тиристор, установив соответствующий пин в высокое состояние
ctrl->gpiox->ODR |= ctrl->gpio_pin;
ctrl->f.TiristorIsEnable = 1; // Устанавливаем флаг, что тиристор включен
//HAL_GPIO_WritePin(ctrl->gpiox, ctrl->gpio_pin, GPIO_TIRISTOR_OPEN);
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;
ctrl->f.TiristorIsEnable = 0; // Снимаем флаг включения тиристора
ctrl->gpiox->ODR &= ~ctrl->gpio_pin;
//HAL_GPIO_WritePin(ctrl->gpiox, ctrl->gpio_pin, GPIO_TIRISTOR_CLOSE);
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;
}
/**
* @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->open_time = 1; // Сохраняем порт GPIO
ctrl->gpiox = gpiox; // Сохраняем порт GPIO
ctrl->gpio_pin = gpio_pin; // Сохраняем номер пина GPIO
tiristor_angle_reset(ctrl); // Сбрасываем угол открытия тиристора на начальное значение
}
ctrl->gpiox = gpiox;
ctrl->gpio_pin = gpio_pin;
ctrl->angle.delay_max_us = 8000;
ctrl->angle.delay_min_us = 500;
ctrl->angle.delay_us = 8000;
ctrl->angle.delay_step_us = 800;
ctrl->angle.sample_time_ms = 20;
ctrl->open_time = 1;
TIMER->CR1 |= TIM_CR1_CEN;
}

View File

@@ -5,108 +5,53 @@
#include "tim.h"
#define GPIO_TIRISTOR_OPEN GPIO_PIN_SET /**< Состояние GPIO для открытия тиристора */
#define GPIO_TIRISTOR_CLOSE GPIO_PIN_RESET /**< Состояние GPIO для закрытия тиристора */
#define GPIO_TIRISTOR_OPEN GPIO_PIN_SET
#define GPIO_TIRISTOR_CLOSE GPIO_PIN_RESET
#define TIMER TIM2 /**< Таймер, используемый для управления тиристором */
/**
* @brief Флаги состояния управления тиристором
*/
#define TIMER TIM2
#define DISABLE_TIRISTOR_READY
typedef struct
{
unsigned EnableTiristor:1; /**< Флаг разрешения управления тиристором */
unsigned TiristorIsEnable:1; /**< Флаг, указывающий, что тиристор включен */
unsigned TiristorReady:1; /**< Флаг готовности тиристора к работе */
} TiristorControlFlags;
unsigned EnableTiristor:1;
unsigned TiristorIsEnable:1;
#ifndef DISABLE_TIRISTOR_READY
unsigned TiristorDone:1;
#endif
}TiristorControlFlags;
/**
* @brief Параметры инициализации угла открытия тиристора
*/
typedef struct
{
uint32_t delay_min_us; /**< Минимальная задержка (микросекунды), соответствует максимальному открытию тиристора */
uint32_t delay_max_us; /**< Начальная задержка (микросекунды), соответствует практически закрытому тиристору */
uint32_t delay_step_us; /**< Шаг уменьшения задержки (микросекунды) */
uint32_t sample_time_ms; /**< Интервал времени между шагами регулировки (миллисекунды) */
unsigned direction; /**< Направление регулировки: разгон (увеличение открытого угла) или торможение */
} AngleInit_t;
uint32_t delay_us; // Текущая задержка (в микросекундах)
uint32_t delay_min_us; // Минимальная задержка (максимальное открытие тиристора)
uint32_t delay_max_us; // Начальная задержка (практически закрыт)
uint32_t delay_step_us; // Шаг уменьшения задержки
uint32_t last_update_ms; // Время последнего обновления
uint32_t sample_time_ms; // Интервал между шагами (например, 200 мс)
/**
* @brief Структура управления углом открытия тиристора
*/
typedef struct
{
AngleInit_t *Init; /**< Указатель на структуру параметров инициализации угла */
uint32_t last_update_ms; /**< Время последнего обновления (миллисекунды) */
uint32_t delay_us; /**< Текущая задержка (микросекунды) */
uint16_t start_delay_tick; /**< Значение таймера при старте задержки */
} TiristorAngleControl_t;
uint16_t start_delay_us;
}TiristorAngleControl_t;
typedef struct TiristorControl_t TiristorControl_t;
/**
* @brief Основная структура управления тиристором
*/
struct TiristorControl_t
{
TiristorControlFlags f; /**< Флаги состояния тиристора */
TiristorAngleControl_t angle; /**< Управление углом открытия */
GPIO_TypeDef *gpiox; /**< Порт GPIO для управления тиристором */
uint32_t gpio_pin; /**< Номер пина GPIO */
uint32_t open_time; /**< Время открытия тиристора */
uint32_t enable_start_tick; /**< Время включения тиристора по таймеру */
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); // Указатель на функцию запуска задержки включения
};
/**
* @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

View File

@@ -1,410 +1,50 @@
#include "upp.h"
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; // Выход из функции, дальнейшая логика не выполняется
}
// Если установлен флаг принудительного отключения, выставляем готовность тиристоров и отключаем УПП
if(Upp.ForceDisconnect)
{
phase_A.ctrl.f.TiristorReady = 1;
phase_B.ctrl.f.TiristorReady = 1;
phase_C.ctrl.f.TiristorReady = 1;
Upp.Go = 0; // Останавливаем работу
disconnect_upp(); // Отключаем УПП (снимаем питание с выхода)
return;
}
// Если установлен флаг плавного отключения УПП, готовим тиристоры и отключаем УПП
if(Upp.GoDisconnect)
{
phase_A.ctrl.f.TiristorReady = 1;
phase_B.ctrl.f.TiristorReady = 1;
phase_C.ctrl.f.TiristorReady = 1;
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; // Флаг для отключения УПП и подачи питания напрямую
}
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; // Флаг для остановки УПП и отключения питания
}
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; // Статическая переменная для хранения предыдущего значения флага GoSafe
// Если текущее значение GoSafe больше предыдущего — это сигнал о старте в режиме запуска (направление 0)
if(Upp.GoSafe > prev_gosafe)
{
Upp.angleInit.direction = 0; // Устанавливаем направление пуска (разгон)
Upp.Prepare = 1; // Включаем режим подготовки
Upp.Go = 1; // Включаем основной флаг запуска работы УПП
// Сбрасываем углы управления тиристорами для всех фаз — начинаем с начального состояния
tiristor_angle_reset(&phase_A.ctrl);
tiristor_angle_reset(&phase_B.ctrl);
tiristor_angle_reset(&phase_C.ctrl);
}
// Если текущее значение GoSafe меньше предыдущего — это сигнал о старте в режиме торможения (направление 1)
else if (Upp.GoSafe < prev_gosafe)
{
Upp.angleInit.direction = 1; // Устанавливаем направление торможения
Upp.Prepare = 1; // Включаем режим подготовки
Upp.Go = 1; // Включаем основной флаг запуска работы УПП
// Сбрасываем углы управления тиристорами для всех фаз — начинаем с начального состояния
tiristor_angle_reset(&phase_A.ctrl);
tiristor_angle_reset(&phase_B.ctrl);
tiristor_angle_reset(&phase_C.ctrl);
}
// Обновляем сохранённое предыдущее значение GoSafe для отслеживания изменений в следующем вызове
prev_gosafe = Upp.GoSafe;
}
/**
* @brief Отключение питания УПП (разрыв всех фаз)
*
* @details Если тиристор готов, вызывает макросы отключения фаз,
* после чего выставляет соответствующие флаги состояния.
*/
void disconnect_upp(void)
Phase_t phase_A;
Phase_t phase_B;
Phase_t phase_C;
// главная функция
void upp_main(void)
{
// Если тиристоры фазы 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; // Прекращаем работу УПП
}
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);
}
/**
* @brief Подключение питания УПП (соединение всех фаз)
*
* @details Вызывает отключение тиристоров и макросы подключения фаз,
* сбрасывает флаг отключения.
*/
void connect_upp(void)
{
// Отключаем управление тиристорами для всех фаз
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;
}
/**
* @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)
void upp_phase_routine(Phase_t *phase)
{
static float sine_freq_old = 0;
static float Duration_old = 0;
static float max_duty_old = 0, min_duty_old = 0; // Задаются в процентах
int update = 0;
// Проверка, изменились ли параметры: частота, скважности
if( (Upp.sine_freq != sine_freq_old) &&
(Upp.max_duty != max_duty_old) &&
(Upp.min_duty != min_duty_old) )
{
update = 1;
min_duty_old = Upp.min_duty;
max_duty_old = Upp.max_duty;
sine_freq_old = Upp.sine_freq;
}
// Проверка, изменились ли длительность
if(Upp.Duration != Duration_old)
{
update = 1;
Duration_old = Upp.Duration;
}
if(update)
{
// Расчёт длительности полупериода в микросекундах (с учётом вычета резерва на открытие тиристора)
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 раз (точность 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 раз (точность 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;
}
// Перевод длительности разгона/торможения из секунд в миллисекунды
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;
tiristor_angle_control(&phase->ctrl);
tiristor_control(&phase->ctrl);
zero_cross_update(&phase->zc_detector);
}
/**
* @brief Инициализация УПП и связанных структур
*
* @details Настраивает параметры управления, GPIO для фаз,
* инициализирует тиристоры, запускает таймер и настраивает детектор нулевого перехода.
*/
void upp_init(void)
{
Upp.max_duty = 0.9;
Upp.min_duty = 0.1;
Upp.angleInit.sample_time_ms = 100;
phase_A.disconnect.gpiox = GPIOA;
phase_A.disconnect.gpio_pin = GPIO_PIN_5;
phase_B.disconnect.gpiox = GPIOA;
phase_B.disconnect.gpio_pin = GPIO_PIN_6;
phase_C.disconnect.gpiox = GPIOA;
phase_C.disconnect.gpio_pin = GPIO_PIN_7;
phase_A.ctrl.angle.Init = &Upp.angleInit;
phase_B.ctrl.angle.Init = &Upp.angleInit;
phase_C.ctrl.angle.Init = &Upp.angleInit;
tiristor_init(&phase_A.ctrl, GPIOB, GPIO_PIN_12);
tiristor_init(&phase_B.ctrl, GPIOB, GPIO_PIN_13);
tiristor_init(&phase_C.ctrl, GPIOB, GPIO_PIN_14);
TIMER->CR1 |= TIM_CR1_CEN;
#ifndef HARDWARE_ZERO_CROSS_DETECT
adc_Attach(&phase_A.zc_detector.AdcFilter, &hadc);
zero_cross_Init(&phase_A.zc_detector, ADC_INITIAL_ZERO_LEVEL);
tiristor_angle_reset(&phase_A.ctrl);
tiristor_angle_reset(&phase_B.ctrl);
tiristor_angle_reset(&phase_C.ctrl);
//Upp.GoSafe = 1;
adc_Attach(&phase_A.zc_detector.AdcFilter, &hadc);
zero_cross_Init(&phase_A.zc_detector, ADC_INITIAL_ZERO_LEVEL);
#endif
}

View File

@@ -9,98 +9,23 @@
#include "zero_cross.h"
#include "tiristor.h"
/**
* @brief Определение используемого ADC
*/
#define hadc hadc1
/**
* @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 Структура, описывающая одну фазу с состоянием тиристора и детектом нуля
*/
#define hadc hadc1
#define ADC_INITIAL_ZERO_LEVEL 2048
typedef struct
{
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;
ZeroCrossDetector_t zc_detector;
TiristorControl_t ctrl;
} Phase_t; // структура для фазы
extern Phase_t phase_A;
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

View File

@@ -1,53 +1,56 @@
#include "zero_cross.h"
ADCFilter_t AdcFilter;
/**
* @brief Инициализация структуры детектора перехода через ноль
* @param zc Указатель на структуру ZeroCrossDetector_t
* @param zeroLevel Значение уровня АЦП, соответствующее нулю (mid-scale)
*/
void zero_cross_Init(ZeroCrossDetector_t *zc, uint16_t zeroLevel)
{
// Сбрасываем флаг обнаружения перехода через ноль
zc->f.ZeroCrossDetected = 0;
zc->lastSample = 0;
zc->f.ZeroCrossDetected = 0;
zc->zeroLevel = zeroLevel;
}
/**
* @brief Обновление флага перехода через ноль
* @param zc Указатель на структуру ZeroCrossDetector_t
* @details Просто переносим флаг EXTI с аппаратного детектора.
*/
// апдейт флага зерокросс детектед
void zero_cross_update(ZeroCrossDetector_t *zc)
{
// Используем флаг аппаратного прерывания EXTI для установки флага перехода через ноль
zc->f.ZeroCrossDetected = zc->f.EXTIZeroCrossDetected;
#ifdef HARDWARE_ZERO_CROSS_DETECT
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;
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;
}
/**
* @brief Обработчик прерывания EXTI для аппаратного детектора перехода через ноль
* @param zc Указатель на структуру ZeroCrossDetector_t
* @details Устанавливает флаг аппаратного перехода через ноль.
*/
#ifdef HARDWARE_ZERO_CROSS_DETECT
void zero_cross_update_EXTI(ZeroCrossDetector_t *zc)
{
zc->f.EXTIZeroCrossDetected = 1;
zc->f.EXTIZeroCrossDetected = 1;
}
#endif

View File

@@ -4,31 +4,38 @@
#include "main.h"
#include "adc_filter.h"
/**
* @brief Флаги состояния детектора нуля
*/
typedef struct
{
unsigned WaitForZeroCrossDetected : 1; /**< Ожидание обнаружения перехода через ноль */
unsigned EXTIZeroCrossDetected : 1; /**< Флаг обнаружения нуля аппаратным прерыванием EXTI */
unsigned ZeroCrossDetected : 1; /**< Флаг обнаружения перехода через ноль */
} ZeroCrossFlags;
#define hadc hadc1
#define HARDWARE_ZERO_CROSS_DETECT // аппаратный детект зеро кросс (альтернатива - считывая через ацп)
/**
* @brief Структура детектора перехода через ноль
*/
typedef struct
{
ZeroCrossFlags f; /**< Флаги состояния детектора */
unsigned WaitForZeroCrossDetected : 1;
#ifdef HARDWARE_ZERO_CROSS_DETECT
unsigned EXTIZeroCrossDetected:1;
#endif
unsigned ZeroCrossDetected:1;
}ZeroCrossFlags;
typedef struct
{
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);
/** Обновление состояния детектора перехода через ноль при аппаратном прерывании EXTI */
void zero_cross_update_EXTI(ZeroCrossDetector_t *zc);
#endif //__ZERO_CROSS_H
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
void zero_cross_update_EXTI(ZeroCrossDetector_t *zc);
#endif
#endif //__ZERO_CROSS_H

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<component_viewer schemaVersion="0.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="Component_Viewer.xsd">
<component name="EventRecorderStub" version="1.0.0"/> <!--name and version of the component-->
<events>
</events>
</component_viewer>

File diff suppressed because one or more lines are too long

View File

@@ -117,26 +117,6 @@
<pMon>STLink\ST-LINKIII-KEIL_SWO.dll</pMon>
</DebugOpt>
<TargetDriverDllRegistry>
<SetRegEntry>
<Number>0</Number>
<Key>ARMRTXEVENTFLAGS</Key>
<Name>-L70 -Z18 -C0 -M0 -T1</Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>DLGTARM</Key>
<Name>(1010=-1,-1,-1,-1,0)(1007=-1,-1,-1,-1,0)(1008=-1,-1,-1,-1,0)(1009=-1,-1,-1,-1,0)</Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>ARMDBGFLAGS</Key>
<Name></Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>DLGUARM</Key>
<Name>(105=-1,-1,-1,-1,0)</Name>
</SetRegEntry>
<SetRegEntry>
<Number>0</Number>
<Key>UL2CM3</Key>
@@ -145,22 +125,10 @@
<SetRegEntry>
<Number>0</Number>
<Key>ST-LINKIII-KEIL_SWO</Key>
<Name>-U-O142 -O2254 -SF10000 -C0 -A0 -I0 -HNlocalhost -HP7184 -P1 -N00("ARM CoreSight SW-DP (ARM Core") -D00(1BA01477) -L00(0) -TO131090 -TC10000000 -TT10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC800 -FN1 -FF0STM32F10x_128.FLM -FS08000000 -FL08000 -FP0($$Device:STM32F103C6$Flash\STM32F10x_128.FLM) -WA0 -WE0 -WVCE4 -WS2710 -WM0 -WP2</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>
</TargetDriverDllRegistry>
<Breakpoint/>
<WatchWindow1>
<Ww>
<count>0</count>
<WinNumber>1</WinNumber>
<ItemText>Upp</ItemText>
</Ww>
<Ww>
<count>1</count>
<WinNumber>1</WinNumber>
<ItemText>phase_A</ItemText>
</Ww>
</WatchWindow1>
<Tracepoint>
<THDelay>0</THDelay>
</Tracepoint>
@@ -203,15 +171,9 @@
<pszMrulep></pszMrulep>
<pSingCmdsp></pSingCmdsp>
<pMultCmdsp></pMultCmdsp>
<SystemViewers>
<Entry>
<Name>System Viewer\TIM1</Name>
<WinId>35905</WinId>
</Entry>
</SystemViewers>
<DebugDescription>
<Enable>1</Enable>
<EnableFlashSeq>0</EnableFlashSeq>
<EnableFlashSeq>1</EnableFlashSeq>
<EnableLog>0</EnableLog>
<Protocol>2</Protocol>
<DbgClock>10000000</DbgClock>

View File

@@ -82,7 +82,7 @@
</BeforeMake>
<AfterMake>
<RunUserProg1>0</RunUserProg1>
<RunUserProg2>1</RunUserProg2>
<RunUserProg2>0</RunUserProg2>
<UserProg1Name></UserProg1Name>
<UserProg2Name></UserProg2Name>
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
@@ -315,7 +315,7 @@
</ArmAdsMisc>
<Cads>
<interw>1</interw>
<Optim>1</Optim>
<Optim>4</Optim>
<oTime>0</oTime>
<SplitLS>0</SplitLS>
<OneElfS>1</OneElfS>
@@ -341,7 +341,7 @@
<MiscControls></MiscControls>
<Define>USE_HAL_DRIVER,STM32F103x6</Define>
<Undefine></Undefine>
<IncludePath>../Core/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F1xx/Include;../Drivers/CMSIS/Include;../Core/upp</IncludePath>
<IncludePath>../Core/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc;../Drivers/STM32F1xx_HAL_Driver/Inc/Legacy;../Drivers/CMSIS/Device/ST/STM32F1xx/Include;../Drivers/CMSIS/Include;..\Core\upp</IncludePath>
</VariousControls>
</Cads>
<Aads>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -30,7 +30,4 @@ upp/stm32f1xx_it.o: ..\Core\Src\stm32f1xx_it.c ..\Core\Inc\main.h \
..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_tim.h \
..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_tim_ex.h \
..\Drivers\STM32F1xx_HAL_Driver\Inc\stm32f1xx_hal_uart.h \
..\Core\Inc\stm32f1xx_it.h ..\Core\upp\upp.h ..\Core\Inc\adc.h \
..\Core\Inc\tim.h ..\Core\Inc\usart.h ..\Core\Inc\gpio.h \
..\Core\upp\zero_cross.h ..\Core\upp\adc_filter.h \
..\Core\upp\tiristor.h
..\Core\Inc\stm32f1xx_it.h

Binary file not shown.

View File

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

Some files were not shown because too many files have changed in this diff Show More