基于IMX6ULL的智能车载终端项目(代码开源)_imx6ull 开源 linux 项目 车载终端
正点原子的 LCD 接口背光控制 IO 连接到了 I.MX6U 的 GPIO1_IO08 引脚上,GPIO1_IO08复用为 PWM1_OUT,通过 PWM 信号来控制 LCD 屏幕背光的亮度。正点原子 I.MX6U-ALPHA 开发板的 LCD 背光引脚和 NXP 官方 EVK 开发板的背光引脚一样,因此背光的设备树节点是不需要修改的。正点原子的 IMX6ULL 与 NXP 官方的 “蓝版”相似
1.4 车载终端:杂项功能
车载终端是一个非常复杂且常用的装置,随着电车与自动驾驶技术的不断升级迭代,需求也与日俱增!我们往往需要在终端上附加许许多多其他的功能,比如:智能家居联动、车内环境监测、天气预报与网上浏览等!
二、IMX6ULL车载项目的驱动
作者强调:考虑到篇幅有限,作者本篇博客仅进行部分功能实现教学,并侧重应用层的实现!基础薄弱的朋友,可以直接使用正点原子出厂的镜像程序进行项目复现!
2.1 音频设备驱动
音频 CODEC 支持 I2S 协议,那么主控制器也必须支持 I2S 协议,I.MX6ULL 也提供了一个叫做 SAI 的外设,全称为 SynchronousAudio Interface,翻译过来就是同步音频接口。
I.MX6ULL 的 SAI 是一个全双工、支持帧同步的串行接口,支持I2S、AC97、TDM和音频DSP。
正点原子 ALPHA 开发板音频原理图如图所示:
NXP 官方已经写好了 WM8960 驱动,因此我们直接配置内核使能 WM8960 驱动即可,按照如下所示步骤使能 WM8960 驱动。
1、根据IMX6ULL的引脚原理图修改设备树;
2、使能内核的 WM8960 驱动;
2.1、取消 ALSA 模拟 OSS API
2.2、使能 I.MX6ULL 的 WM8960 驱动
完整可见:《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6》 第 1544 页
2.2 LCD驱动
正点原子的 IMX6ULL 与 NXP 官方的 “蓝版”相似度极高,就是仿照着进行制作的(一般情况下,大都公司产品的项目板也是如此)
6ULL 的 eLCDIF 接口驱动程序 NXP 已经编写好了,因此 LCD 驱动部分我们不需要去修改。我们需要做的就是按照所使用的 LCD 来修改设备树。重点要注意三个地方:
①、LCD 所使用的 IO 配置。
②、LCD 屏幕节点修改,修改相应的属性值,换成我们所使用的 LCD 屏幕参数。
③、LCD 背光节点信息修改,要根据实际所使用的背光 IO 来修改相应的设备节点信息。
1、修改 LCD 所使用的 IO 配置;
检查一下设备树中 LCD 所使用的 IO 配置,这个其实 NXP 都已经给我们写好了,不需要修改!
2、LCD 屏幕参数节点信息修改
在 imx6ull-alientek-emmc.dts 文件中找到 lcdif 节点,节点内容如下所示:
&lcdif {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcdif_dat
&pinctrl_lcdif_ctrl>;
display = <&display0>;
status = "okay";
/* 7寸1024*600 */
display0: display {
bits-per-pixel = <24>; /* */
bus-width = <24>; /* LCD屏幕数据线有多少 */
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <51200000>; /* 时钟频率51.2MHZ */
hactive = <1024>; /* 水平像素点 */
vactive = <600>; /* 垂直像素点 */
hfront-porch = <160>;
hback-porch = <140>;
hsync-len = <20>;
vback-porch = <20>;
vfront-porch = <12>;
vsync-len = <3>;
/* 像素点有效电平值 */
hsync-active = <0>;
vsync-active = <0>;
de-active = <1>;
pixelclk-active = <0>;
};
};
};
/* 4.3寸480*272 */
/* display0: display {
bits-per-pixel = <24>;
bus-width = <24>;
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <9000000>;
hactive = <480>;
vactive = <272>;
hfront-porch = <5>;
hback-porch = <40>;
hsync-len = <1>;
vback-porch = <8>;
vfront-porch = <8>;
vsync-len = <1>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <1>;
pixelclk-active = <0>;
};
};
};*/
/* 4.3寸800*480 */
/* display0: display {
bits-per-pixel = <24>;
bus-width = <24>;
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <31000000>;
hactive = <800>;
vactive = <480>;
hfront-porch = <40>;
hback-porch = <88>;
hsync-len = <48>;
vback-porch = <32>;
vfront-porch = <13>;
vsync-len = <3>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <1>;
pixelclk-active = <0>;
};
};
};*/
};
根据自己使用 LCD 的实际参数修改红色框中的各个参数信息!
3、LCD 屏幕背光节点信息
正点原子的 LCD 接口背光控制 IO 连接到了 I.MX6U 的 GPIO1_IO08 引脚上,GPIO1_IO08复用为 PWM1_OUT,通过 PWM 信号来控制 LCD 屏幕背光的亮度。正点原子 I.MX6U-ALPHA 开发板的 LCD 背光引脚和 NXP 官方 EVK 开发板的背光引脚一样,因此背光的设备树节点是不需要修改的。
设置 backlight 节点,这个 NXP 已经给我们设置好了,大家在 imx6ull-alientek-emmc.dts 文件中找到如下内容:
backlight {
compatible = "pwm-backlight";
pwms = <&pwm1 0 5000000>;
brightness-levels = <0 4 8 16 32 64 128 255>;
default-brightness-level = <7>;
status = "okay";
};
第 3 行,设置背光使用 pwm1,PWM 频率为 200Hz。
第 4 行,设置背 8 级背光(0~7),分别为 0、4、8、16、32、64、128、255,对应占空比为0%、1.57%、3.13%、6.27%、12.55%、25.1%、50.19%、100%,如果嫌少的话可以自行添加一些其他的背光等级值。
第 5 行,设置默认背光等级为 6,也就是 **50.19%**的亮度。
完整可见:《【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6》 第 1386 页
2.3 AP3216C驱动
本项目作者替换的智能家居 APP 的功能页为 AP3216C 的车载内室监测功能!
篇幅有限,AP3216的使用和 QT 功能页设计博客:http://t.csdn.cn/cN6p1
三、QT智能车载装置
3.1 QMusic音乐播放器
音乐播放器是各家嵌入式机构 QT 练习的常规项目,QMediaPlayer 类是一个高级媒体播放类。它可以用来播放歌曲、电影和网络广播等内容。一般用于播放 mp3 和 mp4 等等媒体文件。QMediaPlayer 类常常与 QMediaPlaylist 类一起使用。可以很轻松的设计一个自己喜欢的音乐播放器与视频播放器。
QMediaPlayer 提供了很多信号,我们可以使用这些信号来完成音乐播放器的一系列操作,比如媒体状态改变的信号 stateChanged(QMediaPlayer::State state),判断这个 state 的状态就可以知道什么时候媒体暂停、播放、停止了。
★在项目文件 14_musicplayer.pro 文件第一行添加的代码:multimedia
在头文件 “mainwindow.h” 具体代码如下:
/******************************************************************
* @projectName musicplayer
* @brief mainwindow.h
* @author 混分巨兽龙某某
* @email 1178305328@qq.com
*******************************************************************/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMediaPlayer>
#include <QMediaPlaylist>
#include <QPushButton>
#include <QSlider>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QListWidget>
#include <QLabel>
#include <QSpacerItem>
#include <QDebug>
/* 媒体信息结构体 */
struct MediaObjectInfo {
/* 用于保存歌曲文件名 */
QString fileName;
/* 用于保存歌曲文件路径 */
QString filePath;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
/* 媒体播放器,用于播放音乐 */
QMediaPlayer *musicPlayer;
/* 媒体列表 */
QMediaPlaylist *mediaPlaylist;
/* 音乐列表 */
QListWidget *listWidget;
/* 播放进度条 */
QSlider *durationSlider;
/* 音乐播放器按钮 */
QPushButton *pushButton[7];
QPushButton *exit_button;
/* 垂直布局 */
QVBoxLayout *vBoxLayout[3];
/* 水平布局 */
QHBoxLayout *hBoxLayout[4];
/* 垂直容器 */
QWidget *vWidget[3];
/* 水平容器 */
QWidget *hWidget[4];
/* 标签文本 */
QLabel *label[4];
/* 用于遮罩 */
QWidget *listMask;
/* 音乐布局函数 */
void musicLayout();
/* 主窗体大小重设大小函数重写 */
void resizeEvent(QResizeEvent *event);
/* 媒体信息存储 */
QVector<MediaObjectInfo> mediaObjectInfo;
/* 扫描歌曲 */
void scanSongs();
/* 媒体播放器类初始化 */
void mediaPlayerInit();
private slots:
/* 播放按钮点击 */
void btn_play_clicked();
/* 下一曲按钮点击*/
void btn_next_clicked();
/* 上一曲按钮点击 */
void btn_previous_clicked();
/* 媒体状态改变 */
void mediaPlayerStateChanged(QMediaPlayer::State);
/* 列表单击 */
void listWidgetCliked(QListWidgetItem*);
/* 媒体列表项改变 */
void mediaPlaylistCurrentIndexChanged(int);
/* 媒体总长度改变 */
void musicPlayerDurationChanged(qint64);
/* 媒体播放位置改变 */
void mediaPlayerPositionChanged(qint64);
/* 播放进度条松开 */
void durationSliderReleased();
};
#endif // MAINWINDOW_H
在源文件 “mainwindow.cpp” 具体代码如下:
#include "mainwindow.h"
#include <QCoreApplication>
#include <QFileInfoList>
#include <QDir>
#include <QProcess>
QProcess * mypro;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
/* 布局初始化 */
musicLayout();
/* 媒体播放器初始化 */
mediaPlayerInit();
/* 扫描歌曲 */
scanSongs();
/* 按钮信号槽连接 */
connect(pushButton[0], SIGNAL(clicked()),
this, SLOT(btn_previous_clicked()));
connect(pushButton[1], SIGNAL(clicked()),
this, SLOT(btn_play_clicked()));
connect(pushButton[2], SIGNAL(clicked()),
this, SLOT(btn_next_clicked()));
/* 媒体信号槽连接 */
connect(musicPlayer,
SIGNAL(stateChanged(QMediaPlayer::State)),
this,
SLOT(mediaPlayerStateChanged(QMediaPlayer::State)));
connect(mediaPlaylist,
SIGNAL(currentIndexChanged(int)),
this,
SLOT(mediaPlaylistCurrentIndexChanged(int)));
connect(musicPlayer, SIGNAL(durationChanged(qint64)),
this,
SLOT(musicPlayerDurationChanged(qint64)));
connect(musicPlayer,
SIGNAL(positionChanged(qint64)),
this,
SLOT(mediaPlayerPositionChanged(qint64)));
/* 列表信号槽连接 */
connect(listWidget, SIGNAL(itemClicked(QListWidgetItem*)),
this, SLOT(listWidgetCliked(QListWidgetItem*)));
/* slider信号槽连接 */
connect(durationSlider, SIGNAL(sliderReleased()),
this, SLOT(durationSliderReleased()));
/* 失去焦点 */
this->setFocus();
exit_button = new QPushButton(this);
exit_button->setMinimumSize(50, 50);
exit_button->setMaximumSize(50, 50);
exit_button->move(760,440);
exit_button->setStyleSheet("QPushButton{background:yellow}");
connect(exit_button,&QPushButton::clicked,[=](){
mypro->close();
exit(1);//退出程序
});
}
void MainWindow::musicLayout()
{
/* 设置位置与大小,这里固定为800, 480 */
this->setGeometry(0, 0, 800, 480);
QPalette pal;
/* 按钮 */
for (int i = 0; i < 7; i++)
pushButton[i] = new QPushButton();
/* 标签 */
for (int i = 0; i < 4; i++)
label[i] = new QLabel();
for (int i = 0; i < 3; i++) {
/* 垂直容器 */
vWidget[i] = new QWidget();
vWidget[i]->setAutoFillBackground(true);
/* 垂直布局 */
vBoxLayout[i] = new QVBoxLayout();
}
for (int i = 0; i < 4; i++) {
/* 水平容器 */
hWidget[i] = new QWidget();
hWidget[i]->setAutoFillBackground(true);
/* 水平布局 */
hBoxLayout[i] = new QHBoxLayout();
}
/* 播放进度条 */
durationSlider = new QSlider(Qt::Horizontal);
durationSlider->setMinimumSize(300, 15);
durationSlider->setMaximumHeight(15);
durationSlider->setObjectName("durationSlider");
/* 音乐列表 */
listWidget = new QListWidget();
listWidget->setObjectName("listWidget");
listWidget->resize(310, 265);
listWidget->setVerticalScrollBarPolicy(
Qt::ScrollBarAlwaysOff);
listWidget->setHorizontalScrollBarPolicy(
Qt::ScrollBarAlwaysOff);
/* 列表遮罩 */
listMask = new QWidget(listWidget);
listMask->setMinimumSize(310, 50);
listMask->setMinimumHeight(50);
listMask->setObjectName("listMask");
listMask->setGeometry(0,
listWidget->height() - 50,
310,
50);
/* 设置对象名称 */
pushButton[0]->setObjectName("btn_previous");
pushButton[1]->setObjectName("btn_play");
pushButton[2]->setObjectName("btn_next");
pushButton[3]->setObjectName("btn_favorite");
pushButton[4]->setObjectName("btn_mode");
pushButton[5]->setObjectName("btn_menu");
pushButton[6]->setObjectName("btn_volume");
/* 设置按钮属性 */
pushButton[1]->setCheckable(true);
pushButton[3]->setCheckable(true);
/* H0布局 */
vWidget[0]->setMinimumSize(310, 480);
vWidget[0]->setMaximumWidth(310);
vWidget[1]->setMinimumSize(320, 480);
QSpacerItem *hSpacer0 = new
QSpacerItem(70, 480,
QSizePolicy::Minimum,
QSizePolicy::Maximum);
QSpacerItem *hSpacer1 = new
QSpacerItem(65, 480,
QSizePolicy::Minimum,
QSizePolicy::Maximum);
QSpacerItem *hSpacer2 = new
QSpacerItem(60, 480,
QSizePolicy::Minimum,
QSizePolicy::Maximum);
hBoxLayout[0]->addSpacerItem(hSpacer0);
hBoxLayout[0]->addWidget(vWidget[0]);
hBoxLayout[0]->addSpacerItem(hSpacer1);
hBoxLayout[0]->addWidget(vWidget[1]);
hBoxLayout[0]->addSpacerItem(hSpacer2);
hBoxLayout[0]->setContentsMargins(0, 0, 0, 0);
hWidget[0]->setLayout(hBoxLayout[0]);
setCentralWidget(hWidget[0]);
/* V0布局 */
listWidget->setMinimumSize(310, 265);
hWidget[1]->setMinimumSize(310, 80);
hWidget[1]->setMaximumHeight(80);
label[0]->setMinimumSize(310, 95);
label[0]->setMaximumHeight(95);
QSpacerItem *vSpacer0 = new
QSpacerItem(310, 10,
QSizePolicy::Minimum,
QSizePolicy::Maximum);
QSpacerItem *vSpacer1 = new
QSpacerItem(310, 30,
QSizePolicy::Minimum,
QSizePolicy::Minimum);
vBoxLayout[0]->addWidget(label[0]);
vBoxLayout[0]->addWidget(listWidget);
vBoxLayout[0]->addSpacerItem(vSpacer0);
vBoxLayout[0]->addWidget(hWidget[1]);
vBoxLayout[0]->addSpacerItem(vSpacer1);
vBoxLayout[0]->setContentsMargins(0, 0, 0, 0);
vWidget[0]->setLayout(vBoxLayout[0]);
/* H1布局 */
for (int i = 0; i < 3; i++) {
pushButton[i]->setMinimumSize(80, 80);
}
QSpacerItem *hSpacer3 = new
QSpacerItem(40, 80,
QSizePolicy::Expanding,
QSizePolicy::Expanding);
QSpacerItem *hSpacer4 = new
QSpacerItem(40, 80,
QSizePolicy::Expanding,
QSizePolicy::Expanding);
hBoxLayout[1]->addWidget(pushButton[0]);
hBoxLayout[1]->addSpacerItem(hSpacer3);
hBoxLayout[1]->addWidget(pushButton[1]);
hBoxLayout[1]->addSpacerItem(hSpacer4);
hBoxLayout[1]->addWidget(pushButton[2]);
hBoxLayout[1]->setContentsMargins(0, 0, 0, 0);
hWidget[1]->setLayout(hBoxLayout[1]);
/* V1布局 */
QSpacerItem *vSpacer2 = new
QSpacerItem(320, 40,
QSizePolicy::Minimum,
QSizePolicy::Maximum);
QSpacerItem *vSpacer3 = new
QSpacerItem(320, 20,
QSizePolicy::Minimum,
QSizePolicy::Maximum);
QSpacerItem *vSpacer4 = new
QSpacerItem(320, 30,
QSizePolicy::Minimum,
QSizePolicy::Minimum);
label[1]->setMinimumSize(320, 320);
QImage Image;
Image.load(":/images/cd.png");
QPixmap pixmap = QPixmap::fromImage(Image);
int with = 320;
int height = 320;
QPixmap fitpixmap =
pixmap.scaled(with, height,
Qt::IgnoreAspectRatio,
Qt::SmoothTransformation);
label[1]->setPixmap(fitpixmap);
label[1]->setAlignment(Qt::AlignCenter);
vWidget[2]->setMinimumSize(300, 80);
vWidget[2]->setMaximumHeight(80);
vBoxLayout[1]->addSpacerItem(vSpacer2);
vBoxLayout[1]->addWidget(label[1]);
vBoxLayout[1]->addSpacerItem(vSpacer3);
vBoxLayout[1]->addWidget(durationSlider);
vBoxLayout[1]->addWidget(vWidget[2]);
vBoxLayout[1]->addSpacerItem(vSpacer4);
vBoxLayout[1]->setContentsMargins(0, 0, 0, 0);
vWidget[1]->setLayout(vBoxLayout[1]);
/* V2布局 */
QSpacerItem *vSpacer5 = new
QSpacerItem(300, 10,
QSizePolicy::Minimum,
QSizePolicy::Maximum);
hWidget[2]->setMinimumSize(320, 20);
hWidget[3]->setMinimumSize(320, 60);
vBoxLayout[2]->addWidget(hWidget[2]);
vBoxLayout[2]->addSpacerItem(vSpacer5);
vBoxLayout[2]->addWidget(hWidget[3]);
vBoxLayout[2]->setContentsMargins(0, 0, 0, 0);
vWidget[2]->setLayout(vBoxLayout[2]);
/* H2布局 */
QFont font;
font.setPixelSize(10);
/* 设置标签文本 */
label[0]->setText("Q Music,Enjoy it!");
label[2]->setText("00:00");
label[3]->setText("00:00");
label[2]->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
label[3]->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
label[3]->setAlignment(Qt::AlignRight);
label[2]->setAlignment(Qt::AlignLeft);
label[2]->setFont(font);
label[3]->setFont(font);
pal.setColor(QPalette::WindowText, Qt::white);
label[0]->setPalette(pal);
label[2]->setPalette(pal);
label[3]->setPalette(pal);
hBoxLayout[2]->addWidget(label[2]);
hBoxLayout[2]->addWidget(label[3]);
hBoxLayout[2]->setContentsMargins(0, 0, 0, 0);
hWidget[2]->setLayout(hBoxLayout[2]);
/* H3布局 */
QSpacerItem *hSpacer5 = new
QSpacerItem(0, 60,
QSizePolicy::Minimum,
QSizePolicy::Maximum);
QSpacerItem *hSpacer6 = new
QSpacerItem(80, 60,
QSizePolicy::Maximum,
QSizePolicy::Maximum);
QSpacerItem *hSpacer7 = new
QSpacerItem(80, 60,
QSizePolicy::Maximum,
QSizePolicy::Maximum);
QSpacerItem *hSpacer8 = new
QSpacerItem(80, 60,
QSizePolicy::Maximum,
QSizePolicy::Maximum);
QSpacerItem *hSpacer9 = new
QSpacerItem(0, 60,
QSizePolicy::Minimum,
QSizePolicy::Maximum);
for (int i = 3; i < 7; i++) {
pushButton[i]->setMinimumSize(25, 25);
pushButton[i]->setMaximumSize(25, 25);
}
hBoxLayout[3]->addSpacerItem(hSpacer5);
hBoxLayout[3]->addWidget(pushButton[3]);
hBoxLayout[3]->addSpacerItem(hSpacer6);
hBoxLayout[3]->addWidget(pushButton[4]);
hBoxLayout[3]->addSpacerItem(hSpacer7);
hBoxLayout[3]->addWidget(pushButton[5]);
hBoxLayout[3]->addSpacerItem(hSpacer8);
hBoxLayout[3]->addWidget(pushButton[6]);
hBoxLayout[3]->addSpacerItem(hSpacer9);
hBoxLayout[3]->setContentsMargins(0, 0, 0, 0);
hBoxLayout[3]->setAlignment(Qt::AlignHCenter);
hWidget[3]->setLayout(hBoxLayout[3]);
//hWidget[0]->setStyleSheet("background-color:red");
//hWidget[1]->setStyleSheet("background-color:#ff5599");
//hWidget[2]->setStyleSheet("background-color:#ff55ff");
//hWidget[3]->setStyleSheet("background-color:black");
//vWidget[0]->setStyleSheet("background-color:#555555");
//vWidget[1]->setStyleSheet("background-color:green");
//vWidget[2]->setStyleSheet("background-color:gray");
}
MainWindow::~MainWindow()
{
}
void MainWindow::btn_play_clicked()
{
int state = musicPlayer->state();
switch (state) {
case QMediaPlayer::StoppedState:
/* 媒体播放 */
musicPlayer->play();
break;
case QMediaPlayer::PlayingState:
/* 媒体暂停 */
musicPlayer->pause();
break;
case QMediaPlayer::PausedState:
musicPlayer->play();
break;
}
}
void MainWindow::btn_next_clicked()
{
musicPlayer->stop();
int count = mediaPlaylist->mediaCount();
if (0 == count)
return;
/* 列表下一个 */
mediaPlaylist->next();
musicPlayer->play();
}
void MainWindow::btn_previous_clicked()
{
musicPlayer->stop();
int count = mediaPlaylist->mediaCount();
if (0 == count)
return;
/* 列表上一个 */
mediaPlaylist->previous();
musicPlayer->play();
}
void MainWindow::mediaPlayerStateChanged(
QMediaPlayer::State
state)
{
switch (state) {
case QMediaPlayer::StoppedState:
pushButton[1]->setChecked(false);
break;
case QMediaPlayer::PlayingState:
pushButton[1]->setChecked(true);
break;
case QMediaPlayer::PausedState:
pushButton[1]->setChecked(false);
break;
}
}
void MainWindow::listWidgetCliked(QListWidgetItem *item)
{
musicPlayer->stop();
mediaPlaylist->setCurrentIndex(listWidget->row(item));
musicPlayer->play();
}
void MainWindow::mediaPlaylistCurrentIndexChanged(
int index)
{
if (-1 == index)
return;
/* 设置列表正在播放的项 */
listWidget->setCurrentRow(index);
}
void MainWindow::musicPlayerDurationChanged(
qint64 duration)
{
durationSlider->setRange(0, duration / 1000);
int second = duration / 1000;
int minute = second / 60;
second %= 60;
QString mediaDuration;
mediaDuration.clear();
if (minute >= 10)
mediaDuration = QString::number(minute, 10);
else
mediaDuration = "0" + QString::number(minute, 10);
if (second >= 10)
mediaDuration = mediaDuration
+ ":" + QString::number(second, 10);
else
mediaDuration = mediaDuration
+ ":0" + QString::number(second, 10);
/* 显示媒体总长度时间 */
label[3]->setText(mediaDuration);
}
void MainWindow::mediaPlayerPositionChanged(
qint64 position)
{
if (!durationSlider->isSliderDown())
durationSlider->setValue(position/1000);
int second = position / 1000;
int minute = second / 60;
second %= 60;
QString mediaPosition;
mediaPosition.clear();
if (minute >= 10)
mediaPosition = QString::number(minute, 10);
else
mediaPosition = "0" + QString::number(minute, 10);
if (second >= 10)
mediaPosition = mediaPosition
+ ":" + QString::number(second, 10);
else
mediaPosition = mediaPosition
+ ":0" + QString::number(second, 10);
/* 显示现在播放的时间 */
label[2]->setText(mediaPosition);
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event);
listMask->setGeometry(0,
listWidget->height() - 50,
310,
50);
}
void MainWindow::durationSliderReleased()
{
/* 设置媒体播放的位置 */
musicPlayer->setPosition(durationSlider->value() * 1000);
}
void MainWindow::scanSongs()
{
QDir dir(QCoreApplication::applicationDirPath()
+ "/myMusic");
QDir dirbsolutePath(dir.absolutePath());
/* 如果目录存在 */
if (dirbsolutePath.exists()) {
/* 定义过滤器 */
QStringList filter;
/* 包含所有.mp3后缀的文件 */
filter << "*.mp3";
/* 获取该目录下的所有文件 */
QFileInfoList files =
dirbsolutePath.entryInfoList(filter, QDir::Files);
/* 遍历 */
for (int i = 0; i < files.count(); i++) {
MediaObjectInfo info;
/* 使用utf-8编码 */
QString fileName = QString::fromUtf8(files.at(i)
.fileName()
.replace(".mp3", "")
.toUtf8()
.data());
info.fileName = fileName + "\n"
+ fileName.split("-").at(1);
info.filePath = QString::fromUtf8(files.at(i)
.filePath()
.toUtf8()
.data());
/* 媒体列表添加歌曲 */
if (mediaPlaylist->addMedia(
QUrl::fromLocalFile(info.filePath))) {
/* 添加到容器数组里储存 */
mediaObjectInfo.append(info);
/* 添加歌曲名字至列表 */
listWidget->addItem(info.fileName);
} else {
qDebug()<<
mediaPlaylist->errorString()
.toUtf8().data()
<< endl;
qDebug()<< " Error number:"
<< mediaPlaylist->error()
<< endl;
}
}
}
}
void MainWindow::mediaPlayerInit()
{
musicPlayer = new QMediaPlayer(this);
mediaPlaylist = new QMediaPlaylist(this);
/* 确保列表是空的 */
mediaPlaylist->clear();
/* 设置音乐播放器的列表为mediaPlaylist */
musicPlayer->setPlaylist(mediaPlaylist);
/* 设置播放模式,Loop是列循环 */
mediaPlaylist->setPlaybackMode(QMediaPlaylist::Loop);
}
上述代码就是常规的 QT 页面布局以及操作函数和信号,代码参考了正点原子的教程。特别需要注意的地方是需要在 QMusic 的功能页中加入退出按钮,即切换至其父进程!具体如下图:
运行结果:
3.2 QVideo视频播放器
视频播放器依旧是各家嵌入式机构QT练习的常规项目,与音乐播放器一样使用 QMediaPlayer 类,不同的是需要使用 setVideoOutput(QVideoWidget*) 设置一个视频输出窗口,好让视频在此窗口显示,其他步骤基本都一样。
★在项目文件 15_videoplayer.pro 文件第一行添加的代码:multimedia multimediawidgets
在头文件 “mainwindow.h” 具体代码如下
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMediaPlayer>
#include <QMediaPlaylist>
#include <QPushButton>
#include <QSlider>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QListWidget>
#include <QLabel>
#include <QSpacerItem>
#include <QVideoWidget>
#include <QDebug>
/* 媒体信息结构体 */
struct MediaObjectInfo {
/* 用于保存视频文件名 */
QString fileName;
/* 用于保存视频文件路径 */
QString filePath;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
/* 媒体播放器,用于播放视频 */
QMediaPlayer *videoPlayer;
/* 媒体列表 */
QMediaPlaylist *mediaPlaylist;
/* 视频显示窗口 */
QVideoWidget *videoWidget;
/* 视频列表 */
QListWidget *listWidget;
/* 播放进度条 */
QSlider *durationSlider;
/* 音量条 */
QSlider *volumeSlider;
/* 视频播放器按钮 */
QPushButton *pushButton[5];
QPushButton *exit_button;
/* 水平布局 */
QHBoxLayout *hBoxLayout[3];
/* 水平容器 */
QWidget *hWidget[3];
/* 标签文本 */
QLabel *label[2];
/* 垂直容器 */
QWidget *vWidget[2];
/* 垂直界面 */
QVBoxLayout *vBoxLayout[2];
/* 视频布局函数 */
void videoLayout();
/* 主窗体大小重设大小函数重写 */
void resizeEvent(QResizeEvent *event);
/* 媒体信息存储 */
QVector<MediaObjectInfo> mediaObjectInfo;
/* 扫描本地视频文件 */
void scanVideoFiles();
/* 媒体初始化 */
void mediaPlayerInit();
private slots:
/* 播放按钮点击 */
void btn_play_clicked();
/* 下一个视频按钮点击 */
void btn_next_clicked();
/* 音量加 */
void btn_volmeup_clicked();
/* 音量减 */
void btn_volmedown_clicked();
/* 全屏 */
void btn_fullscreen_clicked();
/* 媒体状态改变 */
void mediaPlayerStateChanged(QMediaPlayer::State);
/* 列表单击 */
void listWidgetCliked(QListWidgetItem*);
/* 媒体列表项改变 */
void mediaPlaylistCurrentIndexChanged(int);
/* 媒体总长度改变 */
void musicPlayerDurationChanged(qint64);
/* 媒体播放位置改变 */
void mediaPlayerPositionChanged(qint64);
/* 播放进度条松开 */
void durationSliderReleased();
/* 音量条松开 */
void volumeSliderReleased();
};
#endif // MAINWINDOW_H
在源文件**“mainwindow.cpp”**具体代码如下:
#include "mainwindow.h"
#include <QCoreApplication>
#include <QFileInfoList>
#include <QDir>
#include <QProcess>
QProcess * mypro;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
/* 视频播放器布局初始化 */
videoLayout();
/* 媒体初始化 */
mediaPlayerInit();
/* 扫描本地视频 */
scanVideoFiles();
/* 设置按钮的属性 */
pushButton[0]->setCheckable(true);
pushButton[4]->setCheckable(true);
/* 按钮连接信号槽 */
connect(pushButton[0], SIGNAL(clicked()),
this, SLOT(btn_play_clicked()));
connect(pushButton[1], SIGNAL(clicked()),
this, SLOT(btn_next_clicked()));
connect(pushButton[2], SIGNAL(clicked()),
this, SLOT(btn_volmedown_clicked()));
connect(pushButton[3], SIGNAL(clicked()),
this, SLOT(btn_volmeup_clicked()));
connect(pushButton[4], SIGNAL(clicked()),
this, SLOT(btn_fullscreen_clicked()));
/* 列表连接信号槽 */
connect(listWidget, SIGNAL(itemClicked(QListWidgetItem*)),
this, SLOT(listWidgetCliked(QListWidgetItem*)));
/* 媒体连接信号槽 */
connect(videoPlayer,
SIGNAL(stateChanged(QMediaPlayer::State)),
this,
SLOT(mediaPlayerStateChanged(QMediaPlayer::State)));
connect(mediaPlaylist,
SIGNAL(currentIndexChanged(int)),
this,
SLOT(mediaPlaylistCurrentIndexChanged(int)));
connect(videoPlayer, SIGNAL(durationChanged(qint64)),
this,
SLOT(musicPlayerDurationChanged(qint64)));
connect(videoPlayer,
SIGNAL(positionChanged(qint64)),
this,
SLOT(mediaPlayerPositionChanged(qint64)));
/* slider信号槽连接 */
connect(durationSlider, SIGNAL(sliderReleased()),
this, SLOT(durationSliderReleased()));
connect(volumeSlider, SIGNAL(sliderReleased()),
this, SLOT(volumeSliderReleased()));
/* 退出按钮 */
exit_button = new QPushButton(this);
exit_button->setMinimumSize(60, 50);
exit_button->setMaximumSize(60, 50);
exit_button->move(740,10);
exit_button->setStyleSheet("QPushButton{background: black}");
connect(exit_button,&QPushButton::clicked,[=](){
mypro->close();
exit(1);//退出程序
});
}
MainWindow::~MainWindow()
{
}
void MainWindow::videoLayout()
{
/* 设置位置与大小,这里固定为800, 480 */
this->setGeometry(0, 0, 800, 480);
// this->setMinimumSize(800, 480);
// this->setMaximumSize(800, 480);
QPalette pal;
pal.setColor(QPalette::WindowText, Qt::white);
for (int i = 0; i < 3; i++) {
/* 水平容器 */
hWidget[i] = new QWidget();
hWidget[i]->setAutoFillBackground(true);
/* 水平布局 */
hBoxLayout[i] = new QHBoxLayout();
}
for (int i = 0; i < 2; i++) {
/* 垂直容器 */
vWidget[i] = new QWidget();
vWidget[i]->setAutoFillBackground(true);
/* 垂直布局 */
vBoxLayout[i] = new QVBoxLayout();
}
for (int i = 0; i < 2; i++) {
label[i] = new QLabel();
}
for (int i = 0; i < 5; i++) {
pushButton[i] = new QPushButton();
pushButton[i]->setMaximumSize(44, 44);
pushButton[i]->setMinimumSize(44, 44);
}
/* 设置 */
vWidget[0]->setObjectName("vWidget0");
vWidget[1]->setObjectName("vWidget1");
hWidget[1]->setObjectName("hWidget1");
hWidget[2]->setObjectName("hWidget2");
pushButton[0]->setObjectName("btn_play");
pushButton[1]->setObjectName("btn_next");
pushButton[2]->setObjectName("btn_volumedown");
pushButton[3]->setObjectName("btn_volumeup");
pushButton[4]->setObjectName("btn_screen");
QFont font;
font.setPixelSize(18);
label[0]->setFont(font);
label[1]->setFont(font);
pal.setColor(QPalette::WindowText, Qt::white);
label[0]->setPalette(pal);
label[1]->setPalette(pal);
label[0]->setText("00:00");
label[1]->setText("/00:00");
durationSlider = new QSlider(Qt::Horizontal);
durationSlider->setMaximumHeight(15);
durationSlider->setObjectName("durationSlider");
volumeSlider = new QSlider(Qt::Horizontal);
volumeSlider->setRange(0, 100);
volumeSlider->setMaximumWidth(80);
volumeSlider->setObjectName("volumeSlider");
volumeSlider->setValue(50);
listWidget = new QListWidget();
listWidget->setObjectName("listWidget");
listWidget->setVerticalScrollBarPolicy(
Qt::ScrollBarAlwaysOff);
listWidget->setHorizontalScrollBarPolicy(
Qt::ScrollBarAlwaysOff);
//listWidget->setFocusPolicy(Qt::NoFocus);
videoWidget = new QVideoWidget();
videoWidget->setStyleSheet("border-image: none;"
"background: transparent;"
"border:none");
/* H0布局 */
vWidget[0]->setMinimumSize(300, 480);
vWidget[0]->setMaximumWidth(300);
videoWidget->setMinimumSize(500, 480);
hBoxLayout[0]->addWidget(videoWidget);
hBoxLayout[0]->addWidget(vWidget[0]);
hWidget[0]->setLayout(hBoxLayout[0]);
hBoxLayout[0]->setContentsMargins(0, 0, 0, 0);
setCentralWidget(hWidget[0]);
/* V0布局 */
QSpacerItem *vSpacer0 = new
QSpacerItem(0, 80,
QSizePolicy::Minimum,
QSizePolicy::Maximum);
vBoxLayout[0]->addWidget(listWidget);
vBoxLayout[0]->addSpacerItem(vSpacer0);
vBoxLayout[0]->setContentsMargins(0, 0, 0, 0);
vWidget[0]->setLayout(vBoxLayout[0]);
/* V1布局 */
/* 底板部件布局 */
hWidget[1]->setMaximumHeight(15);
hWidget[2]->setMinimumHeight(65);
vBoxLayout[1]->addWidget(hWidget[1]);
vBoxLayout[1]->addWidget(hWidget[2]);
vBoxLayout[1]->setAlignment(Qt::AlignCenter);
vWidget[1]->setLayout(vBoxLayout[1]);
vWidget[1]->setParent(this);
vWidget[1]->setGeometry(0, this->height() - 80, this->width(), 80);
vBoxLayout[1]->setContentsMargins(0, 0, 0, 0);
/* 位于最上层 */
vWidget[1]->raise();
/* H1布局 */
hBoxLayout[1]->addWidget(durationSlider);
hBoxLayout[1]->setContentsMargins(0, 0, 0, 0);
hWidget[1]->setLayout(hBoxLayout[1]);
/* H2布局 */
QSpacerItem *hSpacer0 = new
QSpacerItem(300, 80,
QSizePolicy::Expanding,
QSizePolicy::Maximum);
hBoxLayout[2]->addSpacing(20);
hBoxLayout[2]->addWidget(pushButton[0]);
hBoxLayout[2]->addSpacing(10);
hBoxLayout[2]->addWidget(pushButton[1]);
hBoxLayout[2]->addSpacing(10);
hBoxLayout[2]->addWidget(pushButton[2]);
hBoxLayout[2]->addWidget(volumeSlider);
hBoxLayout[2]->addWidget(pushButton[3]);
hBoxLayout[2]->addWidget(label[0]);
hBoxLayout[2]->addWidget(label[1]);
hBoxLayout[2]->addSpacerItem(hSpacer0);
hBoxLayout[2]->addWidget(pushButton[4]);
hBoxLayout[2]->addSpacing(20);
hBoxLayout[2]->setContentsMargins(0, 0, 0, 0);
hBoxLayout[2]->setAlignment(Qt::AlignLeft | Qt::AlignTop);
hWidget[2]->setLayout(hBoxLayout[2]);
}
void MainWindow::mediaPlayerInit()
{
videoPlayer = new QMediaPlayer(this);
mediaPlaylist = new QMediaPlaylist(this);
/* 确保列表是空的 */
mediaPlaylist->clear();
/* 设置视频播放器的列表为mediaPlaylist */
videoPlayer->setPlaylist(mediaPlaylist);
/* 设置视频输出窗口 */
videoPlayer->setVideoOutput(videoWidget);
/* 设置播放模式,Loop是列循环 */
mediaPlaylist->setPlaybackMode(QMediaPlaylist::Loop);
/* 设置默认软件音量为50% */
videoPlayer->setVolume(50);
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event);
vWidget[1]->setGeometry(0, this->height() - 80, this->width(), 80);
}
void MainWindow::btn_play_clicked()
{
int state = videoPlayer->state();
switch (state) {
case QMediaPlayer::StoppedState:
/* 媒体播放 */
videoPlayer->play();
break;
case QMediaPlayer::PlayingState:
/* 媒体暂停 */
videoPlayer->pause();
break;
case QMediaPlayer::PausedState:
/* 设置视频输出窗口 */
videoPlayer->play();
break;
}
}
void MainWindow::btn_next_clicked()
{
videoPlayer->stop();
int count = mediaPlaylist->mediaCount();
if (0 == count)
return;
/* 列表下一个 */
mediaPlaylist->next();
videoPlayer->play();
}
void MainWindow::btn_volmeup_clicked()
{
/* 点击每次音量+5 */
volumeSlider->setValue(volumeSlider->value() + 5);
videoPlayer->setVolume(volumeSlider->value());
}
void MainWindow::btn_fullscreen_clicked()
{
/* 全屏/非全屏操作 */
vWidget[0]->setVisible(!pushButton[4]->isChecked());
}
void MainWindow::btn_volmedown_clicked()
{
/* 点击每次音量-5 */
volumeSlider->setValue(volumeSlider->value() - 5);
videoPlayer->setVolume(volumeSlider->value());
}
void MainWindow::mediaPlayerStateChanged(
QMediaPlayer::State
state)
{
switch (state) {
case QMediaPlayer::StoppedState:
pushButton[0]->setChecked(false);
break;
case QMediaPlayer::PlayingState:
pushButton[0]->setChecked(true);
break;
case QMediaPlayer::PausedState:
pushButton[0]->setChecked(false);
break;
}
}
void MainWindow::listWidgetCliked(QListWidgetItem *item)
{
videoPlayer->stop();
mediaPlaylist->setCurrentIndex(listWidget->row(item));
videoPlayer->play();
}
void MainWindow::mediaPlaylistCurrentIndexChanged(
int index)
{
if (-1 == index)
return;
/* 设置列表正在播放的项 */
listWidget->setCurrentRow(index);
}
void MainWindow::musicPlayerDurationChanged(
qint64 duration)
{
durationSlider->setRange(0, duration / 1000);
int second = duration / 1000;
int minute = second / 60;
second %= 60;
QString mediaDuration;
mediaDuration.clear();
if (minute >= 10)
mediaDuration = QString::number(minute, 10);
else
mediaDuration = "0" + QString::number(minute, 10);
if (second >= 10)
mediaDuration = mediaDuration
+ ":" + QString::number(second, 10);
else
mediaDuration = mediaDuration
+ ":0" + QString::number(second, 10);
/* 显示媒体总长度时间 */
label[1]->setText("/" + mediaDuration);
}
void MainWindow::mediaPlayerPositionChanged(
qint64 position)
{
if (!durationSlider->isSliderDown())
durationSlider->setValue(position / 1000);
int second = position / 1000;
int minute = second / 60;
second %= 60;
QString mediaPosition;
mediaPosition.clear();
if (minute >= 10)
mediaPosition = QString::number(minute, 10);
else
mediaPosition = "0" + QString::number(minute, 10);
if (second >= 10)
mediaPosition = mediaPosition
+ ":" + QString::number(second, 10);
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数嵌入式工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
![img](https://img-blog.csdnimg.cn/img_convert/7fbe485d8d4baf081563f6c6a3a54f96.png)
![img](https://img-blog.csdnimg.cn/img_convert/57f96529bf1b7657b9846431769aa798.jpeg)
![img](https://img-blog.csdnimg.cn/img_convert/56bccad9ddc61e6d0ba8dc2cbd8469c3.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
![img](https://img-blog.csdnimg.cn/img_convert/f4b3a8b286b9286f478cee96e674a3dc.png)
![img](https://img-blog.csdnimg.cn/img_convert/a9dc63d0350e5c25562e8ca7f9ff81b8.png)
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**
**如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)**
<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />
# 最后
**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**
**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**
/* 显示媒体总长度时间 */
label[1]->setText("/" + mediaDuration);
}
void MainWindow::mediaPlayerPositionChanged(
qint64 position)
{
if (!durationSlider->isSliderDown())
durationSlider->setValue(position / 1000);
int second = position / 1000;
int minute = second / 60;
second %= 60;
QString mediaPosition;
mediaPosition.clear();
if (minute >= 10)
mediaPosition = QString::number(minute, 10);
else
mediaPosition = "0" + QString::number(minute, 10);
if (second >= 10)
mediaPosition = mediaPosition
+ ":" + QString::number(second, 10);
**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**
**深知大多数嵌入式工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
**因此收集整理了一份《2024年嵌入式&物联网开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**
[外链图片转存中...(img-OqHqMWfJ-1712382462148)]
[外链图片转存中...(img-PmH8rlSC-1712382462149)]
[外链图片转存中...(img-75sdQibn-1712382462150)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上嵌入式&物联网开发知识点,真正体系化!**
[外链图片转存中...(img-wRgIHtu7-1712382462151)]
[外链图片转存中...(img-znu7l7JS-1712382462152)]
**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**
**如果你觉得这些内容对你有帮助,可以+V:Vip1104z获取!!! (备注:嵌入式)**
<img src="https://img-community.csdnimg.cn/images/73bb5de17851459088c6af944156ee24.jpg" alt="img" style="zoom: 67%;" />
# 最后
**资料整理不易,觉得有帮助的朋友可以帮忙点赞分享支持一下小编~**
**你的支持,我的动力;祝各位前程似锦,offer不断,步步高升!!!**
**[更多资料点击此处获qu!!](https://bbs.csdn.net/topics/618376385)**
更多推荐
所有评论(0)