帆板控制系统要求
1 、基本要求
(1)用手转动帆板时,能够数字显示帆板的转角 θ 。显示范围为 0~60°,
分辨力为 2°,绝对误差≤5°。
(2)当间距 d=10cm 时,通过操作键盘控制风力大小,使帆板转角 θ 能够
在 0~60°范围内变化,并要求实时显示 θ 。
(3)当间距 d=10cm 时,通过操作键盘控制风力大小,使帆板转角 θ 稳定
d调节装置转速控制风力角度检测信号转轴帆板风扇θ键盘数字显示F-2在 45°±5°范围内。要求控制过程在 10 秒内完成,实时显示 θ ,并由声光提示,以便进行测试。
2 、发挥部分
(1) 当间距 d=10cm 时,通过键盘设定帆板转角,其范围为 0~60°。要求
θ 在 5 秒内达到设定值,并实时显示 θ 。最大误差的绝对值不超过5°。
(2) 间距 d 在 7~15cm 范围内任意选择,通过键盘设定帆板转角,范围为0~60°。要求 θ 在 5 秒内达到设定值,并实时显示 θ 。最大误差的绝0对值不超过 5°。
(3) 其他。
源程序:
#include <stc12c5a60s2.h>
#include<intrins.h>
#define GPIO_KEY P1
#include<1602.h>
int z=0,Pwm,a=0,KeyValue,k,q=0;
unsigned char Model,OK,KeyData,Cancel,Sure,KeyValue1;
unsigned int Angle,SetAngle,Count;
char increment_angle;
unsigned char code ASCII[12]={'0','1','2','3','4','5','6','7','8','9','.','-'};
bit DIR,DIR2;
sbit Out=P2^0;
sbit LED1=P2^1;
sbit LED2=P2^2;
sbit AA=P3^6;
sbit BB=P3^7;
void delay(uint i)
{
while(i--);
}
void Delay500ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 22;
j = 3;
k = 227;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
struct
{
float set_angle;//设定速度
float actual_angle;//实际速度
float error;//偏差
float error_next;//上一个偏差
float error_last;//上上一个偏差
float error_add;
float kp,ki,kd;//定义比例,积分,微分参数
float umax,umin;
}pid;
void LCDDatePro()
{
Angle=z*0.1759;
LcdWriteCom(0x80);
LcdWriteData(ASCII[Angle/1000]);
LcdWriteCom(0x81);
LcdWriteData(ASCII[Angle/100%10]);
LcdWriteCom(0x82);
LcdWriteData(ASCII[Angle/10%10]);
LcdWriteCom(0x83);
LcdWriteData(ASCII[Angle%10]);
}
int key_dispos()
{
int q0=0,q1=0,i=1;
if(KeyData)
{
for(i=1;i>0;i--)
{
q1=q0;
}
q0=KeyData;
i++;
}
q=q1*10+q0;
LcdWriteCom(0x80+0x40);
LcdWriteData(ASCII[q/10%10]);
LcdWriteCom(0x80+0x41);
LcdWriteData(ASCII[q%10]);
return q;
}
int KeyDown()
{
char a=0;
uchar KeyValue=0;
GPIO_KEY=0x0f;
if(GPIO_KEY!=0x0f)//读取按键是否按下
{
delay(10000);//延时10ms进行消抖
if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
{
//测试列
GPIO_KEY=0X0F;
switch(GPIO_KEY)
{
case 0X07: KeyValue=0;break;
case 0X0b: KeyValue=1;break;
case 0X0d: KeyValue=2;break;
case 0X0e: KeyValue=3;break;
}
//测试行
GPIO_KEY=0XF0;
switch(GPIO_KEY)
{
case 0X70:KeyValue=KeyValue;break;
case 0Xb0: KeyValue=KeyValue+4;break;
case 0Xd0: KeyValue=KeyValue+8;break;
case 0Xe0: KeyValue=KeyValue+12;break;
}
while((a<50)&&(GPIO_KEY!=0xf0)) //检测按键松手检测
{
delay(10000);
a++;
}
return KeyValue;
}
}
return 16;
}
void dataproKeyValue()
{
if(KeyValue1!=20)
{
if(KeyValue1==3) {Model=1;}
if(KeyValue1==7) {Model=2;}
if(KeyValue1==11) {Model=3;}
if(KeyValue1==15) {Model=4;}
if(KeyValue1==14) {Cancel=1;}
if(KeyValue1==13) {OK=1;}
if(KeyValue1==12) {KeyData=KeyData*10;}
if(KeyValue1==10) {KeyData=KeyData*10+9;}
if(KeyValue1==9) {KeyData=KeyData*10+8;}
if(KeyValue1==8) {KeyData=KeyData*10+7;}
if(KeyValue1==6) {KeyData=KeyData*10+6;}
if(KeyValue1==5) {KeyData=KeyData*10+5;}
if(KeyValue1==4) {KeyData=KeyData*10+4;}
if(KeyValue1==2) {KeyData=KeyData*10+3;}
if(KeyValue1==1) {KeyData=KeyData*10+2;}
if(KeyValue1==0) {KeyData=KeyData*10+1;}
}
KeyValue1=20;
}
void int_all()
{
TMOD|=0x01;
TH0=0xFF; //1ms
TL0=0xCE;
ET0=1;
EA=1;
TR0=1;
}
void Timer1Init()
{
TMOD|=0x10;
TH1=0xFF;
TL1=0x9C;
ET1=1;
EA=1;
TR1=1;
}
void pid_init()
{
pid.set_angle = 0.0;
pid.actual_angle = 0.0;
pid.error = 0.0;
pid.error_next = 0.0;
pid.error_last = 0.0;
pid.error_add=0.0;
pid.umax=70;
pid.kp = 0.15;
pid.ki = 1.37;
pid.kd = 1.97;
}
void pid_realise(float angle)//实现pid
{
int gex;
pid.set_angle = angle;//设置目标速度
pid.error = pid.set_angle - pid.actual_angle; //设定-实际
if(pid.actual_angle>pid.umax)
{
if(pid.error>30)
{
gex=0;
}
else
{
gex=1;
if(pid.error<0)
{
pid.error_add+=pid.error;
}
}
}
increment_angle = pid.kp*pid.error+gex*pid.ki*pid.error_add+pid.kd*(pid.error-pid.error_next);//增量计算公式
pid.error_next = pid.error;
}
void main()
{
LcdInit();
int_all();
Timer1Init();
pid_init();
while(1)
{
key_dispos();
LCDDatePro();
KeyValue1=KeyDown();
dataproKeyValue();
SetAngle=KeyData;
if(OK==1)
{
Sure=1;
Pwm=100;
while(Sure)
{
LCDDatePro();
KeyValue1=KeyDown();
dataproKeyValue();
OK=0;
if(Model==1)
{
bit DIR3;
LED1=0;
LCDDatePro();
if(Pwm>100){Pwm=100;}
if((Pwm>=90)||(DIR3==1))
{
DIR3=1;
Delay500ms();
Pwm-=5;
}
if((Pwm<=0)||(DIR3==0))
{
DIR3=0;
Delay500ms();
Pwm+=5;
}
}
if(Model==2)
{
LED2=0;
LCDDatePro();
pid.actual_angle=Angle;
pid_realise(45.0);
Pwm+=increment_angle;
if(Pwm>100){Pwm=100;}
if(Pwm<0){Pwm=10;}
}
if(Model==3)
{
a=q;
LCDDatePro();
pid.actual_angle=Angle;
pid_realise(a);
Pwm+=increment_angle;
KeyValue1=KeyDown();
dataproKeyValue();
if(Pwm>100){Pwm=100;}
if(Pwm<0){Pwm=10;}
}
if(Model==4)
{
}
if(Cancel==1){Sure=0;Pwm=0;}
}
Cancel=0;
}
}
}
void Timer0() interrupt 1
{
bit DIR1,DIR2;
TH0=0xFF; //0.05ms
TL0=0xCE;
if(AA==1)
{
DIR1=1;
}
else
{
DIR1=0;
}
if(DIR1!=DIR2)
{
if(DIR1==1&&DIR2==0)
{
if(BB==0)
{
z++;
}
else
{
z--;
}
}
if(DIR1==0&&DIR2==1)
{
if(BB==1)
{
z++;
}
else
{
z--;
}
}
}
DIR2=DIR1;
}
void Time1(void) interrupt 3
{
TH1=0xFF;
TL1=0x9C;
Count++;
if(Count>=100)
{
Count=0;
}
if(Count<Pwm)
{
Out=0;
}
else
{
Out=1;
}
}