// chip: pic16f877
#include
#define AND 0xe0 //状态采集5,6,7位
#define CURA 0X0a //电流环比例和积分系数之和
#define CURB 0X09 //电流环比例系数
#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 0X4c //低电压保护重开电压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 new[10]={0xaf,0xbe,0xff,0x7e,0xcf,
0xff,0xd7,0x77,0xff,0xff}; //状态寄存器表
// DELAYH 延时
// DELAYL 延时
// oldstate 状态
// speed 转速保持寄存器
// speedcount 转速计数寄存器
// count_ts 手柄电压采样次数计数器
// count_vol 低电压采样次数计数器
// gcur 速度环运算结果
// tsh 手柄A/D值
// voltage 电池A/D值
// currenth 电流A/D值
// ts 采集手柄值的标志位
// sp1 转速低标志
// spe 低速标志位
// volflag 电池电压标志
// spepid 转速标志
// lowpower 欠电压标志
// off 复位标志
// shutdown 刹车标志
// curpid 电流标志
// ************逆变桥输出控制表*************
// 逆变桥输出控制表,其输出对应6种状态,霍尔信号来自B口RB7、RB6、RB5,C口输出低电平有效,
// 其中RC1,RC2不作为触发电路输出口,故表中使其为高电平
// RETLW 0X0AF ;如霍尔信号为 0、0、0,则使RC4、RC6为低电平
// RETLW 0X0BE ;如霍尔信号为 0、0、1,则使RC0、RC6为低电平
// RETLW 0X0FF ;没有为0、1、0的霍尔信号对应电机状态
// RETLW 0X07E ;如霍尔信号为0、1、1,则使RC0、RC7为低电平
// RETLW 0X0CF ;如霍尔信号为1、0、0,则使RC4、RC5为低电平
// RETLW 0X0FF ;没有为1、0、1的霍尔信号对应电机状态
// RETLW 0X0D7 ;如霍尔信号为1、1、0则使RC3、RC5为低电平
// RETLW 0X077 ;如霍尔信号为1、1、1则使RC3、RC7为低电平
void INIT877(void)
{
PORTC=0X0FF; // 关断所有MOSFET //
TRISC=0X02; // 设置C口输出 //
PIE1=0X00; // 中断寄存器初始化,关断所有中断 //
TRISA=0XCF; // 设置RA4,RA5 输出 //
TRISB=0XEF; // RB 口高三位输入,采集电机三相的霍尔信号 //
PORTC=new[(PORTB&AND)>>5]; // 采集第一次霍尔信号,并输出相应的信号,导通两个MOS管 //
T2CON=0X01; // 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频率设置为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次电池电压 //
ts=1; // 可以采集手柄值的标志位 //
ADGO=1; // AD采样使能 //
TMR1ON=1; // CCP2部件开始工作 //
}
//------------延时子程序---------------
#pragma interrupt_level 1
void DELAY1(char x)
{
DELAYH=x; //延时参数设置
#asm
DELAY2 MOVLW 0X06
MOVWF _DELAYL
DELAY1 DECFSZ _DELAYL
GOTO DELAY1
DECFSZ _DELAYH
GOTO DELAY2
#endasm
}
void sample(void)
{
char state1,state2,state3,x;
do {
x=1;
state1=(PORTB&AND); // 霍尔信号采集 //
DELAY1(x);
state2=(PORTB&AND);
} while (state1-state2); // 当两次采样结果不相同时继续采集状态 //
if (state1-oldstate!=0) { // ?看本次采样结果是否与上次相同,不同则执行 //
oldstate=state1; // 将本次状态设置为旧状态 //
state1=(oldstate>>5);
PORTC=new[state1]; // ?C口输出相应的信号触发两个MOS管 //
if (sp1==1) {spe=1;sp1=0;} // 如果转速很低,则spe置1, sp1清零 ! //
else { // 否则,spe=0,计转速 //
spe=0;sp1=0;
speedcount<<=1;
state3=(TMR1H>>2);
speed=speedcount+state3; // speed寄存器为每256 μs加1 //
}
speedcount=0;
}
}
void AD(void)
{
char x;
ADIF=0; // 清AD中断标志位 //
if (ts==1) { // 如果为手柄采样,则采样手柄值 //
CHS0=1; // 选择电流采样通道 //
count_vol=count_vol+1; // 电池采样计数寄存器 //
spepid=1; // 置转速闭环运算标志 //
ts=0; tsh=ADRESH; // 存手柄值 //
if (count_vol==0) { // 如果电池采样时间到,则选择AN2通道,采集电池电压 //
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 (speedcount>0x3d) sp1=1; // 如果转速低于1 000 000 μs/(512 μs*3eh*3)则认为为低速状态 //
currenth=ADRESH;
curpid=1;
count_ts=count_ts-1;
if (count_ts==0) { // 如果手柄时间到,则转入手柄采样通道 //
CHS0=0;
count_ts=0x08;
ts=1;
x=1; DELAY1(x);
ADGO=1;
}
}
}
void BREAKON(void)
{
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;) continue; // 如正在采样,则等待采样结束 //
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); // 当手柄值大于2.2 V或刹车仍旧继续时,执行以上语句上语句 //
off=1; // 置复位标志 //
}
}
void POWER(void)
{
char x;
lowpower=0;
voltage>>=1; // 电压值换为7位,以利于单字节运算 //
if (voltage
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
off=1; // 置复位标志 //
}
}
void CURPI(void)
{
static int curep=0x00, curek=0x00, curuk=0x00;
union data{int pwm;
char a[2];}b; // 定义电流环运算寄存器 //
curpid=0; // 清电流运算标志 //
curep=curek*CURB; // 计算上一次偏差与比例系数的积 //
if (currenth<2) currenth=2; // 如果采样电流为零,则认为有一个小电流以利于使转速下降 //
currenth>>=1;
curek=gcur-currenth; // 计算本次偏差 //
curuk=curuk+curek*CURA-curep; // 按闭环PI运算方式得到本次输出结果,下面对结果进行处理 //
if (curuk<0x00) { // 如果输出小于零,则认为输出为零 //
curuk=0; CCPR1L=FULLDUTY;
CCP1X=0; CCP1Y=0;
}
else if (curuk-THL>=0) { // 如果输出大于限幅值,则输出最大电压 //
curuk=THL;
CCPR1L=0; CCP1X=0; CCP1Y=0;
}
else { // 否则,按比例输出相应的高电平时间到CCPR1寄存器 //
b.pwm=THL-curuk;
b.pwm<<=1;
CCPR1L=b.a[1]; // CCPR1L=(b.pwm>>8)&0x0ff;将PWM寄存器的高半字节 //
if (b.pwm&0x80!=0) CCP1X=1;
else CCP1X=0;
if (b.pwm&0x40!=0) CCP1Y=1;
else CCP1Y=0;
}
}
void SPEPI(void)
{
static int speep=0x00, speek=0x00, speuk=0x00;
int tsh1, speed1; // 转速寄存器定义 //
spepid=0; // 清转速运算标志 //
if (spe==1) speed1=0x00; // 若转速太低,则认为转速为零 //
else speed1=0x7f-speed; // 否则计算实际转速 //
if (speed1<0) speed1=0; // 如果speed>0x7f,则认为转速为零 //
{
speep=speek*SPEB;
tsh1=tsh-0x38; // 得到计算用的手柄值 //
speek=tsh1-speed1;
}
if (tsh1<0) {speuk=0; gcur=0;} // 当手柄值低于1.1 V时(tsh<0x33),则认为手柄给定为零 //
else { // 否则tsh<0x33,计算相应的转速环输出 //
if (tsh1>=GSPEH) {
tsh1=GSPEH; // 限制最大转速 //
speuk=speuk+speek*SPEA-speep; // 计算得转速环输出 //
}
if (speuk<=0X00) {speuk=0x00; gcur=0x00;} // 转速环输出处理 //
else if (speuk>GCURHILO) {speuk=GCURHILO; gcur=GCURH;} // 转速环输出限制,即限制最大电流约12A //
else {gcur=(speuk>>4)&0x0ff;} // 调速状态时的输出 //
}
}
main(void)
{
for (;;) {
INIT877(); // 单片机复位后,先对其进行初始化 //
off=0; // 清复位标志 //
for (;off==0;) { // 复位标志为零,则执行下面程序,否则复位 //
if (curpid==1) CURPI(); // 电流标志=1,电流环运算 //
else if (spepid==1) SPEPI(); // 转速标志=1,转速环运算 //
else if (lowpower==1) POWER(); // 欠电压标志=1,欠电压保护 //
else if (shutdown==1) BREAKON(); // 刹车标志=1,刹车处理 //
asm("CLRWDT"); // 清看门狗 //
}
}
}
#pragma interrupt_level 1
void interrupt INTS(void)
{
if (RBIF==1) {RBIF=0; sample();} // 是否为RB口电平变化中断? 是,进入状态采集子程序 //
else if (ADIF==1) AD(); // 是否为AD采样中断? 是,进入AD采样子程序 //
else if (INTF==1) {shutdown=1; INTF=0;} // 刹车中断来,置刹车标志 //
}
Control code
最新推荐文章于 2020-10-13 13:48:34 发布