电机速度控制PIC课设报告程序.docx
《电机速度控制PIC课设报告程序.docx》由会员分享,可在线阅读,更多相关《电机速度控制PIC课设报告程序.docx(15页珍藏版)》请在冰豆网上搜索。
电机速度控制PIC课设报告程序
附录:
#include
__CONFIG(0x00F1);
//__CONFIG(0x3F71);
#defineLCD_ERD6
#defineLCD_RWRD5
#defineLCD_RSRD4
#defineCOM0
#defineDAT1
#defineLINE10b10000000
#defineLINE20b11000000
#defineLEDRB5
#defineDN_POSITIONLINE2+15//第2行显示速度回差的个位位置
bank1charDD[16];
constcharMENU0[2][17]={
{"PIC16F887"},
{"PICC9.5"},
};
constcharLINE[2]={LINE1,LINE2};
constunsignedintND[11]={200,500,800,1100,1400,1700,2000,2300,2600,2900,3200};
//定义结构体类型STRU的变量KEY
structSTRU
{unsignedSET:
3;
unsignedINC:
1;
unsignedDEC:
unsignedFLAG:
unsignedCHANGE:
unsignedSETINT:
}KEY;
union//联合体AD_RESULT存放AD转换结果
{
unsignedintAD_TEMP;
charAD[2];
}AD_RESULT;
//EEPROM第一单元占空比D初值,第二单元转速误差运行值DN初值
__EEPROM_DATA(200,10,255,255,255,255,255,255);
unsignedcharD;//占空比10倍
unsignedHT;//高电平时间(us)
unsignedintN0_MIN=150;
unsignedintN0_MAX=2048;
unsignedintN0;//期望转速值
unsignedintN;//实际测速值
unsignedcharDN;//转速误差
unsignedlongn;
charWW,QW,BW,SW,GW;
unsignedcharT0N;
unsignedintDN_OLD;
unsignedintT=0;
unsignedintN1;
unsignedintN2;
intAD_SUB(void);
voidCSH(void);
voidDISP_N0_DN(unsignedint,unsignedchar);
voidDISP_N_D(unsignedint,unsignedchar);
voidCAP_CSH(void);
voidPWM_CSH(unsignedint);
voidDUTY_SET(unsignedint);
voidAD_CSH(void);
voidLCD_CSH(void);
voidLCD_WRITE_4(char,char);
voidLCD_WRITE(char,char);
voidLCD_BUSY(void);
charLCD_READ(void);
voidDISP_C(char);
voidDISP_MENU(constchar*A);
voidBCD(unsignedint);
voidDELAY(unsignedint);
voidDELAY_I(unsignedint);
voidDELAY_US(char);
voidinterruptINT_ISR(void);
voidchange(void);
//unsignedintDN_GET(void);
//宏定义:
清屏
#defineCLR_LCD()\
LCD_WRITE(0b00000001,COM);\
DELAY
(2)
//AD转换,期望转速N0取值N0_MIN~N0_MAX,并放大100倍
voidmain(void)
unsignedinti;
CSH();
DISP_MENU(*MENU0);
DELAY(100);
//DELAY(400);
CLR_LCD();
while
(1)
N0=AD_SUB();
DISP_N0_DN(N0,DN);//显示期望转速和转速误差允许值
DISP_N_D(N,D);
change();//显示实际转速和占空比
while(KEY.FLAG==0)
{DELAY
(1);
i++;
if(i>200)LED=0;
if(i>400)break;
}
DN_OLD=DN;
while(KEY.FLAG==1)
if(KEY.SET==1)//进入修改,字符闪
LCD_WRITE(DN_POSITION,COM);//确定字符闪的位置
LCD_WRITE(0b00001111,COM);//字符闪
if(KEY.SETINT==1)
{if(KEY.SET==1)
N1=ND[T];
DELAY_US(3);
KEY.SETINT=0;T++;
if(T>10)T=0;
KEY.CHANGE=1;
if(KEY.INC==1)
{if(KEY.SET==1)DN++;
KEY.INC=0;
if(KEY.DEC==1)
{if(KEY.SET==1)DN--;
KEY.DEC=0;
if(KEY.CHANGE==1)//如果有修改,刷新显示
{DISP_N0_DN(N0,DN);
KEY.CHANGE=0;
if(KEY.SET==1)//刷新后重新开字符标闪
LCD_WRITE(0b00001101,COM);//字符闪
if(DN_OLD!
=DN)
EEPROM_WRITE(1,DN);//写入速度控制的回差值,在EEPROM的地址1
voidchange(void)
{unsignedintj;
if(N>N0+DN)
HT--;
if(HT>1000)HT=1000;
DUTY_SET(HT);
DELAY(300);
elseif(N{HT++;if(HT>1000)HT=0;DUTY_SET(HT);DELAY(300);}LED=1;j=0;}voidCSH(void){ANSELH=0;//关闭B口模拟引脚,设为I/O引脚TRISB=0b00001111;OPTION=0b00010111;//B口上拉,且下降沿中断INTCON=0b11010000;//GIE=1;PEIE=1;INTE=1;RBIE=1;IOCB=0b00001110;//B口电平变化中断控制寄存器,RB1、RB2电平变化产生中断,在RBIE=1的前提下KEY.FLAG=0;KEY.SET=0;TMR1H=TMR1L=0;T1CON=0b00110001;//1:8分频TRISD=0b00000000;TRISC=0b00100000;HT=EEPROM_READ(0);DN=EEPROM_READ(1);LCD_CSH();CAP_CSH();PWM_CSH(HT);AD_CSH();}intAD_SUB(void){GODONE=1;while(GODONE==1);ADIF=0;AD_RESULT.AD[0]=ADRESL;AD_RESULT.AD[1]=ADRESH;n=AD_RESULT.AD_TEMP;n*=350;N2=n/1023+N1;returnN2;}voidDISP_N0_DN(unsignedintSTART_N0,unsignedcharDELTA_N){LCD_WRITE(0b00001100,COM);//不闪LCD_WRITE(LINE2,COM);//即第2行的第0个字符BCD(START_N0);//将要显示的起动占空比值做BCD转换LCD_WRITE('N',DAT);//在当前位置显示字符'N'LCD_WRITE('0',DAT);//在当前位置显示字符'0'LCD_WRITE('=',DAT);//在当前位置显示字符':'LCD_WRITE(QW+0x30,DAT);//显示千位LCD_WRITE(BW+0x30,DAT);//显示百位LCD_WRITE(SW+0x30,DAT);//显示十位LCD_WRITE(GW+0x30,DAT);//显示个位LCD_WRITE('r',DAT);//在当前位置显示字符'r'LCD_WRITE('p',DAT);//在当前位置显示字符'/'LCD_WRITE('m',DAT);//在当前位置显示字符'mLCD_WRITE('',DAT);//在当前位置显示空格'BCD(DELTA_N);//将要显示的转速n控制回差量做BCD转换LCD_WRITE('D',DAT);//在当前位置显示字符'D'LCD_WRITE('n',DAT);//在当前位置显示字符'n'LCD_WRITE('=',DAT);//在当前位置显示字符':'LCD_WRITE(SW+0x30,DAT);//显示十位LCD_WRITE(GW+0x30,DAT);//显示个位}voidDISP_N_D(unsignedintR1,unsignedcharDUTY)//速度在R1,占空比DUTY{LCD_WRITE(0b00001100,COM);//不闪BCD(R1);LCD_WRITE(LINE1,COM);//DDRAM地址,第1行的第5个字符LCD_WRITE('',DAT);//在当前位置显示空格''LCD_WRITE('N',DAT);LCD_WRITE('=',DAT);LCD_WRITE(QW+0x30,DAT);//显示千位LCD_WRITE(BW+0x30,DAT);//显示百位LCD_WRITE(SW+0x30,DAT);//显示十位LCD_WRITE(GW+0x30,DAT);//显示个位LCD_WRITE('r',DAT);//在当前位置显示字符'r'LCD_WRITE('p',DAT);//在当前位置显示字符'/'LCD_WRITE('m',DAT);//在当前位置显示字符'm'LCD_WRITE('',DAT);//在当前位置显示空格''BCD(DUTY);//将要显示的转速n控制回差量做BCD转换LCD_WRITE('D',DAT);//在当前位置显示字符'D'LCD_WRITE('=',DAT);//在当前位置显示字符':'LCD_WRITE(SW+0x30,DAT);//显示十位LCD_WRITE(GW+0x30,DAT);//显示个位LCD_WRITE('%',DAT);//显示字符'%'}voidCAP_CSH(void){TRISC2=1;CCP1CON=0b00000110;TMR1H=TMR1L=0;T1CON=0b00110001;CCP1IF=0;CCP1IE=1;GIE=1;PEIE=1;}voidinterruptINT_ISR(void){longX;unsignedintTZ;if(CCP1IF==1){TMR1H=TMR1L=0;TZ=(CCPR1H<<8)|CCPR1L;X=7500000;N=X/TZ;CCP1IF=0;}if(INTF==1){DELAY_I(30);INTF=0;KEY.SET+=1;KEY.FLAG=1;if(KEY.SET>1){KEY.SET=0;KEY.FLAG=0;RBIE=0;}//TMR1ON=1;RBIE=1;//PEIE=1;//GIE=1;T0IE=1;TMR0=0;T0IF=0;T0N=0;}if(RBIF==1){DELAY_I(30);if(RB3==0&&KEY.FLAG==1){KEY.SETINT=1;T0N=0;}if(RB2==0&&KEY.FLAG==1){KEY.DEC=1;T0N=0;}if(RB1==0&&KEY.FLAG==1){KEY.INC=1;T0N=0;}RBIF=0;}if(T0IF==1){T0IF=0;TMR0=0;T0N++;if(T0N>100)//约6S{KEY.FLAG=0;KEY.SET=0;T0IE=0;}}}//设置周期为1000US的PWM输出voidPWM_CSH(unsignedintht){PR2=249;DUTY_SET(ht);//X=0b0011001000;T2CON=0b00000101;//预分频比为1:4}//设置PWM波的高电平时间voidDUTY_SET(unsignedintht){CCPR2L=(ht>>2)&0x0FF;CCP2CON=((ht<<4)&0x30)|0x0C;D=ht/10;//由高电平时间计算占空比}voidAD_CSH(void){TRISA0=1;ANSEL=0x01;ANSELH=0;ADCON1=0b10000000;//A/D结果右对齐,参考电压GND,VDDADCON0=0b10000001;//AD转换时钟8us(32Tosc),AD通道AN0,GODONE=0;AD模块使能;DELAY_US(2);//延时20usAD_SUB();//AD转换}voidLCD_CSH(void){DELAY(20);LCD_WRITE_4(0b0011,COM);DELAY(1);LCD_WRITE_4(0b0011,COM);DELAY_US(10);LCD_WRITE_4(0b0011,COM);DELAY_US(10);LCD_WRITE_4(0b0010,COM);LCD_BUSY();LCD_WRITE(0b00101000,COM);//4位数据格式,2行,5*7点阵LCD_WRITE(0b00001100,COM);//打开显示,光标不显示,不闪烁CLR_LCD();LCD_WRITE(0b00000110,COM);//光标右移,不整体移动}//将R1低4位写入LCD,FLAG选择写命令(0)或者写数据(1)voidLCD_WRITE_4(charR1,charFLAG){LCD_RW=0;NOP();//写模式LCD_RS=FLAG;NOP();//选择写命令还是写数据PORTD&=0xF0;NOP();//RD低4位清零LCD_E=1;NOP();//LCD使能PORTD|=(R1&0x0F);NOP();//将R1低4位送到D端口低4位LCD_E=0;NOP();//使能端形成下降沿,开始送数据LCD_RS=0;NOP();//默认为写命令状态PORTD&=0xF0;//LCD4位数据输入端清零}//将一字节的R1写入LCD,FLAG选择写命令(0)或者写数据(1)//写之前先检查是否忙,写完后延时100us,分两次写4位数据/命令voidLCD_WRITE(charR1,charFLAG){charR2;LCD_BUSY();R2=(R1>>4)&0x0F;//先写入高4位LCD_WRITE_4(R2,FLAG);R2=R1&0x0F;//后写入低4位LCD_WRITE_4(R2,FLAG);DELAY_US(10);//延时100us}voidLCD_BUSY(void){unsignedcharR1;while(1){R1=LCD_READ();//读寄存器if((R1&0x80)==0x00)//最高位为忙标志位break;}}charLCD_READ(void){unsignedcharR1;TRISD|=0xF0;//D口低4位为输入LCD_RS=0;NOP();//选择命令LCD_RW=1;//写命令模式NOP();NOP();LCD_E=1;//LCD使能NOP();NOP();R1=0;R1=PORTD&0x0F;R1=(R1<<4)&0xF0;//读数据的高4位给R1高4位LCD_E=0;NOP();//使能端形成下降沿LCD_E=1;NOP();R1|=PORTD&0x0F;//读数据的低4位给R1低4位LCD_E=0;NOP();LCD_RW=0;TRISD&=0x0F;//D口低4位恢复为向LCD输出returnR1;}voidDISP_C(charline){chari;LCD_BUSY();LCD_WRITE(line,COM);for(i=0;i<16;i++)LCD_WRITE(DD[i],DAT);}voidDISP_MENU(constchar*A){chari,j;for(i=0;i<2;i++){for(j=0;j<16;j++)DD[j]=*A++;A++;DISP_C(LINE[i]);}}//从R1双字节数转换为十进制数万位-个位:WW,QW,BW,SW,GWvoidBCD(unsignedintR1)//延时nmsvoidDELAY(unsignedintn)voidDELAY_I(unsignedintn)//延时(n*10)usvoidDELAY_US(charn)
HT++;
if(HT>1000)HT=0;
LED=1;
j=0;
voidCSH(void)
ANSELH=0;//关闭B口模拟引脚,设为I/O引脚
TRISB=0b00001111;
OPTION=0b00010111;//B口上拉,且下降沿中断
INTCON=0b11010000;//GIE=1;PEIE=1;INTE=1;RBIE=1;
IOCB=0b00001110;//B口电平变化中断控制寄存器,RB1、RB2电平变化产生中断,在RBIE=1的前提下
KEY.FLAG=0;
KEY.SET=0;
TMR1H=TMR1L=0;
T1CON=0b00110001;//1:
8分频
TRISD=0b00000000;
TRISC=0b00100000;
HT=EEPROM_READ(0);
DN=EEPROM_READ
LCD_CSH();
CAP_CSH();
PWM_CSH(HT);
AD_CSH();
intAD_SUB(void)
{GODONE=1;
while(GODONE==1);
ADIF=0;
AD_RESULT.AD[0]=ADRESL;
AD_RESULT.AD[1]=ADRESH;
n=AD_RESULT.AD_TEMP;
n*=350;
N2=n/1023+N1;
returnN2;
voidDISP_N0_DN(unsignedintSTART_N0,unsignedcharDELTA_N)
{LCD_WRITE(0b00001100,COM);//不闪
LCD_WRITE(LINE2,COM);//即第2行的第0个字符
BCD(START_N0);//将要显示的起动占空比值做BCD转换
LCD_WRITE('N',DAT);//在当前位置显示字符'N'
LCD_WRITE('0',DAT);//在当前位置显示字符'0'
LCD_WRITE('=',DAT);//在当前位置显示字符':
'
LCD_WRITE(QW+0x30,DAT);//显示千位
LCD_WRITE(BW+0x30,DAT);//显示百位
LCD_WRITE(SW+0x30,DAT);//显示十位
LCD_WRITE(GW+0x30,DAT);//显示个位
LCD_WRITE('r',DAT);//在当前位置显示字符'r'
LCD_WRITE('p',DAT);//在当前位置显示字符'/'
LCD_WRITE('m',DAT);//在当前位置显示字符'm
LCD_WRITE('',DAT);//在当前位置显示空格'
BCD(DELTA_N);//将要显示的转速n控制回差量做BCD转换
LCD_WRITE('D',DAT);//在当前位置显示字符'D'
LCD_WRITE('n',DAT);//在当前位置显示字符'n'
voidDISP_N_D(unsignedintR1,unsignedcharDUTY)//速度在R1,占空比DUTY
LCD_WRITE(0b00001100,COM);//不闪
BCD(R1);
LCD_WRITE(LINE1,COM);//DDRAM地址,第1行的第5个字符
LCD_WRITE('',DAT);//在当前位置显示空格''
LCD_WRITE('N',DAT);
LCD_WRITE('=',DAT);
LCD_WRITE('m',DAT);//在当前位置显示字符'm'
BCD(DUTY);//将要显示的转速n控制回差量做BCD转换
LCD_WRITE('%',DAT);//显示字符'%'
voidCAP_CSH(void)
TRISC2=1;
CCP1CON=0b00000110;
T1CON=0b00110001;
CCP1IF=0;
CCP1IE=1;
GIE=1;
PEIE=1;
voidinterruptINT_ISR(void)
longX;
unsignedintTZ;
if(CCP1IF==1)
TZ=(CCPR1H<<8)|CCPR1L;
X=7500000;
N=X/TZ;
if(INTF==1)
{DELAY_I(30);
INTF=0;
KEY.SET+=1;
KEY.FLAG=1;
if(KEY.SET>1)
{KEY.SET=0;
RBIE=0;
//TMR1ON=1;
RBIE=1;
//PEIE=1;
//GIE=1;
T0IE=1;
TMR0=0;
T0IF=0;
T0N=0;
if(RBIF==1)
if(RB3==0&&KEY.FLAG==1)
{KEY.SETINT=1;
if(RB2==0&&KEY.FLAG==1)
{KEY.DEC=1;
if(RB1==0&&KEY.FLAG==1)
{KEY.INC=1;
RBIF=0;
if(T0IF==1)
{T0IF=0;
T0N++;
if(T0N>100)//约6S
{KEY.FLAG=0;
T0IE=0;
//设置周期为1000US的PWM输出
voidPWM_CSH(unsignedintht)
PR2=249;
DUTY_SET(ht);//X=0b0011001000;
T2CON=0b00000101;//预分频比为1:
4
//设置PWM波的高电平时间
voidDUTY_SET(unsignedintht)
CCPR2L=(ht>>2)&0x0FF;
CCP2CON=((ht<<4)&0x30)|0x0C;
D=ht/10;//由高电平时间计算占空比
voidAD_CSH(void)
TRISA0=1;
ANSEL=0x01;
ANSELH=0;
ADCON1=0b10000000;//A/D结果右对齐,参考电压GND,VDD
ADCON0=0b10000001;//AD转换时钟8us(32Tosc),AD通道AN0,GODONE=0;AD模块使能;
DELAY_US
(2);//延时20us
AD_SUB();//AD转换
voidLCD_CSH(void)
DELAY(20);
LCD_WRITE_4(0b0011,COM);
DELAY_US(10);
LCD_WRITE_4(0b0010,COM);
LCD_BUSY();
LCD_WRITE(0b00101000,COM);//4位数据格式,2行,5*7点阵
LCD_WRITE(0b00001100,COM);//打开显示,光标不显示,不闪烁
LCD_WRITE(0b00000110,COM);//光标右移,不整体移动
//将R1低4位写入LCD,FLAG选择写命令(0)或者写数据
voidLCD_WRITE_4(charR1,charFLAG)
LCD_RW=0;NOP();//写模式
LCD_RS=FLAG;NOP();//选择写命令还是写数据
PORTD&=0xF0;NOP();//RD低4位清零
LCD_E=1;NOP();//LCD使能
PORTD|=(R1&0x0F);NOP();//将R1低4位送到D端口低4位
LCD_E=0;NOP();//使能端形成下降沿,开始送数据
LCD_RS=0;NOP();//默认为写命令状态
PORTD&=0xF0;//LCD4位数据输入端清零
//将一字节的R1写入LCD,FLAG选择写命令(0)或者写数据
//写之前先检查是否忙,写完后延时100us,分两次写4位数据/命令
voidLCD_WRITE(charR1,charFLAG)
charR2;
R2=(R1>>4)&0x0F;//先写入高4位
LCD_WRITE_4(R2,FLAG);
R2=R1&0x0F;//后写入低4位
DELAY_US(10);//延时100us
voidLCD_BUSY(void)
unsignedcharR1;
R1=LCD_READ();//读寄存器
if((R1&0x80)==0x00)//最高位为忙标志位
break;
charLCD_READ(void)
TRISD|=0xF0;//D口低4位为输入
LCD_RS=0;NOP();//选择命令
LCD_RW=1;//写命令模式
NOP();NOP();
LCD_E=1;//LCD使能
R1=0;
R1=PORTD&0x0F;
R1=(R1<<4)&0xF0;//读数据的高4位给R1高4位
LCD_E=0;NOP();//使能端形成下降沿
LCD_E=1;NOP();
R1|=PORTD&0x0F;//读数据的低4位给R1低4位
LCD_E=0;NOP();
LCD_RW=0;
TRISD&=0x0F;//D口低4位恢复为向LCD输出
returnR1;
voidDISP_C(charline)
chari;
LCD_WRITE(line,COM);
for(i=0;i<16;i++)
LCD_WRITE(DD[i],DAT);
voidDISP_MENU(constchar*A)
chari,j;
for(i=0;i<2;i++)
for(j=0;j<16;j++)
DD[j]=*A++;
A++;
DISP_C(LINE[i]);
//从R1双字节数转换为十进制数万位-个位:
WW,QW,BW,SW,GW
voidBCD(unsignedintR1)
//延时nms
voidDELAY(unsignedintn)
voidDELAY_I(unsignedintn)
//延时(n*10)us
voidDELAY_US(charn)
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1