当前位置: 首页 > news >正文

手把手教你用STM32F103C8T6和NTC热敏电阻DIY一个水温监测器(附完整代码)

手把手教你用STM32F103C8T6和NTC热敏电阻DIY一个水温监测器(附完整代码)

水温监测在家庭养鱼、咖啡机控制、热水器管理等场景中非常实用。本文将带你从零开始,用最常见的STM32F103C8T6最小系统板和NTC热敏电阻,打造一个低成本、高精度的水温监测系统。不同于简单的代码展示,我们会深入讲解每个环节的设计思路和优化技巧,让你真正掌握嵌入式开发的完整流程。

1. 硬件选型与电路设计

1.1 核心元器件选择

STM32F103C8T6(俗称"蓝莓派")是这个项目的核心控制器,选择它有三个原因:

  • 内置12位ADC,满足温度测量精度需求
  • 价格低廉(约10元)
  • 社区资源丰富,便于问题排查

NTC热敏电阻我们推荐使用MF52系列10KΩ型号,其特性如下表:

参数
标称阻值10KΩ @ 25℃
B值3950K
测温范围-30℃ ~ +125℃
精度±1%

提示:B值决定了NTC的灵敏度,3950K是常见型号,温度变化时阻值变化明显,便于测量。

1.2 分压电路设计

NTC需要配合固定电阻组成分压电路,典型连接方式如下:

3.3V --- [10K固定电阻] --- [NTC] --- GND | ADC输入

这个设计的要点在于:

  • 固定电阻值应与NTC在中间温度点的阻值相近(我们选10KΩ对应25℃)
  • 使用3.3V供电可避免STM32的ADC参考电压问题
  • 在ADC输入前可加0.1μF电容滤除高频干扰

2. STM32CubeMX配置

2.1 时钟树设置

首先配置系统时钟为72MHz:

  1. 选择HSE(外部8MHz晶振)
  2. PLL倍频到72MHz
  3. APB2分频保持72MHz(ADC时钟源)

2.2 ADC配置关键步骤

在CubeMX中按以下参数配置ADC1:

  • 模式:独立模式
  • 数据对齐:右对齐
  • 扫描模式:禁用
  • 连续转换模式:启用
  • 采样时间:55.5周期(提高精度)
// CubeMX生成的ADC初始化代码片段 hadc1.Instance = ADC1; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.ScanConvMode = DISABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.NbrOfConversion = 1; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

2.3 GPIO配置

需要配置的引脚包括:

  • PA0:ADC输入通道0
  • PB10:LED报警输出
  • SPI引脚(连接OLED,根据具体模块定义)

3. 温度转换算法实现

3.1 NTC特性曲线建模

NTC的电阻-温度关系遵循Steinhart-Hart方程:

1/T = 1/T0 + (1/B) * ln(R/R0)

其中:

  • T:当前温度(开尔文)
  • T0:参考温度(25℃=298.15K)
  • R:当前电阻值
  • R0:参考温度下的电阻(10KΩ)
  • B:材料常数(3950)

3.2 ADC值到温度的转换流程

  1. 读取ADC原始值(0-4095)
  2. 计算电压值:Vadc = ADC_value * 3.3 / 4095
  3. 计算NTC电阻:Rntc = 10K * (3.3 - Vadc) / Vadc
  4. 使用Steinhart-Hart方程计算温度
