基于开放式虚拟仿真实验教学管理平台的嵌入式智能家居远程系统

本实验基于嵌入式高性能实验箱及其配套传感器,采集温度、光照、PM2.5、CO2等信息,并将信息远程发送到云端,智能手机下载云端数据并显示在手机主界面,当值高于报警值时,系统报警。

将整个系统分为客户端与服务端,客户端负责收集传感器数据并发送到服务器,服务端负责接收数据,更新数据库并且显示到网页上,如图1所示。

 

1 智能家居系统结构逻辑

开发板采用嵌入式6410实验箱,每秒收集数据并且以数据报的形式更新到云服务器上,云服务器接收数据并存入数据库中,网页读取数据库中的内容,用户手动刷新更新网页中有关传感器的相关信息。开发板安装了linux系统,根据linux系统驱动规范来编写相关传感器的驱动程序并加载到linux系统中。

 

 

客户端的系统设计如下:

 

服务器端系统设计如下:

 

应用程序软件流程图如下:

  

(二)构建嵌入式Linux系统

本次实验利用Linux系统来构建虚拟实验平台,我用的是ubuntu 64位的系统。构建好ubuntu系统如下:

接下来就是配置交叉编译环境了,我使用的是arm-linux-gcc-v6

 

然后进行解压缩命令,首先进入arm-linux-gcc的目录。

首先切入到编译器所在目录中:cd /tmp

然后进行解压缩: tar xvzf arm-linux-gcc-4.5.1-v6-vfp-20101103.tgz -C/

后面的大写是C是为了将arm-linux-gcc安装到opt/FriendlyARM/toolschain/4.5.1目录。

接下来就要将其加入环境变量了,我直接修改etc/profile然后每一个用户执行source etc/profile就不必单独修改单个用户的用户环境变量了。使用vim编辑器,结果如下:

 

每个用户都执行语句:source /etc/profile 语句后,环境变量便设置完成。

到此,交叉编译环境便配置完成。

(三)基于QT的图形主界面设计

  接下来就是配置QT图形界面了,首先因为我使用的是64位的Ubuntu的操作系统,所以要安装许多配置文件和32位的文件,在这里浪费了较多的时间。

  老师提供的qt-sdk-linux-x86-opensouce-2010.05.1.bin文件在我的虚拟机中老是出错,如下:

 

  经过查阅资料,发现是qmake的配置问题,于是我又自己下载了一个QT,重新位置了一下。

  然后按照步骤一步一步的安装,基本上都是选择默认安装,安装完成以后在目录下出现了相应的qtsdk-2010.05文件夹,如下所示:

 


接下来还是需要来配置环境变量,我还是安装上面的方法修改了etc/profile文件,将QT的环境变量加入,如下:


然后执行:source /etc/profile命令,将刚才所修改的profile文件立即生效。

这个时候我执行qtcreator命令,发现竟然找不到文件?


经过搜索发现,原来是因为自己缺少了很多配置文件没有装,然后利用dpkg来装:


本来是有很多配置文件没有装的,但是当时只顾着找,便忘了截图,就只截了一张,就是利用该方法来需要需要安装的软件包然后再利用apt-get install 来安装。终于,在n次安装软件包只会,成功启动安装了qtcreator,我首先进行了测试的过程如下:

 

 








编写智能家居设备端控制软件总体架构界面如下图所示:

 

功能如下:红外接收红外发射

      

QT中设计制作效果如下所示

 

(四)传感器采集及设计

LED灯点亮熄灭控制,打开关闭窗帘电动控制,当前温度传感器采集显示控制界面设计:


 




部分使用如下代码

main_form.h

#if !defined (__MAIN_FORM_H__)

# define __MAIN_FORM_H__

#include "main_form_base.h"

class TMainForm: public TMainFormBase {

Q_OBJECT

public:

TMainForm(QWidget * parent = 0, const char * name = 0, WFlags f = WType_TopLevel);

virtual ~TMainForm();

private slots:

void buttonClicked();

private:

int m_fd;

};

#endif

 

main_form.cpp

#include "main_form.h"

#include <qlabel.h>

#include <qpushbutton.h>

#include <qlayout.h>

#include <qspinbox.h>

#include <unistd.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <sys/ioctl.h>

#include <fcntl.h>

#include <qapplication.h>

#define PWM_IOCTL_SET_FREQ 1

#define PWM_IOCTL_STOP 0

TMainForm::TMainForm(QWidget * parent, const char * name, WFlags f)

: TMainFormBase(parent, name, f)

