基于Keil μVision模拟器构建软件调试测试环境
2012-04-17吴瑾,郭华
吴 瑾,郭 华
(北京控制工程研究所,北京 100190)
本文研究了一种基于ARM公司Keil μVision模拟器[1]的单片机软件调试测试环境的制作方法.用户需开发的部分为符合μVision编程接口约定的WIN32动态链接库(后文简称μVision动态链接库扩展).这是一种纯软件方式的仿真模拟环境,无需任何单片机硬件,具有可靠性强、灵活性强、可定制性强、制作周期短、成本低等优点.
文中首先介绍了μVision模拟器提供的编程接口,之后描述了如何应用这些接口构建一个完整的单片机软件调试测试环境.
1 μVision编程接口
1.1 接口函数
Keil μVision提供给动态链接库扩展使用的接口函数十分全面,主要包括如下几类:
1)系统配置定义类,主要用于定义用户特定的特殊寄存器和虚拟寄存器、设置寄存器内存监视、创建定时时钟等:AgsiDefineSFR、AgsiDefineVTR、AgsiDeclareInterrupt、AgsiSetWatchOnSFR、AgsiSetWatchOnVTR、AgsiSetWatchOnMemory、AgsiCreateTimer、AgsiDefineMenuItem.
2)存储器读写类,用于运行过程中获取和写入存储器数据:AgsiWriteSFR、AgsiReadSFR、Agsi-WriteVTR、 AgsiReadVTR、 AgsiWriteMemory、 AgsiReadMemory.
3)模拟器状态获取类,运行过程中获取模拟器状态,如当前模拟器时间、中断状态等:AgsiGet-States、AgsiGetProgramCounter、AgsiIsInInterrupt、Agsi-IsSleeping、AgsiGetExternalClockRate、AgsiGetInternal-ClockRate、AgsiGetClockFactor、AgsiGetLastMemory-Address.
4)模拟器控制类,用于对模拟器进行控制操作:AgsiSetTimer、AgsiSetSFRReadValue、AgsiStopSimulator、AgsiTriggerReset、AgsiUpdateWindows、Agsi-HandleFocus、AgsiMessage、AgsiExecuteCommand.
具体这些接口函数的参数、功能、返回值可参考ARM公司提供的接口编程开发手册[2].
Keil μVision对用户开发的μVision动态链接库扩展有如下要求:
1)引用 Agsi.h/Agsi.cpp 文件;
2)必须为WIN32动态链接库形式[3](推荐使用Microsoft Visual C++6.0(后文简称VC)开发);
3)必须具备μVision指定的入口函数,其名称和形式必须为:
extern“C”DWORD AGSIEXPORT AgsiEntry(DWORD nCode,void*vp).
1.2 动态链接库扩展入口函数
Keil μVision要求动态链接库扩展必须具备AgsiEntry入口函数,它是μVision模拟器与动态链接库扩展实现数据交互的主要途径,μVision模拟器在运行的各个阶段,主动调用AgsiEntry函数,传递消息和消息数据,使动态链接库扩展正确运行.
(1)函数参数
nCode 消息标志,所有可能的值参照表1;
vp 消息参数指针,依nCode不同而不同.
(2)函数返回值
函数调用成功则返回1,否则返回0.
(3)函数描述
AgsiEntry是Keil μVision动态链接库扩展的唯一输入函数.在μVision模拟器启动时,将自动调用此函数.参数nCode的值如表1所示.
表1 AgsiEntry函数消息表Tab.1 AgsiEntry function message
一般来说,需要进行处理和响应的消息是AGSI_INIT、AGSI_RESET、AGSI_TERMINATE,在模拟器初始化、模拟器复位和模拟器结束运行时动态链接库扩展收到这些消息.
当nCode为AGSI_INIT时,动态链接库扩展应进行以下工作:
1)当需要使用自定义的寄存器时,使用AgsiDefineSTR()定义寄存器;
2)当需要使用虚拟寄存器时,使用AgsiDefineVTR()定义虚拟寄存器(如内部串口缓冲区输入寄存器(SIN)、内部串口缓冲区输出寄存器(SOUT)等);
3)当测试平台需要使用操作界面(通常为对话框形式)时,使用AgsiDefineMenuItem()定义弹出对话框菜单入口(定义的菜单入口将出现在μVision环境中调试状态下的Peripherals菜单中);
4)当需要监视单片机寄存器或内存(通常使用此手段采集单片机软件运行过程中的数据)时,使用AgsiSetWatchOnSFR()或AgsiSetWatchOnMemory()定义监视点;
5)当需要使用模拟器同步定时时钟时,使用AgsiCreateTimer()创建时钟.
当nCode为AGSI_RESET时,一般将动态链接库扩展中定义的变量、数组等进行复位,以保证每次复位后,调试测试环境初始状态的一致性.在这个消息的处理中也可以启动模拟器定时时钟,设置时钟事件的处理.
当nCode为AGSI_TERMINATE时,说明模拟器运行已经结束,需将动态链接库扩展中使用的资源进行释放,包括申请的内存、创建的显示界面等.
1.3 回调函数
在开发μVision动态链接库扩展中,必须明确回调函数的概念.本文中回调函数即是指在某种特定事件发生时,自动被模拟器调用的函数.它也是动态链接库扩展的主要功能实现载体,分为3种类型.
(1)寄存器监视回调函数
它用于监视单片机软件的寄存器状态,一旦模拟器对所监视寄存器进行操作,相应的回调函数就会被自动调用.例如模拟外围设备与单片机软件通过内部串口进行通信,则需要监视内部串口缓冲区输出寄存器(SOUT),并在回调函数中对SOUT进行读取操作,并使用内部串口缓冲区输入寄存器(SIN)将应答的数据返回给单片机软件.
(2)内存监视回调函数
它用于监视单片机软件对内存及I/O的操作处理,一旦模拟器对所监视的内存地址进行访问,相应的回调函数就会被自动调用.常用于对单片机软件的数据采集仿真控制,由于单片机系统寻址方式为内存及I/O统一编址,故此种回调函数可模拟出内存及I/O端口的输入输出数据.例如通过监视地址的读写,可以简单明确地获知单片机软件对外围端口的操作时序,只要在回调函数中按实际外围设备的情况将数据反馈给单片机软件即构成了对这些外围设备的模拟.同时还可在回调函数中记录两者间的数据交换情况,供事后分析.
(3)定时时钟触发回调函数
它用于建立对模拟器系统的定时控制,一旦所设置好的定时器触发,相应的定时回调函数就会被自动调用.它常用于产生对单片机软件的外部驱动输入,也可以说是仿真调试环境实现对单片机软件的自动控制的一种方式.
另外,为了方便用户使用,μVision模拟器对内存和寄存器的监视触发时机,是在读之前、写之后触发的.即读取操作的读取之前、写入操作的写入之后触发.如图1所示,单片机软件在读取0x100内存前,模拟器调用回调函数OnMem100Read,函数中对内存0x100进行赋值为0x90,单片机软件实际读取的值就是0x90了,进行运算后再次写入内存0x100,这时是写入后模拟器调用OnMem100Write,此时读取内存0x100的值,即为运算后的结果0x92.
图1 μVision模拟器监视的回调时机Fig.1 μVision simulator watch-callback timing
2 μVision动态链接库扩展的开发
2.1 开发过程概述
一般来说,μVision动态链接库扩展开发过程大体可分为3个阶段:
1)开发者应了解单片机软件的工作原理,熟悉软件的输入、输出数据端口及操作方式.
2)对μVision动态链接库扩展进行设计、编码.
3)结合单片机软件和μVision动态链接库扩展,构成调试运行环境,对二者进行联合调试、测试.
对于第一个阶段,它是动态链接库扩展开发的基础工作,每个单片机软件的实际情况各不相同,需要开发人员在实际的应用中依具体情况而定.第二个阶段中包含几个固定的步骤,是开发μVision动态链接库扩展的主要工作阶段.第三个阶段的联合调试,需要开发人员的经验和技巧,要对单片机软件和动态链接库扩展相互验证、不断完善和修改.
2.2 μVision动态链接库扩展的设计
μVision动态链接库扩展的设计步骤如图2所示.
构建μVision动态链接库扩展,推荐使用Microsoft Visual C++6.0(后文简称 VC)按基于MFC[4]的标准库制作.工程建立后,需要制作扩展库入口AgsiEntry函数,函数中主要处理AGSI_INIT消息,要对用户使用的寄存器(SFR)[5]、虚拟寄存器(VTR)和界面显示菜单项入口进行定义.同时,还要根据单片机软件端口操作情况,对寄存器、内存地址进行监视点设置,对动态链接库扩展中需要使用的定时时钟进行创建.
入口函数AgsiEntry制作后,接下来需要针对寄存器内存监视、定时时钟开发回调函数.监视回调函数中,如果是读监视,一般将准备好的数据填入所监视存储器,供单片机软件获取;如果是写监视,一般将单片机软件输出的数据读出并进行记录,在一些情况下还需要给单片机软件反馈数据.定时时钟回调函数中,一种情况是开发人员要主动给单片机软件送入某种激励,例如可以实现定时向单片机软件发送串口通信数据,定时触发外部中断等;另外也可以是进行某种延时操作,例如单片机软件输出通信数据后,延时100ms再给出通信应答.
图2 μVision动态链接库扩展设计步骤Fig.2 Design steps for μVision dymamic link library(DLL)extension
在大多数情况下,需要制作针对单片机软件的数据显示和操作控制界面,通常为非模式对话框形式.它并不是必须的,但有了它会使单片机软件运行状态和数据更直观的显示,对软件调试的操作控制也更加便捷,建议使用.
建立界面过程主要是制作对话框的建立、刷新和关闭函数,它们是AGSI_INIT消息中定义界面显示菜单项入口函数的参数,如图3所示.
图3 对话框函数定义代码范例Fig.3 The example of dialog function definition
在模拟器运行过程中,点击μVision界面菜单Peripherals中自定义的菜单项时,对话框建立函数被调用.在模拟器运行状态改变,如开始运行、暂停运行时,对话框刷新函数被调用.退出模拟器运行状态时,μVision会调用对话框关闭函数,这个函数中应该做好对话框资源的释放处理.
2.3 单片机软件和μVision动态链接库扩展的调试
上述μVision动态链接库扩展的开发工作完成后,开始对单片机软件和μVision动态链接库扩展进行联合调试.把VC生成的动态链接库拷贝到Keil μVision安装目录的 C51Bin下(例如 Keil μVision安装在C:Keil下,则将动态链接库拷贝到C:KeilC51Bin目录下).
启动μVision,打开单片机软件工程,选择工程属性“Options For Target-Debug”,在弹出对话框中的Dialog Dll的参数项中,添加参数-dDLLNAME(DLLNAME为动态链接库扩展的名称,不含扩展名).例如图4,加载了ALTUDLL动态链接库.
图4 μVision工程属性参数设置Fig.4 Setting μVision project property parameters
加载动态链接库之后,如果制作了平台数据显示和操作控制界面,选择调试状态下Peripherals菜单中自定义菜单入口显示界面.
之后开始运行μVision模拟器,对单片机软件和动态链接库扩展进行共同验证.由于单片机软件的正确性未知,故当出现仿真运行结果与预期不符时,应从单片机软件和动态链接库扩展两方面加以考虑,充分利用μVision和VC提供的调试手段,完善单片机软件仿真调试运行环境.
3 结束语
综上所述,开发一个使用μVision模拟器的单片机软件调试测试环境并不复杂,可以极大提高单片机软件的调试测试效率.目前,ARM公司Keil μVision的产品网站上还提供了不少μVision模拟器的扩展芯片仿真,如AD、CAN等,实际上这些仿真芯片也是使用μVision动态链接库扩展的方式开发的,开发人员熟悉μVision模拟器接口后,完全可以根据自己的需要开发类似的通用芯片仿真,以提高调试运行环境的可重用性.
[1] ARM.Getting started with μVision2 and the C51 microcontroller development tools user’s guide[M].Cambridge:ARM,2001
[2] ARM.Implementing μVision DLL’s for advanced generic simulator interface[M].Cambridge:ARM,2010
[3] 王阔厅,孙俊忠.基于MFC的动态链接库的创建和调用方法研究[J].电脑学习,2009(5):32-35 Wang K T,Sun J Z.Study on creation and calling method of DLL based on MFC[J].Computer Study,2009(5):32-35
[4] 侯俊杰.深入浅出MFC[M].第二版.武汉:华中科技大学出版社,2001 Hou J J.Dissecting MFC[M].2nd ed.Wuhan:Huazhong University of Science and Technology Press,2001
[5] Intel.MCS-51 microcontroller family user’s manual[M].Santa Clara:Intel,1994