自从推出了DS80C390的TINI~运行环境(TINI Runtime Environment),开发人员早就呼吁寻找一种方法,能在不使用Javatm语言的前提下使用TINI的强大功能。但遗憾的是,TINI的网栈和其他特性与Java虚拟机及运行环境曾经是紧密相连的,很难在C语言或汇编程序中去访问。为此,在设计DS80C400网络微控制器的ROM时,一组功能被公开出来,可以在8051汇编、C语言或Java程序中访问。受容量的限制,ROM提供的功能仅限于TINI运行环境的一个子集。这样,ROM可以被视作一个可由C或汇编程序使用的模块,它提供了经过验证的网栈、进程调度器和存储器管理器。简单程序象网络扬声器|蜂鸣器可以用汇编语言轻松实现,更复杂一点的象HTTP(超文本传送协定)服务器这种需要与文件系统交互的程序可以使用C语言。
本文先从一个用C语言实现的Hello World程序人手,然后介绍一个简单的HTTP服务器。文中介绍了如何设置开发五金|工具并编写一个简单的示范程序,然后演示如何使用DS80C400的ROM功能。所有开发都使用TINIm400验证模块和包含7.05版C编译器“C51’’的Keil μVision2TM2.37版
从Keil的μVision2开始
可以使用Keil μVision2开发套件,构建一个简单的Hello World型C语言程序。按照以下步骤完成你的第一个用于DS80C400的C语言应用程序。
.选择Project->Create New 。
输入项目名称。
.屏幕上将出现Select Device for Target对话框。在Data base中选择Dallas Semiconductor和DS80C400。选择Use Extended Linker和Use Extended Assembler。点击OK继续,见图1所示为该对话框的正确配置。
.将有对话框提示:Copy Dallas 80C390 Startup Codey to Project Folder和Add File
to Project?选择No。我们将提供自己的启动代码。
.当项目窗口在左侧打开时,打开Target1。右击Source Group1,并选择Add files to group''Source Group1’。在弹出的文件对话框中,将files of type 改为Asm source file。添加文件startup400.a51。
.应该注意,建立应用的地址应为400000h,它对应于TINIm400上flash的起始地址。双击打开文件startup400.a51。找到段声明?C_CPURESET?0。确保代码段声明为400000h:
?C_CPURESET?0
SEGMENT CODE AT 400000h
.另外,应有一个“DB,’TINI’行,后跟另一个DB行,带有注释“Targe tbank”。这个声明是一个标记的一部分,用于告知DS80C400 ROM从地址400000h开始执行代码。这样就可以确保应用的建立地址为400000h,对应于TINIm400上flash的起始地址。请确认该行为:
DB 40h ; Target bank
.创建一个新的文件,以“main.c”为文件名来保存。在该文件中写人如下代码:
# include <Stdio.h>
Void main( )
{
printf(”Test 400 Program\r\n”);
while (1) { }
)
.保存文件内容。右击Source Group1,并添加源文件main.c。现在就可以将该源文件添加到项目中了。
.右击左侧的Target1。选择options for target’Target1’,打开选项对话框。第一个选择标签应该为Target。将Memory Model改为Large:variables in XDATA。将Code Rom Size改为Contiguous Mode:16MB program。选中检查框Use multiple DPTR registers和far memory type support。在off-chip Code memory项目下加入第一个人口:Start:Ox400000,Size:Ox80000。在off- chip Xdata memory项目下加入一个入口:Start:0x10000,Size:Ox4000。
图2所示为配置完成后的对话框。注意,Ox400000的最后一个0在窗口中没有显示出来。
上述设置基于TINIm400参考模块的存储区配置,该模块在地址0有512k的RAM,从地址400000h开始有1M的flash。Keil配置中的起始地址与大小应根据用户的DS80C400设计来修改。
.选择Output标签。点击Create HEX File,并在下拉框中选择HEX-386。
.按F7键建立应用程序。如果每一步都正确完成,建立过程应不产生错误或警告信息。之后会生成一个hex文件。现在就可以将该应用程序装载到你的电路板上了。
将应用实例装载到TINIm400模块
这部分介绍如何使用JavaKit工具将Keil编译器生成的hex文件装载到TINIm400验证模块中。使用JavaKit之前,必须首先安装Java Runtime Environment(1.2版以上)和Java Communications APl。Java Runtime Environment可以从http://java.sun.com/j2se/downloads.html网页下载,Java Communications API可以在http://java.sun.com/products/javacomm/index.html网页上找到。JavaKit包含在TINI软件开发包中(TINI Software Development Kit),www.Max-ic.com/TINIdevkit上提供下载.运行Java Kit的说明可以在TINI Software Development Kit的docs目录下的Running_JavaKit.txt文件中找到。如果在运行Java Kit时遇到任何技术问题,很可能其他人曾经遇到过类似的问题,这些问题被收集在TINI主题列表中。你可以在www.maxim-ic.com/TINI/lists上搜索有关该列表的文档。
通过以下命令行建立Java Kit与TINIm400模块的通话。(Kit为成套组件,即可以装成一个系统的成套硬件和软件)
java Java Kit -400 -flash 40运行J ava Kit后,选择用来与TINIm400进行通信的串口。使用Open Port按钮打开该串口。然后按Reset按钮。DS80C400装载器将提示如下信息:
DS80C400 Silicon Software-Copyright (C) 2002 Maxim Integrated Products
Detailed product information available at http://www.maxim-ic.com
Welcome to the TINI DS80C400 Auto Boot Loader1.0.1
>
在JavaKit顶部的File菜单中,选择Load HEX File asTBIN。找到并选择我们已经创建的helloworld.hex文件。Load HEX File as TBIN选项先将输入的hex文件转换为TBIN文件,然后装载。这样的操作比直接装载hex文件速度快,因为对于同样的数据,ASCII编码的hex文件的尺寸是二进制文件的二倍多。
用户程序装载后,有两种执行方法。由于程序装载到存储区40中,所以可以直接键人:
> B40
> X
要选择存储区40,并运行这里的代码,也可以键人:
> E
这将使ROM查找可执行代码,有一个特殊标记符用来表示当前存储区中有可执行代码。该标记符由字符“TINI”和紧随其后的当前区号组成。它位于当前区的地址0002处。我们的Hello World程序对于此标记符的声明在startup 400.a51文件中如下所示:
?C_STARTUP:SJMP STARTUPl
DB ‘TINI’;Tag for TINI Environment 1.02C
;or土ater (ignored in土.02b)
DB 40h;Target bank
注意SJNP STARTUP1语句位于40区的地址0000处。由于sjmp语句占两个字节,所以紧随其后的执行标记{‘T’,T,’N’,40h}位于地址0002。
当键人“E”时,ROM在存储区中向下查找可执行代码。如果键人“E”后执行了其他代码,就说明ROM在高于400000h(装载你的代码的位置)的地址处找到了执行标记,你可能需要找到该标记,并删除该存储区中的内容。可以通过使用装载器Z命令擦除一个flash存储区:
> Z41
You sure? Y
要清除flash中所有存储区,你需要对存储区40h至4Fh重复该操作。
接口至ROM和ROM库
从C中调用ROM函数比较复杂(调用ROM函数的步骤参见High-speed MicrocontrollerUser''s Guide:DS80C400 Supplement)。必须将Keil C编译器规范的参数转换成ROM所使用的规范。Keil编译器以XDATA地址和寄存器组合的方式传递参数。而ROM函数采用不同的方式接收参数。例如,套接字函数接受存放在单个参数缓冲器中的参数,而许多其他应用函数接受特殊功能寄存器或直接存储器地址传来的参数。Dallas Semiconductor编写了访问ROM函数的库,可完成Keil调用规范与ROM参数规范间的翻译工作。
要在你的C程序中使用ROM函数,只需要导人相应的库,并包含一个头文件。为了在你的项目中导人一个库,在Keil项目窗口中右击Source Group/,并选择Add Files to Group''Source Group 1’。将文件过滤器改为’*lib’,选择你需要的库。然后在源代码顶部加人头文件。你可以使用任何一个库函数。这些ROM库可支持ROM初始化、DHCP客户端操作、进程管理、套接字函数、TFTP客户端操作以及一些实用函数,例如CRC和伪随机数产生等。
使用扩展库
除了ROM库,还有许多其他库(还有更多正在编写中)提供了很多ROM中没有的实用功能。已经开发的有文件系统操作、DNS检索、12Ct”通信和1—Wire~通信等。
为DS80C400提供的C库项目(包括文档、应用实例和发行说明)可以在www.Maxim-ic.com/DS80C400/libraries上找到。
一个简单的HT-I''P服务器和SNTP客户端应用
Dallas Semiconductor公司编写了一个小的应用程序来演示这些库的功能,特别是文件系统、套接字、进程调度器和TFTP库等。应用实例中包括一个SNTP客户端和一个只响应‘GET’请求的HTTP服务器。它使用Dallas Semiconductor提供的核心库调用套接字和调度器函数。它还使用文件系统保存了几个网页。该应用由两个进程组成:(1)HTTP服务器作为一个新进程被创建并用来处理端口80上的连接,以及(2)主进程位于一个循环中,约每60秒尝试进行一次时间同步。该应用程序的源代码和项目文件在www.maxim-ic.com/timeserver中可以找到。
文件系统的初始化
启动HTTP(超文本传送协定)服务器之前,必须初始化文件系统。演示程序确保两个静态文件,主页(index,html)和程序源码(source.html),在服务器启动之前已位于文件系统中。
程序从TFTP(普通本件传送协定)服务器下载所需的文件,完成文件系统的初始化。在我们这个实例中,TFTP服务器在一个已知的IP地址上运行。文件index.html和source.html由TFTP服务器获得,然后被写入文件系统。
SolarWinds为Windows平台提供了一个免费的TFTP服务器,它被应用于该演示程序的开发中。在SolarWinds网站(www.solarwinds.net),跟随Downloads—Free Software菜单可找到TFTP服务器下载。安装以后,使用File菜单下的Configure选项来配置现有文件。确保程序使用你的TFTP服务器IP地址(TFTP_IP_MSB,TFTP_ IP_ 2,TFTP_IP__3和TFTP_IP_LSB)。
简单的HTTP(超文本传送协定)服务器
该应用中的HTTP服务器是RFC 2068所描述的HTTP服务器的一个简化版实现。在该版本下,只支持‘GET’方法。输人头被忽略,只给出很少的输出头。
服务器套接字通过调用Berkley型套接字函数来创建,这样使得服务器套接字容易建立。以下代码说明了这个简单的HTTP服务器是如何创建、邦定并接受新连接的。
Struct Sockaddr local;
Unsigned int socket_handle, new_socket_handle, temp;
Socket_handle = socket(0,SOCKET_TYPE_STREAM,0);
local.Sin_port=80;
bind(socket_handle,& local, sizeof(local));
listem(socket_handle,5);
print (”Ready to accept HTTP Connections...\r\n”);
// here is the main loop of the HTTP Server
while (1)
{
new_socket_handle = sccept(socket-handle,
&address,sizeof(address)); ‘
handleRequest(new_socket_handle);
closesocket(new_socket_handle);
)
请注意,接受了新的套接字后,这个简单的应用并不启动新的线程或进程来处理请求。而是在同一进程中处理该请求。任何非演示版的HTTP服务器都会在新的线程中处理收到的请求,这样就允许多个连接出现并被同时处理。请求处理完后,关闭套接字,等待另一个收到的连接。
Handl eRequest方法从收到的请求中解析出一个文件名,并确定该方法是‘GET’。其它方法(甚至是‘POST’,‘HEAD’或‘OPTIONS’)均不被接受。两个文件名被作为特例处理。当请求文件为time.Htm时,服务器动态产生一个响应,其中包含来自timeserver的最新结果,以及自上一次查询timeserver以来的秒数。当请求文件为stats.html时,将显示服务器的正常运行时间和请求次数统计结果。
如果找不到文件或发出的是无效的请求方法,HTTP服务器报告错误码。
SNTP客户端
“timeserver应用的第二个主要部分是Simple Network Time Protocol(SNTP)客户端,参见RFCl361的描述。它是Network Time Protocol(RFCl305)的一个版本。SNTP要求UDP从一个侦听端口123的服务器请求时戳。我们的“timeserver使用以下代码周期性地与服务器time.nist.gov同步。请注意,在写这篇文章时,DNS检索还不被支持,因此服务器的IP地址须手动设置。DNS现已被添加到了C库网站,以下代码更新后可通过检索获得IP地址。
Socket-handle = socket(0,SOCKET_TYPE_DATAGRAM,0);
// set a timeout of about 2 Seconds.
// ‘timeout’ is unsigned long
timeout = 2000;
Setsockopt (socket-handle,0,SO_TIMEOUT, & timeout, 4);
// assume ‘buffer’ has already been cleared out
buffer[0] =Ox23; // No warning/NTP Ver 4/client
address。sin_addr[12] = TIME_NIST_GOV—IP-MSB;
address.sin_addr[13] = TIME_NIST_GOV—IP-2;
address.sin_addr[14] = TIME_NIST_GOV—IP-3;
address.sin_addr[15] = TIME_NIST_GOV—IP LSB;
address.sin_port = NTP_PORT;
sendto((socket-handle, buffer, 48, 0, &address,
sizeof(astruct sockaddr));
recvfrom(socket=handle, buffsr, 256, 0, &address,
sizeof(astruct sockaddr));
timeStamp = *(unsigned long*)(&buffer[40]);
timeStamp =timeStamp - NTP_UNIX_TIME_OFFSET;
// now we have time Since Jan 1 1970
formatTimeString(timeStamp, ”London”,last-time-reading-1);
last_reading_seconds = getTimeSecondS();
cloSesocket(Socket handle);
首先生成一个数据报套接字,并给定一个约2秒的超时(0x800=2048ms)。这样可以确保在与我们选择的服务器通信失败时,不必无限期地等待下去。
下一行设定请求选项。关于这些位的描述参见RFCl361第三节。值0x23要求闰秒时无需告警,要求采用NTP版本4,并声明模式为‘C1ient’。当我们使用公共数据报函数sendt。
和recvfrom发出请求并收到回答后,时戳的秒部被赋给变量timeStamp,然后调整到参考时间1970年1月1日。formatTimeString函数将时戳转换为易读的字符串,如“In London it is l5:37:37 onMarch 31,2003”。
getTimeSeconds函数以DS80C400内部时钟为基础确定上一次更新的时间。由于该程序大约每60秒才更新一次,HTML页time.html使用这个数值来报告自上次更新以来的时间间隔。最后,关闭套接字,SNTP客户端在下面的60秒内进入休眠。
结论
Keil C编译器和Dallas Semiconductor公司提供的库允许用C编写的应用也可方便地使用以前只能通过TINI的Java环境访问的功能和函数。C语言程序现在可以访问网栈、存储管理器、进程调度器、文件系统,以及DS80C400网络微控制器的许多其他特性。另外,与TINI运行环境相比,用C语言编写的应用程序为用户代码和数据提供了更多的空间。使用C语言的DS80C400开发者可轻易编写出瘦应用,有充裕的速度、能力、代码空间来解决各种问题。