STM32 HAL 水位传感器驱动程序

工作原理是输出模拟量电压值,只需要使用stm32adc读取电压再转换一下即可

本代码中,水位传感器连接在PA0,可通过宏定义快速设置电压区间和水位之间的关系

water_level.c

cpp 复制代码
/**
  ******************************************************************************
  * @file    water_level.c
  * @brief   水位传感器驱动实现
  ******************************************************************************
  * @attention
  *
  * 水位传感器通过ADC读取PA0引脚电压值
  * 水位范围:0-5cm
  * 对应电压:0.65V-1.9V
  *
  ******************************************************************************
  */

/* 包含头文件 */
#include "water_level.h"

/* 私有定义 */
#define WATER_LEVEL_PIN           GPIO_PIN_0
#define WATER_LEVEL_PORT          GPIOA
#define WATER_LEVEL_ADC_CHANNEL   ADC_CHANNEL_0

/* 水位传感器参数 */
#define WATER_MIN_VOLTAGE         0.8f   // 最小水位对应电压 (V)
#define WATER_MAX_VOLTAGE         1.6f    // 最大水位对应电压 (V)
#define WATER_MIN_DEPTH           0.0f    // 最小水位深度 (mm)
#define WATER_MAX_DEPTH           50.0f   // 最大水位深度 (mm)
#define ADC_REFERENCE_VOLTAGE     3.3f    // ADC参考电压 (V)
#define ADC_RESOLUTION            4096    // ADC分辨率 (12位)

/* 私有变量 */
static ADC_HandleTypeDef hadc1;

/**
  * @brief  水位传感器初始化
  * @param  无
  * @retval HAL状态
  */
HAL_StatusTypeDef WaterLevel_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    ADC_ChannelConfTypeDef sConfig = {0};
    
    /* 使能GPIO时钟 */
    __HAL_RCC_GPIOA_CLK_ENABLE();
    /* 使能ADC1时钟 */
    __HAL_RCC_ADC1_CLK_ENABLE();
    
    /* 配置GPIO引脚 */
    GPIO_InitStruct.Pin = WATER_LEVEL_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(WATER_LEVEL_PORT, &GPIO_InitStruct);
    
    /* 配置ADC */
    hadc1.Instance = ADC1;
    hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    hadc1.Init.ContinuousConvMode = DISABLE;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.NbrOfConversion = 1;
    
    if (HAL_ADC_Init(&hadc1) != HAL_OK)
    {
        return HAL_ERROR;
    }
    
    /* 配置ADC通道 */
    sConfig.Channel = WATER_LEVEL_ADC_CHANNEL;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
    
    if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
    {
        return HAL_ERROR;
    }
    
    /* ADC校准 */
    if (HAL_ADCEx_Calibration_Start(&hadc1) != HAL_OK)
    {
        return HAL_ERROR;
    }
    
    return HAL_OK;
}

/**
  * @brief  读取水位原始ADC值
  * @param  无
  * @retval ADC原始值 (0-4095)
  */
uint16_t WaterLevel_GetRawADC(void)
{
    uint16_t adcValue = 0;
    
    /* 启动ADC转换 */
    HAL_ADC_Start(&hadc1);
    
    /* 等待转换完成 */
    if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK)
    {
        /* 读取ADC转换结果 */
        adcValue = HAL_ADC_GetValue(&hadc1);
    }
    
    /* 停止ADC转换 */
    HAL_ADC_Stop(&hadc1);
    
    return adcValue;
}

/**
  * @brief  读取水位深度
  * @param  无
  * @retval 水位深度,单位:mm (0-50mm)
  */
float WaterLevel_GetDepth(void)
{
    uint16_t adcValue = WaterLevel_GetRawADC();
    float voltage = (float)adcValue * ADC_REFERENCE_VOLTAGE / ADC_RESOLUTION;
    float depth;
    
    /* 将电压值转换为水位深度 */
    if (voltage <= WATER_MIN_VOLTAGE)
    {
        depth = WATER_MIN_DEPTH;
    }
    else if (voltage >= WATER_MAX_VOLTAGE)
    {
        depth = WATER_MAX_DEPTH;
    }
    else
    {
        /* 线性插值计算水位深度 */
        depth = WATER_MIN_DEPTH + (voltage - WATER_MIN_VOLTAGE) * 
                (WATER_MAX_DEPTH - WATER_MIN_DEPTH) / 
                (WATER_MAX_VOLTAGE - WATER_MIN_VOLTAGE);
    }
    
    return depth;
}

water_level.h

cpp 复制代码
/**
  ******************************************************************************
  * @file    water_level.h
  * @brief   水位传感器驱动头文件
  ******************************************************************************
  * @attention
  *
  * 水位传感器通过ADC读取PA0引脚电压值
  * 水位范围:0-5cm
  * 对应电压:0.65V-1.9V
  *
  ******************************************************************************
  */

#ifndef __WATER_LEVEL_H
#define __WATER_LEVEL_H

#ifdef __cplusplus
extern "C" {
#endif

/* 包含头文件 */
#include "main.h"
#include "stm32f1xx_hal.h"

/* 函数声明 */
/**
  * @brief  水位传感器初始化
  * @param  无
  * @retval HAL状态
  */
HAL_StatusTypeDef WaterLevel_Init(void);

/**
  * @brief  读取水位深度
  * @param  无
  * @retval 水位深度,单位:mm (0-50mm)
  */
float WaterLevel_GetDepth(void);

/**
  * @brief  读取水位原始ADC值
  * @param  无
  * @retval ADC原始值 (0-4095)
  */
uint16_t WaterLevel_GetRawADC(void);

#ifdef __cplusplus
}
#endif

#endif /* __WATER_LEVEL_H */
相关推荐
LCG米8 小时前
STM32硬件CRC外设实测:多项式固定陷阱、CRC-32校验不匹配根因与软件查表法耗时对比落地
stm32·单片机·嵌入式硬件
La Pulga11 小时前
【FreeRTOS源码学习笔记】任务切换
单片机·mcu·学习·嵌入式·freertos·实时操作系统
女神下凡15 小时前
芯参谋(85):Linux_PPI_NAND_驱动开发指南
linux·运维·arm开发·驱动开发·单片机·嵌入式硬件·设计规范
Zw-awa16 小时前
从 CH340 到 HC-05 和 HC-06:让小车脱离电脑
stm32
硅基手札17 小时前
【Linux 内核专栏 19】20 · 嵌入式子系统 — GPIO·pinctrl·clock·regulator
linux·运维·单片机·linux内核·嵌入式开发·调试定位
何粥学19 小时前
Vivado 2024.2 开发记录(AC820 Zynq-7020)——软件使用,点亮led灯
单片机·嵌入式硬件·zynq
Sakura_j_h_19 小时前
51 单片机驱动四位数码管:动态扫描、限流电阻与消影的取舍
单片机·嵌入式硬件·51单片机·嵌入式·数码管·动态扫描·限流电阻
HANDY0920021 小时前
从“不照人”到“剂量达标”:扇叶遮挡式UV-C空气消毒的工程边界与可验证评估框架
开发语言·人工智能·嵌入式硬件·智能家居
飞凌嵌入式1 天前
千次静电放电试炼,守住飞凌嵌入式硬件可靠底线
嵌入式硬件
蹊黎1 天前
Linux 下用 C 语言实现进度条
linux·c语言·单片机