告别OLED和复杂代码:用STM32串口直连YL-69,5分钟搞定土壤湿度数据读取
STM32极简实战5分钟实现YL-69土壤湿度传感器串口直读在嵌入式开发中我们常常需要快速验证传感器数据的准确性而不是一开始就陷入复杂的显示驱动和数据处理中。本文将带你用最精简的方式通过STM32的ADC和串口功能直接读取YL-69土壤湿度传感器的数据无需OLED或其他复杂外设。1. 硬件准备与连接YL-69是一款常见的土壤湿度检测模块它通过电阻变化来检测土壤中的水分含量。模块有四个引脚VCC3.3V供电GND地线AO模拟输出0-3.3VDO数字输出阈值可调最小系统连接方案传感器引脚STM32连接点VCC3.3VGNDGNDAOPA1 (ADC1通道1)DO不连接提示YL-69的中间两个引脚需要手动短接这是传感器的电极接口。2. 工程配置与代码实现我们将使用STM32标准外设库创建最简单的ADC采集和串口打印工程。2.1 ADC初始化配置首先配置ADC通道用于读取传感器的模拟电压值// adc.h #ifndef __ADC_H #define __ADC_H #include stm32f10x.h void ADC1_Init(void); uint16_t Get_ADC_Value(uint8_t ch); #endif// adc.c #include adc.h #include stm32f10x_adc.h void ADC1_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; // 使能GPIOA和ADC1时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE); // 配置PA1为模拟输入 GPIO_InitStructure.GPIO_Pin GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AIN; GPIO_Init(GPIOA, GPIO_InitStructure); // ADC基本配置 ADC_InitStructure.ADC_Mode ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode DISABLE; ADC_InitStructure.ADC_ContinuousConvMode DISABLE; ADC_InitStructure.ADC_ExternalTrigConv ADC_ExternalTrigConv_None; ADC_InitStructure.ADC_DataAlign ADC_DataAlign_Right; ADC_InitStructure.ADC_NbrOfChannel 1; ADC_Init(ADC1, ADC_InitStructure); // 使能ADC ADC_Cmd(ADC1, ENABLE); // ADC校准 ADC_ResetCalibration(ADC1); while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while(ADC_GetCalibrationStatus(ADC1)); } uint16_t Get_ADC_Value(uint8_t ch) { // 设置转换通道 ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5); // 启动转换 ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 等待转换完成 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); return ADC_GetConversionValue(ADC1); }2.2 串口配置与数据打印配置USART1用于数据输出// usart.h #ifndef __USART_H #define __USART_H #include stm32f10x.h #include stdio.h void USART1_Init(uint32_t baudrate); void USART1_SendChar(char ch); int fputc(int ch, FILE *f); #endif// usart.c #include usart.h void USART1_Init(uint32_t baudrate) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; // 使能USART1和GPIOA时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE); // 配置PA9为复用推挽输出(TX) GPIO_InitStructure.GPIO_Pin GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_Init(GPIOA, GPIO_InitStructure); // 配置PA10为浮空输入(RX) GPIO_InitStructure.GPIO_Pin GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, GPIO_InitStructure); // USART参数配置 USART_InitStructure.USART_BaudRate baudrate; USART_InitStructure.USART_WordLength USART_WordLength_8b; USART_InitStructure.USART_StopBits USART_StopBits_1; USART_InitStructure.USART_Parity USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode USART_Mode_Rx | USART_Mode_Tx; USART_Init(USART1, USART_InitStructure); // 使能USART1 USART_Cmd(USART1, ENABLE); } void USART1_SendChar(char ch) { while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); USART_SendData(USART1, ch); } // 重定向printf到串口 int fputc(int ch, FILE *f) { USART1_SendChar(ch); return ch; }2.3 主程序实现// main.c #include stm32f10x.h #include adc.h #include usart.h #include stdio.h int main(void) { uint16_t adc_value; uint8_t humidity_percent; // 初始化ADC和USART ADC1_Init(); USART1_Init(9600); while(1) { // 获取ADC值 adc_value Get_ADC_Value(1); // 转换为百分比 (0-100%) // YL-69在干燥环境中输出接近3.3V(ADC值接近4095) // 在湿润环境中输出接近0V(ADC值接近0) humidity_percent 100 - (adc_value * 100 / 4095); // 通过串口输出 printf(ADC值: %d, 湿度: %d%%\r\n, adc_value, humidity_percent); // 适当延时 for(int i0; i1000000; i); } }3. 数据校准与优化YL-69传感器的输出需要根据实际使用环境进行校准。以下是校准步骤干燥环境校准将传感器置于完全干燥的土壤或空气中记录此时的ADC值应为最大值接近4095湿润环境校准将传感器浸入水中记录此时的ADC值应为最小值接近0修改转换公式 根据实际测量值调整main.c中的转换公式// 原始公式 humidity_percent 100 - (adc_value * 100 / 4095); // 校准后公式 humidity_percent 100 * (adc_value - dry_value) / (wet_value - dry_value);注意传感器长期浸泡在水中可能导致氧化建议间歇性测量。4. 常见问题排查在实际使用中可能会遇到以下问题问题1串口无输出检查串口线连接是否正确确认串口助手波特率设置为9600检查USART1的TX(PA9)是否连接正确问题2ADC值不变化确认传感器AO引脚连接到了PA1检查传感器供电是否为3.3V尝试用手触摸传感器电极观察ADC值是否变化问题3数值跳动较大在代码中添加软件滤波uint16_t get_filtered_adc(uint8_t ch, uint8_t samples) { uint32_t sum 0; for(uint8_t i0; isamples; i) { sum Get_ADC_Value(ch); // 适当延时 for(int j0; j1000; j); } return sum / samples; }在main函数中调用此函数替代直接读取ADC5. 进阶应用建议虽然本文实现了最基本的读取功能但在实际项目中你可能还需要低功耗优化间歇性唤醒测量测量后进入低功耗模式数据记录添加时间戳存储历史数据阈值报警使用DO引脚实现硬件报警软件实现多级报警// 简单的阈值报警示例 if(humidity_percent 30) { printf(警告土壤过干\r\n); } else if(humidity_percent 80) { printf(警告土壤过湿\r\n); }这个极简方案已经帮助数十位开发者快速验证了他们的土壤湿度检测原型特别适合课程设计、毕业设计或农业物联网的初期验证阶段。当你在面包板上看到串口打印出的湿度百分比随着土壤湿度变化时那种成就感会让你爱上嵌入式开发。