基于Linux的智能家居的设计(5)
软件设计部分主要包含uboot移植、内核编译、系统移植、设备驱动编程、应用程序编程(QT编程、mysql数据库编程、控制系统编程)、各个模块的功能函数(部分是在windows以下的IAR中实现)。
软件部分的结构框图如图4-1所看到的:
图4-1 软件结构框图
4.1 U-boot移植因为每一个操作系统在执行前必需要执行一段小程序,这个就是通常说的Bootloader。类似windows的BIOS的固件程序[15]。通过这段程序可以初始化硬件设备、建立内存空间映射图。从而将系统引入一个合适的状态,以便可以终于调用操作系统内核准备好的正确环境[16]。Bootloader的启动程序流程图如图4-2所看到的:
图4-2 Bootloader的启动程序流程图
①下载U-boot源代码。到站点http://www.denx.de/wiki/U-Boot下载须要的源代码uboot1.1.6-2012-09-25.tar.gz
②建立和ARM板相适应的类型
改动顶层的Makefileproject文件,改动编译器的路径如图4-3所看到的:
图4-3 编译器的路径
③改动相关的參数參数包含目标板的相关的文件;独立于处理器体系结构的通用代码,比如内存大小的探測与故障检測;与处理器相关的文件,设备驱动程序等。④编译并測试执行#make smdk6410_config和#make命令如图4-4所看到的图4-4 执行#make smdk6410_config和#make命令
编译的时间比較长,最后生成的一个u-boot文件,使用file u-boot命令查看该文件,推断是否生成了ARM平台可以执行的u-boot。图4-5 查看u-boot文件的属性
将生成的u-boot文件复制到SD卡上进行。然后开发板通过SD卡启动,进入putty控制台设置U-boot环境变量:图4-6 设置U-boot环境变量
这里要检測可以ping通虚拟机才干进行下一步:使用ping 192.168.12.18
图4-7 检測可以ping通虚拟机
Linux内核尽管支持多种硬件平台,可是对于一个嵌入式的设备,有些功能是没有必要的,所以要进行一些裁剪[17]。对于这个平台须要用到的就是触摸屏,GPIO口。以太网,串口,摄像头,NandFlash这几个主要驱动程序。
仅仅须要将用到的东西裁剪下来就够了。以下是内核裁剪的基本思路:
①下载并解压源代码包。本次课题使用的Linux-3.0.1版本号的源代码;
②配置编译平台改动Makefile。基本的是体系结构和交叉编译变量的定义。
如图4-8所看到的:
图4-8 改动makefile
③裁剪内核
运行命令:
#make menuconfig
图4-10 内核裁剪界面
进入到Device Drivers上进行配置自己想要的信息当中空格代表的是不须要编译。“*”代表的是必须编译的,“M”是可载入的选项。
执行make zImage制作内核镜像,生成的内核镜像在arch/arm/boot/文件夹下:
通过tftp服务烧写内核镜像到NandFlash上。
利用OK6410开发提供的工具使用命令:
#./mkyaffs2image-nand256m FileSystem-Yaffs2 rootfs.yaffs2
通过tftp服务文件系统烧写到NandFlash中。
本课题的QT程序设计有两个部分,一个是在PC机上执行的远程的client,一个是在开发板的触屏上执行的Qt程序。Qt开发的框架如图4-12所看到的:
嵌入式Qt应用程序从开发到可以应用的流程如图4-13所看到的:
OK6410板上执行的程序设计。首先做一个UI界面,这里使用的是QWidget类设计的。QWidget类是全部用户界面对象的基类。窗体部件是用户界面的一个原子:他从窗体系统接受鼠标、键盘、和其它事件(点触),而且在屏幕上绘制自己的表现[18]。每个窗体部件都是矩形,窗体部件能够被其它的父窗体盖住不见或者被前面的部件盖住一部分。
使用qt-disgner进行布局设计,会得到自己想要的界面效果。本系统在开发板上执行的GUI界面如图4-14所看到的。
图4-14 GUI界面
4.4.2 信号与槽信号与槽机制是Qt的核心机制。信号与槽式一种高级接口,用于对象之间的通信[19]。
当对象改变时。信号就由该对象发射(emit)出去,指导对象所要做的所有事情,通过调用 QObject对象的 connect函数来将某个对象的信号与另外一个对象的槽函数相关联,这样当发射者发射信号时,接收者的槽函数将被调用[20]。该函数的定义例如以下:
bool QObject::connect ( constQObject * sender, const char * signal, const QObject * receiver, const char *member )
本课题中的电灯泡和温湿度的触发就是使用的这个机制,当触屏上的一个事件电灯泡被按下的瞬间就会发送一个信号。调用电灯泡点亮的函数。信号与槽的机制流程图如图4-15所看到的:
使用的一些信号例如以下:
signals:
void isLight(bool states); //灯泡控制信号
void setTempSignal(int temp); //温度信号
void setHumSignal(int hum); //湿度信号
使用的槽函数例如以下:
private slots:
void on_btnLed4_clicked();
void on_btnLed3_clicked();
voidon_btnLed2_clicked();
void on_btnLed1_clicked();
void readMyCom();
void all_Led_on_writeCom();
void all_Led_off_writeCom();
void temphum_writeCom();
void setLightStates(bool states);
void setTempSlot(int temp);
void setHumSlot(int hum);
信号与槽的连接函数例如以下:
MainWin::MainWin(QWidget*parent) :
QWidget(parent),
ui(new Ui::MainWin)
{
ui->setupUi(this);
startInit();
……
connect(tempTimer, SIGNAL(timeout()), this,SLOT(temphum_writeCom()));
connect(this,SIGNAL(isLight(bool)),this,SLOT(setLightStates(bool)));
connect(this,SIGNAL(setTempSignal(int)),this,SLOT(setTempSlot(int)));
connect(this,SIGNAL(setHumSignal(int)),this,SLOT(setHumSlot(int)));
……
}
4.5 智能电器的控制设计本课题的以室内的空调作为一个智能电器,设置一个温度阈值。当温度到达这个阈值的时候启动空调,比方一般夏天室内的温度为25摄氏度,假设温度超过了25摄氏度。那么空调就会自己主动开启。通过周期性的获取室内当前的温度。而且对接受的信息与设定的值进行比对当温度到达适宜的温度的时候自己主动停止,这样能够节约用电。这里的数据处理是DHT11获取环境中的温度。发送到OK6410开发板。与设置的温度进行对照。假设温度超出了阈值,那么就发送对应的指令。
同一时候在触摸屏的界面上能够看到空调对应的状态。
图4-16是温度控制的一个流程图。
因为ARM网关和Zigbee协调器之间是基于RS232串口通信,所以为了解决串口通讯的问题,本课题採用的是波特率为115200。数据位为8,停止位为1。无校验数据位。涉及到数据通信就得设计一个数据的帧格式,这里的帧格式设置为:帧头+节点ID码+模块的ID码+数据(CommandH + CommandL)+帧尾。
这个数据帧的具体说明能够用DHT11温湿度传感器来描写叙述,比如一个温度数据帧为:
0xCC,0xEE,0x01,0x03,0x01,0x00,0x00,0xFF
模块ID用于差别是那个模块由灯的模块、温湿度模块、电机模块等。
这些数据仅仅是发送的命令,那么接受数据帧格式有些差别的在于帧头。数据为0xEE 0xCC比如接收到一个数据帧为:
0xEE,0xCC,0x01,0x03,0x01,0x01,0x01,0xFF
Qt串口编程使用的是库函数编程,使用QextSerialPort类,QextSerialPort类读取串口数据的方式有两种:Polling即轮询方式、EventDriven是指事件驱动方式[21]。可是在Linux系统中仅仅能使用Polling方式,这样的方式下串口读/写是同步的。信号在这样的状态下是无法使用。这样的方式的长处是系统开销小,可是须要自定义一个定时器去读取串口的数据。
使用QextSerialPort实现串口通信,实现串口数据通信的配置工作在以下代码中能够集中的体现。
void MainWin::openCom() { myCom = new Posix_QextSerialPort(COM, QextSerialBase::Polling); //这里QextSerialBase::QueryMode应该使用QextSerialBase::Polling isOpen = myCom->open(QIODevice::ReadWrite); if(isOpen){ // QMessageBox::information(this, tr("打开成功"), tr("已成功打开串口 ") + COM, QMessageBox::Ok); }else{ QMessageBox::critical(this, tr("打开失败"), tr("未能打开串口 ") + COM + tr("\n该串口设备不存在或已被占用"), QMessageBox::Ok); return; } //设置波特率:115200 myCom->setBaudRate(BAUD115200); //设置数据位:8位 myCom->setDataBits(DATA_8); //设置校验:无 myCom->setParity(PAR_NONE); //设置停止位 myCom->setStopBits(STOP_1); //开启读取定时器 timer->start(timerdly); //设置数据流控制 myCom->setFlowControl(FLOW_OFF); //设置延时 myCom->setTimeout(TIME_OUT); }
Zigbee的程序设计使用了IARworkbench开发工具,实现了串口的通信、灯泡的控制、风扇空调的控制、窗帘的控制、传感器的传输数据功能。
串口的使用基本步骤:
①初始化串口,当中包括波特率、校验位、中断、时钟频率等。详细的代码例如以下:
/**************************************************************** 串口初始化函数 ***********************************************************/ void InitUart() { CLKCONCMD &= ~0x40; // 设置系统时钟源为 32MHZ晶振 while(CLKCONSTA & 0x40); // 等待晶振稳定 CLKCONCMD &= ~0x47; // 设置系统主时钟频率为 32MHZ PERCFG = 0x00; //位置1 P0口 P0SEL = 0x3c; //P0_2,P0_3,P0_4,P0_5用作串口,第二功能 P2DIR &= ~0XC0; //P0 优先作为UART0 。优先级 U0CSR |= 0x80; //UART 方式 U0GCR |= 11; //U0GCR与U0BAUD配合 U0BAUD |= 216; // 波特率设为115200 UTX0IF = 0; //UART0 TX 中断标志初始置位0 U0CSR|=0x40; //同意接收 IEN0|=0x84; //开总中断,接收中断 }
②向发送缓冲区发送数据或者从接收缓冲区读取数据。详细的代码例如以下:
/**************************************************************** 串口发送数据函数 ****************************************************************/ void Uart_Send_String(uchar *Data,int len) { int j; for(j=0;j<len;j++) { U0DBUF = *Data++; while(UTX0IF == 0); UTX0IF = 0; } } /*******************串口接收函数***********************/ #pragma vector = URX0_VECTOR __interrupt void UART0_ISR(void) { URX0IF = 0; // 清中断标志 command = U0DBUF; Rxdata[p]=command; p++; if ( p == 8) { p = 0; } }
传感器模块、电机模块、电灯的控制主要用到的是IO口控制编程。使用的配置方式类似STM32的配置方式,详细的过程例如以下:
①功能设置寄存器P1SEL。默认是普通IO口。0表示普通IO口,1表示第二功能
②输入输出配置P1DIR,0表示输入,1表示输出
③IO口的输入时的电路模式配置。0表示上拉/下拉,1表示高阻态。
详细的代码以电灯泡为例说明:
void LEDABCD_INIT(void) { P1SEL &= ~0x30; //选择port P1DIR |= 0x30; //设置为输出模式 P1INP &= ~0x30; //打开上拉 }
由于OK6410开发板上的屏幕与PC机上的屏幕不一样。大小和字体都要设定须要设定。
由于用到的触摸屏是480*272的分辨率。这里支持的中文字体为“wenquanyi”所以在main.cpp中增加下面的代码:
int main(int argc, char *argv[]) { QApplication a(argc, argv); …… MainWin w; #if defined(_WS_QWS) || defined(Q_WS_QWS) w.showFullScreen(); QFont font("wenquanyi",12,QFont::Bold); a.setFont(font); #else w.resize(480, 272); #endif …… w.show(); …… }
在终端中使用交叉编译工具编译并结合脚本语言制作一个shell脚本,使用命令:
#vim myshell.sh
在文件里加入下面的内容:
#/bin/bash
qmake -project
/opt/qt-4.7.1/bin/qmake
make
cp SmartLife /nfsroot/FileSystem-Yaffs2/
然后更改myshell.sh的属性使用命令:
#chmod +777 myshell.sh
执行myshell.sh就能够实现交叉编译并将生成的可在ARM上执行的文件。
这样生成的SmartLife是一个ARM平台上能够运行的文件在putty中使用./SmartLife –qws 就可以运行生成SmartLife。
用户须要使用username和password才干登录,可爱的企鹅作为背景图片。实时查询家居中的全部情况,这样能够通过网络远程控制家居中的情况。
登录的界面使用对话框的模式来写的调用了Dialog类。username和password的校验使用的是密文方式进行的,详细的代码例如以下:
void Dialog::on_loginbtn_clicked() { QTextCodec::setCodecForTr(QTextCodec::codecForLocale()); if(ui->usredit->text()==tr("zhanghao")&&ui->pwdedit->text()==tr("123456")) { accept(); } else { QMessageBox::warning(this,tr("warning"),tr("user name or passwd wrong"),tr("yes"),tr("no")); //假设不对,弹出警告对话框 ui->usredit->clear();//清空username输入框 ui->pwdedit->clear();//清空password输入框 ui->usredit->setFocus();//将光标转到username输入框 } }
背景图片的加入使用画图工具将背景图片放到project文件夹的image下,通过调用paintEvent()函数来时实现,详细的代码:
void Dialog::paintEvent(QPaintEvent *) //界面图片的载人,要在头文件中声明此成员 { QPainter painter(this); QPixmap pix; pix.load(":/image/8.JPG"); painter.drawPixmap(0,0,400,350,pix); }
client相关的UI设计图如图4-17、4-18、4-19、4-20所看到的:
调试的思路是:使用USB转TTL串口,将USB转TTL串口的RX与OK6410开发上的上的TXD,将USB转串口的TX与OK6410开发板上的RXD,特别要注意的是要将OK6410开发板上的GND和USB转TTL串口的GND要接在一起(共地非常重要),之前由于这个问题浪费了非常多的时间,后来实验室的同学跟我说这个一定要共地。否则大多数时候传输数据会出现误码。然后使用串口调试助手在PC机上看发送的命令是否与自己在触摸屏上的操作一致,将接收到的数据保存在txt文档中。用记事本打开保存的txt文档,然后再与之前的操作所相应的命令进行比对发现这个txt文档进行比对发现全然一样。
能够得出结论1:智能家居的ARM网关的串口能够向外界发送指令。
相同的在串口调试助手中发送对应的数据。假设在TFT屏上能够实现对应的显示结果那么ARM网关串口能够接收外界发送的数据。能够得出结论2:智能家居ARM网关的串口能够正确的接受数据并做出对应的应答。
综合结论1和结论2能够得出ARM网关的串口程序是正确的。
5.2 Zigbee调试在Zigbee上的串口要确定数据是正确的,这里发送的数据是每都是通过串口的,首先得确定发送的数据是正确的。这里使用的串口调试助手。将发送的数据与串口调试助手上显示的数据进行比对,假设没有错误,那么这个串口的发送数据是没有问题的。
经过几番的调试和改动代码发现串口的数据发送最终能够按所须要的格式的发送数据了。接下来的便是接收数据,使用的方法是将接收到的数据发送出来在串口调试助手上显示。
可是在使用串口函数的时候就得给发送处理的数据屏蔽掉。不然发送处理的数据是无法预測的。
5.3 Zigbee与ARM之间的通讯调试Zigbee与ARM之间的调试出现的问题了一些问题,用无线传输数据会发送出错误的信息。这里的原因可能是代码的问题,由于使用无线传输要使用协议栈。而这个Zigbee并没有跑协议栈,如此用无线传输肯定会出现故障。
使用的无线串口数传输模块CC1101进行调试发现还是有问题,当中的原因可能是时序的问题。假设要全然解决问题。还是有非常大的困难,这个课题做到的不过有线的传输数据。
于是这个无线的传输失败告终了。只能使用有线的传输数据来进行调试,这样达到了预期的效果。
5.4 实物执行的效果智能家居模型是使用PVC板制作而成的,在模型中有:LED做成的灯具、直流电机和PVC材料做成的空调模型、减速电机和布条做成的窗帘、光照度採集模块(光敏电阻)、温湿度採集模块(DHT11)、门禁模块(单片机+RFID+舵机+蜂鸣器)。
智能家居执行(灯具所有打开。门禁刷卡成功,温湿度在设定的范围内)效果图1。如图5-1所看到的:
开发板上执行的效果(4个LED灯所有亮起,能够看到温湿度正常当前的显示:26摄氏度。湿度为35%。设定的温度阈值为27摄氏度。湿度为70%,当前的温湿度均没有超过阈值,所以空调没有开启)如图5-2所看到的:
本设计中对眼下国内外物联网智能家居系统的发展现状和未来的发展趋势,以及相关技术进行了具体的分析。
在现有的智能家居系统解决方式的基础上,提出了处理器和无线技术相结合的设计方案,而且融合了互联网通信技术,实现了真正意义上的物联网,以及远程对智能家居系统进行实时的监控和管理。本文中主要完毕了下面工作:
(1)在现有的智能家居系统解决方式的基础上,提出了智能家居系统的设计方案,主要包含家庭网关主控制器、终端受控设备、家庭内部控制网络、外部通讯网络四个部分。
(2)对家庭网关及其核心功能模块进行了具体的分析,而且完毕了电源模块、系统复位电路、串行接口电路、接口、接口、以太网接口电路、存储电路、接口电路的硬件设汁。
(3)在软件设计方面主要是进行了引导程序的移植。接着在此基础上进行了内核的移植与对应的配置工作。最后。完毕了文件系统的制作与移植以及嵌入式server的移植。
(4)对家庭内部控制网络模块进行了分析,完毕了客厅灯具的开关控制、家居中温湿度监測及控制、智能窗帘的控制。
(5)在无线网络技术的协议栈和应用开发接口函数等基础上,实现了家庭内部控制网络之间的通信,并在此基础上进行了远程控制和查询功能的初步实现。
(6)在无线射频(RFID)的基础上,实现了智能门禁的控制功能。
本文中非常多能够扩展的地方,能够通过数据库实现家庭中环境的存储查询统计等功能。
同一时候能够通过手机短信接受的方式对家中的异常情况进行报警,另外还能够进行Android开发和IOS的开发。
因为本人的水平有限,在文中出现一些不足和疏忽,希望指教,欢迎批评和交流。