加入星計(jì)劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴(kuò)散
  • 作品版權(quán)保護(hù)
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長(zhǎng)期合作伙伴
立即加入
  • 正文
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請(qǐng)入駐 產(chǎn)業(yè)圖譜

ElfBoard開源項(xiàng)目|“智慧教室”開源項(xiàng)目技術(shù)文檔

09/11 14:10
1110
  • 1評(píng)論
閱讀需 24 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點(diǎn)資訊討論

“智慧教室”項(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)境。接下來(lái),將和各位小伙伴深入探討這一項(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)控制:用戶可以通過(guò)切換界面按鈕選擇手動(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è)備壽命。

二、 環(huán)境說(shuō)明

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)的其它功能,需要對(duì)內(nèi)核源碼進(jìn)行以下適配步驟。

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

風(fēng)扇采用pwm的方式來(lái)控制,需要在設(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

(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個(gè)GPIO來(lái)控制,需要在設(shè)備樹中進(jìn)行GPIO的復(fù)用并在內(nèi)核中添加電機(jī)驅(qū)動(dòng)
(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ū)動(dòng)。

拷貝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盤,通過(guò)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è)計(jì)

主函數(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)用編譯

(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)目測(cè)試

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

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

root@ELF1:~# export DISPLAY=:0.0
root@ELF1:~# ./app

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

相關(guān)推薦

電子產(chǎn)業(yè)圖譜