打印

直流电机的闭环控制问题!

[复制链接]
3032|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dlmudu|  楼主 | 2011-12-12 15:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
下边是我的完整程序
试验的问题有如下:
三段的速度比较明显的显现出来
当运行遇到阻力的时候就出现闷机的现象,没有增加电压(电压保持闷机前的状态);

我用PID程序和我现在的类似PID程序都出现一样的问题

请大侠门指导一下,谢谢,下边是程序
#include <pic.h>
__CONFIG(HS&WDTEN&PWRTEN&CP&CPD&BORDIS&IESODIS&FCMDIS);//外部高速晶振、看门狗使能、上电延时打开、代码与数据保护、低电压检测禁止、内外时钟切换禁止、故障保护时钟禁止
            //脉冲数110
#define uchar   unsigned char
#define uint    unsigned int
#define ulint   unsigned long

#define Kdoor         RA2     //
#define Gdoor         RA3     //
#define suobi         RA4     //
#define jinji         RA5     //
#define geli          RE0     //
#define fuwu          RE1     //
#define dw            RE2     //
#define Adr1          RC0     //
#define Adr2          RC1     //
#define Adr3          RC2     //
#define zj1           RC3     //
#define zj2           RC4     //
#define ENA           RD7     //A使能信号
#define ENB           RD6     //B使能信号
#define INA           RD5     //正转控制信号
#define INB           RD4     //反转控制信号
//#define Speed         RD2     //PWM速度信号
#define relay1        RB2     //
#define relay2        RB1     //
#define relay3        RC4     //
#define relay4        RD3     //
#define relay5        RD1     //

#define speed1        20     //
#define speed2        40     //
#define speed3        20     //

uint loop1in[2];

bank3 uint microS;      //Timer0定时时,用作4096us的时基变量。
bit S20;
bank3 uchar mS50;       //
bank3 uchar mS_50;      //
bank3 uchar SS;
bank3 uchar gggg,qqqq;       //1秒标志。。
bank3 uchar pppp;       //0.5秒标志。。,产生1HZ频率用
int aaaa,bbbb;
int jspeed;

ulint COUNT;
bit FLAG1,FLAG2,FLAG3,FLAG4,FLAG5,FLAG6,FLAG7;

bank2 uchar pwm2_h;//PID输出的占空比

void delay(uint time)     //1就是1ms,误差是偏大1.5us。但2000(即2秒时)偏小18ms
{
    uint i;
    uchar j;
    for(i=0;i<time;i++)
    {asm("clrwdt");
        for(j=0;j<179;j++);
    }
}
void Noop()
{
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");
}


void ccpint()
{
    CCP1CON=0X04;                          //首先设置CCP1捕捉每个脉冲的上升沿
    T1CON=0X00;                            //关闭TMR1震荡器
    //PEIE=1;                                //外围中断允许(此时总中断关闭)
    CCP1IE=1;                              //允许CCP1中断
    TRISC5=1;                              //设置RC5为输入
}

