
本发明涉及一种软件架构设计方法,具体涉及一种硬件底层快速配置的上位机软件架构设计方法。
背景技术:
在科技飞速发展的今天,嵌入式设备无处不在,如无人机飞行控制器、ct机和汽车发动机ecu单元等。在嵌入式设备的计算核心单元(如单片机、soc芯片等)中运行的软件就是下位机软件。通常情况下,下位机软件在开发、调试以及工作过程中,需要实时接收外部指令,然后将自身采集、计算和分析得到的结果数据发送到外部设备(pc机)进行进一步的分析和显示,而在外部设备中运行的软件就是上位机软件。上位机和下位机的关系如附图1所示。
如附图1所示,上位机和下位机通过通信链路(如uart总线、网络总线、can总线或1553b总线)进行数据的交换。下位机工作环境、通信速度以及硬件配置的不同,常常带来通信链路的不同。如一些民用场景常常使用uart总线和网络总线,汽车等常常使用工业现场总线can总线,而飞机等常常使用1553b航空总线。
当前,在实际应用时,需要根据不同的要求、不同的硬件通信接口对上位机软件进行开发和配置,会耗费大量的时间。
技术实现要素:
本发明的目的之一在于提出一种硬件底层快速配置的上位机软件架构设计方法,可根据不同的硬件通信接口对上位机软件进行快速配置,从而扩展上位机软件的使用范围,并显著减少嵌入式设备的开发时间。
本发明是这样实现的:
一种硬件底层快速配置的上位机软件架构设计方法,包括:
(一)配置文件设计;
(二)通用接口设计;
(三)具体的硬件底层驱动设计。
更进一步的方案是:
所述配置文件设计,是将硬件的种类以及参数信息存储在配置文件中,当上位机软件开始运行时,首先从配置文件中读取硬件配置信息,根据读取的配置信息,选择特定的硬件接口,完成硬件初始化,实现对该硬件接口的支持。
更进一步的方案是:
所述通用接口设计,是在硬件初始化中,分配一个接收数据线程,周期性的接收下位机发送过来的数据。如果收到数据,则向数据打包解析层抛出事件,数据打包解析层响应事件,完成数据的检验和解析。
更进一步的方案是:
所述具体的硬件底层驱动设计,包括:
1)利用通用接口,定义底层硬件通信类;
2)定义底层硬件通信类中需要用到的变量;
3)设计通用接口的实现,包括:
31)设计硬件初始化函数
初始化函数根据配置文件中提供的通信端口配置信息,完成通信端口的初始化配置,并返回配置结果;
32)设计清除缓冲区函数
每次进行数据通信前,调用清除缓冲区函数,将数据缓冲区中存储的数据全部清除,从而避免缓冲区中数据对通信的不良影响。
33)设计数据发送函数
数据发送函数主要调用通信硬件底层函数将数据发送缓冲区中的数据发送出去,
34)设计关闭串口函数
在项目退出时,应调用关闭串口函数,首先关闭数据接收线程以释放cpu资源,然后通过关闭串口通信端口以释放硬件通信接口资源。
4)底层硬件通信类私有函数的实现,包括:
41)底层硬件打开函数
实现数据接收线程的启动,并打开串口。
42)底层硬件数据接收线程
当调用硬件初始化函数完成通信接口的初始化后,即启动了数据接收线程,之后该线程周期性的查询底层硬件通信端口状态,如果有数据,则自动开始接收数据,并向数据打包解析层抛出收到数据事件。
更进一步的方案是:
底层硬件通信类中需要用到的变量包括事件、串口类、数据接收线程、数据接收缓冲区、系统等待信号。
更进一步的方案是:
所述上位机软件分解为业务层、数据打包解析层、数据通信层和硬件驱动层;
其中,业务层与上位机功能直接相关,提供上位机的具体操作指令;数据打包解析层为业务层提供接口函数,将需要发送给下位机的数据进行打包,或者解析收到的下位机自检结果数据;数据通信层为数据打包解析层提供接口函数,并调用硬件驱动层的接口函数,完成数据的收发工作;硬件驱动层由各硬件通信板卡厂家提供接口函数,供数据通信层调用。
更进一步的方案是:
上位机软件在实际工作时,数据双向在业务层、数据打包解析层、数据通信层和硬件驱动层之间流动,上位机发出指令时,数据由上而下从业务层、数据打包解析层、数据通信层到硬件驱动层,上位机接收数据时,数据由下而上从硬件驱动层、数据通信层、数据打包解析层到业务层。
本发明通过硬件底层快速配置的上位机软件架构设计方法,显著扩展了上位机软件的使用范围,可适应不同嵌入式设备(不同的通信方式)的数据通信要求。设计完成后,只需通过修改配置文件中的硬件类型和对应的硬件配置信息,即可实现上位机软件对不同硬件通信板卡的支持。
附图说明
图1上位机和下位机关系示意图;
图2上位机软件分层设计示意图;
图3数据通信类设计示意图;
图4硬件初始化流程示意图;
图5数据发送流程示意图;
图6关闭串口流程示意图;
图7串口数据接收线程流程示意图;
图8数据发送流程示意图。
具体实施方式
下面结合附图对本发明作进一步的说明。
如附图2所示,采用软件分层设计思想,将上位机软件分解为业务层、数据打包解析层、数据通信层和硬件驱动层(硬件驱动层一般由硬件板卡厂家提供,不需在上位机软件中进行设计,故图2中用虚线表示)。其中,业务层与上位机功能直接相关,比如设备自检和功能测试等操作;数据打包解析层为业务层提供接口函数,将需要发送给下位机的数据(如设备自检指令)进行打包,或者解析收到的下位机自检结果数据;数据通信层为数据打包解析层提供接口函数,并调用硬件驱动层的接口函数,完成数据的收发工作;硬件驱动层一般由各硬件通信板卡厂家提供接口函数,供数据通信层调用。图2图中,数据双向在各层之间流动,上位机发出指令时,数据由上而下从业务层、数据打包解析层、数据通信层到硬件驱动层,上位机接收数据时,数据由下而上从硬件驱动层、数据通信层、数据打包解析层到业务层。
上位机软件的分层架构中,各层的功能相对独立,从而可对各层进行独立设计。其中,业务层和数据打包解析层与具体的应用场景有关,本发明不进行深入的探讨。本发明的主要目的在于对数据通信层的优化设计。通过对典型通信板卡功能的分析,无论是uart、can总线还是1553b总线,其典型的功能可抽象概括为:
1、硬件初始化;
2、清空接收缓冲区;
3、数据发送;
4、数据接收;
5、关闭硬件端口
可通过为以上硬件通信板卡的典型功能设计通用的接口函数(如附图3中的通用接口部分),对不同的硬件通信板卡的驱动程序进行封装,并对外提供通用的调用接口,从而实现:
1、业务层和数据打包解析层与硬件板卡驱动的完全隔离,仅与项目的功能有关;
2、通过对不同硬件通信板卡的快速配置,使得上位机软件可支持多种硬件接口。
其中,通用接口部分为共同部分。对于不同的硬件通信板卡,对应设计的数据通信类(如uart板卡对应的uarllib类、研华公司can板卡对应的canadvlib、ixxat公司can板卡对应的canixxatlib)具有相同的接口。
本发明实施例的数据通信层设计实现的具体内容包括:
1、配置文件设计;
2、通用接口设计;
3、具体的硬件底层驱动设计
本实施例中,上位机软件的开发环境为vs2010,开发语言为c#。
1.配置文件的设计和读取
1.1配置文件设计
为了实现对不同硬件接口的快速配置和支持,在项目中设计了配置文件app.config,将硬件的种类以及参数信息存储在该文件中。当上位机软件开始运行时,首先从配置文件中读取硬件配置信息,然后根据读取的配置信息,选择特定的硬件接口,完成硬件初始化,实现对该硬件接口的支持。
<!--can口或com口选择
<!--com口:udptcplib.uartlib;-->
<!--研华can口:udptcplib.canadvlib;-->
<!--ixxatcan口:udptcplib.canixxatlib-->
<addkey="drivceconfig"value="udptcplib.canixxatlib"/>
<!--uart参数:端口,波特率,校验,数据长度,停止位,其中校验位0表示none;1表示odd;2表示even-->
<addkey="uartsetting"value="com1,460800,1,8,1"/>
<!--can口参数:端口号,波特率-->
<addkey="cansetting"value="0,500/>
本文的设计中支持uart串口、研华公司的can板卡和ixxat公司的can板卡。如上所示,通过drivceconfig关键字来选择使用的硬件板卡类型,其中,udptcplib.uartlib表示通用串口,udptcplib.canadvlib表示研华公司的can板卡,udptcplib.canixxatlib表示ixxat公司的can板卡。通过uartsetting关键字来配置串口参数,通过cansetting关键字来配置can口参数。
代码中的配置文件关键字以及内容可根据实际的需求进行扩展和裁剪。
1.2配置文件读取
通过在项目中定义全局变量,来读取并存储配置文件中的配置信息,如下所示。
当项目启动运行时,通过configurationmanager.appsettings()函数获取配置文件中的关键字中存储的信息,并将其赋予drivceconfig、cansetting和uartsetting变量,供之后硬件通信板卡底层初始化使用。
2.通用接口设计
无论是uart、can总线还是1553b总线,其典型的功能应该包括:
1、硬件初始化;
2、清空接收缓冲区;
3、数据发送;
4、数据接收;
5、关闭硬件端口
本设计中,在硬件初始化中分配一个接收数据线程,周期性的接收下位机发送过来的数据(所以,本设计中没有设计数据接收通用接口)。如果收到数据,则向数据打包解析层抛出事件,数据打包解析层响应事件,完成数据的检验和解析。
具体的接口设计如下所示。
其中,init(stringstr)为硬件初始化函数,根据str中的信息完成硬件的初始化,并开启数据接收线程;clearreceive()用来清除数据接收缓冲区;send(list<byte>sendarrays,uintcanid=0x00)为数据发送接口函数,用来发送sendarrays中存储的数据;close()为关闭通信口函数,当关闭上位机软件时,调用该接口函数释放硬件接口。
3、基于通用接口的硬件底层驱动函数设计
上文根据通信总线的特点,设计了通用的接口函数,本节则将通用接口函数在具体的通信硬件环境实现,以便通过通用接口函数,调用具体的通信硬件完成数据通信。
本文以设计uart硬件底层驱动函数为例(其他的通信硬件环境设计过程完全相同),来说明基于通用接口的硬件底层驱动函数的设计方法。
3.1uart通信类的定义
基于第4节设计的通用接口来定义uart通信类:publicclassuartlib:idriver
3.2变量的定义
如下所示,定义了uart通信类中需要用到的变量。其中,devicereceiveevent表示事件,用来向数据打包解析层抛出事件;comdevice表示串口类,用来调用硬件板卡公司提供的最底层硬件驱动代码;receivedatathread表示数据接收线程;receivequeue表示数据接收缓冲区;receiveworkevent为系统等待信号,用来实现数据的周期性读取。
privateeventdevicereceiveddatahandlerdevicereceiveevent=null;//声明一个事件
privatevolatileserialportcomdevice=newserialport();
privatevolatilethreadreceivedatathread=null;//接受数据线程
privatevolatileboolbreceivedata=false;//控制线程receivedatathread接受数据
privatelist<byte>receivequeue=newlist<byte>();//接收数据队列
privateautoreseteventreceiveworkevent=newautoresetevent(true);//默认为有信号
3.3通用接口的实现
3.3.1硬件初始化函数
硬件初始化函数定义为:publicintinit(stringparmstring)。初始化函数定义为public类型,可供外部程序直接调用。其中,parmstring为硬件通信板卡配置信息。
初始化函数根据配置文件中提供的通信端口配置信息,完成通信端口的初始化配置,并返回配置结果,其配置流程如附图4所示。
硬件初始化代码如下所示:
其中,initdevice()为uart通信类的私有函数,通过对通信板卡底层驱动函数的简单封装实现,用以完成通信端口的初始化。
3.3.2清除缓冲区函数
清除缓冲区函数定义为:publicvoidclearreceive()。清除缓冲区函数定义为public类型,可供外部程序直接调用。
本函数相对简单,设计如下所示:
每次进行数据通信前,调用清除缓冲区函数,将数据缓冲区中存储的数据全部清除,从而避免缓冲区中数据对通信的不良影响。
3.3.3数据发送函数
数据发送函数定义为:publicintsend(list<byte>sendarrays,uintcanid=0x00)。数据发送函数定义为public类型,可供外部程序直接调用。其中,sendarrays为数据发送缓冲区,canid为can通信专用参数,用来存储需要发送的can信息的id号。
数据发送函数主要调用通信硬件底层函数将数据发送缓冲区中的数据发送出去,数据发送流程如图5所示。
其实现代码如下:
#region发送数据出去
其中,通用接口中的canid变量表示can总线应用中的发送数据包的id号,在uart通用类中未使用。
3.3.4关闭串口函数
关闭串口函数定义为:publicboolclose()。关闭串口函数定义为public类型,可供外部程序直接调用。
在项目退出时,应调用关闭串口函数,首先关闭数据接收线程以释放cpu资源,然后通过关闭串口通信端口以释放硬件通信接口资源,其实现流程如附图6所示。
其实现代码如下:
#region停止读取串口数据,关闭线程,关闭串口
3.4uart通信类私有函数的实现
3.4.1uart打开函数
本函数实现数据接收线程的启动,并打开串口。通常情况下,硬件通信板卡公司提供的通信示例程序中会有本函数的实现,本文不再进行详细论述。其实现代码如下所示。
#region打开串口,并启动读取串口线程
3.4.2uart数据接收线程
当调用硬件初始化函数完成通信接口的初始化后,即启动了数据接收线程,之后该线程周期性的查询uart通信端口状态,如果有数据,则自动开始接收数据,并向数据打包解析层抛出收到数据事件。uart端口数据接收线程实现流程如图7所示。
其实现代码如下所示。
#region读串口数据线程函数
其中,receiveworkevent.waitone(100)表示如果没有数据,则阻塞当前线程100ms,避免数据接收线程长期占用cpu资源。devicereceiveevent(receivequeue,receivequeue.count)数据打包解析层抛出事件(包括数据以及数据个数)。
4、通用接口的使用
4.1硬件接口定义
如前所述,在全局变量定义中,通过publicstaticidrivercommport=null定义通用通信接口commport。通用通信接口初始化之后,根据配置文件中不同的配置信息,将代表不同的通信端口。
4.2通用硬件接口实例化
应在上位机软件的主窗口启动时,完成硬件接口的初始化操作。
global.commport=(idriver)createinstance(global.drivceconfig);
可通过createinstance()创建通信端口实例,然后将其转化为第4节设计的通用接口,并将drivceconfig中存储的通信板卡硬件信息导入通用接口中。以uart通信接口为例,执行上述操作后,global.commport=udptcplib.uartlib。如果需要选择研华的can板卡进行通信,在配置文件中写入的udptcplib.canadvlib,则通用硬件接口实例化的结果就是global.commport=udptcplib.canadvlib。显然,配置文件中的硬件板卡信息将会直接反映在global.commport通用接口中。
4.3通用硬件接口的使用
4.3.1硬件初始化
可通过如下所示的代码,首先根据从配置文件中获取的global.drivceconfig(存储选择的通信板卡类型)信息获取对应的通信板卡的配置信息,然后调用通用接口global.commport.init(initstr),来实现对响应通信板卡的初始化。其中,global.drivceconfig、global.cansetting和global.uartsetting已在配置文件中读取获得。
在此,需要说明一下,调用global.commport.init(initstr)进行通信硬件初始化时,即完成数据接收线程的启动,之后数据的接收均是自动完成。
4.3.2数据发送
以向下位机发送“7e7ecd0100000000ca01”(其中,“7e7ecd”为帧头,“01”为指令码,“00000000”为附加码,”ca01”为校验和)指令数据帧为例,可通过附图8所示流程实现指令帧的发送。
4.3.3数据缓冲区
在进入数据通信之前,为了避免数据接收缓冲区已有的数据的不良影响,应先调用通用接口global.commport.clearreceive(),将缓冲区数据清除,然后再进行数据的传输。
4.3.4关闭通信端口
在下位机软件退出时,应调用通用接口global.commport.close()关闭数据接收线程(释放cpu资源),然后关闭通信硬件端口(硬件端口资源释放后方可供其他软件使用)。
本文提出了一种基于配置文件和通用硬件接口的上位机软件硬件底层快速配置方法,显著扩展了上位机软件的使用范围,可适应不同嵌入式设备(不同的通信方式)的数据通信要求。其中,配置文件的设计和读取、通用接口设计和通用接口的使用的几个部分,对不同的通信硬件板卡均一致,不必进行重新设计;本实施例以uart通信硬件为例,说明了基于通用硬件接口的底层驱动的设计方法,对于其他的通信硬件板卡,可参考uart实例进行设计。设计完成后,只需通过修改配置文件中的硬件类型和对应的硬件配置信息,即可实现上位机软件对不同硬件通信板卡的支持。
尽管这里参照本发明的解释性实施例对本发明进行了描述,上述实施例仅为本发明较佳的实施方式,本发明的实施方式并不受上述实施例的限制,应该理解,本领域技术人员可以设计出很多其他的修改和实施方式,这些修改和实施方式将落在本申请公开的原则范围和精神之内。