#include <reg51.h>
#include< intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define GPIO_DIG P0//自定义数码管显示端
sbit pwm=P1^0;//位定义脉冲输入端口
sbit IN1=P1^1;//位定义L298输入端1
sbit IN2=P1^2;//位定义L298输入端2
sbit LSA=P2^2;//位定义74HC138译码器A端
sbit LSB=P2^3;//位定义74HC138译码器B端
sbit LSC=P2^4;//位定义74HC138译码器C端
sbit zhongduan=P3^2;//位定义中断次数变量
sbit DIN=P3^4;//位定义XPT2046数据输入端
sbit CS=P3^5;//位定义XPT2046片选端
sbit CLK=P3^6;//位定义XPT2046时钟端
sbit DOUT=P3^7;//位定义XPT2046数据输出端
int e=0,e1=0,e2=0;//声明当前偏差值变量、之后偏差值变量、再后偏差值变量
int out=0;//声明PID调节后输出偏差值变量
uint value;//脉冲宽度时间变量
uint temp;//设定速度
uint num;//实际速度
uint Inlpuse=0;//脉冲计数变量
uint time,count,temp1;//定时器0中断次数变量、定时器1中断次数变量、电位器模拟量变量
float uk=0,uk1=0,duk=0;//声明目前总偏差值变量、之后偏差值总变量、偏差值总变量
float kp=5,ki=1.5,kd=0.9;//PID控制系数P=5,I=1.5,D=0.9。
uchar code DIG_CODE[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//0、1、2、3、4、5、6、7、8、9、A、b、C、d、E、F的显示码
uchar DisplayData[8];//用来存放要显示的8位数的值变量
// void SPI_Start()
//{
// CLK=0;
// CS=1;
// DIN=1;
// CLK=1;
// CS=0;
// }
void SPI_Write(uchar dat)//写数据函数
{
uchar i;
CLK=0;
for(i=0;i<8;i++)
{
DIN=dat>>7;
dat<<=1;
CLK=0;
CLK=1;
}
}
uint SPI_Read()//读数据函数
{
uint i,
dat=0;
CLK=0;
for(i=0;i<12;i++)//接收12位数据
{
dat<<=1;
CLK=1;
CLK=0;
dat|=DOUT;
}
return dat;
}
uint Read_AD_Data(uchar cmd)//读XPT2046把模拟量转换为数字量函数
{
uchar i;
uint AD_Value;
CLK=0;
CS=0;
SPI_Write(cmd);
for (i=6;i>0; i--);
CLK=1;//
_nop_();
_nop_();
CLK=0;
_nop_();
_nop_();
AD_Value=SPI_Read();
CS=1;
return AD_Value;
}
void SetSpeed()//速度函数
{
temp1=Read_AD_Data(0x94);//电位器数字量变量
temp=2*temp1>>5;//temp的变化范围在0-250之间
}
void PIDControl()//PID偏差计算函数
{
e=temp-num;
duk=(kp*(e-e1)+ki*e+kd*(e-2e1+e2));
uk=uk1+duk;
out=(int)uk;
if(out>250)
{
out=100;
}
else if(out<0)
{
out=0;
}
uk1=uk;
e2=e1;
e1=e;
value=out;
}
void DigDisplay()//显示函数
{
uchar i;
uint j;
DisplayData[7]=DIG_CODE[num%10000/1000];
DisplayData[6]=DIG_CODE[num%1000/100];
DisplayData[5]=DIG_CODE[num%100/10];
DisplayData[4]=DIG_CODE[num%10];
DisplayData[3]=DIG_CODE[temp%10000/1000];
DisplayData[2]=DIG_CODE[temp%1000/100];
DisplayData[1]=DIG_CODE[temp%100/10];
DisplayData[0]=DIG_CODE[temp%10];
for(i=0;i<8;i++)
{
switch(i)//位选,选择点亮的数码管。
{
case(0)://显示第0位
LSA=0;
LSB=0;
LSC=0;
break;
case(1)://显示第1位
LSA=1;
LSB=0;
LSC=0;
break;
case(2)://显示第2位
LSA=0;
LSB=1;
LSC=0;
break;
case(3)://显示第3位
LSA=1;
LSB=1;
LSC=0;
break;
case(4)://显示第4位
LSA=0;
LSB=0;
LSC=1;
break;
case(5)://显示第5位
LSA=1;
LSB=0;
LSC=1;
break;
case(6)://显示第6位
LSA=0;
LSB=1;
LSC=1;
break;
case(7)://显示第7位
LSA=1;
LSB=1;
LSC=1;
break;
GPIO_DIG=DisplayData[i];//发送段码
j=50;//扫描间隔时间设定
while(j--);
GPIO_DIG=0x00;//消隐
}
}
}
void SystemInit()
{
TMOD=0x21;//设定时器0为工作方式1,定时器1为工作方式2(自动重装初值)。
TH0=0x3c;//设定50ms一次中断
TL0=0xb0;
TH1=0x9c;//设定100us一次中断
TL1=0x9c;
EA=1;//开总中断
EX0=1;//开外部中断0
IT0=1;//启动下降沿触发有效
ET0=1;//开定时器0中断
ET1=1;//开定时器1中断
TR0=1;//启动定时器0
TR1=1;//启动定时器1
}
void exter0() interrupt 0//外部中断0函数
{
Inlpuse++;//M法测速度(外部中断0和定时器0用在M法测速上)
}
void timer0() interrupt 1//定时器0中断函数
{
TH0=0x3c;//重装初值
TL0=0xb0;
time++;
if(time>=20)//1s钟读取一次转速
{
EX0=0;
TR0=0;
num=Inlpuse;//计算转速
Inlpuse=0;
PIDControl();//100ms控制一次Inlpuse=0;
EX0=1;
TR0=1;
}
}
void time1() interrupt 3//定时器1中断函数
{
count++;
if(count>=100)
count=0;
if(count<value)
pwm=1;
else
pwm=0;
}
void main()//主函数
{
SystemInit();
while(1)
{
SetSpeed();
DigDisplay();
}
}