控制对象传递函数:Gp=20/(s(0.1s+1)(0.2s+1)
第一个实验主要是出现等幅震荡的波形(纯比例控制):
#include <STC12C5A60S2.H>
#include <absacc.h>
typedef unsigned char u8; //无符号字符型变量新表示方法定义
typedef unsigned int u16; //无符号整型变量新表示方法定义
//#define AD0 XBYTE [0xF0FF] //给定量外部AD通道0的端口地址
//#define AD1 XBYTE [0xF1FF] //反馈量外部AD通道1的端口地址
//#define DA XBYTE [0xEFFF] //外部DA转换数据输入端口地址
#define D_port XBYTE [0x7FFF] //数码管段码锁存器端口地址
#define B_port XBYTE [0xBFFF] //数码管位码锁存器端口地址
#define A0_r -9.27 //实验五的4通道数据
#define Am_r 10.24 //实验五的4通道数据
#define N0_r 0x20 //实验五的4通道数据
#define Nm_r 0xe0 //实验五的4通道数据
#define A0_m -9.32 //实验五的5通道数据
#define Am_m 9.91 //实验五的5通道数据
#define N0_m 0x20 //实验五的5通道数据
#define Nm_m 0xe0 //实验五的5通道数据
#define Any -8.5 //实验三数据
#define Apy 7.86 //实验三数据
#define Nny 0x20 //你的实验板的实验三数据
#define Npy 0xe0 //你的实验板的实验三数据
sbit SW8 = P1^7; //ON为PID控制,OFF为不做控制,误差标度反变换后直接送DA
bit new_cycle_flag=0; //有新采样数据的位变量定义并初始化(1表示有新采样数据)
u8 r_kT,r_kT_L,m_kT,m_kT_L;//内嵌10位AD4通道结果高8位、低2位及显示计算用中间变量、内嵌10位AD5通道结果高8位、低2位及显示计算用中间变量定义定义
u8 status; //存放内嵌ADC状态信息变量定义(1是转换结束)
u16 temp; //平均滤波计算用中间变量定义
char Ax; //显示用中间变量定义
char buf[8]; //显示缓冲区字符型数组定义
float Ax_r,a1_r,b1_r; //给定电压及其标度变换的斜率和截距等浮点型变量定义
float Ax_m,a1_m,b1_m; //反馈电压及其标度变换的斜率和截距等浮点型变量定义
float e_kT,e_kT_T; //当前电压误差、上次电压误差浮点型变量定义(伏特)
float p_P_kT,p_I_kT,p_D_kT,p_I_kT_T,p_kT;//当前各分量,上次积分分量及总控制量浮点变量定义
float Kp,Ki,Kd; //PID参数等浮点型变量定义
float a2,n0; //标度反变换的斜率和截距等浮点型变量定义
u8 M=0,No_ch=0,n; //扫描显示位计数和AD通道变量定义并初始化
u8 code Stab[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴段码表
u8 code Btab[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //共阴位码表
float code Kptab[8]={0.6,0.61,0.62,0.63,0.64,0.67,0.70,0.75};//0.61时会出现衰减,0.62时正好等幅振荡
//float code Kptab[8]={0.60,0.61,0.63,0.65,0.66,0.67,0.68,0.69};//换数做,应介于0.61-0.63之间
//float code Kptab[8]={0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8};//换数做,应在0.6-0.7之间
/********标度变换初始化********/
void Scale_init(void)
{ Ax_r=Nm_r,Ax_m=Am_r;
Ax_r-=N0_r,Ax_m-=A0_r;
a1_r=Ax_m/Ax_r; //式(3-6-1)
b1_r=-a1_r;
b1_r*=N0_r;
b1_r+=A0_r; //式(3-6-2)
Ax_r=Nm_m,Ax_m=Am_m;
Ax_r-=N0_m,Ax_m-=A0_m;
a1_m=Ax_m/Ax_r; //式(3-6-1)
b1_m=-a1_m;
b1_m*=N0_m;
b1_m+=A0_m; //式(3-6-2)
Ax_r=Npy,Ax_m=Apy;
Ax_r-=Nny,Ax_m-=Any;
a2=Ax_r/Ax_m; //式(3-6-9)
n0=-a2;
n0*=Any;
n0+=Nny; //式(3-6-10)
}
/*********内嵌ADC初始化*********/ //10位AD高8位在ADC_RES,10位AD低2位在ADC_RESL
void AD_init(void) //内嵌ADC初始化程序
{ ADC_CONTR|=0x80; //给内嵌ADC通电
for(temp=0;temp<1000;temp++); //适当延时
P1ASF=0x10; //选择P1.4引脚作为模拟量输入
ADC_CONTR=0xc4; //继续通电 180个时钟 标志清0 不启动 通道4
for(temp=0;temp<1000;temp++); //适当延时
}
/*************PWM初始化*************/
void PWM_init(void) //硬件二阶RC低通Tao=1ms>>0.0463ms=0.5*(1/10.8KHz)
{ CMOD=0x8a; //选Fosc/4,fPWM=Fosc/4/256=10.8KHz,禁止中断
CCON=0x00; //00000000B控制,关闭PCA计数,CF\CCF1\CCF0均清0
CL=0x00; //PCA计数器低8位清0
CH=0x00; //PCA计数器高8位清0
CCAPM0=0x42; //8位PWM,允许比较器功能,P1.3做PWMO输出,禁止中断
PCA_PWM0=0x00; //最低2位EPC0H和EPC0L均设置为0
CCAP0H=0x80; //后续PWM为50%的占空比
CCAP0L=0x80; //当前PWM为50%的占空比
CR=1; //允许PCA计数器工作
}
/***********T0T1初始化***********/
void T0T1_init(void) //T0、T1初始化程序(11.0592MHz)
{ TMOD=0x21; //T0方式1定时、T1方式2定时(8位自动重装)
SCON=0x40; //8位UART波特率可变(2^SMOD*T1溢出率/32)
PCON=0x80; //第8位SMOD=1,波特率加倍
TH0=0xf3; //T0频率=(11059200/12)/(65536-0xf366)=285.679Hz
TL0=0x66; //T0方式1定时周期=1/285.679=0.0035s=3.5ms
TH1=0xfd; //T1溢出率=(11059200/12)/(256-253)=307200Hz
TL1=0xfd; //波特率=2^SMOD*307200/32=19200bps
EA=1; //允许中断
ES=0; //禁止串口中断
ET0=1; //允许T0中断
TR0=1; //启动T0工作
TR1=1; //启动T1工作
}
/*********数字PID控制计算********/
void PID(void) //采用与教材中的式(8-15)相同的PID算法
{ p_P_kT=Kp*e_kT; //控制量的比例部分计算
p_I_kT=p_I_kT_T; //控制量的积分部分计算
p_I_kT+=Ki*e_kT; //累加当前积分部分
p_D_kT=Kd*(e_kT-e_kT_T); //控制量的微分部分计算
p_kT=p_P_kT+p_I_kT+p_D_kT; //教材中的式(8-15)相同
}
/***********DA输出函数***********/
void DAC(void) //
{ p_kT+=n0; //标度反变换的加法
if(p_kT>254.5) CCAP0H = 255 ; //DA输出的修正值超大处理
else if(p_kT<0.5) CCAP0H = 0 ; //DA输出的修正值为负处理
else CCAP0H = (u8)(p_kT+0.5) ; //DA输出的修正值适合DA输出的处理,含四舍五入
}
/*******内嵌4通道AD输入*******/
void inputch4(void)
{
for(temp=0,n=0;n<4;n++) //采样周期到,进行4次AD转换
{ ADC_CONTR|=0x08; //启动内嵌AD转换,转换时间16.276微秒
status=0; //设状态为0
while(status==0)status=ADC_CONTR&0x10;//如果状态还为0,转换还没结束
ADC_CONTR&=0xe7; //状态为1,将ADC_FLAG位清0
r_kT=ADC_RES; //读取内嵌10位AD结果的高8位
r_kT_L=ADC_RESL&0x03; //读取内嵌10位AD结果的低2位
temp+=((u16)r_kT<<2); //累加内嵌10位AD结果的高8位
temp+=(u16)r_kT_L; //累加内嵌10位AD结果的低2位
}
P1ASF=0x20; //选择P1.5引脚作为模拟量输入
ADC_CONTR=0xc5; //继续通电 180个时钟 标志清0 不启动 通道5
No_ch=1; //改成5通道输入的模拟量的A/D转换的标识
} //4次内嵌AD转换总时间>65.1微秒
/*******内嵌5通道AD输入*******/
void inputch5(void)
{
for(temp=0,n=0;n<4;n++) //采样周期到,进行4次AD转换
{ ADC_CONTR|=0x08; //启动内嵌AD转换,转换时间16.276微秒
status=0; //设状态为0
while(status==0)status=ADC_CONTR&0x10;//如果状态还为0,转换还没结束
ADC_CONTR&=0xe7; //状态为1,将ADC_FLAG位清0
m_kT=ADC_RES; //读取内嵌10位AD结果的高8位
m_kT_L=ADC_RESL&0x03; //读取内嵌10位AD结果的低2位
temp+=((u16)m_kT<<2); //累加内嵌10位AD结果的高8位
temp+=(u16)m_kT_L; //累加内嵌10位AD结果的低2位
}
P1ASF=0x10; //重新选择P1.4引脚作为模拟量输入
ADC_CONTR=0xc4; //继续通电 180个时钟 标志清0 不启动 通道4
new_cycle_flag=1; //置2个通道均有采样数据的标志,4次内嵌AD转换总时间>65.1微秒
}
/*****位置控制的显示数据更新*****/
void disp_g(void) //给定量显示缓冲区的显示信息更新
{ Ax=(char)(Ax_r*10); //加快运算速度,给定量放大10倍取整数处理
buf[7]=0x00; //给定符号位预更新为正
if(Ax<0) //如果给定量为负
{ Ax=-Ax; //则取绝对值
buf[7]=0x40; //给定量符号位修改为负号段码
}
buf[4]=Stab[Ax%10]; //给定电压小数位显示信息送显示缓冲第4位
buf[5]=Stab[Ax/10%10]|0x80; //给定电压个位显示信息送显示缓冲第5位
buf[6]=Stab[Ax/100]; //给定电压十位显示信息送显示缓冲第6位
}
void disp_f(void) //反馈量显示缓冲区的显示信息更新
{ Ax=(char)(Ax_m*10); //加快运算速度,反馈量放大10倍取整数处理
buf[3]=0x00; //反馈符号位预更新为正
if(Ax<0) //如果反馈量是负
{ Ax=-Ax; //则取绝对值
buf[3]=0x40; //反馈量符号位修改为负号段码
}
buf[0]=Stab[Ax%10]; //反馈电压小数位显示信息送显示缓冲第0位
buf[1]=Stab[Ax/10%10]|0x80; //反馈电压个位显示信息送显示缓冲第1位
buf[2]=Stab[Ax/100]; //反馈电压十位显示信息送显示缓冲第2位
}
/********延时函数****************/
void delay()
{
int i,j;
for(i=0;i<70;i++)
for(j=0;j<100;j++);
}
/*************主程序*************/
void main(void)
{
BUS_SPEED=0x37;
Kp=Kptab[P1&0x07]; //利用网络标号SW3~SW1设置PID参数Kp
//Kp=1.2726; //控制度1.05时,Kp=0.63*Ks=1.2726
Ki=0.03666; //控制度1.05时,Ti=0.49*Ts=0.16317,Ki=Kp*T/Ti=0.03665637
Kd=12.62311; //控制度1.05时,Td=0.14*Ts=0.04662,Kd=Kp*Td/T=12.6231089
AD_init();
PWM_init();
Scale_init(); //标度变换初始化
e_kT_T=0.0,p_I_kT_T=0.0; //上次误差和上次控制量积分部分必须初始化为0.0
T0T1_init(); //T0、T1初始化程序(11.0592MHz)
//IT0=1; //外部中断引脚INT0以下降沿方式触发中断请求
//EX0=1; //允许外部INT0申请中断
do
{ if(No_ch==0) //如果标志为0,启动内嵌4通道ad
{
inputch4();
r_kT=(u8)(temp>>4); //temp是4次10位AD值的总和,8位AD结果N=temp/16
if((temp&0x0008==1)&&(r_kT<0xff))r_kT+=1;//考虑四舍五入
}
if(No_ch==1) //如果标志为1,启动内嵌5通道ad
{
inputch5();
m_kT=(u8)(temp>>4); //temp是4次10位AD值的总和,8位AD结果N=temp/16
if((temp&0x0008==1)&&(m_kT<0xff))m_kT+=1;//考虑四舍五入
}
if(new_cycle_flag==1) //有新采样数据
{ Ax_r=a1_r*(float)r_kT+b1_r;//给定量线性标度变换算出当前采样值对应的给定模拟电压
Ax_m=a1_m*(float)m_kT+b1_m;//反馈量线性标度变换算出当前采样值对应的反馈模拟电压
e_kT=Ax_r-Ax_m; //计算当前误差电压,单位为伏特
e_kT*=a2; //标度反变换的乘法修正,把电压误差(V)放大得到DA数字误差
if(SW8==0) PID(); //如果SW8实际设置在ON状态,做PID控制
else p_kT=Kp*e_kT; //否则SW8置在OFF状态,仅做P控制
DAC(); //做标度反变换的加法修正,即先+n0后控制量8位D/A输出
TI=0; //清除发送结束状态标志
ES=1; //允许串行发送结束中断
SBUF =r_kT; //发送报文第1字节,即给定量的A/D值
e_kT_T=e_kT,p_I_kT_T=p_I_kT;//迭代移位,为下一次控制做准备
disp_g(); //给定部分显示缓冲区中段码信息的更新
disp_f(); //反馈部分显示缓冲区中段码信息的更新
new_cycle_flag=0; //新采样周期标志清0
delay(); //延时函数
}
}while(1); //固定循环
}
/*********T0中断服务程序*********/
void t0(void) interrupt 1 using 1//3.5ms中断1次,每次均要进行显示处理
{ TH0=0xfb; //T0时间常数高字节重装
TL0=0x80; //T0时间常数低字节重装
if(M==8) //10ms到了吗?因为1.25ms*8=10ms
{
No_ch=0; //中断标志为0
M=0; //M清0
}
B_port=0xff; //关闭显示
D_port=buf[M]; //对应数码管的段码值送给段码端口U2
B_port=Btab[M]; //对应数码管的位码值送给位码端口U3
M++; //修改到下一次要显示的数码管
}
/********INT0中断服务程序********/
/*void int0(void) interrupt 0 using 2//每个采样周期中断2次
{ if(No_ch==0) //是IN0通道输入的模拟量的A/D转换的标识
{ //r_kT=AD0; //读取IN0通道给定量的A/D结果
inputch4();
r_kT=(u8)(temp>>4); //temp是4次10位AD值的总和,8位AD结果N=temp/16
if((temp&0x0008==1)&&(r_kT<0xff))r_kT+=1;//考虑四舍五入
//No_ch=1; //改成IN1通道输入的模拟量的A/D转换的标识
//AD1=0x00; //启动AD0809的IN1通道——反馈量A/D
}
else //否则就是IN1通道输入的模拟量的A/D转换标识
{
inputch4();
r_kT=(u8)(temp>>4); //temp是4次10位AD值的总和,8位AD结果N=temp/16
if((temp&0x0008==1)&&(r_kT<0xff))r_kT+=1;//考虑四舍五入 //m_kT=AD1; //读取IN1通道反馈量A/D结果
//new_cycle_flag=1; //置2个通道均有采样数据的标志
}
} */
/********TXD中断服务程序*********/
void txd(void) interrupt 4 using 3//每个采样周期需发2个字节,第2字节靠串行发送中断完成
{ TI=0; //清除发送结束状态标志
ES=0; //发送到报文最后1个字节,禁止发送结束中断
SBUF=m_kT; //发送报文第2字节,即反馈量的A/D值
}
该实验只采用了内嵌的A/D和PWM,所以其他的外部中断的程序都可以删除。特殊说明,程序的实验五和实验三具体指的是:基于内嵌10位数模转换,基于内嵌PWM波输出后低通滤波的等效8位数模转换。
实验的波形:
注意:该实验利用上位机时设置截距斜率用的是实验5的4通道和5通道的
需要用到的软件:上位机和STC-ISP-15(烧录程序)和Keil
来源:CSDN
作者:weixin_44891114
链接:https://blog.csdn.net/weixin_44891114/article/details/103475510