不讲原理 位置式PID控温实例 实战 (NTC温度采集代码加PID控温代码)

【本文发布于https://blog.csdn.net/Stack_/article/details/130532003,未经允许不得转载,转载须注明出处】


每篇PID文章都长篇大论数学原理,就是不教你怎么代码实现。理论是需要和实践相结合的,只看不做是学不会的。

此代码在STC8H上运行,摒弃了浮点运算,若是在32位单片机上,可根据需要改为浮点以提高精度

此代码能在我的加热器上将温度误差控制在1℃以内,如果需要达到更高的精度需要花更多时间调参数。



【PID控温简单实现代码】


在这里插入图片描述






一、NTC温度采集


1、根据热敏电阻厂家提供的 阻值-温度 对照表计算出各温度下对应的理论AD值,并制表


#ifndef __NTC_LIST_H__
#define __NTC_LIST_H__

//CSDN@Tyrion.Mon
//12位ADC,10K电阻分压,10K电阻在VCC端,5V电压
code unsigned int ntc_ad_list[] = 
{
    /*0℃ - 9℃*/
    3102, 3065, 3027, 2989, 2950, 2910, 2870, 2829, 2788, 2746,
    /*10℃ - 19℃*/
    2704, 2661, 2619, 2585, 2541, 2497, 2452, 2407, 2362, 2317,
    /*20℃ - 29℃*/
    2272, 2227, 2182, 2137, 2092, 2048, 2003, 1959, 1915, 1871,
    /*30℃ - 39℃*/
    1828, 1785, 1743, 1701, 1660, 1619, 1579, 1539, 1500, 1461,
    /*40℃ - 49℃*/
    1423, 1386, 1349, 1313, 1278, 1244, 1210, 1176, 1144, 1112,
    /*50℃ - 59℃*/
    1081, 1051, 1021,  992,  964,  936,  912,  886,  861,  836,
    /*60℃ - 69℃*/
     812,  789,  767,  745,  723,  703,  683,  663,  644,  625,
    /*70℃ - 79℃*/
     607,  590,  573,  557,  541,  525,  510,  496,  481,  468,
    /*80℃ - 89℃*/
     454,  441,  429,  417,  405,  394,  382,  372,  361,  351,
    /*90℃ - 99℃*/
     341,  332,  323,  314,  305,  297,  288,  281,  273,  265
};



#endif

2、根据AD值查表并插值计算出温度值


#ifndef __NTC_H__
#define __NTC_H__

#include "public.h"
    
extern uint8_t xdata ntc_exist;
extern uint16_t xdata ntc_temp;
extern uint8_t xdata ntc_shortcut;

void ntc_proc(void);

#endif

/**
  ******************************************************************************
  * @copyright
  * @file      
  * @author    CSDN@Tyrion.Mon
  * @version
  * @date      
  * @brief
  ******************************************************************************
  * @attention     files encoding : GB2312
  *                      文件编码 :GB2312
  ******************************************************************************
  */
 #include "ntc.h"
 #include "ntc_list.h"

uint8_t xdata ntc_exist = 0;
uint16_t xdata ntc_temp;    //一位小数
uint8_t xdata ntc_shortcut = 0;

/**
  * @brief  
  * @note   
  * @param
  * @retval
  * @author PWH //CSDN@Tyrion.Mon
  * @date   2023/2
  */
