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

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

1. 硬件连接和头文件

1.1 引脚定义 (max6675.h)

#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)

#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)

#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)

#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)

#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)

#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 编译选项

# 在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/contentali/71029.html

7. 高级功能扩展

7.1 PID温度控制 (pid_control.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 温度校准功能

// 温度校准结构体
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传输提高效率
    • 实现环形缓冲区存储历史数据
    • 添加温度变化率计算
    • 实现温度曲线预测
相关文章
|
4月前
|
机器学习/深度学习 数据采集 算法
PCB电路板缺陷检测数据集分享(适用于YOLO系列深度学习检测任务)
本数据集专为PCB缺陷检测设计,含1500张1024×1024图像(训练集1000张、验证集500张),标注6类常见缺陷(缺失孔、鼠咬痕、开路等),采用YOLO格式,开箱即用,适配YOLOv5/v8等主流模型,助力工业质检与AI研发。(239字)
532 6
|
5月前
|
自然语言处理 安全 算法
企业级智能体的 “思考 - 行动” 双循环:TARS 大模型规划 + RPA 精准执行
本文剖析实在Agent“思考-行动”双循环架构:TARS垂直大模型负责语义理解与任务规划,RPA超自动化技术实现跨系统精准执行,通过多模态元素拾取、实时感知反馈与动态协同优化,破解企业智能体“只思考不行动”或“只行动不思考”的结构性断层,已落地财务等强合规场景。
|
5月前
|
监控 安全 C#
C#与三菱PLC串口通信源码实现(基于MC协议)
基于System.IO.Ports.SerialPort实现三菱FX系列PLC的串口通信,支持D寄存器、M位元件读写操作,包含指令帧构建、校验和计算、响应解析等关键模块。
|
3月前
|
人工智能 安全 BI
年轻人开始告别“左右滑社交交友经济”:2026社交交友App源码必须内置的6大吸金玩法
2026年的社交交友赛道,底层逻辑正在发生根本性重构——泛流量已不值钱,精准的情绪价值和真实的连接才值钱。
|
3月前
|
人工智能 自然语言处理 知识图谱
Geo优化评定标准深度解析:“两大核心+四轮驱动”理论与实践
生成式AI浪潮下,传统SEO已失效,GEO(生成式引擎优化)成为新核心。于磊老师首创“两大核心(人性化Geo+内容交叉验证)+四轮驱动(E-E-A-T、精准引用、结构化内容、语义关键词)”方法论,强调真实经验、多源验证与AI信任构建,助力企业提升AI可见度40%+,实现高质量获客。
241 2
|
3月前
|
人工智能 缓存 NoSQL
阿里云服务器通用算力型u1实例2核4G配置199元怎么样?实例性能、购买资格与适用场景解析
阿里云199元/年的通用算力型u1实例云服务器(2核4G、5M固定带宽、80G ESSD云盘),专为企业实名用户打造,活动截止2027年3月31日。该实例采用独享型架构,搭载Intel Xeon Platinum处理器,基准算力对标第5代企业级实例,最高可媲美第6代,网络收发包达30万PPS,性能稳定无基线限制。限企业用户购买,每人限1台,支持续费同价,覆盖国内外多个地域节点。
|
3月前
|
存储 人工智能 JavaScript
工业企业做了十年数据治理,为什么AI还是用不起来
本文揭示工业AI落地的核心瓶颈:数据“可存储”不等于“可理解”。企业虽建有完善系统,但因术语、口径、编码不统一,大模型无法识别业务语义。解决方案是构建企业本体语义体系,实现跨系统概念对齐;并结合智能体架构(AI大脑+技能库+执行环境+知识底座),让AI从“对话机器人”升级为可自主执行任务的“数字员工”,已在SOP指导、CAD审图、包装审核等场景验证实效。(239字)
309 3
|
3月前
|
弹性计算 人工智能 监控
零基础上手Hermes Agent 阿里云轻量/ECS/计算巢/无影云电脑部署+Token Plan配置指南
在AI智能体快速普及的当下,Hermes Agent凭借自主学习、长期记忆、多工具协同、任务自主拆解等核心特性,已经成为办公自动化、行业研究、代码开发、数据采集领域的热门开源智能体。和普通对话机器人不同,Hermes Agent不只是简单问答,还能自主拆分复杂工作、调用浏览器、代码解释器、文件管理等工具,完成从资料搜集、文案撰写、数据分析到流程自动化的全链路任务。
382 2
|
3月前
|
存储 人工智能 自然语言处理
大模型应用:从零构建医疗AI智能体:大模型驱动的医疗辅助系统全流程解析.125
本文系统阐述医疗AI智能体的落地实践:聚焦高敏感、高合规的医疗场景,提出“大模型+专业知识+安全规则”三位一体架构,涵盖需求规划、模型选型、RAG增强、幻觉抑制、五层技术架构及多模态交互设计,强调稳扎稳打、合规优先的工程化路径。
515 2
|
4月前
|
人工智能 监控 数据可视化
AI智能体的开发平台及特点
AI智能体开发平台已形成多层次生态:零代码平台(如Coze、Dify、Copilot Studio)面向业务人员,支持拖拽编排与企业集成;开发者框架(LangGraph、CrewAI、AutoGen)提供精细控制与多Agent协作;轻量平台(Poe)助力创作者快速分发变现。按需选择,高效落地。