用STM32F103C8T6和SSD1306做个水位监测器:从ADC采集到OLED显示的完整流程 基于STM32的水位监测系统开发实战从传感器到OLED可视化在嵌入式系统开发领域将物理世界的数据采集并可视化是一个极具实用价值的技能组合。本文将带您完成一个完整的DIY项目——使用STM32F103C8T6微控制器搭配SSD1306 OLED显示屏构建一个实时水位监测系统。不同于简单的代码片段展示我们将从硬件选型、电路设计、信号处理到用户界面开发全方位解析每个技术环节的实现细节。1. 项目规划与硬件选型1.1 核心组件功能分析一个典型的水位监测系统需要三大功能模块协同工作传感模块Water Sensor水位传感器通过暴露的平行导线测量水量变化输出与水位高度成正比的模拟信号控制核心STM32F103C8T6作为Cortex-M3内核微控制器内置12位ADC可精确采集模拟信号显示单元0.96寸SSD1306 OLED显示屏提供128x64像素的清晰可视化界面关键参数对比表组件工作电压接口类型关键特性Water Sensor3-5V DC模拟输出检测面积40x60mm最大水深60mmSTM32F103C8T63.3VGPIO/ADC/I2C72MHz主频12位ADC64KB FlashSSD1306 OLED3.3-5VI2C/SPI0.96寸128x64分辨率自发光1.2 硬件连接方案推荐采用I2C接口连接OLED以节省GPIO资源典型接线方式如下Water Sensor STM32F103C8T6 SSD1306 OLED VCC → 3.3V/5V → VCC GND → GND → GND AO → PA0(ADC1) PB6 → SCL PB7 → SDA提示若使用5V供电的水位传感器需确保ADC输入电压不超过STM32的3.3V限制可考虑电阻分压电路2. 开发环境搭建与基础配置2.1 工具链准备开发STM32项目通常需要以下软件工具IDE选择Keil MDK-ARM商业版STM32CubeIDE免费官方推荐PlatformIO跨平台适合VSCode用户必备驱动ST-Link/V2调试器驱动USB转串口驱动如CH340库支持STM32 HAL库或标准外设库SSD1306 OLED驱动库# PlatformIO项目配置示例platformio.ini [env:bluepill_f103c8] platform ststm32 board bluepill_f103c8 framework stm32cube upload_protocol stlink2.2 工程初始化步骤在IDE中创建新工程选择STM32F103C8Tx芯片型号配置系统时钟为72MHz8MHz外部晶振倍频启用必要的外设ADC1通道0连续转换模式I2C1标准模式100kHz生成初始化代码框架3. 传感器数据采集与处理3.1 ADC配置优化技巧STM32的12位ADC需要合理配置才能获得最佳性能// ADC初始化代码片段 void MX_ADC1_Init(void) { hadc1.Instance ADC1; hadc1.Init.ScanConvMode DISABLE; hadc1.Init.ContinuousConvMode ENABLE; hadc1.Init.DiscontinuousConvMode DISABLE; hadc1.Init.ExternalTrigConv ADC_SOFTWARE_START; hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion 1; HAL_ADC_Init(hadc1); // 配置通道0PA0的采样时间 sConfig.Channel ADC_CHANNEL_0; sConfig.Rank 1; sConfig.SamplingTime ADC_SAMPLETIME_55CYCLES5; HAL_ADC_ConfigChannel(hadc1, sConfig); }3.2 数字滤波算法实现原始ADC数据通常包含噪声需要数字滤波处理移动平均滤波采集10次数据取平均值中值滤波去除突发干扰一阶滞后滤波适合缓慢变化的水位信号#define SAMPLE_SIZE 10 float get_filtered_water_level(void) { uint32_t sum 0; uint16_t samples[SAMPLE_SIZE]; // 采集多个样本 for(int i0; iSAMPLE_SIZE; i){ HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, 10); samples[i] HAL_ADC_GetValue(hadc1); HAL_Delay(5); } // 排序并取中值 bubble_sort(samples, SAMPLE_SIZE); uint16_t median samples[SAMPLE_SIZE/2]; // 转换为实际水位mm float voltage (median * 3.3f) / 4095.0f; return (voltage / 3.3f) * 60.0f; // 假设满量程60mm对应3.3V }4. OLED界面设计与实现4.1 显示驱动集成SSD1306 OLED通常支持I2C和SPI接口推荐使用现成的驱动库// OLED初始化示例 void OLED_Init(void) { SSD1306_Init(); SSD1306_Clear(); SSD1306_SetFont(Font_7x10); // 绘制静态界面元素 SSD1306_GotoXY(10, 0); SSD1306_Puts(Water Level, Font_11x18, SSD1306_COLOR_WHITE); SSD1306_DrawLine(0, 20, 127, 20, SSD1306_COLOR_WHITE); SSD1306_GotoXY(100, 30); SSD1306_Puts(mm, Font_16x26, SSD1306_COLOR_WHITE); SSD1306_UpdateScreen(); }4.2 动态数据可视化技巧实现专业级数据显示效果的关键技术数字平滑过渡避免数值跳变水位柱状图直观显示变化趋势历史曲线记录最近N次测量值void update_water_display(float level) { static float last_level 0; char buf[16]; // 数字显示带平滑过渡 float display_level last_level (level - last_level) * 0.2; snprintf(buf, sizeof(buf), %4.1f, display_level); SSD1306_GotoXY(40, 30); SSD1306_Puts(buf, Font_16x26, SSD1306_COLOR_WHITE); // 柱状图绘制宽度对应水位 uint8_t bar_width (uint8_t)((level / 60.0f) * 120); SSD1306_DrawRectangle(4, 50, bar_width, 10, SSD1306_COLOR_WHITE, SSD1306_COLOR_WHITE); SSD1306_UpdateScreen(); last_level display_level; }5. 系统优化与扩展思路5.1 低功耗设计对于电池供电的应用场景可采取以下节能措施间歇性采样如每秒唤醒一次降低ADC采样速率OLED局部刷新代替全屏刷新进入STOP模式时关闭传感器电源void enter_low_power_mode(void) { // 关闭传感器电源 HAL_GPIO_WritePin(SENSOR_PWR_GPIO_Port, SENSOR_PWR_Pin, GPIO_PIN_RESET); // 配置唤醒源如RTC定时唤醒 HAL_RTCEx_SetWakeUpTimer_IT(hrtc, 4095, RTC_WAKEUPCLOCK_RTCCLK_DIV16); // 进入STOP模式 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); }5.2 功能扩展方向基础项目完成后可考虑以下增强功能无线传输通过ESP8266/蓝牙模块上传数据报警功能当水位超过阈值时触发蜂鸣器数据记录利用STM32内部Flash存储历史数据校准模式支持用户校准满量程和零点项目开发中常见的水位传感器异常包括导线氧化导致灵敏度下降、气泡附着影响测量精度等。定期用酒精棉清洁传感器表面并避免在导电性差异大的液体间切换使用可以显著延长传感器寿命。