因为我在步进电机的基本原理通电时,强行转动了一下,我换了个电机上去时,显示与通信模板断开连接,这是什么原因?

 上传我的文档
 上传文档
 下载
 收藏
粉丝量:38
该文档贡献者很忙,什么也没留下。
 下载此文档
步进电机控制电路设计
下载积分:1000
内容提示:步进电机控制电路设计
文档格式:PDF|
浏览次数:188|
上传日期: 16:02:13|
文档星级:
全文阅读已结束,如果下载本文需要使用
 1000 积分
下载此文档
该用户还上传了这些文档
步进电机控制电路设计
关注微信公众号思路-如何驱动光驱丝杆电机
TA的更多文章
思路-如何驱动光驱丝杆电机
小城在旧电脑光驱里面发现了一个神奇的电机丝杆电机-1丝杆电机-2以前小城只接触过四相五线步进电机四相五线步进电机四相五线步进电机后来小城在某宝上知道了光驱里面电机的名字:丝杆电机!!!可是下边的电机信息里面竟然没有提供电路图,而且在网上也没找到多少有用的信息,于是我开始研究怎么驱动这个电机。这个电机机身太小,接线很不容易,所以要先把这四个端口分别接到四个排针上,便于后续操作。排针接线-1接线-2现在给四个接线端命名:命名命名-2我用万用表来测量电机四个接口的通断,结果发现A&B,C&D之间导通,而A&C、A&D、B&C、B&D之间断路。而且小城发现给A&B通电(即一个接电源正极,一个接电源负极),接正向(相对)电流和反向电流,丝杆电机都会轻微转一下,然后停止,所以我推测,电流从A到B和从B到A电机都会转到特定的不同的角度然后停下(同理从C到D和从D到C)。现在令AB表示为电流从A到B,同理令BA,CD,DC为相应电流流向。现在总共四种电流流动方式(AB,BA,CD,DC),既然四种电流方式会使电机转向不同方向然后停止,按照步进电机的特点,肯定有个正确的通电顺序(即四种电流方式的顺序),使电机可以持续转动而不是来回振动。目前开发板上的电路是四相五线步进电机的电路,一个正极,四个负极,然后单片机控制四个负极有规律的通电,使得四相五线的步进电机可以转动。四相五线步进电机驱动电路然而按照上边对这个丝杆电机的分析,显然这个电路不能驱动两相四线的步进电机,所以首先需要设计一个电路,使得电流可以是AB、BA、CD、DC,即每个端口都可以与高电压连接,也可以与低电压连接,此时,三极管的开关功能派上了用场(三极管有开关功能和放大功能)。那就要简单讲一下三极管的应用:小城在电路中遇到的三极管是2n2222a(NPN型三极管)至于为什么要选这个。。。因为我只有这种三极管啊!并且这个丝杆电机功率不大,额定电压也只有3V,所以不用担心三极管发热的问题(这是我一个外行估算的,专业人员快撤离!)这个三极管的外观如下图:2N2222A & 三极管将平面面向你,也就是能看见三极管型号的那一面(原理就不讲了感兴趣的请上网查询),这时,左中右有三个引脚,只有当电压满足:左&右,并且中间有高电压的时候,电流会从右边和中间流向左边的引脚,即左右导通(此时相当于开关闭合),当中间电压为零则左右断开(也就是开关断开),所以用这个原理,把三极管当做开关,设计下面的电路:驱动电路假如想让P20那个三极管导通,只需要让单片机给P20一个高电压的信号就可以了,其它7个支路一样的道理。驱动电路实物图如下:驱动电路所以我用C语言编程序,让51单片机驱动丝杆电机(驱动芯片在开发板上有ULN2003),程序的主要作用是:开发板上有四个按键,命名为key1,key2,key3和key4.四个按键分别代表AB,BA,CD,DC。然后按四个按钮,指挥步进电机相应的端口通电和断电,完成相应的电流流向,这样就可以手动找到四种电流流向的正确顺序了。按钮信息找电流方式正确顺序的代码:#include&reg52.h&//定义按钮sbit KEY1=P3^1;sbit KEY2=P3^0;sbit KEY3=P3^2;sbit KEY4=P3^3;&//定义端口sbit p20=P2^0;sbit p21=P2^1;sbit p22=P2^2;sbit p23=P2^3;sbit p24=P2^4;sbit p25=P2^5;sbit p26=P2^6;sbit p27=P2^7;&//定义相应通电方式#define AB{P2=0x00;p20=1;p23=1;}#define BA{P2=0x00;p21=1;p22=1;}#define CD{P2=0x00;p24=1;p27=1;}#define DC{P2=0x00;p25=1;p26=1;}&void main()
{ while(1) {//按下key1则电流为AB//后面同理 & if(KEY1==0)
if(KEY2==0)
if(KEY3==0)
if(KEY4==0)
DC }}&现在假如我想让丝杆电机上的条纹向左流动,然后依次按下四个按钮,找到了正确的顺序就可以了。最后发现:Key1-key3-key2-key4-key1这个顺序可以使电机上的丝杆向左,反之key1-key4-key2-key3-key1可以使丝杆条纹向右流动。知道了这个正确顺序,即电流方式的顺序:向左:AB-CD-BA-DC-AB向右:AB-DC-BA-CD-AB这样就可以写驱动电机持续转动的程序了!!!最终源代码:#include&reg52.h&//定义按钮sbit KEY1=P3^1;sbit KEY2=P3^0;sbit KEY3=P3^2;sbit KEY4=P3^3;&//定义端口sbit p20=P2^0;sbit p21=P2^1;sbit p22=P2^2;sbit p23=P2^3;sbit p24=P2^4;sbit p25=P2^5;sbit p26=P2^6;sbit p27=P2^7;&//定义电流方式#define AB{P2=0x00;p20=1;p23=1;}#define BA{P2=0x00;p21=1;p22=1;}&#define CD{P2=0x00;p24=1;p27=1;}#define DC{P2=0x00;p25=1;p26=1;}&//延时函数void delay(unsigned char n){ unsigned char N; for(;n&0;n--)
for(N=20;N&0;N--);}&//向左void zuo(unsigned char n,int f){ if(f==1)//功能选择 AB delay(n); CD delay(n); BA delay(n); DC
delay(n);}&void you(unsigned char n,int f){ if(f==0)//功能选择 AB delay(n); DC delay(n); BA delay(n); CD
delay(n);}//主函数君void main()
{ int f=0;//控制zuo函数和you函数的选择 unsigned char n=50000;//存储延迟的时间 while(1) {
you(n,f);//按下key1,f=0,执行zuo函数 & if(KEY1==0) f=0;//按下key2,f=1,执行you函数
if(KEY2==0) f=1;//转动减速:按下key3,n加1,延长电流切换的时间
if(KEY3==0) n++;
//转动加速:按下key4,当n大于1的时候,n减1,减少电流方式切换的的时间
if(KEY4==0&&n&1) n--; }}这样,用key1和key2分别使电机条纹向左或向右流动,key3和key4分别控制电机减速或加速转动。最终效果请看小城日的动态好了,这个就是小城在不知道丝杆电机结构的情况下驱动它定向转动的全过程,在内行看来可能有点傻,不过这种解决问题的方式希望能帮助到大家,分享了小城的经验,我很开心呢!!!&&
本文禁止转载或摘编温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
&普通直流电机
普通电机是我们平时间的比较多的电机,电动玩具,刮胡刀等里面都有。一般只有两个引脚,用电池的正负极接上两个引脚就会转起来,然后电池得正负极再相反的接在两引脚上电机也会向反转。这种电机有转速过快,扭力过小的特点,一般不直接用在智能小车上。
减速电机就是普通电机加上了减速箱,这样便降低了转速,增加了扭力,使得普通电机有的更广泛的使用空间。
智能小车底盘
减速电机一般都是用智能小车上,而对于电机的控制一般都用H桥方案(),L298芯片就是这种原理。
而调速一般采用PWM(脉宽调制)机制,单片机利用定时器控制产生占空比可变的 PWM 波或者直接硬件PWM输出不同大小的波形来控制小车整体速度。
步进电机是将电脉冲信号转变为角位移或线位移的开环控制元步进电机件。在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度,称为“步距角”,它的旋转是以固定的角度一步一步运行的。可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。
&舵机和伺服电机
舵机主要是由外壳、电路板、无核心马达、齿轮与位置检测器所构成。其工作原理是由接收机发出讯号给舵机,经由电路板上的 IC判断转动方向,再驱动无核心马达开始转动,透过减速齿轮将动力传至摆臂,同时由位置检测器送回讯号,判断是否已经到达定位。位置检测器其实就是可变电阻,当舵机转动时电阻值也会随之改变,藉由检测电阻值便可知转动的角度。
厂商所提供的舵机规格资料,都会包含外形尺寸(mm)、扭力(kg/cm)、速度(秒/60°)、测试电压(V)及重量(g)等基本资料。扭力的单位是 kg/cm,意思是在摆臂长度 1 公分处,能吊起几公斤重的物体。这就是力臂的观念,因此摆臂长度愈长,则扭力愈小。速度的单位是 sec/60°,意思是舵机转动 60°所需要的时间。
伺服电机又称执行电动机,在自动控制系统中,用作执行元件,把所收到的电信号转换成电动机轴上的角位移或角速度输出。分为直流和交流伺服电动机两大类,其主要特点是,当信号电压为零时无自转现象,转速随着转矩的增加而匀速下降.伺服主要靠脉冲来定位,基本上可以这样理解,伺服电机接收到1个脉冲,就会旋转1个脉冲对应的角度,从而实现位移,因为,伺服电机本身具备发出脉冲的功能,所以伺服电机每旋转一个角度,都会发出对应数量的脉冲,这样,和伺服电机接受的脉冲形成了呼应,或者叫闭环,如此一来,系统就会知道发了多少脉冲给伺服电机,同时又收了多少脉冲回来,这样,就能够很精确的控制电机的转动,从而实现精确的定位,可以达到0.001mm。& 直流伺服电机分为有刷和无刷电机。有刷电机成本低,结构简单,启动转矩大,调速范围宽,控制容易,需要维护,但维护不方便(换碳刷),产生电磁干扰,对环境有要求。因此它可以用于对成本敏感的普通工业和民用场合。
阅读(29370)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
在LOFTER的更多文章
loftPermalink:'',
id:'fks_',
blogTitle:'普通电机,减速电机,步进电机,伺服电机的区别',
blogAbstract:'这里讲的普通电机,步进电机,伺服电机指的是直流电的微型电机,平常我们接触到的也以直流电的居多。电机的学问很深,本文只是为初学者大致讲一下制作机器人常用的各种电机。
电机,俗称“马达”,是指依据电磁感应定律实现电能的转换或传递的一种电磁装置。电动机也称(俗称马达),在电路中用字母“M”(旧标准用“D”)表示。它的主要作用是产生驱动转矩,作为用电器或各种机械的动力源,发电机在电路中用字母“G”表示。
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:1,
publishTime:1,
permalink:'blog/static/',
commentCount:2,
mainCommentCount:2,
recommendCount:4,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'0',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}轻松学PIC之步进电机篇_图文_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&10W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
轻松学PIC之步进电机篇
阅读已结束,下载本文需要
想免费下载本文?
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩2页未读,
定制HR最喜欢的简历
你可能喜欢第九章&&&步进电机和蜂鸣器(一)
本教材现以连载的方式由网络发布,并将于2014年由清华大学出版社出版最终完整版,版权归作者和清华大学出版社所有。本着开源、分享的理念,本教材可以自由传播及学习使用,但未经作者同意不得用于任何商业目的。最终解释权归金沙滩工作室所有,更多信息可登陆www.kingst.org了解。
最新章节的PDF版下载地址可以从我们主站找到:&,如有错误希望大家帮忙找出,我好及时改正。
对于技术的学习,我希望大家一定要有足够的耐性和韧性。如果你决定从事单片机这门技术,那就一定要坚持学习下去,不能半途而废,当你坚持学习一段时间后你会发现自己慢慢会喜欢这些玩意,对这些东西有了浓厚的兴趣和感情,那你离成功就不远了。学到第九课了,鼓励鼓励自己,再加把劲哦!
单片机的IO口结构
上节课我们提到了单片机的IO口的其中一种“准双向IO”的内部结构,实际上我们的单片机IO口还有另外三种状态,分别是开漏、推挽、高阻态,我们通过图9-1来看下三种状态。
图9-1&单片机IO口状态示意图&&&&
前边我们简单介绍“准双向IO”的时候,我们是用三极管来说明的,出于严谨的态度,我们这里按照实际情况用MOS管画图示意。实际上三极管是靠电流导通的,而MOS管是靠电压导通的,具体缘由和他们的内部构造有关系,在这里我们暂且不必关心,如果今后有必要了解可以直接查找模拟电子书或者百度相关资料进行细致学习。在单片机IO口状态这一块内容上,我们可以把MOS管当三极管来理解。在我们的图9-1中,T1相当于一个PNP三极管,T2相当于一个NPN三极管。
其中准双向IO口原理已经讲过了,开漏输出和准双向IO的唯一区别,就是开漏输出把内部的上拉电阻去掉了。开漏输出如果要输出高电平时,T2关断,IO电平要靠外部的上拉电阻才能拉成高电平,如果没有外部上拉电阻IO电平就是一个不确定态。标准51单片机的P0口默认就是开漏输出,如果要用的时候外部需要加上拉电阻。而强推挽输出就有比较强的驱动能力,如图9-1中第三张小图,当内部输出一个高电平时,通过MOS管直接输出电流,没有电阻的限流,电流输出能力也比较大;如果内部输出一个低电平,那反向电流也可以很大,强推挽的一个特点就是驱动能力强。
单片机IO还有一种状态叫高阻态。通常我们用来做输入引脚的时候,可以将IO口设置成高阻态,高阻态引脚本身如果悬空,用万用表测量的时候可能是高可能是低,他的状态完全取决于外部输入引脚的电平,高阻态引脚对GND的电阻很大相当于一个无穷大,所以称之为高阻。
这就是单片机的IO口的四种状态,在我们51单片机学习过程中,我们的主要应用是准双向IO口,随着我们学习的深入,其他状态也会有接触,在这里介绍给大家学习一下。
上下拉电阻
前边似乎我们很多次提到了上拉电阻,下拉电阻,具体到底什么样的电阻算是上下拉电阻,上下拉电阻都有何作用呢?
上拉电阻就是将不确定的信号通过一个电阻拉到高电平,同时此电阻也起到一个限流作用,下拉就是下拉到低电平。
比如我们的IO设置为开漏输出高电平或者是高阻态时,默认的电位是不确定的,外部经一个电阻接到VCC,也就是上拉电阻,那么相应的引脚就是高电平;经一个电阻到GND,也就是下拉电阻,那么相应的引脚就是一个低电平。
上拉电阻应用很多,都可以起到什么作用呢?我们现在主要先了解最常用的以下4点。
1、OC门要输出高电平,必须外部加上拉电阻才能正常使用,其实OC门就相当于单片机IO的开漏输出,其原理可参照图9-1中的开漏电路。
2、加大普通IO口的驱动能力。标准51单片机的内部IO口的上拉电阻,一般都是在几十K欧,比如STC89C52RC内部是20K的上拉电阻,所以最大输出电流是250uA,因此外部加个上拉电阻,可以形成和内部上拉电阻的并联结构,增大高电平时电流的输出能力。
3、在电平转换电路中,比如我们前边讲的5V转12V的电路中,上拉电阻其实起到的是限流电阻的作用,如图9-2所示。
图9-2&上拉电阻R2
4、比如单片机总线引脚,不使用的引脚悬空的时候,容易受到电磁干扰而处于一个紊乱状态,加上一个对VCC的上拉电阻或者一个对GND的下拉电阻后,可以有效的抵抗电磁干扰。
我们在进行电路设计的时候,如何正确选择合适的上下拉电阻的阻值呢?
1、从节约功耗的方面考虑应当足够大,因为电阻越大,电流越小。
2、从确保足够的引脚驱动电流考虑应当足够小,电阻小了,电流才能大。
3、在开漏输出时,过大的上拉电阻会导致信号上升沿变缓。我们来解释一下:实际电平的变化都是需要时间的,虽然很小,但永远都达不到零,而开漏输出时上拉电阻的大小就直接影响了这个上升过程所需要的时间,如图9-3所示。想一下,如果电阻很大,而信号频率又很快的话,最终将导致信号还没等上升到高电平就又变为低了,于是信号就无法正确传送了。
图9-3&上拉电阻对波形的影响
综合考虑,我们常用的上下拉电阻值大多选取在1k到10k之间,具体到底多大通常要根据实际需求来选,通常情况下在标准范围内就可以了,不一定是一个固定的值。
28BYJ-48型步进电机详解与实例
电机的分类
电机的分类方式有很多,从用途的角度可划分电机分为驱动类电机和控制类电机。直流电机属于驱动类电机,这种电机是将电能转换成机械能,主要应用在电钻、小车轮子、电风扇、洗衣机等等设备上。步进电机属于控制类电机,它是将脉冲信号转换成一个转动角度的电机,在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,主要应用在自动化仪表、机器人、自动生产流水线、空调扇叶转动等设备。
步进电机分为反应式、永磁式和混合式三种。
反应式步进电机:结构简单成本低,但是动态性能差、效率低、发热大、可靠性难以保证,所以现在基本已经被淘汰。
永磁式步进电机:动态性能好、输出力矩较大,但误差相对来说大一些,因其价格低广泛应用于消费性产品。
混合式步进电机:综合了反应式和永磁式的优点,力矩大、动态性能好、步距角小,精度高,但是结构相对来说复杂,价格也相对高,主要应用于工业。
我们本章内容主要讲解28BYJ-48这款步进电机,其中
28——步进电机的有效最大外径是28毫米
B&——表示是步进电机
Y&——表示是永磁式
J&——表示是减速型
48——表示四相八拍
28BYJ-48型步进电机原理详解
28BYJ-48是4相永磁式减速步进电机,其外观如下图所示:
图9-4&步进电机外观
我们先来解释什么是“4相永磁式”的概念,28BYJ-48的内部结构示意图9-2所示。先看里圈,它上面有6个齿,分别标注为0-5,这个叫做转子,顾名思义,它是要转动的,转子的每个齿上都带有永久的磁性,是一块永磁体,这就是“永磁式”的概念;再看外圈,这个就是定子,它是保持不动的,实际上它是跟电机的外壳固定在一起的,它上面有8个齿,而每个齿上都缠上了一个线圈绕组,正对着的2个齿上的绕组又是串联在一起的,也就是说正对着的2个绕组总是会同时导通或关断的,如此就形成了4相,在图中分别标注为A-B-C-D,这就是“4相”的概念。
图9-5&步进电机内部结构示意图
现在我们分析一下它的工作原理:
假定电机的起始状态就如上图所示,起始时是B相绕组的开关闭合,B相绕组导通,那么导通电流就会在正上和正下两个定子齿上产生磁性,这两个定子齿上的磁性就会对转子上的0和3号齿产生最强的吸引力,就会如图所示的那样,转子的的0号齿在正上、3号齿在正下而处于平衡状态;此时我们会发现,转子的1号齿与右上的定子齿也就是C相的一个绕组呈现一个很小的夹角,2号齿与右边的定子齿也就是D相绕组呈现一个稍微大一点的夹角,很明显这个夹角是1号齿和C绕组夹角的2倍,同理,左侧的情况也是一样的。
接下来,我们把B相绕组断开,而使C相绕组导通,那么很明显,右上的定子齿将对转子1号齿产生最大的吸引力,而左下的定子齿将对转子4号齿,产生最大的吸引力,在这个吸引力的作用下,转子1、4号齿将对齐到右上和左下的定子齿上而保持平衡,如此,转子就转过了起始状态时1号齿和C相绕组那个夹角的角度。
再接下来,断开C相绕组,导通D相绕组,过程与上述的情况完全相同,最终将使转子2、5号齿与定子D相绕组对齐,转子又转过了上述同样的角度。
那么很明显,当A相绕组导通,即完成一个B-C-D-A的四节拍操作后,转子的0、3号齿将由原来的对齐到上下2个定子齿,而变为了对齐到左上和右下的两个定子齿上,即转子转过了一个定子齿的角度。依此类推,再来一个四节拍,转子就将再转过一个齿的角度,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相则黄色接地,依此类推;再根据上述单四拍和八拍工作过程的讲解,可以得出下面的绕组控制顺序表:
表9-1&&八拍模式绕组控制顺序表
我们板子上控制步进电机部分是和板子上的显示控制的74HC138译码器部分复用的P1.0到P1.3,这个部分我们在“全板子测试视频”里边已经讲过了,可以通过调整跳线帽实现步进电机的控制,如图9-6所示。
图9-6&显示译码器和步进电机接口跳线帽
&&&&如果大家使用电机的话,需要把4个跳线帽都调到跳线组的左侧,即左侧针和中间针连通,就可以使用P1.0到P1.3控制步进电机了,要再使用显示部分的话,就要再换回到右侧了。那如果大家既想让显示部分正常工作,又想让电机工作该怎么办呢?跳线帽保持在右侧,用杜邦线把步进电机的控制引脚(即左侧的排针)连接到其它的暂不使用的单片机IO上即可。
再来看一下我们步进电机的原理图,步进电机的控制电路如下:
图9-7&&步进电机控制电路
诚然,单片机的IO口可以直接输出0V和5V的电压,但是电流驱动能力,也就是带载能力非常有限,所以我们在每相的控制线上都增加一个三极管来提高驱动能力。由图中可以看出,若要使A相导通,则必须是Q2导通,此时A相也就是橙色线就相当于接地了,于是A相绕组导通,此时单片机P1口低4位应输出0b1110,即0xE;如要A、B相同时导通,那么就是Q2、Q3导通,P1口低4位应输出0b1100,即0xC,依此类推,我们可以得到下面的八拍节拍的IO控制代码数组:
unsigned&char&code&BeatCode[8]&=&{&0xE,&0xC,&0xD,&0x9,&0xB,&0x3,&0x7,&0x6&};
到这里,似乎所有的逻辑问题都解决了,循环将这个数组内的值送到P1口就行了。但是,只要再深入想一下就会发现还有个问题:多长时间送一次数据,也就是说一个节拍要持续多长时间合适呢?是随意的吗?当然不是了,这个时间是由步进电机的启动频率决定的。启动频率,就是步进电机在空载情况下能够正常启动的最高脉冲频率,如果脉冲频率高于该值,电机就不能正常启动。下表是由厂家提供的步进电机参数表:
表9-2&&28BYJ-48步进电机参数表
表中给出的参数是≥550,单位是P.P.S,即每秒脉冲数,这里的意思就是说:每个电机保证在你每秒给出550个步进脉冲的情况下,电机可以启动。换算成单节拍持续时间就是1s&550=1.8ms,那为了让电机能够启动,我们控制节拍刷新时间大于1.8ms就可以了。有了这个参数,我们就可以动手写出最简单的电机转动程序了,如下:
unsigned&char&code&BeatCode[8]&=&{&&//步进电机节拍对应到IO控制电平的代码
&&&&0xE,&0xC,&0xD,&0x9,&0xB,&0x3,&0x7,&0x6
void&delay(unsigned&int&cnt);
void&main()
&&&&unsigned&char&
&&&&unsigned&char&step&=&0;
&&&&&&&&buf&&=&P1&&&0xF0;&&&&&&&//用buf暂存P1口的高4位,而低4位清零
&&&&&&&&buf&|=&BeatCode[step];&&//buf低4位改为相应的节拍代码值
&&&&&&&&P1&&&=&&&&&&&&&&&&&&//修改后完毕后的值送回到P1口
&&&&&&&&step++;&&&&&&&&//步进节拍递增
&&&&&&&&step&&=&0x07;&&//用“与”方式实现到8归零
&&&&&&&&delay(200);&&&&//延时2ms,即2ms执行一拍
void&delay(unsigned&int&cnt)
&&&&while&(cnt--);
赶快编译下载到板子上试试吧!看看电机转了没有?记得换跳线哦!
转动精度与深入分析
转是转了,但是不是感觉有点不太对劲呢?太慢了?别急,咱们继续。根据本章开头讲解的原理,八拍模式时,步进电机转过一圈是需要64个节拍,而我们程序中是每个节拍持续2ms,那么转一圈就应该是128ms,即1秒钟转7圈多,可怎么看上去它好像是7秒多才转了一圈呢?
那么,是时候来了解“永磁式减速步进电机”中这个“减速的概念了”。下图是这个28BYJ-48步进电机的拆解图,从图中可以看到,位于最中心的那个白色小齿轮才是步进电机的转子输出,64个节拍只是让这个小齿轮转了一圈,然后它带动那个浅蓝色的大齿轮,这就是一级减速。大家看一下右上方的白色齿轮的结构,除电机转子和最终输出轴外的3个传动齿轮都是这样的结构,一层多齿和一层少齿构成,而每一个齿轮都用自己的少齿层去驱动下一个齿轮的多齿层,这样每2个齿轮都构成一级减速,一共就有了4级减速,那么总的减速比是多少呢?即转子要转多少圈最终输出轴才转一圈呢?
图9-8&步进电机内部齿轮示意图
回头看一下电机参数表中的减速比这个参数吧——1:64,转子转64圈,最终输出轴才会转一圈,也就是需要64&64=4096个节拍输出轴才转过一圈,2ms&ms,8秒多才转一圈呢,是不是更刚才的实验结果正好吻合了?4096个节拍转动一圈,那么一个节拍转动的角度——步进角度就是360/4096,看一下表中的步进角度参数5.625/64,算一下就知道这两个值是相等的,一切都已吻合了。
OK,关于基本的控制原理本该到这里就全部结束了,但是,我们希望大家都能培养一种“实践是检验真理的唯一标准”的思维方式!回想一下,步进电机最大的特点是什么?精确控制转动量!那么我们是不是应该检验一下它到底是不是能精确呢?精确到什么程度呢?怎么来检验呢?让它转过90度,然后量一下准不准?也行,但是如果它只差了1度甚至不到1度,你能准确测量出来吗?在没有精密仪器的情况很难。我们还是让它多转几个整圈,看看它最后停下的位置还是不是原来的位置。对应的,我们把程序修改一下,以方便控制电机转过任意的圈数。
void&delay(unsigned&int&cnt);
void&TrunMotor(unsigned&long&angle);
void&main()
&&&&TrunMotor(360*25);&//360度*25,即25圈
&&&&while(1);
void&TrunMotor(unsigned&long&angle)
&&&&unsigned&char&
&&&&unsigned&char&step&=&0;
&&&&unsigned&long&beats&=&0;
&&&&unsigned&char&code&BeatCode[8]&=&{&&//步进电机节拍对应到IO控制电平的代码
&&&&&&&&0xE,&0xC,&0xD,&0x9,&0xB,&0x3,&0x7,&0x6
&&&&beats&=&(angle&*&4096)&/&360;&//计算需要的节拍数,4096拍对应一圈
&&&&while&(beats--)
&&&&&&&&buf&&=&P1&&&0xF0;&&&&&&&//用buf暂存P1口的高4位,而低4位清零
&&&&&&&&buf&|=&BeatCode[step];&&//buf低4位改为相应的节拍代码值
&&&&&&&&P1&&&=&&&&&&&&&&&&&&//修改后完毕后的值送回到P1口
&&&&&&&&step++;&&&&&&&&//步进节拍递增
&&&&&&&&step&&=&0x07;&&//用“与”方式实现到8归零
&&&&&&&&delay(200);&&&&//延时2ms,即2ms执行一拍
&&&&P1&|=&0x0F;&//关闭电机所有的相
void&delay(unsigned&int&cnt)
&&&&while&(cnt--);
上述程序中,我们先编写了一个控制电机转过指定角度的函数,这个角度值由函数的形式参数给出,然后在主函数中就可以方便的通过更改调用时的实际参数来控制电机转过任意的角度了。我们用了360*25,也就是25圈,当然你也可以随意改为其它的值,看看是什么结果。我们的程序会执行25*8=200秒的时间,先记下输出轴的初始位置,然后上电并耐心等它执行完毕,看一下,是不是……有误差?怎么回事,哪儿出问题了,不是说能精确控制转动量吗?
这个问题其实是出在了减速比上,再来看一下,厂家给出的减速比是1:64,不管是哪个厂家生产的电机,只要型号是28BYJ-48,其标称的减速比就都是1:64。但实际上呢?经过我们的拆解计算发现:真实准确的减速比并不是这个值1:64,而是1:63.684!得出这个数据的方法也很简单,实际数一下每个齿轮的齿数,然后将各级减速比相乘,就可以得出结果了,实测的减速比为(32/9)*(22/11)*(26/9)*(31/10)≈63.684,从而得出实际误差为0.0049,即约为百分之0.5,转100圈就会差出半圈,那么我们刚才转了25圈,是不是就差了八分之一圈了,也就是45度,看一下刚才的误差是45度吧。那么按照1:63.684的实际减速比,可以得出转过一圈所需要节拍数是64*63.684≈4076。那么就把上面程序中电机驱动函数里的4096改成4076再试一下吧。是不是看不出丝毫的误差了?但实际上误差还是存在的,因为上面的计算结果都是约等得出的,实际误差大约是0.000056,即万分之0.56,转一万圈才会差出半圈,已经可以忽略不计了。
那么厂家的参数为什么会有误差呢?难道厂家不知道吗?要解释这个问题,我们得回到实际应用中,步进电机最通常的目的是控制目标转过一定的角度,通常都是在360度以内的,而这个28BYJ-48最初的设计目的是用来控制空调的扇叶的,扇叶的活动范围是不会超过180度的,所以在这种应用场合下,厂商给出一个近似的整数减速比1:64已经足够精确了,这也是合情合理的。然而,正如我们的程序那样,我们不一定是要用它来驱动空调扇叶,我们可以让它转动很多圈来干别的,这个时候就需要更为精确的数据了,这也是我们希望读者都能了解并掌握的,就是说我们要能自己“设计”系统并解决其中发现的问题,而不要被所谓的“现成的方案”限制住思路。
编写实用程序的基础
解决了精度问题,让我们再次回到我们的电机控制程序上吧。上面给出的两个例程都不是实用的程序,为什么?因为程序中存在大段的延时,而在延时的时候是什么其它的事都干不了的,想想第二个程序,整整200秒什么别的事都干不了,这在实际的控制系统中是绝对不允许的。那么怎么改造一下呢?当然还是用定时中断来完成了,既然每个节拍持续时间是2ms,那我们直接用定时器定时2ms来刷新节拍就行了。改造后的程序如下:
unsigned&long&beats&=&0;
void&TrunMotor(unsigned&long&angle);
void&main()
&&&&//配置T0工作在模式1,定时2ms
&&&&TMOD&=&0x01;
&&&&TH0&=&0xF8;
TL0&=&0xCD;
&&&&TR0&=&1;
&&&&ET0&=&1;
&&&&TrunMotor(360*2+180);&//控制电机转动2圈半
&&&&while(1);
void&TrunMotor(unsigned&long&angle)
&&&&//在计算前关闭中断,完成后再打开,以避免中断打断计算过程而造成错误
&&&&EA&=&0;
&&&&beats&=&(angle&*&4076)&/&360;&//实测为4076拍转动一圈
&&&&EA&=&1;
void&InterruptTimer0()&interrupt&1
&&&&unsigned&char&
&&&&static&unsigned&char&step&=&0;&&&&&&//使用静态变量以保存住前一次的值
&&&&unsigned&char&code&BeatCode[8]&=&{&&//步进电机节拍对应到IO控制电平的代码
&&&&&&&&0xE,&0xC,&0xD,&0x9,&0xB,&0x3,&0x7,&0x6
&&&&TH0&=&0xF8;&&//溢出后进入中断重新赋值
&&&&TL0&=&0xCD;
&&&&if&(beats&!=&0)
&&&&&&&&buf&&=&P1&&&0xF0;&&&&&&&//用buf暂存P1口的高4位,而低4位清零
&&&&&&&&buf&|=&BeatCode[step];&&//buf低4位改为相应的节拍代码值
&&&&&&&&P1&&&=&&&&&&&&&&&&&&//修改后完毕后的值送回到P1口
&&&&&&&&step++;&&&&&&&&//步进节拍递增
&&&&&&&&step&&=&0x07;&&//用“与”方式实现到8归零
&&&&&&&&beats--;
&&&&&&&&P1&|=&0x0F;&//关闭电机所有的相
程序还是比较简单的,电机转动的启动函数只负责计算一个需要的总节拍数beats,然后在中断函数内检测这个变量,不为0时就执行节拍刷新操作,同时将其减1,直到减到0位置。
这里,我们要特别说明一下的是函数中对EA的两次操作。我们可以看到对beats的赋值计算语句是夹在EA=0;EA=1;这两行语句中间的,也就是说这行赋值计算语句在执行前先关闭了中断;而等它执行完后,才又重新打开了中断;在它执行过程中CPU是不会响应中断的,即中断函数InterruptTimer0不会被执行;即使这时候定时器溢出了,中断发生了,也只能等待在EA重新置1后,才能得到响应,中断函数InterruptTimer0才会被执行。
那么为什么要这么做呢?我们来想一下:一开始就提到了,我们所使用的STC89C52单片机是8位单片机,这个8位的概念就是说单片机操作数据时都是按8位即1个字节进行的,那么要操作多个字节(不论是读还是写)就必须分多次进行了;而我们程序中定义的beats这个变量是unsigned&long型,它要占用4个字节,那么对它的赋值最少也要分4次才能完成了;我们想象一下,假如在完成了其中第一个字节的赋值后,恰好中断发生了,InterruptTimer0函数得到执行,而这个函数内可能会对beats进行减1的操作,减法就有可能发生借位,借位就会改变其它的字节,但因为此时其它的字节还没有被赋入新值,于是错误就会发生了,减1所得到的结果就不是预期的值了!所以要避免这种错误的发生就得先暂时关闭中断,等赋值完成后再打开中断;而如果我们使用的是char或bit型变量的话,因为它们都是在CPU的一次操作中就完成的,所以即使不关中断,也不会发生错误。问题分析清楚了,如何取舍还得根据实际情况来,遇上这类问题的时候多多考虑考虑吧。
包含综合应用的实用程序
上面我们虽然完成了用中断控制转动的程序,但实际上这个程序还是没多少实用价值的,我们不能每次想让它转动的时候都上下电啊,是吧。还有它不但得能正转还得能反转啊,也就是说不但能转过去,还得能转回来呀。好吧,我们就来做一个实例程序吧,结合第八章的按键程序,我们设计这样一个程序:按数字键1-9,控制电机转过1-9圈;配合上下键改变转动方向,按向上键后正向转1-9圈,向下键则反向转1-9圈;左键固定正转90度,右键固定反转90;Esc键终止转动。程序如下:
sbit&KEY_IN_1&&=&P2^4;&&//矩阵按键的扫描输入引脚1
sbit&KEY_IN_2&&=&P2^5;&&//矩阵按键的扫描输入引脚2
sbit&KEY_IN_3&&=&P2^6;&&//矩阵按键的扫描输入引脚3
sbit&KEY_IN_4&&=&P2^7;&&//矩阵按键的扫描输入引脚4
sbit&KEY_OUT_1&=&P2^3;&&//矩阵按键的扫描输出引脚1
sbit&KEY_OUT_2&=&P2^2;&&//矩阵按键的扫描输出引脚2
sbit&KEY_OUT_3&=&P2^1;&&//矩阵按键的扫描输出引脚3
sbit&KEY_OUT_4&=&P2^0;&&//矩阵按键的扫描输出引脚4
const&unsigned&char&code&KeyCodeMap[4][4]&=&{&//矩阵按键编号到PC标准键盘键码的映射表
&&&&{&'1',&&'2',&&'3',&0x26&},&//数字键1、数字键2、数字键3、向上键
&&&&{&'4',&&'5',&&'6',&0x25&},&//数字键4、数字键5、数字键6、向左键
&&&&{&'7',&&'8',&&'9',&0x28&},&//数字键7、数字键8、数字键9、向下键
&&&&{&'0',&0x1B,&0x0D,&0x27&}&&//数字键0、ESC键、&&回车键、&向右键
unsigned&char&KeySta[4][4]&=&{&&//全部矩阵按键的当前状态
&&&&{1,&1,&1,&1},
&&&&{1,&1,&1,&1},
&&&&{1,&1,&1,&1},
&&&&{1,&1,&1,&1}
signed&long&beats&=&0;&&&//步进电机转动的总节拍数
void&KeyAction(unsigned&char&keycode);
void&main(void)
&&&&unsigned&char&i,&j;
&&&&unsigned&char&backup[4][4]&=&{&&//按键值备份,保存前一次的值
&&&&&&&&{1,&1,&1,&1},
&&&&&&&&{1,&1,&1,&1},
&&&&&&&&{1,&1,&1,&1},
&&&&&&&&{1,&1,&1,&1}
&&&&//配置T0工作在模式1,定时1ms
&&&&TMOD&=&0x01;
&&&&TH0&=&0xFC;
&&&&TL0&=&0x67;
&&&&TR0&=&1;
&&&&ET0&=&1;
&&&&while(1)
&&&&&&&&//检索按键状态的变化
&&&&&&&&for&(i=0;&i&4;&i++)
&&&&&&&&&&&&for&(j=0;&j&4;&j++)
&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&if&(backup[i][j]&!=&KeySta[i][j])
&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&if&(backup[i][j]&==&0)&&//按键弹起时执行动作
&&&&&&&&&&&&&&&&&&&&{
&&&&&&&&&&&&&&&&&&&&&&&&KeyAction(KeyCodeMap[i][j]);
&&&&&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&&&&&&&&&backup[i][j]&=&KeySta[i][j];
&&&&&&&&&&&&&&&&}
&&&&&&&&&&&&}
void&TrunMotor(signed&long&angle)
&&&&//在计算前关闭中断,完成后再打开,以避免中断打断计算过程而造成错误
&&&&EA&=&0;
&&&&beats&=&(angle&*&4076)&/&360;&//实测为4076拍转动一圈
&&&&EA&=&1;
void&StopMotor()
&&&&EA&=&0;
&&&&beats&=&0;
&&&&EA&=&1;
void&KeyAction(unsigned&char&keycode)
&&&&static&bit&dirMotor&=&0;&&//电机转动方向
&&&&if&((keycode&='1')&&&&(keycode&='9'))&&//控制电机转动1-9圈
&&&&&&&&if&(dirMotor&==&0)
&&&&&&&&&&&&TrunMotor(360*(keycode-'0'));
&&&&&&&&else
&&&&&&&&&&&&TrunMotor(-360*(keycode-'0'));
&&&&else&if&(keycode&==&0x26)&&//向上键,控制转动方向为正转
&&&&&&&&dirMotor&=&0;
&&&&else&if&(keycode&==&0x28)&&//向下键,控制转动方向为反转
&&&&&&&&dirMotor&=&1;
&&&&else&if&(keycode&==&0x25)&&//向左键,固定正转90度
&&&&&&&&TrunMotor(90);
&&&&else&if&(keycode&==&0x27)&&//向右键,固定反转90度
&&&&&&&&TrunMotor(-90);
&&&&else&if&(keycode&==&0x1B)&&//Esc键,停止转动
&&&&&&&&StopMotor();
void&MotorDrive()
&&&&unsigned&char&
&&&&static&unsigned&char&step&=&0;&&&&&&//使用静态变量以保存住前一次的值
&&&&unsigned&char&code&BeatCode[8]&=&{&&//步进电机节拍对应到IO控制电平的代码
&&&&&&&&0xE,&0xC,&0xD,&0x9,&0xB,&0x3,&0x7,&0x6
&&&&if&(beats&!=&0)
&&&&&&&&if&(beats&&&0)
&&&&&&&&&&&&step++;&&&&&&&&//正转时步进节拍递增
&&&&&&&&&&&&step&&=&0x07;&&//用“与”方式实现到8归零
&&&&&&&&&&&&beats--;&&&&&&&//正转时节拍计数递减
&&&&&&&&else
&&&&&&&&&&&&step--;&&&&&&&&//反转时步进节拍递增
&&&&&&&&&&&&step&&=&0x07;&&//用“与”方式同样可以实现到-1时归7
&&&&&&&&&&&&beats++;&&&&&&&//反转时节拍计数递增
&&&&&&&&buf&&=&P1&&&0xF0;&&&&&&&//用buf暂存P1口的高4位,而低4位清零
&&&&&&&&buf&|=&BeatCode[step];&&//buf低4位改为相应的节拍代码值
&&&&&&&&P1&&&=&&&&&&&&&&&&&&//修改后完毕后的值送回到P1口
&&&&&&&&P1&|=&0x0F;&&//节拍计数到0时关闭电机所有的相
void&KeyScan()
&&&&unsigned&char&i;
&&&&static&unsigned&char&keyout&=&0;&&//矩阵按键扫描输出计数器
&&&&static&unsigned&char&keybuf[4][4]&=&{&&//按键扫描缓冲区,保存一段时间内的扫描值
&&&&&&&&{0xFF,&0xFF,&0xFF,&0xFF},
&&&&&&&&{0xFF,&0xFF,&0xFF,&0xFF},
&&&&&&&&{0xFF,&0xFF,&0xFF,&0xFF},
&&&&&&&&{0xFF,&0xFF,&0xFF,&0xFF}
&&&&//将一行的4个按键值移入缓冲区
&&&&keybuf[keyout][0]&=&(keybuf[keyout][0]&&&&1)&|&KEY_IN_1;
&&&&keybuf[keyout][1]&=&(keybuf[keyout][1]&&&&1)&|&KEY_IN_2;
&&&&keybuf[keyout][2]&=&(keybuf[keyout][2]&&&&1)&|&KEY_IN_3;
&&&&keybuf[keyout][3]&=&(keybuf[keyout][3]&&&&1)&|&KEY_IN_4;
&&&&//消抖后更新按键状态
&&&&for&(i=0;&i&4;&i++)&&//每行4个按键,所以循环4次
&&&&&&&&if&((keybuf[keyout][i]&&&0x0F)&==&0x00)
&&&&&&&&{&&&//连续4次扫描值为0,即16ms(4*4ms)内都只检测到按下状态时,可认为按键已按下
&&&&&&&&&&&&KeySta[keyout][i]&=&0;
&&&&&&&&else&if&((keybuf[keyout][i]&&&0x0F)&==&0x0F)
&&&&&&&&{&&&//连续4次扫描值为1,即16ms(4*4ms)内都只检测到弹起状态时,可认为按键已弹起
&&&&&&&&&&&&KeySta[keyout][i]&=&1;
&&&&//执行下一次的扫描输出
&&&&keyout++;
&&&&keyout&&=&0x03;
&&&&switch&(keyout)
&&&&&&&&case&0:
&&&&&&&&&&&&KEY_OUT_4&=&1;
&&&&&&&&&&&&KEY_OUT_1&=&0;
&&&&&&&&&&&&
&&&&&&&&case&1:
&&&&&&&&&&&&KEY_OUT_1&=&1;
&&&&&&&&&&&&KEY_OUT_2&=&0;
&&&&&&&&&&&&
&&&&&&&&case&2:
&&&&&&&&&&&&KEY_OUT_2&=&1;
&&&&&&&&&&&&KEY_OUT_3&=&0;
&&&&&&&&&&&&
&&&&&&&&case&3:
&&&&&&&&&&&&KEY_OUT_3&=&1;
&&&&&&&&&&&&KEY_OUT_4&=&0;
&&&&&&&&&&&&
&&&&&&&&default:
&&&&&&&&&&&&
void&InterruptTimer0()&interrupt&1
&&&&static&bit&div&=&0;
TH0&=&0xFC;&&//溢出后进入中断重新赋值,定时1ms
&&&&TL0&=&0x67;
&&&&KeyScan();&&&//执行按键扫描
&&&&//用一个静态bit变量实现二分频,即2ms定时,用于驱动电机
&&&&div&=&~
&&&&if&(div&==&1)
&&&&&&&&MotorDrive();
这个程序是第八章和本章知识的一个综合——用按键控制步进电机转动。程序中有这么几点值得注意,我们分述如下:
1、针对电机要完成正转和反转两个不同的操作,我们并没有使用正转启动函数和反转启动函数这么两个函数来完成,也没有在启动函数定义的时候增加一个形式参数来指明其方向。我们这里的启动函数void&TrunMotor(signed&long&angle)与单向正转时的启动函数唯一的区别就是把形式参数angle的类型从unsigned&long改为了signed&long,我们用有符号数固有的正负特性来区分正转与反转,正数表示正转angle度,负数就表示反转angle度,这样处理是不是很简洁又很明了呢?而你对有符号数和无符号数的区别用法是不是也更有体会了?
2、针对终止电机转动的操作,我们定义了一个单独的StopMotor函数来完成,尽管这个函数非常简单,尽管它也只在Esc按键分支内被调用了,但我们仍然把它单独提出来作为了一个函数。而这种做法就是基于这样一条编程原则:尽可能用单独的函数来完成硬件的某种操作,当一个硬件包含多个的操作时,把这些操作函数组织在一起,形成一个对上层的统一接口。这样的层次化处理,会使得整个程序条理清晰,即有利于程序的调试维护,又有利于功能的扩充。
3、中断函数中要处理按键扫描和电机驱动两件事情,而为了避免中断函数过于复杂,我们就又分出了按键扫描和电机驱动两个函数(这也同样符合上述2的编程原则),而中断函数的逻辑就变得简洁而清晰了。这里还有个矛盾,就是按键扫描我们选择的定时时间是1ms,而本章之前的实例中电机节拍持续时间都是2ms;很显然,用1ms的定时可以定出2ms的间隔,而用2ms的定时却得不到准确的1ms间隔;所以我们的做法就是,定时器依然定时1ms,然后用一个bit变量做标志,没1ms改变一次它的值,而我们只选择值为1的时候执行一次动作,这样就是2ms的间隔了;如果我要3ms、4ms……呢,把bit改为char或int型,然后对它们递增,判断到哪个值该归零,就可以了;这就是在硬件定时器的基础上实现准确的软件定时,其实类似的操作我们在讲数码管的时候也用过了,回想一下吧。
蜂鸣器的学习
蜂鸣器从结构区分分为压电式蜂鸣器和电磁式蜂鸣器。压电式为压电陶瓷片发音,电流比较小一些,电磁式蜂鸣器为线圈通电震动发音,体积比较小。
按照驱动方式分为有源蜂鸣器和无源蜂鸣器。这里的有源和无源不是指电源,而是振荡源。有源蜂鸣器内部带了振荡源,如图9-9所示中,给了BUZZ引脚一个低电平,蜂鸣器就会直接响。而无源蜂鸣器内部是不带振荡源的,要让他响必须给500Hz到4.5kHz之间的脉冲频率信号来驱动它才会响。有源蜂鸣器往往比无源蜂鸣器贵一些,因为里边多了振荡电路,驱动发音也简单,靠电平就可以驱动,而无源蜂鸣器价格比较便宜,此外无源蜂鸣器声音频率可以控制,而音阶与频率又有确定的对应关系,因此就可以做出来“do&re&mi&fa&sol&la&si”的效果,可以用它制作出简单的音乐曲目,比如生日歌、两只老虎等等。
图9-9&蜂鸣器工作原理图
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。}

我要回帖

更多关于 51单片机控制步进电机 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信