一乐电子

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

QQ登录

只需一步,快速开始

微信扫码登录

手机号码,快捷登录

手机号码,快捷登录

搜索
查看: 2821|回复: 6

PID C语言

[复制链接]
发表于 2014-3-19 21:59 | 显示全部楼层 |阅读模式
PID算法(c 语言)2 d! |, c- a4 I4 x
#include <stdio.h> , J" n* p/ K+ T" c+ t, h0 B
#include<math.h>
! y2 s7 ]- r8 D* c- A; E//定义PID 的结构体
! L: \: M& k9 ~) e4 [struct _pid
5 P- V3 {0 V8 j: {{ : L$ G9 U9 @7 _4 E8 L, K
int pv; //integer that contains the process value 过& T4 K+ I/ z; D
程量
3 ], e; I$ o5 J+ M9 `int sp; //*integer that contains the set point   设
9 I5 N0 C5 @% C, M7 N- a, L* g定值
8 S8 ~6 |% U( a( I6 u7 U; ~9 P1 rfloat integral; // 积分值 -- 偏差累计值
9 `$ q! _% s& Z9 D3 S2 @float pgain;
9 I" `7 x, f1 tfloat igain;
- f% V0 B6 o3 m  Q  X$ J7 ufloat dgain;
4 t5 J0 W8 n7 p* o) [int deadband;    //死区
: u' r; B; J- Sint last_error;
3 ]( H. q' [. D}; + ~, X6 k  z2 b

' \+ u' `; `9 ?+ @1 `struct _pid warm,*pid;
7 |0 U6 e) l  A6 g( b5 b7 G: ~int process_point, set_point,dead_band; float p_gain, i_gain, d_gain,
' g4 S* n% @2 X7 S/ a- q0 Kintegral_val,new_integ;;
$ E- A/ a( g" v8 f% a& o
$ n0 x+ z: a9 P! @//------------------------1 |- T! ~2 o) T( c$ o  L
----------------------
! g1 K" g3 Q2 b+ F4 S- h* @- apid_init DESCRIPTION This function initializes the 7 h. M$ y0 Z# P- `
pointers  in  the  _pid  structure  to  the  process  variable
2 p0 s/ k/ U( ?- _/ ]* D' Qand the setpoint. *pv and *sp are integer pointers.
: ^- d. O% S! P, Q9 a8 X6 g% m2 V//------------------------* p2 a* d7 x! F) E9 x
---------------------- 6 l3 h! O$ O7 ^" e, C4 ?( M0 l9 r

: Q" q, u- \3 j  x9 ]" }3 pvoid pid_init(struct _pid *warm, int process_point, 8 ^& t# S+ l. L0 _7 a7 I
int set_point)
' G3 l* D* `8 ?0 ~# F2 N{ . K- E" I* U& O
struct _pid *pid; ) B; B4 \% a5 P: g
pid = warm; , ~- ~4 e) P. F
pid->pv = process_point;
0 t# |; d- [7 Kpid->sp = set_point; / Y- ^/ G6 [) x- a+ k3 o( t+ }
} + [- C" g1 Q; W6 `, L! e( Y" M
5 K0 J* X' o' i  K# t
//------------------------7 L/ V. g& [: u5 l
----------------------pid_tune DESCRIPTION Sets the proportional gain
) C" h& ~$ n8 Y(p_gain), integral gain (i_gain),
8 G! G7 X6 ]9 R7 K. P8 l  l% bderivitive  gain  (d_gain),  and  the  dead  band  (dead_band)
! @7 c7 v6 |) C. V9 F: V$ lof a pid control structure _pid.  + {2 L2 f: P/ M* }7 i$ M

