减速直流电机角度控制
//2014年课设 1100850221 欧宇
//直流减速电机角度控制
//芯片89c52
//驱动芯片L298orL293
//仅供参考,勿ctrl+a and ctrl+c
#include //c51,c52头文件均可
#include
#define NOP _nop_()
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define LCD_COM 0
#define LCD_DAT 1
sbit LcdRS=P2^7;//1602用IO 口衣初始化而定
sbit LcdRW=P2^6;
sbit LcdEN=P2^5;
sbit CA = P3^2;//控制程序用IO 口
sbit CB = P2^1;
sbit IN1=P2^2;
sbit IN2=P2^3;
sbit ENA=P3^7;
sbit mark=P3^6;//电机停止标志 占空比可调 精度过高 否者难以判断电机真正停止
uint tjd,a,c=6000;//c=可为1500以上100000以下任意数值
int post=0,s,real=0,tpd;
void FreqA() interrupt 0
{
if(CB) {post--;real--;}//post可用于参加计算,r
else {post++;real++;}//real禁止用于别处,
} //real直接显示,防止角度产生错误 ?
void timer0() interrupt 1 using 1
{
ENA=~ENA; //周期为100000um 25khz更好,本人用c52实现会出现时序问题所以将就
着点 ?
a=10000-c;//10000个单位占空比, ?
if(!ENA){TH0=(65536-c)/256;//精度超高
TL0=(65536-c)%256;}
else {TH0=(65536-a)/256;
TL0=(65536-a)%256;}
}
void timer1() interrupt 3 using 2 //校正方法为线性差值减缩小法 得到结果是tpd=post*0.18 {
s=(tpd-post*0.18)*60;//设置角度-实际角度 60为MALAB 计算得出较优比例
if(s>3000) s=3000;//限制最大速? 否者电机输出脉冲过快引起误差
if(s
if(s>0) {IN1=0; IN2=1;TR0=1;TR1=1;mark=0;}//正反转
if(s
if(s>-10.8&&s
if(s>-10.8&&s
if (s
c=10000-s; //PWM周期为10UM //s值越大,速度越快
//测试推荐 1500
}
///////1602初始化 ///
void time(unsigned int t)//模块化1602 初始,百度很多
{
uint i;
for(i=0;i
}
void LCD_WRITE(unsigned char x,bit WS)
{
P1=x;
LcdRW=0; LcdRS=WS;
LcdEN=1; time(50); LcdEN=0;
}
void LCD_Initial()
{
LCD_WRITE(0x38,LCD_COM); time(600);
LCD_WRITE(0x38,LCD_COM); time(600);
LCD_WRITE(0x01,LCD_COM); time(600);
LCD_WRITE(0x06,LCD_COM); time(600);
LCD_WRITE(0x0c,LCD_COM); time(600);
}
void GotoXY(unsigned char x,unsigned char y)
{
unsigned char code table[4]={0x00,0x40,0x10,0x50};
LCD_WRITE(0x80+table[x]+y, LCD_COM);
}
void PutCh(uchar m)
{
LCD_WRITE(m,LCD_DAT);
}
void Print(unsigned char *str)
{
while(*str!='\0')
{
PutCh(*str);
str++;
}
}
/////////1602初始化 ///
void Delay1ms(uint count)
{
uint i,j;
for(i=0;i
for(j=0;j
}
//////键盘扫描///////
uchar getbit(uchar x)
{
if(x==0x0e) return 0;
if(x==0x0d) return 1;
if(x==0x0b) return 2;
if(x==0x07) return 3;
return 0;
}
unsigned char Getkey()
{
uchar m,k,n;
P0=0x0f; m=P0;
P0=0xf0; k=P0>>4;
P0=0xff; //此处使用了翻转扫描法
n=getbit(k)+(3-getbit(m))*4;//此处如果用case 语句更明了
if(k==0x0f) n=16;
return n;
}
//////键盘扫描///////
void main()
{
int p;
uchar i=0,key,k[4];
IE=0x8f;//1000 0111
IT0=1;
TMOD=0X11;
mark=0;
LCD_Initial();
GotoXY(0,0); Print("set:");
GotoXY(1,0); Print("real:");
Delay1ms(100);
while(1) //由于时序问题,此处使用定时器键盘互换工作原理
{
if(TR0==0&&TR1==0)//if(TR0==0)表示电机无扰动已经停止才开始扫描键盘 {
key=Getkey();
if(key!=16)
{
Delay1ms(100);
k[i]=key;
Delay1ms(100);
if(i
{
GotoXY(0,5+i);
PutCh(k[i]+'0');//显示按键按了什么
}
i++;
}
if(i==4)
{
i=0; //xxx=0
tjd=k[0]*100+k[1]*10+k[2];//tjd=xxx*10+key,能省很多空间哦 GotoXY(0,9);
PutCh((tjd/100)%10+'0');//显示真正录入角度
PutCh((tjd/10)%10+'0');
PutCh(tjd%10+'0');
TH1=(65536-500)/256;
TL1=(65536-500)%256;
TH0=(65536-20)/256;//快速进入中断调速否者电机失控
TL0=(65536-20)%256;
if(k[3]==10)tpd=tjd;post=0;//加度数
if(k[3]==11)tpd=post*0.18-tjd;//减度数
TR0=1; TR1=1;
IN1=0;//开启电机
}
}
GotoXY(1,7);
p=real*18;
LCD_WRITE((p/10000)%10+0x30,LCD_DAT); //显示绝对脉冲角度, LCD_WRITE((p/1000)%10+0x30,LCD_DAT);
PutCh((p/100)%10+'0');
PutCh('.');
PutCh((p/10)%10+'0');
PutCh(p%10+'0');
}
}