ubuntu串口重命名助手x86_64电脑架构(秒速配好串口)(上)软件介绍

✨✨ Rqtz 个人主页 : 点击✨✨

🎈PyQt系列专栏:点击🎈

🎈Qt智能车上位机专栏: 点击🎈

🎈Qt串口助手专栏:点击🎈

💫宗旨:共享IT之美,共创机器未来

目录

​编辑

​编辑

项目背景

相关参数

 软件下载连接

软件图片

动图展示

shell命令配置串口名称过程

命令过程

shell命令解释

​编辑

转为Qt框架实现

串口扫描识别

判断是USB还是ACM并查询串口内核编号

printshell函数实现精准获取串口内核

函数参数

使用C语言函数fopen()与fgets()获取输出

输出udev命令

输入管理员密码打开usb.rules编辑

代码结构


项目背景

        由于在ubuntu电脑上配置多传感器(如雷达,陀螺仪,单片机)的串口,为了防止每次使用时都要对串口名称进行修改,因此需要重命名。如果按照终端的方法配置,不仅要打开文件,还要记住复杂的shell命令,十分的繁琐与复杂。基于这个问题,我使用C++Qt写了一款ubuntu串口重命名助手,全程不需要输入一条命令,直接点击按钮即可轻松配置串口,5到6秒钟就可以配置完成,十分好用

相关参数

设备:ubuntu20.04 noetic

开发语言:C++/面向对象

软件框架:Qt

IDE:Qt Creater

核心内容:shell命令输出到管道

我是基于这位大佬的博客中描述的串口配置方法来实现的

[005] ubuntu下绑定USB设备的串口名称(KERNELS硬件端口号绑定)_串口名是ttyacm0是什么kernel-CSDN博客

 软件下载连接

https://download.csdn.net/download/m0_75192474/89535177?spm=1001.2014.3001.5503

源码连接:   源码连接-githup

软件图片

比较简单

动图展示

shell命令配置串口名称过程

命令过程

  1. 查看串口详细信息:该命令查询的是ttyUSB0
    udevadm info --attribute-walk --name=/dev/ttyUSB0
  2. 将内核输入到指定文件中
    sudo gedit /etc/udev/rules.d/usb.rules
  3. 重启udev服务
    sudo udevadm trigger
  4. 查询串口更改情况
    ls -l /dev |grep ttyUSB

shell命令解释

  1. udevadm: 这是一个用户空间工具,用于查询和操作udev设备管理器。udev是一个动态设备管理器,它负责在Linux系统中管理设备节点的创建、删除和属性更新。

  2. info: 这是udevadm的一个子命令,用于显示设备的详细信息。

  3. --attribute-walk: 这是一个选项,表示要遍历设备的所有属性并显示它们的值。这将提供关于设备的各种属性的信息,如制造商、型号、序列号等。

  4. --name=/dev/ttyUSB0: 这是一个选项,指定要查询的设备的名称。在这个例子中,我们查询的是名为/dev/ttyUSB0的设备。这个设备通常是一个串行端口设备,例如USB转串口适配器。

  5. sudo gedit /etc/udev/rules.d/usb.rules:该文件用于定义USB设备的自定义规则。

  6. ls -l /dev: 这部分命令会列出/dev目录下的所有文件和目录,以及它们的详细信息。-l选项表示长格式输出,会显示每个文件的类型、权限、所有者、组、大小、最后修改时间和名称。

  7. | :将命令输出传给管道。

  8. grep ttyUSB: 这部分命令是一个过滤工具,它会从前面的命令的输出中筛选出包含ttyUSB字符串的行。换句话说,它会显示所有以ttyUSB开头的设备文件。

  9. udevadm info --attribute-walk --name=/dev/ttyUSB0 | grep 'KERNELS' | awk '{print $1}' :将串口设备的详细信息传入管道

  10. | grep 'KERNELS':这部分命令会从上述命令的输出中筛选出包含KERNELS字符串的行。

  11. | awk '{print $1}':这部分命令会处理grep命令的输出,并使用awk命令仅提取每行的第一个字段(即KERNELS的值)。

转为Qt框架实现

串口扫描识别

.pro文件中添加 serialport模块

遍历串口,count为显示串口的数量,并添加到serial_list中,其为一个Qcombox.

    QList<QSerialPortInfo> serialPorts = QSerialPortInfo::availablePorts();
    //遍历串口信息列表并输出串口号
    foreach (const QSerialPortInfo &serialPortInfo, serialPorts) {
        count++;
        ui->serial_list->addItem(serialPortInfo.portName());
    }

判断是USB还是ACM并查询串口内核编号

//判断是USB还是ACM并查询串口内核编号
void port::on_see_kernel_clicked()
{
  for(int i=0;i<ui->serial_list->currentText().length();i++)
  {
     if(ui->serial_list->currentText()[i]=="U"&&ui->serial_list->currentText()[i+1]=="S"&&ui->serial_list->currentText()[i+2]=="B")
     {
         cr1=ui->serial_list->currentText()[i+3];
         usbflag=true;
     }
     if(ui->serial_list->currentText()[i]=="A"&&ui->serial_list->currentText()[i+1]=="C"&&ui->serial_list->currentText()[i+2]=="M")
     {
         cr2=ui->serial_list->currentText()[i+3];
         acmflag=true;
     }

  }
   if(usbflag)
    printshell(QString(cr1).toStdString(),"udevadm info --attribute-walk --name=/dev/ttyUSB","KERNELS",1);
   else if(acmflag)
    printshell(QString(cr2).toStdString(),"udevadm info --attribute-walk --name=/dev/ttyUSB","KERNELS",1);

}
  • for循环:为遍历当前的combox的内容,判断是否为USB或ACM,并把当前的串口索引号放到cr1/cr2中
  • printshell函数:将索引号和相关命令参数传入,精准获取所需要的内容。

