目录
步进电机原理
原理是给线圈通电产生磁场然后转子旋转,通过控制不同方向的线圈使得中间的转子旋转,一般就是ABCDABCDABCD这样去控制旋转。线圈与转子的具体控制有点玄幻,基本不会出现空转的情况。
步进电机使用
一定要根据手册使用步进电机,例如以下重点参数
- 步进角(每节拍转子转动的角度)
- 减速比(靠外部齿轮)— 意思大概是转子转动1600°,然而外界显示出来只转了1°
- 供电电压(一般不是5V,更高的电压)
- 启动频率(驱动电机输入的频率有上线,因为机械结构有延迟)
- 可以A(AB)B(BC)C(CD)D这样驱动步进电机——四相八拍
步进电机的控制
- 旋转方向—顺逆时针——简单的一个bit变量判定方向即可
- 旋转一定角度——通过bea输入的数值和使用手册控制
- 来回摆动式旋转——如下
- 配合按键完成花样旋转——如下
本次控制使用的是四相电机,仅仅只需要运用到4位,为减少位节的使用,防止影响其他外设的工作,这里有一步特殊的取值
P1=(P1&0xf0)|(motor_code[index]&0x0f);//屏蔽高4位的影响,只对P1低4位进行赋值,高4位和原来一样
这段代码实现的功能是
- 顺逆时针旋转
- 双击来回旋转(一定角度)
核心的步进电机代码
void motor_run()
{
//步进电机转动函数
if(beat || swing_flag)
{
if(dir==0 && curbeat>0)
{
P1=(P1&0xf0)|(motor_code[index]&0x0f);//屏蔽高4位的影响,只对P1低4位进行赋值,高4位和原来一样
index--;
if(index==-1) index=7;
curbeat--;
}
else if(dir==1 && curbeat<64)
{
P1=(P1&0xf0)|(motor_code[index]&0x0f);
index++;
if(index==8) index=0;
curbeat++;
}
if(curbeat==0 && swing_flag){dir=~dir;}
if(curbeat==64 && swing_flag) {dir=~dir;}
if(beat>0)beat--;
}
}
void timer_2ms() interrupt 1
{
static unsigned char count=0;
TH0=63536>>8;
TL0=63536;
cur_sta_update();
count++;
if(count==5)
{
count=0;
motor_run();
}
}
全部代码
#include<reg51.h>
sbit k1=P2^0;
sbit k2=P2^1;
sbit k3=P2^3;
char beat=0;
char curbeat=0;
char index=0;
bit swing_flag=0;
bit dir=1;
unsigned char cur_sta[3]={1,1,1};
unsigned char pre_sta[3]={1,1,1};
unsigned char code motor_code[8]={0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09};
void key_action(unsigned char key_value)
{
if(key_value==1) //第一个按键
{
if(swing_flag==0)
{
dir=1;
beat=8;
}
}
else if(key_value==2) //第二个按键
{
if(swing_flag==0)
{
dir=0;
beat=8;
}
}
else if(key_value==3) ///两个按键同时按下
{
swing_flag=~swing_flag; //摇头功能控制flag
}
}
unsigned char key_scan()
{
char i;
char key_value=0;
//判断两个按键是否同时按下
for(i=0;i<2;i++)
{
if(pre_sta[i]!=cur_sta[i])
{
if(pre_sta[i])
{
if(i==1 && cur_sta[0]==0) //当第二个按键按下时,第一个按键也正好处于按下状态
key_value=3;
else
{
key_value=i+1;
}
}
pre_sta[i]=cur_sta[i];// 状态更新
}
}
return(key_value);
}
void cur_sta_update()
{
char i;
static unsigned char keybuff[3]={0xff,0xff,0xff};
//八次更新状态,要是按键对应的八位都为1则是按下
keybuff[0]=(keybuff[0]<<1)|k1;
keybuff[1]=(keybuff[1]<<1)|k2;
keybuff[2]=(keybuff[2]<<1)|k3;
//遍历三个按键
for(i=0;i<3;i++)
{
if(keybuff[i]==0xff)
cur_sta[i]=1;
else if(keybuff[i]==0x00)
cur_sta[i]=0;
}
}
void motor_run()
{
//步进电机转动函数
if(beat || swing_flag)
{
if(dir==0 && curbeat>0)
{
P1=(P1&0xf0)|(motor_code[index]&0x0f);//屏蔽高4位的影响,只对P1低4位进行赋值,高4位和原来一样
index--;
if(index==-1) index=7;
curbeat--;
}
else if(dir==1 && curbeat<64)
{
P1=(P1&0xf0)|(motor_code[index]&0x0f);
index++;
if(index==8) index=0;
curbeat++;
}
if(curbeat==0 && swing_flag){dir=~dir;}
if(curbeat==64 && swing_flag) {dir=~dir;}
if(beat>0)beat--;
}
}
void timer_config()
{
//定时器配置函数
EA=1;
ET0=1;
TR0=1;
TMOD=0x01;
TH0=63536>>8;
TL0=63536;
}
void main()
{
char key_value=0;
timer_config();
while(1)
{
key_value=key_scan();//返回按键值
key_action(key_value);
}
}
void timer_2ms() interrupt 1
{
static unsigned char count=0;
TH0=63536>>8;
TL0=63536;
cur_sta_update();
count++;
if(count==5)
{
count=0;
motor_run();
}
}
小知识点
- (对于51而言)由于减速比的存在,并且步进电机驱动的前几个节拍很可能是无效的,即前几个节拍可以直接忽视,不用调的很精确,对最后的精度影响也不是很大。步进电机的旋转的精度控制又是一个很复杂的东西,可能涉及惯性、通电时长、扭矩、驱动力等等等,需要一步步的调整参数,对于不同承重的旋转又有不同的要求。
- 可以通过硬件进行消抖和限制运动,但大概率会增加机械结构,从而增加成本,用软件都可以直接实现,进而减少成本的损耗