基于STM32、HAL库的MAX31865模数转换器ADC驱动程序设计
一、简介:
MAX31865是一款高精度的电阻温度检测器(RTD)至数字转换器,适用于铂电阻温度传感器(如PT100、PT1000等)。它具有以下特点:
-
支持2线、3线或4线RTD连接
-
15位ADC分辨率
-
可编程数字滤波器
-
内置RTD开路、短路检测
-
SPI接口通信
-
工作电压:3.0V至3.6V
二、硬件接口:
MAX31865 STM32L4xx ----------------------------- VDD → 3.3V GND → GND CS → GPIO (任意GPIO引脚) SCK → SPI_SCK SDI → SPI_MOSI SDO → SPI_MISO
三、头文件:
#ifndef __MAX31865_H
#define __MAX31865_H
#ifdef __cplusplus
extern "C" {
#endif
#include "stm32l4xx_hal.h"
// MAX31865寄存器地址
#define MAX31865_CONFIG_REG 0x00
#define MAX31865_RTD_MSB_REG 0x01
#define MAX31865_RTD_LSB_REG 0x02
#define MAX31865_HIGH_FAULT_MSB 0x03
#define MAX31865_HIGH_FAULT_LSB 0x04
#define MAX31865_LOW_FAULT_MSB 0x05
#define MAX31865_LOW_FAULT_LSB 0x06
#define MAX31865_FAULT_STATUS 0x07
// 配置寄存器位定义
#define MAX31865_CONFIG_BIAS (1 << 7)
#define MAX31865_CONFIG_MODE_AUTO (1 << 6)
#define MAX31865_CONFIG_1SHOT (1 << 5)
#define MAX31865_CONFIG_3WIRE (1 << 4)
#define MAX31865_CONFIG_FAULT_DETECT_NONE (0 << 2)
#define MAX31865_CONFIG_FAULT_DETECT_AUTO (1 << 2)
#define MAX31865_CONFIG_FAULT_DETECT_MANUAL_CYCLE (2 << 2)
#define MAX31865_CONFIG_FAULT_DETECT_MANUAL_OFFSET (3 << 2)
#define MAX31865_CONFIG_FILTER_50HZ (1 << 0)
#define MAX31865_CONFIG_FILTER_60HZ (0 << 0)
// 故障状态寄存器位定义
#define MAX31865_FAULT_HIGH_THRESH (1 << 7)
#define MAX31865_FAULT_LOW_THRESH (1 << 6)
#define MAX31865_FAULT_REFIN (1 << 5)
#define MAX31865_FAULT_REFIN_FORCE (1 << 4)
#define MAX31865_FAULT_RTDIN_FORCE (1 << 3)
#define MAX31865_FAULT_VOLTAGE (1 << 2)
typedef enum {
MAX31865_2WIRE = 0,
MAX31865_3WIRE = 1,
MAX31865_4WIRE = 0
} MAX31865_Wire_t;
typedef struct {
SPI_HandleTypeDef *hspi;
GPIO_TypeDef *cs_port;
uint16_t cs_pin;
MAX31865_Wire_t wire_mode;
float rtd_nominal;
float ref_resistor;
} MAX31865_HandleTypeDef;
// 函数声明
void MAX31865_Init(MAX31865_HandleTypeDef *hmax, SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, MAX31865_Wire_t wire_mode, float rtd_nominal, float ref_resistor);
uint8_t MAX31865_ReadRegister(MAX31865_HandleTypeDef *hmax, uint8_t reg);
void MAX31865_WriteRegister(MAX31865_HandleTypeDef *hmax, uint8_t reg, uint8_t value);
void MAX31865_EnableBias(MAX31865_HandleTypeDef *hmax, uint8_t enable);
void MAX31865_AutoConvert(MAX31865_HandleTypeDef *hmax, uint8_t enable);
void MAX31865_ClearFault(MAX31865_HandleTypeDef *hmax);
void MAX31865_SetWires(MAX31865_HandleTypeDef *hmax, MAX31865_Wire_t wires);
uint8_t MAX31865_ReadFault(MAX31865_HandleTypeDef *hmax);
float MAX31865_ReadTemperature(MAX31865_HandleTypeDef *hmax);
float MAX31865_ReadResistance(MAX31865_HandleTypeDef *hmax);
#ifdef __cplusplus
}
#endif
#endif /* __MAX31865_H */
四、源文件:
#include "max31865.h"
#include <math.h>
// 私有函数声明
static void MAX31865_CS_Enable(MAX31865_HandleTypeDef *hmax);
static void MAX31865_CS_Disable(MAX31865_HandleTypeDef *hmax);
void MAX31865_Init(MAX31865_HandleTypeDef *hmax, SPI_HandleTypeDef *hspi, GPIO_TypeDef *cs_port, uint16_t cs_pin, MAX31865_Wire_t wire_mode, float rtd_nominal, float ref_resistor) {
hmax->hspi = hspi;
hmax->cs_port = cs_port;
hmax->cs_pin = cs_pin;
hmax->wire_mode = wire_mode;
hmax->rtd_nominal = rtd_nominal;
hmax->ref_resistor = ref_resistor;
// 初始化CS引脚
HAL_GPIO_WritePin(hmax->cs_port, hmax->cs_pin, GPIO_PIN_SET);
// 配置MAX31865
uint8_t config = MAX31865_CONFIG_BIAS | MAX31865_CONFIG_MODE_AUTO | MAX31865_CONFIG_FILTER_60HZ;
if (hmax->wire_mode == MAX31865_3WIRE) {
config |= MAX31865_CONFIG_3WIRE;
}
MAX31865_WriteRegister(hmax, MAX31865_CONFIG_REG, config);
}
uint8_t MAX31865_ReadRegister(MAX31865_HandleTypeDef *hmax, uint8_t reg) {
uint8_t tx_data = reg & 0x7F; // 清除最高位表示读操作
uint8_t rx_data = 0;
MAX31865_CS_Enable(hmax);
HAL_SPI_Transmit(hmax->hspi, &tx_data, 1, HAL_MAX_DELAY);
HAL_SPI_Receive(hmax->hspi, &rx_data, 1, HAL_MAX_DELAY);
MAX31865_CS_Disable(hmax);
return rx_data;
}
void MAX31865_WriteRegister(MAX31865_HandleTypeDef *hmax, uint8_t reg, uint8_t value) {
uint8_t tx_data[2];
tx_data[0] = reg | 0x80; // 设置最高位表示写操作
tx_data[1] = value;
MAX31865_CS_Enable(hmax);
HAL_SPI_Transmit(hmax->hspi, tx_data, 2, HAL_MAX_DELAY);
MAX31865_CS_Disable(hmax);
}
void MAX31865_EnableBias(MAX31865_HandleTypeDef *hmax, uint8_t enable) {
uint8_t config = MAX31865_ReadRegister(hmax, MAX31865_CONFIG_REG);
if (enable) {
config |= MAX31865_CONFIG_BIAS;
} else {
config &= ~MAX31865_CONFIG_BIAS;
}
MAX31865_WriteRegister(hmax, MAX31865_CONFIG_REG, config);
}
void MAX31865_AutoConvert(MAX31865_HandleTypeDef *hmax, uint8_t enable) {
uint8_t config = MAX31865_ReadRegister(hmax, MAX31865_CONFIG_REG);
if (enable) {
config |= MAX31865_CONFIG_MODE_AUTO;
} else {
config &= ~MAX31865_CONFIG_MODE_AUTO;
}
MAX31865_WriteRegister(hmax, MAX31865_CONFIG_REG, config);
}
void MAX31865_ClearFault(MAX31865_HandleTypeDef *hmax) {
uint8_t config = MAX31865_ReadRegister(hmax, MAX31865_CONFIG_REG);
config &= ~0x0C;
config |= MAX31865_CONFIG_FAULT_DETECT_NONE;
MAX31865_WriteRegister(hmax, MAX31865_CONFIG_REG, config);
}
void MAX31865_SetWires(MAX31865_HandleTypeDef *hmax, MAX31865_Wire_t wires) {
uint8_t config = MAX31865_ReadRegister(hmax, MAX31865_CONFIG_REG);
if (wires == MAX31865_3WIRE) {
config |= MAX31865_CONFIG_3WIRE;
} else {
config &= ~MAX31865_CONFIG_3WIRE;
}
MAX31865_WriteRegister(hmax, MAX31865_CONFIG_REG, config);
hmax->wire_mode = wires;
}
uint8_t MAX31865_ReadFault(MAX31865_HandleTypeDef *hmax) {
return MAX31865_ReadRegister(hmax, MAX31865_FAULT_STATUS);
}
float MAX31865_ReadResistance(MAX31865_HandleTypeDef *hmax) {
MAX31865_ClearFault(hmax);
MAX31865_EnableBias(hmax, 1);
HAL_Delay(10);
uint8_t config = MAX31865_ReadRegister(hmax, MAX31865_CONFIG_REG);
config |= MAX31865_CONFIG_1SHOT;
MAX31865_WriteRegister(hmax, MAX31865_CONFIG_REG, config);
HAL_Delay(65);
uint8_t msb = MAX31865_ReadRegister(hmax, MAX31865_RTD_MSB_REG);
uint8_t lsb = MAX31865_ReadRegister(hmax, MAX31865_RTD_LSB_REG);
uint16_t rtd = ((msb << 8) | lsb) >> 1;
float resistance = ((float)rtd * hmax->ref_resistor) / 32768.0f;
return resistance;
}
float MAX31865_ReadTemperature(MAX31865_HandleTypeDef *hmax) {
float resistance = MAX31865_ReadResistance(hmax);
// 使用Callendar-Van Dusen方程计算温度
float temp;
float z1, z2, z3, z4;
float r = resistance / hmax->rtd_nominal;
if (r < 1.0) { // 低于0°C
temp = -242.02 + (2.2228 * r);
temp += 2.5859 * pow(r, 2);
temp -= 0.6393 * pow(r, 3);
temp -= 0.1299 * pow(r, 4);
} else { // 高于0°C
z1 = -3.9083e-3;
z2 = 1.758480889e-5;
z3 = -2.31e-8;
z4 = -1.155e-6;
temp = (z1 + sqrt(z2 + (z3 * r))) / z4;
}
return temp;
}
static void MAX31865_CS_Enable(MAX31865_HandleTypeDef *hmax) {
HAL_GPIO_WritePin(hmax->cs_port, hmax->cs_pin, GPIO_PIN_RESET);
}
static void MAX31865_CS_Disable(MAX31865_HandleTypeDef *hmax) {
HAL_GPIO_WritePin(hmax->cs_port, hmax->cs_pin, GPIO_PIN_SET);
}
五、应用:
#include "main.h"
#include "max31865.h"
SPI_HandleTypeDef hspi1;
MAX31865_HandleTypeDef hmax31865;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_SPI1_Init(void);
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_SPI1_Init();
// 初始化MAX31865
// 参数: PT100传感器, 3线制, 参考电阻430Ω
MAX31865_Init(&hmax31865, &hspi1, GPIOA, GPIO_PIN_4, MAX31865_3WIRE, 100.0f, 430.0f);
while (1) {
float temperature = MAX31865_ReadTemperature(&hmax31865);
float resistance = MAX31865_ReadResistance(&hmax31865);
printf("Temperature: %.2f °C, Resistance: %.2f Ω\n", temperature, resistance);
HAL_Delay(1000);
}
}
// SPI1初始化函数
static void MX_SPI1_Init(void) {
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_32;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK) {
Error_Handler();
}
}
// GPIO初始化函数
static void MX_GPIO_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
// SPI1 CS引脚配置
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
// SPI1引脚配置
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}