电子赛培训课作品设计报告题目:单片机控制步进电机:班别:学号:序号:完成时间:2012-5-17华南理工大学学院电子信息工程学院目录引言 (1)一、系统方案的选择和论证 (1)二、总体设计 (2)三、单元电路设计 (3)四、整体测试 (4)五、结论 (5)六、总结 (6)七、参考文献 (6)单片机控制步进电机摘要:本设计采用一块AT89C52单片机对一个四相步进电机进行控制,使步进电机在安全温度按输入的步数和转动的方向进行运行。
控制电机转动的方法采用四相八拍控制法。
本设计采用矩阵键盘实现步进电机不同转动步数的输入以及转向的控制,还有对键盘实现锁键和开锁的作用。
用DS18B20代替电机的测温系统,实现超温报警和停机的功能。
引言随着数字化技术发展,数字控制技术得到了广泛而深入的应用。
步进电机是一种将数字信号直接转换成角位移或线位移的控制驱动元件, 具有快速起动和停止的特点。
因为步进电动机组成的控制系统结构简单,价格低廉,性能上能满足工业控制的基本要求,所以广泛地应用于手工业自动控制、数控机床、组合机床、机器人、计算机外围设备、照相机,投影仪、数码摄像机、大型望远镜、卫星天线定位系统、医疗器件以及各种可控机械工具等等。
设计容:采用单片机控制一个三相单三拍的步进电机工作。
要实现的功能:一、步进电机的旋转方向由正反转控制信号控制;二、步进电机的步数由键盘输入,可输入的步数分别为3、6、9、12、15、18、21、24和27步,且键盘具有键盘锁功能,当键盘上锁时,步进电机不接受输入步数,也不会运转。
只有当键盘锁打开并输入步数时,步进电机才开始工作;三、电机运转的时候有正转和反转指示灯指示;四、电机在运转过程中,如果过热,则电机停止运转,同时红色指示灯亮,同时警报响。
本次设计的意义:1) 了解51系列单片机及外围相关芯片、电路的工作原理和接口技术,学会进行控制系统软件程序设计。
2) 编制程序完成步进电机速度、方向、及旋转角度的控制。
3) 设计相关的硬件电路,软硬调试实现步进电机速度、方向、及旋转角度的控制,分析结果。
4) 学会运用“自动控制原理”、“现代控制理论”和“计算机控制技术”所学理论知识进行控制器的设计和计算机控制的算法实现。
为今后毕业设计、将来工作做必要的知识储备。
一、系统方案选择和论证本设计由于需要实现9个不同步数的输入以及其它功能的输入,所以可以采用独立键盘和矩阵键盘,实现步进电机的步数由键盘输入且键盘具有键盘锁功能。
考虑到单片机的端口数量有限和编程和方便性,最后决定采用矩阵键盘。
在步进电机方面由于此次设计的软件采用proteus,在此软件中只有一个四相步进电机的模型,然后考虑到步进电机控制方法的难易度最后决定采用四相八拍控制法,由于单片机不能直接驱动步进电机,所以P2口在输出后接入ULN2803,ULN2803输出后接电机,通过此芯片放大控制电压。
在测温方面一开始打算用一个温度传感器开关去实时监测电机的温度,当温度过高的时候就断开开关;但考虑到系统的可操作性、准确性、编程的难易度及仿真软件的限制,最后决定采用DS18B20代替电机的测温系统,实现电机在运转过程中,如果过热,则电机停止运转,同时红色指示灯亮,同时警报响。
在转向方面用不同颜色的LED灯指示正转和反转。
当电机温度超过安全温度时,报警灯会闪烁和报警铃会鸣响,并让电机停止运转同时锁住键盘。
基于单片机和proteus的步进电机控制电路的基本组成如图2-1所示。
图2-1二、总体设计图2-2三、单元电路设计1、电机工作状态指示模块如图3-1所示图3-1功能:指示单片机目前的工作状态,当电机的温度超出安全温度的时候,报警灯闪的同时,报警器也会响。
2、单片机驱动电机模块(如图3-2)图3-2功能:单片机输出的程序通过ULN2803电机驱动器给步进电机一个脉冲信号,使步进电机实现按输入步数正转与反转。
3、电机温度监测模块(如图3-3)图3-3功能:实时监测电机的温度,当电机超过安全温度时,单片机会发出警报并停止电机工作。
4、键盘输入模块(如图3-4)图3-4功能:通过预设使每一个键盘具有一个特定的功能,从而实现按设计要求控制电机的需求。
四、整体测试1、安全温度下电机正转(如图4-1)图4-1此时电机正转,正转指示灯亮,功能正常实现。
2、安全温度下电机反转(如图4-2)图4-2此时电机反转,反转指示灯亮,功能正常实现。
3、超出安全温度时电机停止工作并报警(如图5-1)图5-1此电机温度超出安全温度50,报警灯闪烁,报警器鸣响,键盘锁住禁止输入。
同时指示停机前电机转动的方向。
功能正常。
4、当键盘锁住时键盘无法使用刚开机时,为防止出现事故,整个功能键盘是锁住的,只有解锁后才能对电机进行控制,在运行过程当中,当键盘锁住后,将保持停机前的状态,并禁止对电机进行操作。
其它功能还是正常运行。
结论是正常。
五、结论经测试,整体电路工作正常,实现了要求的所有功能。
由于延时的原因,有些功能会出现一定的误差,比如:有时按下键去的时候电机会没有反应,因为程序还没有执行到这里。
本设计有多个不足之处,比如:电机在没有走完输入的步数之前是不能对电机进行其它的控制,就算此时电机已经超出了安全温度也不能及时的报警和停机。
由于延时的效果,使得电机在执行输入的相应的步数的时候会出现一点偏差,但是走的总步数是没有错的。
对此,我提出改进方案为,用定时器中断方式,每隔一断时间去检查,看电机是否已超出安全温度,这样就能及时的停机。
我还会增加一个紧急停机按钮,使得现场出现紧急情况的时候能实现紧急停机。
我还会再增加一个加速控制钮和一个减速控制钮,使电机在连续转动时能平稳的运行以及起步和停机。
对电路进行调整后,如果可以的话,还可以加上可视功能,显示电机现在走了几步,目前的温度如何。
六、总结在此次设计中,由于是第一次接触步进电机,出于对步进电机的不了解,就在用多少拍控制电机方面我参考了网上不少资料以及不少相关的书籍,最后确定用八拍控制法最合适,四相八拍控制法被普遍认为是比较好用的一种控制方法。
刚开始不知道电机在转动的时候会有惯性效应,即如果在上一个脉冲控制下没有完全走完,但是下个脉冲已经过来了,这就会产生堵转和失步现象。
所以在执行程序的时候要增加一点延时。
在做足了所有的准备后,电机还是不能正确的转动,我曾经一步把注意力放在程序上,但是后来在参考一本资料的时候偶然发现其电机的接线图有所不同,这让我开始注意到,也许硬件电路的设计出了问题,果然在后来对硬件电路进行调整后,实现了预定的功能。
在实现了电机能合理的转动的情况下,我就把温度监测部分加进来。
但这不是简简单单的增加一个子函数的问题,它关系到整个程序的运行,使得整个程序都要做出相应的调整,这真的是牵一发而动全身。
同样一个变量我放在主函数里比较大小与放在子函数里比较都会有不一样的效果,一个能正确实现相应的功能,而另一个却不会。
这也让我在编程方面积累了一点经验。
当测温这一块加进来后,由于程序增加了不少,而且里面还有相当一部分的延时语句,所以,单片机对键盘的扫描就不再那么及时了,这就出现了有时按下键去却没反应的现象。
这是我以后要改进的地方。
七、参考文献【图书文献】[1]、作者:高洪志,《MCS-51单片机原理及应用技术教程》,,人民邮电,2009年4月出版,第314~316页。
[2]、作者:丁向荣,《STC系列增强型8051单片机》,,电子工业,2011年1月出版,第289~290页。
[3]、作者:周润景,《单片机电路设计、分析与制作》,,机械工业,210年8月出版,第16~25页。
【网络文献】[1]、wenku.baidu./view/c5f8513331126edb6f1a10f4.html,2010-12-15, 基于单片机的步进电机控制系统(汇编及C语言程序各一个)[2]、wenku.baidu./view/5a3aa642a8956bec0975e3c1.html,2010-10-07,基于单片机控制的步进电机___毕业论文附程序:#include<reg52.h>#include<intrins.h> //包含_nop_()函数定义的头文件#define uchar unsigned char#define uint unsigned intucharbeheavecount[]={0x00,0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09};ucharopbeheavecount[]={0x00,0x09,0x08,0x0c,0x04,0x06,0x02,0x03,0x01}; //ucharbeheavecount[]={0x00,0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09}; uchar step,temp,lock,lock2,i,o,time,flag;sbit DQ=P3^3;sbit wrong=P0^3;sbit warning=P0^2;void keyscan();void delay(uint z);void beheave(uchar x);void Write(uchar dat);uchar Read();void Init();void delayms(uint i);void tempereture();void main(){step=lock=lock2=0;i=1;o=0x00;P0=0x00;P2=0xff;P0=0x02;wrong=0;while(1){warning=0;tempereture();if(flag==1){warning=0;keyscan();if(step==30) //锁键{step=0;lock=0;}if(step==31) //解锁{lock=1;step=0;}if(step==32&&o==0x00) //换正向{step=0;P0=0x02;lock=0;i=9-i;i++;if(i>8)i=1;i++;if(i>8)i=1;}if(step==32&&o==0xff) //换反向{step=0;P0=0x01;lock=0;i=9-i;i++;if(i>8)i=1;i++;if(i>8)i=1;}}if(flag==0){warning=1;delay(200);wrong=~wrong;lock=0;}if(lock&&step>0)beheave(step);}}void keyscan() //键盘处理函数{P1=0xfe;temp=P1;temp=temp&0xf0;while(temp!=0xf0) //消除抖动{delay(5);temp=P1;temp=temp&0xf0;while(temp!=0xf0){temp=P1;switch(temp) //判断按下哪个键{case 0xee:step=3;break;case 0xde:step=6;break;case 0xbe:step=9;break;case 0x7e:step=12;break;}while(temp!=0xf0) //判断键是否已回位{temp=P1;temp=temp&0xf0;}//lock=1;}}P1=0xfd;temp=P1;temp=temp&0xf0;while(temp!=0xf0){delay(5);temp=P1;temp=temp&0xf0;while(temp!=0xf0){temp=P1;switch(temp){case 0xed:step=15;break;case 0xdd:step=18;break;case 0xbd:step=21;break;case 0x7d:step=24;break;}while(temp!=0xf0) //判断键是否已回位{temp=P1;temp=temp&0xf0;}//lock=1;}}P1=0xfb;temp=P1;temp=temp&0xf0;while(temp!=0xf0){delay(5);temp=P1;temp=temp&0xf0;while(temp!=0xf0){temp=P1;switch(temp){case 0xeb:step=27;break;case 0xdb:step=30;lock2=0;break;case 0xbb:step=0;lock2=1;break;case 0x7b:step=32;o=~o;break;}while(temp!=0xf0) //判断键是否已回位{temp=P1;temp=temp&0xf0;}//lock=1;}}if(lock2==0)lock=0;else if(lock2==1)lock=1;}void beheave(uchar x) //电机转动处理函数{uint y=0; //定义一个记录赋值次数的变量if(o==0xff){do{P2=opbeheavecount[i];if(i==8)i=1;elsei++;y++;delay(600);}while(y<x);}if(o==0x00){do{P2=beheavecount[i];if(i==8)i=1;elsei++;y++;delay(600);}while(y<x);}lock=0;step=0;}void Init(void)//初始化{//unsigned char flag=0;DQ = 0; //单片机将DQ拉低delayms(100); //精确延时大于480us小于960usDQ = 1; //拉高总线delayms(30);//flag=DQ; //稍做延时后如果flag=0则初始化成功flag=1则初始化失败//delay(20);}uchar Read(void)//读字节{uchar a=0;uchar dat = 0;for (a=8;a>0;a--){DQ = 0; // 给脉冲信号dat>>=1;DQ = 1; // 给脉冲信号if(DQ)dat|=0x80;delayms(5);}return(dat);}void Write(uchar dat)//写字节{uchar a=0;for (a=8; a>0; a--){DQ = 0;DQ = dat&0x01;delayms(5);DQ = 1;dat>>=1;}}void tempereture(){unsigned char tl=0,th=0;unsigned char TN,TD;Init();Write(0xCC); // 跳过读序号列号的操作Write(0x44); // 启动温度转换delay(100);Init();Write(0xCC); //跳过读序号列号的操作Write(0xBE); //读取温度寄存器等delay(100);tl=Read(); //读取温度值低位th=Read(); //读取温度值高位if((th&0xf8)!=0x00)//判断高五位得到温度正负标志{tl=~tl; //取反th=~th; //取反time=tl+1; //低位加1tl=time;if(time>255) th++; //如果低8位大于255,向高8位进1TN=th*16+tl/16; //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16//这样得出的是温度的整数部分,小数部分被丢弃了TD=(tl%16)*10/16; //计算温度的小数部分,将余数乘以10再除以16取整,}TN=th*16+tl/16; //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16//这样得出的是温度的整数部分,小数部分被丢弃了TD=(tl%16)*10/16;time=TN+TD;if(time>=50){warning=1;flag=0;}else{warning=0;flag=1;}}void delay(uint z){uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);}void delayms(uint a) //如果i是unsigend char类型,则会出现错误结果{while(a--);}。