面向接口编程

2024-05-20

面向接口编程(共8篇)

面向接口编程 篇1

0 引 言

在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。每个对象的实现方式或同一个对象的实现方式都可能不一样,要使各个对象之间能相互协作通信及交互,则必须规范定义系统各对象,即从概念层次上进行系统分析设计,从领域专家的角度抽象出具体事物的外在共性的层次上进行接口设计,而不用关心具体的接口实现。

组件对象模型(Component Object Model)是组件对象之间相互接口的规范。所谓接口,其精确定义是“基于对象的一组语义上相关的功能”,实际上是一个纯虚类,真正实现接口的是接口对象[1]。文中就基于三层架构系统的网络教学平台中层与层之间的紧耦合的问题,将数据层对象抽象出接口,逻辑层通过调用接口方法访问数据层。数据层将数据实体和业务实体分离,当数据行为改变时并不影响数据实体类,而业务实体则独立于不同的数据库。这样在创建实例时,相关创建的对象有多种类别,而每种类别又有不同的实现。在以往的设计中,一般会通过抽象工厂模式创建对象实例,而文中考虑到数据库的可移植性,利用配置文件和反射功能来实现数据对象的创建,方便了逻辑层的调用。

1 面向接口编程的网络教学平台的设计

平台采取C#、ASP.NET在Windows、VS.NET、DreamWeaver MX 2004环境下进行开发,利用SQLServer2005和Oracle作为平台数据库,采用基于接口模式的B/S三层架构实现平台功能,整个平台在Windows Server 2003上运行。

1.1 平台功能分析

平台主要分有个人空间、课堂空间、资源发布、资源批量下载、智能答疑、专题研讨及视频点播等模块。整个平台经过层层分解,采用自顶向下扩展的方法,把一个复杂的系统分解为多个功能较单一的功能模块。一方面,各个模块既有相对独立性,可以分别加以设计实现,另一方面,模块之间可以通过信息或调用关系等互相关联,共同构成一个整体。如个人空间里所包含的所在课堂空间、个人资源发布管理、个人疑问管理等,都是通过调用其他模块的方法来实现相应的功能。

1.2 三层架构

在软件体系架构设计中,分层式结构是最常见,也是最重要的一种结构。微软推荐的分层式结构一般分为以下三层,如图1所示。

·数据访问层 也称为是持久层,其功能主要是负责数据库的访问,也就是实现对数据表的Select、Insert、Update和Delete的操作。如果要加入ORM的元素,那么就会包括对象和数据表之间的mapping,以及对象实体的持久化[2]。

·业务逻辑层 是整个系统的核心,它与这个系统的业务(领域)有关。如果涉及到数据库的访问,则调用数据访问层。

·表示层 是系统的UI部分,负责使用者与整个系统的交互。在这一层中,理想的状态是不应包括系统的业务逻辑。表示层中的逻辑代码,仅与界面元素有关。因为这是使用ASP.NET设计的系统,因此包含了许多Web控件和相关逻辑。

1.3 平台总体架构

平台采用图1所示的三层架构,每个层实现应用程序一个方面的逻辑功能,通过层与层之间的交互,形成应用程序体系架构,从而实现适应于企业级应用的,功能复杂的应用程序[3]。

平台共包含9个项目,其中一个Web站点项目,8个类库项目,如图2所示。

2 面向接口编程的网络教学平台的实现

2.1 面向接口编程设计

平台的抽象接口模式主要应用在数据层,系统将数据层对象抽象出接口,方便逻辑层直接调用,如图3所示。

在数据访问层(DAL)中,采用DAL Interface抽象出数据访问逻辑,Model模块包含了数据实体对象,并以DAL Factory作为数据访问层对象的工厂模块。抽象出来的IDAL模块,脱离了与具体数据库的依赖,从而使得整个数据访问层利于数据库迁移。DALFactory模块专门管理DAL对象的创建,便于业务逻辑层访问。SQLServerDAL和OracleDAL模块均实现IDAL模块的接口,其中包含的逻辑就是对数据库的Select、Insert、Update和Delete操作。此外,抽象出来的IDAL模块,除了解除了向下的依赖之外,对于其上的业务逻辑层,同样仅存在弱依赖关系,因为业务逻辑层只需实例化IDAL模块的接口类后,便可以通过接口方法操作数据库。因此只要不涉及到IDAL的接口定义修改,那么业务逻辑层和数据层之间的修改都互不影响,保证两层之间的松散耦合。

2.2 数据访问层实现接口

(1) 数据实体

数据实体主要用于表示数据存储中的持久对象,所有实体类都被放到Model模块中。数据实体可以模拟为一个或多个逻辑表,内容可能来自于一个或者多个数据库中的表中的字段。虽然这些类的属性分别映射了数据表的列,而每一个对象实例也恰恰对应于数据表的每一行,但这些实体类却并不具备对应的数据库访问能力。

(2) 数据业务对象

这里所指的数据业务对象是数据层基本的数据库操作,包括Select、Insert、Update和Delete。由于这些业务逻辑对象,仅具有行为而与数据无关,因此它们均被抽象为一个单独的接口模块IDAL,如图4 中的数据表Resource对应的接口IResourceInfo。

将数据实体与相关的数据库操作分离出来,符合面向对象的精神。首先,它体现了“职责分离”的原则。将数据实体与其行为分开,使得两者之间依赖减弱,当数据行为发生改变时,并不影响Model模块中的数据实体对象,避免了因一个类职责过多、过大,从而导致该类的引用者发生“灾难性”的影响[4]。其次,它体现了“抽象”的精神,或者说是“面向接口编程”的最佳体现。抽象的接口模块IDAL,与具体的数据库访问实现完全隔离。这种与实现无关的设计,保证了系统的可扩展性,同时也保证了数据库的可移植性。在平台中,可以支持SQL Server、Oracle或其他数据库,具体的实现代码分别放在数据层SQLServerDAL或OracleDAL两个不同的模块中即可。

(3) 数据对象创建管理

在平台中,一般针对一个数据表或一类数据表创建一个对象,如针对Resource表的ResourceInfo类创建一个对象。在前面的设计中,这些对象已经被抽象为对应的接口,而其实现则根据类的不同而有所不同。也就是说,创建的对象有多种类别,而每种类别又有不同的实现,这是典型的抽象工厂模式的应用场景。而上面所述的两个问题,也都可以通过抽象工厂模式来解决。考虑到数据库的可移植性,系统最后利用配置文件和反射功能来实现,即可以在项目的web.config文件中,配置好具体的Factory对象的完整的类名。然后利用配置文件和反射功能直接指向具体的数据库对象实现类,例如Platform.SQLServerDAL.IResourceInfo。

平台使用DataAccess类取代了前面创建的工厂类体系,它是一个sealed类,其中创建各种数据对象的方法,均为静态方法。之所以能用这个类达到抽象工厂的目的,是因为配置文件和反射的运用,如下的代码片断所示:

public sealed class DataAccess

{

private static readonly string path = ConfigurationManager.AppSettings[″DAL″];

public static IResourceInfo CreateResourceInfo()

{ //直接指向实现类,返回数据访问实例

return(Platform.IDAL.IResourceInfo)Assembly.

Load(path).CreateInstance(path+″.ResourceInfo ″);

}

}

2.3 业务逻辑层访问接口

业务逻辑层作为接口的访问控制部分,它处于数据访问层与表示层中间,起到了数据交换中承上启下的作用。在业务逻辑层中,有关数据访问层中数据对象的调用,均利用多态原理定义了抽象的接口类型对象,然后利用工厂对象的工厂方法创建具体的数据对象[5]。如 Platform.BLL.ResourceInfo类所示:

public class ResourceInfo

{ //创建具体的数据对象

private readonly IResourceInfo dal = DataAccess.CreateResourceInfo();

public int Add(Platform.Model.ResourceInfo model)

{

return dal.Add(model); //数据对象调用接口方法添加一条记录

}

}

2.4 表示层设计

在业务逻辑层与表示之间采用紧耦合,将核心业务逻辑都放到了一个模块BLL中,如图5所示。在业务逻辑的处理中,如果存在业务操作的多样化,或者是今后可能的变化,均可以利用抽象的原理,或者使用接口,或者使用抽象类,从而脱离对具体业务的依赖。

3 结束语

本文针对传统面向对象系统数据层及逻辑层耦合度高的问题,给出了一种实用的接口编程模式。该模式将系统数据层的接口和实现进一步分离。接口类只定义操作,将数据层访问方法抽象成一个IDAL接口模块,实现类定义属性和操作的具体实现,保证了系统的通用性和数据库的可移植性。这些设计思想及方案都有极强的通用性,可以给后来的设计人员带来启发和帮助。

参考文献

