MAX6675 K型热电偶温度采集程序(Keil环境)

1. 硬件连接和头文件

1.1 引脚定义 (max6675.h)

c 复制代码
#ifndef __MAX6675_H
#define __MAX6675_H

#include "stm32f1xx_hal.h"

// MAX6675引脚定义
#define MAX6675_CS_PORT    GPIOA
#define MAX6675_CS_PIN     GPIO_PIN_4
#define MAX6675_SCK_PORT   GPIOA
#define MAX6675_SCK_PIN    GPIO_PIN_5
#define MAX6675_SO_PORT    GPIOA
#define MAX6675_SO_PIN     GPIO_PIN_6

// 函数声明
void MAX6675_Init(void);
float MAX6675_ReadTemp(void);
uint8_t MAX6675_CheckSensor(void);
float MAX6675_GetAverageTemp(uint8_t samples);
void MAX6675_StartConversion(void);
void MAX6675_Delay_us(uint32_t us);

#endif

2. SPI模拟驱动实现

2.1 基本驱动函数 (max6675.c)

c 复制代码
#include "max6675.h"
#include "main.h"
#include <math.h>

// 全局变量
static uint8_t max6675_initialized = 0;

/**
  * @brief  初始化MAX6675
  */
void MAX6675_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // 使能GPIO时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    // 配置CS引脚为推挽输出
    GPIO_InitStruct.Pin = MAX6675_CS_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(MAX6675_CS_PORT, &GPIO_InitStruct);
    
    // 配置SCK引脚为推挽输出
    GPIO_InitStruct.Pin = MAX6675_SCK_PIN;
    HAL_GPIO_Init(MAX6675_SCK_PORT, &GPIO_InitStruct);
    
    // 配置SO引脚为输入
    GPIO_InitStruct.Pin = MAX6675_SO_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(MAX6675_SO_PORT, &GPIO_InitStruct);
    
    // 初始状态:CS高电平,SCK低电平
    HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_SET);
    HAL_GPIO_WritePin(MAX6675_SCK_PORT, MAX6675_SCK_PIN, GPIO_PIN_RESET);
    
    // 延时确保MAX6675准备好
    HAL_Delay(100);
    
    max6675_initialized = 1;
}

/**
  * @brief  微秒延时函数
  * @param  us: 延时微秒数
  */
void MAX6675_Delay_us(uint32_t us)
{
    uint32_t delay = us * (SystemCoreClock / 1000000) / 5;
    while(delay--)
    {
        __NOP();
    }
}

/**
  * @brief  读取16位数据
  * @retval 读取到的16位数据
  */
static uint16_t MAX6675_Read16Bits(void)
{
    uint16_t data = 0;
    
    // CS拉低,开始通信
    HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_RESET);
    
    // 等待至少100ns
    MAX6675_Delay_us(1);
    
    // 读取16位数据
    for(uint8_t i = 0; i < 16; i++)
    {
        // SCK上升沿,MAX6675输出数据
        HAL_GPIO_WritePin(MAX6675_SCK_PORT, MAX6675_SCK_PIN, GPIO_PIN_SET);
        MAX6675_Delay_us(1);
        
        // 读取数据位
        if(HAL_GPIO_ReadPin(MAX6675_SO_PORT, MAX6675_SO_PIN) == GPIO_PIN_SET)
        {
            data |= (1 << (15 - i));
        }
        
        // SCK下降沿
        HAL_GPIO_WritePin(MAX6675_SCK_PORT, MAX6675_SCK_PIN, GPIO_PIN_RESET);
        MAX6675_Delay_us(1);
    }
    
    // CS拉高,结束通信
    HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_SET);
    
    return data;
}

/**
  * @brief  读取温度值
  * @retval 温度值(摄氏度),如果出错返回NAN
  */
float MAX6675_ReadTemp(void)
{
    if(!max6675_initialized)
    {
        MAX6675_Init();
    }
    
    uint16_t raw_data = 0;
    float temperature = 0.0f;
    
    // 读取原始数据
    raw_data = MAX6675_Read16Bits();
    
    // 检查传感器是否连接正常
    if(raw_data & 0x0004)  // D2位为1表示热电偶开路
    {
        return NAN;  // 返回NaN表示错误
    }
    
    // 提取温度数据位(D15-D3)
    raw_data = raw_data >> 3;
    
    // 转换为温度值(每个LSB对应0.25°C)
    temperature = raw_data * 0.25f;
    
    return temperature;
}

