不能再详细的Ubuntu 多USB转串口教程
【引言】
做Ubuntu开发有一段时间了,难免要接触很多的USB转串口设备,无论是USB转RS232还是USB转RS485,都在项目中进行了应用。在开发过程中有两个问题令人十分苦恼,在经历多次项目的经验教训之后,准备撰写博客记录一下。具体问题描述如下:
(1)如何在ubuntu中固定串口设备的串口号?
方法:利用idVendor与idProduct进行识别(详见第一部分)
(2)串口设备的idVendor与idProduct相同(来自同一芯片或根本就是两个一模一样的设备),如何区分?
方法:软的不行,来硬的!(详见第二部分)
(3)串口收发的示例程序?
这个有时间再写
如果你也遇到了类似问题,不妨深入阅读一下。言归正传,正式开始~
(一)如何在ubuntu中固定串口设备的串口号?
问题分析
我们都知道,Window插入USB串口设备会自动分配给其COM口,而且是自动且随机排序的,Ubuntu也是如此,插入一个USB转串口设备,会自动为其分配 /dev/ttyUSB0 这个名字,对于只有一个串口设备的应用来说,我们代码里可以直接调用 /dev/ttyUSB0 这个名字就好。
但是,如果是多个串口设备,比如我们研究机器人,其底层驱动是串口,IMU是串口,有时候加个GPS他也是串口的,这时候怎么办呢?
你可能会说:新加入的设备是会以 /dev/ttyUSB1 和 /dev/ttyUSB2 等命名,这是由挂载顺序决定的,谁先挂载,谁就是那个USB0,我们依然可以进行区分。但是,这仅限于一次使用。一般情况下,我们开发好设备后硬件就不再改变了,而每次“底层驱动”、“IMU”、“GPS”在开机重新启动后,由于都已经挂载在主机上,会争相竞争 /dev/ttyUSB0 ,因此串口设备的名字就会造成混乱,写好的代码也不再工作了。因为他脑海中的那个USB0,可能已经由“底层驱动”变成“IMU”了。
问题解决
要解决这个问题,我们可以从USB转串口的“身份证”出发。使用lsusb
命令可查看挂载的USB设备信息,如下:
未挂载USB转串口设备:
Bus 001 Device 002: ID 8087:8001 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 002: ID 2109:8110 VIA Labs, Inc. Hub
Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 002 Device 008: ID 04f2:b449 Chicony Electronics Co., Ltd
Bus 002 Device 007: ID 8087:0a2a Intel Corp.
Bus 002 Device 005: ID 138a:0017 Validity Sensors, Inc. Fingerprint Reader
Bus 002 Device 003: ID 046d:c52f Logitech, Inc. Unifying Receiver
Bus 002 Device 006: ID 046d:c534 Logitech, Inc. Unifying Receiver
Bus 002 Device 004: ID 045e:028e Microsoft Corp. Xbox360 Controller
Bus 002 Device 002: ID 2109:2811 VIA Labs, Inc. Hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
已挂载USB转串口设备:
Bus 001 Device 002: ID 8087:8001 Intel Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 002: ID 2109:8110 VIA Labs, Inc. Hub
Bus 003 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 002 Device 008: ID 04f2:b449 Chicony Electronics Co., Ltd
Bus 002 Device 007: ID 8087:0a2a Intel Corp.
Bus 002 Device 005: ID 138a:0017 Validity Sensors, Inc. Fingerprint Reader
Bus 002 Device 003: ID 046d:c52f Logitech, Inc. Unifying Receiver
Bus 002 Device 006: ID 046d:c534 Logitech, Inc. Unifying Receiver
Bus 002 Device 004: ID 045e:028e Microsoft Corp. Xbox360 Controller
Bus 002 Device 011: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
Bus 002 Device 010: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
Bus 002 Device 002: ID 2109:2811 VIA Labs, Inc. Hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
所多出来的正是两个串口设备,USB-Serial就是他们身份的象征。
Bus 002 Device 011: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
Bus 002 Device 010: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
这里,两个串口设备的“身份证”就是 ID 0403:6001 和 ID 1a86:7523 了。之所以这两个设备的“身份证”不同,是因为芯片厂家不同(FT232 和 HL-340),因此我们可以得到第一种固定串口设备的串口号的方法。
(1)如何在ubuntu中固定串口设备的串口号?
USB设备的规则,都存储在**/etc/udev/rules.d**文件夹下,我们可以进入此文件夹,新建一个规则
sudo gedit myrobot.rules
在打开的文件中,输入如下指令,保存即可。
KERNEL=="ttyUSB*", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE:="0777", GROUP:="dialout", SYMLINK+="tty_mbot"
KERNEL=="ttyUSB*", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="1a86", MODE:="7523", GROUP:="dialout", SYMLINK+="tty_arduino"
解析:MODE:="0777"表示给最高权限,SYMLINK+=“tty_mbot”、SYMLINK+="tty_arduino"是给设备起一个新名字。
重新插拔设备后,用以下命令即可查看串口设备是否被改名。
ls -l /dev/tty_mobt
ls -l /dev/tty_arduino
(二)如何在ubuntu中固定多个相同串口设备的串口号?
刚才的例子可以固定两个不同的串口设备,那如果是同一串口设备,其idVendor与idProduct相同(来自同一芯片或根本就是两个一模一样的设备),如何区分呢?这就需要第二个方法——硬串口。
首先先看一个rules文件的实例,来说明这个问题。
KERNEL=="ttyUSB*",KERNELS=="1-2.3.2:1.0", MODE:="0777", GROUP:="dialout", SYMLINK+="tty_guide_front"
KERNEL=="ttyUSB*",KERNELS=="1-2.3.1:1.0", MODE:="0777", GROUP:="dialout", SYMLINK+="tty_guide_back"
这里的KERNELS就是硬串口方法,其核心原理就是我们能通过一条神奇指令,知道我们的串口设备具体是挂在哪个物理接口上的,无论是直连主机,还是接上了多少个hub,都可以轻松找到,指令如下:
udevadm info --attribute-walk --name=/dev/ttyUSB0 |grep KERNELS
但运用这条指令之前,需要知道目前设备是ttyUSB0还是ttyUSB1,还是其他……,可以只连接这一个设备,然后用 ls -l /dev/ttyUSB*
查看。
至此,硬串口的配置就算完成,但使用硬串口时需要注意,当设备重新插拔后,一定要接到原来的端口,否则会找不到哦~
(三)脚本文件用于快速配置
如果你在配置串口的过程中,不想去找/etc/udev 文件夹,也可以参考我的写法利用脚本文件进行配置,我所配置tty_dev.sh文件如下:
# tty_dev.sh
echo 'KERNEL=="ttyUSB*", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE:="0777", GROUP:="dialout", SYMLINK+="tty_arduino"' >/etc/udev/rules.d/tty_arduino.rules
echo 'KERNEL=="ttyUSB*",KERNELS=="1-2.3.2:1.0", MODE:="0777", GROUP:="dialout", SYMLINK+="tty_guide_front"
KERNEL=="ttyUSB*",KERNELS=="1-2.3.1:1.0", MODE:="0777", GROUP:="dialout", SYMLINK+="tty_guide_back"' >/etc/udev/rules.d/guide.rules
service udev reload
sleep 2
service udev restart