[1]赵明砚,姜秀萍,刘荣梅.一种应用接口编程思想的软件开发平台[J].计算机工程与应用,2001,21:159-161.

[2]陈冠军.ASP.NET2.0企业级项目开发[M].北京:人民邮电出版社,2007:182-186.

[3]Kevin Hoffman,Jeffrey san,Thiru Thangarathinam,et al.Professional.NETFramework[M].Wrox Press,2001.

[4]Kouresh Ardestani,evin Hoffman,Dnald Xie.高效掌握ADO.NET—C#编程篇[M].张哲峰,译.北京:清华大学出版社,2003.

[5]汤涛,等..NET企业级应用程序开发教程[M].北京:清华大学出版社,2005.

面向接口编程 篇2

正文:

子曰:工欲善其事,必先利其器。我们要把显卡作为通用并行处理器来做并行算法处理,就得知道CUDA给我提供了什么样的接口,就得了解CUDA作为通用高性能计算平台上的一十八般武器。(如果你想自己开发驱动,自己写开发库- -那我不得不佩服你很有时间,想必也不会有很多人想自己在去实现一个CUDA吧,呵呵,虽然实现一个也不是太难)。书接上回《CUDA硬件实现分析(二)------规行矩步------GPU的革命》前面我们讲到了一些简单的CUDA的C语言扩展的规则,下面就具体来讲解CUDA给我听哦买提供了多少方便的API函数。在开发CUDA的时候,CDUA也给我们提供了一套完整的API函数。从一开始就在想,怎么把这些枯燥的API函数,或者这CUDA的一十八般武器说得清楚。如果按照中文的翻译的第四章那么讲解,或许晕的人更多,只知道这些是武器,而不知道什么武器是用来干嘛的。从序言看到,十八般武艺所列兵器大同小异,形式和内容却十分丰富。有长器械,短器械;软器械、双器械;有带钩的、带刺的、带尖的、带刀的;有明的、暗的;有攻的、防的;有打的、杀的击的;也有射的、挡的。我们来看CUDA的时候,一看到这么多的API函数,先来给他分一些类,然后才好徐徐道来。

一、API总结:

1.通用的一些接口,前一章节也有提高过:数学函数,时间函数,同步函数,原子操作;

2.控制Device的函数;就是得到设备信息,管理设备信息的函数。设置那块显卡工作,得到那块显卡的性能。这里有分为driver级别的API和runtime级别的API;有人会问什么是driver级别和runtime级别请看图:

这个图我们在前一章已经看到过了。不会不清楚吧~- -!driver级别的API就是提供驱动级别的API,就像写驱动一样的感觉。Runtime级别的API就是封装了一些Driver级别的API,按照一些常规的方法封装了一些底层的API。其实这里就像我们平时生活中一样,最开始对汽车不熟悉的时候,买一辆车回来能开就ok了;能用熟悉Runtime级别的API就行了。慢慢的,感觉汽车自带的音箱不好,自己就开始买一些原始设备回来改装车;慢慢的感觉整车都有点不爽了,然后慢慢的发现想修改发动机,修改外形……就开始改装车了,这样的工作,就得从Driver级别开始做了,玩得更高级一些的就自己设计图纸,自己来用一些零部件来组装车了。这就是Driver API和Runtime API的关系。Runtime的在开始的用起来一般都比较方便,慢慢的发现如果高层(high-level)的Runtime API用起来不方便,就用底层(low-level)的Driver API来自己做改装的车……

3.内存管理,host的内存,device的内存,global的内存,constant第,shared的,这里会分出来一章单独讲Texture(纹理)内存的使用,说实在的Texture也是内存~非要搞那么神秘,没办法,也只好拿出来单讲……PS:内存管理也分为Runtime级别的API接口,和Device级别的API接口。

4.程序运行控制:像Stream,Event,Context, Module, Execution control这样的咱都把归类到运行管理的。这里也得分清楚有Runtime级别的,也有Driver级别的。

5.好了,这里就剩下OpenGL和Direct3D的接口函数了,其实把,这也是为了方便做图来用的,主要是OpenGL和DX都已经成了图形显示方面的标准,so~显卡也得照顾这两个东东了,要不然显卡自己画……hoho要是真自己再来实现OpenGL或者DX,CUDA就真的会头大了,hoho~~还好就借用现有的图形显示的程序来做就行了。牛顿人家都说是站在“牛头人”(巨人)的肩膀上才能看得更远……咱也不要非自己费那么大的经去做一些无用功。想想吃不饱的时候没看到多少人减肥的,倒是现在吃得好了,减肥的人多了……长胖了去健身房减肥,始终感觉有点怪怪的……拿钱去做无用功,(有用功就是减肥)不过现在也有人在做实验,把多余的这些减肥的人的能量转化为电力……扯远了……提一下:他也有两个层次的API,有Runtime层次的,也有Driver层次的。

好了,差不多就这5个部分的API了。下面我们就来个个讲解CUDA的十八般武器。

二、API讲解

记得小时候练过几天棍法,现在好像起式都记不起来啦,哈哈,只记得棍要齐眉,剑齐耳朵,不知道错没,hoho。大学的时候一直想给武术队的张锐学九节鞭,不过一直太忙,除了和他练习过几次散打对抗,看他刀+鞭,双刀,枪,剑,九节鞭练习过几次以外,到大学毕业,也都没机会学九节鞭,~现在也就留着那一根九节鞭在身边。看到它就能想起一些朋友吧:)大学毕业也就各奔东西,都不知道他现在在干嘛……

又走神了……想想前面五个部分,下面一部分一部分的讲解:

1.一些通用的函数:

数学函数,前面章节已经讲了,提一下CUDA 2.0里面添加了一两个新的函数。

时间函数,clock这个自己去查C的函数库;还有CUDA提供的几个时间函数,用起来也没什么难的,只是说一些,CUDA提供的几个时间函数在计算Device上的运行时间的时候,和CPU上的时间函数比起来还不是那么的完美的准确,所以在做时间数据的时候,最好多取几次求个平均。

同步函数前面章节讲到了, __syncthreads()函数,原子操作函数也就和以前的原子操作函数一个道理,也不用多加解释。不过其实我都觉得这__syncthreads()函数都应该归到程序运行控制部分。

2.Device管理

Runtime和Driver层面的API都提供了设备管理的函数,其实两个层面的API提供的功能都差不多,可以在API的说明中查到他的区别。这里需要指出来的是虽然Host主机上的多线程程序是应该可以同时访问同一块显卡(Device)的,毕竟显卡就是按照PCIE标准插在PCI插槽上的标准设备(也有AGP接口的),这就是一个多线程访问硬件的问题了。So~本来是应该可以的。但是由于CUDA的设计原因,这里的host上的当个多线程的线程每个线程都要执行CUDA kernel的时候,就必须执行在多个Device上面。保证每个线程访问的Device不是同一个。多个线程线程A不能分享线程B在Device上创建的资源。

Runtime API:cudaGetDeviceCount() 和 cudaGetDeviceProperties() 提供了遍历硬件设备,得到某个设备性能参数的功能。

int deviceCount;

cudaGetDeviceCount(&deviceCount);

int device;

for (device = 0; device < deviceCount; ++device) {

cudaDeviceProp deviceProp;

cudaGetDeviceProperties(&deviceProp, device);

}

cudaSetDevice() 设置某一块Device作为这个主机host上的某一个运行线程的设备:

cudaSetDevice(device);

这个函数必须要在使用 __global__ 的函数或者Runtime

的其他的API调用之前才能生效。 如果没有调用cudaSetDevice(),device 0 就会被设置为默认的设备,接下里的如果还有cudaSetDevice()函数也不会有效果。

Driver API:

cuDeviceGetCount()和cuDeviceGet() 看名字就知道干嘛的~(英语不好的这应该能看明白吧- -!不要被我这个那 国家四级都没过的人BS你哈~!~)

int deviceCount;

cuDeviceGetCount(&deviceCount);

int device;

for (int device = 0; device < deviceCount; ++device) {

CUdevice cuDevice;

cuDeviceGet(&cuDevice, device);

int major, minor;

cuDeviceComputeCapability(&major, &minor, cuDevice);

}

3.内存管理:

Device上的内存可以被分配成线性的,也可以分配为CUDA的数组形式的。CUDA的内存可以为1维,2维,还有3维(2.0版本)。内存的类型有unsigned8,16或者32位的int,16位(只有driver API可以做到)float,32位的float。这里分配的内存也只能通过kernel里面的函数通过处理纹理的方法来处理。这个地方也是GPU的历史原因了,以前都是处理图像的,所以这里叫纹理。……叫啥都是别人取得名字 - -!在计算机里面不就是内存嘛 - -!

