不讲原理 位置式PID控温实例 实战 (NTC温度采集代码加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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

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

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
******************************************************************************
* @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;
}
}
}

}

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92

 


二、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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
******************************************************************************
* @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;
}




}

 


————————————————

本文章为CSDN博主Tyrion.Mon原创,未经博主允许不得转载,转载请附上原文链接以及本版权信息。

原文链接:https://blog.csdn.net/Stack_/article/details/130532003

posted @ 2024-08-17 15:32  苍月代表我  阅读(254)  评论(0)    收藏  举报