Linux授权普通用户读写 ttyUSB (USB2Serial)

现在的笔记本一般都不带串行端口(RS232)了,而且市面上带串口的笔记本也很贵,不划算。对于需要经常使用串口调试设备的人,多使用USB转串口了。购买一条转换线也就30元左右,Windows需要安装驱动,而Linux系统一般可以直接识别,但是默认只有 root 角色拥有使用权限,非常不方便!但是你可以参照如下设置修改权限。

一、Linux 下查看 USB2Serial 是否已经识别

Code example:

1

ls -l /dev/ttyUSB*

二、Linux授权普通用户读写 ttyUSB
  1. 创建一个Udev规则,内容如下:

    Code example:

    1

    2

    cat /etc/udev/rules.d/70-ttyUSB.rules

    KERNEL=="ttyUSB*", OWNER="root", GROUP="root", MODE="0666"

  2. 重新启动Udev服务:

    Code example:

    1

    /etc/init.d/udev restart

  3. 重新插拔 USB2Serial 线。

现在你用普通用户试试 minicom,是不是可以访问了?
你也可以查看下 ttyUSB 的权限 ls -l /dev/ttyUSB*,是不是 0666 啦!

Linux下对于其他硬件设备的权限授予,也可以参照此文举一反三

<think>好的,我现在需要帮用户分析如何将提供的C++代码封装成一个类,实现串口设备的自动识别和分配。首先,我得仔细看看用户提供的代码和需求。 用户给出的代码片段中,有三个设备(AHRS、GPS、ADM)通过不同的/dev/ttyUSBX端口连接。当前代码是手动指定每个设备的端口,比如device_ahrs是USB0,device_gps是USB1,device_adm又是USB0,这可能有问题,因为同一端口被多个设备使用?或者可能是用户笔误?不过用户现在的需求是希望自动识别串口,根据接入顺序自动分配USB0、1、2,这样哪个设备先插入就分配较小的编号,避免手动指定。 首先,我需要理解用户的需求:当有多个串口设备插入时,系统会分配ttyUSB0、ttyUSB1等设备节点,但插入顺序不同可能导致设备节点变化。用户希望程序能自动识别这些设备,并根据它们的插入顺序(即设备节点号)自动分配对应的功能,比如先插入的作为AHRS,接着是GPS,然后是ADM。或者,可能是指无论设备插入顺序如何,程序能自动检测并正确分类每个设备的类型,然后分配对应的处理逻辑? 这里可能需要进一步澄清,但根据用户描述,“哪个串口先接入就先分配USB0,1,2这样依次”,可能是指设备插入的顺序决定了分配的USB编号。比如,先插入的设备会被系统识别为ttyUSB0,第二个是ttyUSB1,依此类推。因此,用户希望程序在启动时自动检测当前连接的设备,并按照它们被系统分配的顺序(USB0、USB1等)来分别对应AHRS、GPS、ADM设备。但问题是,如何确定哪个物理设备对应哪个功能?比如,如何区分哪个是AHRS,哪个是GPS? 可能用户假设每个设备类型有固定的标识,例如通过读取设备的某些信息(如ID、数据格式)来识别设备类型,然后自动分配对应的处理逻辑。或者,用户可能希望根据插入顺序来分配,比如第一个插入的作为AHRS,第二个作为GPS,第三个作为ADM,而不管它们实际是什么设备。但这样可能会有问题,因为设备插入顺序可能变化,导致功能错乱。 如果用户希望的是自动识别设备类型,并根据类型分配对应的处理,那么需要在代码中加入设备检测的逻辑,例如发送查询指令或读取设备返回的数据来确定类型。这可能比较复杂,需要设备支持某种识别协议。 但根据用户的问题描述,可能更倾向于根据插入顺序自动分配USB0、1、2,而不需要区分设备类型。例如,无论插入的是什么设备,先连接的作为USB0,分配给AHRS,第二个是USB1给GPS,第三个USB2给ADM。这可能适用于固定数量的设备,且每次插入顺序确定的情况。但这样如果设备数量不够或者顺序变化,可能会有问题。 但用户提供的代码中,device_adm也被设置为USB0,这可能是一个错误,或者用户希望多个设备共享同一个端口?这显然不行,因为一个串口同一时间只能被一个进程访问。所以这可能是一个代码错误,用户需要修正。 现在,用户希望将这些代码封装成一个类,自动管理串口的识别和分配。那么,我需要考虑以下几点: 1. 如何自动检测当前系统中存在的ttyUSB设备,并按照它们的接入顺序(即设备节点号)进行排序。 2. 将这些设备分配给不同的处理实例(AHRS、GPS、ADM),可能按照检测到的顺序,或者根据设备类型。 3. 封装串口配置、线程启动、数据处理等逻辑到一个类中,提高代码的复用性和可维护性。 假设用户希望按照检测到的设备节点顺序来分配,比如先检测到ttyUSB0作为AHRS,ttyUSB1作为GPS,ttyUSB2作为ADM,那么需要程序在启动时扫描/dev/ttyUSB*设备,然后按数字顺序排列,依次分配给各个设备类型。但这样需要确保三个设备都正确连接,否则可能会有缺失。 或者,可能用户希望动态检测,当设备插入时自动识别并分配。这可能需要使用udev规则或文件系统监控,但会增加复杂度。 对于初步封装,可能先实现静态检测,即在程序启动时扫描现有的ttyUSB设备,并按顺序分配。例如,获取所有存在的ttyUSB设备,排序后依次分配给AHRS、GPS、ADM。如果设备数量不足,则报错。 步骤一:创建一个类,比如SerialManager,负责管理所有串口设备。 这个类需要: - 自动检测可用的ttyUSB设备,并按数字顺序排序。 - 为每个检测到的设备分配对应的功能(AHRS、GPS、ADM)。 - 管理串口的配置、读取线程、数据处理线程的启动和停止。 - 处理可能的错误情况,如设备未找到,配置失败等。 步骤二:设备检测的实现。 在Linux系统中,可以通过遍历/dev目录下的ttyUSB*设备,提取数字部分,排序后得到当前连接的设备列表。例如,使用glob函数或opendir读取/dev目录,筛选出ttyUSB*的文件,然后提取数字,排序得到顺序。 步骤三:将检测到的设备列表按顺序分配给不同的设备类型。例如,第一个设备(ttyUSB0)作为AHRS,第二个(ttyUSB1)作为GPS,第三个(ttyUSB2)作为ADM。如果设备数量不够,则初始化失败。 步骤四:封装ConfigureSerialPort、StartReading、ProcessData等方法到类中,每个设备实例可能需要单独的reader和线程。 现在需要考虑原来的代码中有三个reader对象:reader(AHRS)、reader_gps(GPS)、reader_adm(ADM),每个对应不同的设备。在封装后的类中,可能需要为每个设备类型维护一个实例,或者使用容器管理多个实例。 可能的类结构: class SerialManager { private: std::vector<std::string> detected_devices; std::map<DeviceType, gpscomRead> readers; std::map<DeviceType, std::thread> process_threads; // 其他成员变量,如是否需要停止标志等 public: bool initialize(); void startAll(); void stopAll(); // 其他方法 }; 其中,DeviceType可以是枚举,如AHRS, GPS, ADM。 但需要确定每个设备类型对应的设备路径,这需要在initialize方法中检测并分配。 或者,动态检测设备类型:比如,尝试与每个设备通信,根据返回的数据判断设备类型。这需要设备有特定的响应或标识,可能不现实,除非设备有标准查询方式。 如果无法自动识别设备类型,只能根据顺序分配,那么用户需要确保插入顺序正确。例如,先插入AHRS设备,然后是GPS,最后是ADM。这样,程序检测到的ttyUSB0是AHRS,ttyUSB1是GPS,ttyUSB2是ADM。 这种情况下,SerialManager类在初始化时需要检查至少有三个设备,然后按顺序分配。如果设备数量不足,则报错。 接下来,原来的代码中有三个不同的reader实例,每个对应不同的设备和处理线程。在封装后的类中,可能需要将这些实例作为成员变量,或者使用容器存储。 例如: class SerialManager { private: std::vector<gpscomRead> readers; std::vector<std::thread> process_threads; // 其他成员 }; 但每个reader需要关联特定的设备路径和设备类型。或者,可以创建一个结构体,包含设备路径、类型、reader实例等。 另外,原来的代码中,ConfigureSerialPort的第二个参数可能是用来标识设备类型的,比如0代表AHRS,1代表GPS,2代表ADM。例如: reader.ConfigureSerialPort(device_ahrs, 0); reader_gps.ConfigureSerialPort(device_gps, 1); reader_adm.ConfigureSerialPort(device_adm, 2); 所以,在封装时,可能需要为每个检测到的设备调用ConfigureSerialPort,并传入对应的类型参数。 但原来的代码中,device_adm被设置为USB0,与device_ahrs相同,这可能是个错误,导致两个设备使用同一个端口,这在实际情况中会导致冲突。所以用户可能需要修正这个问题,确保每个设备使用不同的端口。 现在,假设每个设备使用不同的端口,并且ConfigureSerialPort的第二个参数代表设备类型(0=AHRS,1=GPS,2=ADM),那么在自动分配时,需要按检测到的设备顺序,依次为每个设备分配类型参数。 例如,检测到三个设备:ttyUSB0, ttyUSB1, ttyUSB2。那么: - ttyUSB0 -> type 0 (AHRS) - ttyUSB1 -> type 1 (GPS) - ttyUSB2 -> type 2 (ADM) 然后,为每个设备创建gpscomRead实例,调用ConfigureSerialPort,并启动线程。 因此,SerialManager类可能需要维护一个设备列表,每个设备对应一个gpscomRead实例和一个处理线程。 现在,关于自动识别设备插入顺序的问题,如何获取当前连接的ttyUSB设备并按数字排序? 在Linux中,可以使用glob函数来获取所有匹配/dev/ttyUSB*的文件,然后提取数字部分进行排序。例如: #include <glob.h> #include <vector> #include <string> #include <algorithm> std::vector<std::string> detect_serial_devices() { glob_t glob_result; glob("/dev/ttyUSB*", GLOB_TILDE, nullptr, &glob_result); std::vector<std::string> devices; for (size_t i = 0; i < glob_result.gl_pathc; ++i) { devices.emplace_back(glob_result.gl_pathv[i]); } globfree(&glob_result); // 排序,按数字升序 std::sort(devices.begin(), devices.end(), [](const std::string& a, const std::string& b) { // 提取数字部分比较 int num_a = std::stoi(a.substr(strlen("/dev/ttyUSB"))); int num_b = std::stoi(b.substr(strlen("/dev/ttyUSB"))); return num_a < num_b; }); return devices; } 这样得到的devices列表是按ttyUSB数字升序排列的。 在SerialManager的initialize函数中,可以调用这个函数,检查设备数量是否足够(比如至少3个),然后分配。 接下来,原来的代码中每个reader实例需要调用ConfigureSerialPort、StartReading,并启动处理线程。 所以,在封装后的类中,可能需要为每个检测到的设备创建gpscomRead实例,配置,启动线程,并保存这些实例和线程。 假设用户有三个设备需要处理,那么在SerialManager类中,可以有一个成员变量是三个gpscomRead对象,或者一个vector,但需要对应到AHRS、GPS、ADM。 或者,可以用一个map,将设备类型映射到对应的reader和线程。 但可能更简单的是,假设检测到的设备顺序对应设备类型,即第一个设备是AHRS,第二个是GPS,第三个是ADM。因此,在SerialManager中,可以有三个gpscomRead成员:ahrs_reader, gps_reader, adm_reader,并在初始化时根据检测到的设备列表进行配置。 例如: class SerialManager { private: gpscomRead ahrs_reader; gpscomRead gps_reader; gpscomRead adm_reader; std::thread ahrs_process_thread; std::thread gps_process_thread; std::thread adm_process_thread; bool initialized = false; public: bool initialize() { auto devices = detect_serial_devices(); if (devices.size() < 3) { std::cerr << "检测到不足3个串口设备" << std::endl; return false; } // 配置AHRS(第一个设备) if (!ahrs_reader.ConfigureSerialPort(devices[0].c_str(), 0)) { std::cerr << "配置AHRS失败" << std::endl; return false; } // 配置GPS(第二个设备) if (!gps_reader.ConfigureSerialPort(devices[1].c_str(), 1)) { std::cerr << "配置GPS失败" << std::endl; return false; } // 配置ADM(第三个设备) if (!adm_reader.ConfigureSerialPort(devices[2].c_str(), 2)) { std::cerr << "配置ADM失败" << std::endl; return false; } initialized = true; return true; } void startAll() { if (!initialized) { std::cerr << "未初始化" << std::endl; return; } ahrs_reader.StartReading(); gps_reader.StartReading(); adm_reader.StartReading(); ahrs_process_thread = std::thread(&gpscomRead::ProcessData, &ahrs_reader); gps_process_thread = std::thread(&gpscomRead::ProcessData, &gps_reader); adm_process_thread = std::thread(&gpscomRead::ProcessData, &adm_reader); } void stopAll() { ahrs_reader.StopReading(); gps_reader.StopReading(); adm_reader.StopReading(); if (ahrs_process_thread.joinable()) ahrs_process_thread.join(); if (gps_process_thread.joinable()) gps_process_thread.join(); if (adm_process_thread.joinable()) adm_process_thread.join(); } }; 这样,在主函数中,可以创建SerialManager实例,调用initialize、startAll,然后等待用户输入,最后stopAll。 但这样还是硬编码了三个设备,不够灵活。如果设备数量变化,或者需要动态添加,可能需要更动态的处理。不过根据用户的需求,可能三个设备是固定的,所以这种方式可以接受。 但原来的代码中,某些部分被注释掉了,比如AHRS和GPS的配置和启动。用户可能希望根据实际连接的设备数量来动态处理,比如如果有两个设备,只启动两个,或者按需分配。但根据问题描述,用户希望自动分配USB0、1、2,可能要求三个设备必须全部连接。 另一个问题是,原来的代码中,device_adm被设置为device_ahrs同一个端口,这可能是错误,需要修正。所以在封装时,确保每个设备使用不同的端口。 综上,封装类的步骤大致如下: 1. 实现自动检测并排序ttyUSB设备。 2. 在初始化时检查设备数量,至少需要三个。 3. 按顺序为每个设备分配类型(AHRS、GPS、ADM)。 4. 配置每个设备的串口,启动读取线程和数据处理线程。 5. 提供开始、停止等方法,管理资源。 此外,需要考虑异常处理,比如某个串口配置失败时,如何清理已分配的资源。 现在,用户可能还需要串口自动识别的动态性,比如设备热插拔,但根据问题描述,可能只需在启动时检测即可,动态识别会增加复杂度,可能超出当前范围。 可能的改进点: - 使用RAII管理资源,确保异常安全。 - 将设备检测和分配逻辑独立出来,提高可测试性。 - 支持更灵活的设备类型分配,比如通过配置文件或设备识别。 但根据用户当前的需求,可能先实现基本的封装,按顺序分配。 最后,测试这个类是否能够正确检测设备,配置,启动线程,并处理数据。</think>可以将代码封装为类来实现串口设备的自动识别与分配。以下是分步解决方案: #### 1. 创建串口管理类框架 ```cpp #include <iostream> #include <vector> #include <thread> #include <glob.h> class SerialManager { private: std::vector<std::string> detected_devices; // 存储检测到的设备 std::vector<gpscomRead> readers; // 设备读写实例 std::vector<std::thread> process_threads; // 数据处理线程 bool running = false; // 运行状态标志 // 检测可用串口设备 void detect_devices() { glob_t glob_result; glob("/dev/ttyUSB*", GLOB_TILDE, nullptr, &glob_result); for (size_t i = 0; i < glob_result.gl_pathc; ++i) { detected_devices.emplace_back(glob_result.gl_pathv[i]); } globfree(&glob_result); // 按设备号排序 std::sort(detected_devices.begin(), detected_devices.end(), [](const std::string& a, const std::string& b) { return std::stoi(a.substr(11)) < std::stoi(b.substr(11)); }); } public: ~SerialManager() { stop(); } bool start() { detect_devices(); if (detected_devices.size() < 3) { std::cerr << "需要至少3个串口设备" << std::endl; return false; } // 初始化设备实例 readers.resize(3); for (int i = 0; i < 3; ++i) { if (!readers[i].ConfigureSerialPort(detected_devices[i].c_str(), i)) { std::cerr << "配置设备" << detected_devices[i] << "失败" << std::endl; return false; } readers[i].StartReading(); process_threads.emplace_back(&gpscomRead::ProcessData, &readers[i]); } running = true; return true; } void stop() { if (running) { for (auto& reader : readers) { reader.StopReading(); } for (auto& thread : process_threads) { if (thread.joinable()) thread.join(); } running = false; } } }; ``` #### 2. 实现原理说明 1. **设备检测**: - 使用`glob()`函数扫描`/dev/ttyUSB*`设备 - 通过字符串排序确保设备按编号顺序排列 2. **动态分配**: - 检测到前3个设备自动分配为AHRS(0)、GPS(1)、ADM(2) - 使用索引号对应设备类型标识 3. **线程管理**: - 每个设备独立读写线程 - 统一线程回收机制 #### 3. 使用示例 ```cpp int main() { SerialManager manager; if (!manager.start()) { return EXIT_FAILURE; } std::cout << "按回车键退出..." << std::endl; std::cin.get(); manager.stop(); return EXIT_SUCCESS; } ``` #### 4. 改进建议 1. **设备热插拔支持**: ```cpp // 可添加定期设备扫描逻辑 void monitor_devices() { while (running) { std::this_thread::sleep_for(std::chrono::seconds(5)); // 实现设备状态检查 } } ``` 2. **设备类型识别**: ```cpp // 通过发送识别指令确认设备类型 bool identify_device(const std::string& port) { // 实现具体的设备识别协议 return true; } ``` 3. **配置灵活性**: ```cpp // 可通过配置文件指定设备映射关系 struct DeviceConfig { std::string type; int priority; }; ``` #### 5. 注意事项 1. 需要保证串口设备的**唯一性**,避免重复打开 2. 建议添加**互斥锁**保护共享资源 3. 推荐使用`rs485`设备时需要特殊配置 4. 实际部署时应考虑**波特率校验**等参数配置 这个设计方案实现了: - 自动设备检测和编号分配 ✅ - 线程安全的管理机制 ✅ - 易扩展的设备类型支持 ✅ - 统一的异常处理流程 ✅ 实际使用时需要根据具体硬件特性调整设备识别逻辑,并完善错误处理机制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值