(1)步进电机稳压直流稳压电源模块程序
#include
unsigned char R1,R2,R3,TXDATA,LEDF,BJF,COUNTW,data;
unsigned int i;
const char table[11]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0XD8,0x80,0x90,0xFF};
//不带小数点的显示段码表
const char table0[11]={0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10,0xFF};
//带小数点的的显示段码表
unsigned char s[4];
//定义一个显示缓冲数组
//把需要显示的数字装入显示缓冲数组
void sfz()
{
s[0]=R3;
s[1]=R2;
s[2]=R1;
s[3]=0x0A;
//最后一个LED显示"DARK"
}
//系统各寄存器初始化子程序
void
initial()
{
R1=0X00;
R2=0X00;
R3=0X00;
sfz();
//把需要显示的数字装入显示缓冲数组
TXDATA=0X00;
LEDF=0X01;
BJF=0X01;
TRISB1=0;
TRISB2=0;
TRISB4=1;
TRISB5=1;
//设置与键盘相关的各口的输入输出方式
RB1=0;
RB2=0;
//设置扫描初始条件
}
//SPI方式显示初始化子程序
void
SPIINIT()
{
PIR1=0;
SSPCON=0x30;
SSPSTAT=0xC0;
//设置SPI的控制方式,允许SSP方式,并且时钟下降沿发送,与"74HC595,当其
//SCLK从低到高跳变时,串行输入寄存器"的特点相对应
TRISC=0xD7;
//SDO引脚为输出,SCK引脚为输出
TRISA5=0;
//RA5引脚设置为输出,以输出显示锁存信号
}
//I2C初始化子程序
void
i2cint()
{
SSPCON = 0X08;
//初始化SSPCON寄存器
TRISC3 =1;
//设置SCL为输入口
TRISC4 =1;
//设置SDA为输入口
TRISA4 = 0;
SSPSTAT=0X80;
//初始化SSPSTAT寄存器
SSPADD=0X02;
//设定I2C时钟频率
SSPCON2=0X00;
//初始化SSPCON2寄存器
di();
//关闭总中断
SSPIF=0;
//清SSP中断标志
RA4=0;
//关掉74HC165的移位时钟使能,以免74HC165
//移位数据输出与I2C总线的数据线发生冲突
SSPEN=1;
//SSP模块使能
}
//软件延时子程序
void
DELAY()
{
for(i = 3553; --i ;) continue;
}
//键服务子程序
void
keyserve()
{
PORTB=0XFD
;
if(RB5==0)
BJF=0X01;
//S9键按下,步进加标志置1
PORTB=0XFB
;
if(RB5==0)
BJF=0X00;
//S11键按下,步进加标志清0
RB1=0;
//恢复PORTB的值
RB2=0;
}
//键扫描子程序
void
KEYSCAN()
{
while(1){
while(1)
{
if (RB5==0)
break;
}
DELAY();
//若有键按下,则软件延时
if (RB5==0)
break;
//若还有键按下,则终止循环扫描,返回
}
}
//SPI传送数据子程序
void SPILED(data)
{
SSPBUF=data;
//
启动发送
do
{
;
}while(SSPIF==0);
SSPIF=0;
}
//显示子程序
void
display()
{
SPIINIT();
//spi方式显示初始化
RA5=0;
//准备锁存
for(COUNTW=0;COUNTW<4;COUNTW++)
{
data=s[COUNTW];
if(COUNTW==1)
data=table0[data];//第二位需要显示小数点
else
data=table[data];
SPILED(data);
//发送显示段码
}
for(COUNTW=0;COUNTW<4;COUNTW++)
{
data=0xFF;
SPILED(data);
//连续发送4个DARK,使显示美观
}
RA5=1;
//最后给一个锁存信号,代表显示任务完成
}
//I2C总线输出数据子程序
void
i2cout()
{
i2cint();
//因为SPI输出和I2C输出不能同时工作,则需要
//不断在两种方式间切换
SEN=1;
//产生I2C启动信号
for(i=0x02;--i;)
continue;
//给予一定的延时,保证启动
do
{
RSEN=1;
//产生I2C启动信号
}while(SSPIF==0);
//如果没能启动,则反复启动,直到启动为止
SSPIF=0;
//SSPIF标志清0
SSPBUF=0X58;
//I2C总线发送地址字节
do
{
;
}while(SSPIF==0);
//等待地址发送完毕
SSPIF=0;
//SSPIF标志清0
SSPBUF=0X01;
//I2C总线发送命令字节
do
{
;
}while(SSPIF==0);
//等待命令发送完毕
SSPIF=0;
//SSPIF标志清0
SSPBUF=TXDATA;
//I2C总线发送数据字节
do
{
;
}while(SSPIF==0);
//等待数据发送完毕
SSPIF=0;
//SSPIF标志清0
PEN=1;
//产生停止条件
do
{
;
}while(SSPIF==0);
//等待停止条件产生
SSPIF=0;
//SSPIF标志清0
}
//步进加子程序
void
BJADD()
{
R1++;
TXDATA=TXDATA+2;
if(R1>9)
{
R1=0;
R2++;
if(R2>9)
{
R2=0;
R3++;
}
}
if((R3==1)&&(R2==2)&&(R1==1))
{
R3=0;
R2=0;
R1=0;
//若R3,R2,R1超过120,则又从0计起
TXDATA=0;
}
sfz();
//把需要显示的数字装入显示缓冲数组
}
//步进减子程序
void
BJSUB()
{
R1--;
TXDATA=TXDATA-2;
if(R1==0XFF)
{
R1=9;
R2--;
if(R2==0XFF)
{
R2=9;
R3--;
if(R3==0XFF)
{
R3=1;
R2=2;
R1=0;
//若R3,R2,R1小于0,则又从120计起
TXDATA=0XF0;
}
}
}
sfz();
//把需要显示的数字装入显示缓冲数组
}
//主程序
main()
{
initial();
//系统各寄存器初始化
display();
//调用一次显示子程序
while(1)
{
i2cout();
//调用I2C子程序,启动D/A转换
KEYSCAN();
//键盘扫描
keyserve()
;
//若确实有键按下,则调用键服务程序
if(BJF==0X01)
BJADD();//若步进加标志为1,则调用步进加子程序
else
BJSUB();
//若步进加标志为0,则调用步进减子程序
display();
//调用一次显示子程序
}
}
(2步进电机驱动模块程序
PCL
EQU
02H
;定义PCL寄存器地址
STATUS
EQU
03H
;定义状态寄存器地址
PORTC
EQU
07H
;定义端口C的数据寄存器地址
PORTD
EQU
08H
;定义端口D的数据寄存器地址
TRISC
EQU
87H
;定义端口C的方向寄存器
TRISD
EQU
88H
;定义端口D的方向寄存器
INTCON
EQU
0BH
;定义INTCON控制寄存器
CCP1IF
EQU
2H
;定义CCP1IF
CCP1CON
EQU
17H
;定义CCP1CON控制寄存器
CCPR1L
EQU
0EH
;定义CCPR1L控制寄存器
CCPR1H
EQU
0FH
;定义CCPR1H控制寄存器
PIR1
EQU
0CH
;定义第一外设中断标志寄存器
PIR2
EQU
0DH
;定义第二外设中断标志寄存器
TMR1L
EQU
0EH
;定义TMR1L
TMR1H
EQU
0FH
;定义TMR1F
ADRESH
EQU
1EH
;定义ADRESH
ADCON0
EQU
1FH
;定义数/模转换器ADC的寄存器
PIE1
EQU
8CH
;定义第一外设中断屏蔽寄存器
PIE2
EQU
8DH
;定义第二外设中断屏蔽寄存器
ADCON1
EQU
9FH
;定义数/模转换器ADC的寄存器
T1CON
EQU
10H
;定义TIMER1控制寄存器
RP1
EQU
06H
;定义状态寄存器中的页选位RP1
RP0
EQU
05H
;定义状态寄存器中的页选位RP0
Z
EQU
02H
;定义状态寄存器中的0标志位Z
C
EQU
00H
;定义状态寄存器中的标志位C
TMR1IF
EQU
00H
;定义第二外设中断屏蔽寄存器中的TMR1IF
DATA1
EQU
20H
;定义外循环变量
DATA2
EQU
21H
;定义内循环变量
TEMP
EQU
22H
;定义临时变量存储端口D的输入
W_TEMP
EQU
25H
;定义临时变量W_TEMP
S_TEMP
EQU
26H
;定义临时变量S_TEMP
SCALER
EQU
27H
;定义临时变量SCLEAR
AD_STATUS
EQU
28H
;定义临时变量AD_STATUS
SIGN
EQU
22H
;定义临时变量SIGN
SUN
EQU
24H
;定义临时变量SUN
INDEX
EQU
25H
;定义临时变量INDEX
W_BUF
EQU
26H
;定义临时变量W_BUF
VALUE
EQU
27H
;定义临时变量VALUE
NUM
EQU
28H
;定义临时变量NUM
COUNT1
EQU
1AH
;定义存储外循环次数的变量
COUNT2
EQU
0FFH
;定义存储内循环次数的变量
; ***************************主程序开始*********************************
ORG
00H
NOP
;空指令
GOTO
MAIN
ORG
04H
;中断向量的地址为04H
GOTO
INT
;跳到中断子程序
; *****************************中断子程序开始****************************
INT
MOVWF
W_TEMP
;W寄存器的
内容
财务内部控制制度的内容财务内部控制制度的内容人员招聘与配置的内容项目成本控制的内容消防安全演练内容
存储
SWAPF
STATUS,0
;将STATUS寄存器中高低字节交换
MOVWF
S_TEMP
;交换后的结果存入S_TEMP
BCF
STATUS,RP0
;转到体0
BCF
STATUS,RP1
;
BTFSC
PIR1,TMR1IF
;查看是否TMR1中断
GOTO
NEXT1
;是
GOTO
NEXT2
;否
NEXT1
BTFSC
SIGN,0
;察看SIGN的第0位是否为0
GOTO
NEXT3
;否
BCF
PORTC,2
;是
NEXT3
COMF
SIGN,1
;SIGN取反
BCF
PIR1,TMR1IF
;清中断标志位
CLRF
TMR1L
;对TMR1重新输入值0F548H
MOVLW
0F5H
;
MOVWF
TMR1H
;
MOVLW
48H
;
MOVWF
TMR1L
;
NEXT2
SWAPF
S_TEMP,0
;中断前的STATUS的内容,重新装入
MOVWF
STATUS
;
SWAPF
W_TEMP,1
;中断前的W的内容重新装入
SWAPF
W_TEMP,0
;
RETFIE
; ********************************主程序开始*****************************
MAIN
CALL
INITIAL
;调用初始化子程序
LOOP
CALL
AAA
;调用AAA输出子程序
NOP
S_0
BTFSS
SIGN,0
;SIGN为1,则转到S_1
GOTO
S_0
;
S_1
BTFSC
SIGN,0
;SIGN为0,则转到LOOP
GOTO
S_1
;
GOTO
LOOP
;
;***************************初始化子程序开始*********************************
INITIAL
BCF
STATUS,RP0
;转到体0
BCF
STATUS,RP1
;
CLRF
W_TEMP
;将各个临时寄存器清零
CLRF
W_BUF
;
CLRF
SIGN
;
BSF
STATUS,RP0
;转到体1
BCF
STATUS,RP1
;
BCF
TRISC,2
;将端口C的RC2设为输出
BCF
STATUS,RP0
;转到体0
BCF
STATUS,RP1
;
CLRF
T1CON
;清T1CON
MOVLW
0F5H
;将TMR1设为0F548H
MOVWF
TMR1H
;
MOVLW
048H
;
MOVWF
TMR1L
;
CLRF
INTCON
;清中断标志
BSF
INTCON,6
;中断使能
BSF
STATUS,RP0
;转到体1
BCF
STATUS,RP1
;
BSF
PIE1,0
;TMR1中断使能
BCF
STATUS,RP0
;转到体0
BCF
STATUS,RP1
;
CLRF
PIR1
;清中断标志
BSF
STATUS,RP0
;转到体1
BCF
STATUS,RP1
;
BSF
T1CON,0
;开TMR1
BCF
STATUS,RP0
;转到体0
BCF
STATUS,RP1
;
BSF
INTCON,7
;开第三梯队的中断
BCF
PORTC,2
;对各个变量清零
CLRF
NUM
;
CLRF
VALUE
;
CLRF
NUM
;
CLRF
INDEX
;
RETURN
;**********************AAA输出子程序***********************
AAA
BCF
STATUS,RP0
;转到体0
BCF
STATUS,RP1
;
MOVF
NUM,0
;
BTFSS
STATUS,Z
;NUM是否为零
GOTO
BBB
;不是,跳转
CLRF
NUM
;将NUM清零
BTFSC
INDEX,4
;INDEX是否大于16
CLRF
INDEX
;是,清零
CALL
TABLE
;否,查表
MOVWF
VALUE
;查表的值存到VALUE
INCF
INDEX,0
;INDEX加1
BBB
MOVF
VALUE,0
;
ADDWF
NUM,0
;VALUE+SUM存到W中
BTFSC
STATUS,C
;测试是否有进位
GOTO
NEXT4
;有,跳转
BCF
PORTC,2
;无
RETURN
NEXT4
BSF
PORTC,2
;有,RC2=1
RETURN
TABLE
MOVF
INDEX,W
ADDWF
PCL,F
RETLW
00H
RETLW
04H
RETLW
08H
RETLW
0CH
RETLW
10H
RETLW
14H
RETLW
14H
RETLW
14H
RETLW
14H
RETLW
14H
RETLW
14H
RETLW
0CH
RETLW
08H
RETLW
04H
RETLW
00H
END
(3)步进电机控制模块程序
#include <16F877.H>
#DEVICE ICD=TRUE
#DEVICE PIC16F877 *=16 ADC=10
#fuses XT,NONDT,NOPROTECT
#use delay(clock=4000000)
#byte PORTB=0x06
#byte PORTC=0x07
#byte PORTD=0x08
#byte OPTION=0x81
#byte INTCON=0x0B
#byte TICON=0x10
#byte PR2=0x92
#byte T2CON=0x12
//timer2负责竖直方向运动
#byte TMRO=0x1
//timer0负责水平方向运动
#byte TMR2=0x11
#byte PR2=0x92
#bit RB_1 = 0x6.1
//力旋钮开关地址
#bit RB_2 = 0x6.2
#6it RB_4 = 0x6.4
#bit RB_5 = 0x6.5
#bit RBPU=Ox81.7
#bit TOIF=OxOB.2
#bit TMR2IF=0xOC.1
#bit TMR20N=0x12.2
#bit RCIF=OxDC.5
#bit fwardl=0x7.0
//脉冲发送脚地址
#bit bwardl=0x7.1
#bit fward2=0x7.2
#bit bward2=0x7.3
#bit RC_4=0x7.4
#bit RC_5=0x7.5
#bit zflg=0x08.0
//光电开关信号
#bit yflg=0x08.2
#bit xflg=0x08.4
#bit sflg=0x08.6
long int I;
int j, k;
long str[12];
//接收到的字符串
char dir;
//方向
int a;
long int pspeed, zspeed,distant;
//运动参数
long int n_pulse;
//完成运动电平变换次数(脉冲数的2倍?int
ctmr0;
//水平方向电平变换,所需timer0定时周期数
int ctmr2;
//竖直方向电平变换,所需timer2定时周期数
float c_tmrO,ctmr2;
//所需周期数的计算值
void setup()
{
RBPG=1;
OPTION=0b10000110;
//TMR0定时方式,分频值取1:64
T2CON=ObOO111001;
//TMR2定时方式,分频值取1:32
enable_interrupts(CLOBAL);
enable_interrupts(int_rda);
RCIF=0;
set_tris_B(0b11111111);
set_tris_C(0b10000000);
set_tris_D (Oblllllll);
}
long int round(float,x)
//四舍五入函数
{
long int n;
n= (long int)(x):
if ((x-n)<0.5)
return(n);
else
return(n+l);
}
void forward1()
//(向左运动)
{
fward1=!fward1;
}
void backward1()
//水平后退(向右运动)
{
Bward1=bward1;
}
void forward2()
//竖直步近电机运动
{
fward2=!fward2;
}
void shoudong()
{
OPTION=0b10000101;
//TMR0定时方式,分频值取1:64
T2CON=0b00111001;
//TMR2定时方式,分频值取1:32
TMR2ON=1;
//TMR2开始工作
bward2=0;
//CCW接地,竖直向下
i= 0;
TMR0=211;
// TMR0定时64×45
output_high(PIN_C0 );
out put_high(PIN_C1);
out put_high(PIN_C2);
output_h igh(PIN_C3);
while(1)
{
while(input(PIN_B1)= 0&&zflg!=0)
{
if(TOIF==1)
{
TMR0 = 211;
TOIF = 0;
Forward1();
}
}
Fward1=1;
while (input(PIN_B2)=0&&yflg!=0)
//后退
{
if (TOIF==1)
{
TMR0 = 211;
TOIF = 0 ;
Backward1();
}
}
bward2=0;
//CCW接地,竖直向下
PR2=62;
//定时62*32us
output_low(PIN_4);
while(input(PIN_B4)==0&&xflg!=0)
{ //打开竖直电机制动
if(TMR2IF==1)
{
TMR2IF=0;
forward2();
}
//output_high(PIN_C4)
hward2=1;
//CCW接高,竖直向上
PR2=31;
//定时3l×32us,速度10mm/s
Output_low(PIN_C4);
while (input(PIN_B5 )==0&&sflg!=0)
{
if(TMR2IF==1)
{
TMR2IF=0;
forward2();
}
}
//output_high(PIN_C4);
//关闭竖直电机制动
output_high(PIN_CO);
output_high(PIN_C1 );
output_high(PIN_C2);
output_high(PIN_C3);
nable_interrupts(GLOBAL);
void qidong()
{
output_low(PlN_C4);
while(RCIF!=1)
{
i=0;
bward2=1;
while(sflg!=0&&i<3000)
//以20mm每秒的速度上升30mm
{
forward2();
Delay_us(500);
i++;
}
output_low(PIN_C4);
while(RCIF!=1)
{
i=0;
bward2 = 0;
while (xflg!=0&&<3500)
//以25mm/s的速度下降35mm;撞击,接触0.2s
{
forward2() ;
delay_us(400);
i++;
}
delay_ms(200);
i= 0;
bward2 = 1;
while(sflg!=0&&i<500)
//以25mm/s的速度上升5mm
{
forward2();
delay_us(400);
i+ +;
}
delay_ms(1000);
//延时1s,等待上位机判断有无电流产生
if(RCIF!=1)
{ bward2=1;
i= 0;
while(sflg!=0 && i<2500)
//以20mm每秒的速度上升25mm
{forward2();
Delay_us(500) ;
i++;
}
}
}
//output_high(PIN_C4);
//--------------------------------------------------
void reset()
{
output_low(PIN_C4 );
//打开竖直电机制动
bward2= 1;
//竖直方向向上
while(sflg!=0&&yflg!=0)
//右起点、上起点都没到
{backward1();
forward2();
delay_ms(2)
}
while(sflg!=0)
{bward2=1;
forward2();
delay_ms(1);
}
while(yflg!=0)
//已到上起点起点,往右运动
{
backward1();
delayms(3);
}
//output_high(PIN_C4 )
//关闭竖直电机制动
//---------------------------------------------------
#int rda
void zidong()
{
for(i=0;i<12;i++)
{
str[i]=getc();
}
delay_ms(5);
disabIe_intcrrupts(GLOBAL);
n_puIse=0;
OPTION=0b10000000;
//TMR0分频值取1:2
TMR0=211 ;
//TMR0定时2*45us
T2CON=0600000001:
//TMR2定时方式,分频值取1:1
RCIF=O;
if(str[0]!=’#'&&str[1]!=’#’)
{
putc('N');
goto END;
}
else
{
putc('Y');
if (str[2]=='E')
reset();
else
{dir=str[2];
distant=100*(str[3]-48)+10*(str[4]-48+(str[5]-48);
//字符串转换为数值
pspeed=100*(str[6]-48)+10*(str[7]-48)+(str[8]-48);
zspeed=100*(str[9]-48)+10*(str[10]-48)+(str[11]-48);
n_pulse=distant*50;
//完成行程总脉冲数
c_tmr0=11000/pspeed;
//所需周期数的计算值
c_tmr2= 3750/zspeed;
ctmr0=round(c_tmrO);
//实际所用为四舍五入取整
ctmr2=round(c_tmr2);
i = 0;
j = 0;
k = 0;
output_high(PIN_C0);
output_high(PIN_C1);
output_high(PIN_C2);
output_high(PIN_C3);
qidong();
//启动
bward2=0;
output_low(PIN_C4);
//打开竖直电机制动
TMR20N=1;
//开timer2
PR2=40;
//TMR2定时40us
while(i<=n_pulse)
{
if(TOIF==1)
{
TOIF=O;
TMRO = 211;
j++;
}
if(j==ctmr0)
{.
j=O;
if(dir=='0')
{
if(zflg!=0)
{
Forward1();
i++;
}
}
else
{if(yflg!=0)
{backwardl();
i++;
}
if(TMR2IF==1)
{
TMR2IF=0;
k++;
}
if(k==ctmr2&&xflg!=0)
{
k=0;
forward2();
}
}
output_high(PIN_CO);
output_high(PIN_C1);
output_high(PIN_C2);
output_high(PIN_C3);
}
}
output_high(PIN_C4);
//关闭竖直电机制动
END:
enable_interrupts(GLOBAL);
//----------------------------------------------------------
main()
(
setup();
enable_interrupts(int_rda);
enable_interrupts(GLOBAL);
while (1)
{
if((RB_1==0||(RB2 ==O||(RB_4==0||(RB_5= 0)) //有键按下为手动
{shoudong();
}
else
{
i=0;
}
(4)直流无刷电机控制模块程序
#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
#define VOLOFF 0X49
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};
//状态寄存器表
(2)PIC16F877初始化子程序
void INIT877()
{
PORTC=0X0FF;
//关断所有MOSFET
TRISC=0X02;
//设置C口输出
PIE1=0X00;
//中断寄存器初始化,关断所有中断
TRISA=0XCF;
//设置RA4,RA5 输出
TRISB=0XEF;
//RB 口高3位输入,采集电机三相的霍尔信号
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部件开始工作
}
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");
}
}
}
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;)
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()
{
char x;
lowpower=0;
voltage>>=1;
//电压值换为7位,以利于单字节运算
if(voltage>1);
CCPR1L=FULLDUTY;
asm("CLRWDT");
}while(voltage>5);
PORTC=new[state1];
//C口输出相应的信号触发2个MOS管
if(sp1==1){spe=1;sp1=0;}
else
{
//如果转速很低,则spe置1
spe=0;sp1=0;
speedcount<<=1;
state3=(TMR1H>>2);
//否则,spe=0,计转速
speed=speedcount+state3;
//speed寄存器为每256 μs加1
}
speedcount=0;
}
}
//AD采样子程序
void AD()
{
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 CURPI()
{
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()
{
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;
speep=speek*SPEB;
tsh1=tsh-0x38;
//得到计算用的手柄值
speek=tsh1-speed1;
if(tsh1<0) {speuk=0;gcur=0;}
//当手柄值低于1.1 V时,则认为手柄给定为零
else {
//否则,计算相应的转速环输出
if(tsh1>=GSPEH)
//限制最大转速
tsh1=GSPEH;
speuk=speuk+speek*SPEA-speep;
//计算得转速环输出
if(speuk<=0X00) {speuk=0x00;gcur=0x00;}//转速环输出处理
else if(speuk>GCURHILO)
{//转速环输出限制,即限制最大电流约12 A
speuk=GCURHILO;gcur=GCURH;}
else
{//调速状态时的输出
gcur=(speuk>>4)&0x0ff;
}
}
}
_1209066871.unknown