一乐电子

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

QQ登录

只需一步,快速开始

微信扫码登录

搜索
查看: 2682|回复: 6

PID C语言

[复制链接]
发表于 2014-3-19 21:59 | 显示全部楼层 |阅读模式
PID算法(c 语言); g/ ~8 G0 q9 h0 A4 L; E; Y6 v9 U# o
#include <stdio.h> " w# d3 U* G! h
#include<math.h>
9 G6 ~) A  T% y& K2 o- `+ z* W//定义PID 的结构体 & L9 Y$ |- S* p' `8 @) s
struct _pid 7 U, w0 m  S/ n- Y" W
{ , N1 Y2 }' x! H+ N! ^4 P
int pv; //integer that contains the process value 过
6 T' \( F6 P7 N5 [# `  f程量
" B0 u, Y1 W. t! Nint sp; //*integer that contains the set point   设3 J6 Y+ N4 p5 u# l7 t7 ~; i
定值 5 E4 _4 ~$ K: V/ K
float integral; // 积分值 -- 偏差累计值 - G/ v5 Q; F4 X' W
float pgain; , }2 k: g% I! G  W+ w" z
float igain;
1 q0 [  P: ~. a. I) n' L- {float dgain; " _) X; p1 l. F8 z
int deadband;    //死区
6 `# u2 v0 E1 a. P# k+ @& Xint last_error;
6 ?/ `3 I; s) I3 C};
* [! |6 D" i# x. i) G5 L" b8 q+ x, ~4 F" J, U! G. O
struct _pid wARM,*pid; , w7 Q. D9 u7 h2 [
int process_point, set_point,dead_band; float p_gain, i_gain, d_gain, ( q, x" B6 G; \  I7 g% O
integral_val,new_integ;;
% Z7 j4 H) n$ k6 ~/ Y; j  Z8 p6 Z7 r% h: B4 |  o* u4 s
//------------------------
" e& c0 R2 O9 r1 s----------------------   v! O+ i& @8 P: }8 ^
pid_init DESCRIPTION This function initializes the : g! |8 L5 c: A4 X
pointers  in  the  _pid  structure  to  the  process  variable ( ], v) e6 ^! C
and the setpoint. *pv and *sp are integer pointers. : U) c$ V" f1 x4 ]- X9 J
//------------------------5 p  C; u/ @9 B8 x2 }5 U( c+ D" Q" `
---------------------- ; \+ ?* B3 ?" x2 H" y
- _/ c% m# g: h6 f
void pid_init(struct _pid *warm, int process_point, . L' s2 @. `. }! {( A, T/ K- Y
int set_point) 8 U' T# Q& v3 T- P
{
1 b8 n7 l3 m: }. i6 {, istruct _pid *pid; - y" \; P/ P; x
pid = warm; & P' ?; l5 s3 y& `* J
pid->pv = process_point; . X# m5 p  D2 E: K) `# Y
pid->sp = set_point;
4 R# h  S2 U4 q: N0 S  a8 f}
/ K% J" d, E) m+ A/ o& _3 c$ E8 K& Q: s
//------------------------! p4 H5 l1 j1 P+ K! u, S8 Q
----------------------pid_tune DESCRIPTION Sets the proportional gain & L/ g3 N' a6 N2 ~! r1 [
(p_gain), integral gain (i_gain), 9 m" K& x' G6 m& c! _( @8 V
derivitive  gain  (d_gain),  and  the  dead  band  (dead_band)
* ^! J* M* J9 h: e: ]of a pid control structure _pid.  . m; y1 b: L/ k7 I& M9 ?% U