/**
  * @brief  检查传感器状态
  * @retval 0: 正常, 1: 热电偶开路
  */
uint8_t MAX6675_CheckSensor(void)
{
    if(!max6675_initialized)
    {
        MAX6675_Init();
    }
    
    uint16_t raw_data = MAX6675_Read16Bits();
    
    // 检查D2位(热电偶开路标志)
    if(raw_data & 0x0004)
    {
        return 1;  // 热电偶开路
    }
    
    return 0;  // 正常
}

/**
  * @brief  读取平均温度(多次采样取平均)
  * @param  samples: 采样次数
  * @retval 平均温度值
  */
float MAX6675_GetAverageTemp(uint8_t samples)
{
    if(samples == 0) samples = 1;
    if(samples > 10) samples = 10;  // 最多采样10次
    
    float sum = 0.0f;
    uint8_t valid_samples = 0;
    
    for(uint8_t i = 0; i < samples; i++)
    {
        float temp = MAX6675_ReadTemp();
        
        // 检查是否为有效温度(非NaN)
        if(!isnan(temp))
        {
            sum += temp;
            valid_samples++;
        }
        
        // 采样间隔
        if(i < samples - 1)
        {
            HAL_Delay(10);
        }
    }
    
    if(valid_samples > 0)
    {
        return sum / valid_samples;
    }
    else
    {
        return NAN;  // 所有采样都无效
    }
}

/**
  * @brief  开始转换(可选,MAX6675自动转换)
  */
void MAX6675_StartConversion(void)
{
    // MAX6675是自动转换的,但可以调用此函数触发新读取
    // 实际只是模拟一下,确保在读取前有足够时间转换
    HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_SET);
    HAL_Delay(1);
}

3. 硬件SPI驱动实现(可选)

3.1 SPI硬件驱动版本 (max6675_spi.c)

c 复制代码
#include "max6675.h"
#include "main.h"

// SPI句柄
extern SPI_HandleTypeDef hspi1;

/**
  * @brief  硬件SPI方式读取温度
  * @retval 温度值
  */
float MAX6675_SPI_ReadTemp(void)
{
    uint16_t raw_data = 0;
    float temperature = 0.0f;
    
    // CS拉低
    HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_RESET);
    
    // 通过SPI读取16位数据
    if(HAL_SPI_Receive(&hspi1, (uint8_t*)&raw_data, 1, 10) == HAL_OK)
    {
        // 交换字节顺序(如果需要)
        raw_data = (raw_data << 8) | (raw_data >> 8);
    }
    else
    {
        HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_SET);
        return NAN;
    }
    
    // CS拉高
    HAL_GPIO_WritePin(MAX6675_CS_PORT, MAX6675_CS_PIN, GPIO_PIN_SET);
    
    // 检查传感器状态
    if(raw_data & 0x0004)  // 热电偶开路
    {
        return NAN;
    }
    
    // 提取温度数据
    raw_data = raw_data >> 3;
    temperature = raw_data * 0.25f;
    
    return temperature;
}

4. 温度处理模块

4.1 温度处理头文件 (temperature.h)

c 复制代码
#ifndef __TEMPERATURE_H
#define __TEMPERATURE_H

#include <stdint.h>
#include <stdbool.h>

// 温度单位定义
typedef enum {
    TEMP_UNIT_CELSIUS = 0,
    TEMP_UNIT_FAHRENHEIT,
    TEMP_UNIT_KELVIN
} TempUnit_t;

// 温度报警结构体
typedef struct {
    float high_threshold;    // 高温报警阈值
    float low_threshold;     // 低温报警阈值
    float high_hysteresis;   // 高温迟滞
    float low_hysteresis;    // 低温迟滞
    bool high_alarm;         // 高温报警状态
    bool low_alarm;          // 低温报警状态
} TempAlarm_t;

// 温度数据滤波结构体
typedef struct {
    float buffer[10];        // 滤波缓冲区
    uint8_t index;           // 当前索引
    uint8_t count;           // 有效数据个数
    uint8_t size;            // 滤波器大小
} TempFilter_t;