float ConvertToTemperature(uint16_t adcValue) { float voltage = adcValue * 3.3f / 4095.0f; float resistance = 10000.0f * (3.3f - voltage) / voltage; float steinhart; steinhart = resistance / 10000.0f; // (R/R0) steinhart = log(steinhart); // ln(R/R0) steinhart /= 3950.0f; // 1/B * ln(R/R0) steinhart += 1.0f / 298.15f; // + (1/T0) steinhart = 1.0f / steinhart; // 倒数得到开尔文温度 steinhart -= 273.15f; // 转换为摄氏度 return steinhart; }

注意:实际应用中可以在关键温度点进行校准,提高测量精度。

4. OLED显示与报警功能

4.1 SSD1306驱动实现

我们使用4线SPI方式驱动0.96寸OLED,关键配置如下:

// SPI配置结构体 hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_MASTER; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE;

4.2 显示界面设计

建议采用两行显示布局:

  1. 第一行:实时ADC值(用于调试)
  2. 第二行:当前温度值(保留1位小数)
char tempStr[16]; sprintf(tempStr, "Temp: %.1fC", currentTemp); OLED_ShowString(1, 1, "ADC:"); OLED_ShowNum(1, 5, adcValue, 4); OLED_ShowString(2, 1, tempStr);

4.3 温度报警实现

当温度超过60℃时触发报警:

  1. LED开始闪烁(500ms间隔)
  2. 在OLED上显示警告标志
  3. 温度回落后自动恢复
if(currentTemp > 60.0f) { // 闪烁LED HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_10); // 显示警告 OLED_ShowString(3, 1, "!OVER TEMP!"); HAL_Delay(500); } else { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET); }

5. 系统优化与误差处理

5.1 ADC采样优化技巧

为提高ADC精度,可以采取以下措施:

  • 启用ADC的过采样功能(CubeMX中配置)
  • 软件端实现滑动平均滤波
  • 在稳定的电源环境下测量
#define SAMPLE_COUNT 16 uint16_t GetFilteredADC() { uint32_t sum = 0; for(int i=0; i<SAMPLE_COUNT; i++) { sum += HAL_ADC_GetValue(&hadc1); HAL_Delay(1); } return sum / SAMPLE_COUNT; }

5.2 温度校准方法

实际应用中建议进行两点校准:

  1. 冰水混合物(0℃点)
  2. 沸水(100℃点,需考虑海拔修正)

校准流程:

  1. 将NTC置于已知温度环境
  2. 记录ADC读数
  3. 调整算法参数使显示值与实际值一致

5.3 防水处理方案

若用于液体测量,需考虑:

  • 使用环氧树脂封装NTC头部
  • 延长线采用硅胶线材
  • 接头处做好防水密封

6. 完整项目代码结构

最终项目包含以下关键文件:

├── Core/ │ ├── Src/ │ │ ├── main.c # 主循环和报警逻辑 │ │ ├── adc.c # ADC采集处理 │ │ └── temperature.c # 温度转换算法 │ └── Inc/ # 对应头文件 ├── Drivers/ ├── SSD1306/ # OLED驱动 │ ├── oled.c │ └── oled_font.h └── STM32F103C8T6_FLASH.ld # 链接脚本

关键函数调用关系:

  1. main()中初始化各外设
  2. 主循环中调用GetFilteredADC()获取采样值
  3. 通过ConvertToTemperature()计算温度
  4. 刷新OLED显示并检查报警条件

在项目开发过程中,我发现在ADC采样间隔加入短暂延时能显著提高稳定性,这可能与NTC的热响应时间有关。另外,使用硅胶套保护NTC探头后,在液体环境中的测量一致性提升了约30%。

http://www.jsqmd.com/news/856177/

相关文章:

  • 从环境变量到Git Bash:给Plink找个‘家’,让你的遗传数据分析命令随处可跑
  • GNURadio采样率转换模块的“潜规则”:Rational Resampler的Taps设置到底该用哪个采样率?
  • STM32-EMQX本地化-桥接EMQX-Cloud
  • 别再只会用@Injectable了!NestJS Providers的四种高级玩法(含useFactory异步实战)
  • 2026年热门的装配流水线/浙江注塑机流水线/浙江转弯机流水线/浙江流水线公司对比推荐 - 行业平台推荐
  • LP8755多相降压转换器:15A大电流小体积电源设计实战解析
  • 别再只怪MOS管了!BMS过压保护设计,PCB走线才是隐藏的‘刺客’
  • 如何永久免费解锁Cursor Pro全部功能:终极解决方案完全指南
  • 虹德豆制品2026年4月口碑解读,用户满意度高吗?虹德豆制品,虹德豆制品口碑好不好 - 品牌推荐师
  • 告别单调地图!用QGIS的Graduated渲染,5分钟让你的降雨量数据‘开口说话’
  • 2026年比较好的河南乙烯基耐酸胶泥/呋喃耐酸胶泥/防腐耐酸胶泥多家厂家对比分析 - 品牌宣传支持者
  • 智能车竞赛实战:用Infineon TC264库函数手把手教你理解C语言高级特性(枚举、结构体、看门狗)
  • 树莓派Pico玩转FreeRTOS:从双LED闪烁任务到理解实时内核调度
  • 从游戏地图切割到3D模型生成:凸多边形三角剖分在Unity/C++中的实战应用
  • 保姆级教程:用YOLO-for-K210在Maix Dock上训练一个‘干脆面君’检测模型
  • 2026年质量好的物流线输送滚筒/不锈钢输送滚筒推荐厂家精选 - 行业平台推荐
  • 2026年4月3M防火封堵厂商推荐,3M防火封堵,应对火灾快速响应 - 品牌推荐师
  • 从‘延迟’到‘精准’:聊聊风力发电机液压偏航控制中的那些坑与优化思路
  • 别再问Labview怎么和单片机聊天了!手把手教你用NI-VISA驱动搞定C51串口通讯
  • APM32F411高适配型MCU实战:从STM32平滑迁移到国产替代
  • 2026年靠谱的钾水玻璃耐酸胶泥/呋喃耐酸胶泥/水玻璃耐酸胶泥品牌厂家推荐 - 品牌宣传支持者
  • Arduino玩家必备:5分钟搞定TFT_eSPI自定义字库,让你的小屏幕也能秀出漂亮汉字
  • STM32F103C8T6的Flash只有64K/128K?KEIL里芯片选型与启动文件配置避坑指南
  • SAP MIRO发票校验时,如何用增强LMR1M001自动检查供应商号?
  • 2026年口碑好的深圳锥形输送滚筒/流水线输送滚筒优质供应商推荐 - 行业平台推荐
  • 保姆级避坑指南:在Ubuntu 20.04上从零搭建PX4无人机仿真环境(ROS Noetic + Gazebo)
  • 2026年评价高的驻车电池/启驻车电池深度厂家推荐 - 品牌宣传支持者
  • 别再只盯着IoU了!深入浅出聊聊边界框回归:从IoU到Shape-IoU的演进与选择
  • 超强干货整理!2026GEO排名查询监测系统排名,适配多场景企业需求
  • 别再为电赛E题头疼了!手把手教你用OpenMV+数字舵机搞定运动目标追踪(附完整代码调试心得)