Host的runtime的运行库也提供按照page-locked的内存管理的函数,page-locked的内存要比pageable方式快很多。好的东西往往比较少~page-locked就是很稀少的。如果通过减少分配pageable的内存来分配多的page-locked内存,系统需要的分页内存就少了,这也就会让系统的性能降低了。所以在处理这块的时候要合理。

Runtime API:

使用 cudaMalloc() 或者 cudaMallocPitch() 来分配线性内存,通过cudaFree()释放内存.

下面是分配一个大小为256 float数组的方法:

float* devPtr;

cudaMalloc((void**)&devPtr, 256 * sizeof(float));

在使用2D数组的时候最好用cudaMallocPitch()来分配,在guide的第五章在讲到内存之间的调度的时候,就会看到他的好处,

下面是一个分配一个大小为width×height 2D float数组的例子:

// host code

float* devPtr;

int pitch;

cudaMallocPitch((void**)&devPtr, &pitch,

width * sizeof(float), height);

myKernel<<<100, 512>>>(devPtr, pitch);

// device code

__global__ void myKernel(float* devPtr, int pitch)

{

for (int r = 0; r < height; ++r) {

float* row = (float*)((char*)devPtr + r * pitch);

for (int c = 0; c < width; ++c) {

float element = row[c];

}

}

}

CUDA 的数组方式,需要用 cudaMallocArray()和cudaFreeArray(). cudaMallocArray()又需要cudaCreateChannelDesc()来管理,这个其实可以在第guide的第五章里面可以看到,我们后面也会详细的介绍内存的调度和管理,和传统的GPU的内存方式不一样的地方.

分配 width×height 32位float的CUDA array例子:

cudaChannelFormatDesc channelDesc =

cudaCreateChannelDesc();

cudaArray* cuArray;

cudaMallocArray(&cuArray, &channelDesc, width, height);

cudaGetSymbolAddress用来在全局中定位一个数组的位置,然后cudaGetSymbolSize()来回忆他分配的时候大小----如果有全局编程或者多线程编程经验的,或者用过几个函数同时处理一个数据的经验,都会为了把数据的独立性弄出来,不能让数据和函数耦合太大,一般都不会让函数直接牵扯上数据,只是在函数处理的时候重新定位数据----这地方有点绕~~

下面是一些例子,内存之间的拷贝,回想一下有几种内存~linear的有两个函数可以分配的,还有CUDA array的内存:

cudaMemcpy2DToArray(cuArray, 0, 0, devPtr, pitch,

width * sizeof(float), height,

cudaMemcpyDeviceToDevice);

The following code sample copies some host memory array to device memory:

float data[256];

int size = sizeof(data);

float* devPtr;

cudaMalloc((void**)&devPtr, size);

cudaMemcpy(devPtr, data, size, cudaMemcpyHostToDevice);

从host上面拷贝内存到device的constant上面:

__constant__ float constData[256];

float data[256];

cudaMemcpyToSymbol(constData, data, sizeof(data));

-#%#$^$^*^&系统int中断:(@$:突然发现已经是早上8点多了

Driver API:

cuMemAllocPitch()被推荐来作为2D的数组分配函数,会在内存对齐方面做一些check~然后保证在处理数据(像cuMemcpy2D()这样的拷贝函数)的时候达到最优的速度。下面就是一个float的width×height的2D的数组,并在循环里面处理的例子: ----(这个地方扩展提两个东东:一个是内存对齐,做程序优化的时候,或者处理网络问题的时候,都会遇到这些问题,内存对齐是一个普遍存在的问题,像SSE这样的编程的时候也是要求内存对齐的,看以后要是有机会以单独讲解内存对齐的问题:)第二个是CUDA的内存访问的问题,就是很多朋友都会在写kernel的时候,搞不明白里面的threadid,block id和传进来的内存的关系,这个地方必须要搞清楚的;内存和线程是CUDA编程必须搞明白的两个概念,不然到时候就会很混乱。其实看看前面的章节,应该能看明白的,不明白就用手画图~要是感觉还是有点不太清楚,也不要担心,接下来的章节会单独把一些难懂的问题更详细的讲解。)

// host code

CUdeviceptr devPtr;

int pitch;

cuMemAllocPitch(&devPtr, &pitch,

width * sizeof(float), height, 4);

cuModuleGetFunction(&cuFunction, cuModule, “myKernel”);

cuFuncSetBlockShape(cuFunction, 512, 1, 1);

cuParamSeti(cuFunction, 0, devPtr);

cuParamSetSize(cuFunction, sizeof(devPtr));

cuLaunchGrid(cuFunction, 100, 1);

// device code

__global__ void myKernel(float* devPtr)

{

for (int r = 0; r < height; ++r) {

float* row = (float*)((char*)devPtr + r * pitch);

for (int c = 0; c < width; ++c) {

float element = row[c];

}

}

}

cuArrayCreate()和cuArrayDestroy()来创建和释放CUDA array类型的数组。下面是一个 width×height 32-bit float类型的CUDA array 分配的例子:

CUDA_ARRAY_DESCRIPTOR desc;

desc.Format = CU_AD_FORMAT_FLOAT;

desc.NumChannels = 1;

desc.Width = width;

desc.Height = height;

CUarray cuArray;

cuArrayCreate(&cuArray, &desc);

这个也是几个内存之间拷贝的例子:

CUDA_MEMCPY2D copyParam;

memset(©Param, 0, sizeof(copyParam));

copyParam.dstMemoryType = CU_MEMORYTYPE_ARRAY;

copyParam.dstArray = cuArray;

copyParam.srcMemoryType = CU_MEMORYTYPE_DEVICE;

copyParam.srcDevice = devPtr;

copyParam.srcPitch = pitch;

copyParam.WidthInBytes = width * sizeof(float);

copyParam.Height = height;

cuMemcpy2D(©Param);

拷贝host上面的内存到device上面:

float data[256];

int size = sizeof(data);

CUdeviceptr devPtr;

cuMemAlloc(&devPtr, size);

cuMemcpyHtoD(devPtr, data, size);

本来想一次把下面的4,5点也讲了~但是如果一下讲出来~lz帖子太长了~~这就不好了~~呵呵,实在的,看第四章的中文翻译的时候,就看了前面几个就不想看了~帖子不能老长老长的又不吸引人- -!hoho~ 所以后面的4,5就在下贴里面发了~~看了这么多也比较累的~好好的休闲一下~你还会发现出了4,5部分,还少了一个部分,那就是CUDA自己的函数,怎么定义,有device的,有global的,这个又有怎么区分啦~且听下回讲解。Hoho

ps:熬夜不好~熬夜很伤身……

有的时候,我们经常会用旧的东东来和新的东东比较,就像C和C++都不知道争论多少年了。其实很多时候我到觉得是没必要的争论,除非你是做C或者C++本身开发的。就像新的硬件不停的变化,以前的概念或者今天就不能用了,有的时候,我们关心架构在这个之上的程序开发就够了,没有太多的必要去问茴香豆的茴有几种写法。有的时候看到论坛里面的争论的时候,很多都不太清楚问题的也参加到争论里面,感觉就是明白事的没有几个,倒是起哄的不少 - -!人家说当局者迷,旁观者清,我看现在很多时候倒是当局者清,旁观者瞎起哄- -!呵呵,好像合乎了现在很多选秀节目的心理哈,起哄的人越多,人家的节目越红,哈哈~----扯远了……

Ps2:在学习API的时候,最好的方法就是多实验,多尝试API的性能,就像练习武术中的器械一样,经常用才会精通的,才能在这个基础上想出新的招式。就像有人在CSDN论坛问,怎么才能弄好ACM比赛,看到像刘汝佳写的《算法艺术与信息学竞赛》的书,都是一些方法,没有代码,就觉得很不解,就像问用什么代码来实现。我的回答就是:阅尽天下A×,心中自然 。多做代码的练习,找一本数据结构的书,对照上面的代码都自己实现一遍,找一个代码练习的书,自己都重新写一遍。要不然就把像MSDN这样的介绍API的资料上的Demo能实现多少都去实现以下,呵呵。其实学习怎么编码都是一些基础工作。最重要的到最后都是算法的实现。其实到最后你会发现写程序就是数组的处理,就是字符串的处理……仅此而已~。所以不要小看了C语言那些书上的小程序例子,不要小看了输出(**)星星这样的例子,实际程序中很多时候都是处理这些星星~hoho~不要一上来就想去写什么游戏,写什么网络软件~先把字符串处理好了,就nb了,真的~你看ACM的题目,topcoder的题目,几乎都是字符串处理- -!哈哈。多实践,多去做一些demo例子。到真正用的时候就会觉得手到擒来,怎么用怎么顺手了。

还是那句话:约尽天下A×,心中自然 。

