
课 程 设 计
课程名称 微型计算机控制技术
题目名称 步进电机角度控制(2)
学生学院 自动化
专业班级 XXXXXXXX
学 号 XXXXX
姓 名 XXX
指导教师 李传芳
2013年06月19日
一、目的……………………………………………………………………3
二、课程设计内容…………………………………………………………3
三、总体设计………………………………………………………………4
四、心得体会………………………………………………………………6
五、参考文献………………………………………………………………6
六、源程序…………………………………………………………………7
七、任务书…………………………………………………………………15
步进电机角度控制(2)
——使用8688系统
一、目的
1.巩固和加深对《计算机控制技术》课程内容的认识和理解,提高应用水平;
2.熟悉键盘控制和七段数码管的使用;
3.掌握直流电机的速度控制和测试方法。
二、课程设计内容
按照如下给出的连线图,完成下面2个任务:
任务1 连接数码管显示电路和键盘电路,实现如下表所示的按键控制,并能够左移显示:
| 0 | 1 | 7 | 8 |
| E | F | A | B |
(1)定义键盘按键:5个为数字键:0、1、3、5、9 ;3个功能键:设置SET、清零 CLR、开始START;按键分布如下表所示:
| CLR | 3 | 9 | SET |
| 0 | 1 | 5 | START |
(3) 通过键盘的按键,设置步进电机各次的角度值;按动SET键后,开始设置:第一位设置次数,后三位设置角度值,再次按动SET置入,并可连续置入2个不同角度;
(4) 按START键启动步进电机开始转动,到位后停止;按CLR键清零,步进电机回原位。
(5)实现任务书中的功能:
、键入3 (次数)315(角度数),键入SET设置完毕,键入START步进电机转动315度 3次;停止后键入CLR返回零位;每个过程都有相关的显示。
、键入5 (次数)90(角度数),键入SET设置完毕,键入START步进电机转动90度5次;停止后键入CLR返回零位;每个过程都有相关的显示。
三、总体设计
硬件设计
本次设计要求通过键盘按键实现对步进电机的转动次数和每次转动的角度的控制,并通过数码管显示出来。
本方案中通过按键对步进电机[1][2]的转动角度进行设定,给各个按键设置不同的键值。按下按键时,给8255A一个信号设定步进电机下一步的动作。8086通过8255A的数据总线读取该信号,并作出反应,通过给8255A一系列的指令驱动其工作,从而驱动步进电机和LED显示器。
系统软件设计
显示模块[3]设计说明:为使显示程序具有通用性和灵活性,在8086内设置一个显示缓冲区,显示缓冲区的每个单元与LED的各位一一对应。当主程序需要显示,只需将要显示的字符送入显示缓冲区,然后调用显示子程序。显示子程序的任务则是逐一取出显示缓冲区中的字符、查字形表转换成相应字型码,然后通过字段口输出显示。显示模块是用四位七段数码管来显示转动次数和每次转动的角度。给八个按键设置不同的子程序,当按下按键时,根据事先设定好的各个按键对应的转动角度的值输出到数码管进行显示。
四相八拍步进电机模块设计说明:在此设计中,采用的是四相步进电机。步进电机控制程序就是完成环形分配器的任务,从而控制电动机的转动,以达到控制转动角度和位移的目的。控制模型可以以立即数的形式一一给出。对于步进电机模块的程序设计采用循环程序设计方法。先把转动的次数和角度的控制模型存放在内存单元中,然后再逐一从单元中取出控制模块并输出。首先启动,按下按键选择步进电机的角度,然后读入转动的控制模型驱动步进电机转动。
软件设计流程图如下图所示:
否
是
四、心得体会
本次的课程设计让我学到了不少的东西,首先,熟练了实际硬件的操作使用,例如,刚刚开始做第一个任务时,我连总线都忘了接,这是因为自身对于硬件系统的不熟悉造成的,所幸尽早发现了这个问题,所以在之后的硬件连接中我都很小心谨慎,反复检查;其次,巩固了课内已学知识,比如说,对于8086的编程使用,因为经过了一个学期的漠视,已经变得很生疏了,因此在完成任务前还需要对8086进行复习;再有,加深了对步进电机的理解和使用技巧,设计中,需要对步进电机进行角度控制,即需要对步进电机的角度进行计算分析,以得到所需的步数,而这些知识在课本上仅仅是以习题题目形式存在,趣味性不高,因此学得也不够深刻,而在此次设计中就充分吊起了我的兴趣,因而完成的气氛很愉快。
另外,在此次课程设计中,在任务二我试探性的采用了之前从未选取过的、略显生疏的C语言来代替汇编语言,因为C语言的易读性与简单性让我很感兴趣。当然,在编写过程中也遇到了很多困难,其中,我的感悟是:最大的错误都不是错误,最小的错误才是错误,因为在程序编写设计中,由于会用到一些全局变量和局部变量,为了偷懒方便,有的地方我采用了一样的变量名,而最后的结果就是:编译链接下载都没错了,但是按键就是无法检测,想来想去,最终在同学和我花费几个小时的共同努力下,发现了原来就是这个变量设置错误,造成了冲突。现在学到了变量真是不能随便设置这个简单的道理。同时也让我懂得了C语言的魅力所在,正是因为它简单易读,我寻求帮助的同学才能一起帮我检查错误,共同合作学习。
五、参考文献
[1] 黄勤,李楠.微型计算机控制技术。北京:机械工业出版社,2010.01
[2] 李传芳,高军礼,林丽纯.《计算机控制技术》实验指导书.广东工业大学,2013.01
[3] 郭天祥.51单片机C语言教程——入门、提高、开发、扩展全攻略.北京:电子工业出版社,2009.1
六、源程序
任务1程序:
SSEGMENT STACK
DW DUP(?)
STACK ENDS
DATA SEGMENT
BUF1 DB 3FH,3FH,3FH,3FH,3FH,3FH
BUF2 DB 00H,00H,00H,00H,00H,00H
PIANXUAN DB 0E0H,0D0H,70H,0BOH
DUANXUAN DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,77H,7CH,39H,5EH,79H,71H
DATA ENDS
CODE SEGMENT
:DATA, CS:CODE
START: , DATA
, AX
, 88H
, 0606H
, AL
STT: , 00H
, 0602H
, AL
NEXT: , 0604H
, DX
, 30H
, 30H
KEYSCAN
DISP
STT
;开始按键扫描
KEYSCAN: DELAY
, 0604H
, DX
, 30H
, 30H
KEY_0
STT
;第一列按键检测
KEY_0: , 0B0H
, 0602H
, AL
, 0604H
, DX
, 0D0H
KEY_E
KEY0
STTK
KEY_E: , 0E0H
KEY_1
KEYE
STTK
;第二列按键检测
KEY_1: , 70H
, 0602H
, AL
, 0604H
, DX
, 0D0H
KEY_F
KEY1
STTK
KEY_F: , 0E0H
KEY_7
KEYF
STTK
;第三列按键检测
KEY_7: , 0D0H
, 0602H
, AL
, 0604H
, DX
, 0D0H
KEY_A
KEY7
STTK
KEY_A: , 0E0H
KEY_8
KEYA
STTK
;第四列按键检测
KEY_8: , 0E0H
, 0602H
, AL
, 0604H
, DX
, 0D0H
KEY_B
KEY8
STTK
KEY_B: , 0E0H
KEY_END
KEYB
STTK
;按键检测完毕
KEY_END:JMP STTK
;各按键键值设置
KEY0: ZUOYI
, 00H
MOV [DI+3], AL
, DUANXUAN
DUANXUAN
MOV [SI+3], AL
DISP
RET
KEYE: ZUOYI
, 0EH
MOV [DI+3], AL
, DUANXUAN
DUANXUAN
MOV [SI+3], AL
DISP
KEY1: ZUOYI
, 01H
MOV [DI+3], AL
, DUANXUAN
DUANXUAN
MOV [SI+3], AL
DISP
RET
KEYF: ZUOYI
, 0FH
MOV [DI+3], AL
, DUANXUAN
DUANXUAN
MOV [SI+3], AL
DISP
RET
KEY7: ZUOYI
, 07H
MOV [DI+3], AL
, DUANXUAN
DUANXUAN
MOV [SI+3], AL
DISP
KEYA: ZUOYI
, 0AH
MOV [DI+3], AL
, DUANXUAN
DUANXUAN
MOV [SI+3], AL
DISP
RET
KEY8: ZUOYI
, 08H
MOV [DI+3], AL
, DUANXUAN
DUANXUAN
MOV [SI+3], AL
DISP
RET
KEYB: ZUOYI
, 0BH
MOV [DI+3], AL
, DUANXUAN
DUANXUAN
MOV [SI+3], AL
DISP
;数码管显示左移程序
ZUOYI: , 0003H
, BUF1
, BUF2
LOOPZ: , [SI+2]
MOV [SI+3], AL
, [DI+2]
MOV [DI+3], AL
DEC SI
DEC DI
LOOPZ
RET
;数码管显示程序
DISP: , PIANXUAN
, BUF1
, 0004H
DIR: , [SI]
, 0602H
, AL
, [DI]
, 0600H
, AL
DELAY
INC SI
INC DI
DIR
RET
;延时程序
DELAY: PUSH AX
PUSH CX
, 0040H
DELAY1: , 0020H
DELAY2: DEC AX
DELAY2
DELAY1
POP CX
POP AX
RET
STTK: DISP
, 00H
, 0602H
, AL
, 0604H
, DX
, 30H
, 30H
STTK
STT
CODE ENDS
START
任务2程序:
#include #include #include #define uint unsigned int #define uchar unsigned char //设置端口号,A口:0x0600; B口:0x0602;C口:0x0604 ;控制口:0x0606 #define pa 0x0600 #define pb 0x0602 #define pc 0x0604 #define ctrl 0x0606 //片选信号 uchar pianxuan[4]={0xb0, 0x70, 0xd0, 0xe0}; //步进电机正向走 uchar forward[8]={ 0x08,0x0c,0x04,0x06,0x02,0x03,0x01,0x09}; //步进电机反向走, uchar backward[8]={0x09,0x01,0x03,0x02,0x06,0x04,0x0c,0x08}; //段选 uchar duanxuan[16]={ 0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f, 0x77,0x7c,0x39,0x5e,0x79, 0x71 }; //设置各种参数,便于使用 uint qian,bai,shi,gee; uint qian8,bai8,shi8,gee8; uchar temp; //sett定义按键SET被按下的次数,flag则表示操作次数标识 uint sett,flag; //定义所需角度,次数,和所需步数 uint angle,cishu,bushu; uint t,w,a,j,i; //设置输入次数、角度时计数,共4次,初值为零 int count = 0; uint temp1,temp2,temp3, temp4,temp5; //延时程序,用于防抖和数码管显示 void delay(int c) { int a,b; for(a=c;a>0;a--) for(b=110;b>0;b--); } //显示程序,参数为四位数码管,如第四位即最高位表示为qian... void displaynow(char qian, char bai,char shi,char gea) { //输入第一个数字,即所需次数 outp(pa,duanxuan[qian]); //选中第一片数码管,下同 outp(pb,pianxuan[0]); //延时防抖 delay(8); //输入第二个数字,即角度的百位数,下同 outp(pa,duanxuan[bai]); outp(pb,pianxuan[1]); delay(8); outp(pa,duanxuan[shi]); outp(pb,pianxuan[2]); delay(8); outp(pa,duanxuan[gea]); outp(pb,pianxuan[3]); delay(8); } //del()参数清零 void del() { qian=0; bai=0; shi=0; gee=0; } //del8()参数清零 void del8() { qian8=0; bai8=0; shi8=0; gee8=0; } //设置SET按键 void sets() { sett ++; //初次按下SET键则清零参数 if(sett==1) del(); //第二次按下SET按键 else if(sett==2) { qian8=qian; bai8=bai; shi8=shi; gee8=gee; flag=0; count=0; } //第三次按下SET else if(sett==3) del(); //第四次按下SET按键 else if(sett==4) { //flag表示已不可再键入数字了 flag=1; sett=0; count=0; } } //START按键,步进电机开始运行 void start() { w=0; //电机所需转动角度、步数、次数的计算 angle=bai8*100+shi8*10+ gee8; bushu=angle*4/15; cishu=qian8; //若次数大于0,则电动机开始转动 while(cishu>0) { for(t=0;t if(j==8) j=0; //电机前进量 outp(pc,forward[j]); //调用显示程序 displaynow(cishu,bai8, shi8,gee8); j++; } cishu--; for(i=0;i<100;i++) displaynow(cishu, bai8,shi8,gee8); } //若已经连续输入了2次角度,则: if(flag==1) { w=0; angle=bai*100+shi*10+gee; bushu=angle*4/15; cishu=qian; while(cishu>0) { for(t=0;t if(j==8) j=0; outp(pc,forward[j]); displaynow(cishu,bai, shi,gee); j++; } cishu--; for(i=0;i<100;i++) displaynow(cishu,bai,shi,gee); } } } //清零程序clrs(),使电机返回原来位置 void clrs() { if(flag==1) { w=0; angle=bai*100+shi*10+gee bushu=angle*4/15; cishu=qian; while(cishu>0) { for(t=0;t j=0; outp(pc,backward[j]); displaynow(cishu,bai,shi,gee); j++; } cishu--; } del(); } w=0; angle=bai8*100+shi8*10+ gee8; bushu=angle*4/15; cishu=qian8; while(cishu>0) { for(t=0;t if(j==8) j=0; outp(pc,backward[j]); displaynow(cishu,bai8, shi8,gee8); j++; } cishu--; } del8(); sett=0; } //按键作用程序 void key() { uchar i,lie,hang,weizhi; for(i=0;i<4;i++) { //片选第i片数码管 outp(pb,pianxuan[i]); //读取C口电平信号 temp=inp(pc); //检测是否有按键按下 temp=temp&0x30 ; //检测哪行的按键被按下 if(temp!=0x30) { lie=i+1; //第一行按键被按下 if(temp==0x20) hang=0; //第二行按键被按下 else if(temp==0x10) hang=1; break ; } } //按键位置计算 weizhi=hang*4+lie; switch(weizhi) { //按键CLR case 1:clrs();break ; //按键3 case 2: if(sett==1||sett==3) temp1=3; switch(count) { Case 0:qian=temp1; break ; case 1:bai=temp1; break ; case 2:shi=temp1; break ; case 3:gee=temp1; break ; default: break ; } count=count+1; break ; //按键9 case 3: if(sett==1||sett==3) temp2=9; switch(count) { case 0:qian=temp2; break; case 1:bai=temp2; break; case 2:shi=temp2; break; case 3:gee=temp2; break; default: break; } count=count+1; break; //按键SET case 4:sets(); break; //按键0 case 5: if(sett==1||sett==3) temp3=0; switch(count) { case 0:qian=temp3; break; case 1:bai=temp3; break; case 2:shi=temp3; break; case 3:gee=temp3; break; default: break; } count=count+1; break ; //按键1 case 6: if(sett==1||sett==3) temp4=1; switch(count) { case 0:qian=temp4; break; case 1:bai=temp4; break; case 2:shi=temp4; break; case 3:gee=temp4; break; default: break; } count=count+1; break ; //按键5 case 7: if(sett==1||sett==3) temp5=5; switch(count) { case 0:qian=temp5; break; case 1:bai=temp5; break; case 2:shi=temp5; break; case 3:gee=temp5; break; default: break; } count=count+1; break; //按键START case 8:start();break; } outp(pb,0x00); temp=inp(pc); temp=temp&0x30 ; while(temp!=0x30) { outp(pb,0x00); temp=inp(pc); temp=temp&0x30; displaynow(cishu,bai,shi,gee); } } //按键扫描程序 void keyscan() { uchar tempt; outp(pb,0x00); tempt = inp(pc); tempt=tempt&0x30; if(tempt!=0x30) { delay(5); outp(pb,0x00); tempt=inp(pc); tempt=tempt&0x30 ; if(tempt!=0x30) key(); } } void main() { qian=0; bai=0; shi=0; gee=0; sett=0; //向控制口输出控制字 outp(ctrl,0x88); while(1) { keyscan(); displaynow(qian,bai, shi,gee); } }
