摘要: 你可以通过互联网回收旧电脑设备。本应用说明展示了如何使用TINI 网络启用只有并行端口连接的旧点阵打印机。这里展示的协议转换技术可用于将许多设备连接到Internet。
我妻子扔掉了只有两个洞的袜子和沾有草渍的衬衫。我并没有太过抗议,直到她来到老式的点阵打印机前。“你已经好几年没用过这个东西了,我们所有的电脑都不能和它说话,”她不屑地说。像任何一个技术极客一样,我无法忍受扔掉一台旧电脑设备的想法。我的任务很明确:要么让那台打印机重新好用起来,要么永远失去它。我决定让它可以通过网络访问,幸运的是,我有一个TINI(微型互联网接口)来完成这项工作。
TINI是Maxim的嵌入式网络平台,运行在该公司的DS80C390、DS80C400、DS80C410和DS80C411微控制器上。这些都是增强型8051微控制器
TINI平台支持TCP/IP网络堆栈(IPv4和IPv6)、内存管理器、进程调度器和大量通信协议,如I²C、SPI和CAN。tini可以用8051汇编语言、C或Java编写,具有熟悉的编程接口。C运行时提供了伯克利风格的套接字接口,Java运行时支持Java 1.1.8 API的核心。
有了大量的IO支持、一个简单的网络接口和许多编程方法,TINI是一个很好的协议转换器。这正是我保存我的旧打印机所需要的:TINI将提供网络接口,我将决定如何使TINI与打印机通信。
对于系统的大脑,我使用了TINI评估(EV)套件。EV套件基于DS80C400微控制器,具有1MB闪存,1MB RAM以及用于RS-232和以太网通信的连接器。它的内存配置与TINI Java运行时兼容,尽管它仍然可以用C语言和汇编语言编程。这为我的打印机界面原型和最终的应用程序提供了大量的选择。
有问题的打印机是爱普生LX-800。碳年代测定和一层厚厚的灰尘使它接近真空管和呼啦圈的时代。LX-800是一个9针打印机,这是指打印头的针数,而不是驱动它所需的并行信号的数量。我实际上需要17个信号来驱动打印机(不包括地面)。图1显示了典型的pc -打印机并行接口中的信号,以及它们在25针打印机连接器中的排列。
图1所示。并行打印机接口的25针信号定义。
由于我使用传统的25针Centronics打印机电缆将TINI连接到打印机,因此需要匹配图1中列出的连接。然而,有一个问题:TINI板的IO不方便用作宽并行总线。只有8或9个通用IO (GPIO)信号,大约是我需要的一半。这些GPIO信号也分布在几个不同的寄存器中。这种GPIO信号的限制使得对打印机的8位数据总线进行简单的写入变得不方便,因为需要多个寄存器写入来设置8个输出位。幸运的是,TINI插座板具有用于添加CPLD(复杂可编程逻辑器件)的焊盘和走线,这将使我能够极大地扩展TINI的IO功能。一旦CPLD关闭,我只需要一个头来编程CPLD(通过JTAG接口)和一个头来提供对一些TINI引脚的访问。
把CPLD看作是可配置的硬件。它具有高度灵活的内部结构,允许实现各种各样的逻辑功能和状态机。TINI插座板设计为XILINX CoolRunner -II XC2C64 CPLD提供了100引脚VQFP封装空间;如果有相同的封装和引脚,也可以使用其他的coolrunner - ii。对于这个项目,我使用了XC2C128,这是一个容量更大的设备,具有相同的引脚。
CPLD通过DS80C400微控制器的外部存储器总线连接到TINI系统。为了访问CPLD,微控制器只需要读取或写入一个特殊地址:
read_from_cpld: mov dptr, #0C00000h;CPLD地址movx a, @dptr;从设备中读取
CPLD的任务更为复杂。一方面,它需要正确地响应TINI的外部内存总线信号:当TINI写入总线时从总线返回值,当TINI请求读时将值驱动到总线上。在打印机端,CPLD需要读取指示打印机正在做什么的状态信号(如BSY),并驱动输出信号(如8位数据总线和写频闪灯STR)来控制打印机。图2给出了CPLD实现的框图。
图2。CPLD必须在它自己的IO引脚和微控制器的地址总线之间实现一个接口。
CPLD实现4个8位寄存器,对应CPLD上的32个I/O引脚。寄存器位设置为0将驱动其相应的输出引脚低,而寄存器位设置为1将浮动高。因此,要从一个
图2中的所有输入信号都来自TINI的外部存储器总线。当TINI写入CPLD时,数据总线包含TINI试图写入的8位值。当TINI执行读取时,CPLD需要用它感知到的输入值驱动数据总线。然而,CPLD不能简单地驱动数据总线每次TINI请求任何类型的读取(即,每次nPSEN是活跃的),因为有可能有其他设备共享总线。如果CPLD这样做,TINI将获取错误的指令或数据,导致不可预测的系统行为(即“坏事情发生”)。同样,CPLD不应该在每次TINI执行写操作(即每次nWr处于活动状态)时都做出反应,因为并非所有写操作都针对CPLD。因此,图2中的Read和Write信号由地址行限定。
当地址线AH0和AH1 (TINI的16(th)和17(th)地址线)为0时,CPLD被激活(在我们的情况下,我们使用芯片使能6)。由于TINI配置为每个芯片使能2MB,访问CPLD的基址是0xC00000 (2,097,152 × 6 = 12,582,912 = 0xC00000)。请注意,在我选择的配置中,大多数TINI的地址行没有在TINI和CPLD之间的接口中指定。例如,TINI的地址线A2到A15可以假设任何值,并且仍然激活CPLD。然而,为了简单起见,我的源代码总是使用地址0xC00000到0xC00003来访问四个8位寄存器。
CPLD编程由硬件描述语言HDL (Hardware Description Language)指定。我使用Xilinx WebPACK 进行开发,并在Verilog 中编写硬件描述,其模块定义如下图2所示,即,有8位寄存器、多路复用器和解码器的独立模块。块和地址解码在顶层块中执行。
在CPLD被填充和编程之后,在连接到打印机之前,我想检查一下,以确保我真的知道哪个信号是哪个。我创建了一个小板,其中有4个LED银行与我的四个逻辑寄存器(IO7:0, IO15:8, IO23:16和IO31:24)相关联,如下所示图3。用C编写了一个简单的程序,向4个LED银行写入增加值,中间有一个暂停,这样我就可以直观地验证程序的操作。相信我的CPLD编程和我对连接的理解是正确的,我把打印机带入了画面。图3显示了从TINI板到25针打印机连接器的飞线连接器。
图3。TINIs400插座板连接到爱普生打印机。
我的最终目标是在没有任何特殊驱动程序或客户端应用程序的情况下使用打印机。或者简单地说,我想使用Windows 内置的打印驱动程序和打印对话框,在我的旧打印机上做点什么。我的应用程序的最终测试是从MS Word中打印一些东西;如果有什么不对的地方,我肯定上帝会告诉我的。与此同时,虽然MS Word是我的最终目标,但我想循序渐进地实现它。
我的第一步是编写一个小应用程序,它可以在没有任何网络连接的情况下向打印机发送一些ASCII字符。这种方法一次只会给我一个需要调试的东西。理论上,只要我不使用命令代码和其他非ascii字符,打印机应该只打印我发送给它的每个字符。像所有好的工程项目一样,我希望这个过程能够顺利而快速地进行,并且我可以很快确定网络接口。当然,我完全错了。
我使用Keil Software µVision 2工具套件用C语言编写了我的第一个打印机应用程序。在我的家乡不可或缺的PC硬件书,似乎我所需要做的就是初始化打印机并开始书写字符。书写一个字符是一个简单的算法:
等待BSY变为非活动状态。
在数据总线上设置输出值。
设置写频闪STR为活动状态。
等待ACK信号确认接收到的数据。
设置写频闪STR为非活动状态。
冲洗干净,根据需要重复。
在我的第一次测试中,我在该算法中安装了大量延迟,以确保如果我有一个状态信号错误(错误的极性,错误的引脚等),我仍然应该看到写的东西。因此,我最初的程序将每秒写一个字符。我选择写一个递增计数器,就像这样:
012345678901234567890123456789……
我将程序加载到TINI上并运行它。我立刻知道我的打印机初始化例程工作了,因为我可以听到打印头在脱机和重新联机时的移动。但几秒钟后,什么也没有打印出来。我重新设置了程序,开始再三检查我的网络连接。不幸的是,我没有一个范围来监视来自打印机的状态信号。一切看起来都很好,所以接下来我又翻开了我那本值得信赖的PC硬件指南。我又读了一遍,发现了一些信号极性上的混淆。例如,传统的PC接口说BSY是活动的,值为0,尽管在硬件级别它实际上是一个活动的高电平。在对不同信号进行不同反转的C程序进行多次迭代后,打印机在初始化后仍然处于沉默状态。我又遍历了一次程序,使逻辑级别与我认为打印机应该表现的方式相匹配。我又查了一遍,还是一无所获。
当我听到这个声音时,我走开了:点阵打印机打出一行文字时发出的激烈而激动的声音。我跑回去,看到一行漂亮的字,虽然打印机又完全静止了。然后我想到了一个理论:打印机一直缓冲到一行的末尾,不管它是否达到了80个字符的限制,或者我在数据流中插入了一个行尾序列。几分钟的工作就证实了那个理论。我现在打印的是简单的文本字符串。
第二天,我决定将网络连接到打印机接口。简单的答案是创建一个自定义应用程序,该应用程序仅从网络接收数据并将其输出到打印机。这种方法有一个问题:要使打印机与MS Word一起工作,我还需要编写一个windows打印机驱动程序——这一点我可能会弄清楚,但并不完全是我的乐趣所在。因此,我开始考虑那些我不会重新发明轮子的选择,希望不要学习所有关于打印机驱动程序的细节。
我理想的设计是一个虚拟的并口。这里的想法是,虚拟并行端口提供与普通并行端口相同的接口,但是在驱动程序级别上,它实际上是通过网络向TINI发送和接收数据。像这样的虚拟端口和协议转换器是TINI的常见应用程序,并且我有一些按照相同思想实现虚拟串行端口的经验。我很难确定如何实现这一点,因为似乎许多应用程序直接写入PC的并行寄存器。我的下一个选择是查看现有的协议。根据一位同事的建议,我研究了RFC 1179,即行打印机守护进程(LPD)协议
LPD正是我所需要的。它是UNIX世界中普遍支持的一种网络协议,但在Windows中也可以使用,只需执行几个简单的配置步骤。要安装驱动程序,您告诉Windows安装一个新的本地打印机连接到您的计算机,但不是告诉它使用哪个现有的端口,而是创建一个新的类型LPR港口。在这里,您可以配置运行LPD服务器的机器的名称(在我的例子中是我的TINI的IP地址),并告诉它打印队列的名称。(我只有一个名为“crusty”的打印队列,我认为这适合我的打印机。)最后,告诉Windows你用的是哪种打印机(我用的是爱普生LX-800)。
这种设置的好处是,Windows打印机驱动程序会自动以打印机的自然语言Epson ESC/P格式化所有要打印的数据。我不需要学习任何关于ESC/P语言的知识,也不需要解析从PC到达TINI的任何数据。此外,基本的LPD服务器非常容易实现;我用Java实现了它,使用了一些本地方法来访问内存映射的CPLD。结果是实际代码大约有400行,而为TINI准备的Java类文件只有大约4kB。注意,我没有实现整个LPD协议,只实现了一次打印一个文件所需的部分。
我认为我需要做三件事来完成这个项目:用记事本打印,用MS Word打印,然后,如果我真的有野心的话,打印一个小的GIF或JPG文件。在对我的LPD服务器进行了一些调试之后,我很高兴地从记事本打印文件。对我来说,一个2行文本文件向TINI发送大约5000字节用于打印确实很奇怪。原因是Windows驱动程序将整个文件转换为ESC/P指令来写入位图图像,而不是简单地发送ASCII字符。不过,用记事本打印还行,所以我改用了微软的Word。
用MS Word打印就有点问题了。为了使我的测试文件更有趣,我每隔两个或三个单词就使用不同的字体,借此机会看到一些我以前从未见过的字体。当我打印时,出现了很多垃圾:打印机跳过了几行,打印出了一些奇怪的ASCII图形字符(范围从0x80到0xFF),并且发出了很多哔哔声。最终,出现了一些正确的文本,但随后出现了更多的垃圾。经过几轮调试和跟踪发送到TINI的ESC/P指令后,我决定尝试为转义字符添加延迟。这使得程序打印正确,但非常慢。经过更多的实验,我发现我只需要在遇到行结束符时延迟。这种情况很少发生,所以我并没有真正注意到任何延迟。
由于在MS Word中打印比较困难,我决定打印GIF文件几乎是不可能的,结果证明并非如此。我只遇到了一个问题:翻译成ESC/P指令的GIF文件大于64k,这是我使用的TINI版本支持的最大动态缓冲区大小。但是,TINI支持没有此类限制的文件系统,因此我将传入的数据存储在文件中,而不是动态内存缓冲区中。一旦进行了更改,我就可以毫无问题地打印图形文件,只是受限于我的TINI上的RAM大小。
我给了我的点阵打印机第二次生命。蒂尼挽救了局面。其易于编程的堆栈使其成为使传统设备联网的绝佳选择。TINI的用处不仅限于将并行设备连接到网络;支持CAN, SPI, I²C, RS-232, 1-Wire和许多其他通信总线,使其成为桥接网络到各种传统设备的完美选择。有了对网络协议(如DHCP、HTTP、FTP、Telnet、DNS等)的软件支持,就有许多可扩展的方法来提供对旧设备的熟悉访问方式(如网页)。当昂贵的旧设备需要更多的可访问性时,TINI是一个很好的选择。(如今,新的点阵打印机的价格约为400美元!)所以不要扔掉你的旧垃圾。用TINI来保存。
Hans-Peter Messmer:不可或缺的PC硬件书(艾迪生·韦斯利,1994)。
²RFC 1179: LPD协议www.faqs.org/rfcs/rfc1179.html
一篇类似的文章出现在网上电路地窖, 192(2006年7月)。
社群二维码
关注“华强商城“微信公众号
Copyright 2010-2023 hqbuy.com,Inc.All right reserved. 服务热线:400-830-6691 粤ICP备05106676号 经营许可证:粤B2-20210308