STM32基于MX的MAX6675硬件SPI驱动

本项目使用STM32的SPI只接收来读取MAX6675的数据,这样可以节省一个IO。

MAX6675 进行热电偶冷端补偿和数字化 K 型热电偶信号。输出 12 位分辨率、 SPI 兼容、只读的数据。转换器的精度为 0.25℃,最高可读+1024℃,如果使用数据的 8LSB 则温度范围为 0℃到+700℃。带有热电偶开路检测功能,如需启用热电偶断路检测功能,负极端 T - 必须接地,接地点应尽可能靠近接地引脚(GND)。

原理图如下

时序图如下

将 CS 拉低后,SO 引脚会输出第一位数据。一次完整的串行接口读取操作需要 16 个时钟周期,需在时钟信号下降沿读取 16 位输出数据。第 15 位(D15)为无效符号位,恒为 0;D14 至 D3 位存储转换后的温度数值,数据格式为高位在前、低位在后;D2 位常态为低电平,若热电偶输入端断路则变为高电平;D1引脚为低电平,用于给MAX6675提供设备标识,D0引脚为三态输出。

串行时钟最大4.3M,在配置SPI时钟时需要注意。

STM32CubeMX部分配置

下面是驱动代码

Core\Inc\max6675.h

复制代码
/**
  ******************************************************************************
  * @file           : max6675.h
  * @brief          : Header for max6675.c file.
  ******************************************************************************
  */

/* Define to prevent recursive inclusion */
#ifndef __MAX6675_H
#define __MAX6675_H

#ifdef __cplusplus
extern "C" {
#endif

/* Includes */
#include "stm32f1xx_hal.h"

/* Exported functions prototypes */
void MAX6675_Init(void);
float MAX6675_ReadTemperature(void);
uint16_t MAX6675_ReadRawData(void);

#ifdef __cplusplus
}
#endif

#endif /* __MAX6675_H */

Core\Src\max6675.c

复制代码
/**
 ******************************************************************************
 * @file           : max6675.c
 * @brief          : MAX6675 Cold-Junction-Compensated Thermocouple-to-Digital Converter driver
 ******************************************************************************
 */

#include "max6675.h"

#include "main.h"
#include "spi.h"

/**
 * @brief  Microsecond delay function (24MHz system clock)
 * @param  us: Delay time in microseconds
 * @retval None
 */
static void MAX6675_DelayUs(uint32_t us)
{
    /* 24MHz system clock: 1 cycle = 41.67ns */
    /* Each loop iteration takes approximately 3 cycles */
    /* 1us = 24 cycles ≈ 8 loop iterations */
    us *= 8;
    while (us--) {
        __NOP();
    }
}

/**
 * @brief  Initialize MAX6675
 * @param  None
 * @retval None
 */
void MAX6675_Init(void)
{
    /* Set SSB pin high (deselect) */
    HAL_GPIO_WritePin(SSB_GPIO_Port, SSB_Pin, GPIO_PIN_SET);
}

/**
 * @brief  Read raw data from MAX6675
 * @param  None
 * @retval Raw 16-bit data from MAX6675
 */
uint16_t MAX6675_ReadRawData(void)
{
    uint8_t rx_buf[2] = {0};

    /* Ensure SPI is ready */
    while (HAL_SPI_GetState(&hspi1) != HAL_SPI_STATE_READY);

    /* Pull SSB low to start communication */
    HAL_GPIO_WritePin(SSB_GPIO_Port, SSB_Pin, GPIO_PIN_RESET);

    MAX6675_DelayUs(1);

    // 手动读取并丢弃DR寄存器残留数据(清空脏数据)
    __HAL_SPI_CLEAR_OVRFLAG(&hspi1);

    /* Receive 2 bytes from MAX6675 using blocking mode */
    HAL_SPI_Receive(&hspi1, rx_buf, 2, 100);

    /* Pull SSB high to end communication */
    HAL_GPIO_WritePin(SSB_GPIO_Port, SSB_Pin, GPIO_PIN_SET);

    MAX6675_DelayUs(1);

    /* Combine bytes: MSB first, LSB second */
    uint16_t raw_data = ((uint16_t)rx_buf[0] << 8) | rx_buf[1];

    return raw_data;
}

/**
 * @brief  Read temperature from MAX6675
 * @param  None
 * @retval Temperature value in Celsius
 */
float MAX6675_ReadTemperature(void)
{
    uint16_t raw_data = MAX6675_ReadRawData();

    /* Check if thermocouple is open (no connection) */
    if (raw_data & 0x04) {
        /* Thermocouple error - return error indicator */
        return -1.0f;
    }

    /* Extract temperature (bits D14-D3) and convert to Celsius
     * Resolution: 0.25°C per bit
     */
    float temperature = (float)((raw_data >> 3) & 0x0FFF) * 0.25f;

    return temperature;
}