EJB的编程接口和编程模型分析 篇3

1 EJB

1.1 EJB技术的概念

EJB是J2EE框架的重要组成部分, 在企业计算任务中发挥着关键性作用, 它不是任何网络产品, 而是针对开发使用事务和分布对象所运用的服务器端组件。其工作原理是在JAVA语言编写的基础上运用EJB容器运行组件进行工作的。EJB可谓是企业级的组件, 它的组件结构较为分散, 适应了企业的需求, 是进行企业计算任务的核心技术。EJB容器主要对企业的事务以及安全进行管理服务, 确保企业计算的精确度及保密性。

1.2 EJB编程模型构建分类

EJB编程模型构建分类大体上可分为三大类型, 分别为实体Bean、会话Bean和消息驱动Bean。其中实体Bean下又包括了BMP和CMP。

实体Bean:实体Bean是保证J2EE框架构成的恒久性组件, 它所包含的内容是指储存在容器外的对象或者是企业计算任务应用中的资源, 总而言之, 它代表的是真实存在的对象, 就像计算机中的数据库一样, 是用来储存信息的, 虽然在某种意义上与数据路的功能相似, 但却有着本质性的区别, 两者不可混为一谈。它所包含的BMP的运行与实践要求开发者必须自己编写适合EJB编程模型的编程代码, 它能够实现业务管理, 而CMP则与之相反, 在其运行中开发者不需要亲自编写编程代码, 只需要利用集成开发工具就可以实现代码编写, 保持其程序的持久性, 降低了编程系统开发的难度, 可以说它是BMP的升级, 提高了程序开发的性能。

会话Bean:会话Bean组件包括了有状态会话Bean以及无状态会话Bean, 它们在不同的状况下有不同的应用, 有状态会话Bean能够保存计算机的应用状态, 这是无状态会话Bean所不能达到的, 无状态会话Bean只是运用在普通的执行操作中。

消息驱动Bean:消息驱动Bean是EJB为了适应计算机的需求后增加进来的类型, 它的主要工作是将信息异步传递到其他位置, 它相当于一个处理组件, 用于网络资源之间的异步传递。进行消息驱动Bean的传递与处理工作可以采取两种方式, 一种为队列模型, 另一种为订阅机制。

2 EJB不同编程接口的应用

EJB技术在计算机编程运用中包括了本地接口与远程接口两种状态。

本地接口就是计算机编程操作中的一般情况下的接口, 是用来维系计算机中各个程序的连接点, 而远程接口则不同, 运用远程接口可以实现计算机的远程控制, 进行企业发展中所要应用的远程服务, 它是传统编程技术的创新, 在现代计算机信息技术中得到大力推广, 但这也并不意味着它可以替代本地接口, 它们只是分工不同, 各有所用。

计算机网络运行中如果要使用本地接口, 那么其测试程序就无法调用其本身, 要实现调用, 就要选择远程接口, 它们自身是无法实现接口调用的。

要远程调用EJB, 就要对两个远程对象进行多数的RMI运行循环, 直到其调用成功。实现不同接口之间的调用, 首先, 找到EJB容器的Home接口, 当获得Home接口的实现类后, 其次再建立统一的Home接口stub对象实例, 而后将整体好的对象一并发往客户端, 但此操作不是一次就可以的, 需要多次循环才能实现接口调用。

3 EJB编程模型实例分析

在J2EE框架中最常用EJB编程模型就是MVC模型, 它的工作原理是为了相同数据编制一个或者多个的编程应用程序。在J2EE框架中运用MVC模型能够使编程中的数据层和其表示层相分离, 它是一种具有开发性质的模型, 其主要功能就是对分布式应用系统进行设计与分析, 之所以在企业计算任务中广泛使用是因为它能够实现数据层的分离以及系统中表示的交互。

MVC编程模型能够控制网络中的访问, 及时调整数据中的业务规则, 当系统中的模型有任何异同, 此模型就会向试图发出变化信号, 以此来确保数据与试图之间的一致。另外MVC编程模型具有开发性质, 它能够开发出构成EJB各个组件的源文件代码, 其次, 编程模型根据EJB容器之间的布局可以实现EJB-Jar程序间的部署。

4 EJB的优势分析

EJB在J2EE框架的应用广泛的原因在于它有属于自身的独特优势。它在运行过程中能够降低开发远程分布式应用程序的难度, 提高编程开发人员的工作效率, 此外, 它的运用能够确保各组件运行期间的安全性, 不仅如此, EJB能够将服务器端的各个组件快速的建立起来, 形成一个整体。

5 总结

总而言之, EJB在J2EE框架的应用广泛是由EJB的特性决定的, 传统的Java编程没有互操作能力, 而EJB却具备, 它不仅能够实现组件之间的互操作, 还能够访问计算机操作系统, 在计算机应用中有较为宽广的空间, 简化了计算机编程运行程序, 适应了计算机信息时代对计算机编程模型的要求。

摘要:现如今, 我国进入了快速发展的计算机信息时代, 计算机中的EJB技术是在Java技术的基础上发展起来的, 它是计算机在编程上的技术创新。EJB在现今企业中得到了广泛运用, 因此也引起了众多研究者的兴趣, 本文正是针对EJB的编程接口及编程模型所做的研究, 重点分析了EJB概念、分类构成、不同编程接口之间的调用及EJB编程模型。

关键词:EJB,编程接口,调用分析,编程模型

参考文献

[1]龙湘明, 杨放春.CCM与EJB的比较与评价[J].计算机工程, 2008, 4 (18) :116-117.

[2]刘新强.一种基于框架和组件技术的J2EE开发模型[J].西安铁路职业技术学院学报, 2009, 11 (7) :240-241.

[3]张文.基于EJB中间件技术的研究和企业应用[J].中国科学院研究生院, 2009, (86) :113-115.

面向接口编程 篇4

Freescale公司于2000年前后开始推出HC08系列微控制器,具有速度快、功能强、功耗小、价格低、型号多、Flash编程及内含编程调试接口等优点,在业界得到了广泛的应用[1,2]。目前,HC08有近20个系列一百多种型号的芯片可供用户根据不同的需求进行选择。进行HC08系列MCU的应用设计,要求配有相应的编程调试器及配套软件。国内用户使用的编程调试器及开发环境主要依赖进口,价格昂贵,且编程调试器编程速度慢。苏州大学飞思卡尔单片机实验室从2001年开始开发针对Freescale MCUs 的集成开发环境,经过6年多的努力,已陆续开发出多种针对不同系列芯片的集成开发环境。MT-IDE for HC08 是专门为HC08系列开发的集成开发环境,具有编辑、编译、USB下载和调试的功能。与其配套的编程调试器具有编程速度快、写入稳定和通用性强等特点。作者作为此项目组的主要成员,针对在使用Mon08实现编程调试器时通信速度慢的问题,经过分析研究,发现了Mon08与目标芯片通信速度慢的主要原因,提出了一种提高编程速度的新的通信方法,并成功地运用到实际的编程调试器中。本文将较详细地阐述有关技术。为了使读者对HC08编程调试器有整体了解,下面给出编程调试器的特点及硬件解决方案。

1编程调试器的硬件电路设计

在编程调试器的硬件电路设计方面,主要考虑通用、方便、稳定等因素。为了方便用户使用,编程调试器采用了USB接口与PC机连接;为了适用于不同芯片的频率需要,采用了可控频率芯片产生目标芯片进入监控所需要的频率;为了适应与不同目标芯片的连接,设计了一个10芯控制接口,控制目标MCU进入监控所需要的特定端口电平,从而使编程调试器可以适用于所有HC08系列芯片。根据这些设计思路,编程调试器的硬件电路设计见图1。

其主要由以下模块组成:

(1) 主控芯片及其支撑电路 采用含有USB模块的MC68HC908JB8[3]作为主控芯片。

(2) USB接口电路 提供PC机与编程调试器的通信接口,它们之间的通信符合USB1.1协议;同时,通过PC机的USB端口取得5V工作电压。

(3) 可变频率产生电路 采用一片可编程晶振产生芯片LTC6903,可以在PC端设定目标芯片所需的频率,从而可以解决不同芯片对晶振频率的需求。

(4) 9V高电压产生电路 目标芯片进入监控模式需要在其IRQ引脚加一高电压。本设计利用MAX232的电器特性产生这一电压[4]。

(5) 可控5V电压产生电路 可控地给目标芯片供电,以保持编程调试稳定、可靠。

(6) 和目标芯片连接的Mon08接口电路(10芯) 通过该接口可以连接所有HC08系列目标芯片,不同芯片进入监控状态的特定电平数据存放在PC机的数据库中。

2Mon08通信机理剖析

