找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 7984|回復(fù): 10
打印 上一主題 下一主題
收起左側(cè)

電動(dòng)車控制

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:3271 發(fā)表于 2009-7-11 11:47 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
 

#include    <pic.h>
//改編PIC控制

//
電動(dòng)車雙閉環(huán)程序,采用雙閉環(huán)方式控制電機(jī),以得到最好的zh轉(zhuǎn)速性能,并且可以

//限制電機(jī)的最大電流。本應(yīng)用程序用到兩個(gè)CCP部件,其中CCP1用于PWM輸出,以控

//制電機(jī)電壓;CCP2用于觸發(fā)AD,定時(shí)器TMR2TMR1,INT中斷,RB口電平變化中斷,

//看門狗以及6個(gè)通用I/O

#define AND  0xe0       //狀態(tài)采集5,6,7   

#define CURA 0X0a       //電流環(huán)比例和積分系數(shù)之和

#define CURB 0X09       //電流環(huán)比例系數(shù)

#define THL  0X6400     //電流環(huán)最大輸出

#define FULLDUTY 0X0FF  //占空比為1時(shí)的高電平時(shí)間

#define SPEA 0X1d       //轉(zhuǎn)速環(huán)比例和積分系數(shù)之和

#define SPEB 0X1c       //轉(zhuǎn)速環(huán)比例系數(shù)

#define GCURHILO 0X0330 //轉(zhuǎn)速環(huán)最大輸出

#define GCURH 0X33      //最大給定電流

#define GSPEH 0X67      //最大轉(zhuǎn)速給定

#define TSON 0X38       //手柄開啟電壓1.1 VTSON*2為剎車后手柄開啟電壓,即

                         //2.2 V

#define VOLON 0X4c      //低電壓保護(hù)重開電壓3.0 V33 V

#define VOLOFF 0X49     //低電壓保護(hù)關(guān)斷電壓2.86 V31.5 V

volatile unsigned char DELAYH,DELAYL,oldstate,speed,

    speedcount,tsh,count_ts,count_vol,gcur,currenth,

    voltage;                    //寄存器定義

static bit sp1,spe,ts,volflag,spepid,lowpower,

    off,shutdown,curpid;        //標(biāo)志位定義

static volatile unsigned char new[10]={0xaf,0xbe,0xff,0x7e,0xcf,

    0xff,0xd7,0x77,0xff,0xff};  //狀態(tài)寄存器表

//------------PIC16F877初始化子程序------------

void INIT877()

{  

    PORTC=0X0FF;            //關(guān)斷所有MOSFET

    TRISC=0X02;         //設(shè)置C口輸出

    PIE1=0X00;          //中斷寄存器初始化,關(guān)斷所有中斷

    TRISA=0XCF;         //設(shè)置RA4,RA5 輸出

    TRISB=0XEF;         //RB 口高三位輸入,采集電機(jī)三相的霍爾信號(hào)

    PORTC=new[(PORTB&AND)>>5];  //采集第一次霍爾信號(hào),并輸出相應(yīng)的信號(hào),導(dǎo)通

//兩個(gè)MOS

    T2CON=0X01;         //TMR2 4分頻

    CCPR1L=0X0FF;       //初始時(shí)PWM輸出全高

    CCP1CON=0X0FF;      //CCP1設(shè)置為PWM方式

    CCP2CON=0X0B;       //CCP2設(shè)置為特殊方式,以觸發(fā)AD

    ADCON0=0X81;            //AD時(shí)鐘為32分頻,AD使能,選擇AN0通道采集手

//柄電壓   

    TMR2=0X00;          //TMR2寄存器初始化

    TMR1H=0X00;         //TMR1寄存器初始化

    TMR1L=0X00;

    T1CON=0X00;         //TMR11分頻

    CCPR2H=0X08;

    CCPR2L=0X00;            //電流采樣周期設(shè)置為TAD=512 μs

    PR2=0XC7;           //PWM頻率設(shè)置為5 kHz

    ADCON1=0X02;            //AD結(jié)果左移

    OPTION=0XFB;            //INT上升沿觸發(fā)

    TMR2ON=1;           //PWM開始工作

    INTCON=0XD8;            //中斷設(shè)置GIE=1,PEIE=1,RBIE=1

    ADIE=1;             //AD中斷使能

    speedcount=0x00;        //轉(zhuǎn)速計(jì)數(shù)寄存器

    speed=0x7f;         //轉(zhuǎn)速保持寄存器

    spe=1;              //低速標(biāo)志位

    sp1=1;              //低速標(biāo)志位

    oldstate=0x0ff;     //初始狀態(tài)設(shè)置,區(qū)別于其他狀態(tài)

    count_ts=0x08;      //電流采樣8,采集1次手柄

    count_vol=0x00;     //采樣256次手柄,采集1次電池電壓

    ts=1;               //可以采集手柄值的標(biāo)志位

    ADGO=1;             //AD采樣使能

    TMR1ON=1;           //CCP2部件開始工作

}