8 M3 w1 C+ e5 P2 G4 W设定PID参数 ---- P,I,D,死区 8 y+ y9 |! k5 A, W
//------------------------
( [3 S4 D! ^  o  X  l8 _0 g----------------------
- m2 E% A" h' O& V/ p; P/ ]2 f8 G! U* N
void pid_tune(struct _pid *pid, float p_gain, float
5 B/ C( X* u6 c. v* O! Ni_gain, float d_gain, int dead_band) - F% m) h4 u* H
{
; [, g4 J9 f! s! lpid->pgain = p_gain;
/ G& Y- ^) h" O+ I2 ?4 V* Zpid->igain = i_gain;
8 F6 n7 I% I) I% R# f9 y* a, V/ cpid->dgain = d_gain; ) E( s3 P4 Y) Y* q0 c2 v( r
pid->deadband = dead_band;
+ [0 n6 A$ Q7 C" ^3 @pid->integral= integral_val;
6 Q0 c( _) O$ r2 @pid->last_error=0;
+ V# d5 r, X! J9 ]0 Z  t}
% e1 _* a& A, W5 F( x  e4 s. h4 c
- D# Z$ ?8 Q: e0 o0 R2 X//------------------------; B( G0 ~* B$ r/ {5 a5 g( J; o7 @" e
---------------------- pid_setinteg DESCRIPTION Set a new value for the
9 L! b" G. e" D! f0 X' yintegral term of the pid equation. ' {* z' C& J" N9 O3 ?( v1 n
This is useful for setting the initial output of the
, u# K; U3 Y% Q& d8 U. _+ \/ Rpid controller at start up. $ V+ W, ^- \$ S. k. F

8 D2 u: H" S9 B# A* T+ c1 P设定输出初始值
3 w3 m" g( n: Q2 y//------------------------
- u6 v- @- y1 m3 d+ a4 W' w% p----------------------
! o8 h" c4 V) b' `3 _* N( ^2 A3 p3 y6 h: P
void pid_setinteg(struct _pid *pid,float new_integ) $ v7 [& O, c; O5 I' ]2 |7 L2 _6 k8 v+ c
{ ( Z$ w9 O7 E4 k$ y' N6 g% u: T% h
pid->integral = new_integ; 1 h2 v/ q7 j1 y1 m* n
pid->last_error = 0; 4 O$ ]  l2 c8 a7 [+ f( g
} # [" I/ B, n" d( K0 g0 T) ?* ]

  B: W* o; [+ ^4 S5 ]* @' y7 c//------------------------: Y; @( b2 T2 G, n. b1 e0 M
---------------------- . u( |3 S9 }2 o% Y3 n
pid_bumpless DESCRIPTION Bumpless transfer 1 r& K5 A3 U" ~& L; s
algorithim.
0 p& t- M8 p. x( U* J9 N3 JWhen suddenly changing setpoints, or when restarting
$ U" u: ?0 C$ u, @the PID equation after an extended pause, 9 Y6 K; G! _0 D- y
the derivative of the equation can cause a bump in the controller output. This function will help smooth out
8 m% j* M: k. q  ]that bump.
; \1 O  P+ s# [/ vThe process value in *pv should be the updated just / C" v  B& z' J5 [
before this function is used.
' Y5 `  y  h& x
* b4 A2 j1 E8 Upid_bumpless 实现无扰切换
* ~8 D0 U6 S- y当突然改变设定值时,或重新启动后,将引起扰动输出。这
& k+ {) N; `) z5 w6 E3 o3 Y个函数将能实现平顺扰动, 在调用该函数之前需要先更新 PV值
2 o5 n, ?: d" L//------------------------- D/ t& r- g; K/ i
---------------------- , m& {1 i) z4 c3 t  ~1 z

3 H( k5 X  ~6 {9 c$ W7 y, yvoid pid_bumpless(struct _pid *pid) ) f+ M0 _$ k! [
{ ) s3 K: n) D7 P. ]
pid->last_error = (pid->sp)-(pid->pv);  //设定值与反馈值偏差
; y1 o5 v# _7 N7 l8 N' [0 T# p  Q}
  \+ E1 t% z0 J0 E( }# c' V+ E+ M) ]; U- _8 `/ g: j
//------------------------' t4 _* }7 o3 ~5 M( I- i
----------------------
, ]% j" ?3 Q- b! Mpid_calc  DESCRIPTION  Performs  PID  calculations  for  the
$ v8 z5 M/ k- I& o# F_pid structure *a. This function uses the positional form of the pid 9 i( T0 t; h3 k$ x* W' {
equation, and incorporates an integral windup * Q4 }5 C( Z% V# y5 l+ K/ W
prevention algorithim.
! r( u/ o% I% q% rRectangular  integration  is  used,  so  this  function  must
* W! h( ~- Q8 Sbe repeated on a consistent time basis for accurate : P/ O: a% t( |8 T- Q9 [8 t
control.
3 s+ b7 r9 D& j2 S, s: @; ^$ NRETURN VALUE The new output value for the pid loop.
- I/ ~$ E1 Z/ C9 o+ ^USAGE #include "control.h" $ \, X& o0 J: Y  ~8 _3 ~5 k% x
本函数使用位置式PID计算方式,并且采取了积分饱和限制运算
# p+ k1 B1 g# l5 t2 c1 qPID计算 $ v% }( y$ ^/ x* b) q" l! J- g2 P
//------------------------6 D6 ^: I8 d# ]& s/ j
---------------------- ( G- X7 L# i7 @9 h2 A! g

* k0 `# r+ g8 X7 ?& Q: v" B  D/ j) bfloat pid_calc(struct _pid *pid)
0 n6 [$ t0 J2 F6 E+ t  ]
6 s/ J, N: J, W  G( Q2 J* {int err;
% W. h' x8 d) T& ufloat pterm, dterm, result, ferror;
  g: F# o( l- X/ \* u. K+ W6 M+ K$ z
// 计算偏差 6 N# W  K% Y' f" o) `" V) u8 K
err = (pid->sp) - (pid->pv);   U/ u; |" D# R( n6 ?( o
// 判断是否大于死区
& k' s2 [6 Y$ \( P3 X! F! Xif (abs(err) > pid->deadband)
; x: F* n- ~0 N9 A{ 9 b; z; M' {1 |7 z4 f1 A; N/ M
ferror = (float) err;   //do integer to float , U5 ?, M, ]& P) Y+ a4 A# z
conversion only once 数据类型转换
  q, j0 Z3 g7 U9 r/ X7 p3 d4 m4 b& ^2 ~; s
// 比例项 6 e. R! B& b( i$ A5 ?
pterm = pid->pgain * ferror;
/ V% B% v2 a& p& p6 x$ z
" \: r+ K6 C& x. `! _+ @. W+ ?if (pterm > 100 || pterm < -100)
' [  p6 c7 p9 G9 s{ 8 W9 d; B7 ?- H# f/ G5 }( U
pid->integral = 0.0;
: R% n1 Z9 l( {# H}
2 @+ I1 J9 \8 S- q* \else 9 X" C  |" A5 r4 c" _
{
9 d1 _8 D; N, p# [( G" o, l0 J5 \// 积分项
2 P8 D/ p- k( D  G7 _/ `pid->integral += pid->igain * ferror; * q1 j% ~2 R" H# I% d' z3 z  V" l  o
% k# Q5 y' D! e, k
// 输出为0--100% # f7 Q5 M- y# C+ n4 S2 E
// 如果计算结果大于100,则等于100 & I( X! x* H6 h( F  i+ \
if (pid->integral > 100.0)
  W( h  a  P1 Y- A8 r# i7 S' p{ pid->integral = 100.0; ) H* b4 i3 t9 ]$ K1 s
} ) H: {, x6 v" Z# Y6 ^
// 如果计算结果小于0.0,则等于0 5 _+ p% K0 u# ]9 U! d# H
else if (pid->integral < 0.0) / l- g- q. v$ {
pid->integral = 0.0;
) M( J" ?5 U0 o. u# a+ ?$ ?& k3 l  R- @# F+ b/ O1 I
}
) A( p  [6 v# s0 M. ^7 e4 B+ y' E0 [' C* j) Z# v$ j
// 微分项 ; X9 x% j# q' Q5 `7 W
dterm  =  ((float)(err  -  pid->last_error))  *  pid->dgain; ' u9 U1 i7 J" X' \
9 h) L! v9 {/ O
result = pterm + pid->integral + dterm; 4 r( y- q! M4 l/ A: _* O
}
. ~; p# r7 n1 M4 J' Uelse
4 _( [+ P  Z: H6 gresult = pid->integral; // 在死区范围内,保持现有输出
) t# y  U. F1 Y+ F4 G% j, y2 q0 L+ j
3 O' N& i. S4 f& t' l// 保存上次偏差 / u1 D+ |* _' A9 E
pid->last_error = err; , s+ R  g4 F6 L
* u( V: q# S  J& M% C: m+ J3 d
// 输出PID值(0-100)
: c1 ?. _* x4 A! j7 z7 treturn (result); }
1 @2 T- j1 h. z0 u% e5 D) G5 e" z  N  q
//------------------------
, \2 y9 w- i6 U4 x----------------------
' L; |4 m0 A4 B& a+ x7 ivoid main(void)
* p5 x. k! c8 m. L) x{ 8 z. P8 E, Y* d# c& L/ A- U
float display_value;
, Z  {, g% v7 Q$ y$ H, V3 ?3 fint count=0;
% E% ~2 n# F3 `8 c2 y7 ]* G7 H( |pid = &warm;
% x3 W$ S: ~. ]6 e2 Z' }
0 W  j  `% _' n. t2 v4 _3 ~% @// printf("Enter the values of Process point, Set
5 I, E! @6 _7 n& d9 V1 Ipoint, P gain, I gain, D gain \n"); 3 U% l2 _% s$ I  _0 J
// scanf("%d%d%f%f%f", &process_point, &set_point, " k* F9 C; Y9 O: V% _
&p_gain, &i_gain, &d_gain); 3 R2 S- n: k' _
8 q/ S# t8 L, h) L1 `$ \( K$ g
// 初始化参数 & `! {( f' b( h' U, E) T
process_point = 30;
, L9 ^$ Z4 D. ~) b) O7 Fset_point = 40; , D; ?( u$ b+ h; I; V. `% A
p_gain = (float)(5.2);
( S' X5 J2 k9 d8 x, Q( Bi_gain = (float)(0.77); 9 [  ?' }, @7 O; K
d_gain = (float)(0.18); . @. `/ e* u4 T/ S
dead_band = 2;  
$ _% T- ~1 v4 r/ E. Qintegral_val =(float)(0.01); - X' S/ N3 E5 H( {3 S/ k- g
' R# G, |/ P  k! J
printf("The  values  of  Process  point,  Set  point,  P  gain,
1 z! W0 k- N+ i$ M( Z% n% JI gain, D gain \n");
4 g+ K+ T  r+ O: Bprintf(" %6d %6d %4f %4f %4f\n", process_point, - m: p" m) s) |5 F8 [) b
set_point, p_gain, i_gain, d_gain);
( s% {) l; r1 E/ h, q$ I/ g, Cprintf("Enter the values of Process point\n"); ( O0 t0 ^( x; ?# v9 O
while(count<=20) + @$ H: {4 `8 F5 R, \% R
{ . \( H' G% B* G- ?
scanf("%d",&process_point); 8 m' X0 v* X4 `3 d  N! y

5 S. A. _8 O3 Q# I// 设定PV,SP 值
6 ~4 E' A1 }! V) ppid_init(&warm, process_point, set_point); ; W- A/ N9 _0 B. r# M

6 i# U6 ?, n& [: a0 ~! w$ x// 初始化PID 参数值
$ u0 I; [  O  ~+ N0 m% ypid_tune(&warm, p_gain,i_gain,d_gain,dead_band);
* V2 |, O2 j! J. [7 t9 ~$ V: Y# S6 E5 j
// 初始化PID 输出值
+ l  f& ^+ ?- j6 h* Jpid_setinteg(&warm,0.0);
5 {- s! U2 I6 Q1 O& q4 h//pid_setinteg(&warm,30.0);
: n# i6 C' \8 F& ]3 ~5 R4 Q //Get input value for process point
  R5 t. u$ C+ D) v" [: K7 |' {pid_bumpless(&warm); - u4 V4 F  n2 S9 Q+ F
" \/ }4 M$ U6 A& J9 `# F8 R
// how to display output
# ?9 f6 S9 u" O! p2 R! \0 H5 \5 zdisplay_value = pid_calc(&warm);
% x/ [' G* I; [, u+ s3 L# {* x! h6 P7 B2 P5 a8 I) h) i6 M
printf("%f\n", display_value);
  f5 z/ y. p# j* Q6 L) J% N//printf("\n%f%f%f%f",warm.pv,warm.sp,warm.igain,wa
0 d, p& N( [4 i# {/ crm.dgain);
+ v! K5 N" V# Y8 [2 @; @
& |- N$ @: j4 n! \1 n4 t' icount++;
' V- r  o" [6 {: O9 I  O# }} - @" X& j  S/ t) _! z% n
}+ w8 x" p  d8 n  x

: I1 D2 ]& j0 ?0 g5 W! S
发表于 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)就足够了。$ ?' s7 x" v$ r* D" k7 J1 A: ?
回复

使用道具 举报

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

使用道具 举报

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

使用道具 举报

发表于 2014-3-20 09:29 | 显示全部楼层
8055 发表于 2014-3-19 22:11, i; _3 q( r% g+ g
版主,这个更是针对什么设备的?是不是要根据不同的设备来制定不同的PID算法?比如驱动两个电炉,一个功率1 ...
- S; R* U3 D* k7 K4 C
用同一个PID算法没问题,但要处理好PID参数,比如热容量差不多的情况下,两个设备的P参数要差一倍左右。; ?" y# u  m( t  L7 l# O  T
回复

使用道具 举报

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

使用道具 举报

本版积分规则

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

GMT+8, 2025-10-28 00:53 , Processed in 0.033532 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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