diff --git a/MATLAB/app_wrapper/app_io.c b/MATLAB/app_wrapper/app_io.c index 4050af7..17fe31a 100644 --- a/MATLAB/app_wrapper/app_io.c +++ b/MATLAB/app_wrapper/app_io.c @@ -52,7 +52,13 @@ __HAL_TIM_SET_AUTORELOAD(&adc_tim, ReadInputArray(1, 0)); */ void app_writeOutputBuffer(real_T* Buffer) { // USER APP OUTPUT START - ThyristorWrite(Buffer); + //ThyristorWrite(Buffer); + for (int i = 0; i < 2; i++) + { + WriteOutputArray(ZC_Detected[i], 0, i); + } + + extern ADC_Period_t adc; for(int i = 0; i < 6; i++) { diff --git a/MATLAB/upp_r2023.slx b/MATLAB/upp_r2023.slx index 1fdd5ac..f972bdf 100644 Binary files a/MATLAB/upp_r2023.slx and b/MATLAB/upp_r2023.slx differ diff --git a/UPP/Core/Inc/main.h b/UPP/Core/Inc/main.h index 02c2ae9..e875bd5 100644 --- a/UPP/Core/Inc/main.h +++ b/UPP/Core/Inc/main.h @@ -57,7 +57,7 @@ extern "C" { void Error_Handler(void); /* USER CODE BEGIN EFP */ - +extern __IO uint32_t micros; /* USER CODE END EFP */ /* Private defines -----------------------------------------------------------*/ diff --git a/UPP/Core/PowerMonitor/adc_tools.c b/UPP/Core/PowerMonitor/adc_tools.c index a49d587..5bba577 100644 --- a/UPP/Core/PowerMonitor/adc_tools.c +++ b/UPP/Core/PowerMonitor/adc_tools.c @@ -1,7 +1,7 @@ /** ****************************************************************************** * @file adc_tools.c -* @brief Функции доступа к данным Modbus +* @brief Модуль считывающий данные с АЦП ****************************************************************************** * @details ******************************************************************************/ @@ -17,8 +17,6 @@ static void ADC_EnableAllFilters(ADC_Period_t *adc) { FILTER_GET_STATE(&adc->filter[i]) = FILTER_ENABLE; } - FILTER_GET_STATE(&adc->temp_filter[0]) = FILTER_ENABLE; - FILTER_GET_STATE(&adc->temp_filter[1]) = FILTER_ENABLE; } static void ADC_InitAllFilters(ADC_Period_t *adc, int coef) { @@ -113,7 +111,9 @@ HAL_StatusTypeDef ADC_Start(ADC_Period_t *adc, uint16_t Period) return res; } - ADC_EnableAllFilters(adc); + //ADC_EnableAllFilters(adc); + FILTER_GET_STATE(&adc->temp_filter[0]) = FILTER_ENABLE; + FILTER_GET_STATE(&adc->temp_filter[1]) = FILTER_ENABLE; return res; } @@ -176,4 +176,54 @@ HAL_StatusTypeDef ADC_Handle(ADC_Period_t *adc) adc->f.DataReady = 1; return HAL_OK; -} \ No newline at end of file +} + + +/** + * @brief Сбор статистики. + */ +void ADC_UpdateStatistics(ADC_Period_t *adc, uint8_t channel, float value) +{ + if(assert_adc(adc)) + return; + if (channel >= ADC_NUMB_OF_REGULAR_CHANNELS) return; + + ADC_Statistics *stat = &adc->Stat[channel]; + + // Первая инициализация + if (stat->SampleCount == 0) { + stat->Max = value; + stat->Min = value; + stat->Sum = 0; + stat->SumSquares = 0; + } + + // Обновление min/max + if (value > stat->Max) stat->Max = value; + if (value < stat->Min) stat->Min = value; + + // Накопление для Avg/RMS + stat->Sum += value; + stat->SumSquares += value * value; + stat->SampleCount++; + + // Расчет Avg/RMS (периодически или по запросу) + if (stat->SampleCount >= 1000) { // Пример: пересчет каждые 1000 samples + stat->Avg = stat->Sum / stat->SampleCount; + stat->RMS = sqrtf(stat->SumSquares / stat->SampleCount); + // Сброс накопителей + stat->Sum = 0; + stat->SumSquares = 0; + stat->SampleCount = 0; + } +} + +/** + * @brief Сброс статистики. + */ +void ADC_ResetStatistics(ADC_Period_t *adc, uint8_t channel) +{ + if (channel < ADC_NUMB_OF_REGULAR_CHANNELS) { + memset(&adc->Stat[channel], 0, sizeof(ADC_Statistics)); + } +} diff --git a/UPP/Core/PowerMonitor/adc_tools.h b/UPP/Core/PowerMonitor/adc_tools.h index fdc8234..a937322 100644 --- a/UPP/Core/PowerMonitor/adc_tools.h +++ b/UPP/Core/PowerMonitor/adc_tools.h @@ -1,7 +1,7 @@ /** ****************************************************************************** * @file adc_tools.h -* @brief Определения структур данных Modbus устройства +* @brief Модуль считывающий данные с АЦП ****************************************************************************** * @details ******************************************************************************/ @@ -11,7 +11,8 @@ #include "main.h" #define ADC_NUMB_OF_CHANNELS 6 -#define ADC_TEMP_CHANNELS_START 4 +#define ADC_NUMB_OF_REGULAR_CHANNELS 4 +#define ADC_TEMP_CHANNELS_START ADC_NUMB_OF_REGULAR_CHANNELS #define ADC_TEMPERATURES_QUANTS \ { 2188, 2197, 2206, 2216, 2226, 2236, 2247, 2259, 2271, 2283, \ @@ -45,10 +46,25 @@ static const int32_t adc_temp_quants[] = ADC_TEMPERATURES_QUANTS; typedef struct { uint16_t lZero; ///< Нулевой уровень (в квантах АЦП) - float vMax; ///< Максимальный уровень Единиц Измерения (в Вольтах/Амперах/Градусах) + float vMax; ///< Максимальный уровень Единиц Измерения (в Вольтах/Амперах) uint16_t lMax; ///< Максимальный уровень АЦП (в квантах АЦП) }ADC_Coefs_t; +/** + * @brief Статистика АЦП + */ +typedef struct +{ + float Max; ///< Пиковое значение + float Min; ///< Минимальное значение + float Avg; ///< Среднее арифметическое значение + float RMS; ///< Действующее значение + + uint32_t SampleCount; ///< Для корректного расчета Avg/RMS + float Sum; ///< Накопитель для среднего + float SumSquares; ///< Накопитель для RMS +}ADC_Statistics; + /** * @brief Хендл АЦП */ @@ -59,18 +75,21 @@ typedef struct ADC_HandleTypeDef *hadc; ///< Хендл АЦП // Data and calculation - uint16_t RawData[ADC_NUMB_OF_CHANNELS]; ///< Сырые значения АЦП - ADC_Coefs_t Coefs[ADC_NUMB_OF_CHANNELS]; ///< Коэффициенты @ref ADC_Coefs_t - float Data[ADC_NUMB_OF_CHANNELS]; ///< Пересчитанные значения АЦП (в Вольтах/Амперах/Градусах) + uint16_t RawData[ADC_NUMB_OF_CHANNELS]; ///< Сырые значения АЦП + ADC_Coefs_t Coefs[ADC_NUMB_OF_REGULAR_CHANNELS]; ///< Коэффициенты @ref ADC_Coefs_t для регулярных каналов (не температуры) + FilterAverageInt_t filter[ADC_NUMB_OF_CHANNELS]; ///< Фильтр от шумов АЦП + FilterLUTInt_t temp_filter[2]; ///< Коррекция нелинейности датчиков температуры + + float Data[ADC_NUMB_OF_CHANNELS]; ///< Пересчитанные значения АЦП (в Вольтах/Амперах) + ADC_Statistics Stat[ADC_NUMB_OF_REGULAR_CHANNELS]; ///< Статистика для регулярных каналов (не температуры) - FilterAverageInt_t filter[ADC_NUMB_OF_CHANNELS]; ///< Фильтр от шумов АЦП - FilterLUTInt_t temp_filter[2]; ///< Коррекция нелинейности датчиков температуры struct { unsigned Initialized:1; unsigned AdcRunning:1; unsigned DataReady:1; - }f; + }f; ///< Флаги + uint32_t LastTick; // Время последнего преобразования }ADC_Period_t; diff --git a/UPP/Core/PowerMonitor/zero_cross.c b/UPP/Core/PowerMonitor/zero_cross.c new file mode 100644 index 0000000..fe64962 --- /dev/null +++ b/UPP/Core/PowerMonitor/zero_cross.c @@ -0,0 +1,333 @@ +/** +****************************************************************************** +* @file zero_cross.c +* @brief Модуль фиксирующий переход через ноль +****************************************************************************** +* @details +******************************************************************************/ + +#include "zero_cross.h" +#include + +/** + * @brief Инициализация детектора нуля с индивидуальными настройками. + * @param zc Указатель на хендл детектора нуля + * @param num_channels Количество каналов для этого хендла + * @param hysteresis Гистерезис для избежания дребезга + * @param debounce_samples Количество samples для антидребезга + * @return HAL Status. + */ +HAL_StatusTypeDef ZC_Init(ZeroCross_Handle_t *zc, uint8_t num_channels, + float hysteresis, uint8_t debounce_samples) +{ + if (zc == NULL || num_channels == 0 || num_channels > ZC_MAX_CHANNELS) { + return HAL_ERROR; + } + + // Инициализация структуры + memset(zc, 0, sizeof(ZeroCross_Handle_t)); + + // Установка параметров хендла + zc->NumChannels = num_channels; + zc->Hysteresis = hysteresis; + zc->DebounceSamples = debounce_samples; + + // Инициализация каналов + for (int i = 0; i < num_channels; i++) { + zc->Channel[i].CrossCount = 0; + zc->Channel[i].LastValue = 0.0f; + zc->Channel[i].CurrentValue = 0.0f; + zc->Channel[i].DebounceCounter = 0; + zc->Channel[i].StableState = 0; + zc->Channel[i].LastCrossTime = 0; + zc->Channel[i].Period = 0; + zc->Channel[i].Frequency = 0.0f; + zc->Channel[i].EdgeType = ZC_BOTH_EDGES; + } + + zc->f.Initialized = 1; + zc->f.Monitoring = 1; + + return HAL_OK; +} + +/** + * @brief Настройка канала детектора. + * @param zc Указатель на хендл детектора нуля + * @param channel Номер канала для конфигурации + * @param edgeType Тип детектируемого перехода + * @return HAL Status. + */ +HAL_StatusTypeDef ZC_ConfigChannel(ZeroCross_Handle_t *zc, uint8_t channel, + ZC_EdgeType_t edgeType) +{ + if (zc == NULL || !zc->f.Initialized) { + return HAL_ERROR; + } + + if (channel >= zc->NumChannels) { + return HAL_ERROR; + } + + zc->Channel[channel].EdgeType = edgeType; + + // Сброс состояния канала при реконфигурации + zc->Channel[channel].LastValue = 0.0f; + zc->Channel[channel].DebounceCounter = 0; + zc->Channel[channel].StableState = 0; + zc->Channel[channel].LastCrossTime = 0; + zc->Channel[channel].Period = 0; + zc->Channel[channel].Frequency = 0.0f; + zc->Channel[channel].CrossCount = 0; + + return HAL_OK; +} +/** + * @brief Основная функция обработки значения канала. + * @param zc Указатель на хендл детектора нуля + * @param channel Номер канала + * @param value Текущее значение сигнала + * @param timestamp Временная метка измерения в микросекундах + */ +void ZC_ProcessChannel(ZeroCross_Handle_t *zc, uint8_t channel, float value, uint32_t timestamp) +{ + if (zc == NULL || !zc->f.Initialized || !zc->f.Monitoring) { + return; + } + + if (channel >= zc->NumChannels) { + return; + } + + ZC_Channel_t *zc_ch = &zc->Channel[channel]; + zc_ch->CurrentValue = value; + + // Детектирование rising edge (отрицательное -> положительное) + if ((zc_ch->LastValue <= -zc->Hysteresis) && + (value >= zc->Hysteresis)) { + + if (zc_ch->EdgeType == ZC_RISING_EDGE || zc_ch->EdgeType == ZC_BOTH_EDGES) { + // Переход подтвержден сразу (без дебаунса) + if (zc_ch->LastCrossTime != 0) { + // Расчет периода и частоты + zc_ch->Period = timestamp - zc_ch->LastCrossTime; + if (zc_ch->Period > 0) { + zc_ch->Frequency = 1000000.0f / zc_ch->Period; + } + } + + zc_ch->LastCrossTime = timestamp; + zc_ch->CrossCount++; + zc_ch->StableState = 1; + } + } + // Детектирование falling edge (положительное -> отрицательное) + else if ((zc_ch->LastValue >= zc->Hysteresis) && + (value <= -zc->Hysteresis)) { + + if (zc_ch->EdgeType == ZC_FALLING_EDGE || zc_ch->EdgeType == ZC_BOTH_EDGES) { + // Переход подтвержден сразу (без дебаунса) + if (zc_ch->LastCrossTime != 0) { + // Расчет периода и частоты + zc_ch->Period = timestamp - zc_ch->LastCrossTime; + if (zc_ch->Period > 0) { + zc_ch->Frequency = 1000000.0f / zc_ch->Period; + } + } + + zc_ch->LastCrossTime = timestamp; + zc_ch->CrossCount++; + zc_ch->StableState = 0; + } + } + + // Сохраняем текущее значение для следующей итерации в случае если оно не в мертвой зоне + if((value > zc->Hysteresis) || (value < -zc->Hysteresis)) + { + zc_ch->LastValue = value; + } +} + +/** + * @brief Пакетная обработка всех каналов. + * @param zc Указатель на хендл детектора нуля + * @param values Массив значений сигналов + * @param timestamp Временная метка измерения + */ +void ZC_ProcessAllChannels(ZeroCross_Handle_t *zc, float values[], uint32_t timestamp) +{ + if (zc == NULL || !zc->f.Initialized || !zc->f.Monitoring || values == NULL) { + return; + } + + for (int ch = 0; ch < zc->NumChannels; ch++) { + ZC_ProcessChannel(zc, ch, values[ch], timestamp); + } +} + +/** + * @brief Получение частоты сигнала. + * @param zc Указатель на хендл детектора нуля + * @param channel Номер канала + * @return Частота в Гц. + */ +float ZC_GetFrequency(ZeroCross_Handle_t *zc, uint8_t channel) +{ + if (zc == NULL || !zc->f.Initialized || channel >= zc->NumChannels) { + return 0.0f; + } + + return zc->Channel[channel].Frequency; +} + +/** + * @brief Получение периода сигнала. + * @param zc Указатель на хендл детектора нуля + * @param channel Номер канала + * @return Период в тактах таймера. + */ +uint32_t ZC_GetPeriod(ZeroCross_Handle_t *zc, uint8_t channel) +{ + if (zc == NULL || !zc->f.Initialized || channel >= zc->NumChannels) { + return 0; + } + + return zc->Channel[channel].Period; +} + +/** + * @brief Получение счетчика переходов. + * @param zc Указатель на хендл детектора нуля + * @param channel Номер канала + * @return Количество переходов. + */ +uint32_t ZC_GetCrossCount(ZeroCross_Handle_t *zc, uint8_t channel) +{ + if (zc == NULL || !zc->f.Initialized || channel >= zc->NumChannels) { + return 0; + } + + return zc->Channel[channel].CrossCount; +} + +/** + * @brief Получение текущего состояния канала. + * @param zc Указатель на хендл детектора нуля + * @param channel Номер канала + * @return Состояние (0 - отрицательное, 1 - положительное). + */ +uint8_t ZC_GetStableState(ZeroCross_Handle_t *zc, uint8_t channel) +{ + if (zc == NULL || !zc->f.Initialized || channel >= zc->NumChannels) { + return 0; + } + + return zc->Channel[channel].StableState; +} + +/** + * @brief Получение текущего значения канала. + * @param zc Указатель на хендл детектора нуля + * @param channel Номер канала + * @return Текущее значение сигнала. + */ +float ZC_GetCurrentValue(ZeroCross_Handle_t *zc, uint8_t channel) +{ + if (zc == NULL || !zc->f.Initialized || channel >= zc->NumChannels) { + return 0.0f; + } + + return zc->Channel[channel].CurrentValue; +} + +/** + * @brief Включение/выключение мониторинга. + * @param zc Указатель на хендл детектора нуля + * @param enable Флаг включения (1 - вкл, 0 - выкл) + */ +void ZC_EnableMonitoring(ZeroCross_Handle_t *zc, uint8_t enable) +{ + if (zc == NULL || !zc->f.Initialized) { + return; + } + + zc->f.Monitoring = enable ? 1 : 0; +} + +/** + * @brief Сброс статистики канала. + * @param zc Указатель на хендл детектора нуля + * @param channel Номер канала + */ +void ZC_Reset(ZeroCross_Handle_t *zc, uint8_t channel) +{ + if (zc == NULL || !zc->f.Initialized) { + return; + } + + if (channel < zc->NumChannels) { + zc->Channel[channel].LastValue = 0.0f; + zc->Channel[channel].CurrentValue = 0.0f; + zc->Channel[channel].DebounceCounter = 0; + zc->Channel[channel].StableState = 0; + zc->Channel[channel].LastCrossTime = 0; + zc->Channel[channel].Period = 0; + zc->Channel[channel].Frequency = 0.0f; + zc->Channel[channel].CrossCount = 0; + } + else { + // Сброс всех каналов + for (int i = 0; i < zc->NumChannels; i++) { + zc->Channel[i].LastValue = 0.0f; + zc->Channel[i].CurrentValue = 0.0f; + zc->Channel[i].DebounceCounter = 0; + zc->Channel[i].StableState = 0; + zc->Channel[i].LastCrossTime = 0; + zc->Channel[i].Period = 0; + zc->Channel[i].Frequency = 0.0f; + zc->Channel[i].CrossCount = 0; + } + } +} + +/** + * @brief Установка гистерезиса для хендла. + * @param zc Указатель на хендл детектора нуля + * @param hysteresis Значение гистерезиса + */ +void ZC_SetHysteresis(ZeroCross_Handle_t *zc, float hysteresis) +{ + if (zc == NULL || !zc->f.Initialized) { + return; + } + + zc->Hysteresis = hysteresis; +} + +/** + * @brief Установка дебаунс samples для хендла. + * @param zc Указатель на хендл детектора нуля + * @param debounce_samples Количество samples для антидребезга + */ +void ZC_SetDebounceSamples(ZeroCross_Handle_t *zc, uint8_t debounce_samples) +{ + if (zc == NULL || !zc->f.Initialized) { + return; + } + + zc->DebounceSamples = debounce_samples; +} + +/** + * @brief Получение количества каналов хендла. + * @param zc Указатель на хендл детектора нуля + * @return Количество каналов. + */ +uint8_t ZC_GetNumChannels(ZeroCross_Handle_t *zc) +{ + if (zc == NULL || !zc->f.Initialized) { + return 0; + } + + return zc->NumChannels; +} \ No newline at end of file diff --git a/UPP/Core/PowerMonitor/zero_cross.h b/UPP/Core/PowerMonitor/zero_cross.h new file mode 100644 index 0000000..a109023 --- /dev/null +++ b/UPP/Core/PowerMonitor/zero_cross.h @@ -0,0 +1,166 @@ +/** +****************************************************************************** +* @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 8 ///< Максимальное количество каналов на хендл +#endif + +/** + * @brief Тип перехода через ноль + */ +typedef enum { + ZC_BOTH_EDGES = 0, ///< Детектирование обоих переходов + ZC_RISING_EDGE, ///< Переход от отрицательного к положительному + ZC_FALLING_EDGE, ///< Переход от положительного к отрицательному +} ZC_EdgeType_t; + +/** + * @brief Структура канала детектора нуля + */ +typedef struct { + uint32_t CrossCount; ///< Счетчик переходов + float LastValue; ///< Предыдущее значение + float CurrentValue; ///< Текущее значение + uint8_t DebounceCounter; ///< Счетчик антидребезга + uint8_t StableState; ///< Стабильное состояние (0=отриц, 1=полож) + uint32_t LastCrossTime; ///< Время последнего перехода + uint32_t Period; ///< Период сигнала (в тактах таймера) + float Frequency; ///< Частота + ZC_EdgeType_t EdgeType; ///< Тип детектируемого перехода +} ZC_Channel_t; + +/** + * @brief Хендл детектора нуля + */ +typedef struct { + ZC_Channel_t Channel[ZC_MAX_CHANNELS]; ///< Каналы @ref ZC_Channel_t + uint8_t NumChannels; ///< Количество используемых каналов для этого хендла + float Hysteresis; ///< Гистерезис для избежания дребезга + uint8_t DebounceSamples; ///< Количество samples для антидребезга + struct { + unsigned Initialized:1; ///< Флаг инициализации + unsigned Monitoring:1; ///< Флаг активности мониторинга + } f; ///< Флаги +} ZeroCross_Handle_t; + +/* Инициализация детектора нуля с индивидуальными настройками */ +HAL_StatusTypeDef ZC_Init(ZeroCross_Handle_t *zc, uint8_t num_channels, + float hysteresis, uint8_t debounce_samples); + +/* Настройка канала детектора */ +HAL_StatusTypeDef ZC_ConfigChannel(ZeroCross_Handle_t *zc, uint8_t channel, + ZC_EdgeType_t edgeType); + +/* Обработка значения отдельного канала */ +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); + +/* Получение частоты сигнала */ +float ZC_GetFrequency(ZeroCross_Handle_t *zc, uint8_t channel); + +/* Получение периода сигнала */ +uint32_t ZC_GetPeriod(ZeroCross_Handle_t *zc, uint8_t channel); + +/* Получение счетчика переходов */ +uint32_t ZC_GetCrossCount(ZeroCross_Handle_t *zc, uint8_t channel); + +/* Получение текущего состояния канала */ +uint8_t ZC_GetStableState(ZeroCross_Handle_t *zc, uint8_t channel); + +/* Получение текущего значения канала */ +float ZC_GetCurrentValue(ZeroCross_Handle_t *zc, uint8_t channel); + +/* Включение/выключение мониторинга */ +void ZC_EnableMonitoring(ZeroCross_Handle_t *zc, uint8_t enable); + +/* Сброс статистики канала */ +void ZC_Reset(ZeroCross_Handle_t *zc, uint8_t channel); + +/* Установка гистерезиса для хендла */ +void ZC_SetHysteresis(ZeroCross_Handle_t *zc, float hysteresis); + +/* Установка дебаунс samples для хендла */ +void ZC_SetDebounceSamples(ZeroCross_Handle_t *zc, uint8_t debounce_samples); + +/* Получение количества каналов хендла */ +uint8_t ZC_GetNumChannels(ZeroCross_Handle_t *zc); + +#endif /* _ZERO_CROSS_H_ */ + +/** + * @} + */ \ No newline at end of file diff --git a/UPP/Core/Src/main.c b/UPP/Core/Src/main.c index 0e2747f..bfbb14c 100644 --- a/UPP/Core/Src/main.c +++ b/UPP/Core/Src/main.c @@ -34,7 +34,7 @@ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ - +__IO uint32_t micros; /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ diff --git a/UPP/Core/Src/stm32f4xx_it.c b/UPP/Core/Src/stm32f4xx_it.c index c199d34..ceef07b 100644 --- a/UPP/Core/Src/stm32f4xx_it.c +++ b/UPP/Core/Src/stm32f4xx_it.c @@ -22,6 +22,7 @@ #include "stm32f4xx_it.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ +#include "upp_main.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ @@ -222,13 +223,11 @@ void TIM8_TRG_COM_TIM14_IRQHandler(void) void DMA2_Stream0_IRQHandler(void) { /* USER CODE BEGIN DMA2_Stream0_IRQn 0 */ -#include "adc_tools.h" - extern ADC_Period_t adc; - ADC_Handle(&adc); + /* USER CODE END DMA2_Stream0_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_adc3); /* USER CODE BEGIN DMA2_Stream0_IRQn 1 */ - + UPP_ADC_Handle(); /* USER CODE END DMA2_Stream0_IRQn 1 */ } diff --git a/UPP/Core/UPP/upp_main.c b/UPP/Core/UPP/upp_main.c index 2f31926..c370f74 100644 --- a/UPP/Core/UPP/upp_main.c +++ b/UPP/Core/UPP/upp_main.c @@ -11,7 +11,10 @@ #include "tim.h" #include "adc_tools.h" +#include "zero_cross.h" ADC_Period_t adc; +ZeroCross_Handle_t hzc; +uint32_t ZC_Detected[ZC_MAX_CHANNELS] = {0}; #define ADC_CHANNEL_UBA 0 #define ADC_CHANNEL_UAC 1 #define ADC_CHANNEL_IC 2 @@ -34,6 +37,10 @@ int UPP_Init(void) ADC_ConfigChannel(&adc, ADC_CHANNEL_TEMP1, 2554, 90, 4095); ADC_ConfigChannel(&adc, ADC_CHANNEL_TEMP2, 2554, 90, 4095); + ZC_Init(&hzc, ZC_MAX_CHANNELS, 10, 3); + ZC_ConfigChannel(&hzc, 0, ZC_BOTH_EDGES); + ZC_ConfigChannel(&hzc, 1, ZC_BOTH_EDGES); + return 0; } @@ -55,4 +62,19 @@ int UPP_While(void) { return 0; +} + +void UPP_ADC_Handle(void) +{ + static uint32_t last_zc_cnt[ZC_MAX_CHANNELS] = {0}; + ADC_Handle(&adc); + ZC_ProcessAllChannels(&hzc, adc.Data, uwTick); + for(int i = 0; i < ZC_MAX_CHANNELS; i++) + { + if(last_zc_cnt[i] != ZC_GetCrossCount(&hzc, i)) + { + last_zc_cnt[i] = ZC_GetCrossCount(&hzc, i); + ZC_Detected[i] = !ZC_Detected[i]; + } + } } \ No newline at end of file diff --git a/UPP/Core/UPP/upp_main.h b/UPP/Core/UPP/upp_main.h index 3d72e8b..bc34d36 100644 --- a/UPP/Core/UPP/upp_main.h +++ b/UPP/Core/UPP/upp_main.h @@ -18,4 +18,6 @@ int UPP_PreWhile(void); /* Основной цикл УПП. */ int UPP_While(void); +void UPP_ADC_Handle(void); +extern uint32_t ZC_Detected[]; #endif //_UPP_MAIN_H \ No newline at end of file diff --git a/UPP/MDK-ARM/UPP.uvoptx b/UPP/MDK-ARM/UPP.uvoptx index e09e15c..5a030cf 100644 --- a/UPP/MDK-ARM/UPP.uvoptx +++ b/UPP/MDK-ARM/UPP.uvoptx @@ -359,6 +359,30 @@ 0 0 + + 3 + 14 + 1 + 0 + 0 + 0 + ..\Core\PowerMonitor\zero_cross.c + zero_cross.c + 0 + 0 + + + 3 + 15 + 5 + 0 + 0 + 0 + ..\Core\PowerMonitor\zero_cross.h + zero_cross.h + 0 + 0 + @@ -377,7 +401,7 @@ 0 5 - 14 + 16 1 0 0 @@ -389,7 +413,7 @@ 5 - 15 + 17 1 0 0 @@ -401,7 +425,7 @@ 5 - 16 + 18 1 0 0 @@ -413,7 +437,7 @@ 5 - 17 + 19 1 0 0 @@ -425,7 +449,7 @@ 5 - 18 + 20 1 0 0 @@ -437,7 +461,7 @@ 5 - 19 + 21 1 0 0 @@ -449,7 +473,7 @@ 5 - 20 + 22 1 0 0 @@ -461,7 +485,7 @@ 5 - 21 + 23 1 0 0 @@ -473,7 +497,7 @@ 5 - 22 + 24 1 0 0 @@ -485,7 +509,7 @@ 5 - 23 + 25 1 0 0 @@ -497,7 +521,7 @@ 5 - 24 + 26 1 0 0 @@ -509,7 +533,7 @@ 5 - 25 + 27 1 0 0 @@ -521,7 +545,7 @@ 5 - 26 + 28 1 0 0 @@ -541,7 +565,7 @@ 0 6 - 27 + 29 5 0 0 @@ -553,7 +577,7 @@ 6 - 28 + 30 5 0 0 @@ -565,7 +589,7 @@ 6 - 29 + 31 5 0 0 @@ -577,7 +601,7 @@ 6 - 30 + 32 5 0 0 @@ -589,7 +613,7 @@ 6 - 31 + 33 5 0 0 @@ -601,7 +625,7 @@ 6 - 32 + 34 5 0 0 @@ -613,7 +637,7 @@ 6 - 33 + 35 1 0 0 @@ -625,7 +649,7 @@ 6 - 34 + 36 5 0 0 @@ -645,7 +669,7 @@ 0 7 - 35 + 37 1 0 0 @@ -657,7 +681,7 @@ 7 - 36 + 38 1 0 0 @@ -669,7 +693,7 @@ 7 - 37 + 39 1 0 0 @@ -681,7 +705,7 @@ 7 - 38 + 40 1 0 0 @@ -693,7 +717,7 @@ 7 - 39 + 41 1 0 0 @@ -705,7 +729,7 @@ 7 - 40 + 42 1 0 0 @@ -717,7 +741,7 @@ 7 - 41 + 43 1 0 0 @@ -729,7 +753,7 @@ 7 - 42 + 44 1 0 0 @@ -741,7 +765,7 @@ 7 - 43 + 45 1 0 0 @@ -753,7 +777,7 @@ 7 - 44 + 46 1 0 0 @@ -765,7 +789,7 @@ 7 - 45 + 47 1 0 0 @@ -777,7 +801,7 @@ 7 - 46 + 48 1 0 0 @@ -797,7 +821,7 @@ 0 8 - 47 + 49 1 0 0 @@ -809,7 +833,7 @@ 8 - 48 + 50 1 0 0 @@ -829,7 +853,7 @@ 0 9 - 49 + 51 1 0 0 @@ -841,7 +865,7 @@ 9 - 50 + 52 1 0 0 @@ -853,7 +877,7 @@ 9 - 51 + 53 1 0 0 @@ -865,7 +889,7 @@ 9 - 52 + 54 1 0 0 @@ -877,7 +901,7 @@ 9 - 53 + 55 1 0 0 @@ -897,7 +921,7 @@ 0 10 - 54 + 56 1 0 0 @@ -909,7 +933,7 @@ 10 - 55 + 57 1 0 0 @@ -921,7 +945,7 @@ 10 - 56 + 58 1 0 0 @@ -933,7 +957,7 @@ 10 - 57 + 59 1 0 0 @@ -945,7 +969,7 @@ 10 - 58 + 60 1 0 0 @@ -957,7 +981,7 @@ 10 - 59 + 61 1 0 0 @@ -969,7 +993,7 @@ 10 - 60 + 62 1 0 0 @@ -981,7 +1005,7 @@ 10 - 61 + 63 1 0 0 @@ -993,7 +1017,7 @@ 10 - 62 + 64 1 0 0 @@ -1005,7 +1029,7 @@ 10 - 63 + 65 1 0 0 @@ -1017,7 +1041,7 @@ 10 - 64 + 66 1 0 0 @@ -1029,7 +1053,7 @@ 10 - 65 + 67 1 0 0 @@ -1041,7 +1065,7 @@ 10 - 66 + 68 1 0 0 @@ -1053,7 +1077,7 @@ 10 - 67 + 69 1 0 0 @@ -1065,7 +1089,7 @@ 10 - 68 + 70 1 0 0 @@ -1077,7 +1101,7 @@ 10 - 69 + 71 1 0 0 @@ -1089,7 +1113,7 @@ 10 - 70 + 72 1 0 0 @@ -1101,7 +1125,7 @@ 10 - 71 + 73 1 0 0 @@ -1113,7 +1137,7 @@ 10 - 72 + 74 1 0 0 @@ -1125,7 +1149,7 @@ 10 - 73 + 75 1 0 0 @@ -1137,7 +1161,7 @@ 10 - 74 + 76 1 0 0 @@ -1149,7 +1173,7 @@ 10 - 75 + 77 1 0 0 @@ -1161,7 +1185,7 @@ 10 - 76 + 78 1 0 0 @@ -1173,7 +1197,7 @@ 10 - 77 + 79 1 0 0 @@ -1193,7 +1217,7 @@ 0 11 - 78 + 80 1 0 0 @@ -1213,7 +1237,7 @@ 0 12 - 79 + 81 2 0 0 diff --git a/UPP/MDK-ARM/UPP.uvprojx b/UPP/MDK-ARM/UPP.uvprojx index fdf03ee..b6b4547 100644 --- a/UPP/MDK-ARM/UPP.uvprojx +++ b/UPP/MDK-ARM/UPP.uvprojx @@ -460,6 +460,16 @@ 5 ..\Core\PowerMonitor\adc_tools.h + + zero_cross.c + 1 + ..\Core\PowerMonitor\zero_cross.c + + + zero_cross.h + 5 + ..\Core\PowerMonitor\zero_cross.h +