DSP28335实现PID闭环

1 Simulink下的模型及结果

给定参考是0.5,经过PID,然后执行机构,最后输出,Simulink的仿真结果如下:

Kp=10;Ki=5;Kd=0.5


2 增量式PID介绍

采用增量式PID算法:

比例P:e(k) - e(k-1),这次误差 - 上次误差

积分I:e(i),误差

微分D:e(k) - 2e(k-1) + e(k-2),这次误差 - 2*上次误差 + 上上次误差

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
%增量式PID
clc % 清屏
clear all; % 删除workplace变量
close all; % 关掉显示图形窗口
%%
%建立传递函数
ts=0.001; %采样时间
sys=tf(400,[1,50,0]);%建立传递函数模型,sys = tf(Numerator,Denominator)
dsys=c2d(sys,ts,'z');%连续函数离散化,sysd = c2d(sys,Ts,method)
[num,den]=tfdata(dsys,'v');%获得分子分母,[num,den] = tfdata(sys)

%%
%PID控制量
u_1=0.0;u_2=0.0;u_3=0.0;
y_1=0;y_2=0;y_3=0;
x=[0,0,0]';%’是转置,储存PID的计算值

%%
%误差
error_1=0;
error_2=0;
for k=1:1:1000
time(k)=k*ts;%时间轴,画图用

yd(k)=2.0;%控制目标(理想位置)

%PID参数
kp=8;
ki=0.2;
kd=10;

du(k)=kp*x(1)+kd*x(2)+ki*x(3);%PID控制值增量
u(k)=u_1+du(k);%PID控制器输出的控制量

%避免PID值饱和,限制输出
if u(k)>10
u(k)=10;
end
if u(k)<-10
u(k)=-10;
end

%计算y(k)
y(k)=-den(2)*y_1-den(3)*y_2+num(2)*u_1+num(3)*u_2;%求系统输出
u_3=u_2;u_2=u_1;u_1=u(k);%更新PID输出值,用于下一次y(k)计算
y_3=y_2;y_2=y_1;y_1=y(k);%更新控制结果,用于下一次y(k)计算

%计算偏差,以及PID输入
error=yd(k)-y(k);%偏差=控制目标-当前的值
x(1)=error-error_1; %计算P
x(2)=(error-error_1)-(error_1-error_2);%计算D
x(3)=error; %计算I

%更新偏差
error_2=error_1;
error_1=error;
end

figure(1);
plot(time,yd,'r',time,y,'b','linewidth',2);
xlabel('时间(s)'); ylabel('误差');
grid on
title('增量式PKD跟踪响应曲线');
legend('理想位置','位置追踪');

figure(2);%误差
plot(time,yd-y,'r','linewidth',2);
xlabel('时间(s)');ylabel('误差');
grid on
title('增量是PID跟踪误差');

运行结果:

参考材料《MATLAB_SIMULINK系统仿真》

C语言实现增量式PID:

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
typedef struct PID
{
float P,I,D,limit;
}PID;
typedef struct Error
{
float Current_Error;//当前误差
float Last_Error;//上一次误差
float Previous_Error;//上上次误差
}Error;

/*!
* @brief 增量式PID
* @since v1.0
* *sptr :误差参数
* *pid: PID参数
* NowPlace:实际值
* Point: 期望值
*/
// 增量式PID电机控制
int32 PID_Increase(Error *sptr, PID *pid, int32 NowPlace, int32 Point)
{

int32 iError, //当前误差
Increase; //最后得出的实际增量

iError = Point - NowPlace; // 计算当前误差

Increase = pid->P * (iError - sptr->Last_Error) //比例P
+ pid->I * iError //积分I
+ pid->D * (iError - 2 * sptr->Last_Error + sptr->Previous_Error); //微分D

sptr->Previous_Error = sptr->Last_Error; // 更新前次误差
sptr->Last_Error = iError; // 更新上次误差

return Increase; // 返回增量
}

3 增量式PID之Matlab-simulink仿真

模型建立:

PID参数设置:

运行结果:


4 DSP实现

包括两块:定时器0中断,PID函数。主要就是在中断函数中实现PID。

定时器0中断函数及PID初始化,运算

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
void TIM0_Init(float Freq,float Period) {
EALLOW;
SysCtrlRegs.PCLKCR3.bit.CPUTIMER0ENCLK=1;
EDIS;
EALLOW;
PieVectTable.TINT0=&TIM0_IRQn;
EDIS;
//指向定时器0的寄存器地址
CpuTimer0.RegsAddr = &CpuTimer0Regs;
//设置定时器0的周期寄存器值
CpuTimer0Regs.PRD.all = 0xFFFFFFFF;
//设置定时器预定标计数器值为0
CpuTimer0Regs.TPR.all = 0;
CpuTimer0Regs.TPRH.all = 0;
//确保定时器0为停止状态
CpuTimer0Regs.TCR.bit.TSS = 1;
//重载使能
CpuTimer0Regs.TCR.bit.TRB = 1;
// Reset interrupt counters:
CpuTimer0.InterruptCount = 0;
ConfigCpuTimer(&CpuTimer0, Freq, Period);
//开始定时器功能
CpuTimer0Regs.TCR.bit.TSS=0;
//开启CPU第一组中断并使能第一组中断的第7个小中断,即定时器0
IER |= M_INT1;
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
//使能总中断
EINT;
ERTM;
}

void PID_initial(void) {
// 初始化PID控制器参数
pidStr.KP=10;
pidStr.KI=5;
pidStr.KD=0.5;
}

float PID_control(float adcvalue, float ref) {
float Inck=0.0;
pidStr.Ek=ref-adcvalue;
Inck = pidStr.KP*(pidStr.Ek - pidStr.Ek_1) + pidStr.KI*pidStr.Ek + pidStr.KD*(pidStr.Ek - 2*pidStr.Ek_1 + pidStr.Ek_2);
pidStr.Ek_2 = pidStr.Ek_1;
pidStr.Ek_1 = pidStr.Ek;
pidStr.dacOut = pidStr.dacOut + Inck*1.000/60;
if(pidStr.dacOut < 0.0000)
pidStr.dacOut = 0.0000;
if(pidStr.dacOut > 0.7)
pidStr.dacOut = 0.7;
return pidStr.dacOut;
}

interrupt void TIM0_IRQn(void) {
EALLOW;
LED2_TOGGLE;
PID_control(a,0.5);
DELAY_US(1);
a=1.5*pidStr.dacOut;
aa[ai]=a;
ai++;
PieCtrlRegs.PIEACK.bit.ACK1=1;
EDIS;
}

主函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void main() {
InitSysCtrl();
p=0;
a=0.0;
ai=0;
LED_Init();
int i;
for(i=0;i<500;i++) {
aa[i]=0;
}
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
PID_initial();
TIM0_Init(150,1000);
while(1) {
p++;
if((p%2)==0) {
LED1_TOGGLE;
}
}
}

全局变量的定义:

1
2
3
4
5
6
//C文件
#include “canshu.h”
PID_ValueStr pidStr;
float32 a;
float32 aa[500];
Uint16 ai;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// H文件
extern float32 m[100];
extern float32 aa[500];
extern float32 a;
extern Uint16 ai;

typedef struct {
float KP;
float KI;
float KD;
float Ek;
float Ek_1;
float Ek_2;
float dacOut;
} PID_ValueStr;

extern PID_ValueStr pidStr;

最终效果: