步进电机与蜂鸣器
单片机I/O口的结构单片机的I/O口结构有四种状态:
[*]准双向I/O口
[*]开漏输出
[*]推挽输出
[*]高阻态
准双向I/O口
准双向IO口
开漏输出
开漏输出和准双向I/O的唯一区别,就是开漏输出把内部的上拉电阻去掉了。
开漏输出如果要输出高电平时,T2关断,I/O口电平要靠外部的上拉电阻才能拉成高电平,如果没有外部的上拉电阻I/O口电平就是一个不确定态。
标准的51单片机的P0口默认就是开漏输出,如果要用的时候外部需要加上上拉电阻。
强推挽输出
强推挽输出就是由比较强的驱动力,如图,当内部输出一个高电平时,通过MOS管直接输出电流,没有电阻的限流,电流输出能力也比较大;如果内部输出一个低电平时,那反向电流也可以很大,强推挽的一个特点就是驱动能力很强。
高阻态
单片机I/O口还有一种状态叫高阻态,通常用来做输入引脚的时候,可以将I/O口设置成高阻态,高阻态引脚本身如果悬空,用万用表测量的时候可能是高可能是低,它的状态完全取决于外部输入信号的电平,高阻态引脚对GND的等效电阻很大(理论上相当于无穷大,但是实际上总是有限值而非无穷大),所以称之为高阻。
上下拉电阻
上拉电阻就是将不确定的信号通过一个电阻拉到高电平,同时此电阻也起到一个限流作用,下拉就是下拉低电平。
例如I/O口设置为开漏输出高电平或者是高阻态时,默认的电平就是不确定的,外部经一个电阻接到VCC,也就是上拉电阻,那么相应的引脚就是高电平;经过一个电阻到GND,也就是下拉电阻,那么相应的引脚就是一个低电平。
上下拉电阻的应用
上拉电阻的应用有很多,最常用的四种:
[*]OC门要输出高电平,必须外部加上拉电阻才能正常使用,其实OC门就相当于单片机I/O口的开漏输出
[*]加大普通I/O口的驱动能力。标准51单片机的内部I/O口的上拉电阻,一般都是在加几万欧姆,比如STC89C52内部是20K欧姆的上拉电阻,所以最大输出电流是250uA,因此外部加个上拉电阻,可以形成和内部上拉电阻的并联结构,增大高电平时电流的输出
[*]在电平转换电路中,例如5V转12V的电路中,上拉电阻其实起到的是限流电阻的作用
[*]单片机中未使用的引脚,比如总线引脚和引脚悬空时,容易受到电磁干扰而处于紊乱状态,虽然不会对程序造成什么影响,但是通常会增加单片机的功耗,加上一个对VCC的上拉电阻或一个对GND的下拉电阻后,可以有效的抵抗电磁干扰。
上下拉电阻的阻值的选择
[*]从降低功耗的方面考虑应当足够大,因为电阻越大,电流越小
[*]从确保足够的引脚驱动能力考虑应当足够小,电阻小了,电流才能大
[*]在开漏输出时,过大的上拉电阻会导致信号上升沿变缓。实际电平的变化都是需要时间的,虽然很小,但永远都达不到零,而开漏输出时上拉电阻的大小就直接影响了这个上升过程所需要的时间。如果电阻很大,而信号频率又很快,最终导致信号还没等上升到高电平就又变低了,于是信号就无法正确传送了。
常用的上下拉电阻值多选在 1 ~ 10k 欧姆,具体到底多大通常要根据实际需求来选取,只要在标准范围内就可以了,不一定是一个固定的值。
28BYJ-48型步进电机详解与实例
电机的分类
电机的分类方式有很多,从用途角度可划分为驱动类电机和控制类电机。
直流电机属于驱动类电机,这种电机是将电能转换为机械能,主要应用在电钻、小车轮子、电风扇、洗衣机等设备。
步进电机属于控制类电机,它是将脉冲信号转换成一个转动角度的电机,在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,主要应用在自动化仪表、机器人、自动生产流水线、空调扇叶转动等设备。
步进电机又分为反应式、永磁式和混合式三种
[*]反应式步进电机:结构简单成本低,但是动态性能差、效率低、发热大,可靠性难以保证,所以现在基本上被淘汰了
[*]永磁式步进电机:动态性能好、输出力矩较大,但误差相对来说大一些,因其价格低而广泛应用于消费性产品
[*]混合式步进电机:综合了反应式和永磁式的优点,力矩大、动态性能好、步距角小、精度高,但结构相对复杂,价格也相对较高,主要用于工业
28BYJ-48步进电机,型号包含的含义:
28--步进电机的有效最大外径[ 直径 ]是28mm
B--表示是步进电机
Y--表示是永磁性
J--表示是减速型
48--表示四相八拍
28BYJ-48型步进电机原理详解
28BYJ-48是4相永磁式减速步进电机,其外观如上图。
上图为28BYJ-48的内部结构示意图。
先看里圈,它上面有6个齿,分别标注了 0 ~ 5 ,这个叫转子,顾名思义,它是要转动的,转子的每个齿上都带有永久的磁性,是一个永磁体,这就是“永磁性”的概念。
再看外圈,就是定子,它是保持不动的,实际上它是跟电机的外壳固定在一起的,上面有8个齿,而每个齿上都缠上了一个线圈绕组,正对着的两个齿上的绕组又是串联在一起的,也就是说正对着的两个绕组总是会同时导通或关断的,如此就形成了4相,在图中分别标注为A-B-C-D,这就是“4相”的概念。
步进电机的工作原理
假定电机的起始状态就如9-4所示,逆时针方向转动,起始时是B相绕组开关闭合,B相绕组导通,那么导通电流就会在正上和正下两个定子齿上产生磁性,这两个定子齿上的磁性就会对转子上的0和3号齿产生最强的吸引力,此时就会如9-4所示,0号转子齿在正上方,3号转子齿在正下方而处于平衡状态,而同时,1号转子齿与右上定子齿即C相有一个小小的夹角,2号转子齿与右边的定子齿即D相有一个稍微大点的夹角,很明显这个夹角是1号转子齿和定子齿夹角的2倍,同理,对侧也是一样。
接下来把B相绕组断开,而使C相绕组导通,则1号转子齿和4号转子齿对齐到了右上和左下的定子齿上而保持平衡。
再断开C相绕组,导通D相绕组,则2号转子齿和5号转子齿与D相的定子齿对其,转子又转动了一个角度。
很明显,当A相绕组再次导通,即完成了一个B-C-D-A的四节拍操作后,转子的0号齿和3号齿将由原来对齐B相定子齿变为对齐C相定子齿,即转子转过了一个定子齿的角度。以此类推,再来一个四节拍,转子就将再转过一个齿的角度,8个四节拍以后,转子将转过完整的一圈,而其中单个节拍使转子转过的角度就很容易计算出来,即360° / (8 × 4) = 11.25°,这个值就叫做步进角度。而上述这种工作模式就是步进电机的单四节拍模式--单相绕组通电四节拍。
还有一种性能更佳的工作模式,那就是再单四拍的每两个节拍之间再插入一个双绕组导通的中间节拍,组成八拍模式。比如,在从B相导通到C相导通的过程中,假如一个B相和C相同时导通的节拍,这个时候,由于B、C两个绕组的定子齿对它们附近的转子齿同时产生相同的吸引力,这将导致这两个转子齿的中心线对比到B、C两个绕组的中心线上,也就是新插入的这个节拍使转子转过了上述单四拍模式中步进角度的一半,即5.625°。这样一来,就使扭转精度增加了一倍,而转子转动一圈则需要8 × 8 = 64拍了。另外,新增加的这个中间节拍还会在原来单四拍的两个节拍吸引力之间又加了一把引力,从而可以大大增加电机的整体扭力输出,使电机更“有劲”了。
除了上述的单四拍和八拍的工作模式外,还有一个双四拍的工作模式--双绕组通电四节拍。其实就是把八拍模式中的两个绕组同时通电的那四拍单独拿出来,而舍弃单绕组通电的那四拍而已。其步进角度同单四拍是一样的,但由于它是两个绕组同时导通,所以扭矩会比单四拍模式大。
八拍模式是这类4相步进电机的最佳工作模式,能最大限度的发挥电机的各项性能,也是绝大多数实际工程中所选择的模式。
让电机转起来
步进电机一共有5根引线,其中红色的是公共端,连接到5V电源上,接下来的橙、黄、粉、蓝就对应了A、B、C、D相;如果要导线通A相绕组,就只需将橙色线接地即可,B相则是黄色接地,以此类推;再根据上述单四拍和八拍工作过程的讲解,可以得到以下顺序表
在上表中:
1拍:A相导通
2拍:A相和B相导通
3拍:B相导通
4拍:B相和C相导通
5拍:C相导通
6拍:C相和D相导通
7拍:D相导通
8拍:D相和A相导通
用跳线帽来控制单片机的I/O连接的是步进电机还是译码器
[*]如果要使用步进电机,则用跳线帽将I/O口和MC口相连
[*]如果要显示部分,则用跳线帽将I/O口和ADDR口相连
[*]如果要兼得,则用跳线帽将I/O口和ADDR口相连,再将MC口连接到单片机无需用的I/O口即可
单片机的I/O口可以直接输出0V和5V的电压,但是电流驱动能力,也就是带载能力非常有限,所以每相的控制线上都增加一个[[第四篇 硬件基础知识#^Transistor|三极管]]来提高驱动能力。若要使A相导通,则必须是Q2导通,此时A相也就是橙色线就相当于接地了,于是A相绕组导通,此时单片机P1口低4位应输出0b1110,即0xE;如果要A、B相同时导通,就是Q2、Q3导通,P1口低四位应输出0b1100,即0xC,以此类推,可以得到下面的八拍节拍的I/O口控制代码数组:
unsigned char code BeatCode = { 0xE, 0xC, 0xD, 0x9, 0xB, 0x3, 0x7, 0x6 };
循环将这个数组的值传送到P1口,那多久送一次数据呢?
这个时间由步进电机的启动频率决定的。
启动频率就是步进电机在空载情况下能够正常启动的最高脉冲频率,如果脉冲频率高于该值,电机就不能正常启动。
上表中给出的参数是 >= 550,单位是P.P.S,即每秒脉冲数,这里的意思就是说:电机保证在每秒给出550个步进脉冲的情况下可以正常启动。
换算成节拍持续时间就是 1s/550 = 1.8ms,为了让电机能够启动,控制节拍刷新时间大于1.8ms就可以了
代码
/*
@file motor.c
@brief 51单片机步进电机篇之让电机转动
@author EricsT (EricsT@163.com)
@version v1.0.0
@date 2025-08-12
@history 2025-08-12 EricsT - 新建文件
*/
#include <reg52.h>
unsigned char code BeatCode = { 0x0E, 0x0C, 0x0D, 0x09, 0x0B, 0x03,0x07, 0x06 };//步进电机i/o口控制节拍
void delay();
void main(void)
{
unsigned char tmp;//暂存值
unsigned char index = 0;//索引
while (1)
{
tmp = P1;//存储P1的值
tmp = tmp & 0xF0;//清空tmp的低四位
tmp = tmp | BeatCode;//写入tmp的低四位
P1 = tmp;//将tmp的值赋值给P1,即上述操作是在对P1进行操作
index++;//索引+1
index &= 0x07;//到8归0
delay();//延时
}
}
void delay(void)
{
unsigned int i = 200;
while (i--);
}
电机转动90度
/*
@file motor.c
@brief 51单片机步进电机篇之电机转动90度
@author EricsT (EricsT@163.com)
@version v1.0.0
@date 2025-08-14
@history 2025-08-14 EricsT - 新建文件
*/
#include <reg52.h>
unsigned char code BeatCode = { 0x0E, 0x0C, 0x0D, 0x09, 0x0B, 0x03,0x07, 0x06 };//步进电机i/o口控制节拍
void delay();
void main(void)
{
unsigned int i = 0;
unsigned char tmp;//暂存值
unsigned char index = 0;//索引
for (i = 0; i < 1024; ++i)//90 / (360 / 4096) = 1024
{
tmp = P1;//存储P1的值
tmp = tmp & 0xF0;//清空tmp的低四位
tmp = tmp | BeatCode;//写入tmp的低四位
P1 = tmp;//将tmp的值赋值给P1,即上述操作是在对P1进行操作
index++;//索引+1
index &= 0x07;//到8归0
delay();//延时
}
P1 = P1 & 0x0F;
while (1);
}
void delay(void)
{
unsigned int i = 200;
while (i--);
}电机转动任意角度
/*
@file motor.c
@brief 51单片机步进电机篇之电机转动任意角度[角度可人为改变]
@author EricsT (EricsT@163.com)
@version v1.0.0
@date 2025-08-14
@history 2025-08-14 EricsT - 新建文件
*/
#include <reg52.h>
unsigned char code BeatCode = { 0x0E, 0x0C, 0x0D, 0x09, 0x0B, 0x03,0x07, 0x06 };//步进电机i/o口控制节拍
void delay();
void Motor(unsigned long iCalc);
void main(void)
{
Motor(360);
while (1);
}
void delay(void)
{
unsigned int i = 200;
while (i--);
}
void Motor(unsigned long iCalc)
{
unsigned long i = 0;
unsigned long iNum = iCalc * 4076 / 360;
unsigned char tmp;//暂存值
unsigned char index = 0;//索引
for (i = 0; i < iNum; ++i)
{
tmp = P1;//存储P1的值
tmp = tmp & 0xF0;//清空tmp的低四位
tmp = tmp | BeatCode;//写入tmp的低四位
P1 = tmp;//将tmp的值赋值给P1,即上述操作是在对P1进行操作
index++;//索引+1
index &= 0x07;//到8归0
delay();//延时
}
P1 = P1 & 0x0F;
}定时器实现电机转动任意角度
/*
@file motor.c
@brief 51单片机步进电机篇之电机转动任意角度[角度可人为改变][定时器实现]
@author EricsT (EricsT@163.com)
@version v1.0.0
@date 2025-08-18
@history 2025-08-18 EricsT - 新建文件
*/
#include <reg52.h>
unsigned char code BeatCode = { 0x0E, 0x0C, 0x0D, 0x09, 0x0B, 0x03,0x07, 0x06 };//步进电机i/o口控制节拍
unsigned long beats;
void Motor(unsigned long iCalc);
void main(void)
{
EA = 1;//打开总使能
TMOD = 1;//定时器0工作在模式1
TH0 = 0xF8;
TL0 = 0xCD;//设置初始值,2ms
ET0 = 1;//定时器0中断使能
TR0 = 1;//打开定时器0
beats = 0;
Motor(180);
while (1);
}
void Motor(unsigned long iCalc)
{
EA = 0;//在计算前关闭中断,完成后再打开,以避免中断打断计算过程而造成错误
beats = iCalc * 4076 / 360;
EA = 1;
}
void InterruptTime0() interrupt 1
{
unsigned long i = 0;
unsigned char tmp;//暂存值
static unsigned char index = 0;//索引
TH0 = 0xF8;
TL0 = 0xCD;//设置初始值,2ms
if (!beats)
{
P1 = P1 & 0x0F;
return;
}
tmp = P1;//存储P1的值
tmp = tmp & 0xF0;//清空tmp的低四位
tmp = tmp | BeatCode;//写入tmp的低四位
P1 = tmp;//将tmp的值赋值给P1,即上述操作是在对P1进行操作
index++;//索引+1
index &= 0x07;//到8归0
beats--;
}按键控制电机-基础
/*@file motor.c@brief 51单片机步进电机篇之按键控制电机转动--基础@author EricsT (EricsT@163.com)@version v1.0.0@date 2025-08-18@history 2025-08-18 EricsT - 新建文件*/#include sbit KEY_IN_1 = P2 ^ 4;sbit KEY_IN_2 = P2 ^ 5;sbit KEY_IN_3 = P2 ^ 6;sbit KEY_IN_4 = P2 ^ 7;sbit KEY_OUT_1 = P2 ^ 3;sbit KEY_OUT_2 = P2 ^ 2;sbit KEY_OUT_3 = P2 ^ 1;sbit KEY_OUT_4 = P2 ^ 0;unsigned char keyStatu = { { 1, 1, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 1, 1 }};unsigned char code BeatCode = { 0x0E, 0x0C, 0x0D, 0x09, 0x0B, 0x03,0x07, 0x06 };//步进电机i/o口控制节拍unsigned long beats;void Motor(unsigned long iCalc);void main(void){ unsigned char i, j; unsigned char backup = { { 1, 1, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 1, 1 }, { 1, 1, 1, 1 } }; EA = 1;//打开总使能 TMOD = 1;//定时器0工作在模式1 TH0 = 0xFC; TL0 = 0x67;//设置定时器0初值,1ms ET0 = 1;//定时器0中断使能 TR0 = 1;//打开定时器0 beats = 0; while (1) { for (i = 0; i < 4; ++i) { for (j = 0; j < 4; ++j) {//扫描按键状态 if (backup != keyStatu)//按键状态改变 { if (0 != backup) { Motor(90);//电机转动 } backup = keyStatu;//更新按键状态 } } } } while (1);}void Motor(unsigned long iCalc){ EA = 0;//在计算前关闭中断,完成后再打开,以避免中断打断计算过程而造成错误 beats = iCalc * 4076 / 360; EA = 1;}//电机中断void MotorInterrupt(){ unsigned long i = 0; unsigned char tmp;//暂存值 static unsigned char index = 0;//索引 if (!beats) { P1 = P1 & 0x0F; return; } tmp = P1;//存储P1的值 tmp = tmp & 0xF0;//清空tmp的低四位 tmp = tmp | BeatCode;//写入tmp的低四位 P1 = tmp;//将tmp的值赋值给P1,即上述操作是在对P1进行操作 index++;//索引+1 index &= 0x07;//到8归0 beats--;}//按键中断void KeyInterrupt(){ unsigned char i; static unsigned char keyOut = 0; static unsigned char keyBuf = { { 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF }, { 0xFF, 0xFF, 0xFF, 0xFF } }; //保留当前按键状态 keyBuf = (keyBuf
页:
[1]