最近在Jetson Nano上发现个问题,插多个USB-TTL后,串口号会发生变化。看来笔者之前
C/C++语言读写UART或USB串口数据正在上传…重新上传取消https://blog.youkuaiyun.com/qq_25662827/article/details/122581819的同学应该都知道,笔者在代码中是将端口号写死了的。
面对多变的串口,我们应该怎么办呢?本篇笔者就分享一下,使用C/C++获取可用串口的方法。
之前也说过,LIUNX下万物皆文件,每个串口的注册实际上就会生成一个文件,我们要获取可用串口,也就是要查找当前的文件名。废话不多说,还是先献上代码:
-
#include <stdlib.h> -
#include <dirent.h> -
#include <stdio.h> -
#include <sys/types.h> -
#include <sys/stat.h> -
#include <unistd.h> -
#include <string.h> -
#include <fcntl.h> -
#include <termios.h> -
#include <sys/ioctl.h> -
#include <linux/serial.h> -
#include <iostream> -
#include <list> -
using namespace std; -
static string get_driver(const string& tty); -
static void register_comport( list<string>& comList, list<string>& comList8250, const string& dir); -
static void probe_serial8250_comports(list<string>& comList, list<string> comList8250); -
list<string> getComList(); -
int main() { -
list<string> l = getComList(); -
list<string>::iterator it = l.begin(); -
while (it != l.end()) { -
cout << *it << endl; -
it++; -
} -
return 0; -
} -
static string get_driver(const string& tty) { -
struct stat st; -
string devicedir = tty; -
// Append '/device' to the tty-path -
devicedir += "/device"; -
// Stat the devicedir and handle it if it is a symlink -
if (lstat(devicedir.c_str(), &st)==0 && S_ISLNK(st.st_mode)) { -
char buffer[1024]; -
memset(buffer, 0, sizeof(buffer)); -
// Append '/driver' and return basename of the target -
devicedir += "/driver"; -
if (readlink(devicedir.c_str(), buffer, sizeof(buffer)) > 0) -
return basename(buffer); -
} -
return ""; -
} -
static void register_comport( list<string>& comList, list<string>& comList8250, const string& dir) { -
// Get the driver the device is using -
string driver = get_driver(dir); -
// Skip devices without a driver -
if (driver.size() > 0) { -
string devfile = string("/dev/") + basename(dir.c_str()); -
// Put serial8250-devices in a seperate list -
if (driver == "serial8250") { -
comList8250.push_back(devfile); -
} else -
comList.push_back(devfile); -
} -
} -
static void probe_serial8250_comports(list<string>& comList, list<string> comList8250) { -
struct serial_struct serinfo; -
list<string>::iterator it = comList8250.begin(); -
// Iterate over all serial8250-devices -
while (it != comList8250.end()) { -
// Try to open the device -
int fd = open((*it).c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY); -
if (fd >= 0) { -
// Get serial_info -
if (ioctl(fd, TIOCGSERIAL, &serinfo)==0) { -
// If device type is no PORT_UNKNOWN we accept the port -
if (serinfo.type != PORT_UNKNOWN) -
comList.push_back(*it); -
} -
close(fd); -
} -
it ++; -
} -
} -
list<string> getComList() { -
int n; -
struct dirent **namelist; -
list<string> comList; -
list<string> comList8250; -
const char* sysdir = "/sys/class/tty/"; -
// Scan through /sys/class/tty - it contains all tty-devices in the system -
n = scandir(sysdir, &namelist, NULL, NULL); -
if (n < 0) -
perror("scandir"); -
else { -
while (n--) { -
if (strcmp(namelist[n]->d_name,"..") && strcmp(namelist[n]->d_name,".")) { -
// Construct full absolute file path -
string devicedir = sysdir; -
devicedir += namelist[n]->d_name; -
// Register the device -
register_comport(comList, comList8250, devicedir); -
} -
free(namelist[n]); -
} -
free(namelist); -
} -
// Only non-serial8250 has been added to comList without any further testing -
// serial8250-devices must be probe to check for validity -
probe_serial8250_comports(comList, comList8250); -
// Return the lsit of detected comports -
return comList; -
}
笔者将代码文件命名为find.cpp,因此用命令行编译为
g++ -o find.o find.cpp
测试
在Jetson Nano B01下进行测试。
在没有插入设备的时候,由于板子自带了RX TX引脚,因此能获得三个串口设备

然后,插上了USB-TTL后,可以得到

多了个ttyUSB1。
优化
这个方法在单端口设备的时候挺有用,我们的目标仅仅是获取ttyUSB*,怎么办呢?我们只需要在main里面做改动。
-
while (it != l.end()) { -
// cout << *it << endl; -
string temp = *it; -
cout << temp << endl; -
if(temp.find("/dev/ttyUSB") != string::npos) -
cout << "1" << endl; -
it++; -
}
这段代码,实现了当发现ttyUSB*的时候就打个1出来。测试情况如下:

其他改动,就留给读者结合自己的项目情况自行展开了吧。
闲谈
那么多端口设备怎么办?笔者的方法的话,会再加个端口信息校验。当连接上串口后,通过接收到设备信息来进行设备身份识别。具体的实现方法就读者自己完善吧,自己动手,丰衣足食。

6738

被折叠的 条评论
为什么被折叠?



