• 嵌入式Qt-控制硬件:滑动条控制RGB灯


    前面的几篇文章,介绍Qt例程,都是和硬件无关的,Windows平台和嵌入式平台都能运行。

    本篇,来测试一下Qt界面控制嵌入式平台上的硬件,以野火i.MX6ULL板子上的RGB LED为例,实现Qt界面控制3种颜色LED的不同亮度混合显示。

    1 设计Qt滑条控制LED界面

    先来看一下最终设计的界面效果:

    有一个按键作为LED的总开关,控制LED的点亮与熄灭。下面的3个滑条,控制3种颜色LED以不同的亮度点亮。右边是一个颜色混合显示面板,模拟RGB三种颜色的LED以不同亮度点亮后的混合亮度。

    1.1 滑条控件

    Qt Creator的UI设置界面中,有水平滑条和竖直滑条控件,可以直接使用:

    右侧的属性窗户可以设置滑条的取值范围和初始值。

    1.2 控件颜色

    使用QPalette可以对界面颜色和控件的颜色进行自定义设置

    • QPalete::Window——通常指窗口部件的背景色
    • QPalette::WindowText——通常指窗口不见的前景色
    • QPalette::Base——底色
    • QPalette::Button——指按钮窗口部件的背景色
    • QPalette::ButtonText——指按钮窗口部件的前景色
    • QPalette::Text——文本输入窗口的前景色
    • QPalette::Background——背景色
    • QPalette::Foreground——前景色(界面中文字的统一颜色)

    界面的颜色

    整个UI界面的颜色可以这样设置:

    QPalette color = palette();//控制窗体颜色
    color.setColor(QPalette::Background, QColor(255,255,255));//背景颜色
    //color.setColor(QPalette::Foreground, QColor(0,0,255,255));//前景颜色
    setPalette(color);
    
    • 1
    • 2
    • 3
    • 4

    这里就是把整个界面的颜色设置为纯白色

    控件的颜色

    例如文本标签控件(QLabel)的文字颜色可以这样设置:

    QPalette pal;
    pal.setColor(QPalette::WindowText,Qt::red);
    ui->label_R->setPalette(pal); //设置滑条左侧的R字体为红色
    pal.setColor(QPalette::WindowText,Qt::green);
    ui->label_G->setPalette(pal);
    pal.setColor(QPalette::WindowText,Qt::blue);
    ui->label_B->setPalette(pal);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    颜色混合面板控件(QTextBrowser)的面板颜色可以这样设置:

    QColor color;
    int R = ui->Slider_R->value(); //读取滑条的当前值
    int G = ui->Slider_G->value();
    int B = ui->Slider_B->value();
    color.setRgb(R, G, B); //颜色混合
    QPalette pal;
    pal.setColor(QPalette::Base, color);
    ui->textBrowser->setPalette(pal); //显示到面板上
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    1.3 滑条UI界面代码编写

    构造函数

    LedWidget::LedWidget(QWidget *parent) :
        QWidget(parent),
        ui(new Ui::LedWidget)
    {
        ui->setupUi(this);
        ui->Value_R->setText(QString::number(ui->Slider_R->value()));
        ui->Value_G->setText(QString::number(ui->Slider_G->value()));
        ui->Value_B->setText(QString::number(ui->Slider_B->value()));
    
        QPalette color = palette();//控制窗体颜色
        color.setColor(QPalette::Background, QColor(255,255,255));//背景颜色
        setPalette(color);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    滑条滑动时的槽函数

    void LedWidget::on_Slider_R_valueChanged(int value)
    {
        ui->Value_R->setText(QString::number(value));
        UpdateShowColor();
    }
    
    void LedWidget::on_Slider_G_valueChanged(int value)
    {
        ui->Value_G->setText(QString::number(value));
        UpdateShowColor();
    }
    
    void LedWidget::on_Slider_B_valueChanged(int value)
    {
        ui->Value_B->setText(QString::number(value));
        UpdateShowColor();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    更新RGB三种颜色的混合显示

    void LedWidget::UpdateShowColor()
    {
        QColor color;
        int R = ui->Slider_R->value();
        int G = ui->Slider_G->value();
        int B = ui->Slider_B->value();
        color.setRgb(R, G, B);
        QPalette pal;
        pal.setColor(QPalette::Base, color);
        ui->textBrowser->setPalette(pal);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2 板子上RGB LED的控制

    2.1 i.MX6ULL系统烧录

    本篇的RGB LED测试,需要先烧录野火i.MX6ULL自带的系统固件,因为该系统已有Qt运行环境,且对应的RGB LED的驱动程序也已配置好了,这样就不需要再自己写RGB LED的驱动程序了,我们只写好Qt的应用程序,实现对板子上LED的控制即可。

    烧写方法可参考:https://doc.embedfire.com/linux/imx6/quick_start/zh/latest/quick_start/install_debian/install_debian.html#

    可以烧写到SD卡中

    烧写到eMMC中

    因为在SD卡中运行系统,无法使用WIFI连网,可以通过fire-config工具将SD卡的系统烧写到eMMC中,刷机过程可参考:

    https://doc.embedfire.com/linux/imx6/linux_base/zh/latest/linux_basis/fire-config_brief/fire-config_brief.html#id7

    设置之后,选择重启,重启后的系统将自动进行从SD卡到EMMC的刷机。刷机过程大约2分钟左右。刷机完成后,控制台会重新进入串口登录页面, 此时观察开发板的LED灯,如果LED在持续闪烁,说明刷机成功。然后调整拨码开关为相应启动方式,重新上电启动系统即可。

    也可以直接通过USB-OTG接口和 MFGTool2软件烧写到eMMC。ssh

    烧写到eMMC启动,可以使用WIFI连网,WIFI配网步骤参考:https://doc.embedfire.com/linux/imx6/quick_start/zh/latest/quick_start/wifi/wifi.html

    Qt系统界面

    野火i.MX6ULL自带的系统固件烧录后自启动Qt程序界面如下:

    串口方式登录时:

    普通用户(带sudo权限)

    • 账户: debian

    • 密码: temppwd

    ROOT用户

    • 账户: root

    • 密码: root

    这个系统第一次运行时,会进行屏幕触摸校准,若校准的不满意,可删除掉**/etc/pointercal文件**后重启再进行校准。

    rm /etc/pointercal
    
    • 1

    2.2 无Qt的RGB LED测试

    野火i.MX6ULL的RGB LED的原理图如下,由于驱动程序不需要自己写了,实际上我们也不需要关心具体的硬件引脚是哪个,只需要使用驱动程序提供的设备描述符进行LED的控制即可。

    参考野火的测试代码:https://doc.embedfire.com/linux/imx6/quick_start/zh/latest/quick_start/led_subsystem/led_subsystem.html#id4

    测试代码

    编写自己的没有Qt界面的RGB LED测试代码:

    #include 
    #include 
    #include 
    
    #include 
    #include 
    
    #define RLED_DEV_PATH "/sys/class/leds/red/brightness"
    #define GLED_DEV_PATH "/sys/class/leds/green/brightness"
    #define BLED_DEV_PATH "/sys/class/leds/blue/brightness"
    
    int main(int argc,int *argv[])
    {
        int r_fd;
        int g_fd;
        int b_fd;
    
        r_fd = open(RLED_DEV_PATH,O_WRONLY);
        if(r_fd < 0)
        {
            perror(RLED_DEV_PATH);
            exit(1);
        }
        
        g_fd = open(GLED_DEV_PATH,O_WRONLY);
        if(r_fd < 0)
        {
            perror(GLED_DEV_PATH);
            exit(1);
        }
        
        b_fd = open(BLED_DEV_PATH,O_WRONLY);
        if(r_fd < 0)
        {
            perror(BLED_DEV_PATH);
            exit(1);
        }
    
        while(1)
        {
            write(r_fd,"255",3);
            sleep(1);
            write(r_fd,"0",3);
            sleep(1);
            
            write(g_fd,"255",3);
            sleep(1);
            write(g_fd,"0",3);
            sleep(1);
            
            write(b_fd,"255",3);
            sleep(1);
            write(b_fd,"0",3);
            sleep(1);
        }
    
        close(r_fd);
        close(g_fd);
        close(b_fd);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    将该程序在Ubuntu进行交叉编译

    arm-linux-gnueabihf-gcc led_noqt.c -o led_noqt
    
    • 1

    测试效果

    运行效果如下,3种颜色的灯每隔1s依次点亮熄灭:
    在这里插入图片描述

    对于亮度的控制,可以先参考教程中的命令行点灯测试:https://doc.embedfire.com/linux/imx6/linux_base/zh/latest/linux_basis/led_key_command_line_testing/led_key_command_line_testing.html

    实际测试,串口指令无法控制灯的亮度,只能控制亮灭,亮度为1和亮度为255的效果一样,都是同样的亮度,不知道是硬件的问题还是软件驱动的问题。

    2.3 Qt中移植RGB LED控制代码

    在滑条UI界面代码工程的基础上,添加一个自定义的类,名字可起为regled:

    然后在这个类中,将无Qt的RGB LED测试用到的代码移植进来,并结合Qt的滑动条对三种颜色的灯进行控制。

    这个是构造函数,先打开3个LED灯的文件描述符:

    rgbled::rgbled(QObject *parent) : QObject(parent)
    {
        r_fd = open(RLED_DEV_PATH,O_WRONLY);
        if(r_fd < 0)
        {
            return;
        }
    
        g_fd = open(GLED_DEV_PATH,O_WRONLY);
        if(r_fd < 0)
        {
            return;
        }
    
        b_fd = open(BLED_DEV_PATH,O_WRONLY);
        if(r_fd < 0)
        {
            return;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    编写一个RGB灯的颜色和亮度的控制函数,供外部调用:

    void rgbled::SetRGBLedValue(LED_TYPE type, int val)
    {
        if (val > 255)
        {
            val = 255;
        }
        else if (val < 0)
        {
            val = 0;
        }
    
        std::string value = std::to_string(val);
    
        switch (type)
        {
            case T_R_LED:
                write(r_fd, value.c_str(), 3);
            break;
    
            case T_G_LED:
                write(g_fd, value.c_str(), 3);
            break;
    
            case T_B_LED:
                write(b_fd, value.c_str(), 3);
            break;
    
            default:break;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在UI界面类中,可以对RGB LED进行控制:

    //LedWidget类中定义一个rgbled成员变量
    rgbled *m_pRGBLed;
    
    //LedWidget构造函数中实例化一个rgbled对象
    m_pRGBLed = new rgbled(this);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在更新UI界面上的模拟颜色面板的同时,也将板子上的RGB LED的亮度进行同步控制:

    void LedWidget::UpdateShowColor()
    {
        QColor color;
        int R = ui->Slider_R->value();
        int G = ui->Slider_G->value();
        int B = ui->Slider_B->value();
        color.setRgb(R, G, B);
        QPalette pal;
        pal.setColor(QPalette::Base, color);
        ui->textBrowser->setPalette(pal);
    
        //控制板子上的RGB LED的亮度
        m_pRGBLed->SetRGBLedValue(T_R_LED, R);
        m_pRGBLed->SetRGBLedValue(T_G_LED, G);
        m_pRGBLed->SetRGBLedValue(T_B_LED, B);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2.4 编译时遇到的问题

    程序首先在Windows的Qt Creator上进行编译,遇到了一些问题,记录下解决方法。

    • 找不到unistd.h

      在Windows中编译时,Qt Creater提示找不到unistd.h,这个其实是Visual Stidio编译器找不这个头文件。

      这个头文件都是Linux系统中常用的,Windows中一般用不到,要消除这个编译错误,可以在VS的安装目录手动添加一个这个文件。

      我的目录是:

      D:\Tools1\vs2015\VC\include
      
      • 1

      新建一个unistd.h:

      //for qt creater, 2022/8/13
      #ifndef _UNISTD_H
      #define _UNISTD_H
      #include 
      #include 
      #endif 
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    • open、write等函数的警告提示

      这些也是Linux中用到的函数,在Window平台编译只是警告信息,没有报错,可以不用管

    3 实验演示

    3.1 交叉编译

    和之前一样,将Windows的Qt Creator中的源码复制到Ubuntu中进行交叉编译,具体操作过程可参考之前的文章:

    嵌入式Qt-动手编写并运行自己的第1个ARM-Qt程序

    这里仅记录下编译指令:

    /home/xxpcb/myTest/imx6ull/otherlib/qt/qt-everywhere-src-5.12.9/arm-qt/bin/qmake
    
    • 1

    3.2 文件复制到板子中

    由于这次测试使用的是野火的系统固件,不能和之前用网络位置挂载根文件系统的方式,在Ubuntu中直接将文件复制到板子中(Ubuntu中的网络挂载位置),因此本篇需要使用其它的方法将Ubuntu中编译的文件复制到板子中。

    这里使用SSH的方式进行拷贝,首先要在Ubuntu中和i.MX6ULL板子中配置SSH功能,配置方法如下:

    配置ssh

    sudo apt update
    sudo apt install openssh-server -y
    sudo systemctl status ssh #查看状态
    # 如果你的防火墙开启了,使用下面语句
    sudo ufw allow ssh
    
    • 1
    • 2
    • 3
    • 4
    • 5

    连接方式

    基本的ssh连接方法是:

    ssh username@ip
    
    • 1
    • username表示该机器的用户名,ip表示对应的ip地址

    • ssh方式文件复制

    从Ubuntu拉取文件到板子中

    # 从服务器拉取文件
    # scp 服务器上的某个用户@服务器IP::/服务器文件存放路径 拉取文件保存路径
    scp server_user_name@192.168.1.101:server_file_path local_path
    
    # 我的板子的拉取命令
    cd /usr/local/qt-app/mytest/
    scp xxpcb@192.168.5.104:~/myTest/imx6ull/qt-test/4-led/led ./
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    3.3 测试效果

    在测试自己的例程之前,需要先将野火的自启动Qt例程kill掉,否则两个Qt程序会同步运行互相遮挡。

    kill掉自启动Qt程序

    通过ps 、top 等命令查询到ebf-qtdemo的pid,然后通过kill命令停止App运行

    #879 为当前 App 的 PID 值,每次可能不一样
    sudo kill 879
    
    • 1
    • 2

    运行自己的Qt程序

    野火的系统中,提供了一个运行脚本run_myapp.sh,需要调用这个脚本来运行自己的Qt程序

    sudo /usr/local/qt-app/run_myapp.sh /usr/local/qt-app/Control_1
    
    • 1

    实际测试效果如下:
    https://www.bilibili.com/video/BV1kF411w7YN
    在这里插入图片描述

    可以看出:

    • 板子上的LED的亮度其实不能调节,只能亮或灭,需要确认下是不是LED驱动的问题
    • 触摸的方式拖动板子上的滑条,不太灵活,可能是触摸和鼠标都在起作用,两者干扰了
    • Qt界面中模拟的颜色混合面板,颜色混合显示正常

    4 总结

    本篇介绍了通过Qt中滑条的使用,并使用滑条来控制i.MX6ULL板子中RGB三个颜色LED的亮灭。通过烧录野火自带的系统固件,使用系统提供的LED驱动程序,再配置自己编译的Qt应用程序,来实现整个功能。

  • 相关阅读:
    Oracle中i列定义int类型对应Java中java.math.BigDecimal类型
    linux 简单处理 设备没有空间
    【JavaSE】String类详解(上篇)
    STM32F103C8T6第一天:认识STM32 标准库与HAL库 GPIO口 推挽输出与开漏输出
    metaRTC7集成lvgl ui demo编译指南
    ​【编写UI自动化测试集】Appium+Python+Unittest+HTMLRunner​
    Spring IOC和AOP
    《七月集训》(第二天)——字符串
    哪些电商平台的 API 很好用?为什么?
    【JavaWeb】案例 1:记录网站的登录成功人数
  • 原文地址:https://blog.csdn.net/hbsyaaa/article/details/126355922