摘 要 介绍了构建单片机虚拟实验仿真平台的基本思路和各功能的实现方法,详细叙述了构建仿真平台所使用的一些技术手段。
关键词 虚拟实验平台;中断;输入输出接口;示波器;仿真实验
1 引言
虚拟仿真实验是利用计算机创建出一个可视化的实验操作环境,其中的每一个可视化仿真物体代表一种实验仪器或者设备,通过操作这些虚拟的实验仪器或设备,即可进行各种复杂的实验,达到与真实实验环境相一致的教学要求和目的。与传统的硬件实验平台相比,虚拟实验平台可以不受时空的限制,用户能随时随地进行实验。通过采用虚拟化技术,利用软件仿真,可以完全不使用真实的实验仪器,因此不会存在仪器磨损、破坏等情况,既节省了资金,又有利于资源共享。对于有危险性的实验,虚拟实验平台更具有优势。
2 单片机虚拟实验仿真平台的实现
2.1 系统设计思想及总体设计
我们开发的“单片机虚拟实验平台”将“硬件实验台”和“软件调试环境”均统一进行虚拟化设计,亦即不仅“硬件实验台”设计为软件形式,原来的汇编程序等调试工具也要重新专门进行设计,MASM等工具就不能使用。并且由于采用封闭式设计思路,对应用环境的适应性及其可靠性、稳定性相对较强;也就是说,这种虚拟平台下的实验结果与硬件条件下的结果更为相似。
图1 传统单片机实验系统组成结构
该仿真平台可以由如图2所示的模块图来表示。
从图2可以看出8031和存储器构成了虚拟的CPU,直接或间接地控制其它所有模块,并负责执行汇编语句。通信桥模块实际上是一个虚拟的存储空间,是接口芯片和外设(LED、开关和显示器等)间数据交换的场所。接口芯片和外设之间不直接发生关系,它们通过通信桥模块提供的接口将数据放入通信桥缓存或从通信桥缓存中取出数据。通常,通信桥分为输入桥、输出桥、芯片桥三种情况。开关与芯片连接构成输入桥,LED或者显示器与芯片连接构成输出桥,芯片与芯片连接构成芯片桥。
图2 总体框架图
2.2 具体设计
2.2.1 仿真平台编译原理
仿真平台对于汇编语言的编译模拟了真实的CPU。大家都知道,真实的CPU在编译过程中要使用寄存器(包括通用寄存器、特殊功能寄存器)。在虚拟的CPU环境下,我们模拟了一些寄存器,并且定义了一些执行函数以及运行规则。当然,这些运行规则是根据汇编指令制定的。虚拟的编译过程则是逐一与运行规则进行比较,从而检查语法错误,同时生成数据库存储所得到的一些数据。我们可以更具体地表述一下虚拟编译系统的工作过程:CPU在执行汇编程序的时候,实际上是运行的执行函数。首先启动一个新的线程mainthread,然后把源程序取出来逐行逐行地执行,这个动作是由Qrun函数执行的。Qrun函数从源程序的第一行开始执行,把取得的这一行数据先进行预处理,去掉注释(以“;”开始的说明)和标号(位于行首并以“;”开始的程序),然后再按照汇编语言的固定格式取得指令名称和操作数,每一个指令名称都有一个与之相对应的执行函数,这些函数负责完成对应指令的功能,例如:MOV函数和MOV指令是对应的,此函数负责把第二个参数的值放到第一个参数里面。程序就像这样一行一行执行下去。
值得我们注意的还有指针的实现以及中断的实现问题。在虚拟的编译系统中,指针和真实的指针不同。我们用行号代替了内存地址。普通情况下,程序每执行一行,指针就加一(不论单指令语句、双指令语句还是多指令语句均同样处理),跳到下一行继续执行。但若遇到跳转指令或类跳转指令的时候就不一样了。首先要根据跳转的目的标号到在编译阶段建立的数据库中查找相应的行号,然后将获得的行号赋值给指针IP,那么此时程序就跳到对应的行继续执行。对于中断的处理,我们借助了虚拟的8259A。具体实现过程将在中断实现模块中详细介绍。
2.2.2 虚拟实验操作台
虚拟实验操作台是硬件设备的一个缩影。它包含了8031的四个并行I/O端口即P0口、P1口、P2口、P3口;以及中断控制器8259A的IR0~IR7八条中断请求输入线;还有8255的三个8位I/O数据口PA口、PB口、PC口;最后还有LED、显示器、开关三种外部设备(示波器是以单独的界面形式存在的,其设计方法将单独介绍)。它可以划分为三个部分:显示部分、外设部分(LED、开关)、接线部分(一个接口实现,用于将外设和实验中用到的芯片连接起来即建立通信)。
对于显示部分,我们模拟了八段显示器。并且在程序中我们给它分配了一个中断号10H,功能号0(AH=0)表示对显示屏的操作(例如,AL=1表示清屏)。功能号1(AH=1)表示将AL中的数据写入显示器。它的实现可以利用一个RichTextBox来模拟,给显示部分划分一个线程,让该线程一直处于不停的检测状态isMonitorInterrupt,若为真表示显示器有中断,然后马上去寻找功能号并实现相应的功能。在执行函数INT中,有一个对应于显示器的分支,当参数为10H(也就是内中断号为10H)时就将状态isMonitorInterrupt置为真,从而,只要在程序中一有显示器中断则马上就可以在模拟的显示器中体现出来。
对于外设部分,我们模拟了LED和开关。LED我们用Label来实现,通过backcolor的变换来实现LED的亮与灭。开关我们用TrackBar来实现,通过变形可以得到一个很形象的开关,将滑块滑到最上面表示开,滑到最下面表示关。在LED相关的程序中,我们还定义了一个线程RunLED,该线程将一直处于运行状态,不停地将缓冲中的数据取出,并按位对LED进行操作。开关的程序实现更简单,当我们改变开关的一个状态之后,马上将SwitchStatus传递给接线部分对应的程序模块。实际上,开关只负责状态的改变。
对于接线部分,实际上是一个复杂的模块。首先要解决表面上接线的问题。在虚拟实验操作台上,每一个需要接线的地方都设定了一个接线孔。实际上是用图片模拟的,没接线的时候是一种图片,处于接线状态的时候又是另一种图片。同时引用了DrawLine函数来绘制导线。其次要考虑到它深层次上的意义。从另外一个角度来说,虚拟实验操作台起到了“桥”的作用。它负责接收外设(开关)送过来的数据,并根据建立的“输入桥”将数据传递给相应的芯片,还负责接收芯片传过来的数据并根据建立的“输出桥”将数据传递给外设(主要是LED)。而各种桥的建立也是不容忽视的。所有接线孔都对应一个序号,芯片对应接线孔的序号固定在一个范围内,外设对应接线孔的序号对应在一个范围内(开关与LED也要区分开)。这样做能够很容易地通过序号获得该接线孔的类型。当连续点击两个接线孔时,程序就会根据接线孔的序号得出接线孔的类型,若是输入的接线孔和芯片孔,则加入输入桥;若是输出的接线孔和芯片孔,则加入输出桥;若两个都是芯片接线孔,则加入芯片桥。这样就建立了桥。
图3 虚拟实验操作台(正在运行中)
2.2.3 中断模块(8259A)
真正的8259A在编程的时候要将中断服务子程序入口地址放入中断向量表;在虚拟系统中,地址均由行号来代替,当用汇编指令获得一个子程序的地址时,实际上是取得了它的行号。当中断到来的时候实际上执行的也正是该行号对应的程序,所以其功能与真实的是一样的。为了能够更真实地模拟硬件,我们定义了状态机来负责管理8259A的工作。状态机的功能是:识别写入端口的是否是初始化数据,并可以根据写入的内容来确定下一步应该写入的内容,即从一个状态到另一个状态的转化;同时还记录8259A的一些工作状态,比如:优先级方式、中断结束方式等等。
对于中断嵌套,我们使用堆栈进行处理。首先定义一个堆栈stack(实际上是由一个数组构成的存储区)负责在执行中断前将IP入栈,即行号入栈。每当程序执行到RETI指令的时候就从stack中取出一个行号放入IP(可称为出栈)。这样就保证了中断程序结束后顺利回到断点处继续执行,这时的断点可以在主程序中,也可以在某个中断程序中(即中断嵌套)。
2.2.4 I/O模块(8255)
8255有三个I/O数据口,即PA口、PB口、PC口。在虚拟实验操作台上有相应的A口、B口、C口的接线孔,共24个。模拟的8255由相应的执行函数和寄存器组成。由于各口工作方式的不同以及编程的方便问题,除了模拟控制寄存器外,还单独模拟了A、B、C三口的输入、输出状态,以及A、B口的工作状态。8255的执行函数只有在OUT、IN两种指令中执行。当在执行OUT指令或者IN指令时端口地址就属于8255,就会去执行8255模块的执行函数。8255的执行函数只负责对其对应的寄存器进行操作,例如:当执行OUT指令的时候模块的执行函数就法则把AL中的值放到相应的端口寄存器中,当执行IN指令时执行函数就负责把对应端口寄存器的值放到AL中。
2.2.5 存储器
存储器是用来存储数据和程序代码的,我们所创建的虚拟平台同样也需要存储器来存储一些数据和代码。具体的实现方法是使用一个一维数组,模拟虚拟内存。数组的下标则代表内存地址,也就是说下标与地址一一对应。并且我们专门设计了一个窗口负责显示和修改内存。比如,在运行一个程序的时候可以根据需要通过此窗口将数据预先输入内存,或者运行程序的时候将结果放入某个内存单元中,程序运行完毕后可以通过此窗口查看结果。
2.2.6 示波器
示波器是一种外部设备。任何数据在送入示波器之前都必须符合一个前提,就是要为模拟量。而在单片机实验中我们处理的数据对象均为数字量,所以要将数据进行D/A转换。所以我们在仿真系统内部模拟了0832(数模转换芯片)。而在具体的实现过程中,我们为示波器建立了一个线程(thread)runshiboqi,用threadstatus 值(True和Flase)控制线程的运行。shiboqiClass.status=True时,线程运行,启动draw函数绘制图形;反之则不运行。而在执行函数启动线程之前,首先是要对D/A转换器中的数据进行处理,因为在写入汇编程序之后,相应的数据会分别存入对应的寄存器中;所以D/A转换器的数据处理在程序写入时已经完成了。D/A转换器实际上所完成的功能是对各存储器中数据的调用以及相关数学函数的引用。
图4 示波器(正在运行中)
3 构建仿真平台使用的一些技术
该仿真平台是构建在VB.NET工作平台之上的。所以使用一些特殊技术能够使得仿真平台的运行结果与硬件实验结果更为相似。
3.1 汇编程序的编译
对于汇编语言的执行和接口芯片的工作,传统的思想是借助于MASM之类的工具将汇编语言编译成二进制代码,这些二进制代码在CPU的控制下去完成相应的功能。对于一个模拟硬件的软件来说,做这样的事情太过于复杂。因此我们用函数来模拟汇编指令,即每一个汇编指令对应一个函数,我们叫它执行函数,如:MOV函数完成MOV指令的功能,实现
Public Sub MOV(ByVal REF1 As String,ByVal REF2 As String)
Dim temp As Integer
temp=ReadData(REF2)
Call WriteData(REF1,temp)
End Sub
ReadData函数为自定义的通用函数,负责取出参数表示的值;WriteData函数也为通用函数,负责将立即数temp写入存储区REF1。
3.2 DirectX技术
DirectX是Microsoft公司提供的一个对硬件直接进行操作的接口,早期的Windows不提供对硬件直接操作的功能,开发了这个接口之后,可以对显示器、鼠标、键盘、声卡、显卡等硬件设备直接进行操作。在仿真平台启动的时候可以利用DirectX改变显示器的分辨率,使可视化操作界面(虚拟实验操作台)的布局具有一致性。其简单实现
Public DirectX As New DirectX7
Public DDraw As DirectDraw7
DDraw=DirectX.DirectDataCreate("")
Call DDraw.SetDisplayMode (800,600,32,0,CONST_DDSDMFLAGS.DDSDM_DEFAULT)
3.3 通信桥
通信桥包括输入桥、输出桥和芯片桥。通信桥决定了芯片和外设间的通信。输入桥负责接收外设(主要是开关)送过来的数据,并将数据传递给对应的芯片;输出桥负责接收芯片送过来的数据,并将数据传递给对应的外设(主要是LED);芯片桥负责在芯片间传递数据。现给出通信桥的基本数据结构:
Public Structure BridgeData
Public chipvalue As Integer ‘芯片接线孔的序号
Public devicevalue As Integer ‘外设接线孔的序号
Public pchip As Integer ‘芯片接线孔的位置,便于连线
Public pdevice As Integer ‘外设接线孔的位置
当在接线板上接线的时候,点击某个接线孔后,根据孔的编号确定它的类型(芯片、输出外设、输入外设),然后根据两个接线孔的类型加入不同的通信桥。例如,若是芯片和输入设备,则加入输入桥。
3.4 多线程以及线程同步技术 由于每一个芯片对应一个线程,就有可能出现多个线程同时对一个数据处理的情况,例如:通信桥模块和8255模块之间就有可能出现这样的情况,8255模块通过通信桥模块提供的接口数据的同时,通信桥模块把从外设接收到的数据写入该接口。可以通过设置一个互斥变量来保证线程对临界资源的互斥访问,或者通过VB.NET提供的SyncLock语句来实现同步锁。
3.5 缓冲技术
由于每个线程(同优先级)运行的时间和次序具有不可预测性,所以在仿真时可能会出现这样额问题:线程1传送数据给线程2,线程1一共发出了3个数据,而线程 2只收到了1个。可以用缓冲的思想来解决这个问题。首先建立一个队列,当线程1发送数据的时候不直接发给线程2,而是进队列,线程2取数据的时候直接到队列中去取。这样就保证了数据的完整性,从而屏蔽了线程之间差异性。实现过程
Public Class CommClass
Public Shared data() As Short
Public Shared IP As Integer
Public Shared Sub PUSH(ByVal VALUE As Short)
IP+=1:ReDim Preserve data(IP)
data(IP)=VALUE
End Sub
Public Shared Function POP() As Short
Dim i As Byte
If IP0 Then
POP=data(1)
If IP=2 Then
For i=2 to IP
Data(i-1)=data(i)
Next
End If
IP-=1
ReDim Preserve data(IP)
End If
End Function
End Class
4 总结
该虚拟实验平台能够仿真CPU、内存、可编程中断控制器8259A、可编程外围接口芯片8255A、D/A转换器0832、示波器、LED、开关、显示器等确定硬件参与的实验。它在一定程度上可代替硬件实验装置,并且可以获得与硬件实验相同的实验效果。
参考文献
【1】唐树才,等.Visual Basic.NET 程序设计与应用[M].北京:电子工业大学出版社,2002
【2】王成耀.80x86汇编语言程序设计[M].北京:人民邮电出版社,2002
【3】麦中凡等.VB.NET编程 入门[M].北京:北京航空航天大学出版社,2003
【4】孙燕莲,韩巍,文福安.构建仿真系统关键技术的研究[J]. 实验技术与管理,2005,22(7):68-71