
简介面向STM32初学者的MAX6675测温例程包基于STM32F103与K型热电偶测温芯片演示SPI接口驱动、冷端补偿、温度解析等完整流程。资源共96个文件其中包含39个头文件、38个C源文件以及启动文件、Keil工程配置、hex烧录文件和readme说明整体仅308KB目录按Board、User、Libraries分层组织便于快速定位并导入Keil工程学习。已有3899人学习浏览。例程完整呈现SPI时钟参数与GPIO配置方法给出温度数据读取、符号判断和0.5°C分辨率换算的具体实现同时涵盖中断时序管理及扩展串口上传思路可直接移植到热电偶测温、工业温度监控等场景。 最近整理手上的STM32小项目时我把MAX6675驱动K型热电偶的测试例程重新写了一遍。这模块网上例程不少但真正能一次跑通的并不多问题基本都出在SPI时序、数据格式以及最容易被忽略的热电偶接线和供电纹波上。这篇博文不是我随手贴代码而是一套实测通过的完整方案从硬件接线、驱动代码到调试排查都覆盖了适合做温度采集、烤箱温控、工业设备监测这类项目的朋友参考。内容不挑具体型号F103、F407甚至G0系列都能用软件部分我给HAL库版本和软件模拟SPI版本你可以按自己的工程环境直接抄作业。1. 项目概述与核心思路1.1 为什么选MAX6675 K型热电偶做温度采集时很多人第一反应是DS18B20或者NTC热敏电阻。这两者确实简单但测温范围都有限NTC超过200℃基本就报废了DS18B20标称上限也就125℃。如果你要测烤箱内部温度、发动机排气管温度或者做工业设备的过热保护最常用的是一两百块钱一根的K型热电偶测温范围能干到-200℃~1300℃左右响应速度也快。但K型热电偶有个麻烦它输出的是微伏级别的热电动势而且热电偶的电压和温度是非线性关系再加上需要冷端补偿直接用单片机ADC采集几乎没法用。MAX6675就是专门干这个事的芯片内部集成了冷端补偿、信号放大和ADC转换直接输出12位数字信号把“模拟前端”的所有脏活累活全包了单片机通过SPI读两个字节就能拿到温度。这方案在工业测温里非常成熟成本低外围电路简单一个模块几块钱就能买到。1.2 整体方案与选型考量这套测试例程的硬件组成很简单STM32最小系统板一块、MAX6675模块一个、K型热电偶一支再加上一个串口模块用于打印温度。核心目标是验证驱动代码能稳定读到温度所以不需要屏幕、不需要上位机串口打印就够。软件层面我建议优先用标准外设库或者HAL库因为Max6675本身是SPI从机STM32的SPI外设足够应付。代码我写了两个版本硬件SPI版和模拟SPI版。硬件SPI版适合正式项目模拟SPI版适合你第一次调这个芯片时用来理解时序。我实际测试时也是先跑模拟SPI确认芯片和接线没问题了再切到硬件SPI这样出问题容易定位。2. 硬件设计与接线细节2.1 MAX6675模块引脚与芯片特性市面上常见的MAX6675模块基本都是8引脚或者5引脚的接口端子引脚定义很统一VCC、GND、SCK、CS、SO。需要注意MAX6675是单向输出只有SOSerial Output没有SI。所以模块上的接线端子一般就是五个少部分模块会多一个NC或SDA不管它就行。芯片工作电压范围是3.0V~5.5V直接给3.3V就能正常工作逻辑电平也是3.3V和STM32直连没有任何电平转换问题。这也是我推荐用3.3V供电的原因省事不会出现5V模块输出高电平把STM32引脚打坏的情况。如果你手上的模块明确标注需要5V供电那先确认一下STM32引脚是否兼容5V容忍F1系列大部分可以F4系列部分引脚不行别盲接。2.2 接线方式与SPI引脚映射以STM32F103C8T6为例我用的SPI1引脚SCK接PA5MISO接PA6CS接普通GPIO——PA4或PB12都行。这里有个关键点CS片选不要用硬件SPI的NSS引脚直接用普通GPIO手动拉低拉高最省心因为MAX6675每次读取都是16个时钟周期读取结束就要拉高CS手动控制逻辑特别清晰不容易踩NSS模式的坑。接线表如下MAX6675引脚STM32引脚说明VCC3.3V推荐3.3V供电GNDGND共地SCKPA5 (SPI1_SCK)时钟SOPA6 (SPI1_MISO)数据输出CSPB12 (普通GPIO)片选手动控制如果你是模拟SPI方案那SCK和SO可以任意接两个GPIO比如PA5和PA6CS也随意。反正模拟就是靠代码去模拟时序引脚自由度很高。2.3 供电去耦与PCB布局建议MAX6675模块虽然集成了大部分电路但使用中有一个容易被忽略的点冷端补偿精度受芯片自身温度影响。MAX6675的冷端补偿参考点就是芯片本身的引脚温度如果芯片周围有发热元件比如大功率MOS管、线性稳压器特别是7805这类测出来的温度就会有明显偏差。我实测过一次把MAX6675放在一个12V转5V的LDO旁边不到1cm处沸水测试整体偏高了6℃左右挪远之后误差立刻恢复正常。所以布线时尽量让MAX6675远离热源。如果自己画PCB芯片底下建议铺一块独立的地铜皮电源引脚加100nF和10uF去耦电容。热电偶的两根引线应该双绞到一起尽量减少磁场干扰延长线也不要和电机线、继电器线捆在一起走否则读数会跳得让你怀疑人生。3. 软件驱动原理与代码实现3.1 SPI时序与16位数据格式MAX6675的SPI时序是标准SPI Mode 0CPOL0CPHA0时钟空闲为低电平数据在上升沿采样MSB先出最高支持4.2MHz左右。主机在CS拉低后连续发送16个时钟周期从SO引脚读回16位数据。这16位数据的格式很有讲究新手经常在这里栽跟头。数据手册写得比较乱我直接给你整理成表格位名称含义D15伪位恒为0忽略D14 ~ D3温度数据12位二进制每一位代表0.25℃D2热电偶开路标志为1表示热电偶断开或输入超出范围D1设备ID位恒为0D0状态位恒为0所以读取到完整的16位原始值raw之后温度计算方法是float temperature (raw 3) * 0.25;raw右移3位后剩下12位温度数据乘以0.25就是实际摄氏温度。比如raw 0x0A40右移3位得到0x148即328乘以0.25就是82℃。需要注意的是热电偶开路标志位D2如果K型热电偶没有接好、断了、或者极性接反导致信号异常D2往往会被置1。更极端的情况是读出的raw直接是0xFFF这时候基本可以认定热电偶没有接入先别急着怀疑芯片拿万用表量一下热电偶两端的电阻正常常温下应该是几欧到几十欧。3.2 模拟SPI驱动代码排查利器我建议所有第一次用MAX6675的朋友先花两分钟把模拟SPI版本跑通。它的好处是每个时钟周期、每个引脚状态你都能一目了然哪一步出了问题逻辑分析仪都不用接看代码和串口打印就能推断出来。下面是我实测通过的代码#include stm32f1xx_hal.h // 根据自己芯片型号调整头文件 #define MAX6675_SCK_PORT GPIOA #define MAX6675_SCK_PIN GPIO_PIN_5 #define MAX6675_SO_PORT GPIOA #define MAX6675_SO_PIN GPIO_PIN_6 #define MAX6675_CS_PORT GPIOB #define MAX6675_CS_PIN GPIO_PIN_12 void MAX6675_Init(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitStruct.Pin MAX6675_SCK_PIN | MAX6675_CS_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(MAX6675_SCK_PORT, GPIO_InitStruct); HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(MAX6675_SCK_PORT, MAX6675_SCK_PIN, GPIO_PIN_RESET); GPIO_InitStruct.Pin MAX6675_SO_PIN; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_PULLDOWN; HAL_GPIO_Init(MAX6675_SO_PORT, GPIO_InitStruct); } uint16_t MAX6675_ReadRaw(void) { uint16_t raw 0; int i 0; HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_RESET); delay_us(1); for (i 0; i 16; i) { raw 1; HAL_GPIO_WritePin(MAX6675_SCK_PORT, MAX6675_SCK_PIN, GPIO_PIN_SET); delay_us(1); if (HAL_GPIO_ReadPin(MAX6675_SO_PORT, MAX6675_SO_PIN) GPIO_PIN_SET) { raw | 0x0001; } HAL_GPIO_WritePin(MAX6675_SCK_PORT, MAX6675_SCK_PIN, GPIO_PIN_RESET); delay_us(1); } HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_SET); return raw; } int8_t MAX6675_ReadTemp(float *temp) { uint16_t raw MAX6675_ReadRaw(); if (raw 0x0004) // D2位为1热电偶开路 { return -1; } *temp (raw 3) * 0.25f; return 0; }这里有几个细节要认真说。第一SO引脚的上下拉我用了下拉电阻为的是防止在SCK为低电平期间SO引脚浮空导致误读。不过MAX6675的SO在芯片内部有驱动其实不加上下拉也能读但加上会更稳尤其是模块和单片机距离比较远线缆长的时候。第二每次SCK拉高后、拉低前读数据——这是和MAX6675的时序匹配的实测稳定。第三CS拉低后要稍微延时一下给芯片一点响应时间我这边延时1us就够了如果你用的是慢速MCU建议延时拉到3~5us。3.3 硬件SPI版本HAL库实例模拟SPI跑通之后再切到硬件SPI就非常快了。CubeMX里配置SPI1Mode选择Full-Duplex Master硬件NSS不使能参数如下Baud Rate Prescaler选择分频后时钟频率在2MHz左右比如72MHz主频下选Prescaler 64得到1.125MHz稳妥Clock Polarity (CPOL)LowClock Phase (CPHA)1 EdgeData Size8 bitFirst BitMSB First读取温度时CS由GPIO控制SPI接收使用8位模式连续读两个字节拼成16位数据。注意不要直接用16位模式接收因为字节序问题很容易搞反8位读两字节最直观uint16_t MAX6675_HW_ReadRaw(void) { uint8_t buf[2]; uint16_t raw 0; HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_RESET); HAL_SPI_Receive(hspi1, buf, 2, 100); HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_SET); raw ((uint16_t)buf[0] 8) | buf[1]; return raw; }这段代码看起来简单但有一个地方容易出错HAL_SPI_Receive不是只接收它也要对外发送时钟所以SCK线上一定有脉冲这是正常的。另外CS拉低到首个SCK上升沿之间芯片需要一点建立时间HAL_SPI_Receive内部已经处理了这个过程但如果你发现偶尔读到的第一个字节不对可以试试在CS拉低后加一个1us延时问题基本就消失了。3.4 数据稳定与滤波处理MAX6675的ADC转换时间大约是220ms也就是说每次读到的数据其实是大约0.22秒前的采样结果所以读取间隔不要太短。我一般是500ms读一次。这还不够实际测量过程中工业环境下的工频干扰、继电器通断、电源纹波都会导致读数轻微跳动。我常用的滤波方式是连续读5次排序取中值再把中值结果做一阶低通。效果很明显可以把±0.5℃的随机跳动压到±0.25℃以内。一阶低通的递推公式很简单filtered filtered * 0.8f current * 0.2f;初次上电时把filtered初始化为第一次读到的温度值就行。注意这个低通系数在你读得越频繁时越要调小否则滞后太严重温度突变时要好几秒才能跟上。4. 实操调试与问题排查实录4.1 常见问题速查表我在调试这套例程时把群里朋友遇到的各种情况汇总了一下整理成一张速查表按现象找原因特别方便现象可能原因解决办法读回数据一直是0x0000CS没有正常拉低、SCK时钟没输出、SO接错引脚查GPIO配置用示波器或万用表量引脚电平读回数据是0xFFFF或0xFFF热电偶断路、探针没插到底、极性接反万用表量热电偶电阻重新插拔或更换热电偶温度值和实际明显不符冷端补偿受影响、芯片周围热源、供电纹波大远离热源加强电源滤波重新校准温度数值跳动超过±1℃热电偶线受电磁干扰、接触不良、采样太频繁双绞线走线、降低采样频率、软件滤波K型热电偶接反后温度仍然显示读取的数据解析错误、D2位误判检查数据位解析确认接线正负极下载程序时提示no stm32 target found调试器连接问题、BOOT0跳线问题检查ST-Link接线按住复位键再下载或用ST-LINK Utility连接确认4.2 温度数据跳动的排查思路如果温度数据一直在跳先别急着加软件滤波那只能掩盖问题不能解决问题。我的排查顺序是这样的第一步把热电偶从模块上拔下来用一个短接跳线帽把输入端短接此时读到的温度应该接近环境温度且非常稳定。如果短接之后数值还在跳问题在模块供电、SPI读取或单片机端如果短接后稳定了那干扰源在热电偶线路上。第二步检查供电。用示波器看模块VCC引脚的纹波如果纹波超过50mV就在模块电源引脚附近加一个100uF电解电容和一个100nF陶瓷电容。我遇到过几次跳动问题都是电源导致的单独给模块用一颗AMS1117-3.3供电之后问题直接消失。第三步检查热电偶走线。K型热电偶输出的是微弱信号延长线如果和220V电源线、继电器控制线走在同一个线槽里感应出来的噪声随便就能让MAX6675读数乱跳。把热电偶线单独走并且双绞起来效果立竿见影。4.3 读数异常与热电偶开路判断如果读到的数据一直是0xFFF同时D2位为1说明芯片检测到了热电偶开路。但很多新手不知道的是热电偶没有完全断开、只是接触电阻变大时也会触发开路标志。比如K型热电偶探针断断续续、端子氧化、或者用了劣质延长线都会间歇性出现0xFFF。我建议在代码里对开路标志做一个去抖处理连续读到5次开路标志才判定为热电偶故障避免偶发抖动就报错。另外如果程序初始化阶段热电偶还没有插好也要做一次初始化检查避免上电瞬间的误报被记录下来。还有一个容易忽略的情况K型热电偶正负极接反时显示的温度不是直接报错而是会往下走。比如你把探针放在热水中温度会反向跳动甚至显示负值或者表现成开路。遇到这种情况先检查红色线和黄色线不同厂家的线色有差异最好看标签确认分别接在模块的哪个端子上记住K型热电偶的正极是镍铬合金负极是镍硅模块端子一般标有和-。5. 精度校准与工程经验5.1 两点校准法实战MAX6675出厂精度本身是±2℃最大值加上冷端补偿误差实际系统误差往往会到±3℃~±5℃。如果你的项目要求误差在±1℃以内必须做校准。MAX6675内部没有校准寄存器所以校准是通过代码里的增益和偏置修正完成的公式很简单real_temp read_temp * gain offset;两点校准的基本方法准备0℃冰水混合物和100℃沸水。理论上冰水混合物是0℃沸水在标准大气压下是100℃但要注意海拔海拔每升高300米沸点大约下降1℃所以有条件的话用高精度水银温度计或者工业铂电阻温度计作为参考更准确。实操流程把热电偶探针放进冰水混合物中等读数稳定后记下值T0再放沸水里稳定后记下值T100。然后根据以下公式计算gain (100 - 0) / (T100 - T0)offset 100 - T100 * gain将计算出的gain和offset代入代码再测一次冰水和沸水验证误差能轻松压到±0.5℃。如果只校准零点也可以只做偏移修正但高温段误差可能仍然偏大所以条件允许尽量做两点校准。5.2 几个容易被忽略的工程细节最后分享几个我踩过坑之后才意识到的问题这些细节在数据手册里也有但往往不会有人专门告诉你。第一MAX6675上电后需要大约1秒才能稳定输出正常温度值。有些同学上电立刻读温度发现读出来是0℃或者一个大得离谱的值以为是程序问题。实际上芯片内部有个上电复位过程读取前最好等1~2秒或者丢弃前几次读取结果。第二不要和发热器件共用3.3V稳压器。MAX6675的冷端补偿参考点就是芯片引脚如果给它供电的LDO本身发热严重热量直接传导到芯片上冷端补偿就会出现系统性偏差而且在环境温度变化时误差会跟着漂移。我给模块单独供电之后整体稳定性提升非常明显。第三长期高温环境下热电偶本身会老化。K型热电偶在400℃以上长时间使用后材料会逐渐氧化输出电动势发生漂移表现为读数越来越不准。工业项目建议定期校准或者直接把热电偶作为易耗品定期更换。第四如果SPI总线上还挂了其他从设备注意在片选切换时留一点空闲时间避免MCU在切换时间段内给MAX6675发出残余时钟信号导致读到的数据错位。这个问题的典型表现是单独读MAX6675正常和其他传感器轮询读取时偶尔出现一个离谱温度值。这套例程我已经在F103和F407上都跑过模拟SPI和硬件SPI两种方式都验证过了。MAX6675本身不复杂架构就是“热电偶 → 芯片调理 → SPI输出”读懂时序和数据结构剩下的就是细心排查接线。如果你按照上面的步骤走一遍还是读不到正常温度回头先查供电和热电偶线缆这两项占了故障原因的八成。最后再提醒一句用硬件SPI时优先选择8位模式读两字节别为了省代码量直接干16位读字节序的坑踩过的人太多了。本文还有配套的精品资源点击获取