void ntc_proc(void)
{
    uint16_t xdata i, j;

    ntc_exist = 1;
    ntc_shortcut = 0;
    
    if (ad_val > 3800)  //ntc电阻不存在
    {
        ntc_exist = 0;
    }
    if (ad_val < 20)  //ntc电阻短路
    {
        ntc_shortcut = 1;
    }

    if (!ntc_exist || ntc_shortcut)
    {
        ntc_temp = 0;
        return;
    }
    
    if (ad_val >= ntc_ad_list[0])
    {
        ntc_temp = 0;
    }
    else if (ad_val <= ntc_ad_list[sizeof(ntc_ad_list) / 2 - 1])
    {
        ntc_temp = 990; //99度
    }
    else
    {
        for (i = 0; i < sizeof(ntc_ad_list) / 2 - 1; i++)   //查表
        {
            if (ad_val == ntc_ad_list[i])
            {
                ntc_temp = i * 10;
                break;
            }
            else if (ad_val == ntc_ad_list[i + 1])
            {
                ntc_temp = (i + 1) * 10;
                break;
            }
            else if (ad_val < ntc_ad_list[i] && ad_val > ntc_ad_list[i + 1])	//落在中间,将两点之间视为直线,进行插值
            {
                /*将 i 和 i+1 两点间视为直线,分为10段对应小数0-9*/
                for (j = 1; j < 10; j++)
                {
					ntc_temp = i * 10 + j;
                    if (ad_val >= ntc_ad_list[i] - (ntc_ad_list[i] - ntc_ad_list[i + 1]) * j / 10)
                    {
						return;
                    }
                }
				break;
            }
        }
    }

}






二、PID控温


需要根据实际的加热器对参数进行修改,例如 P、I、D系数积分限幅值温度补偿值开启PID控温的温度区间,在升温速度和超调之间取得一个平衡。


#ifndef __PTC_H__
#define __PTC_H__

#include "public.h"


typedef struct {
    int16_t pid_set_temp;          //设置温度
    int16_t pid_now_temp;          //现在温度
    int16_t pid_err_last;          //上次误差
    int16_t pid_err;               //误差
    int16_t pid_err_sum;           //历史误差和
    int16_t pid_result;
} PID_Para_t;

extern xdata PID_Para_t    PID_Para;



extern uint8_t timer_ptc; 
    
void ptc_proc(void);
void pid_init(void);

#endif


/**
  ******************************************************************************
  * @copyright
  * @file      
  * @author    //CSDN@Tyrion.Mon
  * @version
  * @date      
  * @brief
  ******************************************************************************
  * @attention     files encoding : GB2312
  *                      文件编码 :GB2312
  ******************************************************************************
  */
 #include "ptc.h"

#define TEMPERATURE_COMPENSATION    1   //1:开启温度补偿
 
#define Kp          100       //比例常数  100倍值    100即1
#define Ki          18       //积分常数  100倍值   18即0.18
#define Kd          10       //微分常数  100倍值    90即0.9

#define I_MAX         2500
#define I_MIN         0



xdata PID_Para_t    PID_Para;


/**
  * @brief  
  * @note   
  * @param
  * @retval
  * @author PWH //CSDN@Tyrion.Mon
  * @date   2023/2
  */
void pid_init(void)
{
    PID_Para.pid_set_temp = 30;
    PID_Para.pid_err_last = 0;
    PID_Para.pid_err_sum = 0;
}

/**
  * @brief  位置式PID
  * @note   
  * @param
  * @retval
  * @author PWH //CSDN@Tyrion.Mon
  * @date   2023/2
  */
void pid(void)
{
    int16_t xdata P, D;
    
    PID_Para.pid_err = PID_Para.pid_set_temp - PID_Para.pid_now_temp;   //当前误差
    
    P = PID_Para.pid_err * Kp;  //比例量   P
    
    PID_Para.pid_err_sum += PID_Para.pid_err * Ki;  //积分量      I
    if (PID_Para.pid_err_sum > I_MAX) PID_Para.pid_err_sum = I_MAX;       //积分限幅 
    else if (PID_Para.pid_err_sum < I_MIN) PID_Para.pid_err_sum = I_MIN;
    
    D = (PID_Para.pid_err - PID_Para.pid_err_last) * Kd;    //微分量      D
    
    PID_Para.pid_err_last = PID_Para.pid_err;
    
    #if (1)
    PID_Para.pid_result = (P + PID_Para.pid_err_sum + D) / 100;
    #else
    PID_Para.pid_result = (P + D) / 100;
    #endif
    if (PID_Para.pid_result > 100) PID_Para.pid_result = 100;	//占空比 0-100
    else if (PID_Para.pid_result < 0) PID_Para.pid_result = 0;
}

