背景
42步进电机,基本的一步是1.8度,加上程序中的细分之后就更精准了,比如用64细分,一步就已经是1.8°/64=0.028125°.
而硬件上用的不锈钢码盘是25齿的,如下图,遮挡为0,不遮挡为1,一圈50个高低电平状态。如果用双光耦的话一圈有100个高低电平,分辨率也就是360°/100=3.6°,这个精度在步进电机来说没啥意义。
但是,如果因为一些外力干扰,步进电机丢步了,光耦就可以在此时发挥作用,将情况反馈给步进电机。
例如:步进电机到达目标位置后,被人为旋转过,此时的位置与程序中标定的位置不一致了。
例如:安装在设备上,步进电机被机械限位,无法继续运行了。
单个光耦的硬件电路
光耦的内部,左边是一个发光二极管,右边一个光敏三极管。
当发光二极管的光照到右边的时候,就会给右边光敏三极管的基极提供电流,从而三极管导通;否则三极管截止。
单个光耦的硬件电路如下,导通为0,不导通为1,左边的电阻用于发光二极管的导通,右边的电阻用于上拉。
1、光被挡上,在仿真中我把发光二极管的回路断开,此时三极管截止,电压表就是接单片机IO的,检测为5V,即为高电平。
2、发光二极管导通时,右边光敏三极管也导通,也就是集电极和发射极就导通了,电压表接的是集电极,电压应该是CE的饱和压降零点几伏,所以为低电平,电压电流如下图所示。
双光耦的电路
就是上面的原理,把两个槽型光耦串起来,接单片机两个IO口。
程序原理
两个IO口,能记下四种状态,如下四张图为顺时针方向旋转时我拍的,一看明了,挡住为1,不挡为0.
两个IO口记为S1、S2,单片机读取到的值依次为:00,01,11,10.
代码
解释都写在注释里了,对着代码看容易理解
//Y轴光耦检测,顺时针S1 S2 —— 00 10 11 01
void Y_OPTO_Check()
{
u8 input = 0; //存储光耦状态的值
static u8 opto_last = 0;
u8 a,b;
if(Y_OPTO_S2) //S2
input|=(1<<0);
if(Y_OPTO_S1) //S1
input|=(1<<1); //input == 0000 0 0 S1 S2
a = input^opto_last;
if(a!=0){ //与上一次状态不同,位置变化,光耦更新
b = input^(input>>1);
if(a&0x02){ //S1与上次不同,顺时针可能从00到10,11到01,逆时针可能从10到00,01到11
if(b&0x01) Y_opto+=1; //S1与S2不同,定位在顺时针,光耦值+
else Y_opto-=1; //S1与S2相同,定位在逆时针,光耦值-
}else if(a&0x01){ //S2与上次不同,顺时针可能从10到11,01到00,逆时针可能从11到10,00到01
if(b&0x01) Y_opto-=1; //S1与S2不同,定位在逆时针,光耦值-
else Y_opto+=1; //S1与S2相同,定位在顺时针,光耦值+
}
opto_last = input;
}
}
背景
42步进电机,基本的一步是1.8度,加上程序中的细分之后就更精准了,比如用64细分,一步就已经是1.8°/64=0.028125°.
而硬件上用的不锈钢码盘是25齿的,如下图,遮挡为0,不遮挡为1,一圈50个高低电平状态。如果用双光耦的话一圈有100个高低电平,分辨率也就是360°/100=3.6°,这个精度在步进电机来说没啥意义。
但是,如果因为一些外力干扰,步进电机丢步了,光耦就可以在此时发挥作用,将情况反馈给步进电机。
例如:步进电机到达目标位置后,被人为旋转过,此时的位置与程序中标定的位置不一致了。
例如:安装在设备上,步进电机被机械限位,无法继续运行了。
单个光耦的硬件电路
光耦的内部,左边是一个发光二极管,右边一个光敏三极管。
当发光二极管的光照到右边的时候,就会给右边光敏三极管的基极提供电流,从而三极管导通;否则三极管截止。
单个光耦的硬件电路如下,导通为0,不导通为1,左边的电阻用于发光二极管的导通,右边的电阻用于上拉。
1、光被挡上,在仿真中我把发光二极管的回路断开,此时三极管截止,电压表就是接单片机IO的,检测为5V,即为高电平。
2、发光二极管导通时,右边光敏三极管也导通,也就是集电极和发射极就导通了,电压表接的是集电极,电压应该是CE的饱和压降零点几伏,所以为低电平,电压电流如下图所示。
双光耦的电路
就是上面的原理,把两个槽型光耦串起来,接单片机两个IO口。
程序原理
两个IO口,能记下四种状态,如下四张图为顺时针方向旋转时我拍的,一看明了,挡住为1,不挡为0.
两个IO口记为S1、S2,单片机读取到的值依次为:00,01,11,10.
代码
解释都写在注释里了,对着代码看容易理解
//Y轴光耦检测,顺时针S1 S2 —— 00 10 11 01
void Y_OPTO_Check()
{
u8 input = 0; //存储光耦状态的值
static u8 opto_last = 0;
u8 a,b;
if(Y_OPTO_S2) //S2
input|=(1<<0);
if(Y_OPTO_S1) //S1
input|=(1<<1); //input == 0000 0 0 S1 S2
a = input^opto_last;
if(a!=0){ //与上一次状态不同,位置变化,光耦更新
b = input^(input>>1);
if(a&0x02){ //S1与上次不同,顺时针可能从00到10,11到01,逆时针可能从10到00,01到11
if(b&0x01) Y_opto+=1; //S1与S2不同,定位在顺时针,光耦值+
else Y_opto-=1; //S1与S2相同,定位在逆时针,光耦值-
}else if(a&0x01){ //S2与上次不同,顺时针可能从10到11,01到00,逆时针可能从11到10,00到01
if(b&0x01) Y_opto-=1; //S1与S2不同,定位在逆时针,光耦值-
else Y_opto+=1; //S1与S2相同,定位在顺时针,光耦值+
}
opto_last = input;
}
}
举报