//------------延時(shí)子程序---------------

#pragma interrupt_level 1

void DELAY1(x)

char x;

{

    DELAYH=x;           //延時(shí)參數(shù)設(shè)置

#asm

DELAY2  MOVLW   0X06

    MOVWF   _DELAYL

DELAY1  DECFSZ  _DELAYL

    GOTO    DELAY1

    DECFSZ  _DELAYH

    GOTO    DELAY2

#endasm

}

//-----------狀態(tài)采集子程序----------------------

void sample()

{

    char state1,state2,state3,x;

    do  {

        x=1;

        state1=(PORTB&AND);     //霍爾信號(hào)采集

        DELAY1(x);

        state2=(PORTB&AND);

    }while(state1-state2);      //當(dāng)三次采樣結(jié)果不相同時(shí)繼續(xù)采集狀態(tài)

    if(state1-oldstate!=0)      //看本次采樣結(jié)果是否與上次相同,不同

//則執(zhí)行

     {oldstate=state1;          //將本次狀態(tài)設(shè)置為舊狀態(tài)

      state1=(oldstate>>5);

      PORTC=new[state1];            //C口輸出相應(yīng)的信號(hào)觸發(fā)兩個(gè)MOS

      if(sp1==1){spe=1;sp1=0;}

      else  {                   //如果轉(zhuǎn)速很低,則spe1

spe=0;sp1=0;

        speedcount<<=1;

        state3=(TMR1H>>2);      //否則,spe=0,計(jì)轉(zhuǎn)速

        speed=speedcount+state3;    //speed寄存器為每256 μs1

      }

      speedcount=0;

    }

}

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏1 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:3271 發(fā)表于 2009-7-11 11:48 | 只看該作者

//-----------------AD采樣子程序----------------------

void AD()

{

    char x;

    ADIF=0;                 //AD中斷標(biāo)志位

    if(ts==1){              //如果為手柄采樣,則采樣手柄值

     CHS0=1;                    //選擇電流采樣通道

     count_vol=count_vol+1; //電池采樣計(jì)數(shù)寄存器

     spepid=1;              //置轉(zhuǎn)速閉環(huán)運(yùn)算標(biāo)志

     ts=0;tsh=ADRESH;       //存手柄值

     if(count_vol==0) { //如果電池采樣時(shí)間到,則選擇AN2通道,采集電池電壓

        CHS0=0;CHS1=1;volflag=1;x=1;DELAY1(x);ADGO=1;

      }

    }

    else if(volflag==1) {           //電池采樣完畢,進(jìn)行相應(yīng)的處理

       CHS1=0;CHS0=1;volflag=0;voltage=ADRESH;lowpower=1;

    }

    else    {                       //否則,中斷為采樣電流中斷

      speedcount=speedcount+1;  //speedcount寄存器加1,作為測(cè)量轉(zhuǎn)速用

      if(speedcount>0x3d)  sp1=1;   //如果轉(zhuǎn)速低于1 000 000 μs/(512 μs*3eh*3)   

                                  // 則認(rèn)為為低速狀態(tài)

      currenth=ADRESH;

      curpid=1;

      count_ts=count_ts-1;

      if(count_ts==0) {         //如果手柄時(shí)間到,則轉(zhuǎn)入手柄采樣通道

          CHS0=0;count_ts=0x08;ts=1;x=1;DELAY1(x);ADGO=1;

        }

     }

}

//-------------剎車處理子程序------------------

void BREAKON()

