微机接口课程设计报告Word格式.docx
《微机接口课程设计报告Word格式.docx》由会员分享,可在线阅读,更多相关《微机接口课程设计报告Word格式.docx(26页珍藏版)》请在冰豆网上搜索。
其引脚图和内部框图分别如下:
2.1流水灯的控制平台的介绍:
在学校的实验平台上LED灯的端口地址是0x0c860,通过控制LED输入电平的高低来控制LED灯的明与暗,而电平的高低是通过想端口写的数据来体现的,例如向端口写1就代表输入的是高电平而0则代表的是低电平。
因而要实现需求分析中的流水灯的各种功能,只需要控制各端口的电平的高低,也就是对端口写数据的不同。
灯的闪烁的实现就是在LED灯全明与全暗之间设置一个延迟,这样观察的效果就是闪烁,而从左至右和从右至左的变化是通过将初始值(10h和01h)进行向左移位或者向右移位即可。
图3:
实验平台简介
2.2设计思想:
在以前的上机实验中我们分别做过流水灯和步进电机的实验,而且都成功的完成了这两次实验,因此此次课程设计算的上是对以前做的实验的一次综合,而创新点就在于在自动控制方式下编码与解码的问题,因此在设计思想中,手动控制这一块我将只做简要介绍,详细介绍的是在自动控制中所采用的方法。
手动控制:
因为时间和速度都是按照一定的比例来完成的,所以不同档位的实现也就是LED灯的控制开关在不同状态下时延迟时间不同的控制,同时在不同的延迟时间下给每个档位指定一个速度,延迟长的速度小,延迟短的速度大,这样便能实现对不同档位的控制,而灯的闪烁也只是在灯的明与暗之间加上一个延迟的时间便能完成,总体来说手动控制的大体思想较为简单,而难点主要是在档位切换的问题,开关的拔动和档位的变换以及电机做出的反应这期间的时间差应该越小越好,因而在程序的书写过程中我使用的Switch…Case…语句,电机每走一步就进行一次判断,而不是用For循环来控制,这样能将时间差缩短到很小的范围内。
表1:
相序表的设计
绕组与数据线的连接及八拍数据的表示
D
C
B
A
PA7
PA6
PA5
PA4
PA3
PA2
PA1
PA0
0
1
自动控制:
档位的切换和LED灯的明暗控制和手动控制肯定是没有什么区别的,而自动控制的主要难点在于对控制序列的定义及解析,也就是将不同的档位及在该档位下行进的步数进行的定义。
我的解决思路是用abcdefgh八个不同的字母来分别表示不同的档位,同时用数字表示在该档位下运行的步骤,在得知档位和数字后,就只需要用循环来控制在当前档位下的行进步数便能完成在自动控制下的工作。
控制序列的输入在我的程序中并不是用常用的文本输入(实验后发现文本输入更为简单而不需要进行数字的转换,这里走了弯路,但是还是按照最初自己的设计思路来说明的),我是从编辑框的控件进行输入的,由于编辑框的数据相当与字符串的类型,因而并不能对数字进行识别(即在编辑框中输入123,程序中只能分别识别数字123而不是整数123而文本输入便能解决这个问题,这就是我说的弯路所在),同时在序列输入完毕后我会对该序列进行遍历,如果遇到不是a~h或者不是0~9中的字符便提示该序列是非法序列,否则用两个数组对字母或者数字分别进行存储,同时用计数器进行计数来判别字母或者数字是否相对应,一个字母应该相对应的对应一个数字,这样才算完整的序列。
序列判别完毕后,接下来的工作就是用序列来控制电机的自动运转,即控制在整数步骤内完成相应的电机运转操作,具体的运转操作还是和手动控制一样。
值得注意的是无论是自动测试还是手动测试,都要求用文件来保存小车行驶的里程,以便下次程序运行时开始重新调用,因此在程序中涉及到了读、写文件的操作,我的设计过程中,都是在电机没运转一步时便开始重新将里程写入文件,而读文件是在每次程序开始重新运行时。
2.3基于MFC的程序具体的设计步骤:
(1)主程序框图如下:
主程序的设计框图如下:
是
否
(2)详细的设计步骤
步骤1:
创建基于对话框的MFC程序,同时将主对话框及作为程序的主登录界面,给程序添加自动测试和手动测试的选择按钮,及进入测试的按钮,如图示:
图4:
主程序界面
步骤2:
创建2个新的对话框分别作为手动测试和自动测试的主界面,同时都给对话框分别添加速度和里程显示的编辑框以及进入测试的按钮,同时MFC的头文件中还必须添加#include"
conio.h"
的头文件,以便对实验中的端口地址进行调用。
界面设置如图示:
图5:
各测试程序界面
步骤3:
完成相应代码部分的书写
3.调试分析
调试过程中在手动控制这块基本没有什么问题,问题主要是集中在自动测试的过程中,这也和每个人的程序书写有关,由于我的程序不是用的文本来进行控制序列的输入,因此在进行字符的转换这一块经常一些没想到的情况出现,但是通过不断的调试和老师的验收,最后还是圆满的完成了此次课程设计。
下面主要给出自动测试过程中一些非法的序列输入:
图六:
一些非法的输入
其中正确的输入即为程序中定义的a~h八个档位加数字(及在档位行进的步数)如下图:
图七:
正确的输入序列
4.实验结果及收获
本次实验一共是四个人一组,因此在纠错方面能够较为迅速的发现问题同时解决问题,在第二次实验的时候我们组就已经验收了,这里也颇为自豪。
实验的过程印象较为深刻的是老师在检查自动运转这一块,有几次都是因为程序不够严谨而犯了错误,因此在以后的程序书写过程中应该更加认真的审视自己的程序。
同时此次实验也是对MFC综合应用的一次锻炼,在以后的学习中应该自己多给自己创造一些这样的机会,锻炼自己学习的综合运用能力。
5.部分程序清单如下:
//不同状态的定义分别表示不同的档位
typedefenum{s0,s1,s2,s3,s4,s5,s6,s7,s8,s9}State;
//手动测试部分
voidSpeed:
:
OnButtonStart()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
fp=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("
w"
fprintf(fp,"
m_length);
MessageBox("
本次测试结束,请重新开始!
"
break;
}
switch(state)
cases0:
//测试开始开关
flag=1;
cases1:
//静止
_outp(0x0c860,255);
Sleep(300);
_outp(0x0c860,0);
cases2:
//进档1
m_speed=60;
m_length+=40;
Right();
_outp(0x0c860,2);
cases3:
//进档2
m_speed=70;
_outp(0x0c860,4);
cases4:
//进档3
m_speed=80;
_outp(0x0c860,8);
cases5:
//进档4
m_speed=90;
_outp(0x0c860,16);
cases6:
//进档5
m_speed=100;
_outp(0x0c860,32);
cases7:
//进档6
m_speed=120;
_outp(0x0c860,64);
cases8:
//倒档
m_speed=40;
Left();
_outp(0x0c860,128);
cases9:
//换档
确定要换档?
default:
}
//初始化及档位的判断
intSpeed:
ReadDota()
intk;
k=_inp(0x0c860);
//读入LED的开关信息
//根据开关的信息做出判断当前档位
if(k==0)//
elseif(k==1)
state=s1;
elseif(k==2)
state=s2;
dalay=1000;
elseif(k==4)
state=s3;
dalay=800;
elseif(k==8)
state=s4;
dalay=600;
elseif(k==16)
state=s5;
dalay=400;
elseif(k==32)
state=s6;
dalay=200;
elseif(k==64)
state=s7;
dalay=100;
elseif(k==128)
state=s8;
dalay=1500;
else
state=s9;
UpdateData(0);
UpdateWindow();
return0;
//电机开始右转
Right()
_outp(0x0c801,a[ii]);
ii++;
//到下一相序
if(ii==8)
ii=0;
//电机开始左转
Left()
_outp(0x0c801,a[jj]);
jj--;
if(jj==-1)
jj=7;
//自动测试部分
/////////////////////////////////////////////////////////////////////////////
//Lengthmessagehandlers
//对输入的初始行进序列的判断判断是否合法如果合法则开始存储运行
voidLength:
OnButton1()
m_ceshi="
;
fp1=fopen("
//文件操作
feof(fp1))
fscanf(fp1,"
chars[1000];
intn;
inti,j;
charalp[200];
intnum[200],tmp=0;
intcount1=0,count2=0,countN=0;
intflag=0;
//表示是数字1表示是字母
charz[10];
UpdateData
(1);
n=m_ceshi.GetLength();
itoa(n,z,10);
MessageBox(z);
s[0]=m_ceshi.GetAt(0);
(s[0]>
=97&
&
s[0]<
=104))
MessageBox("
非法序列monkey!
m_ceshi="
nimei();
return;
//用于序列的判断及存储
for(i=0;
i<
n;
i++)
s[i]=m_ceshi.GetAt(i);
if(s[i]>
s[i]<
=104)
if(flag==1)
{
MessageBox("
非法序列biaoge!
m_ceshi="
nimei();
break;
}
if(countN!
=0)
for(j=0;
j<
countN;
j++)
{
intjj;
jj=countN-j-1;
tmp+=PanDuan(jj)*((int)s[i-countN+j]-48);
}
num[count2++]=tmp;
tmp=0;
countN=0;
alp[count1++]=s[i];
countN=0;
elseif(s[i]>
=48&
=57)
countN++;
else
非法序列mengge2!
m_ceshi="
nimei();
return;
if((i==(n-1))&
(flag==0)&
(s[i]>
=48)&
(s[i]<
=57))
for(j=0;
tmp+=PanDuan(jj)*((int)s[i-countN+j+1]-48);
//MessageBox("
wofuleni"
num[count2++]=tmp;
tmp=0;
//countN=0;
/*if(s[i]==97)
}*/
//序列之间不匹配
if(flag==1)
MessageBox("
非法序列mengge!
//itoa(count2,z,10);
//MessageBox(z);
/*for(i=0;
count2;
m_speed=num[i];
Sleep(300);
count1;
m_length=alp[i];
*/
ReadDota(alp[i]);
SoGa(num[i]);
fp1=fopen("
fprintf(fp1,"
//刷新窗口
intLength:
nimei()
//主要用于在进行序列判断时序列当前位数的识别
PanDuan(int&
n)
switch(n)
case0:
return1;
case1:
return10;
case2:
return100;
case3:
return1000;
case4:
return10000;
case5:
return1000000;
//自动运行的主函数
SoGa(intn)
inti;
caseS1:
//静止挡
caseS2:
caseS3:
caseS4:
caseS5:
caseS6:
caseS7:
caseS8:
//慢挡
//cases9:
//break;
br