#include "stm32c0xx_hal.h"
#include <stdio.h>
#include <string.h>
#define ADC_BUFFER_SIZE 10
#define VOLTAGE_REF 3300 // 3.3V в милливольтах
// Дескрипторы периферии
ADC_HandleTypeDef hadc;
DMA_HandleTypeDef hdma_adc1;
UART_HandleTypeDef huart2;
// Буфер для ADC samples
uint16_t adc_buffer[ADC_BUFFER_SIZE];
uint32_t last_uart_time = 0;
// Прототипы функций
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC1_Init(void);
static void MX_USART2_UART_Init(void);
void Error_Handler(void);
void Serial_Print(const char *message);
void Serial_Println(const char *message);
// Функция для вычисления скользящего среднего
uint16_t moving_average_filter(uint16_t *buffer, uint8_t size) {
uint32_t sum = 0;
for (uint8_t i = 0; i < size; i++) {
sum += buffer[i];
}
return (uint16_t)(sum / size);
}
// Функция для преобразования ADC значения в милливольты
uint32_t adc_to_mv(uint16_t adc_value) {
return (adc_value * VOLTAGE_REF) / 4095; // 12-bit ADC
}
// Функция для отправки строки в Serial Monitor
void Serial_Print(const char *message) {
HAL_UART_Transmit(&huart2, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
}
// Функция для отправки строки с переводом строки в Serial Monitor
void Serial_Println(const char *message) {
HAL_UART_Transmit(&huart2, (uint8_t*)message, strlen(message), HAL_MAX_DELAY);
HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", 2, HAL_MAX_DELAY);
}
// Функция для отправки данных по UART
void send_adc_value(uint32_t voltage_mv) {
char buffer[50];
snprintf(buffer, sizeof(buffer), "ADC: %lu mV", voltage_mv);
Serial_Println(buffer);
}
int main(void) {
// Инициализация HAL
HAL_Init();
// Настройка тактирования
SystemClock_Config();
// Инициализация периферии
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_USART2_UART_Init();
// Инициализация Serial Monitor
Serial_Println("=== STM32C031C6 ADC with DMA ===");
Serial_Println("Initializing ADC...");
// Калибровка ADC (для STM32C0 только один аргумент)
if (HAL_ADCEx_Calibration_Start(&hadc) != HAL_OK) {
Serial_Println("ERROR: ADC calibration failed!");
Error_Handler();
}
Serial_Println("ADC calibration successful");
// Запуск ADC с DMA в непрерывном режиме
if (HAL_ADC_Start_DMA(&hadc, (uint32_t*)adc_buffer, ADC_BUFFER_SIZE) != HAL_OK) {
Serial_Println("ERROR: ADC DMA start failed!");
Error_Handler();
}
Serial_Println("ADC DMA started successfully");
Serial_Println("Reading potentiometer values every 500ms...");
Serial_Println("=====================================");
// Бесконечный цикл
while (1) {
uint32_t current_time = HAL_GetTick();
// Отправка данных каждые 500 мс
if (current_time - last_uart_time >= 500) {
last_uart_time = current_time;
// Применение фильтра скользящего среднего
uint16_t filtered_adc = moving_average_filter(adc_buffer, ADC_BUFFER_SIZE);
// Преобразование в милливольты
uint32_t voltage_mv = adc_to_mv(filtered_adc);
// Отправка по UART в Serial Monitor
send_adc_value(voltage_mv);
// Дополнительная информация для отладки (можно убрать)
static uint32_t counter = 0;
counter++;
if (counter % 10 == 0) { // Каждые 5 секунд
char debug_buffer[80];
snprintf(debug_buffer, sizeof(debug_buffer),
"Debug: Raw ADC=%u, Filtered=%u, Samples=%d",
adc_buffer[0], filtered_adc, ADC_BUFFER_SIZE);
Serial_Println(debug_buffer);
Serial_Println("-------------------------------------");
}
}
// Короткая задержка
HAL_Delay(10);
}
}
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// Настройка тактирования от HSI16
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
Error_Handler();
}
// Настройка системной тактовой частоты
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
Error_Handler();
}
}
static void MX_ADC1_Init(void) {
ADC_ChannelConfTypeDef sConfig = {0};
// Конфигурация ADC1
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.ContinuousConvMode = ENABLE; // Непрерывный режим
hadc.Init.NbrOfConversion = 1;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = ENABLE; // Непрерывные DMA запросы
hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc.Init.SamplingTimeCommon1 = ADC_SAMPLETIME_160CYCLES_5;
hadc.Init.SamplingTimeCommon2 = ADC_SAMPLETIME_160CYCLES_5;
hadc.Init.OversamplingMode = DISABLE;
hadc.Init.TriggerFrequencyMode = ADC_TRIGGER_FREQ_HIGH;
if (HAL_ADC_Init(&hadc) != HAL_OK) {
Error_Handler();
}
// Конфигурация канала ADC (PA0 - Channel 0)
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLINGTIME_COMMON_1;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) {
Error_Handler();
}
}
static void MX_USART2_UART_Init(void) {
// Конфигурация UART2 для Serial Monitor
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK) {
Error_Handler();
}
}
static void MX_DMA_Init(void) {
// Включение тактирования DMA
__HAL_RCC_DMA1_CLK_ENABLE();
// Конфигурация DMA для ADC1
hdma_adc1.Instance = DMA1_Channel1;
hdma_adc1.Init.Request = DMA_REQUEST_ADC1;
hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_adc1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_adc1.Init.Mode = DMA_CIRCULAR; // Циркулярный буфер
hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
if (HAL_DMA_Init(&hdma_adc1) != HAL_OK) {
Error_Handler();
}
// Связывание DMA с ADC
__HAL_LINKDMA(&hadc, DMA_Handle, hdma_adc1);
// Настройка прерываний DMA
HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);
}
static void MX_GPIO_Init(void) {
// Включение тактирования GPIOA
__HAL_RCC_GPIOA_CLK_ENABLE();
}
// Обработчик завершения преобразования ADC
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
// Callback вызывается при завершении преобразования
// Можно использовать для дополнительной логики
}
// Обработчик ошибок
void Error_Handler(void) {
Serial_Println("Fatal error! System halted.");
__disable_irq();
while (1) {
}
}
// Обработчики прерываний
void DMA1_Channel1_IRQHandler(void) {
HAL_DMA_IRQHandler(&hdma_adc1);
}
void HardFault_Handler(void) {
Serial_Println("Hard Fault! System halted.");
while (1) {
}
}Loading
st-nucleo-c031c6
st-nucleo-c031c6