void sspeed()                 //速度计算函数
{  
        int tttt;
        tttt=aaaa;
        if(        pppp==2)                           //0.2秒的定时时间
        {
                pppp=0;
                jspeed=5*(aaaa-tttt);      //   0.2秒的定时时间,aaaa是即时脉冲数,tttt是0.2秒钱的脉冲数(不知这样写对不对),扩大1000倍的  个/毫秒
        }
}
void guanji()                   //关电机
{
  ENA=0;
  ENB=0;
  
}
void kmpwm()                                 //满行程是65个脉冲
{       
        int xx;
        sspeed();                                                                //计算实时速度
        if((0<=aaaa)&&(aaaa<10))                //前半段
    {   
                xx=40;
                if(jspeed=speed1)                   //比较
                {
                        pwm2_h=xx;
                    CCPR2L=pwm2_h;                  //输出占空比
               
                }
                else if(jspeed<speed1)              //比较
                {
                        xx+=5;
                        if(xx>200)
                                xx=200;
                        pwm2_h=xx;
                    CCPR2L=pwm2_h;                  //输出占空比
                       
                }
                else                             //比较
                {
                        xx-=5;
                        if(xx<0)
                                xx=0;
                        pwm2_h=xx;
                    CCPR2L=pwm2_h;               //输出占空比
                       
                }
        }

        else if((10<=aaaa)&&(aaaa<55))    //中间半段
    {       
                xx=80;
                if(jspeed=speed2)                //比较
                {
                        pwm2_h=xx;
                    CCPR2L=pwm2_h;                 //输出占空比
                       
                }
                else if(jspeed<speed2)               //比较
                {
                        xx+=5;
                        if(xx>200)
                                xx=200;
                        pwm2_h=xx;
                    CCPR2L=pwm2_h;               //输出占空比
               
                }
                else                                //比较
                {
                        xx-=5;
                        if(xx<0)
                                xx=0;
                        pwm2_h=xx;
                    CCPR2L=pwm2_h;             //输出占空比
                       
                }
    }
        else if((55<=aaaa)&&(aaaa<65))     //后半段
    {
                xx=40;
                if(jspeed=speed3)                  //比较
                {
                        pwm2_h=xx;
                    CCPR2L=pwm2_h;
               
                }
                else if(jspeed<speed3)           //比较
                {
                        xx+=5;
                        if(xx>200)
                                xx=200;
                        pwm2_h=xx;
                    CCPR2L=pwm2_h;              //输出占空比
                       
                }
                else                           //比较
                {
                        xx-=5;
                        if(xx<0)
                                xx=0;
                        pwm2_h=xx;
                    CCPR2L=pwm2_h;             //输出占空比
                       
                }
    }
   
        else if(65<=aaaa)     //开门到位
     {
             FLAG5=0;
       
             ENA=0;                  //电机停止输出
             ENB=0;
             pwm2_h=0;
             CCPR2L=pwm2_h;
     }
}
void guanmen()
{       

     FLAG3=1;
     ENA=1;
     ENB=1;
     INA=0;
     INB=1;
     kmpwm();

}

//中断服务程序
void interrupt cp1int(void)
{
   if(CCP1IF)
   {
           CCP1IF=0; //清除中断标志
           CCPR1L=0;
           CCPR1H=0;
           bbbb++;
           if(FLAG3==1)    //后退脉冲递增
           {
                   aaaa++;
                   COUNT++;
           }
           if(FLAG3==0)        //前进脉冲递减
           {
                   aaaa--;
                   if(aaaa<0)
                   aaaa=0;
                   COUNT--;
                   if(COUNT<0)
                           COUNT=0;
           }
           if(!COUNT)
    {
    // FLAG2=0;
    }
  }
   if(T0IE&&T0IF)  //若是Timer0中断
    {
        T0IF=0;     //清空中断标志
        microS+=4096;
        if(microS>10000)
        {
            microS=0;
            mS50+=1;
            mS_50+=1;
            if(mS50=10)                 //0.1秒
             {
              mS50=0;
              pppp++;

             }
            if(mS_50==20)               //2秒
            {
                mS_50=0;
                gggg++;
                                qqqq++;
            }
        }      
    }
}

