步进电机
一种将电脉冲信号转换成相应角位移或线位移的电动机。每输入一个脉冲信号,转子就转动一个角度或前进一步,其输出的角位移或线位移与输入的脉冲数成正比,转速与脉冲频率成正比。
驱动方式:使用八拍方式(按照下方拍子顺序输出即可)
在24BYJ-48说明介绍中知道步距角和减速比
步距角:5.625
减速比:1/64
步距角与脉冲控制有关,
一个脉冲一个步距角,360/5.625=64 则需要64脉冲 转子转一圈
脉冲:变化的拍数,如现使用5线4相8拍方法,
8拍则8个脉冲,一次输出的高低电平就是一个拍子
转子圈数不等于输出轴圈数,输出轴圈数才是真正的转动一圈
由 减速比1:64 可得 64圈转子等于1圈输出轴
!!!!
1拍子-》一脉冲
64脉冲-》1圈转子
64圈转子-》1圈输出轴(电机转动一圈)
得计算:64*64* 角度/360 =脉冲数 !!!!!
=》8*8*64/360*角度=》8*64/45*角度 (计算出角度对应的脉冲数)
修改Motors数组数值,数值是由角度计算出的脉冲数,带复位示例:
const unsigned char Motors[4] ={0,85,57,29};
//使用数组先计算出对应的脉冲数
(数组数值对应公式,但还没有乘8,需要再乘8)
//85=64*60度/45 57=64*40度/45 29=64*20度/45
大概:设置摇头中间值,需要根据需求调整中间值,以防越界,
当设置某个方向为正方向,进行脉冲时,摇头中间值则+1,反方向则摇头中间值-1,
需要保证摇头中间值 + 最大脉冲数不越界,
需要保证摇头中间值 - 最大脉冲数大于0,
在需要复位时候,可以简化成 摇头中间值经过脉冲数变化后是900 则是复位成功
volatile unsigned char round;//圈数
volatile unsigned int swingmotors;//方向数值
volatile unsigned int swingnegatuve;//负方向数值
volatile unsigned int swingforward;//正方向数值
volatile unsigned int swingcenter;//摇头中心值 900 为中间
const unsigned char Motors[4] ={0,85,57,29}; //还没有乘8
//85=64*60度/45 57=64*40度/45 29=64*20度/45
//1024 =8*64*90/45 90度 1024是脉冲数
//8192=8*64*720/45 720度 8192是脉冲数
//4096=8*64*360/45 360度 4096是脉冲数
/*
40度 456 /8 =58 20度 29 29*8=232
80度 912 /8 =114 40度 57 57*8=456
120度 1366 /8 =170 60度 85 85*8=680
*/
//黑 黄 棕 蓝
//触发一次脉冲 摇头1档间隔脉冲时间1.216ms =38*32us
void motor_uln2003(void)
{
if(swingstall==0)//档位为0 需要复位
{
if(swingcenter>900)//当摇头中间值大于900则有偏角度,
{
swingcenter--;
motor--;
if(motor<1)//逆转 motor值控制对应拍子
{
motor=8;
}
}
else if(swingcenter<900)//当摇头中间值小于900则有偏角度,
{
swingcenter++;
motor++;
if(motor>8) //正转
{
motor=1;
}
}
else
{
swingreset=0;
//标志位是当摇头中间值为900,复位成功才能不用进入本函数
//否则会一直进入
}
}
else
{
swingmotors=Motors[swingstall]*8;//swingstall是对应的档位的偏角度!!!!
//由上述所知我公式是少了一次乘8的,在这补上才是正正需要偏移的脉冲数
swingforward=swingmotors+900;//正方向数值
swingnegatuve=900-swingmotors;//负方向数值
//如:我想要是摇头中间值 左右20度,则共40度
//计算得出 swingmotors=8*29=232 29由 64*20度/45来 请上上述公式
//那么 正方向数值=900+232=1132 负方向数值=900-232=668
//可知只要我脉冲数与摇头值对应, 1132~668之间 进行对应的拍子脉冲就能实现角度控制左20度右20度
if(dir)//正向
{
swingcenter++;
if(swingcenter>=swingforward)
{
dir=0;//摇头中间值超过范围值最大值则进行反向
}
motor++;
if(motor>8)
{
motor=1;
}
//!!!!!需要注意拍子数方向,就是旋转方向与 motor从1到8还是8到1有关
}
else//反向
{
swingcenter--;
if(swingcenter<=swingnegatuve)//摇头中间值超过范围值最小值则进行反向
{
dir=1;
}
motor--;
if(motor<1)
{
motor=8;
}
}
}
OEP4|=0x0F;//各个io口需要配置成输出模式!!!!
//在关闭后,是配置成输入模式,原因是不用步进电机还是发热,高阻态(输出模式)则不会
//所以在不使用时候我配置成输入模式,需要用到再打开
switch(motor)//对应上述八拍方法进行驱动(标志着 “-” 的io口输出低电平,否则就高电平)
{
case 1:
P43D=0;P42D=1;P41D=1;P40D=0;// 0110
break;
case 2:
P43D=0;P42D=1;P41D=1;P40D=1;// 0111
break;
case 3:
P43D=0;P42D=0;P41D=1;P40D=1;// 0011
break;
case 4:
P43D=1;P42D=0;P41D=1;P40D=1;// 1011
break;
case 5:
P43D=1;P42D=0;P41D=0;P40D=1;// 1001
break;
case 6:
P43D=1;P42D=1;P41D=0;P40D=1;// 1101
break;
case 7:
P43D=1;P42D=1;P41D=0;P40D=0;// 1100
break;
case 8:
P43D=1;P42D=1;P41D=1;P40D=0;// 1110
break;
default:
break;
}
}
void main(void)
{
CLR_RAM();
GIE = 0;
Timer0_init();
Timer1_init();
GIE = 1;
//0输入1输出
OEP0=0xF7;
OEP4=0x1F;
OEP5=0x13;
swingreset=1;//控制启动,找个地方启动置1就好
swingtime=38;//设置时间延时, 38*32=1216us
//每个脉冲之间1.216ms 可实现转动,可调节时间控制转速,
swingstall=1;//数组控制需要偏转的角度
while(1)
{
//放在32us的定时器中断中,不使用软延时来延时
//也可以放在其他定时器中断触发,我使用1.2ms脉冲是可以驱动的
if(timer1us)
{
timer1us=0;
//摇头步进电机
if(swingreset)//启动,只有复位成功,摇头中间值是900,swingreset才为0
{
timer1ms_1++;
if(timer1ms_1>=swingtime) //!!!!!!38*32=1.216ms
{
timer1ms_1=0;
motor_uln2003(); //每次触发都是一次脉冲电平
}
}
else//关闭则电平高
{
//端口设置输入模式 设置高阻态,否则持续有电流,电机发烫
OEP4&=0x10;
}
}
}
}
void int_isr(void) __interrupt
{
__asm
push
__endasm;
//当T0CNT递减到0时,此时产生T0溢出中断请求标志T0IF/T1IF置1
if(T0IF) //104us触发一次
{
T0IF=0;
T0CNT=0x9A;
}
if(T1IF) //32uS
{
T1IF=0;
timer1us=1;
}
__asm
pop
__endasm;
}
修改Motors数组数值,数值是转圈数,带复位示例:
const unsigned char Motors[4] ={0,1,2,3};
由上述公式可知 脉冲数=8*64*角度/45
所以一圈是360度 则一圈脉冲数=8*64*360/45=4096
设置摇头中间值需要大于旋转1圈的脉冲数 所以摇头中间值设值5000
大概:前述设置角度不同,设置摇头中间圈数值,则每进行4096次脉冲,根据摇头中间值得变化,,如顺时针进行4096次脉冲则摇头中间圈数值进行+1,逆时针进行4096次脉冲则摇头中间圈数值进行-1
在需要复位时候,可以简化成 摇头中间值经过脉冲数变化后是5000 同时也需要保证摇头中间圈数值是50,才能复位成功。(本次设置摇头中间圈数值为50)
volatile unsigned char round;//圈数
volatile unsigned char swingmotors;//方向数值
volatile unsigned char swingnegatuve;//负方向数值
volatile unsigned char swingforward;//正方向数值
volatile unsigned int swingcenter;//一圈脉冲数
volatile unsigned char swinground;//一圈数标志位
const unsigned char Motors[4] ={0,1,2,3};
//8192=8*64*720/45 720度 8192是脉冲数
//4096=8*64*360/45 360度 4096是脉冲数
//黑 黄 棕 蓝
//触发一次脉冲 摇头1档间隔脉冲时间1.216ms =38*32us
void motor_uln2003(void)
{
if(dir)//顺时针
{
swingcenter++;
if(swingcenter>=9096)//5000+4096=9096 即超过了一圈
{
swingcenter=5000;
round++; //圈数+1,换向由下方的圈数范围决定
}
motor++;
if(motor>8) //正转
{
motor=1;
}
}
else //逆时针
{
swingcenter--;
if(swingcenter<=904)//5000-4096=904
{
swingcenter=5000;
round--;
}
motor--;
if(motor<1)//逆转
{
motor=8;
}
}
if(swingstall==0)//档位为0 需要复位
{
//!!!!!!!如果需要复位的话先对摇头中间圈数值进行判断要等于50,在对摇头中间值判断要等于5000
//当还没到一圈就停止得也可以复位,圈数等于50后,也能判断不到一圈的摇头中间值5000
if(round>50)
{
dir=0;//逆时针
}
else if(round<50)
{
dir=1;//顺时针
}
else
{
if(swingcenter>5000)
{
dir=0;//逆时针
}
else if(swingcenter<5000)
{
dir=1;//顺时针
}
else
{
swingreset=0;
//需要复位到摇头中间圈数值等于50,摇头中间值等于5000
}
}
}
else
{
swingmotors=Motors[swingstall];
swingforward=swingmotors+50;//正方向圈数
swingnegatuve=50-swingmotors;//负方向圈数
if(dir)//正向
{
if(round>=swingforward)
{
dir=0;//脉冲数超过 进行反向
}
}
else//反向
{
if(round<=swingnegatuve)
{
dir=1;//脉冲数超过 进行反向
}
}
}
OEP4|=0x0F;
switch(motor)
{
case 1:
P43D=0;P42D=1;P41D=1;P40D=0;// 0110
break;
case 2:
P43D=0;P42D=1;P41D=1;P40D=1;// 0111
break;
case 3:
P43D=0;P42D=0;P41D=1;P40D=1;// 0011
break;
case 4:
P43D=1;P42D=0;P41D=1;P40D=1;// 1011
break;
case 5:
P43D=1;P42D=0;P41D=0;P40D=1;// 1001
break;
case 6:
P43D=1;P42D=1;P41D=0;P40D=1;// 1101
break;
case 7:
P43D=1;P42D=1;P41D=0;P40D=0;// 1100
break;
case 8:
P43D=1;P42D=1;P41D=1;P40D=0;// 1110
break;
default:
break;
}
}
void main(void)
{
CLR_RAM();
GIE = 0;
Timer0_init();
Timer1_init();
GIE = 1;
//0输入1输出
OEP0=0xF7;
OEP4=0x1F;
OEP5=0x13;
swingreset=1;//控制启动,找个地方启动置1就好
swingtime=38;//设置时间延时, 38*32=1216us
//每个脉冲之间1.216ms 可实现转动,可调节时间控制转速,
swingstall=1;//数组控制需要偏转的圈数
while(1)
{
if(timer1us)//放在32us的定时器中断中,不使用软延时来延时
{
timer1us=0;
//摇头步进电机
if(swingreset)//启动,只有复位成功,摇头中间值是900,swingreset才为0
{
timer1ms_1++;
if(timer1ms_1>=swingtime)//38*32=1.216ms
{
timer1ms_1=0;
motor_uln2003(); //每次触发都是一次脉冲电平
}
}
else//关闭则电平高
{
//端口设置输入模式 设置高阻态,否则持续有电流,电机发烫
OEP4&=0x10;
}
}
}
}
void int_isr(void) __interrupt
{
__asm
push
__endasm;
//当T0CNT递减到0时,此时产生T0溢出中断请求标志T0IF/T1IF置1
if(T0IF) //104us触发一次
{
T0IF=0;
T0CNT=0x9A;
}
if(T1IF) //32uS
{
T1IF=0;
timer1us=1;
}
__asm
pop
__endasm;
}