По основному алгу - расчет частоты сети тепер по всему периоду, а не полупериоду - добавлены новые параметры: сдвиг синуса от нуля и сдвиг между фазами
169 lines
8.0 KiB
C
169 lines
8.0 KiB
C
/**
|
||
******************************************************************************
|
||
* @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_ */
|
||
|
||
/**
|
||
* @}
|
||
*/ |