// 函数声明
void Temp_Init(void);
float Temp_Read(void);
float Temp_GetAverage(uint8_t samples);
void Temp_ConvertUnit(float *temp, TempUnit_t from, TempUnit_t to);
void Temp_AlarmInit(TempAlarm_t *alarm, float high, float low, float hys);
void Temp_CheckAlarm(TempAlarm_t *alarm, float temp);
float Temp_FilterAdd(TempFilter_t *filter, float temp);
void Temp_FilterReset(TempFilter_t *filter);
bool Temp_IsValid(float temp);

#endif

4.2 温度处理实现 (temperature.c)

c 复制代码
#include "temperature.h"
#include "max6675.h"
#include <math.h>

// 全局变量
static TempUnit_t current_unit = TEMP_UNIT_CELSIUS;
static TempAlarm_t temp_alarm = {0};
static TempFilter_t temp_filter = {0};

/**
  * @brief  温度模块初始化
  */
void Temp_Init(void)
{
    MAX6675_Init();
    
    // 初始化温度滤波器
    temp_filter.size = 5;  // 5点滑动平均
    Temp_FilterReset(&temp_filter);
    
    // 初始化报警器
    Temp_AlarmInit(&temp_alarm, 100.0f, 0.0f, 2.0f);
}

/**
  * @brief  读取温度
  * @retval 温度值
  */
float Temp_Read(void)
{
    float temp = MAX6675_ReadTemp();
    
    if(Temp_IsValid(temp))
    {
        // 滤波处理
        temp = Temp_FilterAdd(&temp_filter, temp);
        
        // 检查报警
        Temp_CheckAlarm(&temp_alarm, temp);
    }
    
    return temp;
}

/**
  * @brief  读取平均温度
  * @param  samples: 采样次数
  * @retval 平均温度
  */
float Temp_GetAverage(uint8_t samples)
{
    return MAX6675_GetAverageTemp(samples);
}

/**
  * @brief  温度单位转换
  * @param  temp: 温度值
  * @param  from: 原始单位
  * @param  to: 目标单位
  */
void Temp_ConvertUnit(float *temp, TempUnit_t from, TempUnit_t to)
{
    if(from == to) return;
    
    // 先转换为摄氏度
    switch(from)
    {
        case TEMP_UNIT_FAHRENHEIT:
            *temp = (*temp - 32.0f) * 5.0f / 9.0f;
            break;
            
        case TEMP_UNIT_KELVIN:
            *temp = *temp - 273.15f;
            break;
            
        default:
            break;
    }
    
    // 从摄氏度转换到目标单位
    switch(to)
    {
        case TEMP_UNIT_FAHRENHEIT:
            *temp = *temp * 9.0f / 5.0f + 32.0f;
            break;
            
        case TEMP_UNIT_KELVIN:
            *temp = *temp + 273.15f;
            break;
            
        default:
            break;
    }
}

/**
  * @brief  温度报警器初始化
  */
void Temp_AlarmInit(TempAlarm_t *alarm, float high, float low, float hys)
{
    alarm->high_threshold = high;
    alarm->low_threshold = low;
    alarm->high_hysteresis = hys;
    alarm->low_hysteresis = hys;
    alarm->high_alarm = false;
    alarm->low_alarm = false;
}

/**
  * @brief  检查温度报警
  */
void Temp_CheckAlarm(TempAlarm_t *alarm, float temp)
{
    if(isnan(temp)) return;
    
    // 高温报警检查
    if(!alarm->high_alarm && temp >= alarm->high_threshold)
    {
        alarm->high_alarm = true;
    }
    else if(alarm->high_alarm && temp <= (alarm->high_threshold - alarm->high_hysteresis))
    {
        alarm->high_alarm = false;
    }
    
    // 低温报警检查
    if(!alarm->low_alarm && temp <= alarm->low_threshold)
    {
        alarm->low_alarm = true;
    }
    else if(alarm->low_alarm && temp >= (alarm->low_threshold + alarm->low_hysteresis))
    {
        alarm->low_alarm = false;
    }
}

/**
  * @brief  温度滤波
  * @param  filter: 滤波器结构体
  * @param  temp: 新温度值
  * @retval 滤波后的温度
  */
float Temp_FilterAdd(TempFilter_t *filter, float temp)
{
    if(isnan(temp)) return 0.0f;
    
    // 添加到缓冲区
    filter->buffer[filter->index] = temp;
    filter->index = (filter->index + 1) % filter->size;
    
    if(filter->count < filter->size)
    {
        filter->count++;
    }
    
    // 计算平均值
    float sum = 0.0f;
    for(uint8_t i = 0; i < filter->count; i++)
    {
        sum += filter->buffer[i];
    }
    
    return sum / filter->count;
}

