Skip to content
c
#include "adc.h"

// 定义全局变量
ADC_HandleTypeDef hadc2;       // ADC2外设句柄
uint16_t ADC_Value = 0;        // 存储ADC转换结果
float Voltage = 0.0;           // 存储计算后的电压值

/**
  * @brief  ADC2初始化函数
  * @note   配置ADC2的基本参数和通道参数
  * @retval None
  */
void MX_ADC2_Init(void)
{
    ADC_ChannelConfTypeDef sConfig = {0};  // ADC通道配置结构体

    /* 配置ADC2基本参数 */
    hadc2.Instance = ADC2;                             // 选择ADC2外设
    hadc2.Init.ScanConvMode = ADC_SCAN_DISABLE;        // 禁用扫描模式(单通道)
    hadc2.Init.ContinuousConvMode = ENABLE;            // 启用连续转换模式
    hadc2.Init.DiscontinuousConvMode = DISABLE;        // 禁用间断转换模式
    hadc2.Init.ExternalTrigConv = ADC_SOFTWARE_START;  // 使用软件触发转换
    hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;        // 数据右对齐
    hadc2.Init.NbrOfConversion = 1;                    // 1个转换在规则序列中
    HAL_ADC_Init(&hadc2);                              // 初始化ADC2

    /* 配置ADC2通道参数 */
    sConfig.Channel = ADC_CHANNEL_0;                   // 选择通道0 (PA0)
    sConfig.Rank = ADC_REGULAR_RANK_1;                 // 规则组第1个转换
    sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; // 采样时间为239.5个周期
    HAL_ADC_ConfigChannel(&hadc2, &sConfig);           // 配置ADC通道

    /* 执行ADC校准 */
    HAL_ADCEx_Calibration_Start(&hadc2);
}

/**
  * @brief  获取ADC转换值
  * @note   启动ADC转换并等待转换完成,返回转换结果
  * @retval ADC转换值(12位分辨率)
  */
uint16_t Get_ADC_Value(void)
{
    HAL_ADC_Start(&hadc2); // 启动ADC转换

    // 等待转换完成,超时时间100ms
    HAL_ADC_PollForConversion(&hadc2, 100);

    // 判断转换是否完成(检查EOC标志位)
    if (HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc2), HAL_ADC_STATE_REG_EOC))
    {
        return HAL_ADC_GetValue(&hadc2); // 返回转换结果
    }

    return 0; // 转换失败返回0
}

/**
  * @brief  获取平均电压值
  * @param  times: 采样次数
  * @note   多次采样取平均值以提高精度,并转换为电压值
  * @retval 计算后的电压值(单位:伏特)
  */
float Get_Average_Voltage(uint8_t times)
{
    uint32_t temp_val = 0; // 临时累加值
    uint8_t t;             // 循环计数器

    // 多次采样累加
    for (t = 0; t < times; t++)
    {
        temp_val += Get_ADC_Value(); // 获取ADC值并累加
        HAL_Delay(5);                // 每次采样间隔5ms
    }

    // 计算平均ADC值
    temp_val = temp_val / times;

    // 将ADC值转换为电压值(假设参考电压为3.3V,12位分辨率)
    return (float)temp_val * (3.3 / 4096);
}

/**
  * @brief  ADC MSP初始化
  * @param  adcHandle: ADC句柄指针
  * @note   此函数由HAL_ADC_Init()调用,用于底层硬件初始化
  *         包括: 1. 使能外设时钟
  *              2. 配置GPIO
  *              3. 配置中断
  * @retval None
  */
void HAL_ADC_MspInit(ADC_HandleTypeDef *adcHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // 判断是否为ADC2外设
    if (adcHandle->Instance == ADC2)
    {
        /* 1. 使能ADC2时钟 */
        __HAL_RCC_ADC2_CLK_ENABLE();

        /* 2. 配置ADC通道对应的GPIO */
        __HAL_RCC_GPIOA_CLK_ENABLE();                  // 使能GPIOA时钟
        GPIO_InitStruct.Pin = GPIO_PIN_0;              // 选择PA0引脚
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;       // 模拟输入模式
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);       // 初始化GPIO

        /* 3. 配置ADC中断 */
        HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0);       // 设置中断优先级
        HAL_NVIC_EnableIRQ(ADC1_2_IRQn);               // 使能ADC中断
    }
}

/**
  * @brief  ADC MSP反初始化
  * @param  adcHandle: ADC句柄指针
  * @note   此函数由HAL_ADC_DeInit()调用,用于底层硬件反初始化
  * @retval None
  */
void HAL_ADC_MspDeInit(ADC_HandleTypeDef *adcHandle)
{
    // 判断是否为ADC2外设
    if (adcHandle->Instance == ADC2)
    {
        /* 1. 禁用ADC2时钟 */
        __HAL_RCC_ADC2_CLK_DISABLE();

        /* 2. 反初始化GPIO */
        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0);           // 反初始化PA0引脚

        /* 3. 禁用ADC中断 */
        HAL_NVIC_DisableIRQ(ADC1_2_IRQn);             // 禁用ADC中断
    }
}