Mon08是Freescale公司HC08系列芯片的编程调试接口,是固化在芯片内部的一段监控程序[5]。Mon08可以通过单线接收外部命令,利用这些命令可以实现对目标芯片内存的读写及执行内存里的程序。目标芯片在复位后,编程调试器会使其进入监控模式,即芯片运行Mon08程序。在实现编程时,主要用到的监控命令是WRITE和IWRITE。WRITE和IWRITE都可以实现对内存的写入,不过WRITE每次都必须发送要写入的地址,而IWRITE只需要发送要写入的数据,它会接着上次写入的地址继续写入。

在写入之前,编程调试器首先通过Mon08把Flash写入子程序和要写入的一页数据发送到目标芯片的内存,然后执行Flash写入子程序,即可完成对一页数据的编程。如果还有数据要写入,只要替换掉原来的数据后,继续执行Flash写入程序即可。如此反复,便可以实现对整个Flash的编程。采用这种方法,可以实现编程调试器的功能,本编程调试器的第一版就是根据这种思想实现的。在实际的使用过程中,如果程序稍微大些,就会感觉速度很慢,一个10K左右的代码要写一分多钟。后来通过分析Mon08通信时的特点,找出了编程调试器速度慢的主要原因。图2给出了Mon08在执行IWRITE命令的时序图。

说明:1=等待回复延时,2位的延时时间2=取消命令延时,11位的延时时间3=发送下一个字节前的1位延时时间

1位延时的计算方法如下所述:

1位延时是指以某种数据传输率传输1位所需要的时间[2]。

假如用9600bps的速率进行数据传输,则1位延时=1/9600 秒。

如果总线频率2.4576MHz,则一个指令周期的时间是1/(2.4576×106) 秒。则1位延时需要的指令周期数是:

19600÷12.4576×106=2457696=256个指令周期

根据图2可以得出主机通过IWRITE命令向目标芯片的内存写一个字节数据(8个数据位+1个起始位+1个停止位)需要花费的位时间为:

1位时间(发送下一字节前的延时)+10位写命令时间+2位时间(等待回复延时)+10位写命令回复时间+1位时间+10位数据时间+2位时间+10位回复数据时间+11位时间(取消命令延时)+1位时间=58位时间

所以,Mon08的通信效率是很低的,尤其是在进行大批量数据写入时。在实现编程调试器时,需要连续地写目标芯片内存,在这种情况下,不宜使用Mon08所提供的通信算法,其原因如下:

(1) Mon08每收一个字节后,会返回一个回应字节,发送方可以据此判断通信是否正确。这种方式虽然可以保证通信的正确性,但并不能保证编程调试器写入数据的正确性。

(2) Mon08在每收到一个字节后,都要有一定的延时,而且在两次命令之间,也要有一段长时间的延时。

(3) 利用Mon08对一个内存块写入时,每次都要发送写命令字。

(4) Mon08使用固定的通信波特率,用户不能设定。

由以上的分析可以看出,当对一段连续的内存区域写入时,Mon08的效率很低。要想提高编程调试器的编程速度,就必须改进Mon08通信算法。

3通信算法改进及高速编程调试器的实现

由于Mon08采用单线串行方式通信,因此,可以在硬件不改动的条件下,编写一段模拟串行通信的程序,在进行数据写入时,使用这段自定义的通信子程序来和编程调试器通信,从而提高通信速度。由于这段代码的通信协议是自定义的,因此可以避免使用Mon08时存在的不足,减少数据传输过程中所消耗的不必要时间。

如图3所示,目标芯片进入监控后,会自动执行⑤区中的监控程序,进入等待监控命令的状态。利用监控命令WRITE和IWRITE,将自定义的通信子程序的S19代码发送到图3中的①区,再将Flash写入子程序的S19代码发送到图3中的②区;然后发送RUN命令[6],使目标芯片执行①中的程序。①中的程序首先等待接收要写入的页大小,然后开始接收要写入Flash中的第一页的数据、页首址和页标志字节,并放入③中,接收完成后,①中的程序会自动调用②中的Flash写入子程序将③中的数据写入到页首址所指向的Flash中。一页写入完毕后,自定义通信子程序会根据页标志判断刚写入的是否是最后一页,如果还有要写入的页,则继续处于接收数据状态;如果所有页均已写入完毕,则返回到⑤中的监控程序。

改进后的编程算法只有自定义的通信子程序和Flash写入子程序是通过监控命令写入的,由于这部分的代码比较小(150字节左右),因此这部分用的时间很少。

自定义的通信子程序不需要其他不必要的延时及命令字节,因此发送一个字节的时间为10个位时间。下面给出了部分主要子程序的实现代码。

串行接收一位的汇编程序如下:

为了保证通信及写入的正确性,在写入一页数据之后,计算该页的异或校验和,并发送到主机供校验使用。如果校验正确,不仅说明通信是正常,而且也确保了Flash写入成功。

4性能分析及测试

如果采用Mon08通信方式,对目标芯片MC68HC908GP32(以下简称GP32)进行写入操作,当写入10KB的代码量时,理论上所需要的最少时间(GP32的总线频率为2.4576MHz,通信波特率为9600bps)等于总的数据传输时间及总的Flash编程时间之和。

总的发送字节=Flash写入子程序(约80字节) +10KB的代码(80页)+160B的页首址=10480字节

总的数据传输时间=总的发送字节×58位时间=10480×58×1/9600≈63.3秒

总的Flash编程时间=总页数×写入一页Flash的执行时间=80×6.5us≈0.52秒

总时间=63.3+0.52≈64秒

在实际写入过程中,因为通信过程的连续性问题,数据传输时间要比理论传输时间长,写入10K的Flash时间约为80秒。

由于通信子程序是自定义的,所以通信波特率也不必局限于9600bps或7200bps。通信双方只要协调好,就可以提高通信的波特率,从而加快写入的速度。本编程调试器一般使用19200bps的波特率,并允许用户根据实际需要进行修改。

采用自定义的通信协议而不采用Mon08所提供的通信方式,在相同串行通信波特率的条件下,传送速度可提高5.8倍(58位时间/10位时间)。改进后,在9600bps的通信波特率下,对GP32写入10K的Flash时间约为13秒。如果采用19200bps的通信波特率,则仅需要9秒。

编程调试器在对目标芯片编程前,应先将Flash写入子程序和要写入的一页数据发送到目标芯片的内存,因此,如果目标芯片的RAM太小,那么每次写入的数据数就会受到限制,要分多次写入,这就增加了编程调试器和目标芯片以及编程调试器和PC机之间的通信次数,从而影响编程的速度。为了适应不同RAM大小的芯片,本编程调试器可以由用户设定每次写入的页大小,从而使具有不同大小RAM、Flash的芯片都能达到比较满意的写入速度。

GP32内存有512字节,是比较通用的一款MCU,写入时每次可以写入128字节;而QY4内存仅有128字节,相对较小,每次写入的数据为16字节。实验中选取了这两款比较典型的芯片,表1和表2分别给出了GP32和QY4采用不同通信程序时所需编程时间的实验数据。

综合表1、表2可以看出,使用自定义的通信算法可以明显地提高编程调试器的编程速度。对于机器码在2K左右的程序,若自定义通信波特率与Mon08使用的波特率一致(9600bps),则写入时间从20秒左右降到5秒左右。若把波特率提高到19200bps,则可降到2秒左右,方便了用户修改、调试程序。对于更大的程序,速度提高更明显。

5结束语

编程调试器的编程速度是衡量编程调试器好坏的重要指标之一。在项目开发过程中,需要不断地修改程序,调试程序,程序的下载就会频繁发生,写入的速度也就显得尤为重要。本文给出的编程调试器,在硬件和软件方面采用了多项技术措施,达到了通用、方便、稳定的目的。本文介绍的编程调试器,以及本文并未介绍的PC机集成开发环境,作为一个整体开发套件,已在国内众多高校及研发单位使用,其稳定的性能、快捷的编程调试,受到了用户的好评。文中重点给出的Mon08通信改进算法,可以供开发类似工具或嵌入式应用产品时借鉴。

参考文献

[1]王宜怀.MC68HC908GP32单片机编程器的设计与实现.计算机工程,2004.

[2]王宜怀,刘晓升.嵌入式应用技术基础教程.清华大学出版社,2005.

[3]MC68HC908JB8 Technical Data.Motorola Inc.2002.

[4]戴晓静,王宜怀.Motorola新型单片机MC68HC908JL3编程器的设计与实现.计算机工程与应用,2004.

[5]宫辉,邵贝贝.MC68HC908LJ12监控ROM中的子程序调用.单片机与嵌入式系统应用,2002.

面向服务架构技术的接口设计 篇5

特别是, 在服务逻辑之前先创建服务契约会带来下列好处:

· 能够将服务设计成能精确表达服务候选的语境和功能。

