“智慧教室”項(xiàng)目的目標(biāo)是實(shí)現(xiàn)實(shí)時(shí)采集環(huán)境中的溫度、濕度及光照信息,并將這些數(shù)據(jù)可視化地呈現(xiàn)在Qt圖形界面上。用戶既可以選擇手動(dòng)控制風(fēng)扇與窗簾的開關(guān),也可以設(shè)置系統(tǒng)根據(jù)所采集的環(huán)境參數(shù)自動(dòng)調(diào)節(jié),以達(dá)到舒適的室內(nèi)環(huán)境。接下來,將和各位小伙伴深入探討這一項(xiàng)目的具體實(shí)現(xiàn)方式。
1、數(shù)據(jù)監(jiān)測(cè)與顯示:實(shí)時(shí)監(jiān)測(cè)室內(nèi)溫度、濕度和光照強(qiáng)度,并直觀地顯示在Qt界面上。
2、手動(dòng)/感應(yīng)控制:用戶可以通過切換界面按鈕選擇手動(dòng)控制風(fēng)扇和窗簾的狀態(tài),或者根據(jù)實(shí)時(shí)監(jiān)測(cè)到的環(huán)境數(shù)據(jù),自動(dòng)的調(diào)節(jié)風(fēng)扇和窗簾的狀態(tài),以提供最佳的舒適度和能源利用效率。
3、節(jié)能優(yōu)化:自動(dòng)調(diào)節(jié)功能可實(shí)時(shí)調(diào)整設(shè)備狀態(tài),以減少能源消耗并提高設(shè)備壽命。
1、開發(fā)環(huán)境操作系統(tǒng):Ubuntu18.04 64位版
2、交叉編譯工具鏈:arm-poky-linux-gnueabi-gcc 5.3.0
3、開發(fā)板使用Bootloader版本:u-boot-2016.03
4、開發(fā)板內(nèi)核版本:linux-4.1.15
5、開發(fā)板移植QT版本:qt5.6.2
2、步進(jìn)電機(jī)與板卡的連接
ELF 1開發(fā)板已集成溫濕度傳感器與光線傳感器,實(shí)現(xiàn)環(huán)境溫度、濕度和光照強(qiáng)度的采集。為支持智慧教室系統(tǒng)的其它功能,需要對(duì)內(nèi)核源碼進(jìn)行以下適配步驟。
1、實(shí)現(xiàn)風(fēng)扇轉(zhuǎn)動(dòng)的功能
風(fēng)扇采用pwm的方式來控制,需要在設(shè)備樹中進(jìn)行pwm7的復(fù)用。
(1)拷貝ELF1開發(fā)板資料包2-Linux 源代碼2-0 出廠內(nèi)核和uboot源碼內(nèi)核源碼linux-4.1.15-elf1.tar.bz2內(nèi)核源碼到開發(fā)環(huán)境/home/elf/work/目錄下解壓。
elf@ubuntu:~/work$ tar -xvf linux-4.1.15-elf1.tar.bz2
(2)修改頂層設(shè)備樹文件arch/arm/boot/dts/imx6ull.dtsi
elf@ubuntu:~/work$ cd linux-4.1.15-elf1/
elf@ubuntu:~/work/linux-4.1.15-elf1$ vi arch/arm/boot/dts/imx6ull.dtsi
elf@ubuntu:~/work/linux-4.1.15-elf1$ vi arch/arm/boot/dts/imx6ull-elf1-emmc.dts
&pwm7 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_pwm7>;
status = "okay";
};
pinctrl_pwm7: pwm7grp {
fsl,pins = <
MX6UL_PAD_CSI_VSYNC__PWM7_OUT 0x110b0
>;
};
elf@ubuntu:~/work$ cd linux-4.1.15-elf1/
elf@ubuntu:~/work/linux-4.1.15-elf1$ vi arch/arm/boot/dts/imx6ull-elf1-emmc.dts
mymotor {
compatible = "motor";
pinctrl-names = "default";
pinctrl-0 = <&mymotor>;
status = "okay";
motorA-gpios = <&gpio4 21 GPIO_ACTIVE_HIGH>;
motorB-gpios = <&gpio4 22 GPIO_ACTIVE_HIGH>;
motorC-gpios = <&gpio4 23 GPIO_ACTIVE_HIGH>;
motorD-gpios = <&gpio4 24 GPIO_ACTIVE_HIGH>;
};
mymotor: mymotorgrp {
fsl,pins = <
MX6UL_PAD_CSI_DATA00__GPIO4_IO21 0x10b0
MX6UL_PAD_CSI_DATA01__GPIO4_IO22 0x10b0
MX6UL_PAD_CSI_DATA02__GPIO4_IO23 0x10b0
MX6UL_PAD_CSI_DATA03__GPIO4_IO24 0x10b0
>;
};
(2)添加電機(jī)驅(qū)動(dòng)。
obj-y += motor.o
3、編譯并替換設(shè)備樹和內(nèi)核
(1)執(zhí)行環(huán)境變量
elf@ubuntu:~/work/linux-4.1.15-elf1$ . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
(2)編譯設(shè)備樹和內(nèi)核
elf@ubuntu:~/work/linux-4.1.15-elf1$ make imx6ull_elf1_defconfig
elf@ubuntu:~/work/linux-4.1.15-elf1$ make dtbs
elf@ubuntu:~/work/linux-4.1.15-elf1$ make zImage
(3)將arch/arm/boot/路徑下的zImage和arch/arm/boot/dts/路徑下的imx6ull-elf1-emmc.dtb放到U盤,通過U盤拷貝到開發(fā)板。
root@ELF1:~# cp /run/media/sda1/imx6ull-elf1-emmc.dtb /run/media/mmcblk1p1/
root@ELF1:~# cp /run/media/sda1/zImage /run/media/mmcblk1p1/
root@ELF1:~# sync
root@ELF1:~# reboot
主函數(shù)的實(shí)現(xiàn)main.cpp
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
if(!ControllerHandler::instance()->startController())
{
return 0;
}
a.setStyle("Fusion");
QFont f = a.font();
f.setPointSize(20);
f.setPixelSize(16);
a.setFont(f);
MWainWindow w;
w.setWindowFlags(Qt::FramelessWindowHint);
if(a.primaryScreen())
{
w.resize(a.primaryScreen()->size());
}
w.show();
int ret = a.exec();
return ret;
}
設(shè)置顯示的時(shí)間的樣式和位置
void MWainWindow::showtime()
{
/* 實(shí)例化與設(shè)置顯示的位置大小*/
lcdNumber = new QLCDNumber(this);
QScreen *screen = QGuiApplication::primaryScreen();
// 獲取屏幕分辨率的大小
QSize screenSize = screen->size();
int screenWidth = screenSize.width();
int screenHeight = screenSize.height();
// 根據(jù)屏幕分辨率的大小執(zhí)行不同的操作
if (screenWidth == 1024 && screenHeight == 600) {
lcdNumber->setGeometry( 850, 9, 100, 40);
} else if (screenWidth == 800 && screenHeight == 480) {
lcdNumber->setGeometry( 650, 9, 100, 40);
} else {
qDebug() << "Performing other operation";}
/* 設(shè)置顯示的位數(shù) 8 位 */
lcdNumber->setDigitCount(8);
/* 設(shè)置樣式 */
lcdNumber->setFrameStyle(QFrame::NoFrame);
/* 設(shè)置 lcd 顯示為當(dāng)前系統(tǒng)時(shí)間 */
QTime time = QTime::currentTime();
/* 設(shè)置顯示的樣式 */
lcdNumber->display(time.toString("hh:mm:ss"));
lcdNumber->setStyleSheet("color: black");
}
設(shè)置顯示的圖片的大小和位置
void MWainWindow::showphoto()
{ /* 設(shè)置大小與位置 */
this->setGeometry(0, 0, 1024, 600);
/* 使用資源里的文件時(shí)格式是 :+前綴+文件路徑 */
QPixmap pixmap(":images/res.png");
labelImage = new QLabel(this);
QScreen *screen = QGuiApplication::primaryScreen();
// 獲取屏幕分辨率的大小
QSize screenSize = screen->size();
int screenWidth = screenSize.width();
int screenHeight = screenSize.height();
// 根據(jù)屏幕分辨率的大小執(zhí)行不同的操作
if (screenWidth == 1024 && screenHeight == 600) {
labelImage->setGeometry(14, 61, 343, 524);
} else if (screenWidth == 800 && screenHeight == 480) {
labelImage->setGeometry(14, 61, 343, 403);
} else {
qDebug() << "Performing other operation";
}
/* 設(shè)置圖像 */
labelImage->setPixmap(pixmap);
/* 開啟允許縮放填充 */
labelImage->setScaledContents(true);
}
獲取設(shè)備的狀態(tài)
void MWainWindow::readData()
{
/* 當(dāng)定時(shí)器計(jì)時(shí) 1000 毫秒后,刷新 lcd 顯示當(dāng)前系統(tǒng)時(shí)間 */
QTime time = QTime::currentTime();
/* 設(shè)置顯示的樣式 */
lcdNumber->display(time.toString("hh:mm:ss"));
ControllerHandler* pInstance =ControllerHandler::instance();
float value=-100;
int curtainstate = targetCurtainState;
pInstance->getValue(TEMPERATURE_SENSOR,value);
ui->widget_temp->setData("溫度", QString::number(value) +"°");
if(bOpen==1)
{
if(value > 31) {
ControllerHandler::instance()->setValue(FAN, 10, ' ', ' ');
} else {
ControllerHandler::instance()->setValue(FAN, 0, ' ', ' ');
}
}
pInstance->getValue(HUMIDITY_SENSOR,value);
ui->widget_hum->setData("濕度", QString::number(value) +"%");
pInstance->getValue(LIGHT_SENSOR,value);
ui->widget_light->setData("亮度", QString::number(value) +" lt");
if(bOpen==1)
{
if (value >= 0 && value < 100) {
if (curtainstate == 0) {
printf("Automatic curtain opening!!!n");
//ControllerHandler::instance()->setValue(MYMOTOR, ' ', 'R', 2048);
targetCurtainState = 1;
}
} else if (value >= 100 && value < 500) {
if (curtainstate == 1) {
printf("Automatic curtain closing!!!n");
//ControllerHandler::instance()->setValue(MYMOTOR, ' ', 'L', 2048);
targetCurtainState = 0;
}
}
}
if(bOpen==0)
{
if(bOpen2==1)
{
//printf("Fan open!!!n");
ControllerHandler::instance()->setValue(FAN, 10, ' ', ' ');
}
if(bOpen2==0)
{
//printf("Fan close!!!n");
ControllerHandler::instance()->setValue(FAN, 0, ' ', ' ');
}
}
if(bOpen == 0){
if (isFirstCheck) {
lastbOpen3 = bOpen3;
isFirstCheck = false;
} else if (bOpen3 != lastbOpen3) {
if(bOpen3 == 1){
printf("Curtain open!!!n");
//ControllerHandler::instance()->setValue(MYMOTOR, ' ', 'R', 2048);
} else {
printf("Curtain close!!!n");
//ControllerHandler::instance()->setValue(MYMOTOR, ' ', 'L', 2048);
}
lastbOpen3 = bOpen3;
}
}
}
設(shè)置界面樣式
void MWainWindow::Style()
{
QString qssFileName;
qssFileName = ":/green.qss";
QFile file(qssFileName);
if(file.open(QFile::ReadOnly| QFile::Text)){
QString qss =file.readAll();
QApplication *app = dynamic_cast<QApplication*>(qApp);
if(!qss.isEmpty()){
app->setStyleSheet(qss);
}
file.close();
}
}
2、應(yīng)用編譯
elf@ubuntu:~/work$ tar xvf smartclassroom.tar.bz2
elf@ubuntu:~/work/adc$ . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi
(3)編譯
elf@ubuntu:~/work$ cd smartclassroom/
elf@ubuntu:~/work/smartclassroom$ qmake
elf@ubuntu:~/work/smartclassroom$ make
(4)壓縮
elf@ubuntu:~/work/smartclassroom$ cd ../smartclassroom_output/release/
elf@ubuntu:~/work/smartclassroom_output/release$ tar -cjvf smartclassroom.tar.bz2 *
root@ELF1:~# cp /run/media/sda1/smartclassroom.tar.bz2 ./
root@ELF1:~# tar xvf smartclassroom.tar.bz2
root@ELF1:~# chmod 777 *
root@ELF1:~# cp lib* /usr/lib
root@ELF1:~# sync
2、執(zhí)行應(yīng)用
root@ELF1:~# export DISPLAY=:0.0
root@ELF1:~# ./app
應(yīng)用執(zhí)行成功后,Qt界面顯示如下,此時(shí)可以通過切換按鈕選擇手動(dòng)控制或者感應(yīng)控制風(fēng)扇開關(guān)以及窗簾開合。