uint8_t timer_ptc = 0;	//定时器中断10ms递增
/**
  * @brief  
  * @note   
  * @param
  * @retval
  * @author PWH //CSDN@Tyrion.Mon
  * @date   2023/2
  */
void ptc_proc(void)
{
    uint16_t xdata temperature_now;
    uint16_t xdata target;
    static uint8_t xdata timer = 0;
    #if (TEMPERATURE_COMPENSATION == 1)
    uint8_t xdata compensation; //补偿温度,陶瓷表面温度比热敏电阻处高,加温目标需要比设置的低
    #endif
    
    if (!timer_ptc) return;	//每10ms执行一次
    
    timer_ptc = 0;

    if (ntc_exist)
    {
        #if (TEMPERATURE_COMPENSATION == 1)
        switch (app_para.target)	//app_para.target 目标温度无小数
        {
            case 30: compensation = 0; break;   //一位小数  eg. 33=3.3℃
            case 33: compensation = 0; break;
            case 37: compensation = 0; break;
            case 40: compensation = 0; break;
            case 43: compensation = 5; break;
            case 47: compensation = 5; break;
            case 50: compensation = 12; break;
            case 53: compensation = 15; break;
            case 57: compensation = 11; break;
            case 60: compensation = 16; break;
            case 65: compensation = 21; break;
        
            default: break;
        }
        #endif

        temperature_now = ntc_temp;
        
        #if (TEMPERATURE_COMPENSATION == 1)
        target = app_para.target * 10 - compensation;
        #else
        target = app_para.target * 10;
        #endif

        if (temperature_now < target - 5)   //达到目标温度-0.5℃前全速加热
        {
            Pin_Heater_Ctrl = HEATER_ON;    //
        }
        else if (temperature_now > target + 1 * 10) //超出设置值1℃时全关
        {
            Pin_Heater_Ctrl = HEATER_OFF;
        }   
        else    //PID控制
        {   //设定加热周期为1000ms,1000分之PID_Para.pid_result毫秒开加热器
            if (timer_ptc >= PID_Para.pid_result)
            {
                Pin_Heater_Ctrl = HEATER_OFF;
            }
            else
            {
                Pin_Heater_Ctrl = HEATER_ON;
            }
            
            if (++timer > 100)	//100 * 10ms = 1000ms周期
            {
                timer = 0;
                PID_Para.pid_set_temp = target;
                PID_Para.pid_now_temp = temperature_now;
                pid();
            }
        }
    }
    else
    {
        Pin_Heater_Ctrl = HEATER_OFF;
    }
    
    
    
    
}





  • 7
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: NTC温度采集模块是一种使用热敏电阻作为温度传感器的模块,它可以在不同的环境温度采集到相应的电阻值,并通过微控制器进行转换,最终转化为温度值。下面是一份NTC温度采集模块的源代码,可以供参考: ``` #include <stdio.h> //定义一些必要的变量 float ADC_voltage; //定义模拟输入电压变量 float ADC_resolution = 5.0/1024; //定义ADC分辨率,单位为V/bit float ref_R = 10000; //定义电路中的参考电阻为10kΩ float R1 = 10000; //定义NTC串联电阻为10kΩ //函数-读取模拟电压 float read_ADC_voltage() { int ADC_value; //定义模拟输入值变量 float ADC_voltage; //定义模拟输入电压变量 ADC_value = analogRead(A0); //从A0模拟口读取模拟输入值 ADC_voltage = ADC_value * ADC_resolution; //将模拟输入值转换成电压 return ADC_voltage; //返回模拟输入电压 } //函数-计算NTC阻值 float calc_R_ntc(float Vout) { float R_ntc; //定义NTC电阻变量 R_ntc = (Vout * R1) / (5 - Vout); //计算NTC电阻值 return R_ntc; //返回NTC电阻值 } //函数-计算NTC温度 float calc_T_ntc(float R_ntc) { float T_ntc; //定义NTC温度变量 float k = 3950; //定义NTC热敏参数为3950 T_ntc = 1 / ((1/298.15) + (1/k) * log(R_ntc/ref_R)); //计算NTC温度 return T_ntc; //返回NTC温度 } void setup() { Serial.begin(9600); //初始化串口通讯 } void loop() { ADC_voltage = read_ADC_voltage(); //读取模拟输入电压 float R_ntc = calc_R_ntc(ADC_voltage); //计算NTC电阻值 float T_ntc = calc_T_ntc(R_ntc); //计算NTC温度值 Serial.print("NTC电阻值:"); //输出NTC电阻值 Serial.print(R_ntc); Serial.print("Ω,NTC温度值:"); //输出NTC温度值 Serial.print(T_ntc); Serial.println("℃"); delay(1000); //延时1秒,间隔采集 } ``` 这份代码主要通过模拟口A0读取模拟输入电压,并通过计算得到NTC电阻值和NTC温度值,最终通过串口输出给上位机。在使用过程中,需要注意电路中的参考电阻和NTC串联电阻的数值,以及NTC热敏参数的正确设置,才能得到准确的温度采集结果。 ### 回答2: NTC温度采集模块源代码通常由两部分组成:硬件驱动代码温度采集控制代码。 硬件驱动代码主要是针对硬件进行操作的代码,包括IO口的配置、定时器的设置、ADC模块的初始化和配置等等。在这部分代码中,需要根据具体的硬件类型和接口规范进行编写,以确保能够与NTC温度采集模块正常通讯。 温度采集控制代码主要是针对NTC温度传感器进行操作的代码。这部分代码一般包含了温度转换函数、温度采集周期控制函数、温度算法函数等。温度转换函数用于将传感器采集到的电压值转换为具体的温度值,采集周期控制函数用于控制温度采集的频率和间隔时间,温度算法函数则用于进行温度补偿、温度校准等处理。 在具体编写NTC温度采集模块源代码时,需要根据实际采集场景考虑相应的硬件和软件设计方案,以确保温度数据的准确性和稳定性。同时,还需要进行充分的测试和验证,以保证源代码的可靠性和稳定性。 ### 回答3: NTC温度采集模块是一种应用广泛的温度测量设备,其源代码通常由C语言编写。下面是一段可能的NTC温度采集模块源代码: ```c #include <stdio.h> #include <math.h> float calculate_ntc_temperature(float Rntc, float Rref, float B) { // Calculate temperature using Steinhart-Hart equation float T0 = 25.0; // Reference temperature float K0 = 273.15; // Absolute zero temperature float r_inf = Rref * exp(-B / T0); // Resistance at reference temperature float t = (B / log(Rntc / r_inf)) - K0; // Temperature in Celsius return t; } int main() { float Rntc = 1000.0; // NTC resistance in ohms float Rref = 10000.0; // Reference resistance in ohms float B = 3950.0; // Beta value for NTC float temperature = calculate_ntc_temperature(Rntc, Rref, B); printf("NTC temperature: %.2f C\n", temperature); return 0; } ``` 该程序定义了一个名为calculate_ntc_temperature的函数,该函数的输入参数是NTC电阻值Rntc、参考电阻值Rref和Beta值B,输出参数为计算得到的温度值。该函数的计算方法基于Steinhart-Hart方程,旨在将给定电阻值转换为温度值。main函数则定义了一些用于测试calculate_ntc_temperature函数的变量,并将计算得到的温度值输出到控制台窗口。需要注意的是,实际使用中,该源代码将会与其他代码一起编写为一个完整的程序,并通过外部硬件设备读取NTC电阻值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值