{

    char x;

    off=0;                  //off清零,如果是干擾則不復(fù)位

    shutdown=0;

    if(RB0==1)  {           //如果剎車信號(hào)為真,則停止輸出電壓

    ADIE=0;             //關(guān)AD中斷

        INTE=0;             //關(guān)剎車中斷

        CCPR1L=FULLDUTY;        //輸出電壓0

        TMR1ON=0;           //關(guān)CCP2,不再觸發(fā)AD

        for(;ADGO==1;)  continue;//如正在采樣,則等待采樣結(jié)束

        ADIF=0;             //ADIF位清零

        CHS0=0;             //選擇通道0采樣手柄

        CHS1=0;

        x=1;

DELAY1(x);

        do  {

            ADGO=1;

            for(;ADIF==0;)continue;

            ADIF=0;

            CCPR1L=FULLDUTY;

        asm("CLRWDT");

            tsh=(ADRESH>>1);

        }while(tsh>TSON||RB0==1);   //當(dāng)手柄值大于2.2 V或剎車仍舊繼續(xù)時(shí),執(zhí)行以

                                 //上語(yǔ)句

        off=1;                  //置復(fù)位標(biāo)志

  }

}

回復(fù)

使用道具 舉報(bào)

板凳
ID:3271 發(fā)表于 2009-7-11 11:49 | 只看該作者

//---------欠保護(hù)子程序-------------------

void POWER()

{

    char x;

    lowpower=0;

    voltage>>=1;                    //電壓值換為7位,以利于單字節(jié)運(yùn)算

    if(voltage<VOLOFF) {            //電池電壓小于3*k(V)時(shí)保護(hù)

    ADIE=0;

        INTE=0;

        TMR1ON=0;

        CCPR1L=FULLDUTY;

        for(;ADGO==1;)continue;

        ADIF=0;

        CHS0=0;CHS1=1;

        x=1;

DELAY1(x);

        do{ADGO=1;

            for(;ADIF==0;)continue;

            ADIF=0;

            voltage=(ADRESH>>1);

            CCPR1L=FULLDUTY;

        asm("CLRWDT");

        }while(voltage<VOLON);  //電池電壓小于35 V時(shí)繼續(xù)保護(hù)

        off=1;                  //置復(fù)位標(biāo)志

    }

}

//------------電流環(huán)運(yùn)算子程序-----------------

void CURPI()

{   static int curep=0x00,curek=0x00,curuk=0x00;

    union data{int pwm;

        char a[2];}b;           //定義電流環(huán)運(yùn)算寄存器

    curpid=0;                   //清電流運(yùn)算標(biāo)志

    curep=curek*CURB;           //計(jì)算上一次偏差與比例系數(shù)的積

    if(currenth<2)currenth=2;       //如果采樣電流為零,則認(rèn)為有一個(gè)小電流以利于

//使轉(zhuǎn)速下降

    currenth>>=1;

    curek=gcur-currenth;            //計(jì)算本次偏差

    curuk=curuk+curek*CURA-curep;       //按閉環(huán)PI運(yùn)算方式得到本次輸出結(jié)果,下

//面對(duì)結(jié)果進(jìn)行處理

    if(curuk<0x00) {                //如果輸出小于零,則認(rèn)為輸出為零

      curuk=0;CCPR1L=FULLDUTY;CCP1X=0;CCP1Y=0; 

      }

else if(curuk-THL>=0)   {   //如果輸出大于限幅值,則輸出最大電壓

            curuk=THL;CCPR1L=0;CCP1X=0;CCP1Y=0;

        }

else    {               //否則,按比例輸出相應(yīng)的高電平時(shí)間到CCPR1寄存器

            b.pwm=THL-curuk;

            b.pwm<<=1;

            CCPR1L=b.a[1]; //CCPR1L=(b.pwm>>8)&0x0ff;PWM寄存器的高半字節(jié)

            if(b.pwm&0x80!=0) CCP1X=1;

            else CCP1X=0;

            if(b.pwm&0x40!=0) CCP1Y=1;

            else CCP1Y=0;

    }

}

回復(fù)

使用道具 舉報(bào)

地板
ID:3271 發(fā)表于 2009-7-11 11:49 | 只看該作者

//---------------轉(zhuǎn)速環(huán)運(yùn)算子程序-----------------------

void SPEPI()