! f1 _6 {+ @8 z/ D( w) g& Q, f, |设定PID参数 ---- P,I,D,死区 ( C5 E! U9 w' I  o# p5 h
//------------------------0 T* f/ n5 D6 \$ e( P: S
---------------------- + j/ Q, X" ^5 y# H5 V/ X2 l
! a7 M1 S! C% W" b
void pid_tune(struct _pid *pid, float p_gain, float
4 @( C6 t6 e& qi_gain, float d_gain, int dead_band) 4 @- F. K% x6 J. H, g1 U# [
{
6 j/ s& E* V/ v, P0 h' |( x0 M6 Qpid->pgain = p_gain; ' |8 F3 f% w" U( P
pid->igain = i_gain; 2 U2 s( b: P# z* n8 q6 z& J
pid->dgain = d_gain;
) n$ S2 T- O/ J6 ^4 i1 O0 ppid->deadband = dead_band;
7 g- b3 V7 \3 Upid->integral= integral_val;
( B5 p& f* F) R! ]- Z1 Z6 gpid->last_error=0; " x( d9 T) N9 H8 F# F
} ; {1 W7 Z5 ~& O  I2 Q
9 ~1 ?- |) ~9 ]8 O) s  J
//------------------------
) j. j0 Y% H5 W' d: M+ f# s---------------------- pid_setinteg DESCRIPTION Set a new value for the
. N% m; ?  l$ I' V' U) Bintegral term of the pid equation. 0 z3 a/ b& k5 m; q8 C/ [! R/ h
This is useful for setting the initial output of the - a; Y* B0 c6 u& ~" |/ L
pid controller at start up.
6 F8 l) A, n; r, O. `  O/ H; i" h$ W  U+ e4 D; Y# G/ d
设定输出初始值
9 y7 I( H& x! H//------------------------
3 @. Q8 j0 W* J' M+ l2 T2 X" n5 m3 d---------------------- 3 y* F, g" C: o! N
* f+ h  T4 ^2 ]# ~
void pid_setinteg(struct _pid *pid,float new_integ)
! Y4 e8 H# W% \: M1 {) W{ ) j: c4 [8 X1 W% m7 j1 Z
pid->integral = new_integ;
( H6 x* }  r  v5 l" w' S3 Upid->last_error = 0;
- P3 u, I  Q! w  t. ^0 u} 0 |+ y5 G! b. g% M# @; B

# x# c! a/ ^; Y' X- [//------------------------
0 i4 M$ U; `) ~5 V/ e" H----------------------
- V; v6 F7 Y2 T+ s. ppid_bumpless DESCRIPTION Bumpless transfer
2 @( u* G0 J+ E( @algorithim.
4 c2 `1 t0 l$ O- O7 zWhen suddenly changing setpoints, or when restarting - _9 [2 ^7 q6 U) I
the PID equation after an extended pause,
1 q* z+ ?1 S# J% }6 p- ]the derivative of the equation can cause a bump in the controller output. This function will help smooth out
2 d8 @* l+ b! r7 X+ l8 R: z" kthat bump.
) u3 g- A3 T- Y8 }' p# c0 kThe process value in *pv should be the updated just
  T- V% s; b+ O$ E. X* d+ j: T3 O6 `before this function is used.
0 F; C# K/ B/ B) G9 `: Y
: ?% T6 {; F9 g/ O1 ]pid_bumpless 实现无扰切换 . x( J3 e6 R( q! D
当突然改变设定值时,或重新启动后,将引起扰动输出。这' |5 [4 _" {. _8 y  c6 K
个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值
2 C% j3 N2 U' b, p, j# }4 N+ N//------------------------
/ [0 w& u* C' t/ k% m9 L---------------------- * D6 u2 G+ P0 f/ `' e

, E3 R) @3 c$ V' K/ S2 z. uvoid pid_bumpless(struct _pid *pid)
8 d( M9 r# \( {/ v+ I7 @{ 7 B2 c4 d8 Q4 ]+ e% n
pid->last_error = (pid->sp)-(pid->pv);  //设定值与反馈值偏差 ' h+ {/ O. h7 p
}
2 [; H- \. K2 f3 `) z- n) w& ^3 N1 P$ |+ e# U! w: W- P
//------------------------/ h- w: Y( \# h4 f9 ^. m+ k2 y1 o/ D
---------------------- 3 c- R( f# @6 [+ p" g1 q
pid_calc  DESCRIPTION  Performs  PID  calculations  for  the : b- d0 @: P- d/ }9 Y# B
_pid structure *a. This function uses the positional form of the pid $ G/ y3 g) S* F- `
equation, and incorporates an integral windup , S" Q9 }" G2 I% @: }
prevention algorithim.
# |0 d4 {( C: P3 \8 T6 HRectangular  integration  is  used,  so  this  function  must
, u. z6 s" j1 [be repeated on a consistent time basis for accurate ) H( t4 ^+ w* s' V. }6 p
control.
& o) I( A  y! z# q. u) CRETURN VALUE The new output value for the pid loop.
: C1 R3 a: @8 K( j2 V6 iUSAGE #include "control.h" # U$ E3 a8 U! ]+ ]  o6 E
本函数使用位置式PID计算方式,并且采取了积分饱和限制运算
- z# ]* d9 Z* u. P1 |0 {PID计算 . y2 D3 B) V* z) f, l" l( C
//------------------------
- ]. l. q$ v" p! q---------------------- 5 ?: h& B1 `4 m% p6 F
$ x5 c4 q, l" j
float pid_calc(struct _pid *pid)
/ x0 H# Q4 x9 D9 [& [" P1 g* Z9 ~* K3 E. `
int err; $ G- R, n# q" J( C
float pterm, dterm, result, ferror; ! T0 S1 L; |9 N" n) z
+ [8 D+ F# \7 M
// 计算偏差
* X1 Z' `/ H8 @* I, {5 Werr = (pid->sp) - (pid->pv);
* H$ c  g8 Q* a! N- b7 r // 判断是否大于死区
* R) H8 {) e5 h8 S6 D  k4 }- Aif (abs(err) > pid->deadband)
; v) M0 t  P! Z4 a{ , h. y$ ~* V. h5 @2 Z& ~% i
ferror = (float) err;   //do integer to float
( g) P9 h5 d! t& |! Q* @conversion only once 数据类型转换 " G( `0 P' j3 j4 t

( ~1 K4 J' E) U  i// 比例项
) h. d5 y7 w! K  C( F* K$ l) B0 ypterm = pid->pgain * ferror; , u8 ^8 V7 p# W  d

6 @" `+ h0 u) _5 z8 F0 r7 Q0 rif (pterm > 100 || pterm < -100)
' m+ D! c6 a( r: j, D; S{
  y* H6 Y! w/ x! }0 @# a5 ~pid->integral = 0.0; - k: i: i5 r6 P4 R& d
}
7 R, }# A; k1 k" H: }( M, telse
2 Q. v& h' B- \  V* A. D, }5 E7 J9 H{ 3 y) ]( r+ C5 D* J3 Y: C
// 积分项 1 X. h8 X9 J- M- |9 b
pid->integral += pid->igain * ferror;
  t& ~4 P" K5 H/ L6 R- m1 g( l. N2 r" j# Z" q
