diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index db9c4a9..dd27b94 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -4,6 +4,8 @@ on: push: branches: [ '*' ] tags: [ 'v*' ] + pull_request: + branches: [ '*' ] workflow_dispatch: jobs: diff --git a/Core/Inc/pressure_wrapper.h b/Core/Inc/pressure_wrapper.h index a6039c9..ca1de62 100644 --- a/Core/Inc/pressure_wrapper.h +++ b/Core/Inc/pressure_wrapper.h @@ -14,102 +14,78 @@ extern "C" { #include #include -/** - * Константы преобразований (замена макросов) - */ namespace PressureConversions { - // Преобразование среднего значения АЦП (без учёта атмосферного давления) в напряжение (мВ) constexpr uint32_t adcToVoltage(uint32_t adc_press, uint32_t adc_z) noexcept { return (adc_press - adc_z) * 16575u / 2048u; } - // Преобразование напряжения (мВ) в давление (Па) constexpr uint32_t voltageToPascals(uint32_t voltage_mv) noexcept { return voltage_mv * 6895u / 4u * 37u / 9u; } - // Преобразование давления (Па) в глубину (мм) constexpr uint32_t pascalsToDepthMm(uint32_t pascals) noexcept { - return pascals / (10u * 981u); // 10 * 981 = 9810 + return pascals / (10u * 981u); } - // Преобразование среднего значения АЦП температуры в напряжение (мВ) constexpr uint32_t tempAdcToVoltage(uint32_t adc_temp) noexcept { return adc_temp * 33120u / 4096u; } - // Преобразование напряжения температуры (мВ) в температуру (десятые доли градуса Цельсия) constexpr int32_t voltageToTempCelsius(uint32_t voltage_mv) noexcept { - // формула: (напряжение - 5000) * 10 return (static_cast(voltage_mv) - 5000) * 10; } -} // namespace PressureConversions +} class PressureWrapper { public: - // Конструктор PressureWrapper(ADC_HandleTypeDef& hadc, TIM_HandleTypeDef& htim) noexcept : hadc_(hadc), htim_(htim) {} - // Инициализация: калибровка АЦП, запуск таймера и DMA bool init() noexcept { - // Калибровка АЦП (однополярный режим для большинства STM32) if (HAL_ADCEx_Calibration_Start(&hadc_) != HAL_OK) { return false; } - HAL_Delay(100); if (HAL_TIM_Base_Start(&htim_) != HAL_OK) { return false; } + HAL_Delay(100); // дополнительная задержка для стабильности - // Запуск DMA: буфер adcRaw_ объявлен как uint16_t, приводим к uint32_t* - if (HAL_ADC_Start_DMA(&hadc_, reinterpret_cast(adcRaw_.data()), kAdcBufferSize * 2) != HAL_OK) { + // Запуск DMA с правильным типом буфера + if (HAL_ADC_Start_DMA(&hadc_, adcRaw_.data(), kAdcBufferSize * 2) != HAL_OK) { return false; } - return true; } - // Опрос: вызывать в основном цикле void poll() noexcept { - // Проверяем, завершён ли полный буфер (флаг атомарный) if (fullConvDone_.load(std::memory_order_acquire)) { - // Определяем, какая половина буфера заполнена (если обе, то обрабатываем полную) bool half = halfConvDone_.load(std::memory_order_acquire); - - // Обрабатываем данные буфера (используется локальное копирование) adcProcess(half); - // Для первого набора данных сохраняем нулевое давление (атмосферное) if (isFirst_) { - adc_z_ = pressSum_; // среднее значение АЦП для нулевого давления + adc_z_ = pressSum_; isFirst_ = false; } - // Вычисляем физические величины adcVoltage_ = PressureConversions::adcToVoltage(pressSum_, adc_z_); adcPascals_ = PressureConversions::voltageToPascals(adcVoltage_); depthMm_ = PressureConversions::pascalsToDepthMm(adcPascals_); - - // Если температура используется, вычисляем и её tempMilliCelsius_ = PressureConversions::voltageToTempCelsius( PressureConversions::tempAdcToVoltage(tempSum_) ); - // Сбрасываем флаг полного завершения (после того как данные обработаны) fullConvDone_.store(false, std::memory_order_release); } } - // Геттеры uint32_t getDepthMm() const noexcept { return depthMm_; } uint32_t getPressurePascals() const noexcept { return adcPascals_; } uint32_t getAdcVoltage() const noexcept { return adcVoltage_; } int32_t getTemperatureMilliCelsius() const noexcept { return tempMilliCelsius_; } - // Методы, вызываемые из обработчиков прерываний + // Эти методы должны вызываться из прерываний DMA void setHalfConvFlag() noexcept { halfConvDone_.store(true, std::memory_order_release); fullConvDone_.store(true, std::memory_order_release); @@ -119,24 +95,17 @@ class PressureWrapper { fullConvDone_.store(true, std::memory_order_release); } - // Доступ к дескриптору АЦП для идентификации в обработчиках (опционально) ADC_HandleTypeDef& getHadc() noexcept { return hadc_; } - ~PressureWrapper() = default; - private: - // Обработка данных из DMA-буфера void adcProcess(bool isHalf) noexcept { - // Определяем диапазон индексов в буфере adcRaw_ const size_t start = isHalf ? 0 : kAdcBufferSize; const size_t end = isHalf ? kAdcBufferSize : kAdcBufferSize * 2; uint32_t pressSumLocal = 0; uint32_t tempSumLocal = 0; - // Суммируем значения из указанной половины буфера for (size_t i = start; i < end; ++i) { - // Чётные индексы — канал давления, нечётные — температуры if ((i & 1) == 0) { pressSumLocal += adcRaw_[i]; } else { @@ -144,12 +113,10 @@ class PressureWrapper { } } - // Вычисляем среднее значение для каждой половины буфера - const size_t halfCount = kAdcBufferSize / 2; + const size_t halfCount = kAdcBufferSize / 2; // количество пар в половине pressSum_ = pressSumLocal / halfCount; tempSum_ = tempSumLocal / halfCount; - // Сбрасываем флаги (только тот, который был обработан) if (isHalf) { halfConvDone_.store(false, std::memory_order_release); } else { @@ -157,30 +124,22 @@ class PressureWrapper { } } - // Дескрипторы периферии ADC_HandleTypeDef& hadc_; TIM_HandleTypeDef& htim_; - // Параметры DMA - static constexpr size_t kAdcBufferSize = 200; // количество отсчётов на канал - // Буфер АЦП: 16-битные значения от DMA (обычно для 12-битных АЦП) - std::array adcRaw_{}; + static constexpr size_t kAdcBufferSize = 200; + // Буфер теперь 32-битный, как требует HAL + std::array adcRaw_{}; - // Атомарные флаги для синхронизации с прерываниями std::atomic halfConvDone_{false}; std::atomic fullConvDone_{false}; - // Состояние bool isFirst_ = true; - // Суммы/средние АЦП uint32_t pressSum_ = 0; uint32_t tempSum_ = 0; + uint32_t adc_z_ = 0; - // Эталонное значение АЦП для атмосферного давления - uint32_t adc_z_ = 0; - - // Вычисленные физические величины uint32_t adcVoltage_ = 0; uint32_t adcPascals_ = 0; uint32_t depthMm_ = 0; diff --git a/Core/Src/main.cpp b/Core/Src/main.cpp index 8308eaa..4347ead 100644 --- a/Core/Src/main.cpp +++ b/Core/Src/main.cpp @@ -3,7 +3,7 @@ extern "C" { #endif #include "main.h" - +#include "stm32f1xx_it.h" #ifdef __cplusplus } #endif @@ -263,12 +263,17 @@ static void MX_DMA_Init(void) { } /* USER CODE BEGIN 4 */ -void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { - sensor.setFullConvFlag(); + +void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc) { + if (hadc == &sensor.getHadc()) { + sensor.setHalfConvFlag(); + } } -void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef *hadc) { - sensor.setHalfConvFlag(); +void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { + if (hadc == &sensor.getHadc()) { + sensor.setFullConvFlag(); + } } void USART1_IRQHandler(void) { RS.IRQCallback(); }