{   static int speep=0x00,speek=0x00,speuk=0x00;

    int tsh1,speed1;                //轉(zhuǎn)速寄存器定義

    spepid=0;                   //清轉(zhuǎn)速運(yùn)算標(biāo)志       

    if(spe==1)  speed1=0x00;        //若轉(zhuǎn)速太低,則認(rèn)為轉(zhuǎn)速為零

    else speed1=0x7f-speed;     //否則計(jì)算實(shí)際轉(zhuǎn)速

    if(speed1<0) speed1=0;

    speep=speek*SPEB;

    tsh1=tsh-0x38;              //得到計(jì)算用的手柄值

    speek=tsh1-speed1;

    if(tsh1<0) {speuk=0;gcur=0;}    //當(dāng)手柄值低于1.1 V時(shí),則認(rèn)為手柄給定為零

    else {                      //否則,計(jì)算相應(yīng)的轉(zhuǎn)速環(huán)輸出

        if(tsh1>=GSPEH)         //限制最大轉(zhuǎn)速

        tsh1=GSPEH;

    speuk=speuk+speek*SPEA-speep;   //計(jì)算得轉(zhuǎn)速環(huán)輸出

        if(speuk<=0X00) {speuk=0x00;gcur=0x00;}//轉(zhuǎn)速環(huán)輸出處理

        else if(speuk>GCURHILO) {   //轉(zhuǎn)速環(huán)輸出限制,即限制最大電流約12 A

            speuk=GCURHILO;gcur=GCURH;}

        else        {                   //調(diào)速狀態(tài)時(shí)的輸出

            gcur=(speuk>>4)&0x0ff;

        }

    }

}

//-----------主程序-------------------------

void main()

{

for(;;){                    //比while(1) 優(yōu)良的語(yǔ)句

        INIT877();              //單片機(jī)復(fù)位后,先對(duì)其進(jìn)行初始化

        off=0;                  //清復(fù)位標(biāo)志

        for(;off==0;)   {       //復(fù)位標(biāo)志為零,則執(zhí)行下面程序,否則復(fù)位

        if(curpid==1) CURPI();  //電流PI運(yùn)算

        else if(spepid==1)  SPEPI();    //轉(zhuǎn)速PI運(yùn)算

        else if(lowpower==1)    POWER();

        else if(shutdown==1)    BREAKON();

        asm("CLRWDT");

    }

  }

}

//---------中斷服務(wù)子程序---------------------

#pragma interrupt_level 1

void interrupt INTS(void)

{  

    if(RBIF==1) {RBIF=0;sample();}

    else if(ADIF==1)    AD();

    else if(INTF==1)    {shutdown=1;INTF=0;}    //剎車中斷來,置剎車標(biāo)志

}

初學(xué)者看看還可以,把他搞成51的就可以了

回復(fù)

使用道具 舉報(bào)

5#
ID:13088 發(fā)表于 2009-7-11 11:51 | 只看該作者
學(xué)習(xí)下   保存下來慢慢研究   
回復(fù)

使用道具 舉報(bào)

6#
ID:14095 發(fā)表于 2009-7-11 15:25 | 只看該作者
C語(yǔ)言看不 懂
回復(fù)

使用道具 舉報(bào)

7#
ID:14957 發(fā)表于 2009-7-11 16:11 | 只看該作者

啊啊啊...論壇里好多C語(yǔ)言....看不懂

回復(fù)

使用道具 舉報(bào)

8#
ID:15281 發(fā)表于 2009-7-14 10:49 | 只看該作者
hao
回復(fù)

使用道具 舉報(bào)

9#
ID:3271 發(fā)表于 2009-7-15 10:32 | 只看該作者

如果要做大一點(diǎn)的程序關(guān)靠匯編是不行的,我一般做大型的都會(huì)C嵌入?yún)R編,讓匯編做底層驅(qū)動(dòng),因?yàn)镃達(dá)不到匯編那么精準(zhǔn)

回復(fù)

使用道具 舉報(bào)

10#
ID:15225 發(fā)表于 2009-7-19 20:39 | 只看該作者

開始學(xué)C
回復(fù)

使用道具 舉報(bào)

11#
ID:84745 發(fā)表于 2015-10-9 23:05 來自觸屏版 | 只看該作者
看看好用不
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表