// 输出为0--100%
( y( a. R$ O5 z) q// 如果计算结果大于100,则等于100
7 v. X7 Z$ S" dif (pid->integral > 100.0)
/ F- B% m3 b" y{ pid->integral = 100.0;
3 d% L) \5 _8 Z8 i% ?! B} 1 H8 }: P) t. G' J5 L
// 如果计算结果小于0.0,则等于0
0 w; t- b% u6 W; n& qelse if (pid->integral < 0.0) , I: S3 {4 O0 o( E8 V
pid->integral = 0.0;
, }6 L3 Q: A  H  x6 W7 r5 w& R5 U3 |+ s# c" |. z1 {
}
" T5 f" m$ S7 M+ j8 a0 _1 \. o  H8 w) G; p' a0 m
// 微分项
3 \# [$ @  C: b% w0 Idterm  =  ((float)(err  -  pid->last_error))  *  pid->dgain; ! L% m6 h* D! t2 z

. W9 `+ ~' a0 T$ rresult = pterm + pid->integral + dterm;
: h: g* H5 x  G1 X5 ~& u  s) N; E0 `- B}
! M. p( [) H3 N; j1 @' }: ]else 8 ~. f) C9 [1 T2 u" H
result = pid->integral; // 在死区范围内,保持现有输出 . A8 y' ~$ k( T/ v, M

% d! q  F% U' B! d0 X// 保存上次偏差 + j3 V$ f9 ^4 [( o* u+ L5 G( d
pid->last_error = err;
, O5 J8 @; U7 B  n7 k* z( _9 i1 t
9 j2 u5 ?4 w( F9 i// 输出PID值(0-100) $ C# P" _$ ]" R( F" u4 K; p1 ?* c+ G, O
return (result); } ) f: S' V  l8 w9 i3 n& c
* T; z, [: X- Q* s* {+ ^1 ^
//------------------------
* O# V) L1 J( P! ^" e" r----------------------
# E0 E' e. I* m4 ]void main(void) . h. p/ D8 r" }! W' ?7 k7 j" J0 ~' {
{ , h: N9 }, {4 U% {. O" b/ m
float display_value;
7 H% e) S* L( w+ F8 `' }int count=0; 7 W+ M8 D$ c6 Z
pid = &warm; 0 H/ a  W0 S8 v- |

2 c) @! d4 s: L8 b// printf("Enter the values of Process point, Set
, Y* L- U) R0 p) X! lpoint, P gain, I gain, D gain \n");
5 Y9 y) m" }/ j8 B. N& Q// scanf("%d%d%f%f%f", &process_point, &set_point, + \3 v7 ^. F3 ?0 M
&p_gain, &i_gain, &d_gain); : \; ~/ I9 T/ }/ L  y! G/ F
  F' @7 `. B% K* e/ P" o$ J
// 初始化参数
$ k! S, g" c+ r* R7 hprocess_point = 30; * `9 H: V- s1 y' G% B
set_point = 40; ( [0 j! G+ q4 z0 \& H1 q& q9 l
p_gain = (float)(5.2); 8 `) j6 {% x- O: T! [% j
i_gain = (float)(0.77); $ |7 Y, i& R& |5 ^' n/ o* r
d_gain = (float)(0.18); : _5 z& w: \, N. g! `. b( l
dead_band = 2;  
4 k( V9 u+ A" X" W/ Q- Aintegral_val =(float)(0.01);
! v6 e$ j3 I/ F; s5 {, s; f, u+ M+ c+ ?8 d
printf("The  values  of  Process  point,  Set  point,  P  gain, ) W) G( }* n' J% p- I# L) S- F# i
I gain, D gain \n");
- J3 T" a2 `5 _/ r  y1 T7 \printf(" %6d %6d %4f %4f %4f\n", process_point,
. D# |, H3 C" [& B6 o% Tset_point, p_gain, i_gain, d_gain);
) v5 W! `. w1 s  ]/ S) jprintf("Enter the values of Process point\n"); / M# X, Q+ r0 Y3 M/ j, u2 o& c8 o
while(count<=20) , d* A$ i+ n. \1 p9 J) N1 A1 i
{ 5 G. u+ v: Z# X0 F$ W% ^5 d/ K
scanf("%d",&process_point);
  G3 Y! d. r/ q( i. e: R( o, G% l- {: q4 a
// 设定PV,SP 值
6 t- j; [4 U5 Dpid_init(&warm, process_point, set_point);
: C6 ]% K% }6 o* `* n9 K; ^. _. K. B* I; q' T
// 初始化PID 参数值
8 t5 L0 t( O1 v- d4 j: v: Dpid_tune(&warm, p_gain,i_gain,d_gain,dead_band); 7 p2 a" U. f3 C3 C) r
; P! B, A: a1 d4 A. {
// 初始化PID 输出值 6 e4 t5 Y& ?- v$ \" }( m
pid_setinteg(&warm,0.0);   m+ a7 U1 v# N  {0 R5 d
//pid_setinteg(&warm,30.0);
$ m6 f( V0 @' A  ^) J6 Y; U8 T3 _ //Get input value for process point
( i% ^; W, Y0 b/ R3 k, o, j# E( |: Gpid_bumpless(&warm);
% @: ^& v/ z. ?. D; [# `% d+ o
5 M8 g3 p1 e# [3 B5 [& a8 T& u; c// how to display output
! ^( Z2 X$ J, e8 V  V6 g5 Ydisplay_value = pid_calc(&warm); " t7 x5 `5 W9 P8 i6 X* L" J; @

( r) a& ~5 m$ M; |  c0 tprintf("%f\n", display_value);
/ J7 w6 K. b  q1 s+ R* S( X! p5 o//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa
0 a8 l$ _0 L8 V+ _' r9 grm.dgain);
' o- F5 w6 a; _
) g5 W: h; Z& u- ~7 ^  F5 Fcount++;
& e2 N% ]" j( k& j}
% `" \  t# Z8 @( x3 a}, t; W: j# D  p1 Q
# A1 P$ R" {8 y2 z
发表于 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)就足够了。
3 M/ A, w% o# D' U: ?
回复

使用道具 举报

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

使用道具 举报

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

使用道具 举报

发表于 2014-3-20 09:29 | 显示全部楼层
8055 发表于 2014-3-19 22:11
: [1 o4 J9 c7 F% o+ T# A3 W1 @! [版主,这个更是针对什么设备的?是不是要根据不同的设备来制定不同的PID算法?比如驱动两个电炉,一个功率1 ...
1 X0 f# D* ?  [9 A1 N! y; n4 N
用同一个PID算法没问题,但要处理好PID参数,比如热容量差不多的情况下,两个设备的P参数要差一倍左右。: M$ L/ |9 H+ X. r7 z" @1 b4 `0 Z
回复

使用道具 举报

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

使用道具 举报

本版积分规则

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

GMT+8, 2025-8-20 12:03 , Processed in 0.035523 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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