· 服务的操作名称使用约定, 将使端点定义标准化。

· 可将操作粒度建模成提供一致性和可预知的接口设计。

· 要求底层应用遵照服务设计来表示。

· 业务分析师能进行业务服务的设计。

本文以Student服务的设计步骤, 初步的要求是能够执行一个查询以获得他的学籍基本信息和宿舍信息, 通过赋予以下两个操作候选来表达这两个功能:GetStudentDetailInfo。

GetStudentDormInfo

1 第一步:审查现存服务并定义实体Schema

设计新服务的第一步是确认它是否是必须的, 如果其他服务存在, 它们也许已经提供了在操作候选中识别出的部分或者全部功能;或者它们已经建立了适当的语境, 通过它能够实现这些新操作。

SOAP消息在其封装的Body部分携带了有效负载数据。需要对该数据进行组织和分类, 我们依靠XSD schema可以完成这一操作。实际上一个单独的schema可以嵌入到type结构中, 在那里可以定义每个表示SOAP消息体的数据元素。

对于该Student服务从需要识别的数据着手, 这些类别的数据将履行“学籍基本信息”的处理需求。以定义两个复杂类型结束:一个包含Student服务接收的请求消息所要求的搜索准则, 另一个包括服务返回的查询结果。有意识的命名类型, 使类型与各自的消息相关联。这两个类型组成了新的StudentInfo.xsd.schema文件。如下:

但是我们发现从StudentInfo.xsd.文件中派生出的schema并不包括宿舍信息, 该信息是不在学生信息采集系统中的, 而是在宿舍管理系统中, 于是我们使用不同的targetNamespace来识别截然不同的起源, 命名为StudentDorm的schema。

为了提高可复用性, 并且允许单独维护WSDL的每个schema文件, 将 XSD schema语句 import 用于把两个 schemas的内容放到Student服务 的WSDL文件的 types 结构中。

2 第二步:派生抽象接口

接下来, 我们将分析服务的候选操作, 并且遵照下列步骤来定义初始的服务接口。

(1) 确认每个操作候选是恰当的, 并且通过合理的逻辑封装粒度来保证重用。

(2) 在WSDL文件中创建portTpye域, 并用候选操作的operation结构来展开它。

(3) 列出每个操作的逻辑处理所需要的输入和输出值。这可以通过引用子集part 元素中的XSD Schema 类型, 定义合适的message结构来完成。

决定使用GetStudentDetailInfo () 和GetStudentDormInfo () 两个操作。

随后进入抽象定义的剩余部分, 以下就是定义了message和portTpye结构后的结果:

3 第三步:应用面向服务原则

根据本文前面分析的对于Web Service没有提供的4条面向服务的原则来进行分析:

服务可复用性;

服务自治;

服务无状态;

服务可发现性。

可复用性会在第四步进一步推广, 第四步可将设计扩展到更容易的需求。

由于以实体为中心的服务经常要求组合成服务层, 而且他们依赖应用服务层来执行某些业务逻辑, 所以他们的即时自治通常都定义的良好。

同样, 无状态也是相对可管理的, 以实体为核心的服务一般并不拥有大量的工作流逻辑, 并且那些要通过调用多个应用来执行操作的情况, 首选的是延期状态管理。

可发现性是以实体为核心的服务设计和后续部署需要利用的重要部分, 正如第一步中所述, 我们必须确保设计的服务并不是重复已存在的逻辑, 发现机制会使这个决定更加简单。同样, 我们可以采用documentation元素的元数据细节来使其更容易被发现。

在审查了初始的抽象服务接口后, 可以确定结合少量修改就能够更好地支持基本的面向服务、。特别是, 将元消息增加到WSDL定义中, 这样能更好地描述两个操作及其相关消息的目的与功能。

以下是用额外的元数据文件来补充服务接口的结果:

4 第四步:标准化和简化服务接口及其扩展服务设计

调整抽象服务接口, 特别是将命名约定结合到标准化的操作名称中去, 使用命名标准对内在互操作性提供了本地支持, 这是当代SOA的关键特性。

以下是具有新的标准化名称的两个operation结构:

本步骤包含执行一个推理分析, 在它预定义的功能语境中应该为这个服务提供哪些其他类型的特性。实现新功能一般有两种方法:填加新操作和在现存操作中填加新参数, 虽然后一种方法可能更有效的简化服务接口, 但它可能会违背直觉, 因为太多的参数与操作相关, 可能要求服务请求者了解房屋的众多内容以便有效利用它。所以填加操作是提供与实体相关的明显功能最直接的方式, 以实体为核心的服务的一组经典操作是:

GetSomething

UpdateSomethng

AddSomething

DeletSomething

标准操作在业务服务层构建了一致的互操作水平, 促进了可复用性, 但是不要为了潜在的可复用性使操作过度复杂化。

为此对于本服务我们分析能够增加到Student服务的几类操作如下:

GetDetailInfo

GetDormInfo

UpdateDormInfo

下面示例显示了portType结构如何扩展补充操作的。

5 小结

本文给出了一个具有指导意义的服务的设计步骤与过程, 并在设计过程中应用设计服务的指导原则, 比如使用命名标准, 注重于可扩展性, 识别当前和未来的服务请求者, 使用模块化WSDL, 以及使用原数据说明服务。通过本章的分析, 我们可以看到, 把以实体为核心的业务服务设计为精确表示现存业务的实体, 而保存业务的处理不可知。这其中可能需要一些推理分析, 以便用所需范围的通用操作适当地以配备以实体为核心的业务服务。

参考文献

[1]朱振杰.SOA的关键技术的研究与应用实现[J].电子科技大学硕士文, 2006.

[2]Mark Endrei, Jenny Ang, Ali Arsanjani, et a1.Patterns:Service Oriented Architecture and Web Services.IBMIn.temational Technical Support Organization, April 2004.

[3]Mark colan.Service-Oriented Architecture expands the visionof Web Service http://www-128.ibm.com/developer-works/webservices/library/ws-soaintro.html, 2004.

面向接口编程 篇6

关键词:系统芯片,通用可编程接口,IP核,数据传输

0 引言

在现代数据通信与传输领域, 系统芯片 (System-ona-Chip, So C) 与不同外设间的数据交换越来越频繁, 交换的数据量越来越大, 而且不同外设采用的数据通信协议和接口形式也各不相同。So C与外设间连接的要求越来越高, 主要表现在: (1) 高带宽, 要求通信传输速度越来越高; (2) 通用性, 要求接口具有对多种标准通信协议有一定的广适性; (3) 可再配置, 要求通信系统具有用户根据实际需要进行二次配置的特性。

另一方面, 外设接口往往采用一定的协议或标准, 典型的有UART接口、IIC接口、SPI接口等。芯片实现时, 通常将外设接口的逻辑功能固化在芯片内部, 但由于芯片资源有限, 不可能把所有的协议都集成在片上[1]。为了实现可编程的外设接口, 传统的方法是利用通用输入输出 (General Purpose Input/Output, GPIO) , 通过编程方式设置GPIO寄存器的高/低电平, 从而控制数据的读写和时钟的生成。但是, GPIO模块采用CPU内核直接控制, 模拟外设接口的读写过程会占用大量CPU运行周期, 影响系统中其他任务的实现, 所以一般只用于低速协议或接口的实现[2]。

本文针对So C与外围设备多种接口的连接问题, 设计了一种通用可编程接口IP核, 实现了So C与外围设备接口间的可编程特性, 并以增强型8051内核为基础构建了仿真验证平台, 验证了设计的正确性和有效性。

1 通用可编程接口IP的原理

通用可编程接口的工作方式采用主控方式, 可通过配置CPU实现对外设接口读写波形的编程, 从而完成外设接口的读写。

为了使数据在与外围设备交换过程中不需要CPU的控制, 利用通用可编程接口的高速带宽设计了一套FIFO缓存架构, 其工作机制使得数据以包的形式被提交到端点FIFO, 而不是每次一个字节, 并可设置多级缓存[3,4]。

通用可编程接口IP的本质是一个可编程状态机, 用户通过编写波形描述符控制状态机。通用可编程接口可生成4个用户定义波形描述符, 每个波形描述符最多可定义7个状态, 这7个状态通常情况下用于批量读、批量写、单字读、单字写。

2 通用可编程接口IP核设计

2.1 通用可编程接口IP架构

通用可编程接口模块的内部结构如图1所示, 主要由4个模块组成。

(1) 端点控制模块

端点控制模块 (CONTROL) 产生控制信号 (CTL) 控制外部设备, CTL信号可通过编程组合使用, 实现复杂的逻辑功能;接收外部准备信号 (RDY) 触发事件;接收/发送时钟信号 (IFCLK) ;输出状态信号 (STATE) , 显示状态机目前工作状态。时钟信号可选内部产生或外部输入, 其他控制信号也可设置为高有效或低有效。

