资讯动态

STM32F103驱动四路MAX6675热电偶温度采集与显示系统

发布时间:2026/9/2 2:21:30 来源:尧图企业网站定制
简介基于STM32F103的四路MAX6675温度采集工程面向嵌入式学习者与开发者解决多通道K型热电偶数据采集、LCD1602实时显示与串口上传问题。工程完整既可直接烧录验证也可对照学习STM32的SPI主机配置、多从机片选切换、定时采样及UART打印等关键环节。压缩包共216个文件以c/h源码、uvprojx工程、axf/hex固件及crf/o编译中间文件为主sct链接脚本、map映射表等辅助文件齐全体积7.65MB便于排查链接与编译细节。当前已有1143人学习。内容包含标准外设库驱动、四路MAX6675共用SPI总线的采样子程序、LCD1602显示逻辑及串口输出格式配套工程可快速移植到同类多点测温项目中。通过阅读代码能掌握从硬件接线、SPI时序到人机交互与数据上送的完整开发流程适合作为STM32传感器采集类项目的参考模板。 做过多路温度采集项目的朋友应该都有体会单个传感器方案好写一旦扩展到四路、八路问题就全来了——通道之间互相干扰、SPI时序对不上、串口数据乱成一团、屏幕上显示错位。我这次把一个完整可跑的方案整理出来STM32F103 最小系统板做主机挂四路 MAX6675 模块采集热电偶温度数据同时输出到 LCD1602 显示并通过串口打印到调试助手。整个工程文件打包后命名为“STM32F103 驱动四路MAX6675 采集温度 LCD1602显示 串口打印数据.zip”正好把硬件接线、软件代码、调试方法都包含了。这篇文章把我实际调通的思路和踩过的坑原样写出来供正在做类似项目的朋友参考。这套东西适合谁刚接触 STM32 但已经会用标准库跑 GPIO、USART 的人想从单路采集往多路扩展的或者需要在设备上配一个人机交互界面但又不想上屏幕方案太复杂的都可以直接照这个思路改。我会把每一条连线、每一段关键代码、以及为什么这么写的原因都讲清楚保证你照着做能跑通。1. 项目整体思路四路温度采集系统从需求到选型1.1 需求拆解与方案选型这个项目核心要解决的事情是用一块主控芯片同时读取四路 K 型热电偶的温度值然后一路送到 LCD1602 上显示一路通过串口发送到上位机。听起来不复杂但当你真的把四个 MAX6675 挂在同一条 SPI 总线上时就会遇到一个非常实际的问题——MAX6675 不是普通 SPI 从机它没有寄存器地址每次片选拉低之后直接从 SO 引脚吐 16 位数据所以多路扩展只能靠片选去区分。选型上我没有直接上 STM32F4 或者加外部 ADC而是选择 STM32F103 四片 MAX6675原因很直接F103 的 SPI 外设完全够用72MHz 主频下跑这几个传感器绰绰有余MAX6675 自带冷端补偿和数字输出省掉了热电偶信号调理电路比用运放加 ADC 的方案简单太多。单路 MAX6675 是 0.25℃ 分辨率测 0 到 1023.75℃ 范围K 型热电偶的典型应用场景都覆盖了。有人会问为什么不用 DS18B20它便宜而且同样是单总线但测温范围只有 -55 到 125℃工业环境测个发热体、测个烤箱温度就完全无能为力了。热电偶加 MAX6675 才是这类场景的正解虽然单路成本稍高但换来的是量程和抗干扰能力。1.2 系统框架与数据流向整体数据流是这样走的四路 MAX6675 的 SO 输出线并接到同一个 GPIO 输入引脚我这里用的是软件模拟 SPI后文会讲原因SCK 共用一根引脚每路各占一根片选 CS。主控轮流拉低不同通道的 CS等一小段时间后读出 16 位数据换算成实际温度值存入一个 float 数组。然后主循环里每隔几百毫秒刷新一次 LCD1602 显示同时通过串口中断或轮询方式把格式化好的字符串发给上位机。我用的是标准外设库而不是 HAL 库因为这种老项目在很多代码仓库里都是标准库写的移植起来方便而且像 F103 这种芯片标准库的代码量更少逻辑更直观。软件模拟 SPI 而不是用硬件 SPI也是因为四路 MAX6675 共用时钟和数据线时软件控制片选更灵活不用担心硬件 SPI 从机管理带来的片选信号同步问题。实际跑下来四路全部读完一次也就几毫秒完全不影响实时性。2. 硬件设计与连接细节2.1 STM32F103 与四路 MAX6675 的接线接线是整个项目里最容易出问题的一步别急着上电先把线对清楚。我用的最小系统板是 F103C8T6MAX6675 模块是市面上最常见的红色小板上面自带 K 型热电偶插座和滤波电容。四个模块的 SO 引脚全部连接到单片机的 PB14MISO 方向SCK 全部连接到 PB13四路 CS 分别连接到 PA4、PA5、PA6、PA7。这里有个关键点四个 SO 引脚并在一起相当于开漏输出再接一个公共上拉但 MAX6675 模块的 SO 本身是推挽输出所以不需要额外上拉直接并接即可。如果你发现并接之后某一路读数不正常检查一下是不是某个模块的 CS 没有完全拉高处于半选通状态此时它会继续往总线上输出数据把其他通道的数据给干扰了。模块供电统一接 3.3V注意不要接 5V。虽然很多 MAX6675 模块上带了稳压芯片能接受 5V 输入但直接接 5V 后SO 输出高电平会达到 5V而 STM32F103 的 GPIO 并不都是 5V 容忍的PB14 如果配置成输入模式耐压有限很容易把引脚搞坏。我在这上面烧过一块芯片后来学乖了全部统一 3.3V 供电。2.2 LCD1602 显示模块的连接与电平问题LCD1602 是 5V 器件的典型代表而 STM32F103 的 GPIO 输出是 3.3V直接接逻辑电平理论上能驱动但存在两个隐患一是 3.3V 高电平对于 5V 供电的 LCD1602 来说可能达不到 VIH 阈值导致命令识别不稳定二是 LCD1602 背光电路如果直接吃 5V控制引脚电平需要串电阻限流否则长时间运行会发热。我的做法是LCD1602 供电接 5V但数据线和控制线通过 1kΩ 电阻串联后接到 STM32 引脚上实测非常稳定。RS 接 PB0EN 接 PB1D4-D7 接 PB2-PB5。用四线模式而不是八线模式省四个引脚。对比度调节引脚 V0 接一个 10kΩ 电位器中间抽头接到 V0这个电位器必须接否则屏幕上可能什么都看不到这是很多新手第一次点不亮 LCD 的最大原因不是代码问题是硬件对比度没调好。2.3 电源、地线与噪声处理四路 MAX6675 同时工作时的功耗并不大主要电流来自 LCD 背光和芯片本身但有一个坑要注意热电偶线本身是一根金属导线如果走线很长会像天线一样接收环境噪声尤其是工业现场有电机、开关电源的时候读数可能产生跳动。我的处理方式是在 MAX6675 模块的电源引脚旁边加一个 10μF 电解电容和一个 0.1μF 陶瓷电容做二级滤波。模块上本身有小电容但外加电容对长电源线的压降和纹波有明显的改善作用。另外热电偶线不要和电源线、电机驱动线绑在一起走尽量分开。如果传感器离主板很远建议用屏蔽线屏蔽层单端接地。这些经验都是从实际测试里得来的我在实验室里第一次测试时就是因为热电偶线绕过了开关电源读数一直跳后来把线重新走位后才稳定下来。3. 软件实现与核心代码解析3.1 SPI 初始化与多路片选管理软件模拟 SPI 的好处是可以随便映射引脚不受硬件外设引脚复用限制代码逻辑也直白。初始化时把 PB13 配成推挽输出PB14 配成浮空输入或上拉输入PA4-PA7 全部推挽输出并默认拉高。这里要特别强调CS 引脚默认必须拉高否则上电瞬间 MAX6675 处于未知状态可能在 SO 线上产生毛刺影响第一次读取。实际读取时先把对应通道的 CS 拉低然后延时 1-2 微秒再开始产生 16 个 SCK 上升沿。为什么要在 CS 拉低后延时因为 MAX6675 内部在 CS 下降沿后需要一小段时间准备数据如果立刻给时钟读到的前几位可能不是有效数据。很多移植失败的例子就是少了这个延时。每次读完把 CS 拉高完成一次通道切换。// 片选引脚宏定义 #define CS1_PORT GPIOA #define CS1_PIN GPIO_Pin_4 #define CS2_PORT GPIOA #define CS2_PIN GPIO_Pin_5 #define CS3_PORT GPIOA #define CS3_PIN GPIO_Pin_6 #define CS4_PORT GPIOA #define CS4_PIN GPIO_Pin_7 #define SCK_PORT GPIOB #define SCK_PIN GPIO_Pin_13 #define SO_PORT GPIOB #define SO_PIN GPIO_Pin_14 uint16_t MAX6675_Read(uint16_t cs_port, uint16_t cs_pin) { uint16_t value 0; GPIO_WriteBit(cs_port, cs_pin, Bit_RESET); delay_us(2); for (uint8_t i 0; i 16; i) { GPIO_WriteBit(SCK_PORT, SCK_PIN, Bit_SET); delay_us(1); value 1; if (GPIO_ReadInputDataBit(SO_PORT, SO_PIN)) { value | 0x0001; } GPIO_WriteBit(SCK_PORT, SCK_PIN, Bit_RESET); delay_us(1); } GPIO_WriteBit(cs_port, cs_pin, Bit_SET); return value; }3.2 MAX6675 数据读取与温度换算MAX6675 每次输出 16 位数据其中 bit15 始终为 0bit14 到 bit3 是温度数据bit2 是热电偶开路标志为 1 时表示热电偶断线或没插好。温度值的换算公式很直接把 bit14 到 bit3 这 12 位数据右移 3 位再乘以 0.25得到的就是实际温度值单位是摄氏度。举个例子读到的原始值是 0x01B4二进制是 0000 0001 1011 0100。右移 3 位得到 0x36也就是十进制 54乘以 0.25 等于 13.5℃。这个换算过程在代码里就一行但要注意数据类型的处理右移之前不能把 uint16_t 强转成 int8_t否则高位会被截断负温度场景下直接就错了。另外MAX6675 有热电偶开路检测读取完成后先判断 bit2 是否为 1如果是说明热电偶断开或者没接好这时候温度值没有意义我习惯返回一个特殊值比如 -1000表示异常状态方便上位机显示报警。别忽略这个位它能帮你快速定位是传感器问题还是程序问题。float MAX6675_GetTemp(uint16_t cs_port, uint16_t cs_pin) { uint16_t raw MAX6675_Read(cs_port, cs_pin); if (raw 0x0004) // 热电偶开路检测位 { return -1000.0f; } return (float)(raw 3) * 0.25f; }实际使用时四个通道轮流读取每次读取间隔建议至少 200 毫秒。因为 MAX6675 内部完成一次温度转换大约需要 170-220 毫秒如果连续快速读取读到的可能是上一次的旧数据或者转换中间的不稳定数据。我最初为了刷新率把读取间隔压到 50 毫秒结果四路数据轮流跳变后来在循环里加了一个 250 毫秒的延时数据就非常稳定了。3.3 LCD1602 显示与串口打印LCD1602 的驱动代码网上很多但我这儿要提醒几个容易忽略的细节。初始化时4 位模式必须按数据手册规定的时序来先发 0x03 三次再发 0x02 切换到 4 位模式然后才是功能设置、显示开关、清屏等命令。很多人直接套用网上代码结果因为时序问题导致显示乱码问题就出在初始化阶段。显示逻辑上我用的是比较简单的方式把四路温度分别格式化到两行显示第一行显示 CH1 和 CH2第二行显示 CH3 和 CH4。每行可以显示 16 个字符四路温度加标识符绰绰有余。显示温度时要处理异常值如果返回值是 -1000就显示 ERR 而不是一个怪异的数字。串口部分我用的 USART1PA9 做 TXPA10 做 RX波特率 1152008 位数据位1 位停止位无校验。调试助手用常见的串口助手软件就行注意 CH340 驱动要先装好设备管理器里能看到 COM 口才能连上。打印格式我是这样组织的printf(CH1: %.2f C CH2: %.2f C\r\n, temp[0], temp[1]); printf(CH3: %.2f C CH4: %.2f C\r\n, temp[2], temp[3]);记得在工程里重定向 fputc 函数到串口发送不然 printf 输出到不了串口int fputc(int ch, FILE *f) { USART_SendData(USART1, (uint8_t)ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); return ch; }4. 调试过程与常见问题排查4.1 温度读数异常问题我调试过程中遇到的最典型问题是某一通道读数始终是 0℃ 或者固定跳到某个数值。这种情况九成是热电偶插反或者接触不良。MAX6675 模块上的热电偶插座是有极性的K 型热电偶的红色线一般接正极黄色线接负极插反了温度显示会异常。还有一次是热电偶插头氧化导致接触电阻变大读数持续跳动。另外一类问题是所有通道都读到同一个值而且这个值不变化。这多半是片选引脚配置问题比如四路 CS 全部被拉低了SO 总线同时被多个芯片驱动读出来的数据是拼凑的乱码。排查方法很简单用万用表量 CS 引脚电平确认只有当前通道是低电平。4.2 LCD1602 不显示或显示乱码LCD1602 不显示先查三件事对比度电位器调了没有、背光正不正常、电源是不是 5V。我见过太多人在这上面折腾半天结果就是 V0 没接电位器或者电位器旋到了最暗的位置。对比度调节的标准方法是慢慢旋转电位器直到屏幕上出现一排黑色方块。显示乱码的原因大多是初始化时序不对。我的经验是每次写命令或数据之间至少延时 1-2 毫秒特别是清屏命令需要更长的延时。如果 4 位模式下 D4-D7 接反了或者 RS、EN 接错也会出现乱码。检查方法是用示波器看 EN 引脚确认每次写入时 EN 有下降沿。4.3 串口打印数据异常串口打印出来是乱码优先级最高的是波特率配置。检查 USART 初始化时 BRR 寄存器计算是否正确尤其是外部晶振频率和你代码里写的 HSE_VALUE 是否一致。我用的是 8MHz 外部晶振如果代码误配成 12MHz波特率就会偏得离谱上位机收到全是乱码。其次检查 USB 转 TTL 模块的 TX、RX 有没有接反。STM32 的 TX 要接模块的 RXSTM32 的 RX 接模块的 TX交叉连接这是新手最容易犯的错误。4.4 多路采集相互干扰的处理四路同时采集时如果发现某一路读数会轻微影响其他路多半是读取切换时产生的电气干扰。我的解决方法是每读完一路后将 CS 拉高然后延时 5 毫秒再操作下一路让 SO 总线上的电平有一个稳定的过程。如果还不行检查四路模块是否共地如果共地点接触不良也会产生压差干扰。还有一种情况是热电偶引线过长感应到工频干扰。可以把采样值做一次简单的滑动平均滤波比如连续读五次去掉最大最小值再取平均虽然 MAX6675 本身已经有数字滤波但工程环境下加上软件滤波会明显提高稳定性。一点实际体会最后再说一个我在测试时发现的细节MAX6675 手册上写的转换时间可能因模块设计和供电电压不同而略有变化。我实际测试时四路通道在 3.3V 供电下200 毫秒的间隔稳定可靠但如果我把电压降到 3.1V 以下读数偶尔会出现跳变说明模块在低压边缘工作不稳定。如果你的系统供电电压有波动建议在程序里检测 MAX6675 的异常值位同时电源部分多留点余量。这个项目整体调试下来最难的不是代码而是硬件细节和耐心排查希望这份经验能帮你少走弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价