{

m_fd = ::open("/dev/pwm", O_RDONLY);

::ioctl(m_fd, PWM_IOCTL_STOP);

connect(m_startButton, SIGNAL(clicked()), this, SLOT(buttonClicked()) );

connect(m_stopButton, SIGNAL(clicked()), this, SLOT(buttonClicked()) );

connect(m_closeButton, SIGNAL(clicked()), this, SLOT(buttonClicked()) );

}

TMainForm::~TMainForm()

{

::ioctl(m_fd, PWM_IOCTL_STOP);

::close(m_fd);

}

void TMainForm::buttonClicked()

{

QPushButton* obj = (QPushButton*)sender();

if (obj == m_startButton) {

::ioctl(m_fd, PWM_IOCTL_SET_FREQ, 1000);

} else if (obj == m_stopButton) {

::ioctl(m_fd, PWM_IOCTL_STOP);

} else if (obj == m_closeButton) {

close();

}

}

 

(五)远程web服务器设计及实现

首先为了完成远程控制我需要先构建BOA服务器,Boa是一种非常小巧的Web服务器,其可执行代码只有大约60KB左右。作为一种单任务Web服务器,Boa只能依次完成用户的请求,而不会fork出新的进程来处理并发连接请求。但Boa支持CGI,能够为CGI程序fork出一个进程来执行。

首先下载Boa源码boa-0.94.13.tar.gz,并解压:

# tar xzf boa-0.94.13.tar.gz

 

解压:

 

然后安装需要工具bisonflex,通过命令:sudo apt-get install bison flex来进行安装。否则会出现错误。

然后修改文件src/compat.h、修改src/boa.c和src/log.c。找到#define TIMEZONE_OFFSET(foo) foo##->tm_gmtoff修改成:#define TIMEZONE_OFFSET(foo) (foo)->tm_gmtoff。

 

然后在src/log.c注释掉如下内容:

if (dup2(error_log, STDERR_FILENO) == -1)

{ DIE("unable to dup2 the error log");}

 

src/boa.c中注释掉下面两句话:

if (passwdbuf == NULL)

{DIE(”getpwuid”);}
if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1)

{DIE(”initgroups”);}

 

if (setuid(0) != -1)

{DIE(”icky Linux kernel bug!”);}

 

然后需要生成Makefile文件,执行:#cd boa-0.94.13/src

#./configure

修改Makefile

#cd src
#vim Makefile

修改CC = gcc 为 CC = arm-linux-gcc

修改CPP = gcc -E 为 CC = arm-linux-gcc -E

然后进行编译

#ls -l boa -rwxr-xr-x 1 david david 189223 2009-05-31 13:44 boa

然后为生成的二进制文件boa瘦身:

#ls -l boa -rwxr-xr-x 1 david david 61052 2009-05-31 13:51 boa

然后需要对Boa进行配置,这一步的工作也在电脑主机上完成。在boa-0.94.13目录下已有一个示例boa.conf,可以在其基础上进行修改。如下:

#vi boa.conf

(1)修改 Group nogroup为 Group 0

(2)修改User nobody为 User 0

(3)修改ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/为 ScriptAlias /cgi-bin/ /var/www/cgi-bin/

(5)修改DoucmentRoot /var/www

(6)修改#ServerName www.your.org.here为 ServerName www.your.org.here

(7)修改AccessLog /var/log/boa/access_log为#AccessLog /var/log/boa/access_log

以下步骤在开发板上进行:

创建目录/etc/boa并且把boa 和 boa.conf拷贝到这个目录下mkdir /etc/boa创建HTML文档的主目录/wwwmkdir /var/www/cgi-bin

CGI脚本所在录 /var/www/cgi-bin

以下步骤在ubuntu下进行:

boa.conf拷贝到开发板根文件系统的/etc/boa下

#cp boa.conf /source/rootfs/etc/boa

boa拷贝到开发板根文件系统的/bin下

#cp src/boa /source/rootfs/bin

ubuntu下/etc/mime.types拷贝到开发板根文件系统的/etc下

#cp /etc/mime.types /source/rootfs/etc

将你的主页index.html拷贝到 /var/www 目录下。

这样环境就搭建完成了。接下来将进入实际应用阶段。在这里以控制LED为例。

1.客户端控制界面

采用CGI将浏览器端的控制信息传到boa服务器端,index.html文件

<html xmlns="http://www.w3.org/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    

<title>web控制mini2440开发板led</title>

</head>

<body>

<h1 align="center">基于mini2440web控制GPIO</h1>

<form action="/cgi-bin/cgi_led.cgi" method="get">   

<p align="center">led的测试工作</p>