/**
  * @brief  重置滤波器
  */
void Temp_FilterReset(TempFilter_t *filter)
{
    for(uint8_t i = 0; i < filter->size; i++)
    {
        filter->buffer[i] = 0.0f;
    }
    filter->index = 0;
    filter->count = 0;
}

/**
  * @brief  检查温度是否有效
  */
bool Temp_IsValid(float temp)
{
    if(isnan(temp)) return false;
    if(temp < -270.0f || temp > 1370.0f) return false;  // MAX6675范围
    return true;
}

5. 主程序示例

5.1 主程序 (main.c)

c 复制代码
#include "main.h"
#include "max6675.h"
#include "temperature.h"
#include "stdio.h"
#include "string.h"

// 全局变量
UART_HandleTypeDef huart1;
TIM_HandleTypeDef htim2;

// LCD显示相关(如果需要)
typedef struct {
    float current_temp;
    float max_temp;
    float min_temp;
    float avg_temp;
    uint32_t sample_count;
} TempDisplay_t;

TempDisplay_t temp_display = {0};
TempAlarm_t temp_alarm = {0};

/**
  * @brief  系统时钟配置
  */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    
    // 配置HSE
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);
    
    // 配置系统时钟
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                  |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}

/**
  * @brief  GPIO初始化
  */
static void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    // 使能GPIO时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
    
    // 配置LED引脚
    GPIO_InitStruct.Pin = GPIO_PIN_13;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    // 配置报警输出引脚
    GPIO_InitStruct.Pin = GPIO_PIN_12;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

/**
  * @brief  USART1初始化
  */
static void MX_USART1_UART_Init(void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&huart1);
}

/**
  * @brief  TIM2初始化(用于定时采样)
  */
static void MX_TIM2_Init(void)
{
    TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    TIM_MasterConfigTypeDef sMasterConfig = {0};
    
    htim2.Instance = TIM2;
    htim2.Init.Prescaler = 7200 - 1;  // 10kHz时钟
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 10000 - 1;    // 1秒定时
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    HAL_TIM_Base_Init(&htim2);
    
    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig);
    
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
}

/**
  * @brief  通过串口发送字符串
  */
void UART_SendString(char *str)
{
    HAL_UART_Transmit(&huart1, (uint8_t*)str, strlen(str), HAL_MAX_DELAY);
}

/**
  * @brief  通过串口发送温度数据
  */
void UART_SendTempData(float temp, uint8_t sensor_status)
{
    char buffer[64];
    
    if(sensor_status == 1)
    {
        sprintf(buffer, "ERROR: Thermocouple Open!\r\n");
    }
    else if(isnan(temp))
    {
        sprintf(buffer, "ERROR: Invalid Temperature!\r\n");
    }
    else
    {
        sprintf(buffer, "Temperature: %.2f°C\r\n", temp);
    }
    
    UART_SendString(buffer);
}

/**
  * @brief  更新温度显示数据
  */
void UpdateTempDisplay(float temp)
{
    if(isnan(temp)) return;
    
    temp_display.current_temp = temp;
    temp_display.sample_count++;
    
    // 更新最大温度
    if(temp > temp_display.max_temp || temp_display.sample_count == 1)
    {
        temp_display.max_temp = temp;
    }
    
    // 更新最小温度
    if(temp < temp_display.min_temp || temp_display.sample_count == 1)
    {
        temp_display.min_temp = temp;
    }
    
    // 更新平均温度
    temp_display.avg_temp = (temp_display.avg_temp * (temp_display.sample_count - 1) + temp) / temp_display.sample_count;
}

/**
  * @brief  显示温度统计数据
  */
void DisplayTempStats(void)
{
    char buffer[128];
    
    sprintf(buffer, "\r\n=== Temperature Statistics ===\r\n");
    UART_SendString(buffer);
    
    sprintf(buffer, "Current: %.2f°C\r\n", temp_display.current_temp);
    UART_SendString(buffer);
    
    sprintf(buffer, "Maximum: %.2f°C\r\n", temp_display.max_temp);
    UART_SendString(buffer);
    
    sprintf(buffer, "Minimum: %.2f°C\r\n", temp_display.min_temp);
    UART_SendString(buffer);
    
    sprintf(buffer, "Average: %.2f°C\r\n", temp_display.avg_temp);
    UART_SendString(buffer);
    
    sprintf(buffer, "Samples: %lu\r\n", temp_display.sample_count);
    UART_SendString(buffer);
    
    sprintf(buffer, "=============================\r\n\r\n");
    UART_SendString(buffer);
}

