一乐电子

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
查看: 3191|回复: 6

PID C语言

[复制链接]
发表于 2014-3-19 21:59 | 显示全部楼层 |阅读模式
PID算法(c 语言)
; R8 Z  A) ]1 P! T+ `: ^1 `# K" }#include <stdio.h> 9 C: O) u) t( A0 t& |
#include<math.h> 0 X( }- L7 X. l
//定义PID 的结构体
0 ]9 W% O8 L1 ystruct _pid
5 `. _' Z/ B6 V( ]{
+ ^  F6 d+ y3 G8 `, iint pv; //integer that contains the process value 过/ j* N5 x+ c2 q- H: u, A% b1 l1 h
程量 ) P/ P# [/ L1 Q# `: J  ]
int sp; //*integer that contains the set point   设7 l$ F. W2 _* Z5 {: V2 p# h
定值
% K7 h8 S0 o9 v' L( R7 s. @float integral; // 积分值 -- 偏差累计值 ) j0 R! E9 f5 ?8 o
float pgain; ' J1 J* e' I$ ~
float igain; ; {0 P1 b' w) g2 y" J5 `6 x/ x/ V) \
float dgain; ! q% Y, u1 J; [; o; j9 y: j
int deadband;    //死区
' m* w% ~6 V. E9 _- y7 F% v: X0 o& Hint last_error;
& F0 ^( O: I0 s% X}; ; b$ n( d' `7 T) \5 ]
" J* t3 A( r5 x% T
struct _pid warm,*pid; 8 `% `0 T( ]5 z- E0 j
int process_point, set_point,dead_band; float p_gain, i_gain, d_gain,
8 ~1 d1 S1 d% i5 {integral_val,new_integ;;
+ B% }( Q. [( U' U6 I) k
. h8 L4 Q" U/ n; Y//------------------------! c. s  c/ m: P9 ]6 S9 o3 v: L
---------------------- ) o) O) G) E3 d" ]* ~+ q
pid_init DESCRIPTION This function initializes the * H7 y% _9 m$ ?" D5 h$ H
pointers  in  the  _pid  structure  to  the  process  variable 2 y3 r! M  L' C! N$ J' U# |
and the setpoint. *pv and *sp are integer pointers. 8 r+ Z& s" f- M7 g' @
//------------------------8 @+ k( C/ }" ~; ~# ]/ H3 {
----------------------
$ }6 E2 e: g! w' m4 G4 |# z$ M$ H3 J5 Y8 s, U' j
void pid_init(struct _pid *warm, int process_point, 2 }; H1 o) W# e3 i) o  G
int set_point) ; ?+ R% n7 q, o( m! z8 M
{ ; X6 [5 J# v+ @9 A$ u
struct _pid *pid; + a2 r  a4 r* T0 R
pid = warm; ' ?: w, c. H4 Q
pid->pv = process_point;
  ?* f! a2 L+ g2 c2 a2 Zpid->sp = set_point; ; t7 N' o( E( x- M
}
7 m! P: K6 Z3 v9 ~9 e8 H" X
6 L& F% w% A' s//------------------------
  B8 c. c$ f& Z  N$ }' t----------------------pid_tune DESCRIPTION Sets the proportional gain
7 n# I# H9 N/ H3 Q" d  J(p_gain), integral gain (i_gain),
. ]# B1 x. X, K0 y5 Z4 I3 O/ Oderivitive  gain  (d_gain),  and  the  dead  band  (dead_band) 7 f" {1 R, u; a! ^% |5 A4 g
of a pid control structure _pid.  
6 T7 A) s6 \. g# t# G" \
) S* \: S( m: P) k0 D& ^6 b设定PID参数 ---- P,I,D,死区
1 I$ [  }2 H% L! ]7 C: C//------------------------
: c& g* R& q! l; p! [+ U---------------------- 8 M: R4 \. X8 z2 q% j
; B2 ^* L& h; }+ O
void pid_tune(struct _pid *pid, float p_gain, float
" A& @& j& |) G5 Ci_gain, float d_gain, int dead_band) ' |% r/ [# Z$ A( l3 @
{ ! ~" u/ ~( b" Q# N
pid->pgain = p_gain;
7 r, W( d7 U, s8 h% wpid->igain = i_gain; ( g# v5 h% w) M3 ~% {
pid->dgain = d_gain;
* }5 J* n5 |: g0 n( v& g/ xpid->deadband = dead_band;
9 ]9 R$ H+ ~, J8 hpid->integral= integral_val; * a* _0 W0 O. G$ u- m
pid->last_error=0;
4 L- X7 H0 l" i7 B4 G$ _2 o" M}
+ F: g" ~' b( F
3 z4 W4 b: {2 G5 E. M, \( \//------------------------
3 U2 n  }6 r3 H3 f8 l---------------------- pid_setinteg DESCRIPTION Set a new value for the 3 C1 }2 K( f  u0 d2 M0 p0 I) ?' s2 B
integral term of the pid equation.
9 ]) P$ S3 h' z3 |; A- NThis is useful for setting the initial output of the
; }/ ]# |) w" W8 n6 epid controller at start up.
' E) {, Z* `3 c
' P. v6 ~! }1 V. N" i, K; `, q+ t! r设定输出初始值 ; Y1 r5 c0 Y! k
//------------------------
8 A! f2 g. W3 k7 i$ P9 m/ x----------------------
6 B' J6 m1 y/ u0 U  O/ Z& a& Z$ {1 A4 a5 @
void pid_setinteg(struct _pid *pid,float new_integ)
" C2 s$ i6 L# ^$ A) h! `" q{
% ?' J& ~- Z( A' {. i' p. n9 Tpid->integral = new_integ; 3 R( [( p4 v% r2 t" ]
pid->last_error = 0; 6 k9 H( |) ]" N& q& A1 g
}
( N" y, i! _: w: |3 L$ O1 p# ]! q6 I2 C( o/ V% \. \
//------------------------" Q. `! s/ O2 Z, x6 g: B
---------------------- " ]/ q2 I* H# t+ }' `1 t+ \$ ]
pid_bumpless DESCRIPTION Bumpless transfer 9 d' Q4 `2 l; F0 j2 ~. K9 Q
algorithim.
1 _6 J4 f* n' p7 I9 O' ]% H+ JWhen suddenly changing setpoints, or when restarting * t9 ~6 h- q# f' i/ G# r" h
the PID equation after an extended pause,
. T: z+ m/ W; d/ \  @" x* _; Xthe derivative of the equation can cause a bump in the controller output. This function will help smooth out ! x+ y  M. w) \, s) G: c
that bump.
! b% H! y( w9 a9 \, ]5 C- w. sThe process value in *pv should be the updated just   r$ m- H  y: @. a6 s
before this function is used. 4 \9 y  h( D  F
4 e6 r& A; p! p
pid_bumpless 实现无扰切换
# Y4 w+ D2 b3 j0 j: g$ V) D当突然改变设定值时,或重新启动后,将引起扰动输出。这
/ O# a$ `; E6 l+ @& h# f: n5 _2 B个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值
! t& i+ K( N. s2 i//------------------------" N6 Q8 r" n* J$ m& g
---------------------- - r. i  T; |3 G

# M: q6 x9 c! Q3 c& f( qvoid pid_bumpless(struct _pid *pid) " T! M7 |/ j  A3 I! [
{
/ N% k* j, @- n0 o  [* a9 _pid->last_error = (pid->sp)-(pid->pv);  //设定值与反馈值偏差 9 e+ d3 w; H  x9 r* K
} 8 B1 t# Q2 R* f

: {& Q" V5 {9 E3 n6 Z' V/ c3 G//------------------------( x! B$ D. z4 H" M# E9 ^* ^
---------------------- % g. U1 o6 m) s1 y
pid_calc  DESCRIPTION  Performs  PID  calculations  for  the 6 b% E! `- z+ C* x
_pid structure *a. This function uses the positional form of the pid 1 h9 z7 B) |! C. u6 x' M. V0 L
equation, and incorporates an integral windup * J% {/ M( |; p8 N
prevention algorithim.
2 L7 _1 O5 _$ lRectangular  integration  is  used,  so  this  function  must / H+ Y" P3 w! F
be repeated on a consistent time basis for accurate ! }6 b" O: Z3 K& y% V# t" q5 \4 h% w
control.
8 f( K, j3 F6 W9 _7 ?: }2 L0 pRETURN VALUE The new output value for the pid loop. # _$ n; |) X9 \& W, ]5 T
USAGE #include "control.h"
' c, X( @6 V1 K5 M' M, W( z4 ^本函数使用位置式PID计算方式,并且采取了积分饱和限制运算
5 N& G* J  ~8 z) {) |, A5 U3 Q4 aPID计算 6 m1 r9 ^/ T$ _3 h: A" N: T6 r0 S
//------------------------
# E6 {+ `/ K' f7 Y: Y---------------------- 3 F9 o+ o" I* J! d6 C' T, g
- z* J; E$ [( o% @6 O. K6 D
float pid_calc(struct _pid *pid) : G9 m' }& C* K) M; Y5 W2 M

, E+ v8 w! L8 Yint err;
/ v5 e% o0 O) y. {# b% J1 Ufloat pterm, dterm, result, ferror;   y% B+ k. v6 f# T# M

" d+ A4 w# r3 b& v# {& T6 U& j// 计算偏差 " u/ C1 A5 ~, Q7 _& R
err = (pid->sp) - (pid->pv);
9 y4 E5 c. J& R9 r! ?4 B // 判断是否大于死区 ( R5 g: W; `9 M4 N6 U8 D
if (abs(err) > pid->deadband) ) c2 z' A3 v9 C5 F) ^
{ 2 G1 X6 Z. v5 `. x% b; A
ferror = (float) err;   //do integer to float 4 J' N% u2 W: M# X% |! B: y% X5 m
conversion only once 数据类型转换
7 _' d- Y$ b0 R& _" \$ ^$ Y; o: n& N7 l
// 比例项
3 _# y+ x" ~+ g! v$ F0 Kpterm = pid->pgain * ferror;
- r7 e  Y# d: \1 |6 X, O9 f8 a% g+ s
9 d& u) v! z( z8 ]# H+ ^% vif (pterm > 100 || pterm < -100)
! ?) H' o! T6 @- k- z{
8 J6 Z" s0 N; h. D; kpid->integral = 0.0;
9 m8 ?! @* a4 X1 U}
5 X( I8 X$ ?3 }- C. W6 delse
  U7 E+ a3 X: m; [6 T) _. _5 L{ 9 i1 g: Z; C1 Q
// 积分项 : U+ _+ V( l0 S% K
pid->integral += pid->igain * ferror;
; Q) i+ \& X3 s" e/ b& }! t% [8 [3 D: A1 S  o0 e9 t9 `
// 输出为0--100% 9 ^' Z7 k/ `: ?
// 如果计算结果大于100,则等于100 4 [$ X  L2 a/ e; \4 A" g8 B
if (pid->integral > 100.0) & Y8 [! T4 Z  e. u5 O. K' z" D
{ pid->integral = 100.0;
! K! R' }& H7 ^8 A+ K' y. S}
% t5 p* U5 B# T! G// 如果计算结果小于0.0,则等于0
) O+ o3 Z" J6 A, k; p9 V' @else if (pid->integral < 0.0)
, v8 e+ {. K! f( M: [9 rpid->integral = 0.0; & `, D; }' j- D  r# Q& e
$ K( u/ u% T  [4 l: l' t
} ) @% X. w' k) w2 Q

9 a( {& `% k/ h2 G5 b- U/ [1 c// 微分项
. q) H( R0 c' a. g4 Kdterm  =  ((float)(err  -  pid->last_error))  *  pid->dgain; - t6 c/ ?% x& f0 \+ u6 o
$ C. u1 R0 w1 P  I
result = pterm + pid->integral + dterm;
; e/ K7 t2 \. b9 j' P}
$ o: U2 a8 A: ielse " G/ ^5 T8 z: l% s- r) ~
result = pid->integral; // 在死区范围内,保持现有输出
6 g2 t3 W! S; j) G" {. K, @) ^' e6 u: C! A$ a& L& L
// 保存上次偏差 ; Q8 [1 |6 A- m) ?8 }& o
pid->last_error = err;
- r0 O% p2 \$ ?* w
- U: ~. O0 p6 f6 {& o  H% V// 输出PID值(0-100) : |" H) }1 D; |( l5 s% g% s" n
return (result); }
5 M2 {- \/ F+ p7 l+ w+ q% O: a) q$ J1 p: ?# F
//------------------------
1 c' J8 o! F8 F7 r----------------------
0 E9 g' Q( ~5 Z; Y( Mvoid main(void)
2 E% F4 M+ n" k- w( t. D. ^# o{
) I1 c) M; [5 x5 l( p. Lfloat display_value;
( v+ |- s+ x  x4 V! rint count=0;
- w8 D, A* i' qpid = &warm; ( C; W; g7 J. j% W2 [) a
( O4 H( I2 ^) K' c9 c
// printf("Enter the values of Process point, Set
' W1 ]$ n/ N& T; jpoint, P gain, I gain, D gain \n"); 6 ^1 ~& M# o- [. Z: u3 `! Y
// scanf("%d%d%f%f%f", &process_point, &set_point,
0 z0 B" B5 L# L* S4 }&p_gain, &i_gain, &d_gain);   O+ a: C; \5 B4 `0 T4 O. [; |
2 T( k# [2 ^5 M* T. Q
// 初始化参数 ' z/ a/ @# U3 I
process_point = 30;
- x5 @5 w! q0 R& ^/ x' hset_point = 40; ) U1 u7 l7 [! |
p_gain = (float)(5.2);
5 B) h+ r, k* \i_gain = (float)(0.77);
) S  _* ]0 K2 ~% ad_gain = (float)(0.18); ; b8 L. M' K- m9 i6 |* _( ]2 p
dead_band = 2;    i  I' ]: ?0 \! I& j
integral_val =(float)(0.01);
8 m" o5 T' j4 Q* q# @$ G7 _; B
2 h) P, Y+ C' f3 e* kprintf("The  values  of  Process  point,  Set  point,  P  gain,
" ^4 C( }) S" U7 a1 A0 UI gain, D gain \n");
  k" C8 \- I- [+ [+ J; p  S  }) Tprintf(" %6d %6d %4f %4f %4f\n", process_point, 4 H' ]" o- I) y3 O: U
set_point, p_gain, i_gain, d_gain); 7 Y5 T* Z! j0 w& I" d
printf("Enter the values of Process point\n"); & G) Q; U  N, R: ]
while(count<=20)
& B) n" Z5 u6 P: _3 G3 @{ ; F9 H  U* @8 y  P' X
scanf("%d",&process_point); 5 D* y% \" @5 ^! F3 G3 }
7 k. E9 S& R% H! h% ]4 y0 ]
// 设定PV,SP 值 + h! @) y% v5 E  c3 x. }' _" |
pid_init(&warm, process_point, set_point); ( x2 k! w& e- I5 g! t, `

; u4 X- f& Y' K) a8 `5 _+ ~5 k: I// 初始化PID 参数值
8 ^& S2 |  l6 L; q+ }$ qpid_tune(&warm, p_gain,i_gain,d_gain,dead_band); 8 W' P* W1 h8 Q' A% R  B) H, K
+ \0 O' W' k" S
// 初始化PID 输出值 ! |  ~2 g* [" R: y; \) c. A
pid_setinteg(&warm,0.0); 9 x, N/ e- H# }* o
//pid_setinteg(&warm,30.0);
9 H! ~, w( j) R% Y9 ]& E# O. Q //Get input value for process point % _0 p1 M, t2 J% N# _5 V$ \
pid_bumpless(&warm); 5 ^* m" g4 s* F  E
: t$ P4 O5 V( N5 c# [* O
// how to display output . R9 q. t) V% {, E8 I8 o
display_value = pid_calc(&warm); * n2 l% d' J# H0 m  j
( ^# D  a+ j7 x) D( ^3 D  R
printf("%f\n", display_value);
5 i" n4 Z6 F; s! R& X1 _//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa
( D& t( l% l* d% A: _8 jrm.dgain); 3 V) g  \6 V7 S+ s5 n2 ~
% A8 O% M- v0 R5 }
count++; ) i9 W3 J% K6 E; J( y
} ; p3 a. v# u8 F. `4 l) p
}2 B$ L9 w, Z( j& }9 b& m

) B+ {1 m0 L$ j2 v0 U# {
发表于 2014-3-19 22:11 | 显示全部楼层
版主,这个更是针对什么设备的?是不是要根据不同的设备来制定不同的PID算法?比如驱动两个电炉,一个功率1000w,另一个2000w,在相同的控制温度下,同一个PID处理程序,温度的变化曲线就相差很大。
回复

使用道具 举报

 楼主| 发表于 2014-3-19 22:13 | 显示全部楼层
在电子数字计算机直接数字控制系统中,PID控制器是通过计算机PID控制算法程序实现的。计算机直接数字控制系统大多数是采样-数据控制系统。进入计算机的连续-时间信号,必须经过采样和整量化后,变成数字量,方能进入计算机的存贮器和寄存器,而在数字计算机中的计算和处理,不论是积分还是微分,只能用数值计算去逼近。 在数字计算机中,PID控制规律的实现,也必须用数值逼近的方法。当采样周期相当短时,用求和代替积分,用差商代替微商,使PID算法离散化,将描述连续-时间PID算法的微分方程,变为描述离散-时间PID算法的差分方程。算法中,为了求和,必须将系统偏差的全部过去值e(j)(j=1,2,3,... ,k)都存储起来。这种算法得出控制量的全量输出u(k),是控制量的绝对数值。在控制系统中,这种控制量确定了执行机构的位置,例如在阀门控制中,这种算法的输出对应了阀门的位置(开度)。所以,将这种算法称为“位置算法”。当执行机构需要的不是控制量的绝对值,而是控制量的增量(例如去驱动步进电动机)时,需要用PID的“增量算法”。已看不出是PID的表达式了,也看不出P、I、D作用的直接关系,只表示了各次误差量对控制作用的影响。数字增量式PID算法,只要贮存最近的三个误差采样值e(k)、e(k-1)、e(k-2)就足够了。4 w$ b8 B1 \4 S; c; q! M' W
回复

使用道具 举报

 楼主| 发表于 2014-3-19 22:15 | 显示全部楼层
好多是在网上找的,我也在学习当中。
回复

使用道具 举报

发表于 2014-3-19 22:18 | 显示全部楼层
保留,这个应该好好理解
回复

使用道具 举报

发表于 2014-3-20 09:29 | 显示全部楼层
8055 发表于 2014-3-19 22:111 t9 m- N1 |6 y
版主,这个更是针对什么设备的?是不是要根据不同的设备来制定不同的PID算法?比如驱动两个电炉,一个功率1 ...

) B9 K8 ^9 s2 Q  W( ]用同一个PID算法没问题,但要处理好PID参数,比如热容量差不多的情况下,两个设备的P参数要差一倍左右。
" G  `4 |/ ]# L* b
回复

使用道具 举报

发表于 2014-3-20 10:26 | 显示全部楼层
收藏学习中、、、
回复

使用道具 举报

本版积分规则

QQ|一淘宝店|手机版|商店|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2026-4-17 18:21 , Processed in 0.035246 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表