应用场景
在物联网智能农业、盆栽监测等场景中,土壤湿度是核心监测指标之一。本文基于OpenHarmony 1.0 轻量级系统(Hi3861_WiFi_IoT开发板),搭配电阻式土壤湿度传感器,实现土壤湿度的精准采集、ADC模拟信号转数字信号、电压值到湿度百分比的换算,并输出标准化采集数据,为后续的智能浇水、湿度阈值报警等功能提供基础。
开发核心需求:
- 基于OpenHarmony 1.0标准驱动,实现ADC采集功能,匹配Hi3861硬件特性;
- 完成模拟电压到土壤湿度百分比的转换,解决传感器实际特性与理论公式的匹配问题;
- 保证代码符合OpenHarmony开发规范,结构精简、可维护性强;
- 输出纯英文打印日志,避免串口乱码,适配嵌入式开发调试场景。
二、硬件准备与原理说明
2.1 硬件
2.2 传感器工作原理
本文使用的电阻式土壤湿度传感器为模拟输出型,核心原理是:土壤湿度不同,导电性不同,传感器电极间的电阻值会发生变化——土壤湿度越高,电阻越小,输出的模拟电压越低;土壤湿度越低,电阻越大,输出的模拟电压越高。
传感器输出 0~3.3V(5V供电时)的模拟电压,需通过开发板的ADC(模拟/数字转换器)将模拟信号转换为0~4095的数字信号,再通过公式换算为 0~100% 的湿度百分比,实现量化监测。
三、开发环境准备
- 系统环境:Ubuntu 18.04/20.04(推荐,OpenHarmony官方编译环境);
- 开发工具:VS Code(代码编写)、MobaXterm/Xshell(串口调试)、HarmonyOS DevEco Device Tool(可选);
- 固件版本:OpenHarmony 1.0(Hi3861专用版,已适配ADC、GPIO驱动);
- 串口配置:波特率115200、数据位8、停止位1、无校验、无流控。
四、核心代码实现
4.1 代码设计思路
- 分层设计:按“硬件初始化、数据采集、数值换算”分层,函数职责单一,符合高内聚低耦合原则;
- 规范适配:严格遵循OpenHarmony 1.0开发规范,头文件、宏定义、函数命名、注释均符合嵌入式开发标准;
- 异常处理:对ADC读取结果做校验,对湿度值做范围限制,避免程序崩溃或输出异常数据;
- 无冗余设计:仅保留土壤湿度采集核心功能,移除无关的GPIO控制、水泵驱动等代码,降低资源占用。
4.2 代码
创建目录,如:
\applications\sample\wifi-iot\app\code_v2.0\std_30_土壤湿度
创建 main.c文件
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
// OpenHarmony系统初始化头文件
#include "ohos_init.h"
// 操作系统任务创建头文件
#include "cmsis_os2.h"
// ADC驱动头文件(核心:读取模拟信号)
#include "hi_adc.h"
// GPIO配置头文件(配置ADC引脚功能)
#include "hi_io.h"
// ===================== 硬件配置(匹配你的开发板) =====================
// 土壤湿度传感器ADC通道:GPIO9对应ADC4(硬件文档指定)
#define SOIL_ADC_CHANNEL HI_ADC_CHANNEL_4
/**
* @brief 初始化ADC采集引脚(GPIO9)
* @note 仅配置ADC采集所需的GPIO,移除水泵/继电器相关配置
*/
static void ADC_Pin_Init(void)
{
// 配置GPIO9为ADC功能(关闭默认的上下拉电阻,避免干扰采集)
hi_io_set_func(HI_IO_NAME_GPIO_9, HI_IO_FUNC_GPIO_9_GPIO);
hi_io_set_pull(HI_IO_NAME_GPIO_9, HI_IO_PULL_NONE);
}
/**
* @brief 读取并计算土壤湿度(核心函数)
* @return 湿度百分比(0~100%)
* @note 电压越低 → 湿度越高(0V=100%,3.3V=0%)
*/
static uint8_t Read_Soil_Humidity(void)
{
uint16_t adc_raw = 0; // 原始ADC值(0~4095)
float voltage = 0.0f; // 转换后的电压值(0~3.3V)
uint8_t humidity = 0; // 最终湿度百分比
// 读取ADC原始值:通道4、8次平均滤波、默认偏置电流
if (hi_adc_read(SOIL_ADC_CHANNEL, &adc_raw, HI_ADC_EQU_MODEL_8,
HI_ADC_CUR_BAIS_DEFAULT, 0) == HI_ERR_SUCCESS)
{
// ADC值转换为实际电压(公式:电压 = ADC值 * 3.3V / 4095)
voltage = hi_adc_convert_to_voltage(adc_raw);
// 计算湿度:电压越高湿度越低,最终结果限制在0~100%
humidity = 100 - (uint8_t)((voltage / 3.3f) * 100);
humidity = (humidity > 100) ? 100 : humidity;
// 打印结果(纯英文,避免乱码)
printf("ADC raw: %d | Voltage: %.2fV | Soil humidity: %d%%\n", adc_raw, voltage, humidity);
}
else
{
// ADC读取失败时的提示
printf("Failed to read ADC data!\n");
humidity = 0;
}
return humidity;
}
/**
* @brief 土壤湿度采集主任务
* @param arg: 任务入参(未使用)
* @note 死循环持续采集,每秒刷新一次
*/
void Soil_Humi_Collect_Task(void *arg)
{
(void)arg; // 忽略未使用参数,避免编译警告
// 初始化ADC引脚
ADC_Pin_Init();
// 任务启动提示(纯英文)
printf("Soil humidity collection task started!\n");
// 持续采集湿度
while (1)
{
Read_Soil_Humidity(); // 读取并打印湿度
sleep(1); // 延时1秒,降低采集频率
}
}
/**
* @brief 系统初始化入口
* @note 创建并启动湿度采集任务,系统开机自动运行
*/
void Soil_Humi_Init(void)
{
// 任务属性配置:名称、栈大小、优先级
osThreadAttr_t task_attr = {
.name = "SoilHumiTask", // 任务名称
.stack_size = 1024 * 2, // 简化栈大小(仅采集功能,2KB足够)
.priority = osPriorityNormal, // 普通优先级
};
// 创建任务并启动
if (osThreadNew(Soil_Humi_Collect_Task, NULL, &task_attr) == NULL)
{
printf("Failed to create soil humidity task!\n");
}
}
// 注册系统启动入口,开机自动执行Soil_Humi_Init
SYS_RUN(Soil_Humi_Init);
同目录创建 BUILD.gn 文件:
# static_library中指定业务模块的编译结果.为静态库文件libmyapp.a,开发者根据实际情况完成填写。
#sources中指定静态库.a所依赖的.c文件及其路径,若路径中包含"//"则表示绝对路径(此处为代码根路径),若不包含"//"则表示相对路径。
#include_dirs中指定source所需要依赖的.h文件路径。
static_library("app") {
sources = [
"main.c"
]
include_dirs = [
"//utils/native/lite/include",
"//base/iot_hardware/interfaces/kits/wifiiot_lite",
"//kernel/liteos_m/components/cmsis/2.0",
]
}
4.3 核心代码解析
4.3.1 头文件引入
仅引入核心必要头文件,遵循“最小依赖”原则:
- 标准库头文件(
stdio.h/stdint.h/unistd.h):实现打印、固定宽度类型、延时功能; - OpenHarmony系统头文件(
ohos_init.h/cmsis_os2.h):实现系统启动、任务创建; - 硬件驱动头文件(
hi_adc.h/hi_io.h):实现ADC采集、GPIO引脚配置。
4.3.2 宏定义配置
所有硬件配置、任务参数均通过宏定义实现,便于后期修改与移植:
SOIL_ADC_CHANNEL:指定ADC采集通道,与硬件接线匹配;- 任务栈大小与优先级:根据功能需求配置,避免资源过度分配或不足。
4.3.3 ADC引脚初始化
ADC_Pin_Init函数仅完成ADC采集引脚的核心配置:
hi_io_set_func:将 GPIO9 配置为 ADC 功能,兼容OpenHarmony 1.0底层驱动;hi_io_set_pull:关闭GPIO9上下拉电阻,防止外部电阻干扰ADC采集信号,保证数据准确性。
4.3.4 土壤湿度采集与换算
Read_Soil_Humidity是核心业务函数,完成三大核心功能:
- ADC采集:调用
hi_adc_read读取原始值,使用8次平均滤波(HI_ADC_EQU_MODEL_8)提高采集稳定性; - 电压转换:调用官方API
hi_adc_convert_to_voltage将ADC原始值转换为实际电压,避免手动计算带来的误差; - 湿度换算:根据传感器“电压越低湿度越高”的特性,通过理论公式
humidity = 100 - (uint8_t)((voltage / 3.3f) * 100);将电压值换算为0~100%的湿度百分比,并对电压、湿度值做范围限制,避免异常数据。
同时对ADC读取结果做校验,采集失败时打印错误日志并返回默认值,保证程序健壮性。
4.3.5 任务创建与系统启动
- 采集任务:
Soil_Humi_Collect_Task为后台死循环任务,初始化引脚后每秒调用一次采集函数,实现持续监测; - 任务创建:
Soil_Humi_Init配置任务属性并创建任务,判断创建结果,避免任务创建失败导致程序无响应; - 系统注册:通过
SYS_RUN宏注册入口函数,OpenHarmony系统开机后自动执行,无需手动调用。
五、编译与烧录
5.1 编译
详见:
https://www.malaoshi.top/show_1GW1wTyUOMPk.html
5.3 固件烧录
详见:
https://www.malaoshi.top/show_1GW1wWWflGbq.html
六、运行结果与调试
- 传感器在干燥空气中:ADC值≈1800~4095,电压≈3.0~3.3V,湿度≈0%~10%;
- 传感器插入湿润土壤:ADC值≈500~1500,电压≈0.5~2.5V,湿度≈20%~80%;
- 传感器完全浸入水中:ADC值≈0~300,电压≈0~0.5V,湿度≈90%~100%。
注意:经过测试发现,探头前三分之一放到水里,湿度是:25%,探头全部放到水里,湿度是:33%,应该是硬件问题
七、常见问题与调试方案
问题1:ADC值固定不变,湿度无变化
原因:GPIO引脚未配置为ADC功能;接线错误,AO引脚未接GPIO9;传感器供电异常。
调试:检查ADC_Pin_Init函数是否执行;重新核对接线,确保AO接GPIO9;用万用表测量传感器VCC电压,保证5V/3.3V供电正常。
问题2:传感器放入水中,湿度仅20%~30%,无法达到90%+
原因:传感器供电为3.3V,量程压缩;传感器电极氧化/污染;传感器本身质量问题。
调试:将传感器VCC改为5V供电;用酒精棉擦拭电极表面,清除氧化层与污垢;更换全新的电阻式模拟输出传感器。
问题3:串口打印乱码
原因:打印内容包含中文;串口波特率与开发板不匹配。
调试:保证打印内容为纯英文(本文代码已做处理);确认串口波特率为115200,与开发板配置一致。
问题4:ADC采集失败,打印“Failed to read ADC data!”
原因:ADC通道被其他功能占用;GPIO9引脚损坏;底层驱动未适配。
调试:检查工程中是否有其他代码使用ADC4通道;更换开发板其他ADC通道(如ADC5)测试;确认使用的是Hi3861专用的OpenHarmony 1.0固件。

