ElfBoard开源项目|“智慧教室”开源项目技术文档

devtools/2024/12/22 1:34:20/

“智慧教室”项目的目标是实现实时采集环境中的温度、湿度及光照信息,并将这些数据可视化地呈现在Qt图形界面上。用户既可以选择手动控制风扇与窗帘的开关,也可以设置系统根据所采集的环境参数自动调节,以达到舒适的室内环境。接下来,将和各位小伙伴深入探讨这一项目的具体实现方式。

一、 功能特性

1、数据监测与显示:实时监测室内温度、湿度和光照强度,并直观地显示在Qt界面上。

2、手动/感应控制:用户可以通过切换界面按钮选择手动控制风扇和窗帘的状态,或者根据实时监测到的环境数据,自动的调节风扇和窗帘的状态,以提供最佳的舒适度和能源利用效率。

3、节能优化:自动调节功能可实时调整设备状态,以减少能源消耗并提高设备寿命。

二、 环境说明

1、开发环境操作系统:Ubuntu18.04 64位版

2、交叉编译工具链:arm-poky-linux-gnueabi-gcc 5.3.0

3、开发板使用Bootloader版本:u-boot-2016.03

4、开发板内核版本:linux-4.1.15

5、开发板移植QT版本:qt5.6.2

三、 硬件连接

1、风扇与板卡的连接

图片

2、步进电机与板卡的连接

图片

四、 内核适配

ELF 1开发板已集成温湿度传感器与光线传感器,实现环境温度、湿度和光照强度的采集。为支持智慧教室系统的其它功能,需要对内核源码进行以下适配步骤。

1、实现风扇转动的功能

风扇采用pwm的方式来控制,需要在设备树中进行pwm7的复用。

(1)拷贝ELF1开发板资料包\02-Linux 源代码\02-0 出厂内核和uboot源码\内核源码\linux-4.1.15-elf1.tar.bz2内核源码到开发环境/home/elf/work/目录下解压。

elf@ubuntu:~/work$ tar -xvf linux-4.1.15-elf1.tar.bz2

(2)修改顶层设备树文件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)修改设备树文件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设备节点

&pwm7 {pinctrl-names = "default";pinctrl-0 = <&pinctrl_pwm7>;status = "okay";
};

图片

在iomux节点下面添加pwm7引脚复用

pinctrl_pwm7: pwm7grp {fsl,pins = <MX6UL_PAD_CSI_VSYNC__PWM7_OUT     0x110b0>;
};

图片

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

图片

图片

至此pwm7已经复用完成。

2、实现控制窗帘开合的功能

该项目选用28BYJ-48步进电机实现窗帘的开合操作,28BYJ-48电机需要4个GPIO来控制,需要在设备树中进行GPIO的复用并在内核中添加电机驱动。

(1)修改设备树文件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

添加设备节点

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节点下面添加引脚复用

mymotor: mymotorgrp {fsl,pins = <MX6UL_PAD_CSI_DATA00__GPIO4_IO21        0x10b0MX6UL_PAD_CSI_DATA01__GPIO4_IO22        0x10b0MX6UL_PAD_CSI_DATA02__GPIO4_IO23        0x10b0MX6UL_PAD_CSI_DATA03__GPIO4_IO24        0x10b0>;
};

图片

(2)添加电机驱动。

拷贝motor.c到内核源码的drivers/gpio目录下,修改drivers/gpio目录下的Makefile文件,添加如下内容:

obj-y += motor.o

图片

3、编译并替换设备树和内核

(1)执行环境变量

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)编译设备树和内核

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盘拷贝到开发板。

root@ELF1:~# cp /run/media/sda1/imx6ull-elf1-emmc.dtb /run/media/mmcblk1p1/
root@ELF1:~# cp /run/media/sda1/zImage /run/media/mmcblk1p1/

(4)保存并重启开发板

root@ELF1:~# sync                                            
root@ELF1:~# reboot

五、基于Qt界面的数据采集和控制

1、程序设计

图片

主函数的实现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;
}

设置显示的时间的样式和位置