<p align="center">请输入需要控制的led <input type="text" name="led_control"/></p>

<p align="center">请输入控制led的动作 <input type="text" name="led_state"/></p>

<p align="center"><input type="submit" value="sure"/>        

<input type="reset" value="back"/>

</p>

</form>

</body>

</html>

2.服务器端数据处理

通过客户端浏览器的from表单将,控制信息提交到服务器,服务器获取数据并通过有名管道将控制数据传给调用LED驱动的控制程序。

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/stat.h>

#include <sys/mman.h>

#include <limits.h>

#include <string.h>

#define MYFIFO "/www/myfifo"

#define MAX_BUFFER_SIZE PIPE_BUF

int main()

{

    char* data;   //定义一个指针用于指向QUERY_STRING存放的内容

    char buff[MAX_BUFFER_SIZE];

    int fd, nwrite;

    int led_control, led_state;

    printf("Content-type: text/html\n\n");

    printf("<html>\n");

    printf("<head><title>cgi led demo</title></head>\n");

    printf("<body>\n");

    printf("<p>led is setted successful! you can watch the led's change</p>\n");

    printf("<p><a herf=index.html><button>get back</button></a></p>\n");

    printf("</body>\n");

   data = getenv("QUERY_STRING"); //getenv()读取环境变量的当前值的函数

    strcpy(buff, data);

    fd = open(MYFIFO, O_WRONLY);

    if(-1 == fd)

    {

        printf("Open fifo file error\n");

        exit(1);

    }

    if((nwrite = write(fd, buff, sizeof(buff))) < 0)

    {

        printf("\nWrite data error\n");

        exit(1);

    }

    if(sscanf(buff,"led_control=%d&led_state=%d",&led_control,&led_state)!=2)

    {   //利用sscnaf()函数的特点将环境变量分别提取出led_controlled_state这两个值

        printf("<p>please input right");

        printf("</p>");

    }

    printf("<p>led_control = %d,led_state =  %d</p>", led_control, led_state);

    if(led_control>3)

    {

        printf("<p>Please input 0<=led_control<=3!");

        printf("</p>");

    }

    if(led_state>1)

    {

        printf("<p>Please input 0<=led_state<=1!");

        printf("</p>");

    }

    close(fd);

    printf("</html>\n");

    return 0;

}

3.控制端

通过管道接受到控制数据,调用驱动程序实现对LED灯的控制

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/ioctl.h>

#include <sys/stat.h>

#include <sys/mman.h>

#include <errno.h>

#include <limits.h>

#include <string.h>

#include <linux/micro2440_leds.h>

#define MYFIFO "/www/myfifo"

#define LEDS_DEVICE  "/dev/led4s"

#define MAX_BUFFER_SIZE PIPE_BUF

int main(int argc, char* argv[])

{

    int led_fd, fifo_fd, led_control,led_state, nread;

    struct leds_stat oneStat;

    char buff[MAX_BUFFER_SIZE];  //定义一个指针用于指向QUERY_STRING存放的内容

    led_fd = open(LEDS_DEVICE, O_RDWR);  //打开led设备

    if(-1 == led_fd)

    {

        perror("open led device");

        exit(1);

    }

    if(-1 == access(MYFIFO, F_OK))

    {

        if((mkfifo(MYFIFO, 0666) < 0) && (errno != EEXIST))

        {

            printf("Connot create fifo file\n");

            exit(1);

        }

    }

    fifo_fd = open(MYFIFO, O_RDONLY);

    if(-1 == fifo_fd)

    {

        perror("open fifo file error\n");

        exit(1);

    }

    while(1)

    {

        //memset(buff, 0, sizeof(buff));使用会使控制数据出错

        if((nread = read(fifo_fd, buff, sizeof(buff))) < 0)

        {

            perror("Read data error");

            exit(1);

        }

if(sscanf(buff,"led_control=%d&led_state=%d",&led_control,&led_state)!=2)

        {   //利用sscnaf()函数的特点将环境变量分别提取出led_controlled_state这两个值

            printf("please input right \n");

            exit(1);

        }

        if(led_control>3)

        {

            printf("Please input 0<=led_control<=3!");

            exit(1);

        }

        if(led_state>1)

        {

            printf("Please input 0<=led_state<=1!");

            exit(1);

        }

        oneStat.led_nr = led_control;

        oneStat.led_st = led_state;

        ioctl(led_fd, LEDS_SET_ONE, &oneStat);

    }

    close(led_fd);

    close(fifo_fd);

    return 0;

}


猜你喜欢

转载自blog.csdn.net/weixin_40602516/article/details/80984024
今日推荐