(2) 端点缓存模块

端点缓存模块由4个相互重叠的FIFO端点缓存组成, 存储与外设通信过程中接收/发送的数据。其读信号 (RD) 、写信号 (WR) 、输出使能信号 (OE) 及时钟信号 (CLK) 控制数据总线 (FD[15:0]) 的读写, 并输出空信号 (EF) 、满信号 (FF) 。

(3) 波形存储器模块

波形存储器用于存储用户设计的波形描述符。通用可编程接口通过波形描述符控制数据的输入输出, 最多可存储4个波形描述符, 分别为WF0、WF1、WF3、WF4。

(4) 地址生成模块

地址生成器 (ADDR_GEN) 用于输出地址总线 (GPI-FADR[8:0]) , 由控制模块控制。

2.2 波形描述符设计

波形描述符是通用可编程接口的核心, 用于描述数据传输的时序。通用可编程接口可以存储4个波形描述符: (1) 单字读:从外设中读取1字节/字的数据; (2) 单字写:向外设中写入1字节/字的数据; (3) 批量读:从外设中读取一个长数据流; (4) 批量写, 往外设中写入一个长数据流。这些描述符可以动态地配置给任何一个端点FIFO。配置后, 通用可编程接口将依据波形描述符产生相应的控制逻辑和握手信号给外界接口, 满足向FIFO读写数据的需要。

图2为一种批量写模式下的波形描述符状态转移图。批量写状态机共定义了5个状态, 分别是IDLE、State1、State2、State3、State4, 每个状态的意义描述如下。

(1) IDLE:当写事件发生, 转移到State (1) ;

(2) State1:将SRAM写信号和使能信号置为有效, 触发写事件, 转移到State (2) ;

(3) State2:若外部SRAM模型的“满”标志为真 (FF=1) , 则停留在State (2) , 否则转移到State (3) ;

(4) State3:通用可编程接口采样数据线, 将内部端点FIFO数据写入外部SRAM模型, 转移到State (4) ;

(5) State4:如有更多数据需要传输, 则转移到State (2) , 否则转移到步骤 (1) 。

2.3 端点FIFO缓存设计

通用可编程接口内部包含4重端点FIFO缓存, 对内部总线端来说, 只要有1个FIFO为“半满”, 就可以继续发送数据。当前操作的FIFO写“满”时, 自动将其转换到外部接口端, 排队等候读取;并将队列中下一个为“空”的FIFO转移到So C内部总线接口上, 供其继续写数据。图3为FIFO缓存架构的传输原理图, 此时通用可编程接口内部总线接口执行OUT传输, FIFO端点被设置为512 B四重缓存。

3 仿真平台设计

为验证设计的接口IP核, 构建了一个以8051 CPU为内核的So C仿真平台, 利用设计的接口IP核访问外部设备。为了充分利用通用可编程接口地址总线、数据总线及控制信号, 外设采用SRAM芯片的Verilog模型, 并加以改进, 添加握手信号, 使通用可编程接口能读取该信号并控制数据传输。通过设计波形描述符, So C控制接口IP向外部存储器执行写/读操作, 仿真平台对两次的数据进行比较并报告设计的正确性。

该仿真平台在Linux操作系统下开发, 平台系统结构如图4所示。仿真器采用Synopsys公司的VCS仿真器。组成系统的各个模块可以按照需要加入仿真环境中, 仿真结果由环境产生、检查并输出到指定目录结构下的文件中。

仿真平台包括Verilog编写的Testbench、So C模型、外部程序存储器 (EXT PROGRAM ROM) 、SRAM Verilog模型。SRAM包括地址线 (A8~A0) 、数据线 (I/O15~I/O0) 、芯片使能、握手信号E_RDY (“1”表示SRAM未写入数据, “0”代表已写入数据) 、F_RDY (“1”表示SRAM存满数据, “0”代表未满) 。

仿真平台工作时, 由Testbench产生时钟 (CLK) 和通用可编程接口IP时钟 (IFCLK) 。

4 仿真结果分析

通用可编程接口单字节写的仿真结果如图5所示, 其中IFCLK为内部48 MHz时钟, 数据宽度为8 bit。当拉低时, 外部SRAM有效;当有效, 且RDY1 (F_RDY) 为低时, 数据 (5A) 被放入数据总线, 并经数据总线写入外部SRAM。状态总线STATE (PE[2:0]) 显示通用可编程接口引擎在每一操作期间循环经过的状态。

通用可编程接口单字读模式与单字写模式类似, 仿真结果如图6所示。

图7为通用可编程接口批量写传输的仿真结果, 数据宽度为16 bit。当被拉低, 且F_RDY为低时, 接口开始执行批量写程序, 从内部的FIFO缓存向外部SRAM写入512 B (00-FF, FF-00) 。

通用可编程接口批量读传输的仿真结果与批量写类似, 仿真结果如图8所示。

由上述仿真波形可看出, 通用可编程接口读写数据时, 时钟周期为20.8 ns, 数据总线宽度为16 bit, 对应数据传输速率为96 Mb/s。相比之下, UART的传输速率为1.5 Mb/s, IIC总线为400 Kb/s~3.4 Mb/s, SPI总线为18 Mb/s, GPIO总线的传输速率最高为50 Mb/s[5]。可见, 通用可编程接口的传输速率最快, 更适合当前大容量存储器之间的数据传输要求。

5 结束语

本方案实现了通用可编程接口与外围设备接口连接的可配性, 并通过设计验证了该方案的可行性与准确性。在数据传输过程中, 通用可编程接口无需CPU的干预, 只需对其进行正确设置就可以正常工作。通用可编程接口的强大功能使其不仅可以与外部SRAM连接, 还可以与更复杂的接口 (例如ATA接口) 实现无缝连接, 加快了产品的开发速度, 降低了开发成本和提高了产品的可靠性。

参考文献

[1]王占领, 张登福, 李云杰, 等.便携式ARINC429总线通信接口的设计与实现[J].微电子学与计算机, 2013, 30 (7) :133-136.

[2]HASAMNIS M A, LIMAYE S S.Custom hardware interface using NIOS II processor through GPIO[C].The 7th Conference on Industrial Electronics and Applications (ICIEA′12) .Singapore, 2012:1381-1385.

[3]刘志华, 郭付才, 彭新伟, 等.基于CY7C68013A的FPGA配置和通信接口设计[J].电子技术应用, 2013, 39 (2) :18-21.

[4]赵林, 孟令军, 于磊, 等.基于CY7C68013A的USB2.0高速接口设计[J].电子技术应用, 2014, 40 (1) :131-133.

面向接口编程 篇7

在我院,《计算机接口编程技术》课程原名为《计算机组成原理与接口技术》,是嵌入式系统方向的一门专业基础课,即后续课程有8位的单片机、32的ARM等相关课程。学习该门课程,一方面是为后续课程奠定专业基础,同时掌握学习新的硬件知识的方法。我系教学团队在教学实施过程中根据高职高专院校的培养目标、学习者分析以及工作岗位需求分析情况对该门课程进行了改革。

1 改革教学内容

学生普遍反映《计算机接口编程技术》课程难度较大,理论知识信息量大且抽象,不易理解,比较枯燥,从而会降低学习兴趣。怎样提高学生学习的积极性与主动性是课程教学改革的任务之一,其中首先体现在教学内容方面。针对这种情况我们课程组对课程的教学内容进行了适当的选取与整合,使之适应专业培养目标的需求。

传统的《计算机组成原理与接口技术》课程以传授理论知识为主,且以汇编语言贯穿始终,实践课时和实践项目非常有限,从而使学习过程变得枯燥无味。我院购置了清华大学科教仪器厂的TPC-2003A+接口实验仪后,对教学内容以及组织形式加以了改进。在教学内容选取过程中,我们认真反思了原《计算机组成原理和接口技术》课程的教学内容和教学效果,借鉴了TPC—2003A+通用微机接口实验系统的随机参考资料,充分考虑了以下因素:课程应该提供相对比较完整的计算机体系结构体系信息,而不是仅仅让学生完成实践项目,讲授必要的理论知识,并引导学生通过网络学习拓展知识面,打牢基础;实践教学环节以TPC—2003A+通用微机接口实验系统提供的实践项目为主,力求覆盖实验系统提供的全部资源;在学生有一定基础知识后,以项目化教学方法进行各种接口电路的编程技能学习;适当增加归纳、总结的内容,引导学生改进学习方法。在语言工具方面我们选择使用C语言作为接口驱动程序开发的工具,这样一方面降低了学习难度,另一方面与企业对嵌入式人才要求接轨。