/**
  * @brief  控制报警输出
  */
void ControlAlarmOutput(void)
{
    static uint32_t blink_counter = 0;
    
    if(temp_alarm.high_alarm)
    {
        // 高温报警:快速闪烁
        if((blink_counter % 5) == 0)
        {
            HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_12);
        }
    }
    else if(temp_alarm.low_alarm)
    {
        // 低温报警:慢速闪烁
        if((blink_counter % 20) == 0)
        {
            HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_12);
        }
    }
    else
    {
        // 正常状态:关闭报警
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);
    }
    
    blink_counter++;
}

/**
  * @brief  TIM2定时器中断回调
  */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM2)
    {
        static uint32_t counter = 0;
        
        // 翻转LED指示运行状态
        HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13);
        
        // 每秒读取一次温度
        if(counter % 1 == 0)
        {
            float temp = Temp_Read();
            uint8_t status = MAX6675_CheckSensor();
            
            UART_SendTempData(temp, status);
            UpdateTempDisplay(temp);
        }
        
        // 每10秒显示一次统计信息
        if(counter % 10 == 0)
        {
            DisplayTempStats();
        }
        
        // 控制报警输出
        ControlAlarmOutput();
        
        counter++;
    }
}

/**
  * @brief  主函数
  */
int main(void)
{
    // HAL库初始化
    HAL_Init();
    
    // 系统时钟配置
    SystemClock_Config();
    
    // 外设初始化
    MX_GPIO_Init();
    MX_USART1_UART_Init();
    MX_TIM2_Init();
    
    // 温度模块初始化
    Temp_Init();
    
    // 初始化报警器
    Temp_AlarmInit(&temp_alarm, 100.0f, 10.0f, 2.0f);
    
    // 启动定时器
    HAL_TIM_Base_Start_IT(&htim2);
    
    // 发送启动信息
    UART_SendString("\r\n=== MAX6675 Temperature Monitor ===\r\n");
    UART_SendString("Initialization Complete!\r\n\r\n");
    
    // 主循环
    while(1)
    {
        // 主循环中可以添加其他任务
        // 例如:按键检测、屏幕刷新等
        
        // 空闲时进入低功耗模式
        __WFI();
    }
}

6. Keil工程配置

6.1 工程配置要点

  1. Device: 选择对应的STM32型号(如STM32F103C8T6)
  2. Target: 设置正确的晶振频率
  3. C/C++: 添加包含路径和预定义符号
  4. Debug: 配置调试器
  5. Utilities: 配置Flash烧录算法

6.2 编译选项

makefile 复制代码
# 在Keil的Options for Target -> C/C++中设置
# Define: STM32F103xB, USE_HAL_DRIVER
# Include Paths: 
#   ../Drivers/STM32F1xx_HAL_Driver/Inc
#   ../Drivers/STM32F1xx_HAL_Driver/Inc/Legacy
#   ../Drivers/CMSIS/Device/ST/STM32F1xx/Include
#   ../Drivers/CMSIS/Include
#   ../Core/Inc

参考代码 max6675温度采集keil程序 www.youwenfan.com/contentcsv/71029.html

7. 高级功能扩展

7.1 PID温度控制 (pid_control.c)

c 复制代码
#include "pid_control.h"
#include <math.h>

/**
  * @brief  PID控制器初始化
  */
void PID_Init(PID_Controller *pid, float kp, float ki, float kd, float out_min, float out_max)
{
    pid->kp = kp;
    pid->ki = ki;
    pid->kd = kd;
    pid->out_min = out_min;
    pid->out_max = out_max;
    pid->integral = 0.0f;
    pid->prev_error = 0.0f;
    pid->prev_time = 0;
}

/**
  * @brief  PID计算
  */
