版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
页码硬件课程设计智能路由器摘要XilinxZynq功能强大,可以实现很多功能。我们这个项目以它为中心,与其他的最小系统板和手机客户端模块进行通信。组建一个互联网络,从而实现智能家居的控制系统。这个系统既可以采集数据并显示在手机客户端上,也可以由手机客户端控制各个家庭电器设备。关键词:XilinxZynq;智能家居;wifi
目录摘要 21项目概述 42设计与实现背景 53项目功能指标 64团队分工 75系统框图 86工作原理、关键技术及实施描述 96.1XilinxZynq功能的实现 96.1.1嵌入式linux系统的移植 96.1.2与模块的通信方法 10socket简介 10socket的具体实现 106.2Andriod客户端的设计与实现 126.2.1背景以及目的要求 12背景简介 12目的及要求 136.2.2设计思路 13设计题目 13功能分析 13模块划分 136.2.3设计实现及代码分析 15UI设计 15字符串资源文件:strings.xml 26程序清单文件:AndroidManifest.xml 266.2.4程序功能测试及截图 28工程项目目录 28程序运行界面 296.3温度测试及空调控制 296.2.1总体思路 296.2.2硬件框图 306.2.3实现细节 30WiFi模块的驱动 30温度传感器的驱动 31程序整体思路 311项目概述 智能家居(英文:smarthome,homeautomation)是以住宅为平台,利用综合布线技术、网络通信技术、安全防范技术、自动控制技术、音视频技术将家居生活有关的设施集成,构建高效的住宅设施与家庭日程事务的管理系统,提升家居安全性、便利性、舒适性、艺术性,并实现环保节能的居住环境。可以说,智能家居就是我们未来生活的方向。 因此,我们这一次硬件课程设计的目标就是实现一个以智能路由器为核心的智能家居的模型,这个模型具备完善的通信控制系统,但是并没有直接连通到电器设备上。但是只需要通过简单的继电器或者其他方式的连接,稍加改造,就可以在真正的家庭中得到应用。所以说,我们做的这个项目是具有很强的实际意义和应用价值的。
2设计与实现背景我们的目的是设计并实现一个面向智能家居应用的智能路由器系统,应用软件无线电/软件定义网络的理论、算法和技术,实现智能家居应用所需的网络通信及控制功能,并展示智能路由器工作的基本原理。 在智能家居系统中,需要以智能路由器为中心控制很多电器设备,所以,我们采用了分立模块的设计理念。使用XilinxZynq作为主控制处理器实现智能家居应用的网络通信、控制与信息处理功能。而分立的以ARM为内核的最小系统板负责采集数据或者执行用户的命令。同时,手机的客户端也可以直接与主控中心通信,监控数据变化和控制电器设备。 一般的手机不具备温度检测和遥控器的功能,所以我们想实现一个检测温度和空调遥控器的模块,负责采集温度并根据指示控制空调。如果温度高于一定值,主控中心会指示该模块开启空调。与此同时,手机客户端可以读取温度并直接控制空调的开关和温度。而在智能家居中,控制电灯显然必不可少,所以还有一个模块可以通过继电器来负责电灯的亮灭,这个是在手机客户端上进行控制的。这个模块稍加改进,就可以很容易的用到一切由开关直接控制的设备上,比如洗衣机、电饭煲和电视机等。最后,我们可能经常忘记关门,可以在门口设置两对红外线管来检测人数的变化,并将这个反馈到手机客户端,如果人数为0,而门没有关的话,可以自动提醒,防止主人忘记关门。总之,我们的设计立足的背景就是一个普通的家庭环境,一切想法都从用户的方便出发。
3项目功能指标项目实现的功能指标如下:1.使用XilinxZynq作为主控制处理器,可以与分立模块之间通过wifi进行实时通信,处理分立模块发送过来的数据,并根据数据的情况给分立模块发送不同的指令。2.空调模块可以检测温度,并将温度数据反馈给主控中心。还可以根据主控中心的指令发送红外信号来控制空调,对空调的操作包括开关和升降温度。3.手机客户端与主控中心进行双向通信。主控中心发送温度数据,客户端予以显示,客户端给主控中心发送控制空调的命令,由主控中心中转执行。其中,手机客户端可以设置两种模式:自动和手动。自动模式由系统自行决定是否开关空调,手动模式就只根据手机客户端的
4团队分工康健:负责完成分立模块的数据采集和控制功能,以及分立模块与主控中心通信的功能。易坤:负责完成XilinxZynq的嵌入式linux系统的移植。以及主控中心与分立模块之间的通信,处理分立模块的数据,向分立模块发送命令,并且实现分立模块通信进程之间的数据通信。艾曦:负责完成手机客户端的UI设计及开发功能,以及手机客户端与主控中心的通信的功能。
5系统框图
6工作原理、关键技术及实施描述6.1XilinxZynq功能的实现6.1.1嵌入式linux系统的移植嵌入式linux系统的简介嵌入式linux是将日益流行的Linux操作系统进行裁剪修改,使之能在嵌入式计算机系统上运行的一种操作系统。就是利用Linux其自身的许多特点,把它应用到嵌入式系统里。Linux做嵌入式有着很多优势。首先,Linux是开放源代码的,不存在黑箱技术,遍布全球的众多Linux爱好者又是Linux开发者的强大技术支持;其次,Linux的内核小、效率高,内核的更新速度很快,linux是可以定制的,其系统内核最小只有约134KB。第三,Linux是免费的OS,在价格上极具竞争力。最重要的是,Linux内核的结构在网络方面是非常完整的,Linux对网络中最常用的TCP/IP协议有最完备的支持。提供了包括十兆、百兆、千兆的以太网络,以及无线网络,Tokerring(令牌环网)、光纤甚至卫星的支持。所以我们选用嵌入式linux来实现智能家居。嵌入式linux系统移植的具体方法1.首先准备一张SD卡,在linux系统中对其进行分区和格式化。先将SD卡分为两个区,再把第一个分区格式化为FAT格式,将第二个分区格式化为EXT4格式。2.FAT分区需要三个文件:boot.bin(引导文件),devicetree.dtb(设备树文件),uImage(内核镜像)。这些文件的制作过程比较复杂,需要用到很多东西。在这里不再赘述。我选修的嵌入式课程也是使用的XilinxZynq板卡,这些文件都由老师提供,我虽然阅读了有关这些文件制作过程的文件,但是是采用的是老师提供的文件。3.将文件系统复制到EXT4分区。文件系统指的是嵌入式liunx的文件系统。由于我们嵌入式选修课上提供的文件系统非常符合我们的需要,所以我直接采用了老师提供的文件系统。省去了对嵌入式linux内核裁剪等一系列艰难的工作。4.到了这里已经将嵌入式linux系统移植到了XilinxZynq板卡中了。将SD卡插入到XilinxZynq板卡中,启动板卡,就可以使用嵌入式linux系统了。6.1.2与模块的通信方法socket简介网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。Socket的英文原义是“孔”或“插座”。作为BSDUNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。显而易见,我们采用socket来实现我们的主控中心和模块之间的通信是恰到好处的。我们的主控中心上就只需要运行socket服务器程序。一旦与模块上的客户端建立了连接,接下来就可以很容易的实现通信了。socket的具体实现1.socketAPI函数的介绍(来自德致伦教育《ZRobot_Car入门指导(ZYBO)》) 这个嵌入式linux系统对socket进行了封装,提供了一系列好用的API。下面分别进行介绍。函数:zrtcp_srv_open()描述:打开一个socket服务,并将指定IP指定端口绑定到此服务,返回代表该socket服务的文件描述符。函数原型:intzrtcp_srv_open(in_addr_tip,intport,structsockaddr_in*local_addr);参数:in_addr_t:服务器IP,类型是in_addr_t,拥有可选项:
INADDR_ANY:所有本地IP
ZR_IP(“xxx.xxx.xxx.xxx”):指定IP为”xxx.xxx.xxx.xxx”port:服务器端口,一个整型数,推荐的范围为1024~65535
local_addr:地址结构体,用于保存地址信息。返回值:
一个int类型的服务器socket文件描述符。函数:zrtcp_srv_accept()描述:让描述符为sockfd的服务开始监听TCP连接。该函数会阻塞程序的执
行,直到监听到一个连接后返回代表该连接的文件描述符。函数原型:intzrtcp_srv_accept(intsockfd,structsockaddr_in*client_addr);参数:
sockfd:TCP服务的文件描述符,可以从zrtcp_src_accept函数获得。client_addr:地址结构体,用于保存地址信息。返回值:一个int类型的文件描述符,代表此次连接。函数:zrtcp_clt_open()描述:打开TCP服务,并向指定IP指定端口发起连接,返回代表此次连接的文件描述符。函数原型:intzrtcp_clt_open(in_addr_tip,intport,structsockaddr_in*tag_addr);参数:in_addr_t:服务器IP,类型是in_addr_tport:目标端口,一个整型数,推荐的范围为1024~65535tag_addr:地址结构体,用于保存地址信息。返回值:一个int类型的文件描述符,代表此次连接。函数:recv()描述:Linux系统提供的socket函数,用于接收从其他设备通过socket发来的数据。该函数会阻塞程序,直到接收到数据或发生错误。函数原型:ssize_trecv(intsockfd,void*buff,size_tnbytes,intflags);参数:
sockfd:socket文件描述符,recv会从该描述符代表的socket中读取数据
buff:数据缓冲区,读取的数据存在这里
nbytes:一个非负整型数,代表一次读取数据的最大长度,该参数的值不应大于缓冲区长度。flags:一般为0返回值
一个整型数,代表本次实际接收的数据量。返回值==0表示对方已断开
TCP连接,返回值<0表示该次接收失败(一般是由文件描述符失效引起)。函数:send()描述:Linux系统提供的socket函数,用于向其他设备发送数据。函数原型:ssize_tsend(intsockfd,void*buff,size_tnbytes,intflags);参数:
sockfd:socket文件描述符,send会从该描述符代表的socket中发送数据
buff:数据缓冲区,需要发送的数据存在这里
nbytes:一个非负整型数,代表一次发送数据的长度,该参数的值不应大于缓冲区长度。
flags:一般为0返回值:
一个整型数,代表本次实际发送的数据量。如果返回值<0表示该次接收失败(一般是由文件描述符失效引起)。2.socket服务器的实现 这里由于没有什么复杂的功能,服务器程序较为简单。就是建立一个socket连接然后阻塞进程,直到有客户端连接上并发送信息。此时就开始直接与该客户端一对一进行通信。读取客户端发来的数据,根据事先的约定发送命令给客户端。 但是关键问题是,这个服务器只能与一个客户端进行一对一的通信,不能进行一对多的通信。所以应该使用一个多进程的服务器。然后我就着手查阅相关资料。发现可以用fork()函数实现了一个多客户端的服务器。于是我就开始编写相应的多客户端服务器程序。但是不断出现了问题,会一直产生连接失败的信息,我几乎是仿照示例代码所编写的,所以我完全无法找到问题的所在。于是我开始做各种尝试,很遗憾,我在努力了很久之后这个问题依旧无法解决。所以我就放弃了这种方式,另辟蹊径,转而采用多个服务器进程,采取多个一对一来解决通信问题。这样复制原来的程序,改一下端口号就没有问题了。所以这个问题暂时顺利解决了。我现在面临另外一个问题,就是如何让手机和分立模块进行间接通信,即实现两个进程间的通信。6.1.3进程间的通信方法 在linux系统中,进程间的通信方式有很多种,而管道是一种使用非常频繁的通信机制。从本质上说,管道也是一种文件。所以我准备选用管道实现多个进程之间的通信。 一共有2个socket进程,分别其中一个与模块通信的进程,一个与手机客户端通信的进程。由于管道是单向的,所以我需要开启两个不同方向的管道。显然它们是镜像对称的,所以我决定先实现一个管道,再反向复制得到另一个管道。开始由于我对管道不太了解,直接套用示例代码。出现了很多问题。随着我慢慢理解了什么是阻塞、什么是非阻塞,以及一些管道的其他性质和应用,我顺利完成了一个管道。实现了两个进程的单向通信。 然后我反向复制得到了另一个管道,却出了问题,一直报错。我很疑惑,因为两个相关的代码一模一样。这样又折腾了很久,排除了很多可能。最后发现是我粗心的忘了设置一个重要的参数(读写的那个参数),导致两个管道其实方向一致。所以方向传输时遇到了问题。这就是编程经验的不足了。 解决了这个问题之后,我就实现进程间的通信。可以把模块的信息给手机显示,也可以把手机的命令,交个模块执行。主控中心只需要进行数据的简单处理即可。6.2Andriod客户端的设计与实现6.2.1背景以及目的要求背景简介Android(读音:['ændrɔid])是一种以Linux为基础的开放源码操作系统,主要使用于便携设备,目前尚未有统一中文名称,中国大陆地区较多人使用安卓。Android操作系统最初由AndyRubin创办[5],最初只支持手机。2005年由Google收购注资,并拉拢多家制造商组成开放手机联盟(OpenHandsetAlliance)开发改良,逐渐扩展到到平板电脑及其他领域上[6]。2010年末数据显示,仅正式推出两年的操作系统的Android已经超越称霸十年的诺基亚Symbian系统,跃居全球最受欢迎的智慧手机平台。采用Android系统手机厂商包括HTC、Samsung、Motorola、Lenovo、LG、SonyEricsson等。目的及要求本次硬件课程设计的题目是只能家具,而智能家居的客户端必然是大家天天都使用的移动端,所以我们选择位只能家具系统编写一个android手机客户端。目的:1、培养运用所学课程Java语言程序设计的理论知识和技能,分析解决计算机实际应用中的问题的能力。2、培养在Java语言程序设计的基础上,开发Android应用程序的思想和方法。3、培养调查研究、查阅技术文献、资料、手册以及编写技术文献的能力。6.2.2设计思路设计题目以Android系统的UI界面开发为基础,设计一个符合Client-Server架构,可与zybo开发板进行通信的androidapp,要求能够与主机(zyboip地址)、端口8800(zybo进程端口)建立TCP连接,交换信息。以一个Activity作为输入界面,该界面具有5个UI控件,分别显示当前温度、设定温度、开启连接、降低温度、减少温度。功能分析该app要求实现可进行TCP连接的能够交互信息应用。通过查阅资料可知,我们需要使用javaapi为我们的提供的套接字(socket)来进行,连接,在建立连接之后,我们还要使用javaapi提供的IO函数,javaio函数多大六十多个,各有各的用途,分别对应于文本、二进制文件,我们一般使用对应于文本的IO函数。模块划分通过程序功能分析,可将程序划分为2个部分,一个是UI,另一个是连网:UI:为了方便,只使用一个activity,其中包含两个textview,两个按键(Button),一个按键获取增加温度,另一个按键减少温度,一个开关(switch)获取当前温度。联网:由于android4.0之后,不允许在UI线程中进行网络操作,所以我们将会新开一个线程进行网络操作,并使用androidhandler机制来进行消息传递。6.2.3设计实现及代码分析UI设计.1布局文件:main.xml:采用相对布局,将五个空间摆成梅花形;两侧有两个按键(button)实现加减温度上下两个textview分别显示当前和设定温度。中间是开关(switch)用于打开连接在该代码中,我们首先将switch放置在parentlayout的中心,然后把两个按键放置在垂直中心,分别位于switch的左右,把两个textview放置在水平中心,放置在switch的上下。main.xml完整代码如下:<?xmlversion="1.0"encoding="utf-8"?>
<RelativeLayoutxmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.ayk.aixi.controler.MainActivity">
<Switch
android:id="@+id/switch_status"
android:layout_width="80dp"
android:layout_height="80dp"
android:textOff="On"
android:textOn="Off"
android:layout_centerInParent="true"/>
<TextView
android:id="@+id/text_current"
android:layout_width="80dp"
android:layout_height="80dp"
android:text="currenttemperature"
android:layout_above="@id/switch_status"
android:layout_centerHorizontal="true"/>
<TextView
android:id="@+id/text_set"
android:layout_width="80dp"
android:layout_height="80dp"
android:text="settemperature"
android:layout_below="@id/switch_status"
android:layout_centerHorizontal="true"/>
<Button
android:id="@+id/button_up"
android:layout_width="80dp"
android:layout_height="80dp"
android:text="Up"
android:layout_toLeftOf="@id/switch_status"
android:layout_centerVertical="true"/>
<Button
android:id="@+id/button_down"
android:layout_width="80dp"
android:layout_height="80dp"
android:text="down"
android:layout_toRightOf="@id/switch_status"
android:layout_centerVertical="true"/>
</RelativeLayout>.2源代码文件:MainActivity.java使用main.xml布局文件,为两个按钮(Button)注册事件监听,添加事件响应代码;实现增加温度:buttonUp.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewview){
inttemp=Integer.parseInt(textSet.getText().toString());
textSet.setText(temp+1);//当前温度+1
if(socket.isConnected()){
if(!socket.isOutputShutdown()){
out.println(textSet.getText().toString());
}
}
}
});实现降低温度:buttonDown.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewview){
inttemp=Integer.parseInt(textSet.getText().toString());
textSet.setText(temp-1);
if(socket.isConnected()){
if(!socket.isOutputShutdown()){
out.println(textSet.getText().toString());
}
}
}
});封装socketio函数:Socket通信实现步骤解析:Step1:创建ServerSocket和SocketStep2:打开连接到的Socket的输入/输出流Step3:按照协议对Socket进行读/写操作Step4:关闭输入输出流,以及Socket客户端要做的事有这些:Step1:创建Socket对象,指明需要链接的服务器的地址和端号Step2:链接建立后,通过输出流向服务器发送请求信息Step3:通过输出流获取服务器响应的信息Step4:关闭相关资源socket=newSocket(HOST,PORT);
in=newBufferedReader(newInputStreamReader(socket.getInputStream(),"UTF-8"));
out=newPrintWriter(newBufferedWriter(newOutputStreamWriter(socket.getOutputStream())),true);MainActivity.java完整代码如下:packagecom.ayk.aixi.controler;
importandroid.app.Activity;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.os.Bundle;
importandroid.view.View;
importandroid.widget.Button;
importandroid.widget.Switch;
importandroid.widget.TextView;
importjava.io.BufferedReader;
importjava.io.BufferedWriter;
importjava.io.IOException;
importjava.io.InputStreamReader;
importjava.io.OutputStreamWriter;
importjava.io.PrintWriter;
import.Socket;
publicclassMainActivityextendsActivityimplementsRunnable{
privateTextViewtextCurrent;
privateTextViewtextSet;
privateButtonbuttonUp;
privateButtonbuttonDown;
privateSwitchswitchStatus;
privatestaticfinalStringHOST="";
privatestaticfinalintPORT=8800;
privateSocketsocket=null;
privateBufferedReaderin=null;
privatePrintWriterout=null;
privateStringcontent="";
publicHandlerhandler=newHandler(){
publicvoidhandleMessage(Messagemsg){
if(msg.what==0x0){
textCurrent.setText(content.toString());
}
}
};
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textCurrent=(TextView)findViewById(R.id.text_current);
textSet=(TextView)findViewById(R.id.text_set);
buttonDown=(Button)findViewById(R.id.button_down);
buttonUp=(Button)findViewById(R.id.button_up);
switchStatus=(Switch)findViewById(R.id.switch_status);
newThread(){
@Override
publicvoidrun(){
try{
socket=newSocket(HOST,PORT);
in=newBufferedReader(newInputStreamReader(socket.getInputStream(),"UTF-8"));
out=newPrintWriter(newBufferedWriter(newOutputStreamWriter(socket.getOutputStream())),true);
}
catch(IOExceptione){
e.printStackTrace();
}
}
}.start();
buttonUp.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewview){
inttemp=Integer.parseInt(textSet.getText().toString());
textSet.setText(temp+1);//当前温度+1
if(socket.isConnected()){
if(!socket.isOutputShutdown()){
out.println(textSet.getText().toString());
}
}
}
});
buttonDown.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewview){
inttemp=Integer.parseInt(textSet.getText().toString());
textSet.setText(temp-1);
if(socket.isConnected()){
if(!socket.isOutputShutdown()){
out.println(textSet.getText().toString());
}
}
}
});
switchStatus.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewview){
if(!socket.isOutputShutdown()){
out.println("aixi");
}
newThread(MainActivity.this).start();
}
});
textSet.setText(textCurrent.getText().toString());
}
@Override
publicvoidrun(){
try{
while(true){
if(!socket.isInputShutdown()){
if((content=in.readLine())!=null){
handler.sendEmptyMessage(0x0);
}
}
}
}
catch(IOExceptione){
e.printStackTrace();
}
}
}字符串资源文件:strings.xml在一个Android工程中,我们可能会使用到大量的字符串作为提示信息。这些字符串都可以作为字符串资源声明在配置文件中,从而实现程序的可配置性。在代码中我们使用Context.getString()方法,通过传递资源ID参数来得到该字符串,也可以在其他资源文件中引用字符串资源,引用格式为:"@string/字符串资源名称。本程序所引用的strings.xml内容为:<resources>
<stringname="app_name">Controler</string>
<stringname="on">On</string>
<stringname="off">Off</string>
<stringname="up">up</string>
<stringname="down">down</string>
<stringname="test">connected</string>
</resources>程序清单文件:AndroidManifest.xml每一个Android项目都包含一个清单(Manifest)文件--AndroidManifest.xml,它存储在项目层次中的最底层。清单可以定义应用程序及其组件的结构和元数据。它包含了组成应用程序的每一个组件(活动、服务、内容提供器和广播接收器)的节点,并使用Intent过滤器和权限来确定这些组件之间以及这些组件和其他应用程序是如何交互的。因本程序使用了2个Activity,故对AndroidManifest.xml有一定的修改,内容如下:<?xmlversion="1.0"encoding="utf-8"?>
<manifestxmlns:android="/apk/res/android"
package="com.ayk.aixi.controler">
<uses-permissionandroid:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activityandroid:name=".MainActivity">
<intent-filter>
<actionandroid:name="ent.action.MAIN"/>
<categoryandroid:name="ent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>6.2.4程序功能测试及截图工程项目目录程序运行界面6.3温度测试及空调控制6.2.1总体思路这是整个智能家居系统的子模块之一。总体的想法是通过wifi与智能路由器进行连接(zybo板),将传感器采集到的温度数据传输到主控制板。主控板的linux的一个程序接受这个数据并且进行判断,如果此时主控制中心的收到另一个子模块的人数统计不为0且温度超过35摄氏度的时候,主控中心通过wifi模块向这个子模块传递打开空调的命令,这个模块收到命令以后,将会通过红外线发射器向空调发送命令,然后空调就可以开始制冷。当温度传感器传到主控中心的温度低于30摄氏度的时候,主控中心通过wifi发出关闭空调的命令,然后子模块驱动红外发射模块发送信号关闭空调。通过温度传感器和空调,实现对于空调的的调节控制。这种设计方式,使得只要安装我们的对应模块,无需更换家电本身,就可以实现家居的智能化。6.2.2硬件框图其中WiFi采用的是串口通信,通过AT命令和stm32来交换信息。温度传感器传回来的是模拟量,我们将其通过ADC转换为数字量传输到stm32.红外发射模块需要PWM进行驱动,PWM产生的是频率为38KHZ,占空比为0.5的方波,单片机内部通过IO的高低电平和延时函数进行红外编码,驱动红外发射管产生对应的红外信号,进而控制对应的家用电器。之所以选择stm32f103这款芯片,是因为其功能强大,而且成本较低,适合作为仅仅是收集数据的而不进行数据处理和汇总的分离模块。而且芯片的体积比较小,硬件资源的浪费比较少。6.2.3实现细节WiFi模块的驱动我们利用MCU的USART3实现与WIFI模块的通信。这一部分我们参考了stm32f10x中文参考手册,掌握了驱动USART的方法。首先将USART初始化以后,就是和WiFi模块进行通信。因为在库函数里面,USART每次只能发送一个字符,所以我们自己写了一个类似printf的函数,只要输入相应的字符串,就可以通过USART发送出去,这样,就可以方便的发送AT命令。但是,我们在发送以后还需要知道时候发送成功,根据ESP8266的数据手册,当命令执行成功或者失败以后,都会返回相应的信息,于是,我们在之前printf的基础之上,又封装了一个函数,这个函数的参数是需要发送的命令和需要返回的字符串,如果实际返回的字符串和输入的参数不一致,说明指令的执行不成功,则函数返回0,反之,则返回1。有了这个子函数,就可以自由的给模块发送相应的指令,并且不需要考虑发送细节。可以说,这个函数的封装是十分关键的,接下来的工作会大大的简化,而且保证了指令发送这个环节的0错误。然后,我们根据ESP8266进行配置,我们将模块配置为SPA模式,在物理层加入主控中心的wifi信号,实现物理层的连接。在物理层的连接成功以后,我们配置TCP的连接。这个模块是没有操作系统的,所以,我们直接配置连接,给予命令ip地址和端口还就可以实现和主控板当中的一个进程进行连接。这个连接是至关重要的,这个连接的成功,代表这个分离模块可以和主控中心进行通信。经过测试,两者可以正常的传递数据,可以继续进行下一步的工作。温度传感器的驱动温度传感器传回来的是一个在一定范围内的电压值,所以解决这个地方的本质就是可以正常的测量相应的电压值。这个问题我们也是参考《stm32f10x中文参考手册》和《stm32f1库函数说明文档》,完成对于ADC的初始化以后,然后就可以进行采样。设置合适采样频率,最后将采集的数据传回到单片机当中。根据LM35的数据手册,温度和电压的换算关系为U=T×10mV/℃。但是在实际当中,由于温度传感器的线性误差,需要对于公式进行一些相应的修正,最后得到准确的温度,然后将准确的温度传到主控中心,主控中心根据温度的数据进行相应的动作。红外模块的驱动这个东西是最麻烦,也是最曲折的。我们解决这个东西先后经历了三个方案:第一个是利用成品的红外编码模块,这个模块和单片机通过串口进行通信,只要按照相应的格式发送相应的命令和十六进制的红外编码,模块就会自动发送红外信号,但是我们的红外模块固定的进行的是NEC红外编码。我们需要控制的空调并不是这种形式的编码,所以这种方法不行;第二种方案是自己焊接红外发射硬件,利用晶体振荡器产生38khz的方波脉冲,然后作为与门的一个输入,另一端是单片机的一个IO口,当IO口为高电平的时候,有载波输出,当IO口为低电平的时候,无载波输出,实现红外调制。但是,在实现过程当中,首先没有38khz的晶振可以用,其次,晶振电路并不能很好的起振。最终,我们采用了第三种方案,38khz的载波源也是单片机产生,其余的部分和前一个方案相同,这样,我们可以精确的产生38khz的振荡频率,而且电路的实现也比较简单。但是,这就需要用到单片机内部的定时器,产生占空比为0.5的方波。而且,光靠单片机的功率无法驱动红外管,所以在与门后面需要添加三极管驱动电路,这一点,与第二个方案也是一致的。于是,我们完成了对于这三者的驱动,接下来,就是纯粹的程序的设计了。程序整体思路我们的分立模块一直读取温度传感器的值,当温度超过35摄氏度驱动WiFi将温度发送到主控模板,发送完毕的后,将flag置1,此时,温度即使在超过的35摄氏度也不会再发送温度值。在flag为1且温度低于30摄氏度时驱动WiFi将温度发送到主控模板,发送完毕以后将flag置为0。在这期间,WiFi一直处于接受状态,确保只要收到主控中心的指令,便会立即执行相应的动作,完成对于空调的控制。6.4灯光控制灯光的控制比较简单,我们利用LED来模拟灯光。通过手机可以发送信息到控制中心。控制中心再将命令转发到具体控制灯管的分离模块当中。分立模块收到命令,然后通断相应的IO口,完成对于灯光的控制。
7主要器件清单及经费使用情况1、测试加研发成本核算:2、产品成本核算从表格上面可以看出,研发时由于测试工具也需要成本。但是主要成本其实就是主控中心的开发板。由于我们时间比较的匆忙,所以是直接使用官方的开发板。其实,开发板上面的大部分资源都没有使用到。所以,在后期,可以自己设计板子,然后使用zynq的芯片就可以。这样,既减少了不必要的功率消耗,也可以大大降低成本。其次,在研发阶段用到的空调模拟机,只是一种极其简便的方法。其实可以通过电脑和一个红外接收头来解决,这也可以降低成本。但由于是硬件课设,所以因陋就简,利用手边现成的一些东西来进行操作。这些开发板都是平时学习时购买,所以也大大造成了开发成本的增加。其实,在真正的研发过程当中,这些事情都应该提前进行考虑,防止临时拼凑,这样,既会减少成本开销,也可以增加系统的专一性和稳定性。8项目中的一些矛盾以及解决方法案例一:在调试空调模块和控制中心进行连接的时候,开始WiFi可以连接成功。但是却无法正确接收温度数据。然后我和易坤同学都觉得自己的代码没有什么问题。我觉得我的硬件系统也没有问题。然后为了证明我们各自的观点,我们分别从两边做了验证试验。试验过程是这样的:我是将本来需要通过串口传递给WiFi的数据传给了串口,打印在电脑屏幕上面。然后WiFi连接成功时,屏幕上面正确的显示了当前的温度信息。说明我的这部分没有问题。易坤同学将他的主控中心作为服务器,在电脑上开了一个客户端来模拟我的设备,然后和他的主控中心进行TCP连接,然后模拟进行数据收发,发现也是正常的。双方都是正常,那就说明是WiFi模块出现问题。然后我们更换了一个新的WiFi模块,重新开机启动,可以正确运行。案例二:在测试手机客户端和控制中心还有遥控器模块联调的时候,手机无法显示红外模块的温度数据。然后我们就开始争论问题所在,过程如下:因为之前已经测试红外模块和主控中心通信正常,说明这两部分的连接不会出现问题,问题只能是andriod和住空中中心的通信问题。然后,易坤同学在电脑上面又模拟了一个新的客户端模拟手机,测试双方收发数据正常。艾爔同学在电脑上模拟客户端,和andriod客户端通信,收发数据正常。那问题究竟出在哪里呢?经过分析,主控中心在Linux系统上面开了两个进程,两个进程之间需要通过通道来进行通信。然后进过程序的调试,发现我们开的两个通道均为同向,即只能从客户端进程到遥控板进程,控制遥控板的进程是无法传输数据给控制手机通信的进程,这就造成了温度数据无法正确的进行传输。然后我们改了另一条通道的属性,问题得到了解决。案例三在进行最后的验收的时候,很遗憾,WiFi模块一直无法连接。折腾了几个小时,模块就是连不上,非常遗憾。我们再次利用排除法,先后排除了是主控中心问题(重新刷了系统);红外控制模块问题(可以连接手机,串口打印数据正常);andriod是软件,之前调好不可能有问题。但是就是连接不上,即红外控制板无法连接主控中心的WiFi。无奈回到宿舍,直接连接好可以工作。事后我们进行分析,发现可能是由于互联网实验室测试WiFi信号正好对我们很弱的实验WiFi信号产生了干扰,因为只有这可以解释了。这个问题很遗憾,有条件可以拿到实验室进一步进行测试,找出真正原因。9项目实施总结及心得体会 这个项目是我们迄今为止接触到的最复杂的工程项目了。这个项目涉及到软件、硬件以及软硬件的结合。最为重要的是,在这个项目中,我们学会了团队协作,各取所长,取长补短。我们三个同学各自有各自的擅长和优势,也有各自不了解的短板。这样我们三个合作的话,就互相弥补了各自的不足。我们在项目初的时候,一起商议,各抒己见,最终产生了一个初步的项目方案出来。然后我们确定了各自要负责的方向,各自的任务后。分别去查阅资料,印证方案。最后我们汇总所有资料,进行可行性分析,商量细节,敲定了最终的方案。这个过程,就是项目的开题。我们从中学到了不少东西,获益匪浅。然后我们按照自己要做的部分开工,通过各种方式实现自己的部分。如果遇到了问题,就讨论解决。就这样,我们度过了一个又一个的技术难关。最终完成了各自部分的雏形。完成了各自的雏形后,我们采用联合调试的方法。一个一个的通信调试,然后根据要实现的功能改进各自的程序,再进行实验,就这样,我们完成了各个模块的工作。最终我们就完成了硬件课设,得到了最终的结果。过程是很艰难的,我们遇到了很多困难。但是通过解决这些困难,我们收获了更多了东西。我们学到了知识和方法。最后的成果也是对我们努力的最大肯定。10项目展望由于时间比较紧张,所以只是实现了想法的核心部分。其实,完成WiFi的通信以后,我们可以实现的扩展有很多,其中有一个我们很想实现的就是对于人数的统计。我们在家里面,经常会离开家忘了关灯,忘了关煤气等。这些行为小则会造成对于能源的浪费,大则会造成火灾,造成严重的事故等,所以我们利用两组红外对管,统计进出人数,当检测到室内的人数为0时,会将警告发送到主控中心,主控中心会关闭点灯,同时向手机客户端发出警告信息。这样,就可以避免由于家里面没有人而造成的事故。之所以将主控中心和分立模块分开,我们是为了实现系统的可升级和可扩展。我们的思路是主控中心提供一套标准的WiFi接入命令,我们可以根据这个标准扩展各个分立的模块。这样,你可以先购买一个主控中心(连接外网后,主控中心就是一个路由器)然后需要怎样的分立模块购买对应的分立的模块即可。然后升级软件就可以完成无障碍的连接。我们以后如果有机会,可以在这次设计的基础上,进一步的扩展完善,进一步的进行标准化。也许,最终可以投入市场。这只是一些设想,但是,我觉得完全是可以实现的,只是时间问题。11参考文献1.《stm32f10x中文参考手册》 2.《stmf1开发指南》3.《ATK-ESP8266WIFI用户手册》4.NeilMatthew、RichardStones《Linux程序设计》第四版5.StephenPrata《CPrimerPlus》第五版6.德致伦教育《ZRobot_Car入门指导(ZYBO)》7.谢自美,电子线路综合设计,华中科技大学出版社,2006-68.康华光,《电子技术基础:模拟部分(第六版)》,高等教育出版社,20149.康华光,《电子技术基础:数字部分(第六版)》,高等教育出版社,201410.罗杰,电子线路设计.实验.测试,电子工业出版社,2008
附录Xilinx板卡程序源代码1.zrtcp.c(socket通信的声明文件)#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<unistd.h>#include<arpa/inet.h>#include<sys/wait.h>#include<string.h>#include"zrtcp.h"#defineLISTEN_LIMIT1//staticstructsockaddr_inlocal_addr,client_addr;staticintsin_size;intzrtcp_srv_open(in_addr_tip,intport,structsockaddr_in*local_addr){ intsockfd=0; if(-1==(sockfd=socket(PF_INET,SOCK_STREAM,0))){ perror("socketerror!"); exit(1); } local_addr->sin_family=PF_INET; local_addr->sin_port=htons(port); local_addr->sin_addr.s_addr=INADDR_ANY; bzero(&(local_addr->sin_zero),0); if(-1==bind(sockfd,(structsockaddr*)local_addr,sizeof(structsockaddr))){ perror("binderror!"); exit(1); } if(-1==listen(sockfd,LISTEN_LIMIT)){ perror("listenerror"); exit(1); } returnsockfd;}intzrtcp_srv_accept(intsockfd,structsockaddr_in*client_addr){ intclientfd=0; sin_size=sizeof(structsockaddr_in); if(-1==(clientfd=accept(sockfd,(structsockaddr*)client_addr,&sin_size))){ perror("accepterror!"); exit(1); } returnclientfd;}intzrtcp_clt_open(in_addr_tip,intport,structsockaddr_in*tag_addr){ intsockfd=0; tag_addr->sin_family=AF_INET; tag_addr->sin_port=htons(port); tag_addr->sin_addr.s_addr=ip; sockfd=socket(AF_INET,SOCK_STREAM,0); if(sockfd<0){ printf("socketfailed!\n"); return-1; } if(0>connect(sockfd,(structsockaddr*)tag_addr,sizeof(structsockaddr_in))){ printf("connectfailed!\n"); return-1; } returnsockfd;}2.zrtcp.h(socket通信的头文件)#ifndefZRTCP_H_INCLUDED#defineZRTCP_H_INCLUDED//#include<stdio.h>//#include<unistd.h>//#include<stdlib.h>//#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>//#include<arpa/inet.h>//#include<sys/wait.h>//#include<string.h>#defineZR_IP(tag_ip)inet_addr(tag_ip)intzrtcp_srv_open(in_addr_tip,intport,structsockaddr_in*local_addr);intzrtcp_srv_accept(intsockfd,structsockaddr_in*client_addr);intzrtcp_clt_open(in_addr_tip,intport,structsockaddr_in*tag_addr);#endif3.tcp_server_phone.c(与手机客户端通信的进程代码)#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<stdlib.h>#include<string.h>#include<fcntl.h>#include<limits.h>#include<sys/types.h>#include<sys/stat.h>#include"zrtcp.h"#defineFIFO_NAMEptr"/tmp/my_fifo1"#defineFIFO_NAMErtp"/tmp/my_fifo2"#defineTEN_MEG(1024*1024*10)#defineBUFFER_SIZE64intmain(intargc,char**argv){ intpipe_fd; intpipe_fd2; intres; intres2; inttemp1; chartemp2[64]={0}; intopen_mode=O_WRONLY|O_NONBLOCK; intopen_mode2=O_RDONLY|O_NONBLOCK; intbytes_sent=0; intsockfd,datafd; intbytes_read=0; structsockaddr_inserver_addr,client_addr; sockfd=zrtcp_srv_open(INADDR_ANY,8000,&server_addr); datafd=zrtcp_srv_accept(sockfd,&client_addr); intreceived=0; inti=0; charbuf[64]={0}; char*bufrtp=malloc(64); if(access(FIFO_NAMEptr,F_OK)==-1){ res=mkfifo(FIFO_NAMEptr,0777); if(res!=0){ fprintf(stderr,"Couldnotcreatefifo%s\n",FIFO_NAMEptr); //exit(EXIT_FAILURE); } } while(1){ received=recv(datafd,buf,64,0); if(-1==received){ perror("recverror"); break; } elseif(0==received){ printf("tcpdisconnected"); break; } printf("received:%d,buf[0-3]:%s\n",received,buf); printf("Process%dopeningFIFOO_RDONLY\n",getpid()); pipe_fd2=open(FIFO_NAMErtp,open_mode2); printf("Process%dresult%d\n",getpid(),pipe_fd2); if(pipe_fd2!=-1){ //do{ res2=read(pipe_fd2,bufrtp,BUFFER_SIZE); //bytes_read+=res; printf("%s,readisright\n",bufrtp); //}while(res>0); } temp1=atoi(bufrtp); temp1=temp1/10-10; if(temp1!=-10){ sprintf(temp2,"%d",temp1); send(datafd,temp2,64,0); } for(i=0;i<64;i++){ bufrtp[i]='\0'; temp2[i]='\0'; } printf("Process%dopeningFIFOO_WRONLY\n",getpid()); pipe_fd=open(FIFO_NAMEptr,open_mode); printf("Process%dresult%d\n",getpid(),pipe_fd); if(pipe_fd!=-1){ //while(bytes_sent<64){ res=write(pipe_fd,buf,64); printf("writeisright"); if(res==-1){ fprintf(stderr,"Writeerroronpipe\n"); } //bytes_sent+=res; //} } for(i=0;i<64;i++) buf[i]='\0'; } (void)close(pipe_fd); (void)close(pipe_fd2); close(datafd); close(sockfd); return0;}4.tcp_server_red.c(与分立模块进行通信的进程源码)#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<string.h>#include<fcntl.h>#include<limits.h>#include<sys/types.h>#include<sys/stat.h>#include"zrtcp.h"#defineFIFO_NAMEptr"/tmp/my_fifo1"#defineFIFO_NAMErtp"/tmp/my_fifo2"#defineBUFFER_SIZE64intmain(intargc,char**argv){ intpipe_fd; intpipe_fd2; unsignedlongintwendu; intres; intflag=0; intres2=0; intopen_mode=O_RDONLY|O_NONBLOCK; intopen_mode2=O_WRONLY|O_NONBLOCK; intbytes_read=0; intsockfd,datafd; char*kg=malloc(10); char*kg2=malloc(10); structsockaddr_inserver_addr,client_addr; sockfd=zrtcp_srv_open(INADDR_ANY,8800,&server_addr); datafd=zrtcp_srv_accept(sockfd,&client_addr); intreceived=0; inti=0; charbuf[64]={0}; charbufptr[64]={0}; if(access(FIFO_NAMErtp,F_OK)==-1){ res2=mkfifo(FIFO_NAMErtp,0777); if(res2!=0){ fprintf(stderr,"Couldnotcreatefifo%s\n",FIFO_NAMErtp); //exit(EXIT_FAILURE); } } while(1){ received=recv(datafd,buf,64,0); if(-1==received){ perror("recverror"); break; } elseif(0==received){ printf("tcpdisconnected"); break; } printf("received:%d,buf[0-3]:%s\n",received,buf); wendu=atoi(buf); printf("Process%dopeningFIFOO_RDONLY\n",getpid()); pipe_fd=open(FIFO_NAMEptr,open_mode); printf("Process%dresult%d\n",getpid(),pipe_fd); if(pipe_fd!=-1){ //do{ res=read(pipe_fd,bufptr,BUFFER_SIZE); //bytes_read+=res; printf("readisright"); //}while(res>0); } if(strstr(bufptr,"aa")){ flag=0; } elseif(strstr(bufptr,"ab")){ flag=0; } elseif(strstr(bufptr,"ba")){ flag=1; kg=strcpy(kg2,"on\0"); } elseif(strstr(bufptr,"bb")){ flag=1; kg=strcpy
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026校招:计算机视觉工程师试题及答案
- 2026年拖灰渣合同(1篇)
- 外贸订单加工合作合同协议书模板
- 2026校招:东南网架集团笔试题及答案
- 2026校招:朝阳集团面试题及答案
- 2025-2026学年小学教资英语教学设计
- 2025-2026学年灰雀教学设计图册初中
- 2025-2026学年JPG下载音乐教案
- 2026年广东省肇庆市单招职业倾向性测试题库附参考答案详解(研优卷)
- 2026年山西职业技术学院单招职业技能考试题库及完整答案详解一套
- 化工设计知到智慧树章节测试课后答案2024年秋浙江大学
- 苏教版六年级数学下册第2单元《圆柱和圆锥》全部课件(共10课时)
- 2024商铺转租转让合同
- DB13(J)T 8446-2021 建筑施工安全技术资料管理标准
- 2024-2030年中国寺庙经济市场运行态势与发展战略建议报告
- 小学安全监督检查工作计划
- 体育统计学复习题库
- 雨水节气课件
- 开学工作方案及应急预案及措施
- 节后工程复工复产检查方案
- 煤矿岗位标准化作业流程
评论
0/150
提交评论