“智慧教室”開源項(xiàng)目技術(shù)文檔(搞創(chuàng)作必看@沧狻)

“智慧教室”項(xiàng)目的目標(biāo)是實(shí)現(xiàn)實(shí)時采集環(huán)境中的溫度煮岁、濕度及光照信息噪奄,并將這些數(shù)據(jù)可視化地呈現(xiàn)在Qt圖形界面上。用戶既可以選擇手動控制風(fēng)扇與窗簾的開關(guān)人乓,也可以設(shè)置系統(tǒng)根據(jù)所采集的環(huán)境參數(shù)自動調(diào)節(jié)勤篮,以達(dá)到舒適的室內(nèi)環(huán)境。接下來色罚,將和各位小伙伴深入探討這一項(xiàng)目的具體實(shí)現(xiàn)方式碰缔。

一偿洁、?功能特性

1逮诲、數(shù)據(jù)監(jiān)測與顯示:實(shí)時監(jiān)測室內(nèi)溫度秸应、濕度和光照強(qiáng)度荆针,并直觀地顯示在Qt界面上。

2梗肝、手動/感應(yīng)控制:用戶可以通過切換界面按鈕選擇手動控制風(fēng)扇和窗簾的狀態(tài)榛瓮,或者根據(jù)實(shí)時監(jiān)測到的環(huán)境數(shù)據(jù),自動的調(diào)節(jié)風(fēng)扇和窗簾的狀態(tài)巫击,以提供最佳的舒適度和能源利用效率禀晓。

3、節(jié)能優(yōu)化:自動調(diào)節(jié)功能可實(shí)時調(diào)整設(shè)備狀態(tài)坝锰,以減少能源消耗并提高設(shè)備壽命粹懒。

二、?環(huán)境說明

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

三、?硬件連接

1翔冀、風(fēng)扇與板卡的連接


2嚣镜、步進(jìn)電機(jī)與板卡的連接


四、?內(nèi)核適配

ELF 1開發(fā)板已集成溫濕度傳感器與光線傳感器橘蜜,實(shí)現(xiàn)環(huán)境溫度菊匿、濕度和光照強(qiáng)度的采集。為支持智慧教室系統(tǒng)的其它功能计福,需要對內(nèi)核源碼進(jìn)行以下適配步驟跌捆。

1、實(shí)現(xiàn)風(fēng)扇轉(zhuǎn)動的功能

風(fēng)扇采用pwm的方式來控制象颖,需要在設(shè)備樹中進(jìn)行pwm7的復(fù)用佩厚。

(1)拷貝ELF1開發(fā)板資料包\02-Linux 源代碼\02-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


(3)修改設(shè)備樹文件arch/arm/boot/dts/imx6ull-elf1-emmc.dts

elf@ubuntu:~/work/linux-4.1.15-elf1$ vi arch/arm/boot/dts/imx6ull-elf1-emmc.dts

添加pwm7設(shè)備節(jié)點(diǎn)

&pwm7 {

????????pinctrl-names = "default";

????????pinctrl-0 = <&pinctrl_pwm7>;

????????status = "okay";

};


在iomux節(jié)點(diǎn)下面添加pwm7引腳復(fù)用

pinctrl_pwm7: pwm7grp {

???????fsl,pins = <

?????????????MX6UL_PAD_CSI_VSYNC__PWM7_OUT ????0x110b0

??????>;

};


取消其它用到csi功能的地方



至此pwm7已經(jīng)復(fù)用完成说订。

2抄瓦、實(shí)現(xiàn)控制窗簾開合的功能

該項(xiàng)目選用28BYJ-48步進(jìn)電機(jī)實(shí)現(xiàn)窗簾的開合操作,28BYJ-48電機(jī)需要4個GPIO來控制陶冷,需要在設(shè)備樹中進(jìn)行GPIO的復(fù)用并在內(nèi)核中添加電機(jī)驅(qū)動钙姊。

(1)修改設(shè)備樹文件arch/arm/boot/dts/imx6ull-elf1-emmc.dts。

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

添加設(shè)備節(jié)點(diǎn)

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>;

????????};