printshell函数实现精准获取串口内核

//将shell命令输出到管道并按规则打印
QString port::printshell(std::string data,std::string comm,std::string findstr,int num)
{

    std::array<char,128> buffer;
    std::string res;
    //字符串拼接
    std::stringstream str;
    str<<comm<<data<<" | grep '"<<findstr<<"' | awk '{print $"<<num<<"}'";
    qDebug()<<str.str().c_str();
    //创建一个文件对象指针
    FILE* pipe = popen(str.str().c_str(),"r");
    if (!pipe) {
            std::cerr << "popen() failed!" << std::endl;
        }
        //fgets函数直到有一个换行符或文件末尾才终止
        int temp = 0;
        while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {

            temp++;
            //第二个为需要的那一个
            if(temp==2)
            {
                ui->KERENEL->setText(buffer.data());
                qDebug()<<buffer.data();
            }

            res+=buffer.data();
        }
        auto returnpope = pclose(pipe);
        return QString::fromStdString(res);
}
函数参数
  1. std::string data : 为串口设备索引号,如ttyUSB0中的0
  2. std::string comm: 为查询串口设备的命令 即udevadm info --attribute-walk --name=/dev/ttyUSB
  3. std::string findstr:为grep命令查找的内容 如KERNELS
  4. int num:awk命令所打印的字段
  5. 使用std::stringstream拼接得到完整的命令 udevadm info --attribute-walk --name=/dev/ttyUSB0 | grep 'KERNELS' | awk '{print $2}'
  6. 效果

但是此时我们需要的是第二个数据,红框中的

使用C语言函数fopen()与fgets()获取输出
  1. fopen()函数:参数1 :传入shell命令的c风格字符串,参数2: 访问方式
  2. fgets()函数   原型解析fgets()函数的原型为 char *fgets(char *str, int n, FILE *stream)
  3. 参数详解
    • char *str:这是一个指向字符数组的指针,用于存储从流中读取的字符串。
    • int n:这是要读取的最大字符数(包括最后的空字符'\0')。通常使用数组长度作为此参数。
    • FILE *stream:这是指向FILE对象的指针,标识了要从中读取字符的流。
  4. while (fgets(buffer.data(), buffer.size(), pipe) != nullptr)这段代码用于从管道或文件中逐行读取数据,直到读取到文件末尾或者发生错误返回空指针为止。
  5.  if(temp==2) 时刚好读取到第二行也就是我们需要的数据,把他添加到输入框中

输出udev命令

//输出串口内核命令kernels
void port::on_pushButton_2_clicked()
{
    if(ui->KERENEL->text()==""||ui->set_portname->text() == "")
    {
        ui->textEdit->append("串口内核或串口别名不能为空..................");
    }
    else {
        //除去最后那个换行符
        QString aimker = "";
        for (int i = 0;i<ui->KERENEL->text().size();i++) {
            if(ui->KERENEL->text()[i]=="\n")
                break;
            aimker+=ui->KERENEL->text()[i];
        }
        //串口内核命令
        QString com=aimker+", MODE:=\"0777\", GROUP:=\"dialout\", SYMLINK+=\"" +ui->set_portname->text()+"\"";
        ui->rule_edit->setText(com);
        if(usbflag)
        {
            ui->textEdit->insertHtml(QString("<strong><font color= 'red' >%1</font> </strong> ").arg("/dev/ttyUSB"+QString(cr1)));
            ui->textEdit->insertHtml(QString("<font color= 'blue' >%1</font><hr> ").arg(com));
        }

        else if(acmflag)  {
            ui->textEdit->insertHtml(QString("<strong><font color= 'red' >%1</font> </strong>").arg("/dev/ttyACM"+QString(cr2)));
            ui->textEdit->insertHtml(QString("<font color= 'blue' >%1</font><hr> ").arg(com));
        }
    }
}

核心:

 QString com=aimker+", MODE:=\"0777\", GROUP:=\"dialout\", SYMLINK+=\"" +ui->set_portname->text()+"\"";
  1. aimker 为串口设备的kERNELS
  2. ui->set_portname->text() 为设置的串口别名
  3. 生成命令 KERNELS=="3-3:1.0", MODE:="0777", GROUP:="dialout", SYMLINK+="rplidar"
  4. 使用富文本将内容按照不同颜色插入信息框.

输入管理员密码打开usb.rules编辑

//打开usb.rules文件修改
void port::on_change_btn_clicked()
{
    if(ui->password->text()=="")
    {
        ui->textEdit->insertPlainText("请输入管理员密码...............\n");
    }
    else {
        //使用&使其在后台运行不妨碍主线程
        std::string command = "echo '"+ui->password->text().toStdString()+"' | sudo -S gedit /etc/udev/rules.d/usb.rules &";
        system(command.c_str());
        ui->udev_btn->setDisabled(false);
    }

}

使用的是

echo "your_password" | sudo -S command

  1. 将管理员密码与shell命令相结合,用-S连接,可以不用在终端输入密码,直接用用户在输入框中输入的密码。
  2. comand 指的是终端shell命令 --> gedit /etc/udev/rules.d/usb.rules &
  3. 使用system函数启动并使用 "&"在后台运行,注意有部分电脑可能打开这个文件有点慢,请耐心等待,如果一直没有打开,有可能是密码输入错误.
  4. 将命令复制到文件中点击保存.

代码结构

如有错误,请大佬指正批评!

  • 21
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值