嵌入式点灯正如hello world一样,是我们常写的第一个测试程序,本章将介绍如何从底层内核搭建驱动,到使用Qt应用控制底层led灯显示
前期准备
1.imx6ull 开发板(笔者使用的是 韦东山开发板)
2.内核版本 4.9.88
3.文件系统(buildroot 2019.02工具输出)移植好qt(本章简单介绍)
4.ubuntu 安装好qt
5.交叉编译工具链:gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf
驱动篇
首先看原理图,LED的IO是哪个
1.内核配置
因为LED是非常基本的设备驱动,所以内核中已经集成了该功能,如下修改
2.基于设备驱动卡框架,设备树修改如下
sys_led2 {
compatible = "gpio-leds";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_leds>;
// status = "disabled";
led0 {
label = "green";
gpios = <&gpio5 3 GPIO_ACTIVE_LOW>;
default-state = "on";
linux,default-trigger = "heartbeat";
};
};
......
pinctrl_leds: ledgrp {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER3__GPIO5_IO03 0x110A0
>;
};
修改完成
make dtbs
启动新的dtb文件,内核系统启动后,led会如心跳一样闪烁,证明led驱动已经搭建完成了
应用篇
1.使用buildroot添加qt,配置如下
make 编译输出文件系统,修改文件系统 /etc/profile 文件(也可以在buildroot路径中修改 /output/target/etc/profile,然后编译输出的打包文件系统就不用再修改了),profile文件修改如下(主要看 tslib和qt内容,其他先不管):
export PATH="/bin:/sbin:/usr/bin:/usr/sbin"
if [ "$PS1" ]; then
if [ "`id -u`" -eq 0 ]; then
export PS1='\u@\h:\w\# '
else
export PS1='\u@\h:\w\$'
fi
fi
export EDITOR='/bin/vi'
# Source configuration files from /etc/profile.d
for i in /etc/profile.d/*.sh ; do
if [ -r "$i" ]; then
. $i
fi
done
unset i
export ALSA_CONFIG_PATH=/usr/share/alsa/alsa.conf
#tslib
export TSLIB_ROOT=/usr/lib/ts
#export TSLIB_ROOT=/usr/lib/arm-tslib
export TSLIB_CONSOLEDEVICE=none
export TSLIB_FBDEVICE=/dev/fb0
export TSLIB_TSDEVICE=/dev/input/event1
export TSLIB_CONFFILE=/etc/ts.conf
export TSLIB_PLUGINDIR=/usr/lib/ts
#export TSLIB_CONFFILE=$TSLIB_ROOT/etc/ts.conf
#export TSLIB_PLUGINDIR=$TSLIB_ROOT/lib/ts
export TSLIB_CALIBFILE=/etc/pointercal
export LD_PRELOAD=/usr/lib/libts.so
#export LD_PRELOAD=$TSLIB_ROOT/lib/libts.so
echo "tslib init success by l17!"
#qt
#export QT_ROOT=/usr/lib/arm-qt
export QT_ROOT=/usr/lib/qt
#export QT_QPA_GENERIC_PLUGINS=tslib:/dev/input/event1
export QT_QPA_FONTDIR=/usr/share/fonts
export QT_QPA_PLATFORM_PLUGIN_PATH=$QT_ROOT/plugins
export QT_QPA_PLATFORM=linuxfb:tty=/dev/fb0
export QT_PLUGIN_PATH=$QT_ROOT/plugins
export LD_LIBRARY_PATH=$QT_ROOT/lib:$QT_ROOT/plugins/platforms
#export QML2_IMPORT_PATH=$QT_ROOT/qml
export QT_QPA_FB_TSLIB=1
echo "qt5.12 init success by l17!"
export XDG_RUNTIME_DIR=/usr/lib/
export RUNLEVEL=3
2.创建一个QT工程
笔者在网上找了两张灯泡png,一个是开,一个是关,如下图,通过按钮可以实现LED的开关
具体代码如下:
//头文件///
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFile>
#include <QMessageBox>
#include <QPushButton>
#include <QLabel>
#include <QImage>
#include <QVBoxLayout>
#include <QHBoxLayout>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
QPushButton *pPushButton;
QLabel *pLabel;
QImage *pImg[2];
/* 文件 */
QFile file;
/* 设置lED的状态 */
void setLedState(bool onOff);
/* 获取lED的状态 */
bool getLedState();
private slots:
void pushButton_Clicked();
};
#endif // MAINWINDOW_H
//cpp文件///
#include "mainwindow.h"
#include <QDebug>
#include <QGuiApplication>
#include <QScreen>
static bool lightOnOff;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
QList <QScreen *> list_screen = QGuiApplication::screens();
#if __arm__
/* 重设大小 */
this->resize(list_screen.at(0)->geometry().width(),
list_screen.at(0)->geometry().height());
//先关闭心跳
system("echo none > /sys/class/leds/green/trigger");
#else
this->setGeometry(0, 0, 800, 480);
#endif
pPushButton = new QPushButton("light switch",this);
/* 居中显示 */
pPushButton->setMinimumSize(200, 50);
pPushButton->setGeometry((this->width() - pPushButton->width()) /2 ,this->height() - 120,
pPushButton->width(),pPushButton->height());
pLabel = new QLabel(this);
pImg[0]=new QImage; //新建一个image对象
pImg[1]=new QImage; //新建一个image对象
#if __arm__
pImg[0]->load("/img/light_off");
pImg[1]->load("/img/light_on");
#else
pImg[0]->load("/home/l17/qt_workspace/pngBtn/img/light_off");
pImg[1]->load("/home/l17/qt_workspace/pngBtn/img/light_on");
#endif
pLabel->setPixmap(QPixmap::fromImage(*pImg[0]));
pLabel->resize(pImg[0]->width(),pImg[0]->height());
pLabel->setGeometry((this->width() - pLabel->width()) /2 ,(this->height() - pLabel->height()) /4,
pImg[0]->width(),pImg[0]->height());
file.setFileName("/sys/class/leds/green/brightness");
if (!file.exists())
{
/* 设置按钮的初始化文本 */
pPushButton->setText("not find LED device!");
}
else
{
lightOnOff = getLedState();
if(lightOnOff)
{
this->setStyleSheet("QMainWindow { background-color: rgba(0, 204,68, 100%); }");
pLabel->setPixmap(QPixmap::fromImage(*pImg[1]));
pPushButton->setText("LED ON");
}
else
{
this->setStyleSheet("QMainWindow { background-color: rgba(255, 245,238, 100%); }");
pLabel->setPixmap(QPixmap::fromImage(*pImg[0]));
pPushButton->setText("LED OFF");
}
}
connect(pPushButton, SIGNAL(clicked()), this,SLOT(pushButton_Clicked()));
}
MainWindow::~MainWindow()
{
}
/*bt click*/
void MainWindow::pushButton_Clicked()
{
lightOnOff ^= 1;
setLedState(lightOnOff);
if(lightOnOff)
{
this->setStyleSheet("QMainWindow { background-color: rgba(0, 204,68, 100%); }");
pLabel->setPixmap(QPixmap::fromImage(*pImg[1]));
pPushButton->setText("LED ON");
}
else
{
this->setStyleSheet("QMainWindow { background-color: rgba(255, 245,238, 100%); }");
pLabel->setPixmap(QPixmap::fromImage(*pImg[0]));
pPushButton->setText("LED OFF");
}
}
void MainWindow::setLedState(bool onOff)
{
/* 在设置LED状态时先读取 */
//bool state = getLedState();
/* 如果文件不存在,则返回 */
if (!file.exists())
return;
if(!file.open(QIODevice::ReadWrite))
qDebug()<<file.errorString();
QByteArray buf;
buf = (onOff)?"1":"0";
file.write(buf);
/* 关闭文件 */
file.close();
}
bool MainWindow::getLedState()
{
/* 如果文件不存在,则返回 */
if (!file.exists())
return false;
if(!file.open(QIODevice::ReadWrite))
qDebug()<<file.errorString();
QTextStream in(&file);
/* 读取文件所有数据 */
QString buf = in.readLine();
/* 打印出读出的值 */
qDebug()<<"buf: "<<buf<<endl;
file.close();
if (buf == "1")
{
pPushButton->setText("LED ON");
return true;
}
else
{
pPushButton->setText("LED OFF");
return false;
}
}
通过ubuntu调试Qt工程,测试OK后,交叉编译适合arm的执行文件,将执行文件拷贝到开发板文件系统,启动开发板执行qt输出的可执行文件
另外注意将图片拷贝到文件系统根目录下 /img下(这个随便放哪里没有特别要求,保证我们代码能找到就行)
输出结果,绿灯亮灭: