直流电机PID控制,为什么我仿真时,无法进行按键处理,一运行就电机转到最大速度了

2019-07-18 15:22发布

#include <reg52.h>
#include <intrins.h>

                        //IO口设置
sbit a=P1^1;            //L298信号口,{ a=1 ;b=0;}      //启动输出  正转
sbit b=P1^2;            //            { a=0 ;b=1;}      //启动输出   反转
sbit K1 =P1^3 ;                    //减少键
sbit K2 =P1^4 ;                    //增加键
sbit K3 =P1^5 ;                    //正转键
sbit K4 =P1^6 ;                    //反转键
sbit K5 =P1^7 ;
unsigned int  speed_s=0;      //设置的转速,单位r/s
unsigned int  speed_m=0;       //测量的转速
unsigned char  zhuanxiang=1;   //转向标志,0不转,1正转,2反转.默认正转


                        //LCD模块IO口以及子程序定义
#define LCD_DATA P0
sbit LCD_RS = P2^0;
sbit LCD_RW = P2^1;
sbit LCD_EN = P2^2;
unsigned char dispBuff0[16]={'S','D',':',' ',' ',' ',' ',' ',' ',' ',' ','r','/','m','i','n'};//LCD第一行显示  不显示用空格
unsigned char dispBuff1[16]={'D','Q',':',' ',' ',' ',' ',' ',' ',' ',' ','r','/','m','i','n'};//LCD第二行显示

void    Delay20ms() ;
void         LCD_WriteDat(unsigned char lcd_dat);
void         LCD_WriteCmd(unsigned char lcd_cmd);
unsigned char         LCD_ReadStatus(void);
void         LCD_Goto(unsigned char x,unsigned char y);
void    LCD_Display(unsigned char row,unsigned char *str);

/*1、LCD模块子函数*/

  void         LCD_Init(void)
{
        Delay20ms();
    LCD_WriteCmd(0x38);        //8位机接口、双行显示、5×7字符点阵;
        LCD_WriteCmd(0x0c);        //显示开启、光标不显示也不闪烁;
        LCD_WriteCmd(0x01);        //清屏;
        LCD_WriteCmd(0x06);        //光标右移一位、整屏不移动;

    LCD_Goto(0,0);
        }
void         LCD_WriteDat(unsigned char lcd_dat)
{
        unsigned char tmp;
        tmp = LCD_ReadStatus();                //读状态;
        while((tmp & 0x80))                        //是否忙 ?
                {
                        tmp = LCD_ReadStatus();
                        }

        LCD_RS = 1;
        LCD_RW = 0;
        LCD_DATA = lcd_dat;
        _nop_();
        LCD_EN = 0;
        _nop_();
        _nop_();
        LCD_EN = 1;

        }
void         LCD_WriteCmd(unsigned char lcd_cmd)         //写指令数据到LCD
{
        unsigned char tmp;
        tmp = LCD_ReadStatus();
        while((tmp & 0x80))
        {
                tmp = LCD_ReadStatus();
                }

        LCD_RS = 0;
        LCD_RW = 0;
        LCD_DATA = lcd_cmd;
        _nop_();
        LCD_EN = 0;
        _nop_();
        _nop_();
        LCD_EN = 1;
        }
unsigned char         LCD_ReadStatus(void)
{
        unsigned char tmp;
        #if 0
        LCD_RS = 0;
        LCD_RW = 1;
        LCD_EN = 1;
        tmp = LCD_DATA;
        LCD_EN = 0;
        #endif
        LCD_DATA = 0xff;
        LCD_RS = 0;
        LCD_RW = 1;
        LCD_EN = 0;
        _nop_();
        _nop_();
        LCD_EN = 1;
        tmp = LCD_DATA;
        return tmp;
        }
void         LCD_Goto(unsigned char x,unsigned char y)
{
        unsigned char tmp;
        if(y)                                //若是第二行;
                {
                        tmp = 0xc0 + x;
                        LCD_WriteCmd(tmp);
                        }
        else
                {
                        tmp = 0x80 + x;
                        LCD_WriteCmd(tmp);
                        }               
        }



void LCD_Display(unsigned char row,unsigned char *str)
{
        if(row)
                {
                        LCD_Goto(0,1);
                        }
  else
          {
                  LCD_Goto(0,0);
                  }
  while(*str != '')
  {
          LCD_WriteDat(*str++);
          }
        }


void dectobit(unsigned int dec) //显示测得的速度
{
   dispBuff1[4]=(dec/1000)%10+'0';dispBuff1[5]=(dec/100)%10+'0';
   dispBuff1[6]=(dec/10)%10+'0';dispBuff1[7]=(dec)%10+'0';
   LCD_Display(1,dispBuff1);
}


