本文探讨了一种简单而经济的方法,通过使用DS80C400/DS80C410/DS80C411网络微控制器改造基于微型互联网接口(TINI®)平台的传统系统,将独立串行设备迁移到以太网。一旦设备连接到以太网,实现 TINI Web 服务(如 HTTP 服务器)就非常简单了。
概述
使用串行端口作为与其他电子设备通信手段的设备数量惊人。事实上,对于许多人来说,串行端口提供了与外界通信的唯一机制 - 包括恒温器、销售点系统、远程监视器、条形码阅读器、收据打印机、RFID 收发器、血压计等等,涉及从传统测试工具到最新的楼宇自动化等领域。这些设备没有直接参与更大的计算机网络的方法,但新的应用程序需要TCP / IP连接和以太网功能。通常,昂贵且耗时的重新设计不是一种选择。
本文探讨了一种简单而经济的方法,通过使用DS80C400微控制器改造基于TINI®平台的传统系统,将独立串行设备迁移到以太网。一旦设备连接到以太网,实现 TINI Web 服务(如 HTTP 服务器)就非常简单了。
RS-232 串行端口
本文中讨论的异步串行通信基于RS-232-C标准,该标准可以追溯到记录计算机历史的早期;RS-232-C 于 1969 年发布¹。大多数现代串行端口不支持标准中定义的所有信号 - 并且实现的信号的使用方式仅与标准中定义的方式“相当接近”。我们将忽略纯粹的历史定义,专注于RS-232的使用方式。
空格和标记
RS-232-C将+3V至+25V的电压电平指定为“SPACE”(二进制0),将-3V至-25V的电压电平指定为“MARK”(二进制1)。-3V和+3V之间的区域是“开关区域”。许多UART(通用异步接收器发送器)对0和5使用更现代(相对而言)的TTL电压电平0V和+1V。专用电平转换器,如著名的MAX-232,在TTL和RS-232电平之间转换。由于DS80C400/DS80C410/DS80C411上的串行端口是TTL电平,因此在与另一个TTL电平UART接口时不需要电平转换器。
DCE 和 DTE
DCE(数据通信设备)和DTE(数据终端设备)是通信通道的两个端点。主要区别在于串行连接器引脚排列(所谓的零调制解调器可用于在两者之间进行转换)。
表 1 显示了使用零调制解调器时 DB-9 DTE 串行连接器上的信号和另一个 DTE 上的相应信号。
表 1.DB-9 DTE 串行连接器信号 | ||
DTE 引脚 | 信号名称 | 零调制解调器 |
1 | 光盘(载波检测) | 4 (DTR) |
2 | RD(接收数据) | 3 (道明) |
3 | TD(传输数据) | 2 (RD) |
4 | DTR(数据终端就绪) | 6 (DSR) 和 1 (CD) |
5 | 公共(信号接地) | 5(普通) |
6 | DSR(数据集就绪) | 4 (DTR) |
7 | 即时战略(请求发送) | 8 (CTS) |
8 | CTS(清除发送) | 7 (即时战略) |
9 | RI (环形指示器) | 不适用 |
流控制
串行通信可以通过在一个引脚(TD)上发送并在另一个引脚(RD)上侦听来实现。但是,当两台通过RD通信的设备时,TD随意传输,其中一个可能会溢出另一个,从而导致数据丢失。通常有两种方式实现流控制:
- XON/XOFF(通常松散地称为软件流控制) - RTS/CTS(通常松散地称为硬件流控制)
XON/XOFF 流控制方案传输带内字符,导致另一端暂停(XOFF,13h)和恢复(XON,11h)传输。XON 和 XOFF 字符必须由发送方在软件中转义,如果它们出现在二进制数据流中,则由接收方解开包装。
RTS/CTS使用额外的信令线。RTS(发送请求)由发送方断言。当接收方准备好接收数据时,接收方使用 CTS(清除发送)进行响应,在其接收缓冲区已满时清除 CTS。
有些设备支持流控制,有些则不支持。因此,默认值通常设置为“无流控制”,如果已知设备实现流控制,则应覆盖该默认值。
速度、数据位、停止位和奇偶校验
为了使通信成功,必须正确设置的其他参数当然是传输速度(比特率),数据和停止位的数量以及奇偶校验的类型(如果有的话)。大多数新设备使用“8N1”设置,这意味着 8 个数据位、无奇偶校验和 1 个停止位。但是,众所周知,遗留系统使用所有可能性,因此正确的设置实际上可能不是那么简单。
天尼与网络
TINI(微型互联网接口)是达拉斯半导体公司开发的技术平台,允许在DS80C400/DS80C410/DS80C411微控制器上快速开发。具体来说,TINI包含一个芯片组定义,以及一个与高度优化的Java™ 1.1运行时环境集成的嵌入式操作系统。使用Java,程序员可以从嵌入式开发中不常见的强大功能中受益:多线程,垃圾收集,继承,虚拟化,跨平台功能,强大的网络支持,以及最后但并非最不重要的一点是,大量的免费开发工具。TINI用户通常不受汇编语言编码的影响。但是,支持并鼓励使用本机语言子例程来优化速度关键路径或低级硬件访问(TINI 操作系统是用本机代码编写的,因此串行 I/O 吞吐量与现代 PC 没有显着差异)。
除了完全支持 java.net 包之外,TINI Java 1.1 运行时还包含 javax.comm 子系统的实现。由于TCP/IP和串行端口都可以从Java轻松访问,因此TINI系统很容易实现串行到以太网桥接。
TINI环境在TINI规范和开发人员指南(Addison-Welsey,2001)中有详细的记录。
例子
我们将从两个具体的应用程序开始,然后介绍一个通用串行到以太网程序的简短摘录,该程序可以修改以适应几乎任何特定应用程序。这些示例是使用 TINIm400 验证模块构建的。
图1.
TINI验证模块可以用作“黑匣子”,将多个串行设备连接到以太网。根据终端设备的需要,TINI可以直接传递数据,也可以解析、解释和修改数据流。
请注意,虽然您可以在 TINIm400 上运行 slush 开发人员外壳中的示例,但更完善的应用程序将驻留在闪存中,在断电时自启动,并使用其他 TINI 构造技术使成品几乎坚不可摧。
需要一些基本的网络知识和编程经验才能修改示例。工作示例代码也可从Maxim下载。
虚拟调制解调器
第一个示例是“虚拟调制解调器”²,它使用 TINIm400 将物理调制解调器和电话线替换为 TCP/IP 连接。假设像工厂“机器状态监视器”这样的传统设备,它使用调制解调器每天多次拨入中央服务器,以报告机器状态、负载和效率数据。为了消除服务器端对不断增长的调制解调器库的需求,并且能够使用现有的LAN而不是设备的电话线,可以
- 将服务器软件重写为基于 TCP/IP 和
- 使用 TINI 虚拟调制解调器替换每台计算机上的原始调制解调器
但是,机器状态监视器不必修改,因为就终端设备而言,虚拟调制解调器的行为类似于真正的调制解调器!
当然,虚拟调制解调器也可以成对使用,而不是上述配置。使用两个虚拟调制解调器时,根本不需要更改服务器软件,TINI模块是现有调制解调器的直接替代品。
在后台,虚拟调制解调器在收到“ATD”调制解调器拨号命令时建立 TCP 连接。“ATH”断开连接命令将关闭 TCP 连接。该软件还实现了许多其他经典的AT调制解调器命令,例如,被Microsoft® Windows®网络识别为真正的调制解调器。此外,虚拟调制解调器侦听TCP端口本身,并可以应答由“RING”向终端设备发出信号的传入“呼叫”。
以下代码片段演示如何初始化 TINIm400 上的串行端口:
public static void main(String args[]) { TINIOS.setSerialBootMessagesState(false); TINIOS.setDebugMessagesState(false); TINIOS.setConsoleOutputEnabled(false); System.out.println("Connecting to serial0 at 9600bps, " "listening on TCP port 8001"); try { CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier("serial0"); SerialPort port = (SerialPort) portId.open("VModemTINI", 10000); TINIOS.setRTSCTSFlowControlEnable(1, false); TINIOS.setRTSCTSFlowControlEnable(0, true); TCPSerialVirtualModem modem = new TCPSerialVirtualModem(port, /* Comm speed */ 9600, /*TCP Port */ 8001); modem.processInput(); } catch (Exception e) { System.out.println("Exception: "+e.toString()); } }
该代码首先禁用所有 TINI 操作系统调试输出,这是 TINI 的标准做法。获取端口标识符后,将打开该端口(第二个参数告诉 open 如果该端口当前正由另一个应用程序使用,则等待多长时间)。接下来,设置硬件流控制的状态。由于 TINIm400 只有一组用于串行端口 0 和 1 的 RTS/CTS 线路,因此程序应始终禁用另一个端口上的流量控制,然后再在所需端口上启用它。接下来,实例化 Java 虚拟调制解调器。
虚拟调制解调器类由 AT 命令解释器(此处未显示,尽管到目前为止是示例的最大部分)和网络代码组成。以下代码设置串行端口比特率、数据和停止位以及奇偶校验,并显示处理入站连接的难易程度:
/** Creates a new VirtualModem connected to a serial port on * one end and a TCP port on the data side. * serial -- the serial port this VirtualModem talks to. * speed -- the speed the serial port should be set to. * tcpport -- the TCP port this VirtualModem listens on. * throws IOException when there's a problem with the serial or TCP port. */ public TCPSerialVirtualModem(SerialPort serial, int speed, int tcpport) throws IOException { super(serial); try { serial.setSerialPortParams(speed, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); } catch (UnsupportedCommOperationException e) { throw new IOException(); } ... serverSock = new ServerSocket(tcpport, 1); // backlog of one listenThread = new listenInbound(); listenThread.start(); }
最后,以下 listenThread() 摘录接受传入的连接请求:
public void run() { int rc; Socket s; while (running) { s = null; // No incoming connection request try { answered = false; s = serverSock.accept(); // Discard incoming connection if already connected if (connected) throw new IOException(); sock = s; // for answer() ...
不间断电源监控器
第二个示例将 TINIm400 连接到不间断电源的串行端口。该软件实现了网络UPS工具协议³,允许各种平台上的各种客户端监控UPS状态和运行状况(该项目源于需要从没有任何串行端口的新Macintosh计算机监控现有UPS)。
UPS设备有两种基本类型:所谓的“智能”设备和简单(或“哑”)的设备。一个简单的UPS在几个串行引脚上发出其状态信号,它实际上并不发送任何ASCII数据。由于串行引脚不是很多,它只能报告非常有限的一组信息,例如:
信号 | 意义 |
即时战略(来自不间断电源)) | 低电量 |
道明(来自 UPS) | 使用电池 |
CTS(来自 UPS) | 终止 UPS 电源 |
javax.comm.notifyOn...() 方法可以在 Java 中用于轻松实现对状态更改做出反应的代码,例如:
... // Listen for DTR changes try { port.addEventListener(this); } catch (TooManyListenersException e) { ... } port.notifyOnDSR(true); ... public void serialEvent(SerialPortEvent ev) { try { if (ev.getEventType() == SerialPortEvent.DSR) ... } catch ... ... }
智能UPS更有趣,因为它实现了串行协议,并且可以返回电池充电百分比或温度等值。不同供应商之间的协议差异很大,而且通常没有记录。
以下代码演示如何接收 UDP 请求并通过 UDP 发送 UPS 状态信息。
// Listen to incoming UDP requests private class listenUDPThread extends Thread { private DatagramSocket sock; private byte[] buffer; private DatagramPacket dp; public listenUDPThread(DatagramSocket s) { sock = s; buffer = new byte[BUF_SIZE]; dp = new DatagramPacket(buffer, buffer.length); } public void run() { while (running) { try { sock.receive(dp); byte[] data = parseCommand(buffer, dp.getLength()); sock.send(new DatagramPacket(data, data.length, dp.getAddress(), dp.getPort())); } catch (Exception e) { } } try { sock.close(); } catch (Exception e) { } } }
由于 Java 中内置了强大的网络支持,此示例几乎是不言自明的。while() 循环中的代码会等待,直到它收到 UDP 请求,解析它并向请求的发起方发送答案(在传入数据包上使用 getAddress()。
通用串行到以太网应用
完整的串行到以太网示例超出了本文的范围。(完整的示例在 TINI 规范和开发人员指南中显示和解释。但是,以下代码片段演示如何有效地使用多线程在串行到以太网网桥的串行和网络部分之间传输数据。串行端口和TCP端口被抽象为输入/输出流dataIn和dataOut,因此这一层代码实际上根本不需要知道有关网络的任何信息,并且还可以在CAN和1-Wire之间桥接数据。
public GenericBridge() { ... running = true; dcThread = new dataCopy(); dcThread.start(); } // Thread that copies everything from dataIn to dataOut private class dataCopy extends Thread { public void run() { int r = 0; while (running && r >= 0) { try { synchronized (threadLock) { r = dataIn.read(dataBuffer); if (r > 0) dataOut.write(dataBuffer, 0, r); } } catch (Exception e) { r = -1; ... // Handle error } } } }
结论
许多传统设备仅支持异步串行通信,但当前应用需要以太网连接和 TCP/IP 网络。DS80C400/DS80C410/DS80C411微控制器采用强大的Java运行时和TINI技术,开发串行到以太网转换器非常简单,只需几个小时即可完成。
审核编辑:郭婷
全部0条评论
快来发表一下你的评论吧 !