《微机接口课程设计报告利用步进电机模拟小车的运行.doc》由会员分享,可在线阅读,更多相关《微机接口课程设计报告利用步进电机模拟小车的运行.doc(19页珍藏版)》请在三一办公上搜索。
1、 微机接口课程设计报告 利用步进电机模拟小车的运行1、 需求分析及实验目的:此次实验的需求分析如下:1. 计算每次加电代码输入步进电机以后小车(步进电机)行进的距离(弧度,并按照一定的比例换算成长度)2. 利用8个开关设计8个档位,其中一个倒档,6个进档,1个静止档,不同档位设置不同的行进速度,其中出静止档外倒档最低;3. 在屏幕上显示2个窗口,分别显示小车当前的速度与行驶里程,其中行驶里程与程序运行的次数无关;4. 利用8个led显示当前的档位状况,其中:a. 倒档时,某一个等闪烁b. 静止档是,全部等闪烁5. 另外设计一种小车的自动行驶模式,在这种模式下,小车不通过开关控制档位,而通过一个
2、窗口的输入小车行进模式 (请自行设计行进代码),实现小车在不同档位下运行的时间、次序。实验要求同学能够理解8255A的0工作方式下通过时序对步进电机的工作流程的控制,同时将流水灯当作档位的控制开关,能够更好的体现对接口芯片的控制过程,而自动方式控制步进电机的运转,题目非常的开放,能够充分的发挥同学们的想象空间,同学们可以通过不同的编码形式来完成这个题目。2、 设计2.0 8255A芯片简介由于此次的设计涉及到8255A接口芯片的编程,因此在这里先对8255A的接口芯片做简要的介绍:8255A是一个具有两个8位和两个4位并行I/O端口的接口芯片,它为Intle系列的CPU与外部设备之间提供TTL
3、电平兼容的接口,以及需要同时两位以上信息传送的一切形式的并行接口。在学校的实验平台上它的命令口的地址为0x0c803,PA,PB,PC口的端口地址分别为0x0c800,0x0c801,0x0c802。其引脚图和内部框图分别如下: 2.1流水灯的控制平台的介绍:在学校的实验平台上LED灯的端口地址是0x0c860,通过控制LED输入电平的高低来控制LED灯的明与暗,而电平的高低是通过想端口写的数据来体现的,例如向端口写1就代表输入的是高电平而0则代表的是低电平。因而要实现需求分析中的流水灯的各种功能,只需要控制各端口的电平的高低,也就是对端口写数据的不同。灯的闪烁的实现就是在LED灯全明与全暗之
4、间设置一个延迟,这样观察的效果就是闪烁,而从左至右和从右至左的变化是通过将初始值(10h和01h)进行向左移位或者向右移位即可。图3:实验平台简介2.2设计思想:在以前的上机实验中我们分别做过流水灯和步进电机的实验,而且都成功的完成了这两次实验,因此此次课程设计算的上是对以前做的实验的一次综合,而创新点就在于在自动控制方式下编码与解码的问题,因此在设计思想中,手动控制这一块我将只做简要介绍,详细介绍的是在自动控制中所采用的方法。手动控制:因为时间和速度都是按照一定的比例来完成的,所以不同档位的实现也就是LED灯的控制开关在不同状态下时延迟时间不同的控制,同时在不同的延迟时间下给每个档位指定一个
5、速度,延迟长的速度小,延迟短的速度大,这样便能实现对不同档位的控制,而灯的闪烁也只是在灯的明与暗之间加上一个延迟的时间便能完成,总体来说手动控制的大体思想较为简单,而难点主要是在档位切换的问题,开关的拔动和档位的变换以及电机做出的反应这期间的时间差应该越小越好,因而在程序的书写过程中我使用的SwitchCase语句,电机每走一步就进行一次判断,而不是用For循环来控制,这样能将时间差缩短到很小的范围内。表1:相序表的设计 绕组与数据线的连接及八拍数据的表示DCBAPA7PA6PA5PA4PA3PA2PA1PA00 0000101000101010001010001010100010100000
6、10100010100000101000101自动控制:档位的切换和LED灯的明暗控制和手动控制肯定是没有什么区别的,而自动控制的主要难点在于对控制序列的定义及解析,也就是将不同的档位及在该档位下行进的步数进行的定义。我的解决思路是用a b c d e f g h八个不同的字母来分别表示不同的档位,同时用数字表示在该档位下运行的步骤,在得知档位和数字后,就只需要用循环来控制在当前档位下的行进步数便能完成在自动控制下的工作。控制序列的输入在我的程序中并不是用常用的文本输入(实验后发现文本输入更为简单而不需要进行数字的转换,这里走了弯路,但是还是按照最初自己的设计思路来说明的),我是从编辑框的控件
7、进行输入的,由于编辑框的数据相当与字符串的类型,因而并不能对数字进行识别(即在编辑框中输入123,程序中只能分别识别数字1 2 3 而不是整数123 而文本输入便能解决这个问题,这就是我说的弯路所在),同时在序列输入完毕后我会对该序列进行遍历,如果遇到不是ah 或者不是09中的字符便提示该序列是非法序列,否则用两个数组对字母或者数字分别进行存储,同时用计数器进行计数来判别字母或者数字是否相对应,一个字母应该相对应的对应一个数字,这样才算完整的序列。序列判别完毕后,接下来的工作就是用序列来控制电机的自动运转,即控制在整数步骤内完成相应的电机运转操作,具体的运转操作还是和手动控制一样。值得注意的是
8、无论是自动测试还是手动测试,都要求用文件来保存小车行驶的里程,以便下次程序运行时开始重新调用,因此在程序中涉及到了读、写文件的操作,我的设计过程中,都是在电机没运转一步时便开始重新将里程写入文件,而读文件是在每次程序开始重新运行时。2.3基于MFC的程序具体的设计步骤:(1) 主程序框图如下:进入主程序主程序的设计框图如下:手动?是否进入手动测试部分,用户手动控制c程序的测试过程用户输入运行序列,程序自动运行 (2)详细的设计步骤步骤1:创建基于对话框的MFC程序,同时将主对话框及作为程序的主登录界面,给程序添加自动测试和手动测试的选择按钮,及进入测试的按钮,如图示:图4:主程序界面步骤2:创
9、建2个新的对话框分别作为手动测试和自动测试的主界面,同时都给对话框分别添加速度和里程显示的编辑框以及进入测试的按钮,同时MFC的头文件中还必须添加#include conio.h的头文件,以便对实验中的端口地址进行调用。界面设置如图示:图5:各测试程序界面步骤3:完成相应代码部分的书写3. 调试分析调试过程中在手动控制这块基本没有什么问题,问题主要是集中在自动测试的过程中,这也和每个人的程序书写有关,由于我的程序不是用的文本来进行控制序列的输入,因此在进行字符的转换这一块经常一些没想到的情况出现,但是通过不断的调试和老师的验收,最后还是圆满的完成了此次课程设计。下面主要给出自动测试过程中一些非
10、法的序列输入:图六 :一些非法的输入其中正确的输入即为程序中定义的ah八个档位加数字(及在档位行进的步数)如下图:图七:正确的输入序列4 .实验结果及收获本次实验一共是四个人一组,因此在纠错方面能够较为迅速的发现问题同时解决问题,在第二次实验的时候我们组就已经验收了,这里也颇为自豪。实验的过程印象较为深刻的是老师在检查自动运转这一块,有几次都是因为程序不够严谨而犯了错误,因此在以后的程序书写过程中应该更加认真的审视自己的程序。同时此次实验也是对MFC综合应用的一次锻炼,在以后的学习中应该自己多给自己创造一些这样的机会,锻炼自己学习的综合运用能力。 5. 部分程序清单如下:/不同状态的定义 分别
11、表示不同的档位typedef enums0,s1,s2,s3,s4,s5,s6,s7,s8,s9State; /手动测试部分void Speed:OnButtonStart() / TODO: Add your control notification handler code herefp=fopen(data.txt,r);/打开保存里程的文档if(!feof(fp)fscanf(fp,%d,&m_length);_outp(0x0c803,0x80);while(1)ReadDota();if(flag=1)flag=0;fp=fopen(data.txt,w);fprintf(fp,%
12、d,m_length);MessageBox(本次测试结束,请重新开始!);break;switch(state)case s0:/测试开始开关flag=1;break;case s1:/静止_outp(0x0c860,255);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case s2:/进档1m_speed=60;m_length+=40;Right();_outp(0x0c860,2);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case s3:/进档2m_speed=70;m_length+=4
13、0;Right();_outp(0x0c860,4);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case s4:/进档3m_speed=80;m_length+=40;Right();_outp(0x0c860,8);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case s5:/进档4m_speed=90;m_length+=40;Right();_outp(0x0c860,16);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case s6:/进档5m_s
14、peed=100;m_length+=40;Right();_outp(0x0c860,32);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case s7:/进档6m_speed=120;m_length+=40;Right();_outp(0x0c860,64);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case s8:/倒档m_speed=40;m_length+=40;Left();_outp(0x0c860,128);Sleep(300);_outp(0x0c860,0);Sleep(300)
15、;break;case s9:/换档MessageBox(确定要换档?);break;default:break;/初始化及档位的判断int Speed:ReadDota()int k;k=_inp(0x0c860);/读入LED的开关信息/根据开关的信息做出判断当前档位if(k=0)/else if(k=1)state=s1;else if(k=2)state=s2;dalay=1000;else if(k=4)state=s3;dalay=800;else if(k=8)state=s4;dalay=600;else if(k=16)state=s5;dalay=400;else if(k
16、=32)state=s6;dalay=200;else if(k=64)state=s7;dalay=100;else if(k=128)state=s8;dalay=1500;elsestate=s9;UpdateData(0);UpdateWindow();return 0;/电机开始右转int Speed:Right()_outp(0x0c801,aii);ii+;/到下一相序if(ii=8)ii=0;return 0;/电机开始左转int Speed:Left()_outp(0x0c801,ajj);jj-;/到下一相序if(jj=-1)jj=7;return 0;/自动测试部分/ L
17、ength message handlers/对输入的初始行进序列的判断 判断是否合法 如果合法则开始存储 运行void Length:OnButton1() / TODO: Add your control notification handler code herem_ceshi=;fp1=fopen(data.txt,r);/文件操作if(!feof(fp1)fscanf(fp1,%d,&m_length);char s1000;int n;int i,j;char alp200;int num200,tmp=0;int count1=0,count2=0,countN=0;int fl
18、ag=0;/表示是数字 1表示是字母char z10;UpdateData(1);n=m_ceshi.GetLength();itoa(n,z,10);MessageBox(z);s0=m_ceshi.GetAt(0);if(!(s0=97&s0=104)MessageBox(非法序列monkey!);m_ceshi=;nimei();return ;/用于序列的判断及存储for(i=0;i=97&si=104)if(flag=1)MessageBox(非法序列biaoge !);m_ceshi=;nimei();break;if(countN!=0)for(j=0;j=48&si=48)&(
19、si=57)for(j=0;jcountN;j+)int jj;jj=countN-j-1;tmp+=PanDuan(jj)*(int)si-countN+j+1-48);/MessageBox(wo fu le ni );numcount2+=tmp;tmp=0;/countN=0;/*if(si=97)flag=0;*/序列之间不匹配if(flag=1)MessageBox(非法序列meng ge!);m_ceshi=;nimei();return ;/itoa(count2,z,10);/MessageBox(z);/*for(i=0;icount2;i+)m_speed=numi;Sl
20、eep(300);nimei();for(i=0;icount1;i+)m_length=alpi;Sleep(300);nimei();*/for(i=0;icount1;i+)ReadDota(alpi);SoGa(numi);UpdateData(1);fp1=fopen(data.txt,w);fprintf(fp1,%d,m_length);/刷新窗口int Length:nimei()UpdateData(0);UpdateWindow();return 0;/主要用于在进行序列判断时 序列当前位数的识别int Length:PanDuan(int &n)switch (n)cas
21、e 0:return 1;case 1:return 10;case 2:return 100;case 3:return 1000;case 4:return 10000;case 5:return 1000000;return 0;/自动运行的主函数int Length:SoGa(int n)int i;UpdateData(1);fp1=fopen(data.txt,r);if(!feof(fp1)fscanf(fp1,%d,&m_length);_outp(0x0c803,0x80);for(i=0;in;i+)switch(state)case S1:/静止挡_outp(0x0c86
22、0,255);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case S2:/进档1m_speed=60;m_length+=40;Right();_outp(0x0c860,2);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case S3:/进档2m_speed=70;m_length+=40;Right();_outp(0x0c860,4);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case S4:/进档3m_speed=80;m_length+=40;
23、Right();_outp(0x0c860,8);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case S5:/进档4m_speed=90;m_length+=40;Right();_outp(0x0c860,16);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case S6:/进档5m_speed=100;m_length+=40;Right();_outp(0x0c860,32);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case S7:/进档6m_s
24、peed=120;m_length+=40;Right();_outp(0x0c860,64);Sleep(300);_outp(0x0c860,0);Sleep(300);break;case S8:/慢挡m_speed=40;m_length+=40;Left();_outp(0x0c860,128);Sleep(300);_outp(0x0c860,0);Sleep(300);break;/case s9:/MessageBox(确定要换档?);/break;default:break;fp1=fopen(data.txt,w);fprintf(fp1,%d,m_length);Upda
25、teData(0);UpdateWindow();/fp=fopen(data.txt,w);/fprintf(fp,%d,m_length);/MessageBox(本次测试结束,请重新开始!);return 0;/序列动能的识别 及当前序列进行翻译 相当于手动中的初始化及档位的识/别 及相当于解码的功能 解读当前字符的含义完成相应动作int Length:ReadDota(char s) if(s=a)/静止档state=S1;else if(s=b)/进档1state=S2;dalay1=1000;else if(s=c)/进档2state=S3;dalay1=800;else if(s
26、=d)/进档3state=S4;dalay1=600;else if(s=e)/进档4state=S5;dalay1=400;else if(s=f)/进档5state=S6;dalay1=200;else if(s=g)/进档6state=S7;dalay1=100;else if(s=h)/倒档state=S8;dalay1=1500;UpdateData(0);UpdateWindow();return 0;/电机右转int Length:Right()_outp(0x0c801,a1iii);iii+;/到下一个相序if(iii=8)iii=0;return 0;/电机左转int Length:Left()_outp(0x0c801,a1jjj);jjj-;/到下一个相序if(jjj=-1)jjj=7;return 0;/主程序 用于选择void CMonkeyDlg:OnButtonEnter() / TODO: Add your control notification handler code hereUpdateData(1);if(m_choose=0)/选择手动测试程序Speed dlg;dlg.DoModal();else if(m_choose=1)/选择自动测试程序Length dlg;dlg.DoModal();