在iomux節(jié)點(diǎn)下面添加引腳復(fù)用

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ū)動

拷貝motor.c到內(nèi)核源碼的drivers/gpio目錄下埂伦,修改drivers/gpio目錄下的Makefile文件煞额,添加如下內(nèi)容:

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/

(4)保存并重啟開發(fā)板

root@ELF1:~# sync ???????????????????????????????????????????

root@ELF1:~# reboot


五胀莹、基于Qt界面的數(shù)據(jù)采集和控制

1、程序設(shè)計

主函數(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è)置顯示的時間的樣式和位置

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)時間 */

????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);


????/* 使用資源里的文件時格式是 :+前綴+文件路徑 */

????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)定時器計時 1000 毫秒后婚温,刷新 lcd 顯示當(dāng)前系統(tǒng)時間 */

???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)用編譯

(1)拷貝smartclassroom.tar.bz2到開發(fā)環(huán)境/home/elf/work目錄下解壓

elf@ubuntu:~/work$ tar xvf smartclassroom.tar.bz2

(2)執(zhí)行環(huán)境變量

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 *

(5)拷貝smartclassroom.tar.bz2壓縮包到開發(fā)板/home/root路徑下解壓

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

六、項(xiàng)目測試

1栅螟、確保開發(fā)板已正確連接風(fēng)扇荆秦、步進(jìn)電機(jī)和屏幕

2、執(zhí)行應(yīng)用

root@ELF1:~# export DISPLAY=:0.0

root@ELF1:~# ./app

應(yīng)用執(zhí)行成功后嵌巷,Qt界面顯示如下,此時可以通過切換按鈕選擇手動控制或者感應(yīng)控制風(fēng)扇開關(guān)以及窗簾開合室抽。


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末搪哪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子坪圾,更是在濱河造成了極大的恐慌晓折,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,185評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兽泄,死亡現(xiàn)場離奇詭異漓概,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)病梢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,445評論 3 385
  • 文/潘曉璐 我一進(jìn)店門胃珍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蜓陌,你說我怎么就攤上這事觅彰。” “怎么了钮热?”我有些...
    開封第一講書人閱讀 157,684評論 0 348
  • 文/不壞的土叔 我叫張陵填抬,是天一觀的道長。 經(jīng)常有香客問我隧期,道長飒责,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,564評論 1 284
  • 正文 為了忘掉前任仆潮,我火速辦了婚禮宏蛉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘性置。我一直安慰自己檐晕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,681評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著辟灰,像睡著了一般个榕。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上芥喇,一...
    開封第一講書人閱讀 49,874評論 1 290
  • 那天西采,我揣著相機(jī)與錄音,去河邊找鬼继控。 笑死械馆,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的武通。 我是一名探鬼主播霹崎,決...
    沈念sama閱讀 39,025評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼冶忱!你這毒婦竟也來了尾菇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,761評論 0 268
  • 序言:老撾萬榮一對情侶失蹤囚枪,失蹤者是張志新(化名)和其女友劉穎派诬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體链沼,經(jīng)...
    沈念sama閱讀 44,217評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡默赂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,545評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了括勺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缆八。...
    茶點(diǎn)故事閱讀 38,694評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖疾捍,靈堂內(nèi)的尸體忽然破棺而出耀里,到底是詐尸還是另有隱情,我是刑警寧澤拾氓,帶...
    沈念sama閱讀 34,351評論 4 332
  • 正文 年R本政府宣布冯挎,位于F島的核電站,受9級特大地震影響咙鞍,放射性物質(zhì)發(fā)生泄漏房官。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,988評論 3 315
  • 文/蒙蒙 一续滋、第九天 我趴在偏房一處隱蔽的房頂上張望翰守。 院中可真熱鬧,春花似錦疲酌、人聲如沸蜡峰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,778評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽湿颅。三九已至载绿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間油航,已是汗流浹背崭庸。 一陣腳步聲響...
    開封第一講書人閱讀 32,007評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谊囚,地道東北人怕享。 一個月前我還...
    沈念sama閱讀 46,427評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像镰踏,于是被迫代替她去往敵國和親函筋。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,580評論 2 349

推薦閱讀更多精彩內(nèi)容