2 改革教学方法与手段

随着教学内容的重新选取与组织,在教学方法手段方面必然要求打破传统的单一的理论讲授法,而采用多种教学方法的综合应用。在教学改革过程中,主要采用了三种教学方法:

(1)理论课讲授。这种传统的教学方法在基础知识教学中是不可缺少的,在本课程教学中,结合理论教学安排了一些让学生利用网络进行学习和知识拓展的任务,目的是让学生自己带着问题查询资料。

(2)以案例演示分析为主要特征的课堂教学。根据项目、任务、案例的教学内容分解层次,以案例为课堂教学单元,过程包括:问题引入———案例功能、需求和目标分析———相关知识点说明———案例成果演示———案例开发过程示范(硬件接线和软件编程、调试)———学生模仿练习———教师归纳总结———教师布置学生课后任务,学生在进行分组情况下,课后进行适量的作业和任务实施工作。

(3)以学生课后任务完成情况展示为主要内容的课堂教学。在学生分组完成课后任务后,教师安排学生演示任务完成情况,过程包括:学生课后作业项目成果展示———教师和学生点评———教师补充说明相关知识点———总结和归纳———布置课后任务,在学生展示作品同时,锻炼学生表达能力。

总之,本课程教学中综合运用了项目教学法、案例教学法、理论实践一体化的教学等,在课程教学整体上采用项目教学法,在具体课程教学中采用案例教学法。通过理论实践一体化教学,让学生从模仿开始,逐步锻炼学生自主实施项目的能力。

此外充分使用现代教育技术手段促进教学活动开展,构建了立体化课程教学资源,开发了自主开发课程教学网站,激发学生学习兴趣。

3 改革考核方法

高职高专院校是培养综合素质和高技能人才的摇篮,因此对于一门实践性的课程来说,如果只通过课程的期末考试来评定学生对一门课的掌握情况显然是不客观也是不合理的。为全面考核学生掌握知识和技能的情况,我们采用了过程考核和考试方式并用的考核方式,学生课程成绩包括学习过程的项目成绩和考试成绩,加重过程考核的比例同时降低最后考试成绩所占的比例。这种考核方式在综合评价学生掌握知识技能的同时激励了学生平时学习的积极性和主动性。

4 结束语

《计算机接口编程技术》这门课程的教学改革涉及多方面的内容,我系教学团队都进行了深入的研究与探讨,经过近两年的实施情况看到教学改革效果非常好,使得这门课深受学生欢迎,从而得出只有不断的进行教学改革与创新才能提高教学质量,培养出优秀的高技能的人才。

参考文献

[1]王义.《微机原理与接口技术》课堂教学的创新实践[J].科技信息,2007,(36).

[2]李彩霞.如何教好《微机原理与接口技术》[J].中北大学学报,2008,(24).

面向对象编程思想解析 篇8

面向对象的思想不仅仅局限于软件设计, 它已经拓展到更多的领域, 如分布式系统、应用平台、交互式界面、数据库系统、人工智能、嵌入式软件系统等领域。作为计算机专业的求学者和从业人员, 不管钻研或从事哪个方向的, 都应该对面向对象编程思想有所了解。

通俗地讲, 面向对象编程思想可以概括如下:系统中的一切事物都是对象;将属性和对属性执行的操作封装成为整体, 这个封装体即是对象;属性和操作相同的对象抽象成为类, 对象则是类的实体;发送消息可以使对象执行相应的操作;在现有类的基础上增加属性或操作可以构成另一个类, 这是类的继承。

2 面向过程编程思想所存在的问题

2.1 可维护性差

用传统的面向过程方法所开发出的软件, 由于可修改性较差, 维护时产生的费用仍很高, 造成其可维护性差。

2.2 重用性差

重用性指软件不用修改或略加修改就能重复使用。面向过程程序设计阶段软件重用性极差, 引起软件危机, 软件工程这一学科由此而诞生, 提高重用性是软件工程的重要目标, 而面向对象的继承机制很好地解决了软件重用性这一问题。

2.3 软件功能与用户需求不一致

用传统的结构化方法开发大型软件系统涉及各种不同领域的知识, 在开发需求模糊或需求动态变化的系统时, 所开发出的软件系统往往不能真正满足用户的需要。

3 面向对象的重要概念

3.1 类

类是属性与操作相同的对象的抽象。因此, 类是对象的抽象, 对象是类的实例。例如“人”是所有人的一个抽象的总称, 他是一个类, “鲁迅”是具体的一个人, 这就是个对象。再如“班级”是个抽象的类名, “计算机系13级软件1班”是具体的一个班级对象。

类的属性用来表示对象的各种特征, 用数据结构来描述。如长方体有三个基本属性长、宽、高;时间有三个基本属性小时、分、妙;人的基本属性有姓名、年龄、性别、工作单位等。在不同的处理需求下对于同一事物的属性描述是不一样的。

类的操作是对于对象行为的描述, 包括操作的名称和操作实现过程。

3.2 对象

对象是任何被人类研究的实物, 不管是简单的实数还是结构复杂的核潜艇都可以认为是对象。除了具体的事物, 对象还能表示抽象的规则、计划。

3.3 对象的属性和操作

对象的属性用各类数据描述。如一个餐桌的属性包括长、宽、高、材质和颜色, 前三种属性值用实型数据表示, 后两种属性值用字符串表示。对象的操作用于改变或访问对象的属性。如一个餐桌对象有一个求桌面面积的操作, 这个操作需要访问此餐桌的长和宽。对象将其属性值与操作结合在一起形成一个整体, 将这个整体封装在对象中。

3.4 消息和方法

当要求对象执行某种操作时, 必须由外界向对象发送一条消息, 消息包括对象名和方法名, 有时还要加若干参数。类中操作的实现过程叫做方法, 一个方法有方法名、参数、方法体。

3.5 类与类的特殊关系

在现实世界中存在很多类, 有些类之间是毫无关联的, 但有些类之间具有一定的特殊关系, 有两种这样的关系:继承关系和组合关系。

如果现有一个定义好的类是“人”, 还需要再定义一个“男人”类, 可以不用对“男人”类进行重新定义, 而是选择在“人”这个类的基础上增加一个性别属性即可。“人”称为父类或基类, “男人”称为子类或派生类, 这两个类的关系叫做继承, 可以说这两个类是一种“是”的关系, 即男人是人。

如果现有一个“日期”类, 还要定义一个“学生”类, 属性中要体现出生日期, 那也可以不用在“学生”类中重新定义出生日期这一属性, 可以直接用已有的“日期”类来定义生日, 这两个类的关系叫做类的组合, 可以说这两个类是一种“有”的关系, 即每个学生都有生日, 而生日是日期信息。

4 面向对象的显著特征

4.1 封装

封装很好地实现了信息隐藏, 可以达到数据保护的目的, 即对象的属性一般不被外界直接访问, 而是通过对象的方法来访问, 从而保护了对象的属性, 为软件的模块性提供了保证。另外, 类定义将外部接口 (用户可见) 与内部实现 (外界不可见) 分离, 对象的方法其内部实现细节对外界是不可见的, 用户只管调用外部接口完成对象的一系列操作。

4.2 继承

子类继承父类的所有属性和方法, 避免了许多重复性的工作, 在一个现有类的基础上新增一些属性或方法级大地减少了软件设计的工作量。继承是面向对象编程语言区别于面向过程编程语言的最显著的特点。如果子类只有一个父类称为单继承, 子类存在多个父类叫做多重继承。在软件设计工作中, 继承是信息分类与组织的切实可行的方法, 它简化了创建类的过程, 提高了软件的可重用性, 使得软件的可扩充性大大加强。

4.3 多态

多态指相同的方法作用于类型不同的对象上可以得到不一样的结果。每个对象通过满足自身意愿的方式响应同样的消息。例如在听到统一的上课铃声后, 老师们各自进入自己任课的班级, 而不是进入同一个班级, 并且所讲的内容也都不同。多态性使得软件的可重用性和灵活性进一步增强了。

5 结语

面向对象编程思想以其独特的形式将数据以及在数据之上的操作细节封装在类中, 改变了面向过程编程思路的程序结构和整体格局, 由于其继承性可以加快软件开发速度, 并增强软件可重用性, 便于软件扩充功能, 多态性可提高软件设计的灵活性, 故从过去较长时间至今一直以来仍占据着程序设计的主流地位, 也一直是衡量各层次程序员与计算机从业人员业务素质的标准。

参考文献

[1]彭莉芬、陈俊生.浅析面向对象的三大特征[J].福建电脑, 2010 (05) .

[2]谭大海、刘兴勇.面向对象分析与设计[J].科技信息, 2014 (10) .

上一篇:高中生英语写作漫谈下一篇:关爱农民工子女