float PID_Calculate(PID_Controller *pid, float setpoint, float measured, uint32_t time_ms)
{
    float error = setpoint - measured;
    float dt = (time_ms - pid->prev_time) / 1000.0f;  // 转换为秒
    
    if(dt <= 0) dt = 0.1f;  // 默认0.1秒
    
    // 比例项
    float proportional = pid->kp * error;
    
    // 积分项
    pid->integral += error * dt;
    
    // 积分限幅
    if(pid->integral > pid->out_max) pid->integral = pid->out_max;
    if(pid->integral < pid->out_min) pid->integral = pid->out_min;
    
    float integral = pid->ki * pid->integral;
    
    // 微分项
    float derivative = pid->kd * (error - pid->prev_error) / dt;
    
    // 计算输出
    float output = proportional + integral + derivative;
    
    // 输出限幅
    if(output > pid->out_max) output = pid->out_max;
    if(output < pid->out_min) output = pid->out_min;
    
    // 保存状态
    pid->prev_error = error;
    pid->prev_time = time_ms;
    
    return output;
}

/**
  * @brief  PID重置
  */
void PID_Reset(PID_Controller *pid)
{
    pid->integral = 0.0f;
    pid->prev_error = 0.0f;
    pid->prev_time = 0;
}

7.2 温度校准功能

c 复制代码
// 温度校准结构体
typedef struct {
    float offset;      // 零点偏移
    float gain;        // 增益修正
    float cal_temp1;   // 校准点1温度
    float read_temp1;  // 校准点1读数
    float cal_temp2;   // 校准点2温度
    float read_temp2;  // 校准点2读数
} TempCalibration_t;

/**
  * @brief  计算校准参数
  */
void TempCal_CalculateParams(TempCalibration_t *cal)
{
    // 计算斜率和偏移
    cal->gain = (cal->cal_temp2 - cal->cal_temp1) / (cal->read_temp2 - cal->read_temp1);
    cal->offset = cal->cal_temp1 - (cal->read_temp1 * cal->gain);
}

/**
  * @brief  应用温度校准
  */
float TempCal_Apply(float raw_temp, TempCalibration_t *cal)
{
    return (raw_temp * cal->gain) + cal->offset;
}

8. 使用注意事项

  1. 硬件连接

    • VCC: 连接3.3V或5V电源
    • GND: 连接电源地
    • SCK: 连接时钟引脚
    • CS: 连接片选引脚
    • SO: 连接数据输出引脚
    • T+ T-: 连接K型热电偶
  2. 注意事项

    • MAX6675最大测量温度:0-1024°C
    • 精度:±2°C(0-700°C范围内)
    • 分辨率:0.25°C
    • 转换时间:170ms
    • 需要冷端补偿
  3. 调试技巧

    • 使用逻辑分析仪检查SPI时序
    • 添加CRC校验提高可靠性
    • 实现软件看门狗防止程序卡死
    • 添加掉电保护功能
  4. 优化建议

    • 使用DMA传输提高效率
    • 实现环形缓冲区存储历史数据
    • 添加温度变化率计算
    • 实现温度曲线预测
相关推荐
豆包公子9 小时前
AUTOSAR CP XCP 移植到裸机 MCU-实践篇
单片机·嵌入式硬件
三佛科技-134163842129 小时前
智能暖脚按摩器方案开发,智能暖脚按摩器MCU单片机主控芯片选择 (FT60F系列8位MCU)
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
与仪共舞10 小时前
罗德与施瓦茨NRP 40T功率传感器
科技·单片机·目标检测
是温不嗜温10 小时前
芯茂微100V SR同步整流方案技术解析:效率+5%、温降-20°C,管脚兼容直接替代传统肖特基
嵌入式硬件·电源管理·电源芯片·ac-dc
嵌入式-老费10 小时前
esp32开发与应用(按键输入)
嵌入式硬件
追兮兮10 小时前
告别手动搭建Keil工程!MCUQuickStart一键生成STM32/GD32工程模板,打开即编译
stm32·单片机·嵌入式硬件·gd32·keil5
不会武功的火柴11 小时前
SystemVerilog语法(9)-验证基础与简单Testbench
嵌入式硬件·fpga开发·fpga·systemverilog·硬件描述语言·rtl·uvm验证
XINVRY-FPGA11 小时前
XC7Z020-2CLG484I Xilinx Zynq-7000 SoC FPGA
嵌入式硬件·fpga开发·云计算·硬件工程·fpga
XMAIPC_Robot11 小时前
RK3588 PLC AMP 核隔离配置 + RT‑Thread 实时优化 + FPGA 接口定义 + CODESYS 工程
人工智能·嵌入式硬件·深度学习·fpga开发