Files
UPP/UPP/Core/PowerMonitor/zero_cross.h
Razvalyaev 5090ddfd48 Всякие оптимизации и переделки под отладку на 417
По основному алгу
- расчет частоты сети тепер по всему периоду, а не полупериоду
- добавлены новые параметры: сдвиг синуса от нуля и сдвиг между фазами
2025-11-19 15:29:42 +03:00

169 lines
8.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
******************************************************************************
* @file zero_cross.h
* @brief Модуль фиксирующий переход через ноль
******************************************************************************
* @addtogroup ZERO_CROSS Zero-cross detection
* @brief Библиотека для детектирования переходов сигнала через ноль
* @details
Поддерживает:
- Многоканальное детектирование (несколько независимых сигналов)
- Детектирование фронтов: rising, falling, both
- Антидребезг с настраиваемым количеством samples
- Расчет частоты и периода сигнала
- Гистерезис для устойчивого детектирования
- Независимость от источника данных (ADC, DAC, другие)
- Индивидуальные настройки для каждого хендла
@par Пример использования:
@code
#include "zero_cross.h"
// Объявление структур
ZeroCross_Handle_t zc_handle;
float adc_values[2] = {0};
uint32_t timestamp = 0;
// Инициализация с индивидуальными настройками
ZC_Init(&zc_handle, 2, 0.1f, 3); // 2 канала, гистерезис 0.1, дебаунс 3 samples
// Настройка каналов
ZC_ConfigChannel(&zc_handle, 0, ZC_RISING_EDGE); // Канал 0 - только rising edge
ZC_ConfigChannel(&zc_handle, 1, ZC_BOTH_EDGES); // Канал 1 - оба фронта
// В основном цикле обработки ADC
while (1) {
// Получение данных от ADC (пример)
adc_values[0] = read_adc_channel(0); // Фаза A
adc_values[1] = read_adc_channel(1); // Фаза B
timestamp = HAL_GetTick() * 1000; // Текущее время в микросекундах
// Обработка всех каналов
ZC_ProcessAllChannels(&zc_handle, adc_values, timestamp);
// Получение результатов
float freq_a = ZC_GetFrequency(&zc_handle, 0);
float freq_b = ZC_GetFrequency(&zc_handle, 1);
uint32_t period_a = ZC_GetPeriod(&zc_handle, 0);
uint32_t cross_count_a = ZC_GetCrossCount(&zc_handle, 0);
// Использование в логике управления
if (freq_a > 55.0f || freq_a < 45.0f) {
// Авария по частоте
handle_frequency_fault();
}
}
// Пример создания нескольких хендлов с разными настройками
ZeroCross_Handle_t zc_high_sensitivity;
ZeroCross_Handle_t zc_low_sensitivity;
// Высокая чувствительность - малый гистерезис
ZC_Init(&zc_high_sensitivity, 2, 0.01f, 5); // 0.01 гистерезис, 5 samples дебаунс
// Низкая чувствительность - большой гистерезис для зашумленных сигналов
ZC_Init(&zc_low_sensitivity, 2, 0.5f, 2); // 0.5 гистерезис, 2 samples дебаунс
@endcode
* @{
*****************************************************************************/
#ifndef _ZERO_CROSS_H_
#define _ZERO_CROSS_H_
#include "main.h"
#ifndef ZC_MAX_CHANNELS
#define ZC_MAX_CHANNELS 3 ///< Максимальное количество каналов на хендл
#endif
/**
* @brief Тип перехода через ноль
*/
typedef enum {
ZC_BOTH_EDGES = 0, ///< Детектирование обоих переходов
ZC_RISING_EDGE, ///< Переход от отрицательного к положительному
ZC_FALLING_EDGE, ///< Переход от положительного к отрицательному
} ZC_EdgeType_t;
/**
* @brief Структура канала детектора нуля
*/
typedef struct {
uint8_t Occurred; ///< Флаг что пересечение нуля произошло
uint32_t CrossCount; ///< Счетчик переходов
float LastValue; ///< Предыдущее значение
float CurrentValue; ///< Текущее значение
uint16_t DebounceCounter; ///< Счетчик антидребезга
uint32_t LastCrossTime; ///< Время последнего перехода
float halfPeriod; ///< Длительность полупериода (в тактах таймера)
uint32_t PeriodStartTime; ///< Время начала периода (в тактах таймера)
uint32_t Period; ///< Период сигнала (в тактах таймера)
float Frequency; ///< Частота
float FrequencyOffset; ///< Смещение частот полупериода - насколько сигнал смещен
UPP_HalfWave_t HalfWave; ///< Текущая полуволна
ZC_EdgeType_t EdgeType; ///< Тип детектируемого перехода
} ZC_Channel_t;
/**
* @brief Параметры перехода через ноль
*/
typedef struct {
uint8_t NumChannels; ///< Количество используемых каналов для этого хендла
float Hysteresis; ///< Гистерезис для избежания дребезга
uint16_t DebounceSamples; ///< Количество samples для антидребезга
} ZC_Config_t;
/**
* @brief Хендл детектора нуля
*/
typedef struct {
ZC_Channel_t Channel[ZC_MAX_CHANNELS]; ///< Каналы @ref ZC_Channel_t
ZC_Config_t Config;
struct {
unsigned Initialized:1; ///< Флаг инициализации
unsigned Monitoring:1; ///< Флаг активности мониторинга
} f; ///< Флаги
uint32_t LastTick; ///< Послднее время вызова
} ZeroCross_Handle_t;
// ====== ИНИЦИАЛИЗАЦИЯ ==========
/* Инициализация детектора нуля с индивидуальными настройками */
HAL_StatusTypeDef ZC_Init(ZeroCross_Handle_t *zc, uint8_t num_channels,
float hysteresis, uint16_t debounce_samples);
/* Настройка канала детектора */
HAL_StatusTypeDef ZC_ConfigChannel(ZeroCross_Handle_t *zc, uint8_t channel,
ZC_EdgeType_t edgeType);
// ====== УПРАВЛЕНИЕ ==========
/* Включение/выключение мониторинга */
void ZC_EnableMonitoring(ZeroCross_Handle_t *zc, uint8_t enable);
/* Сброс статистики канала */
void ZC_Reset(ZeroCross_Handle_t *zc, uint8_t channel);
// ====== РАСЧЕТЫ ==========
/* Обработка значения отдельного канала */
void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value,
uint32_t timestamp);
/* Пакетная обработка всех каналов */
void ZC_ProcessAllChannels(ZeroCross_Handle_t *zc, float *values,
uint32_t timestamp);
// ====== API ==========
/* Полученить флаг - переход произошел. */
int ZC_isOccurred(ZeroCross_Handle_t *zc, uint8_t channel);
/* Получение частоты сигнала */
float ZC_GetFrequency(ZeroCross_Handle_t *zc, uint8_t channel);
/* Получение смещение частот полупериода сигнала */
float ZC_GetOffset(ZeroCross_Handle_t *zc, uint8_t channel);
/* Получить сдвиг между двумя фазами. */
float ZC_GetPhaseShift(ZeroCross_Handle_t *zc, uint8_t channel1, uint8_t channel2);
/* Получение полуволны (после последнего zero-cross) */
UPP_HalfWave_t ZC_GetHalfWave(ZeroCross_Handle_t *zc, uint8_t channel);
#endif /* _ZERO_CROSS_H_ */
/**
* @}
*/