void MWainWindow::showtime()
{/* 实例化与设置显示的位置大小*/lcdNumber = new QLCDNumber(this);QScreen *screen = QGuiApplication::primaryScreen();// 获取屏幕分辨率的大小QSize screenSize = screen->size();int screenWidth = screenSize.width();int screenHeight = screenSize.height();// 根据屏幕分辨率的大小执行不同的操作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";}/* 设置显示的位数 8 位 */lcdNumber->setDigitCount(8);/* 设置样式 */lcdNumber->setFrameStyle(QFrame::NoFrame);/* 设置 lcd 显示为当前系统时间 */QTime time = QTime::currentTime();/* 设置显示的样式 */lcdNumber->display(time.toString("hh:mm:ss"));lcdNumber->setStyleSheet("color: black");}

设置显示的图片的大小和位置

void MWainWindow::showphoto()
{    /* 设置大小与位置 */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();// 根据屏幕分辨率的大小执行不同的操作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";}/* 设置图像 */labelImage->setPixmap(pixmap);/* 开启允许缩放填充 */labelImage->setScaledContents(true);}

获取设备的状态

void MWainWindow::readData()
{/* 当定时器计时 1000 毫秒后,刷新 lcd 显示当前系统时间 */QTime time = QTime::currentTime();/* 设置显示的样式 */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;}}
}

设置界面样式

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、应用编译

(1)拷贝smartclassroom.tar.bz2到开发环境/home/elf/work目录下解压

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

(2)执行环境变量

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压缩包到开发板/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

六、项目测试

1、确保开发板已正确连接风扇、步进电机和屏幕

2、执行应用

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

应用执行成功后,Qt界面显示如下,此时可以通过切换按钮选择手动控制或者感应控制风扇开关以及窗帘开合。

图片


http://www.ppmy.cn/devtools/110302.html

相关文章

【网络安全】漏洞挖掘:文件上传实现Webshell

未经许可,不得转载。 文章目录 正文正文 提交文件功能点,显示只能上传png、jpg、pdf文件 上传一个正常的图片,请求响应如下: 可以看到,该文件被上传到redacted.com,这为后面实现Webshell提供了前提。 接着,我上传webshell.php文件,文件内容为payload,拦截请求包,将…

Java重修笔记 第五十三天 坦克大战(一)绘图入门

绘制简单的图形 1. 创建画板 定义一个画板类&#xff0c;通过继承 JPanel 类来创建画板 2. 创建画笔 在画板类中调用 paint 方法&#xff0c;并传入一个 Graphics g 对象&#xff0c;通过对 g 对象的操作来实现画画的过程 3. 开始作画 调用 Graphics g 对象的方法在 paint …

【代码随想录训练营第42期 Day55打卡 - 图论Part5 - 并查集的应用

目录 一、并查集 适用范围 三大基本操作 二、经典题目 题目&#xff1a;卡码网 107. 寻找存在的路径 题目链接 题解&#xff1a;并查集 三、小结 一、并查集 适用范围 动态连通性问题&#xff1a;并查集可以判断两个节点是否在同一个连通分量中&#xff0c;这在处理网络…

美团GTIS防重系统 幂等操作 防重提交

一、介绍 美团GTIS防重系统 使用 请求参数与用户Token或URL 生成全局业务ID 有效防止 同一个用户 在 限制时间 内对 同一个业务 提交 相同的数据 流程图: 二、注解方式(基于AOP切面实现) 2.1 切面代码 根据token 和 请求参数生成唯一key 来验证重复请求异常 或者 处理失败…

C语言小游戏--贪吃蛇实现

C语言小游戏--贪吃蛇实现 1.游戏实现背景2.Win32 API介绍2.1什么是Win32 API2.2控制台程序(Console)2.3控制台屏幕的坐标COORD2.4GetStdHandle2.4.1函数语法2.4.2函数的使用 2.5GetConsoleCursorInfo2.5.1函数语法2.5.2函数的使用 2.6CONSOLE_CURSOR_INFO2.6.1结构体结构2.6.2结…

字符串模式匹配有哪些常见应用场景

1. 文本搜索与编辑器 文本编辑器&#xff1a;在文本编辑器中查找关键字或替换文本中的特定字符串时&#xff0c;通常会使用字符串模式匹配算法。用户输入一个关键词&#xff0c;编辑器会从文件的头部开始逐个字符进行比较&#xff0c;直到找到匹配的子串或者遍历完整个文件。 …

Python 从入门到实战13(字符串简介)

我们的目标是&#xff1a;通过这一套资料学习下来&#xff0c;通过熟练掌握python基础&#xff0c;然后结合经典实例、实践相结合&#xff0c;使我们完全掌握python&#xff0c;并做到独立完成项目开发的能力。 上篇文章我们通过举例学习了流程控制语句中的循环语句。今天继续讨…

实现C程序绑定TCP端口

实现C程序绑定TCP端口 步骤概述伪代码C代码实现解释在网络编程中,TCP(传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。绑定TCP端口是服务器端应用程序在网络通信中的一个关键步骤,它允许服务器监听来自客户端的连接请求。 本文将介绍如何使用C语言…