STM32高精度PID温控系统设计与实现:Pt1000温度传感器与PWM控制技术的深度应用

一、项目概述

随着科技的发展和工业自动化的普及,高精度的温度控制系统在各个领域的应用越来越广泛,如实验室设备、食品加工、电子元器件测试等。本项目基于 STM32 微控制器设计了一种快速、高精度的 PID 温控系统。该系统采用比例积分微分(PID)控制算法,能够实时监测和调整温度,确保控制精度。

项目目标

本项目旨在开发一个能够快速响应并高精度控制温度的系统,适用于对温控的响应速度和精度要求较高的场合。系统将通过上位机进行设定温度输入,同时监控系统的运行状态。

技术栈关键词

  • 硬件:STM32 微控制器、Pt1000 温度传感器、TLP521-1 光电耦合器、BD237 功率晶体管、FTA951 热电冷却器(TEC)

  • 软件:PID 控制算法、PWM 控制、串口通信

  • 开发环境:Keil MDK,STM32CubeMX

  • 二、系统架构

    设计系统架构

    本系统采用 STM32 作为主控单元,温度采集电路通过 Pt1000 电阻温度计进行温度传感。TLP521-1 光电耦合器与 BD237 功率晶体管的组合用于驱动 TEC。PWM 信号用于控制 TEC 的工作状态,进而实现温度调节。

    系统架构图

    设定温度

    读取温度

    温度信号

    PWM信号

    驱动

    控制

    串口监控

    上位机

    STM32 MCU

    Pt1000 温度传感器

    TLP521-1 光电耦合器

    BD237 功率晶体管

    FTA951 热电冷却器TEC

    组件选择

  • STM32 微控制器:选择 STM32F103C8T6,具有较强的处理能力和丰富的外设接口。

  • Pt1000 温度传感器:高精度,适用于温度测量。

  • TLP521-1 光电耦合器:用于隔离控制信号和功率电路。

  • BD237 功率晶体管:用于驱动 TEC,控制大电流。

  • FTA951 热电冷却器:用于温度控制,快速响应。

  • 三、环境搭建和注意事项

    环境搭建

    1. 硬件连接:

    2. 将 Pt1000 温度传感器连接到 STM32 的 ADC 引脚。

    3. 使用 TLP521-1 光电耦合器将 STM32 的 PWM 输出连接到 BD237 功率晶体管。

    4. 将 BD237 的输出连接到 FTA951 热电冷却器。

    5. 软件准备:

    6. 安装 STM32CubeMX 和 Keil MDK 开发环境。

    7. 配置 STM32 的 ADC、PWM、串口等外设。

    注意事项

  • 确保电路连接正确,避免短路和干扰。

  • 在调试过程中,注意温度传感器的校准,确保测量准确。

  • 避免 TEC 超负荷工作,以免损坏。

  • 四、代码实现过程

    在本节中,我们将详细介绍基于 STM32 的 PID 温控系统的代码实现过程,包括温度采集、PID 控制算法的实现、PWM 输出控制等。每个模块将配有代码示例和详细说明,以确保代码逻辑清晰、易于理解和维护。

    1.主程序框架

    代码示例

    以下是 STM32 PID 温控系统的主程序框架,包含温度采集、PID 控制和 PWM 输出的核心代码。

    #include "stm32f4xx.h"
    #include "pid.h"
    #include "temperature.h"
    #include "pwm.h"
    #include "usart.h"
    
    // PID 控制参数和目标温度
    float setpoint = 25.0; // 设定温度(目标温度)
    PID_Controller pid;     // PID 控制器实例
    
    void setup() {
        USART_Init();           // 初始化串口
        ADC_Init();             // 初始化ADC,用于温度采集
        PWM_Init();             // 初始化PWM,用于控制TEC
        PID_Init(&pid, 1.0, 0.1, 0.01); // 初始化PID控制器,设置Kp, Ki, Kd
    }
    
    int main() {
        setup();                // 进行系统初始化
        while (1) {
            // 获取当前温度
            float current_temp = Get_Temperature(); 
    
            // 计算PWM值
            float pwm_value = PID_Compute(&pid, setpoint, current_temp);
    
            // 根据计算得到的PWM值进行控制
            Set_PWM(pwm_value); 
    
            // 通过串口输出当前温度和PWM值,便于调试
            USART_Send(current_temp, pwm_value);
    
            // 延时,避免程序过快循环
            HAL_Delay(1000); // 每秒更新一次
        }
    }
    

    代码说明

    1. 库文件引用:

    2. #include "stm32f4xx.h":包含 STM32F4 系列的标准库。

    3. 其他头文件如 pid.htemperature.hpwm.husart.h 分别用于 PID 控制、温度读取、PWM 控制和串口通信。

    4. 全局变量定义:

    5. float setpoint = 25.0;:设定温度为 25°C,用户可以根据需求调整此值。

    6. PID_Controller pid;:创建一个 PID 控制器实例,用于管理 PID 控制的参数和状态。

    7. 系统初始化:

    8. USART_Init():初始化串口,用于数据传输和调试。

    9. ADC_Init():初始化 ADC 模块,用于读取温度传感器的数据。

    10. PWM_Init():初始化 PWM 模块,用于控制热电冷却器(TEC)的输出。

    11. PID_Init(&pid, 1.0, 0.1, 0.01):初始化 PID 控制器,并设置比例(Kp)、积分(Ki)和微分(Kd)参数。

    12. 主循环:

    13. Get_Temperature():调用温度读取函数,获取当前温度值。

    14. PID_Compute(&pid, setpoint, current_temp):根据设定温度和当前温度计算 PWM 控制值。

    15. Set_PWM(pwm_value):根据 PID 计算得到的 PWM 值调整 TEC 的工作状态。

    16. USART_Send(current_temp, pwm_value):通过串口发送当前温度和 PWM 值,便于监控和调试。

    17. HAL_Delay(1000):延时 1 秒,以避免循环过快导致 CPU 占用过高。

    2.温度读取模块

    代码示例

    以下是温度读取模块代码,使用 ADC 读取 Pt1000 温度传感器的温度。

    #include "temperature.h"
    
    float Get_Temperature() {
        // 启动 ADC 转换
        HAL_ADC_Start(&hadc1);
    
        // 等待 ADC 转换完成
        HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
    
        // 获取 ADC 转换结果
        uint32_t adc_value = HAL_ADC_GetValue(&hadc1);
    
        // 将 ADC 值转换为温度(假设线性关系)
        float temperature = (adc_value / 4095.0) * 100.0; // 线性转换,假设满量程为 100°C
        
        return temperature; // 返回温度值
    }
    

    代码说明

  • 函数定义:

  • float Get_Temperature():定义一个函数,用于读取温度传感器的值并返回当前温度。
  • ADC 启动和转换:

  • HAL_ADC_Start(&hadc1):启动 ADC 转换。hadc1 是 ADC 的句柄,需根据具体配置进行定义。

  • HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY):等待 ADC 转换完成。此函数会阻塞,直到转换结束。

  • 获取 ADC 值:

  • uint32_t adc_value = HAL_ADC_GetValue(&hadc1):获取 ADC 转换的结果,返回值为 ADC 的数字表示(0 到 4095,通常为 12 位分辨率)。
  • 温度转换:

  • float temperature = (adc_value / 4095.0) * 100.0:将 ADC 值转换为温度值。这里假设 Pt1000 温度传感器的输出为线性关系,满量程为 100°C,具体转换关系需根据温度传感器的特性曲线进行调整。
  • 返回温度值:

  • return temperature:返回计算得到的温度值。
  • 3.PID 控制模块

    代码示例

    以下是 PID 控制模块的代码,实现 PID 控制算法。

    #include "pid.h"
    
    // 初始化 PID 控制器
    void PID_Init(PID_Controller *pid, float Kp, float Ki, float Kd) {
        pid->Kp = Kp; // 比例增益
        pid->Ki = Ki; // 积分增益
        pid->Kd = Kd; // 微分增益
        pid->previous_error = 0.0; // 初始化误差
        pid->integral = 0.0; // 初始化积分
    }
    
    // 计算 PID 控制输出
    float PID_Compute(PID_Controller *pid, float setpoint, float measured_value) {
        // 计算当前误差
        float error = setpoint - measured_value;
    
        // 计算积分
        pid->integral += error;
    
        // 计算微分
        float derivative = error - pid->previous_error;
    
        // 计算 PID 输出
        float output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative;
    
        // 更新上一误差
        pid->previous_error = error;
    
        // 输出限制(根据系统要求进行限制)
        if (output > 100.0) output = 100.0; // 限制最大输出
        if (output < 0.0) output = 0.0;     // 限制最小输出
    
        return output; // 返回控制输出
    }
    

    代码说明

  • PID 控制器结构体:

  • PID_Controller 结构体包含 PID 控制器的参数和状态变量(如比例增益 Kp、积分增益 Ki、微分增益 Kd、上次误差、积分值等)。
  • 初始化 PID 控制器:

  • void PID_Init(PID_Controller *pid, float Kp, float Ki, float Kd):初始化 PID 控制器的参数,并将误差和积分初始化为 0。
  • 计算 PID 控制输出:

  • float PID_Compute(PID_Controller *pid, float setpoint, float measured_value):根据设定值和测量值计算 PID 控制输出。

  • float error = setpoint - measured_value:计算当前误差。

  • pid->integral += error:累加误差,计算积分项。

  • float derivative = error - pid->previous_error:计算微分项,表示误差的变化率。

  • float output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative:计算 PID 控制输出。

  • pid->previous_error = error:更新上一误差,用于下次计算微分项。

  • 输出限制:为了防止输出超出系统控制范围,设置了输出的最大值和最小值。

  • 4.PWM 控制模块

    代码示例

    以下是 PWM 控制模块的代码,负责根据计算得到的 PWM 值控制 TEC 的工作。

    #include "pwm.h"
    
    // 初始化 PWM
    void PWM_Init() {
        // 1. 定义定时器句柄
        TIM_HandleTypeDef htim2;
    
        // 2. 启用定时器时钟
        __HAL_RCC_TIM2_CLK_ENABLE();
    
        // 3. 设置定时器基础参数
        htim2.Instance = TIM2; // 选择定时器2
        htim2.Init.Prescaler = 84 - 1; // 预分频器设置(假设72MHz的时钟频率,分频到1MHz)
        htim2.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式
        htim2.Init.Period = 1000 - 1; // 设定PWM周期(1ms)
        htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    
        // 4. 初始化定时器
        HAL_TIM_PWM_Init(&htim2);
    
        // 5. PWM输出通道配置
        TIM_OC_InitTypeDef sConfigOC;
        sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM模式1
        sConfigOC.Pulse = 0; // 初始占空比为0%
        sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 输出极性:高电平有效
        sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 禁用快速模式
    
        // 6. 启用PWM通道
        HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);
        HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // 启动PWM通道
    }
    
    // 设置PWM输出
    void Set_PWM(float pwm_value) {
        // 限制PWM值在0到1000之间
        if (pwm_value > 1000.0) pwm_value = 1000.0;
        if (pwm_value < 0.0) pwm_value = 0.0;
    
        // 设置PWM的占空比
        __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, (uint32_t)pwm_value);
    }
    

    代码说明

    1. PWM初始化:

    2. void PWM_Init():初始化 PWM 功能。

    3. TIM_HandleTypeDef htim2;:定义一个定时器句柄,用于配置和控制定时器。

    4. __HAL_RCC_TIM2_CLK_ENABLE();:启用 TIM2 定时器的时钟。

    5. htim2.Init.Prescaler = 84 - 1;:设置预分频器,将 72MHz 的时钟频率分频到 1MHz。

    6. htim2.Init.Period = 1000 - 1;:设定 PWM 周期为 1ms,即 1000 个时钟周期。

    7. 初始化定时器:

    8. HAL_TIM_PWM_Init(&htim2);:初始化定时器以支持 PWM 功能。
    9. PWM输出通道配置:

    10. TIM_OC_InitTypeDef sConfigOC;:定义 PWM 输出通道的配置结构体。

    11. sConfigOC.OCMode = TIM_OCMODE_PWM1;:设置为 PWM 模式 1。

    12. sConfigOC.Pulse = 0;:初始占空比为 0%。

    13. HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1);:配置 PWM 输出通道。

    14. 启动 PWM 通道:

    15. HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);:启动 PWM 输出通道。
    16. 设置 PWM 输出:

    17. void Set_PWM(float pwm_value):根据 PID 计算结果设置 PWM 输出。

    18. if (pwm_value > 1000.0) pwm_value = 1000.0;:限制 PWM 值在 0 到 1000 之间,确保其在可接受范围内。

    19. __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, (uint32_t)pwm_value);:设置 PWM 的占空比,以控制 TEC 的功率。

    5. 串口通信模块

    代码示例

    以下是串口通信模块的代码,用于发送当前温度和 PWM 值,便于监控和调试。

    #include "usart.h"
    
    // 初始化串口
    void USART_Init() {
        // 1. 定义串口句柄
        UART_HandleTypeDef huart1;
    
        // 2. 启用USART1时钟
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE(); // 使能GPIOA时钟
    
        // 3. 配置GPIO引脚
        GPIO_InitTypeDef GPIO_InitStruct;
        GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10; // TX和RX引脚
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用推挽输出
        GPIO_InitStruct.Pull = GPIO_NOPULL; // 无上下拉
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; // 高速
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
        // 4. 配置USART参数
        huart1.Instance = USART1;
        huart1.Init.BaudRate = 9600; // 波特率
        huart1.Init.WordLength = UART_WORDLENGTH_8B; // 8位数据位
        huart1.Init.StopBits = UART_STOPBITS_1; // 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; // 16倍过采样
        HAL_UART_Init(&huart1); // 初始化UART
    }
    
    // 发送数据通过串口
    void USART_Send(float temperature, float pwm_value) {
        char buffer[100];
        int len = sprintf(buffer, "Current Temp: %.2f °C, PWM Value: %.2f\r\n", temperature, pwm_value); // 格式化字符串
        HAL_UART_Transmit(&huart1, (uint8_t *)buffer, len, HAL_MAX_DELAY); // 发送数据
    }
    

    代码说明

    1. 串口初始化:

    2. void USART_Init():该函数用于配置和初始化串口。

    3. UART_HandleTypeDef huart1;:定义一个串口句柄,用于管理 USART1 的配置。

    4. 启用时钟:

    5. __HAL_RCC_USART1_CLK_ENABLE();:使能 USART1 时钟。

    6. __HAL_RCC_GPIOA_CLK_ENABLE();:使能 GPIOA 时钟,用于串口引脚配置。

    7. 配置 GPIO 引脚:

    8. GPIO_InitTypeDef GPIO_InitStruct;:定义 GPIO 初始化结构体。

    9. GPIO_InitStruct.Pin = GPIO_PIN_9 | GPIO_PIN_10;:TX(发送)和 RX(接收)引脚的配置。

    10. GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;:设置引脚为复用推挽输出模式。

    11. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);:初始化 GPIO 引脚。

    12. 配置 USART 参数:

    13. huart1.Init.BaudRate = 9600;:设置波特率为 9600。

    14. huart1.Init.WordLength = UART_WORDLENGTH_8B;:数据位长度为 8 位。

    15. huart1.Init.StopBits = UART_STOPBITS_1;:设置 1 位停止位。

    16. huart1.Init.Parity = UART_PARITY_NONE;:设置无奇偶校验。

    17. HAL_UART_Init(&huart1);:根据配置初始化 USART1。

    18. 发送数据:

    19. void USART_Send(float temperature, float pwm_value):该函数用于通过串口发送当前温度和 PWM 值。

    20. char buffer[100];:定义字符数组用于存储发送的数据。

    21. int len = sprintf(buffer, "Current Temp: %.2f °C, PWM Value: %.2f\r\n", temperature, pwm_value);:格式化输出字符串。

    22. HAL_UART_Transmit(&huart1, (uint8_t *)buffer, len, HAL_MAX_DELAY);:通过 USART 发送数据。

    作者:极客小张

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32高精度PID温控系统设计与实现:Pt1000温度传感器与PWM控制技术的深度应用

    发表回复