void Delay20ms()   //粗略延时;
{
  unsigned int tmp = 50000;
  while(tmp--);
  }        

/*----------------按键识别程序----------------*/

void key()        //正转反转调节  zhuanxiang; 转向标志,0不转,1正转,2反转
{
    if(K1==0)                                        //减速
  {
            speed_s=speed_s-50;
     if (speed_s<0)
       { speed_s=0;}
  }
    if(K2==0)                                         //加速
  {  if (speed_s<300)
       { speed_s=speed_s+50;}
  }
  dispBuff0[4]=(speed_s/1000)%10+'0';dispBuff0[5]=(speed_s/100)%10+'0';
  dispBuff0[6]=(speed_s/10)%10+'0';dispBuff0[7]=(speed_s)%10+'0';
  LCD_Display(0,dispBuff0);

  if(K3==0 )                                       //正转
    {
     zhuanxiang=1;
    }
  if(K4==0 )                                         //反转
    {
        zhuanxiang=2;
    }
  if(K5==0)                                //两键按下,停止
    {
        zhuanxiang=0;
    }
        switch (zhuanxiang)
       {case 0:
              { a=0 ;b=0;break;}      //停止
        case 1:
              {  a=1 ;b=0;break;}      //启动输出  正转
        case 2:
              { a=0 ;b=1; break;}      //启动输出   反转
        default:break;
       }
}


/*------------------测转速程序------------------*/
unsigned int pusle=0;//脉冲个数
unsigned char count=0;//个数







void int0() interrupt 0 //外部中断0中断处理程序,用于脉冲计数
{        
        pusle++;
}

/*-------------电机调速程序,增量式PID算法------------*/
int Now_speed[3]={0,0,0};  //用于存储当前转速、前一次转速、再前一次转速

int KP=100;
int KI=20;
int KD=15;
int last_out=0;
#define out_max 10000
#define out_min 0
unsigned int PWMH=0;//PWM波在10000us内高电平时间

/********电机PID控制**********/
void Motor_control(void)      
{
    int PID=0;
    int P=0;
    int I=0;
    int D=0;
    int out=0;

    Now_speed[2] = Now_speed[1];
    Now_speed[1] = Now_speed[0];
    Now_speed[0] = speed_s-speed_m;

    P = KP*(Now_speed[0]-Now_speed[1]);
    I = KI* Now_speed[0];
    D = KD*(Now_speed[0]-2*Now_speed[1]+Now_speed[2]);
        PID = P+I+D;
        out=last_out+PID;
        if(out>=out_max) out=out_max;        //大于10000,取值为10000
        if(out<=out_min) out=out_min;        //小于0,取值为0
    PWMH=out;
        last_out=out;
}

unsigned char jishi=0;//计时
void timer0 (void) interrupt 1 //定时器0中断,用于定时产生PWM周期,一个控制周期定为10000us
{   
                   count++;
            if(count>=100)//这就大约1s
      {
             speed_m=pusle/2;//测速转速,单位r/M.转一圈产生2个脉冲

             count=0;//计数变量清零
             pusle=0;
      }

        jishi++;
        if (jishi>=100)//1s计算一次PID
    {/*设置并打开定时器1*/
    Motor_control()  ;
    jishi=0;
    }
  TH1=((65536-PWMH) & 0xff00)>>8;           // 高8位
  TL1=(65536-PWMH) & 0x00ff;                   // 低8位
  TR1=1; //运行开关  打开计时器1
TH0=(65536-10000)/256; //10000us
TL0=(65536-10000)%256;


}

void timer1 (void) interrupt 3//定时器1中断,用于定时产生PWM波的高电平时间
{
a=0 ;b=0;    //PWM输出低电平
TR1=0;
}




/*----------------主程序----------------------*/
void main()
{
a=0;
b=0;

/*计时器0设置,用于设置PWM的周期*/
TMOD=0x11; //定时器1、2都工作于方式1
TH0=(65536-10000)/256; //10000us
TL0=(65536-10000)%256;
ET0=1;     //定时器0的中断允许
TR0=1;     //运行开关 开始计时

/*计时器1设置,用于设置PWM的高电平时间*/
TH1=0;
TL1=0;
ET1=1;     //定时器1的中断允许
TR1=0;     //停止计时


/*外部中断0设置*/
IT0=1;    //外部中断0,0低电平触发,1边沿触发
EX0=1;    //打开外部中断0


EA=1;//开全局中断

/*LCD显示*/
LCD_Init();//LCD初始化

LCD_Display(0,dispBuff0);
LCD_Display(1,dispBuff1);
Delay20ms();
while(1)
     {key();//按键识别
      Delay20ms()           ;
         dectobit(speed_m);
     }

}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。