STM32软硬件SPI驱动MAX31865实现PT100高精度测温与Shell交互

📅 2026/7/8 16:06:25 👁️ 阅读次数 📝 编程学习
STM32软硬件SPI驱动MAX31865实现PT100高精度测温与Shell交互

1. PT100测温与MAX31865模块基础

PT100铂电阻作为工业测温的常青树,其原理就像体温计里的水银柱——温度变化时电阻值会线性改变。但要把这微小的电阻变化(0.385Ω/℃)转换成精确温度读数,MAX31865就像个专业翻译官,把电阻信号"翻译"成数字信号。实测下来,这个芯片在-200℃~+850℃范围内能实现±0.5℃的精度,比普通DS18B20强不少。

硬件连接其实比想象中简单,模块的典型接线就像搭积木:

  • VIN接3.3V(注意别超3.6V)
  • GND接地
  • SCK/CS/MOSI/MISO对应STM32的SPI引脚
  • RTD+和RTD-接PT100的两根线(注意2/3/4线制区别)

我推荐直接用现成模块,自己画PCB容易在参考电阻精度和走线抗干扰上踩坑。有个细节要注意:模块上的RREF参考电阻(通常430Ω)决定了量程,换成400Ω能提升低温段分辨率。

2. 软件模拟SPI的实战实现

当硬件SPI被占用或需要快速验证时,软件模拟SPI就像瑞士军刀——灵活但效率低。我用STM32F103实测,模拟SPI的时钟最快只能到500kHz左右,而硬件SPI轻松上8MHz。

初始化GPIO是关键第一步:

void MAX31865_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // 配置CS/SCK/SDI为推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_9 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOC, &GPIO_InitStructure); // 配置SDO/DRDY为上拉输入 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_13; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(GPIOC, &GPIO_InitStructure); MAX31865_CS_SET; // 初始置高CS }

读写时序要注意的坑:

  1. 写操作时先发地址字节(最高位置1),再发数据字节
  2. 读操作时先发地址字节(最高位清0),再读数据
  3. 每个字节传输都要从高位开始(MSB first)
  4. 时钟上升沿采样数据

温度换算有个技巧:直接套用Callendar-Van Dusen公式计算正温度,负温度段用多项式拟合更高效:

float MAX31865_GetTemp(void) { uint16_t data = (MAX31865_Read(0x01) << 8) | MAX31865_Read(0x02); data >>= 1; // 丢弃错误标志位 float Rt = (float)data / 32768.0 * RREF; // 正温度计算 float temp = (-3.9083e-3 + sqrt(9.304e-6 + 1.6e-5 * (Rt/100 - 1))) / (2 * -5.775e-7); if(temp >= 0) return temp; // 负温度拟合 return -242.02 + 2.2228*Rt + 2.5859e-3*Rt*Rt - 4.8260e-6*Rt*Rt*Rt; }

3. 硬件SPI的高效驱动

硬件SPI就像开了高速公路,配置时这几个参数最容易出错:

SPI_InitTypeDef SPI_InitStructure; SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; SPI_InitStructure.SPI_Mode = SPI_Mode_Master; SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // MAX31865要求CPOL=1 SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // 第2边沿采样 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // 软件控制CS SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; // 9MHz@72MHz SPI_Init(SPI1, &SPI_InitStructure);

硬件SPI的读写函数要处理超时,避免死等:

uint8_t SPI_WriteByte(uint8_t data) { uint32_t timeout = 100000; while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) && timeout--); SPI_I2S_SendData(SPI1, data); timeout = 100000; while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) && timeout--); return SPI_I2S_ReceiveData(SPI1); }

实测对比数据:

指标软件SPI硬件SPI
最大时钟频率500kHz8MHz
CPU占用率85%<5%
代码体积1.2KB0.8KB
抗干扰能力较弱

4. Shell交互的实用技巧

给测温系统加上Shell就像装了个控制台,调试时不用反复烧录。我用串口实现基础命令:

  • temp:立即读取当前温度
  • config [bias] [filter]:配置偏置电压和滤波器
  • fault:读取故障状态

实现框架建议用状态机解析:

void Shell_Process(void) { if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) { char ch = USART_ReceiveData(USART1); if(ch == '\r') { if(strcmp(cmd_buf, "temp") == 0) { float temp = MAX31865_GetTemp(); printf("Current temp: %.2fC\r\n", temp); } memset(cmd_buf, 0, sizeof(cmd_buf)); cmd_idx = 0; } else { cmd_buf[cmd_idx++] = ch; } } }

提升Shell体验的三个技巧:

  1. 添加Tab键命令补全
  2. 实现命令历史记录(上下键调取)
  3. 加入ANSI转义序列实现彩色输出

我在实际项目中发现,用硬件SPI+Shell组合后,调试效率提升至少3倍。特别是批量测试时,直接通过串口命令自动化采集数据,不用再连接调试器。