#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(); } }