1、 215 第 14 章 单片机控制的电动自行车驱动系统 14.4.4 C 语言程序 #include /电动车双闭环程序,采用双闭环 方式控制电机,以 得到最好的 zh 转 速性能,并且可以 /限制电机的最大电流。本应用程序用到两个 CCP部件,其中 CCP1用于 PWM输出 , 以控 /制 电机电压 ; CCP2用于触发 AD, 定时器 TMR2、 TMR1, INT中断, RB口电平变化中断, /看 门狗以及 6个通用 I/O口 #define AND 0xe0 /状态采集 5, 6, 7位 #define CURA 0X0a /电流环比例和积分系数之和 #define CURB 0X09
2、 /电流环比例系数 #define THL 0X6400 /电流环最大输出 #define FULLDUTY 0X0FF /占空比为 1时的高电平时间 #define SPEA 0X1d /转速环比例和积分系数之和 #define SPEB 0X1c /转速环比例系数 #define GCURHILO 0X0330 /转速环最大输出 #define GCURH 0X33 /最大给定电流 #define GSPEH 0X67 /最大转速给定 #define TSON 0X38 /手柄开启电压 1.1 V, TSON*2为刹车后手柄开启电压 , 即 /2.2 V #define VOLON 0X4
3、c /低电压保护重开电压 3.0 V即 33 V #define VOLOFF 0X49 /低电压保护关断电压 2.86 V即 31.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; /标志位定义 static volatile unsigned char new10=
4、0xaf,0xbe,0xff,0x7e,0xcf, 0xff,0xd7,0x77,0xff,0xff; /状态寄存器表 /-PIC16F877初始化子程序 - void INIT877() PORTC=0X0FF; /关断所有 MOSFET TRISC=0X02; /设置 C口输出 PIE1=0X00; /中断寄存器初始化,关断所有中断 TRISA=0XCF; /设置 RA4,RA5 输出 TRISB=0XEF; /RB 口高三位输入,采集电机三相的霍尔信号 216 PORTC=new(PORTB /采集第一次霍尔信号,并输出相应的信号 , 导通 /两 个 MOS管 T2CON=0X01; /
5、TMR2 4分频 CCPR1L=0X0FF; /初始时 PWM输出全高 CCP1CON=0X0FF; /CCP1设置为 PWM方式 CCP2CON=0X0B; /CCP2设置为特殊方式 , 以触发 AD ADCON0=0X81; /AD时钟为 32分频 ,且 AD使能 ,选择 AN0通道采集手 /柄电压 TMR2=0X00; /TMR2寄存器初始化 TMR1H=0X00; /TMR1寄存器初始化 TMR1L=0X00; T1CON=0X00; /TMR1为 1分频 CCPR2H=0X08; CCPR2L=0X00; /电流采样周期设置为 TAD=512 s PR2=0XC7; /PWM频率设置
6、为 5 kHz ADCON1=0X02; /AD结果左移 OPTION=0XFB; /INT上升沿触发 TMR2ON=1; /PWM开始工作 INTCON=0XD8; /中断设置 GIE=1,PEIE=1,RBIE=1 ADIE=1; /AD中断使能 speedcount=0x00; /转速计数寄存器 speed=0x7f; /转速保持寄存器 spe=1; /低速标志位 sp1=1; /低速标志位 oldstate=0x0ff; /初始状态设置,区别于其他状态 count_ts=0x08; /电流采样 8次 ,采集 1次手柄 count_vol=0x00; /采样 256次手柄 ,采集 1次电
7、池电压 ts=1; /可以采集手柄值的标志位 ADGO=1; /AD采样使能 TMR1ON=1; /CCP2部件开始工作 /-延时子程序 - #pragma interrupt_level 1 void DELAY1(x) char x; DELAYH=x; /延时参数设置 #asm 217 DELAY2 MOVLW 0X06 MOVWF _DELAYL DELAY1 DECFSZ _DELAYL GOTO DELAY1 DECFSZ _DELAYH GOTO DELAY2 #endasm /-状态采集子程序 - void sample() char state1,state2,state3,
8、x; do x=1; state1=(PORTB /霍尔信号采集 DELAY1(x); state2=(PORTB while(state1-state2); /当三次采样结果不相同时继续采集状态 if(state1-oldstate!=0) /看本次采样结果是否与上次 相同,不同 /则执行 oldstate=state1; /将本次状态设置为旧状态 state1=(oldstate5); PORTC=newstate1; /C口输出相应的信号触发两个 MOS管 if(sp1=1)spe=1;sp1=0; else /如果转速 很低,则 spe置 1 spe=0;sp1=0; speedcou
9、nt2); /否则, spe=0,计转速 speed=speedcount+state3; /speed寄存器为每 256 s加 1 speedcount=0; /-AD采样子程序 - void AD() char x; ADIF=0; /清 AD中断标志位 218 if(ts=1) /如果为手柄采样,则采样手柄值 CHS0=1; /选择电流采样通道 count_vol=count_vol+1; /电池采样计数寄存器 spepid=1; /置转速闭环运算标志 ts=0;tsh=ADRESH; /存手柄值 if(count_vol=0) /如果电池采 样时间到,则选择 AN2通道,采集电池电压
10、CHS0=0;CHS1=1;volflag=1;x=1;DELAY1(x);ADGO=1; else if(volflag=1) /电池采样完毕,进行相应的处理 CHS1=0;CHS0=1;volflag=0;voltage=ADRESH;lowpower=1; else /否则,中断为采样电流中断 speedcount=speedcount+1; /speedcount寄存器加 1,作为 测量转速用 if(speedcount0x3d) sp1=1; /如果转速低于 1 000 000 s/(512 s*3eh*3) / 则认为 为低速状态 currenth=ADRESH; curpid=1
11、; count_ts=count_ts-1; if(count_ts=0) /如果手柄时间到,则转入手柄采样通道 CHS0=0;count_ts=0x08;ts=1;x=1;DELAY1(x);ADGO=1; /-刹车处理子程序 - void BREAKON() char x; off=0; /off清零,如果是干扰则不复位 shutdown=0; if(RB0=1) /如果刹车信号为真,则停止输出电压 ADIE=0; /关 AD中断 INTE=0; /关刹车中断 CCPR1L=FULLDUTY; /输出电压 0 TMR1ON=0; /关 CCP2,不再触发 AD for(;ADGO=1;)
12、continue;/如正在采样,则等待采样结束 ADIF=0; /ADIF位清零 CHS0=0; /选择通道 0采样手柄 219 CHS1=0; x=1; DELAY1(x); do ADGO=1; for(;ADIF=0;)continue; ADIF=0; CCPR1L=FULLDUTY; asm(“CLRWDT“); tsh=(ADRESH1); while(tshTSON|RB0=1);/当手柄值大于 2.2 V或刹车仍旧继 续时 ,执行以 /上 语句 off=1; /置复位标志 /-欠 保护子程序 - void POWER() char x; lowpower=0; voltage=
13、1; /电压值换为 7位,以利于单字节运算 if(voltage1); CCPR1L=FULLDUTY; asm(“CLRWDT“); while(voltage=1; curek=gcur-currenth; /计算本次偏差 curuk=curuk+curek*CURA-curep; /按闭环 PI运算方式得到本次输出结果,下 /面对结果进行处理 if(curuk=0) /如果输出大于限幅值,则输出最大 电压 curuk=THL;CCPR1L=0;CCP1X=0;CCP1Y=0; else /否则,按比例输出相应的高电平时间到 CCPR1寄存器 b.pwm=THL-curuk; b.pwm8
14、)将 PWM寄存器的高半字节 if(b.pwm else CCP1X=0; if(b.pwm else CCP1Y=0; /-转速环运算子程序 - void SPEPI() static int speep=0x00,speek=0x00,speuk=0x00; int tsh1,speed1; /转速寄存器定义 spepid=0; /清转速运算标志 if(spe=1) speed1=0x00; /若转速太低,则认为转速为零 221 else speed1=0x7f-speed; /否则计算实际转速 if(speed1=GSPEH) /限制最大转速 tsh1=GSPEH; speuk=speu
15、k+speek*SPEA-speep;/计算得转速环输出 if(speukGCURHILO) /转速环输出限制,即限制最大电流约 12 A speuk=GCURHILO;gcur=GCURH; else /调速状态时的输出 gcur=(speuk4) /-主程序 - main() for(;) INIT877(); /单片机复位后,先对其进行初始化 off=0; /清复位标志 for(;off=0;) /复位标志为零,则执行下面程序,否则复位 if(curpid=1) CURPI(); /电流 PI运算 else if(spepid=1) SPEPI(); /转速 PI运算 else if(lowpower=1) POWER(); else if(shutdown=1) BREAKON(); asm(“CLRWDT“); /-中断服务子程序 - #pragma interrupt_level 1 void interrupt INTS(void) if(RBIF=1) RBIF=0;sample(); 222 else if(ADIF=1) AD(); else if(INTF=1) shutdown=1;INTF=0; /刹车中断来,置刹车标志