首页 > 公文写作 > 调研报告 / 正文
基于安卓Android智能家居详细设计毕业论文
2020-12-09 17:57:07 ℃基于Android的智能家居 目
录 第 1 章 项目概述 1 1.1 项目背景 1 1.2 术语定义 2 第 2 章 技术方案 3 2.1 系统描述 3 2.2 功能描述 3 2.3 项目功能图 4 2.4 所涉及的系统、工具 4 第 3 章 前端数据中心(A8)总体设计 5 3.1 程序设计流程图 5 3.2 线程定义 5 3.3 所用类定义 6 第 4 章 前端A8模块设计 7 4.1 A8-Android
Application层设计 7 4.1.1 数据流分析 7 4.1.2 Application层详细设计与实现 9 4.2 A8-数据传递架构模块 16 4.2.1 层次接口表 16 4.2.2 HAL层 17 4.2.3 JNI层 19 4.2.4 Framework层 20 4.2.5 整体流程 21 4.2.6 关键代码分析 22 4.3 传输协议模块设计 32 4.3.1 A8接收数据格式 32 4.3.2 M0接收命令数据结构 33 第 5 章 终端M0模块设计 35 5.1 终端设备方案描述 35 5.2 终端设备工作流程 35 5.3 功能模块描述 36 5.3.1 温湿度传感器DHT10 36 5.3.2 ZigBee通信部分 37 5.3.3 RFID读卡模块 40 5.3.4 IIC接口部分 41 第 6 章 系统测试 45 6.1 项目演示 45
第 1 章
项目概述 1.1 项目背景 随着社会电子信息化的不断发展,人们在家居中使用的电器越来越多,由此带来的安全隐患也有了明显的增多。在这些电器中一旦出现一些异常,便会给人们带来很大的损失。为了降低电器的不合理使用带来的异常情况,就要求在异常发生时用户能及时得到信息,并通过实时监控采取一定的操作排除异常。因此,远程监控系统的作用是非常巨大的。
90年代末,随着多媒体技术、视频压缩编码技术、网络通讯技术的发展,数字视频监控系统迅速崛起,现今市场上由两种数字视频监控系统类型,一种是以数字录像设备为核心的视频监控系统,另一种是以嵌入式视频web服务器为核心的视频监控系统。以数字录像设备为核心的视频监控系统采用PC机作为多媒体监控主机,综合了视频矩阵、图像分割器、录像机等众多的功能,使系统结构大为简化,采用计算机网络技术,数字多媒体远程网络监控不受距离限制,采用大容量磁盘阵列存盘器或光盘存储器,可以节省大量的磁盘介质,同时有利于系统实现多媒体信息查询。但随着基于PC机的视频监控录像系统的发展,在实际使用过程中,也暴露出一些不足,主要是系统工作的不稳定性。
以嵌入式视频web服务器为核心的视频监控系统,采用嵌入式实时多任务操作系统。摄像头采集到的图片信息经过压缩,通过内部总线送到内置的web服务器,网络上的用户可以直接用浏览器观看web服务器上的由摄像头采集的图像。由于把图片采集和web功能集中到一个体积很小的设备内,可以直接连入局域网,用户无需安装任何硬件设备,仅用浏览器即可观看。同时还具有以下优点:
布控区域广阔,嵌入式视频web服务器监控系统web服务器直接连入网络,没有线缆长度和信号衰减的限制,同时网络是没有距离概念的,彻底抛弃了地域的概念,扩展布控的区域。系统具有几乎无限的无缝扩展能力。所以设备都以IP地址进行标示,增加设备只是意味着IP地址的扩充。性能稳定可靠,无需专人管理。嵌入式web服务器实际上是基于嵌入式微处理器技术,采用嵌入式实时多任务操作系统,对于用户来讲,上网进行登陆,便可对家中情况进行监控。除了WEB服务器实时控制之外,当前智能手机的发展趋势已经愈加明显。智能手机(Smartphone),是指“像个人电脑一样,具有独立的操作系统,可以由用户自行安装软件、游戏等第三方服务商提供的程序,通过此类程序来不断对手机的功能进行扩充,并可以通过移动通讯网络来实现无线网络接入的这样一类手机的总称”。而当前应用在智能手机上的操作系统中Android操作系统占有相当大的比例。
Android( 中文名:安卓) 是基于Linux平台开源手机操作系统名称,该平台由操作系统、中间件、用户界面和应用软件组成,号称是首个为移动终端打造的真正开放和完整的移动软件。随着Android应用的更见广泛,了解并能使用Android来完成我们对智能家居的控制已经显得愈加重要。
现在监控系统发展到第三代,前端一体化、视频十字化、监控网络化、系统集成化成为视频监控系统公认的发展方向,它以网络为依托,以数字视频的压缩、传输、存放和播放为核心,以智能实用的图像分析为特点,并为报警系统、门禁系统完美的整合到一个使用平台上,引发了视频控制行业的一次技术革命。
1.2 术语定义 Android: Android是一种以Linux为基础的开放源码操作系统,主要使用于便携设备。
HAL:硬件抽象层。
JNI:JNI是Java Native Interface的缩写,中文为JAVA本地调用。
RFID:射频识别即RFID(Radio Frequency IDentification)技术,又称电子标签、无线射频识别,是一种通信技术,可通过无线电讯号识别特定目标并读写相关数据,而无需识别系统与特定目标之间建立机械或光学接触。
A8: ARM Cortex-A8处理器是第一款基于ARMv7架构的应用处理器,并且是有史以来ARM开发的性能最高、最具功率效率的处理器。
M0:Cortex-M0处理器,是市场上现有的最小、能耗最低、最节能的ARM处理器。
第 2 章
技术方案 2.1 系统描述 Android是一个开放源码的操作系统专门为移动电话而设计的系统。Android手机将开辟新的应用,使家居智能化运用于普通家庭。
Android 界面显示(Cortex_A8)来自于Cortex_m0模拟量,并可对Cortex_m0进行控制或操作。
本系统做为裁减项目,实现了M0采集房间信息,通过无线方式发送到A8进行监控、控制。A8即可作为移动终端设备(如phone、pad等),亦可作中央监控服务器设备。本项目采用后者方案,即作中央监控。若需作移动设备,只需将程序移植到移动设备上,再在中央端移植web服务器,移动设备登陆服务器即可查看房屋信息。
2.2 功能描述 1.检测室内温度、湿度、光感、电压情况(通过Cortex_m0采集的信息)。
2.通过温度、湿度的情况来对应调节风扇开关(控制Cortex_m0)。
3.根据光敏传感器情况对应调节led灯亮灭(控制Cortex_m0)。
4.根据三轴加速度情况对应调节蜂鸣器开关(控制Cortex_m0)。
5.显示Rfid信息等功能(通过Cortex_m0采集)。
2.3 项目功能图
图2.1 项目功能图 2.4 所涉及的系统、工具 表2.1 系统与工具 系统名称 系统版本 备注 Linux内核 Linux3.0.8
Android文件系统 Android4.0版本
工具链 arm-none-linux-gnueabi-gcc
Android程序开发 Eclipse
第 3 章
前端数据中心(A8)总体设计 3.1 程序设计流程图
图3.1 程序设计流程图 3.2 线程定义 1. SmartHomeActivity,程序主Activity界面,打开程序首先运行。
2. NodeInfoActivity,从界面Activity,用来显示详细设备采集信息和控制按键。
3. MainReadThread,读数据主线程,该线程只负责对通过Zigbee获取的数据转发给读进程,不进行数据操作。
4. MainHandlerThread,处理数据线程,该线程对从读进程传来的数据进行数据校验并转发。
5. NodeWriteThread,控制线程,该线程负责处理由用户对设备的操作。
3.3 所用类定义 1. Data,用来存储和处理设备的采集数据。
2. NodeCmd,定义操作方法,实现对设备的读操作和控制操作。
3. NodeInfo,定义设备的所有采集信息,控制器状态和WatchDog。
4. NodeList,使用链表存储设备信息。……………………………………?? 5. MyUartService:提供与底层的接口,以读写串口。
第 4 章
前端A8模块设计 4.1
A8-Android
Application层设计 4.1.1 数据流分析 4.1.1.1 NEWNODE,新节点加入 1.数据处理流程图 图4.1 NEWNODE数据流程图 2.数据格式 NEWNODE数据格式 数据 格式 NEWNODE S4FnI1
3.数据处理详细描述 Cortex-M0开启,通过Zigbee发送NEWNODE数据给Cortex-A8,程序通过MainReadThread线程读取到数据,交由MainHandlerThread线程处理。MainHandlerThread对NOEWNODE进行校验,判断是否合法,如果数据无误,通过发送Handler消息交由SmartHomeActivity主界面UI线程,SmartHomeActivity 判断链表是否已经存在该节点,不存在则加入链表并创建节点。…………………….? 4.1.1.2 NODEINFO,节点信息更新。
1.数据处理流程图 图4.2 NODEINFO数据流程图 2.数据格式 NODEINFO数据 数据 格式 NODEINFO S23FiI1T24H30L6V220X1Y1Z60 3.数据处理详细描述 Cortex-M0开启,通过Zigbee发送NEWNODE数据给Cortex-A8,程序通过MainReadThread线程读取到数据,交由MainHandlerThread线程处理。MainHandlerThread对NODEINFO进行校验,判断是否合法,如果数据无误,通过发送Handler消息交由SmartHomeActivity主界面UI线程,SmartHomeActivity 判断链表是否已经存在该节点,存在则更新该链表信息,并判断是否进入该节点从界面,如果进入发送Broadcast通知从界面更新数据。
4.1.1.3 RFID,用户登录或退出。
1.数据处理流程图 图4.3 RFID数据流程图 2.数据格式 RFID数据格式 数据 格式 RFID S11FrI1R103132 3.数据处理详细描述 Cortex-M0开启,通过Zigbee发送NEWNODE数据给Cortex-A8,程序通过MainReadThread线程读取到数据,交由MainHandlerThread线程处理。MainHandlerThread对RFID进行校验,判断是否合法,如果数据无误,通过发送Handler消息交由SmartHomeActivity主界面UI线程,SmartHomeActivity发送Broadcast通知从界面,从界面判断是否为自己设备,是则更新数据。
4.1.2 Application层详细设计与实现 4.1.2.1 类对象详细描述 1 .Data类,负责对接受来数据进行处理 表4.1 Data成员属性表 属性 类型 描述 serialVersionUID long 序列化时保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。
data String 存储从串口的数据 表4.2 Data成员方法表 方法 参数 返回值 描述 getDataSize Void String 从传来的数据获取数据大小 isValidData Void boolean 数据有效性校验,包括数据是为为空,完整等 getDataType Void int 从传来的数据获取数据类型 getDataTarget Void String 从传来的数据获取数据的设备号 getRfid Void String 从传来的数据获取Rfid信息 getTemperature Void String 从传来的数据获取温度 getHumidity Void String 从传来的数据获取湿度 getLight Void String 从传来的数据获取光感 getAd Void String 传来的数据获取AD值 getX Void String 从传来的数据获取三轴加速度x值 getY Void String 从传来的数据获取三轴加速度y值 getZ Void String 从传来的数据获取三轴加速度z值 2 .NodeCmd类,负责与底层进行交互,实现对硬件设备读,写操作。
表4.3 NodeCmd成员属性表 属性 类型 描述 DevCmd enum 使用枚举将命令声明一组命名的常数,方便函数调用。
myUartService MyUartService 串口操作所使用框架 表4.4 NodeCmd成员方法表 方法 参数 返回值 描述 devControl int, DevCmd String 向串口发送数据 readNode Void String 从串口获取数据 3 .NodeInfo类,负责存储一个设备的信息。
表4.5 NodeInfo成员属性表 属性 类型 描述 serialVersionUID long 序列化时保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。
temperature String 存储节点对象的温度值 humidity String 存储节点对象的湿度 light String 存储节点对象的光感值 x String 存储节点对象的三轴加速度x值 y String 存储节点对象的三轴加速度y值 z String 存储节点对象的三轴加速度z值 ad String 存储节点对象的ad值 led int 存储节点对象的led灯状态(0,灭;1,亮) fun int 存储节点对象的风扇状态(0,关;1,开;2,加速) beep int 存储节点对象的报警器状态(0,关;1,开) nixietub int 存储节点对象的数码管状态(0,关;1,开) rfid rfid 存储节点对象的rfid信息 devNum int 存储节点对象的设备号 next NodeInfo 便于生成链表 watchDog int 看门狗,监控节点生命值 表4.6 NodeInfo成员方法表 方法 参数 返回值 描述 NodeInfo void void 构造函数,初始化节点对象 NodeInfo void int 有参数构造函数,参数为节点设备号 getNext void NodeInfo 获取下一个节点并返回节点信息 setNext NodeInfo void
getTemperature void String 获取该对象温度值 setTemperature String void 设置该对象温度值 getHumidity void String 获取该对象湿度值 setHumidity String void 设置该对象湿度值 getLight void String 获取该对象光感值 setLight String void 设置该对象光感值 getAd void String 获取该对象AD值 setAd String void 设置该对象AD值 getX void String 获取该对象三轴加速度x值 setX String void 设置该对象三轴加速度x值 getY void String 获取该对象三轴加速度y值 setY String void 设置该对象三轴加速度y值 getZ void String 获取该对象三轴加速度z值 setZ String void 设置该对象三轴加速度z值 getLed void int 获取该对象Led状态值 setLed int void 设置该对象Led状态值 getFun void int 获取该对象Fun状态值 setFun int void 设置该对象Fun状态值 getBeep void int 获取该对象Beep状态值 setBeep int void 设置该对象Beep状态值 getNixietub void int 获取该对象Nixietub状态值 setNixietub int void 设置该对象Nixietub状态值 getDevNum void int 获取该对象DevNum值 setDevNum int void 设置该对象DevNum值 getRfid void String 获取该对象Rfid值 setRfid String void 设置该对象Rfid值 getWatchDog void int 获取该对象WatchDog值 setWatchDog int void 设置该对象WatchDog值 ledOn void void 开灯 ledOff void void 关灯 funOn void void 开风扇 FunOn1 void void 风扇加速 funOff void void 关风扇 beepOn void void 开蜂鸣器 beepOff void void 关蜂鸣器 nixietubeOn void void 开数码管 nixietubeOff void void 关数码管 4 .NodeList类,存储所有连接设备的信息,便于进行界面节点的更新,删除和添加操作。
表4.7 NodeList成员属性表 属性 类型 描述 head NodeInfo 链表头结点 len Long 链表长度 表4.8 NodeList成员方法表 方法 参数 返回值 描述 getHead NodeInfo void 获取链表头结点 setHead void NodeInfo 设置链表头结点 createNodeList void void 创建设备节点链表 insertNode NodeInfo void 插入节点 delNode NodeInfo void 删除节点 allNode void void 遍历链表所有节点 findByDevNum int NodeInfo 通过设备号找到节点 nodeIsNotExisted int boolean 通过设备号查找节点是否存在于链表 delByDevNum int void 通过设备号删除节点 allNodeSetWatchDog void String 所有设备节点看门狗减一 oneNodeFeedWatchDog int void 通过设备号找到设备节点并喂狗 findNodeDogDie void int 遍历设备节点,查看是否有节点生命结束 getLen void int 得到链表长度 findNodeByPos int NodeInfo 通过在链表中位置查找到设备节点 4.1.2.2 线程类详细描述 1 . MainReadThread类 当启动MainReadThread线程,执行run方法,run方法先通过running判断是否执行读操作,如果running为true,进行对设备读操作,判断MainHandlerThread处理线程是否创建,未创建则创建并将读出的数据传给MainHandlerThread,并启动线程,循环执行。
图4.4 MainReadThread RUN流程图 2 . MainHandlerThread类 当MainReadThread线程将读取的数据传到MainHandlerThread后,先对数据进行有效性认证,如果数据有误,使用handler传递发送给SmartHomeActivity即主界面UI线程,进行处理;如果数据无误,判断数据类型并使用handler传递,发送给SmartHomeActivity进行处理。
图4.5 MainHandlerThread RUN流程图 3 . NodeWriteThread类 只负责执行设备控制的命令,使用线程可以使程序多次独立线程执行,不被影响。
图4.6 NodeWriteThread RUN流程图 4.1.2.3 UI类详细描述 1 . SmartHomeActivity类 (1) onCreate a) 初始化节点列表nodeList。
b) 设置从界面标题,setTitle。
c) 设置视图,setContentView。
d) 获取主界面控件的引用,findViewById。
e) 设置GridView和使用的适配器BaseAdapter。
f) 设置选项被单击的监听器,setOnItemClickListener。
g) 设置线程的 Handler,重写handleMessage方法。
h) 打开程序读线程。
i) 注册返回广播接收器。
(2) onDestroy a) 卸载广播接收器,unregisterReceiver。
b) 关闭读线程,mainReadThread.stop。
c) 关闭主界面Activity,this.finish。
a) 设置所有节点的看门狗减一,allNodeSetWatchDog。
b) 判断是否有节点看门狗死亡,findNodeDogDie。如果存在,删除Node节点链表,delByDevNum,并判断是否进入该节点从界面,如果进入则发送广播使其退出。最后,向该死亡设备发送确认命令ISEXIT,如果未死亡,重新发送添加节点NewNode的数据。……………….? c) 更新适配器notifyDataSetChanged。>>>>>>>>>>>>>>>>>>? (4) BackReceiver 广播接受器 a) 从节点列表删除从界面返回的节点的原对象,nodeList.delByDevNum() b) 向节点列表插入从界面返回的新节点对象,nodeList.insertNode() c) 关闭从界面Activity ,finishActivity()。
2 . NodeInfoActivity类 (1) onCreate a) 创建从节点对象NodeInfo。
b) 设置视图,setContentView。
c) 获取从界面控件的引用,findViewById。
d) 通过Intent对象,获取从主界面传来的nodeInfo对象并赋给从界面对象。
e) 设置从界面标题,setTitle。
f) 将主界面获取的nodeInfo对象反馈到界面,setText。
g) 注册广播接收器 h) 设置返回键监听器 i) 设置风扇监听器,设置Led监听器,设置蜂鸣器监听器,设置数码管监听器 (2) onDestroy 卸载广播接收器,unregisterReceiver。
4.1.2.4 数据库详细描述 1 . RfidRecordDBHelper类 继承SQLiteOpenHelper类,重写onCreate方法。
·表新建 使用SQLiteDatabase对象的execSQL方法去添加表。命令如下:
create table if not exists rfidTable (id INTEGER primary key autoincrement,
devId varchar, rfId varchar) ·增加 使用SQLiteDatabase对象的execSQL方法去增加数据。命令如下:
insert into rfidTable(devId, rfId) values (?,?) ·删除 使用SQLiteDatabase对象的execSQL方法去删除数据。命令如下:
delete from rfidTable where rfId = ? 2 . 数据库表设计 表4.9 rfidTable数据库表 字段名 类型 属性 描述 id INTEGER primary key autoincrement ID主键 devId VARCHAR Null 设备号 rfId VARCHAR Null RFID号 4.1.2.5 框架详细描述 · MyUartService类 1 .加载库,System.loadLibrary(“uart_runtime“) 2 .重写构造函数,调用本地 __init方法,对设备进行初始化。
3. 通过调用本地方法实现java方法 4.2 A8-数据传递架构模块 4.2.1 层次接口表
数据传递(串口操作) 应用层 UartDataUpdate New
UartSendCmd
framework层 _uart_send_cmd _uart_data_update _init
JNI层 Uart_write Uart_init Uart_read
Hal层 Uart_write_hal Uart_read_drv Uart_device_open Uart_read_hal Uart_write_drv
驱动 Write Open Read
图4.6.1 接口层次图
图4.6.2 结构图 4.2.2 HAL层 1、 宏 表4.10 HAL层宏定义表 名称 内容 功能 UART_HARDWARE_MODULE_ID “uart“ 定义hal 的模块id START 0xAA 数据包的开始符 NEW 0x01 新节点加入发的包 INFO 0x02 采集的信息包 RFID 0x04 刷卡时发的包 2、 全局变量 表4.11 HAL层全局变量表 名称 类型 功能 fd int 操作设备的文件描述符 3、 结构体 表4.12 HAL层结构体表 struct uart_module_t 成员名 类型 功能 common struct hw_module_t 记录本stub的基本信息和入口 struct uart_control_device_t 成员名 类型 功能 common struct hw_device_t 记录本stub操作设备时需要包括的接口 uart_read_hal 函数指针 指向实际读串口的函数 uart_write_hal 函数指针 指向实际写串口的函数 4、流程图
图4.7 HAL层结构图 4.2.3 JNI层 1、 宏 表4.13 JNI层宏定义表 名称 内容 功能 UART_HARDWARE_MODULE_ID “uart“ 定义HAL 的模块ID 2、 全局变量 表4.14 JNI层全局变量表 名称 类型 功能 sUartDevice uart_control_device_t * 保存通过调用stub中的open接口后得到的devices handle sUartModule uart_module_t* 保存通过调用Android HAL标准函数hw_get_module,传入UART_HARDWARE_MODULE_ID后得到的UART stub的句柄 3、 流程图 JNI层主要实现了Java与c/c++之间的过渡,不涉及复杂的逻辑,只根据规则为上层函数调用相应的下层接口,参见整体流程。
4.2.4 Framework层 表4.15 Framework层类表 public class MyUartService 方法 功能 System.loadLibrary 装载编译好的JNI层的共享库 public MyUartService 构造函数,打开并初始化串口 public String UartDataUpdate 读取当前串口信息数据包 public int UartSendCmd 向串口传送命令数据包 4.2.5 整体流程
下续:hal层
图4.8 整体流程图 4.2.6 关键代码分析 1. NodeCmd.java static MyUartService myUartService = new MyUartService(); //新建对象,初始化
String s = myUartService.UartDataUpdate(); //更新采集数据
myUartService.UartSendCmd(1, LED_ON);
//点亮1号设备的灯
2. MyUartService.java package cn.com.smarthome.uart;
import android.util.Log;
public class MyUartService {
/*
* load native service.
*/
static {
System.loadLibrary(“uart_runtime“); //装载库
}
public MyUartService() {
_init(); //注册本地方法,打开串口并初始化
}
/*
* uart native methods.
*/
public String UartDataUpdate() {
String s = _uart_data_update();
return s;v
}//更新采集的数据
public int UartSendCmd(int n, int c) {
_uart_send_cmd(n, c);
return 0;
} //发送命令控制M0板
private static native boolean _init();
/声明jni库可以提供的方法
private static native String _uart_data_update();
private static native int _uart_send_cmd(int n, int c);
3. uart_stub\include\uart.h struct uart_module_t {
struct hw_module_t common;
};//HAL 规定不能直接使用hw_module_t结构,因此需要做这么一个继承。
struct uart_control_device_t {
//自定义的一个针对Uart控制的结构,包含hw_device_t和支持的API操作
struct hw_device_t common;
/* attributes */
/* supporting control APIs go here */
int (*uart_read_hal)(struct uart_control_device_t *dev, char *buf, int count);
int (*uart_write_hal)(struct uart_control_device_t *dev, const char *cmd);
};
#define UART_HARDWARE_MODULE_ID “uart“
//定义一个MODULE_ID,HAL层可以根据这个ID找到我们这个HAL stub
4. cn_com_smarthome_uart_MyUartService.cpp #define LOG_TAG “MyUartService“
#include “utils/Log.h“
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <jni.h>
#include “../../uart_stub/include/uart.h“
static uart_control_device_t *sUartDevice = 0;
static uart_module_t* sUartModule=0;
JNINativeMethod是 jni层注册的方法,Framework层可以使用这些方法
*_init 、uart_read、uart_write 是在Framework中调用的方法名称,函数的类型及返回值如下:
*()Z无参数 返回值为bool型
* ()Ljava/lang/String; 无参数 返回值为String型
* (II)I
参数为2个int型 返回值为int型
static const JNINativeMethod gMethods[] = {
{“_init“, “()Z“, (void*)uart_init},
{ “_uart_data_update“, “()Ljava/lang/String;“, (void*)uart_read },
{ “_uart_send_cmd“, “(II)I“,
(void*)uart_write },
};
static int registerMethods(JNIEnv* env) {
static const char* const kClassName =
“cn/com/smarthome/uart/MyUartService“; //注意:必须和Framework层的service类名相
jclass clazz;
/* look up the class */
clazz = env->FindClass(kClassName); //查找被注册的类
if (clazz == NULL) {
LOGE(“Can't find class %s\n“, kClassName);
return -1;
}
/* register all the methods */
if (env->RegisterNatives(clazz, gMethods,
sizeof(gMethods) / sizeof(gMethods[0])) != JNI_OK)
{
LOGE(“Failed registering methods for %s\n“, kClassName);
return -1;
} //向类中注册本SO中Native的接口,接口定义在gMethods数组中
/* fill out the rest of the ID cache */
return 0;
}
/*
*
*
* This is called by the VM when the shared library is first loaded.
* 在Android系统初始化时,就会自动加载该JNI方法调用表。
* 当第一次加载此库时,调用此函数注册本地方法 */ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env = NULL;
jint result = -1;
LOGI(“zzs_JNI_OnLoad“);
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
LOGE(“ERROR: GetEnv failed\n“);
goto fail;
} //获取当前的VM的环境,保存在env变量中
assert(env != NULL);
if (registerMethods(env) != 0) {
LOGE(“ERROR: PlatformLibrary native registration failed\n“);
goto fail;
} //自己写的函数,向当前JAVA环境中注册接口
/* success -- return valid version number */
result = JNI_VERSION_1_4;
fail:
return result; } /* JNI_OnLoad()函数完成:
(1) 把虚拟机环境信息保存到本地库的一个结构体“JNIEnv”的实例中; (2) 建立一个应用层中的UART控制服务与本地库的JNI函数表; (3) 返回虚拟机本地库使用的JNI版本。
*/
5. uart_stub\module\uart.c #define LOG_TAG “UartStub“
#include <hardware/hardware.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <cutils/log.h>
#include <cutils/atomic.h>
#include <sys/ioctl.h>
#include “../include/uart.h“
#include “crc16.h“
#define N 6
#define START 0xAA //用于传输协议的宏
#define NEW 0x01
#define INFO 0x02
#define RFID 0x04
int fd;
typedef struct {
char head;
char dev_no;
char type_data;
char length;
char temp[2];
char hum[2];
char bright[2];
char adc[2];
char acc[3];
char rfid[N];
short crc16;
}dev_data; //传输协议的格式
//CRC16的校验函数,查表法,表在crc16.h内
static unsigned short
get_crc16(const char * crc_head, int crc_lenth )
{
unsigned char ucCRCHi = 0x0;
unsigned char ucCRCLo = 0x0;
int iIndex;
while ( crc_lenth-- ) {
iIndex = ucCRCLo ^ *( crc_head++ );
ucCRCLo = ( unsigned char )( ucCRCHi ^ aucCRCHi[iIndex] );
ucCRCHi = aucCRCLo[iIndex];
}
return ( unsigned short )( ucCRCHi << 8 | ucCRCLo );
}
static int uart_device_close(struct hw_device_t* device)
{
struct uart_control_device_t* ctx = (struct uart_control_device_t*)device;
if (ctx) {
free(ctx);
}
close(fd);
return 0;
}
static int uart_read_drv(struct uart_control_device_t *dev, char *buf, int count)
{
dev_data info_buf;
char rev_buf[40] = {0}; //用于存放整个消息包
char data_buf[40] = {0}; //用于存放消息包内的数据段
char ch;
ssize_t cur_size = 0;
ssize_t r_size = 0;
char data_lenth = 0; //数据段的长度
char data_type;
//数据类型
char *data_head;
//数据段头
int dev_no;
//设备号
char *crc_head;
//用于CRC校验的头
int crc_lenth;
//用于crc校验的长度,从消息包头到数据段尾
unsigned short crc16; //校验值
int timeout = 10;
//超时处理,长时间读不到消息,当timeout减到0时,返回到上层
while (1)
{
timeout--; //由于采用轮询读的方法,如果没消息则会一直循环,设置一个超时值,当超出后还没数据的话,就退出此次读消息
if (!timeout) {
LOGI(“No start info_buf“);
return -1;
}
if (read (fd, &info_buf.head, 1) < 0) {
LOGE(“read START err“);
continue;
} //判断是否为帧头,不是就继续循环判断
if (info_buf.head != START) {
LOGI(“head is %x“, info_buf.head);
continue;
} else { //判断是否为帧头,不是就继续循环判断
timeout = 40;
if (read (fd, &info_buf.dev_no, 1) < 0) {
LOGE(“read dev_no err“);
return -1;
} //读出设备号
if (read (fd, &info_buf.type_data, 1) < 0) {
LOGE(“read type_data err“);
return -1;
} //读出数据类型
if (read (fd, &info_buf.length, 1) < 0) {
LOGE(“read length err“);
return -1;
}
//读出数据长度
while (cur_size < (info_buf.length+2)) {
if ((r_size = read (fd, (rev_buf + 4) + cur_size, (info_buf.length + 2) - cur_size)) < 0) {
LOGI(“read data err“);
continue;
}
cur_size += r_size; //累加到总共已读数据,用以与应对数据长度比较
} //读出数据
break;
}
}
rev_buf[0] = info_buf.head;
rev_buf[1] = info_buf.dev_no;
rev_buf[2] = info_buf.type_data;
rev_buf[3] = info_buf.length;
data_lenth = info_buf.length;
crc16 = ((rev_buf[4+data_lenth] & 0xffff) << 8) | rev_buf[5+data_lenth];
crc_head = rev_buf;
crc_lenth = data_lenth + 4 ;
//CRC16校验
if (crc16 == get_crc16(crc_head, crc_lenth)) {
switch (info_buf.type_data) {
case NEW:
sprintf(buf, “S%dFnI%d“, 4,info_buf.dev_no); //传递到上层传下的buf
break;
case INFO:
sprintf(data_buf,“T%d.%dH%d.%dL%dV%d.%dX%dY%dZ%d“,
rev_buf[4],rev_buf[5],
rev_buf[6],rev_buf[7], ((rev_buf[8] << 8) | rev_buf[9]), rev_buf[10], rev_buf[11],
rev_buf[12], rev_buf[13], rev_buf[14]);
//传递到上层传下的buf
sprintf(buf, “S%dFiI%d%s“, strlen(data_buf) + 4, info_buf.dev_no, data_buf);
break;
case RFID:
for (i=0; i< data_lenth; i++) {
sprintf(data_buf+i*2, “%x“, rev_buf[i+4] >> 4);
sprintf(data_buf+i*2+1, “%x“, rev_buf[i+4] & 0xf);
}
//传递到上层传下的buf
sprintf(buf, “S%dFrI%dR%s“, strlen(data_buf)+5, info_buf.dev_no, data_buf);
break;
} //将收到的数据打包成适合上传的格式,向上传递
LOGI(“HAL: buf is : %s“, buf);
} else {
LOGE(“CRC error!“);
}
return 0;
}
static int uart_write_drv(struct uart_control_device_t *dev, const char *cmd)
{
ssize_t w_size = 0;
char cmd_buf[10] = {0};
char *crc_head;
char crc_lenth;
unsigned short crc16;
cmd_buf[0] = 'S';
cmd_buf[1] = cmd[0];
//dev_no
cmd_buf[2] = 'c';
//cmd flag:
cmd_buf[3] = '1'; //size of cmd
cmd_buf[4] = cmd[1]; // cmd
crc16 = get_crc16(cmd_buf, 5);
sprintf(cmd_buf + 5, “%c%c“, crc16 >> 8, crc16 &0xff);
//eg:S1c105656
if ((w_size = write(fd, cmd_buf, strlen(cmd_buf))) < 0) {
LOGE(“write erro, write %d bytes“, w_size);
return -1;
}
LOGI(“Hal write %d bytes cmd :%s“, w_size, cmd_buf);
return 0;
}
static int uart_device_open(const struct hw_module_t* module, const char* name,
struct hw_device_t** device)
{
struct uart_control_device_t *dev;
struct termios options;
LOGD(“HAL:uart_device_open“);
dev = (struct uart_control_device_t *)malloc(sizeof(*dev));
memset(dev, 0, sizeof(*dev));
//HAL must init property
dev->common.tag= HARDWARE_DEVICE_TAG; //必须写这个
dev->common.version = 0;
dev->common.module= module;
dev->common.close = uart_device_close;
//关联关闭函数
//实例化支持的操作
dev->uart_read_hal = uart_read_drv;
dev->uart_write_hal = uart_write_drv;
*device= &dev->common;
//将实例化后的uart_control_device_t地址返回给jni层
//这样jni层就可以直接调用uart_read_drv、uart_write_drv、uart_device_close方法
//打开硬件设备,由于上层需求底层不能阻塞,故使用非阻塞方式打开
if((fd = open(“/dev/ttyUSB0“,O_RDWR | O_NOCTTY | O_NDELAY)) < 0)
{
LOGE(“open error“);
return -1;;
}else {
LOGI(“open ok\n“);
}
//初始化串口
tcgetattr(fd, &options);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~CSIZE;
options.c_cflag &= ~CRTSCTS; // 不使用数据流控制
options.c_cflag |= CS8;
//将数据位修改为8bit
options.c_cflag &= ~CSTOPB;
//无结束位
options.c_iflag |= IGNPAR;
/*网上许多流行的linux串口编程的版本中都没对c_iflag(termios成员变量)这个变量进行有效的设置,
这样传送ASCII码时没什么问题,但传送二进制数据时遇到0x0d,0x11和0x13却会被丢掉。
不用说也知道,这几个肯定是特殊字符,被用作特殊控制了。关掉ICRNL和IXON选项即可解决。*/
c_iflag &= ~(ICRNL | IXON);
/*0x0d 回车符CR
0x11 ^Q VSTART字符
0x13 ^S VSTOP字符
ICRNL 将输入的CR转换为NL
IXON 使起动/停止输出控制流起作用*/
options.c_oflag = 0;
options.c_lflag = 0;
cfsetispeed(&options, B115200); //指定输入波特率,115200bps
cfsetospeed(&options, B115200); //指定输出波特率,115200bps
tcsetattr(fd,TCSANOW,&options);
return 0;
}
//定一个hw_module_methods_t结构体,关联入口函数
static struct hw_module_methods_t uart_module_methods = {
open: uart_device_open
};
//定义Stub入口
//注意必须使用:
//1。hw_module_t继承类
//2。必须使用HAL_MODULE_INFO_SYM这个名字
const struct uart_module_t HAL_MODULE_INFO_SYM = {
common: {
tag: HARDWARE_MODULE_TAG,
version_major: 1,
version_minor: 0,
id: UART_HARDWARE_MODULE_ID,
//模块ID,上层的Service通过这个ID应用当前Stub
name: “uart HAL module“,
author: “farsight“,
methods: &uart_module_methods, //入口函数管理结构体
},
/* supporting APIs go here */
};
4.3 传输协议模块设计 4.3.1 A8接收数据格式 表4.16 数据格式表 buf[0] buf[1] buf[2] buf[3] buf[length] send_buf[n] 数据包头 设备号 数据类型 数据长度 数据 校验 0xAA dev_no type_data length data Crc16校验 1byte 1byte 1byte 1byte length bytes 2bytes 数据包头:M0向A8发送数据包头为0xAA
A8向M0发送数据包头为0x55 设备号:
为M0设备号(房间号) 数据类型:0x01 M0开机(房间开启监控)
0x02 为温度、湿度、光照度类型数据
0x04为RFID卡类数据 数据长度:为数据域的字节数 校验:crc16校 M0采集数据的结构体 #define N 6
typedef struct
{
char
head;
//数据包头
char
dev_no;
//设备号
char
type_data; //数据类型 0x02为一般温度、湿度类型数据 0x04为卡类数据类型
char
length;
//数据的长度
温湿度数据长度为
char
temp[2];
//温度数据
char
hum[2];
//湿度数据
char
bright[2]; //光照度数据
char
adc[2];
//ADC 转换数据
char
acc[3];
//三轴加速x,y,z
char
rfid[N];
//卡类数据
short crc16;
//crc校验值
}dev_data;
表4.17 M0发送数据类型 命令类型 0x01 命令 Crc16校验
0x01 开机 高位 低位
Buf[4] Buf[5] Buf[6]
温湿度数据 0x02 温度 湿度 光照度 AD转换 高位 低位位 高位 低位 高位 低位 高位 低位 Buf[4] Buf[5] Buf[6] Buf[7] Buf[8] Buf[9] Buf[10] Buf[11] 16位 16位 16位 16位 三轴加速 Crc16校验
X Y Z 高位 低位
Buf[12] Buf[13] Buf[14] Buf[15] Buf[16]
8位 8位 8位 16位
卡类信息 0x04 RFID卡号 Crc16校验 高位 低位 高位 低位 高位 低位 高位 低位 Buf[4] Buf[5] Buf[6] Buf[7] Buf[8] Buf[9] Buf[10] Buf[11] 16位 16位 16位 16位 4.3.2 M0接收命令数据结构 Typedef struct
{
char
head;
//数据包头 ‘S’
char
dev_no;
//设备号(房间号)
char
type_data; // 数据类型为‘c’
char
length;
//数据的长度
数据长度为
char
cmd;
//命令
温湿度数据长度为
short crc16;
}dev_cmd
表4.18 M0接收数据类型 命令 Crc16校验 M0接收数据 高位 低位 8位 8位 8位 Buf[5] Buf[6] Buf[7] 表4.19 数据对应命令 命令 动作 0x30 LED_ON(开灯) 0x31 LED_OFF(关灯) 0x32 Fan_ON(开风扇) 0x33 Fan_OFF(关风扇) 0x34 Nixietube_ON(开数码管) 0x35 Nixietube _OFF(关数码管) 0x36 BEEP_ON(开蜂鸣器) 0x37 BEEP_OFF(关蜂鸣器 第 5 章
终端M0模块设计 5.1 终端设备方案描述 智能家居的终端设备,主要负责对室内各种信息进行采集,并将信息上传给终端设备,并对终端设备发出的指令进行及时响应。室内的相关信息主要包括温湿度、光感度、三轴加速度、电压信息以及进出室内的刷卡信息。
主控制器选择了NXP的LPC11C14(以下简称M0),它是ARM Cortex-M0系列的低功耗32位处理器,它最高可以工作到50MHZ,无论是在速度上还是在功耗上,亦或是抗干扰能力上,它完全能够胜任终端数据采集的重任。
前端设备与终端设备的通信采用的是ZigBee通信模块,它功耗低,成本低,具有优良的网络拓扑结构,便于组网。它与M0之间的连接采用的是双向的SPI/IIC到UART转换芯片SC16IS752,节省了片上有限的UART资源。其他器件这里不做赘述,整体方案如图5.1所示:
图5.1 终端设备整体方案图
5.2 终端设备工作流程 1) 系统上电,初始化系统时钟,使能IO时钟、配置LED、FAN、SPEAKER、7LED的IO端口,初始化SPI0、SPI1。使能系统滴答定时器,设置其中断时间为1ms。其中断处理函数中每到1S,对全局变量counter1,counter2加1。
2) 向终端发送新设备注册节点信息 3) 判断counter1是否大于4S,大于则收集数据信息,并按指定协议发送给终端设备,同时将counter1清零。
4) 判断counter1是否大于3S,大于则喂狗,同时将counter2清零。
5) 读取 SPI752_rbuf_1[],如果有数据,则将其存储到指定的数组中,然后判断是否接收完毕,若接受完毕,则进行数据校验,若校验正确,则根据协议中的指定位判断是否为发给自己的指令,如果是则执行相应的指令处理函数;若数据未接受完毕,则继续下一步的操作。
6) 查看是否有刷卡信息,若有,则进行相应的卡操作,若没有则返回步骤3继续操作。
M0工作流程如图5.2所示。
图5.2
M0整体工作流程图 5.3 功能模块描述 5.3.1 温湿度传感器DHT10 5.3.1.1 基本概述 DHT10数字温湿度传感器是是一款含有已校准数字信号输出的温湿度传感器,它具有成本低,性能稳定,抗干扰能力强等优点。
它采用简化的单总线通信,主机通过特定的时序对其进行访问,它一次传送给主机40位数据,高位先出,其数据格式如下:
8bit温度整数数据 + 8bit温度小数数据 + 8bit湿度整数数据 + 8bit湿度小数数据 + 8bit校验位 其中8bit的校验位为前面4Byte数据之和。
它与M0的连接如图5.3所示,其中上拉电阻R30是为了保证在总线空闲时,其状态为高电平。
图5.3
DHT11原理图 5.3.1.2 操作流程及时序 用户主机发起开始信号后,数据时序如图5.4所示:
图5.4
DHT11数据时序图 M0读取数据的步骤如下:
1) DHT11上电后(DHT11上电后要等待1S越过不稳定状态,在此期间不要做任何操作),测试环境温湿度,并记录数据,此时DHT11的DATA数据线由上拉电阻拉高,它的引脚处于输入状态,时刻检测外部起始信号。
2) 将M0设置为输出,并输出低电平,保持18ms以上,然后M0设置为输入,此时DATA数据线被拉高,等待DHT11的响应信号。
3) DHT11接收到M0的低电平起始信号后,延时一段时间,向M0发送80us的低电平响应信号,接下来继续发送80us的高电平信号,通知M0准备接收数据。M0接受到低电平响应信号后,延时80us后接受数据。
4) DHT11的DATA引脚输出40位的数据,MO根据电平的变化来获得数据。位数据0的格式为50us的低电平加26-28us的高电平。位数据1的格式为50us的低电平加70us的高电平。
5) DHT11输出40位数据后,继续输出50us的低电平后转为输入状态。
5.3.2 ZigBee通信部分 5.3.2.1 ZigBee通信模块 ZigBee模块采用的是周立功公司代理的ZICM2410模块,它提供了多种数据接口,这里我们选择的是UART串口,它与M0之间是通过SC16IS752转换芯片进行连接,如图5.5所示。
图5.5
ZigBee与M0连接图 对于ZICM2410模块,由于其使用方便,我们只需对数据接口进行读写即可,所以这里不做过多赘述。对于它的网络配置,可参照其操作手册。
5.3.2.2 SC16IS752使用及操作流程
SC16IS752是一款双向的SPI/IIC转UART的芯片,在这里,我们选择的是SPI转UART,在这种模式下,它只能做为从机,MO为主机。它分别含有64Byte的发送和接收FIFO,默认情况下,FIFO未使能,用FIFO的第一个字节来接收数据。它含有七种优先级的中断,在这里我们将RHR(数据接收)中断使能,当有数据时,产生RHR中断,此时IRQ引脚被拉低,由于与之相连的MO管脚设置为下降沿触发中断,所以此时M0产生中断,在中断处理函数中,通过读取IS752的中断标识寄存器(IIR),判断是否为数据接收中断,若是,则读取数据接收保持寄存器(RHR),并将读取出来的数据保存到全局的数据接收循环队列SPI752_rbuf_1[MAX]中,同时将队尾全局变量SPI752_rbuf_0_ip加1,若超过最大位置MAX - 1,则将其置0,同时还存在另一队头全局变量SPI752_rbuf_0_op,指向当前读取到的数据位置,开始时队头和队尾指向同一位置。在主函数中,通过轮询查看是否有数据,即队头和队尾是否相等,若不等,则读取队头数据,将队头加1,若超过MAX - 1,则置0。M0的ZigBee接收中断程序流程如图5.6所示。
5.3.2.3 SPI串行外设接口 1.概述 M0有两个SPI控制器,分别为SPI0和SPI1,与ZigBee相连的是SPI1,SPI0与RFID模块相连。
SPI接口有四个引脚,分别为SCK、SSEL、MISO和MOSI,它们的功能如下:
● SCK:串行时钟信号,用来同步数据传输,由主机驱动,从机接收,只有在发送数据时才会处于激活状态。
● SSEL:作为主机时,在发送数据前,使能该管脚,在发送数据结束后,释放该管脚。
● MISO:主机输入,从机输出 ● MOSI:主机输出,从机输入
图5.6
ZigBee接收中断函数流程图 2.SPI操作流程 在使用SPI前,先使能SPI的时钟单元,对于M0来说,初始状态各个单元的时钟模块都是未使能的。接下来对SPI进行基本设置,如设置数据帧长度及捕获方式等。另外还要将M0设置为主机模式。接下来进行数据的收发操作分析,SPI数据传输是双向的,即数据发送和接受时同步的,但往往只有一个方向的数据是有效的,在操作时,一般将发送和接收封装在一个函数中。
发送数据前,先要判断TX FIFO是否满,若不满,则将要发送的数据写入DR寄存器的低16位既DATA寄存器,如果此时总线上的SPI控制器不忙,则数据会被立即发送,否则,写入DATA寄存器的数据要一直等待,直到当前数据被发送完为止。如果发送的数据不足16位,则需要软件进行纠正。
接收数据时,先判断RX FIFO是否不空,若不空,则可以读取DATA寄存器里的数据,这里返回的数据是最新一帧的数据。如果数据长度不足16位,则高位补零。
SPI数据发送和接收如图5.7所示:
图5.7
SPI数据发送和接收流程图 5.3.3 RFID读卡模块 RFID读卡模块通过SPI0接口与M0进行连接,它的中断引脚与M0的IO 口相连,在主程序中,只要判断该IO口的电平高低,即可判断是否有卡,如果有卡,则进行相应的读卡操作。
RFID的命令格式为:前导头 + 通讯长度 + 命令字 + 数据域 + 校检码 其中前导头固定为0XAA 0XBB,通讯长度为去掉前导头和通讯长度本身的所有数据帧的字节数,命令字和数据域详见模块使用说明。在这里我们只要读取卡号,命令字为0X20,返回的数据域为4字节的卡号。cpu发送命令帧之后,需要等待读取返回值,返回值的格式如下:
前导头+数据长度+上次发送的命令字+数据域+校检码 RFID读卡的流程如图5.8所示:
图5.8
RFID读卡流程 5.3.4 IIC接口部分 5.3.4.1 IIC概述 根据方向位的状态(R/W),IIC总线上可能存在两种数据传输状态:
1)主发送器向从接收器发送数据。主机发送的第一个字节是从机的地址,接下来的是发送给从机的数据,从机每接收到一个字节即发回一个ACK 应答。
2)从发送器向主接收器发送数据。主接收器先发送从发送器的地址,从发送器接收到后返回ACK,接下来从发送器向主接收器发送数据,除了最后一字节外,主接收器每接收一个字节即返回一个ACK,最后一个字节返回一个非应答位。
无论是发送还是接收,串行时钟信号及起始和停止位都由主机发起。每发送一个字节,在状态寄存器中都会有相应的状态其SI位会置位,这时我们可以在SI中断处理函数中,根据不同的寄存器状态,作相应的处理。具体的状态及相应的操作,可详见数据手册。
5.3.4.2 IIC操作流程分析 1) IIC的初始化:复位IIC,使能IIC时钟单元,设置相应的I0口为IIC功能,清除应答位、起始位、中断位、IIC使能位,设置IIC传输速率,如果是从机的话,设置从机地址,IIC中断使能,最后启动IIC. 2) IIC的启动 uint32_t I2CStart( void )
{
uint32_t timeout = 0;
uint32_t retVal = FALSE;
LPC_I2C->CONSET = I2CONSET_STA
//设置起始位
/*循环等待起始位发送,设置超时时间*/
while( 1 )
{
if ( I2CMasterState == I2C_STARTED )
//起始位发送成功,中断中设置
{
retVal = TRUE;
break;
}
if ( timeout >= I2C_MAX_TIMEOUT )
//起始位发送超时
{
retVal = FALSE;
break;
}
timeout++;
}
return( retVal );
}
3)IIC的停止 uint32_t I2CStop( void )
{
LPC_I2C->CONSET = I2CONSET_STO;
//设置停止位
LPC_I2C->CONCLR = I2CONCLR_SIC;
//清除中断标志
/*等待停止位发送*/
while( LPC_I2C->CONSET & I2CONSET_STO );
return TRUE;
}
4)IIC的一次完整通信 uint32_t I2CEngine( void )
{
I2CMasterState = I2C_IDLE;
//初始状态
RdIndex = 0;
WrIndex = 0;
if ( I2CStart() != TRUE )
//发送启动信号
{
I2CStop();
return ( FALSE );
}
while ( 1 )
{
if ( I2CMasterState == DATA_NACK )
//判断数据是否传输完毕
{
I2CStop();
//IIC停止
break;
}
}
return ( TRUE );
}
5)主发送代码 void I2CWrite(uint8_t addr, uint8_t* buf, uint32_t len)
{
I2CAddr = addr;
//设置从机地址
I2CMasterBuffer = buf;
//主发送Buffer指向要传输的数据
I2CWriteLength = len;
//发送数据的长度
I2CReadLength = 0;
I2CEngine();
//启动IIC完整的通信过程
I2CWriteLength = I2CWriteLength;
}
6)中断处理函数
每次状态的改变,SI位都会置位,在中断处理函数中,根据不同的状态码,进行相应的操作,在这些操作中,清除SI位是必须要做的,在这里主要列出主发送中断的处理函数部分,其他部分可根据数据手册的操作流程进行相应的操作。
void I2C_IRQHandler(void)
{
uint8_t StatValue;
/* 仅列出了主发送方式的处理*/
StatValue = LPC_I2C->STAT;
//读取状态码
switch ( StatValue )
//根据状态码执行不同的操作
{
case 0x08:
//已发送起始条件
WrIndex = 0;
LPC_I2C->DAT = I2CAddr;
//SLA + W装入数据寄存器
LPC_I2C->CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);//请吃SIC及STAC位
I2CMasterState = I2C_STARTED;
break;
case 0x10:
//已发送重复起始条件
RdIndex = 0;
/* 发送SLA + R状态位 */
LPC_I2C->DAT = I2CAddr;
LPC_I2C->CONCLR = (I2CONCLR_SIC | I2CONCLR_STAC);
I2CMasterState = I2C_RESTARTED;
break;
case 0x18:
//以发送SLA + W,并已接受ACK
if ( I2CMasterState == I2C_STARTED )
{
LPC_I2C->DAT = I2CMasterBuffer[WrIndex++]; //发送数据写入DATA寄存器
I2CMasterState = DATA_ACK;
}
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
case 0x28: /* 数据已发送,返回ACK或非ACK*/
case 0x30:
if ( WrIndex < I2CWriteLength ) //判断是否发送完,未完继续发送
{
LPC_I2C->DAT = I2CMasterBuffer[WrIndex++];
I2CMasterState = DATA_ACK;
}
Else
//指定长度的数据已发送完
{
if ( I2CReadLength != 0 )
{
LPC_I2C->CONSET = I2CONSET_STA; //设置重复起始条件
I2CMasterState = I2C_REPEATED_START;
}
else
{
I2CMasterState = DATA_NACK;
LPC_I2C->CONSET = I2CONSET_STO;
// 置位停止位
}
}
LPC_I2C->CONCLR = I2CONCLR_SIC;
break;
……
}
第 6 章
系统测试 6.1 项目演示 1. 打开A8设备,启动SmartHome程序,如图6.1所示。
图6.1 启动SmartHome 2. 打开M0设备(NO.2), SmartHome程序检测到设备并添加,如图6.2所示。打开M0设备(NO.1),SmartHome程序会自动排序并添加,如图6.3所示。
图6.2 启动M0(No.2)
图6.3 启动M0(No.2) 3. 测试M0控制器。点击风扇按键,如图6.4所示,M0风扇正常打开。点击Led灯按键,如图6.5示,M0 Led灯正常打开。点击蜂鸣器按键,如图6.6所示,M0蜂鸣器正常打开。点击数码管按键,如图6.7所示,M0数码管正常打开。
6 图6.4 打开风扇 图6.5 打开电灯 图6.6 打开蜂鸣器 图6.7 打开数码管 4. 测试M0传感器。未调节M0 ADC前,AD值如图6.8所示。调节M0 ADC后,AD值如图6.9所示。由以上图例,可观测到,程序左上角机器人,会根据M0 三轴加速器(x,y)的值而进行位置改变。
图6.8 未调整的AD值
图6.9调整后的AD值 4. 测试RFID。使用磁卡对M0进行刷卡操作,模拟用户进入,效果如图6.10所示。使用磁卡再次对M0进行刷卡操作,模拟用户退出,效果如图6.11所示。
图6.10用户进入 图6.11用户退出 5. 测试设备离线。关闭设备,模拟设备退出,在等待3-5秒后,相应设备图标消失,效果如图6.12所示。打开设备,设备重新添加,效果如图6.13所示。
图6.12关闭设备
图6.13关闭设备
- 上一篇:农村食品安全整治月工作方案
- 下一篇:大棚租赁合同
猜你喜欢
- 2024-01-20 2024年某县食用菌产业发展调研报告(全文完整)
- 2024-01-20 有关机关公文格式调研报告
- 2024-01-20 关于国有企业腐败问题预防惩治情况调研报告【精选推荐】
- 2024-01-19 (10篇)关于企业文化建设调研报告
- 2024-01-19 2024年党校开展党纪律教育情况调研报告(完整文档)
- 2024-01-19 思政教育学科社会服务调研报告
- 2024-01-19 2024年度主题教育调研文章(2024年)
- 2024-01-18 2024年度(7篇)落实全面从严治党主体责任情况报告、述责述廉报告、一岗双责素材汇编(四)
- 2024-01-18 2024年关于市直机关意识形态风险防范情况调研报告
- 2024-01-18 述德述职述廉报告(范文推荐)
- 搜索
-
- 党支部2021年度工作计划 10-14
- 取得脱贫攻坚战全面胜利的内涵和意义7篇 12-16
- 社区工作人员上班工作纪律制度 06-02
- 2021大学生组织生活会党员个人对照检查 09-14
- 关于市重大项目进展情况与下一步工作推 07-13
- 巡察报告反馈意见建议(全文完整) 11-02
- 关于推进全面深化改革工作的情况和建议 10-09
- 团员推优党支部意见 06-28
- 2020领导个人述法报告三篇 09-02
- 国开(中央电大)行管本科《西方行政学说 06-08
- 网站分类
-
- 标签列表
-