Ruby 的 Win32 串口





5.00/5 (3投票s)
适用于 Ruby 的 Win32 串行端口类。
引言
Win32SerialPort::SerialPort
是一个简单的 Ruby 类,用于访问 Windows 上的串行端口。此类使用标准的 Win32 API,不需要任何外部 C/C++ 库。
使用代码
此代码已在 Windows XP、Ruby 1.8.6 和 Win32API gem 1.4.8 上进行了测试。
1. 创建并打开串行端口
串行端口类存储在 win32serial
模块中,并封装在 Win32SerialPort
命名空间中。使用 require
将模块附加到脚本。
require "win32serial"
使用 new
函数创建串行端口对象实例,如下所示:
serial = Win32SerialPort::SerialPort.new
下一步是打开串行端口并使其准备好使用。例如,您可能希望以 115200,8,n,1 模式打开 COM1,而不使用流控制模式(波特率:115200,8 数据位,无校验,1 停止位)。以下示例可以完成此操作:
# Open COM1 serial port in 115200,8,n,1 mode without flow control
return 0 if false == serial.open(
"COM1", # port name
115200, # baudrate
Win32SerialPort::FLOW_NONE, # no flow control
8, # 8 data bits
Win32SerialPort::NOPARITY, # no parity bits
Win32SerialPort::ONESTOPBIT) # one stop bit
传递给函数的参数将按原样传递给 Windows 库,如果打开失败,则归咎于 Windows 的限制。如果无法打开串行端口,open
函数将返回 false
,当串行端口准备好使用时,返回 true
。
要启用硬件流控制,请使用 FLOW_HARDWARE
开关而不是 FLOW_NONE
。
要切换校验,请使用标志 NOPARITY
、ODDPARITY
、EVENPARITY
、MARKPARITY
和 SPACEPARITY
。
要更改停止位数,可以选择:
ONESTOPBIT
– 一个停止位ONE5STOPBITS
- 1.5 个停止位TWOSTOPBITS
– 两个停止位
数据位数必须是 5 到 8 位。
使用 5 个数据位和 2 个停止位是一种无效组合,同样 6、7 或 8 个数据位和 1.5 个停止位也是无效组合。
使用 close
函数关闭串行端口。
有一个选项可以配置串行端口超时。Windows API 中的 COMMTIMEOUTS
结构定义了五个超时:ReadIntervalTimeout
、ReadTotalTimeoutMultiplier
、ReadTotalTimeoutConstant
、WriteTotalTimeoutMultiplier
和 WriteTotalTimeoutConstant
。
以下示例将前三个读取超时设置为 0,将最后两个写入超时设置为 100ms 和 1000ms。这些超时作为包含 5 个数字的表传递给 setCommTimeouts
函数。
# Configure serial port read/write timeouts
timeouts = [0,0,0,100,1000]
result = serial.setCommTimeouts(timeouts)
print "\nSetCommTimeouts result: " + result.to_s + "\n\n"
2. 准备要发送的数据
Ruby 语言的特殊性导致要发送的数据需要特别准备。这一段更多的是关于如何准备数据,而不是关于使用串行端口类本身。如果您熟悉 Array::pack
和 String::unpack
方法,可以跳过此段。
Ruby 中的 Array
是一个对象,不能被解释为字节流,而是在将参数传递给 Windows 内核时需要这样。这意味着要发送到串行端口的数据必须提前准备好。
Ruby 库中有两个函数有助于将数据从数组转换为字节流,以及将字节流转换回数组格式。第一个在传输时有用,第二个在接收字节时有用。
Array
类实例的每个项可能有不同的类型,也意味着不同的大小。Array
类有一个 pack
方法,该方法将数组的项作为字节字符串返回。数组的每一项在字符串中占用所需的字节数,并且每一项一个接一个地放置。pack
方法不知道如何解释其项。因此,该方法接受一个称为 formatter
的参数,该参数描述如何格式化项。例如,‘i’ 表示有符号整数,‘f’ 表示浮点数,‘a’ 表示字符串。所有格式化程序都在 pack
方法文档中有描述。
当从串行端口接收到数据时,它表示为字节字符串。每个期望从串行端口接收数据的应用程序也知道如何解析接收到的字节,并知道如何从该字符串中提取信息。String
类有一个 unpack
方法,该方法接受格式化程序参数(与前面提到的 pack
方法具有相同的开关),描述如何解释接收到的字节。该方法返回一个 Array
类实例,其中包含根据格式化程序参数从二进制字符串中提取的项。
例如,准备一个包含两个整数和一个字符字符串的二进制字符串。首先,创建一个数组:
toSend = [4,7,"Hello World!"]
数组 toSend
有三个项。两个整数(4、7)和一个字符串(Hello World!)。
必须按如下方式将数组转换为二进制字符串:
binaryString = toSend.pack("iia12")
“iia12” 是格式化程序参数,它告诉 pack
方法如何解释存储在 toSend
数组中的项。‘i’ 是有符号整数,‘a12’ 是 12 个字节的字符串。结果,binaryString
包含 20 个字节:每个整数 4 个字节(32 位 Windows)和 12 个字符字节。
binaryString
包含已准备好发送格式的数据。
3. 发送数据
write
方法只接受一个参数。该参数是一个字符串。这里有一些示例:
- 发送一个简单的字符串
# send simple string
written = serial.write(“Hello World!”)
# one character “7”
i = 7
written = serial.write(i.to_s)
# two characters: 7 and 6
i = 76
Written = serial.write(i.to_s)
# an array of items
toSend = [4,7,"Hello World!"]
# the array of items converted to a binary string
binaryString = toSend.pack("iia12")
# send the binary string
written = serial.write(binaryString)
#
# Test if data has been sent
if 0 < written
print "Data has been successfully sent\n"
else
print "Could not send data\n"
end
write
方法返回已发送的字节数。
4. 接收数据
该类中有两个方法允许读取接收到的字节。read
方法尝试读取输入参数中指定的字节数。它会立即返回输入缓冲区中可用的字节,但不会超过指定数量。
第二个方法 readUntil
会阻塞程序的执行,直到读取指定的字节数。如果串行端口已关闭,它将返回比指定字节数少的字节。如果串行端口超时设置为不等待数据,readUntil
将立即返回可读取的字节。
这两个函数都返回一个包含接收到的字节的二进制字符串。请参阅“准备要发送的数据”段落,了解如何解析/解释接收到的数据。示例:
- 读取所有可用(已接收)字节
# Reads as many bytes as it is stored in
# the input buffer of the serial port.
binString = serial.read
if binString.length > 0
print "Received data: " + binString + "\n"
else
print "Nothing received\n"
end
# Returns 10 or less bytes of data
binString = serial.read(10)
if binString.length > 0
print "Received " + binString.length.to_s + " bytes\n"
else
print "Nothing received\n"
end
# blocks until 10 bytes is available
binString = serial.readUntil(10)
# test the length in case if the serial port has been closed
if binString.length > 0
print "Received " + binString.length.to_s + " bytes\n"
else
print "Nothing received\n"
end
该类中有一个 bytesToRead
属性,它返回可从串行端口接收缓冲区读取的字节数。
bytesAvailable = serial.bytesToRead
print "\nBytes available to read: " + bytesAvailable.to_s + "\n"
binString = serial.readUntil(bytesAvailable)
5. 缺失的功能
例如,简单查看 Microsoft .NET 库中的 System.IO.Ports.SerialPort
类,就可以发现此处描述的类缺少一些有趣的功能。最重要的可能是:
- 实现 IO 接口,
- 以及访问调制解调器引脚(DCD、DTR 等)