void main(void)
{
    int i;
    uchar pwm2_h;
   
    TRISA|=0x3f;        //RA口,除了RA0--RA5做输入,其中RA0做模拟输入,其他做识字数字量输入
    TRISA&=0x3f;
    CMCON0|=0x07;       //关闭比较器,
    ANSEL=0x01;         //RA0为模拟输入  
    ADCON1|=0x50;       //设置AD转换时钟,在8M晶振下,一个转换周期是2us。        
    VCFG1=0;            //设置AD的参考电压为单片机电源电压。
    VCFG0=0;
    ADFM=1;             //AD结果右对齐
    ADON=1;             //启动AD采样

    TRISB|=0xf9;        //RB口中RA1--RA2为继电器输出口
    TRISB&=0xf9;
    WPUB=0xff;          //使能RB所有口的内部弱上拉功能。
   
    TRISC|=0xaf;        //RC口中RC0-RC3,RC5,RC7为输入端,其余输出
    TRISC&=0xaf;
    LCDCON=0;           //禁止PORTC几个脚的VLCD功能   

    TRISD|=0x01;        //RD口,除了RD0做输入,其余都做输出
    TRISD&=0x01;        //其中RD2用作PWM输出(自身带有)。

    TRISE|=0x07;        //RD口,除了RE0--RE2做输入
    TRISE&=0x07;        

    PR2=0xc7;           //Timer2作为PWM的频率控制器,当PR2为0xc8、Timer2为16预分频(是在对晶振的4分频后),晶振是8M时,PWM的频率是612HZ(见917手册的P219)
    CCP2CON=0x0c;       //将CCP2设置为PWM模式,其中的占空比数值在后面设置
    T2CKPS1=1;          //将Timer预分频值设为16
    T2CKPS0=0;
    TMR2IF=0;           //清空Timer2的中断标志
    TMR2ON=1;           //启动Timer2

    T0CS=0;             //给Timer0选择内部指令周期计数,即将它设置为定时器功能。此时Timer0也开始工作了。
    PSA=0;              //将预分频器分配给Timer0.
    PS2=1;              //分频比设置为32.则在8M晶振下,Timer0一个中断周期为4096us。
    PS1=0;
    PS0=0;
    T0IE=1;             //允许Timer0中断
    //CCP1IE=1;            //允许CCP1中断
    PEIE=1;             //允许外围中断
    GIE=1;              //允许总中断
   

    pppp=0;
    gggg=0;
        qqqq=0;
    aaaa=0;
    FLAG1=0;
    FLAG2=0;

    WDTPS3=0;           //设置看门狗分频是2048,则其周期为66ms
    WDTPS2=1;
    WDTPS1=1;
    WDTPS0=0;
   
    ENA=0;
    ENB=0;
    INA=0;
    INB=0;  
    relay1=1;
    relay2=1;
    relay3=1;
    relay4=1;
    relay5=1;

    TMR1H=0;
    TMR1L=0;           //定时器1清0
    CCP1IF=0;         //清除CCP1的中断标志,以免中断一打开就进入
    //中断
    ei( );           //中断允许
    TMR1ON=1;        //定时器1开

        FLAG1=0;
        FLAG2=0;
        FLAG5=0;
        FLAG3=0;
        FLAG4=0;
        FLAG6=0;
        FLAG7=0;
    COUNT=0;
    aaaa=0;
        jspeed=0;
        while(1)
        {
    asm("clrwdt");         //喂狗
   
        if(Gdoor==0&&Kdoor==1&&jinji==1&&geli==1&&FLAG1==0)    //启动后退,防抖
        {           
               
                delay(300);
                if(Gdoor==0)
                {
                delay(200);
                        if(Gdoor==0)
                        {
                                pppp=0;
                        FLAG5=1;
                        }
                }
        }

         if(FLAG5==1)
        {       
                //qqqq=0;
                ccpint();                    //后退
                guanmen();       
        }  
        else
        {
        relay3=1;                  //
        guanji();
        }       
}
}

相关帖子

沙发
dlmudu|  楼主 | 2011-12-12 15:29 | 只看该作者
我在试验台调试两天了,就是搞不明白了,希望大家指导

使用特权

评论回复
板凳
dlmudu|  楼主 | 2011-12-12 17:52 | 只看该作者
void sspeed()                 //速度计算函数
{  
        int tttt;
        tttt=aaaa;
        if(        pppp==2)                           //0.2秒的定时时间
        {
                pppp=0;
                jspeed=5*(aaaa-tttt);      //   0.2秒的定时时间,aaaa是即时脉冲数,tttt是0.2秒钱的脉冲数(不知这样写对不对),扩大1000倍的  个/毫秒
        }
这个速度计算函数不知道有没有问题?

使用特权

评论回复
地板
触觉的爱| | 2011-12-12 21:29 | 只看该作者
程度没看明白。最近也折腾闭环, 感觉反馈的脉冲计数变量A不宜直接参与运算,用一个缓冲变量B来存放测得的脉冲数,然后在一定周期内将A值赋给B,并将A清零。而B则用来计算。
 赋值周期与转速和反馈的脉冲数有关,不能顺便设定的
PID的不懂。

使用特权

评论回复
5
dlmudu|  楼主 | 2011-12-13 08:09 | 只看该作者
这个反馈的脉冲数不能清零的,因为有三段的速度是按反馈脉冲数排的

使用特权

评论回复
6
hongchengway| | 2011-12-13 08:17 | 只看该作者
[code][/code]

使用特权

评论回复
7
DownCloud| | 2011-12-13 09:14 | 只看该作者
看到delay我想吐。

使用特权

评论回复
8
rebewn| | 2011-12-13 09:30 | 只看该作者
晕了

使用特权

评论回复
9
xwj| | 2011-12-13 09:47 | 只看该作者
如果中断设计好的话,主程序里delay倒不一定错。
但是主程序里和delay里无条件喂狗,那你的狗就白养了。

随便扫了眼,没仔细看。
不过看到guanmen();        guanji();
我也被恶心到了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

18

主题

57

帖子

0

粉丝