基于51单片机XPT2046转换电位器模拟量为数字量当作设定速度经PID控制直流电机实际转速的项目工程

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

 

posted @ 2020-05-05 21:27  吃不了就兜着走  阅读(819)  评论(0编辑  收藏  举报