冬枭

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

 

    

1、需求分析 6

2、选用的开发技术和理由 6

3、系统总框图和功能模块说明

3.1 系统用例图 7

3.2 系统总框图 7

3.3 功能模块说明 8

3.4 硬件模块说明 8

4、系统设计 12

4.1 系统部分重要功能的时序图 12

5、系统调试 15

6、界面效果 21

7、总结

8、源程序清单

8.1 arduino IDE源代码文件

8.2 BTClint文件

8.3 DeviceListActivity文件 38

8.4 Device_list.xml文件 55

8.5 Device_main.xml 55

8.6 Device_name.xml 56

 

 

 

1、需求分析

随着科技的发展,人们越发追求舒适、便捷、安全的生活质量.同时,随着移动支付等,人们使用手机的频率也逐渐的增加,本次设计以安卓为上位机,控制arduino实现一系列功能诸如,第一通过移动手机端打开卧室灯、厨房灯、厕所灯。第二,开门,主要有两个门一个是大门,大门可以通过蓝牙手机打开,开门的时候会顺便打开门旁边的灯,室内的还有一个自动门,通过超声波,有人路过会自动开门。第三,可以通过蓝牙手机移动端开门,第四,监控室内温度,当室内温度过高的时候会提示,并打印温度。第五,监控室内一氧化碳浓度,当室内一氧化碳浓度过高的时候会提示,并且开窗和打印室内一氧化碳浓度。第六,串口显示数据,可以通过串口传看多类数据,和通过串口调试。

实现以上功能,当人们已经躺在床上时,而发现厕所,或者厨房灯没关,可以一键关灯。室内温度高于人体舒适温度的时候也会发出提示,并且在后期可以添加一些控制设备,开空调灯。同时可以监控室内一氧化碳含量,如果含量过高就会自己开窗,还会不断地提示。

1 功能流程图

2、选用的开发技术和理由

选用安卓技术,现如今手机的使用量大大增加,使用手机十分的方便,并且这学期学习了安卓技术,所以用安卓作为上位机。使用arduino作为下位机,使用蓝牙模块和手机进行通信。

使用arduino可以大大缩减开发周期,Arduino是一款便捷灵活、方便上手的开源电子原型平台。包含硬件(各种型号的Arduino板)和软件(Arduino IDE)。1、跨平台Arduino IDE可以在Windows、Macintosh OS X、Linux三大主流操作系统上运行,而其他的大多数控制器只能在Windows上开发。2、简单清晰Arduino IDE基于processing IDE开发。极易掌握,同时有着足够的灵活性。Arduino语言基于wiring语言开发,是对 avr-gcc库的二次封装

 

3、系统总框图和功能模块说明

3.1 系统

3.2 系统总框图

 

3.3 功能模块说明

从需求分析可以找到,该系统分为用户使用的基本功能

多功能数字生活智能门系统包括以下主要功能:

(1)手机开灯功能:通过移动手机端打开卧室灯、厨房灯、厕所灯。

(2)安卓手机移动端开门模块,主要有两个门一个是大门,大门可以通过蓝牙手机打开,开门的时候会顺便打开门旁边的灯

(3)自动开门模块:室内的还有一个自动门,通过超声波,有人路过会自动开门。

(4)温度阈值监控模块:监控室内温度,当室内温度过高的时候会提示,并打印温度。

(5)一氧化碳阈值监控模块:监控室内一氧化碳浓度,当室内一氧化碳浓度过高的时候会提示,并且开窗和打印室内一氧化碳浓度

(6)用户查看模块:串口显示数据,可以通过串口传看多类数据,和通过串口调试。

 

3.4 硬件说明

1)arduino下位机

 

rduino是一款便捷灵活、方便上手的开源电子原型平台。包含硬件(各种型号的Arduino板)和软件(ArduinoIDE)。由一个欧洲开发团队于2005年冬季开发。其成员包括Massimo Banzi、David Cuartielles、Tom Igoe、Gianluca Martino、David Mellis和Nicholas Zambetti等。

它构建于开放原始码simple I/O介面版,并且具有使用类似Java、C语言的Processing/Wiring开发环境。主要包含两个的部分:硬件部分是可以用来做电路连接的Arduino电路板;另外一个则是Arduino IDE,你的计算机中的程序开发环境。你只要在IDE中编写程序代码,将程序上传到Arduino电路板后,程序便会告诉Arduino电路板要做些什么了。

Arduino能通过各种各样的传感器来感知环境,通过控制灯光、马达和其他的装置来反馈、影响环境。板子上的微控制器可以通过Arduino的编程语言来编写程序,编译成二进制文件,烧录进微控制器。对Arduino的编程是通过 Arduino编程语言 (基于 Wiring)和Arduino开发环境(基于 Processing)来实现的。基于Arduino的项目,可以只包含Arduino,也可以包含Arduino和其他一些在PC上运行的软件,它们之间进行通信 (比如 Flash, Processing, MaxMSP)来实现。

(2)蓝牙模块 ZS-040

 

低功耗:无线模块都需要上电才能够使用,BLE蓝牙模块支持1.8~3.6V供电,模块工作的时候就会提高产品的功耗,而为了优化智能产品/设备的功耗值,选择低功耗的蓝牙模块是有必要的。BLE蓝牙模块本身就是低功耗的物联网无线模块,低功耗蓝牙之所以非常省电,在于它有一个超低峰值的标准,在空闲模式下基本不需要消耗电量。随着蓝牙5.0标准到来的是比蓝牙4.2更低的功耗值,如MS50SFB就属于蓝牙5.0模块。

高传输速率:5.0蓝牙模块速度最快可以达到3Mbps(目前是1.5Mbps),让反应更快、性能更高的蓝牙设备被更好使用。快速数据传输可满足固件升级或可穿戴设备数据日志同步等应用场景,设备连接响应时间也会大大缩短,产品性能将更加出色,体验效果也会随之上升。

远传输距离:在之前的物联网无线传输应用中,传输距离稍微远一点的,工程师就会推荐使用WiFi模块,但是在5.0蓝牙模块出来之后,情况得到很好改善,新到来的蓝牙5.0带来了更高速、更远传输距离的优势,理论上的有效距离300米以上,整个家庭或整间办公室里的移动设备都可以稳定连结。

(3)超声波模块

 

超声波测距模块是用来测量距离的一种产品,通过发送和收超声波,利用时间差和声音传播速度,计算出模块到前方障碍物的距离。

超声波测距模块:

超声波测距模块有好多种类型,比较常用的有URM37超声波传感器默认是232接口,可以调为TTL接口,URM05大功率超声波传感器测试距离能到10米,算是测试距离比较远的一款了,另外还有比较常用的国外的几款SRF系列的超声波模块,超声波模块精度能到1cm

(4)监控一氧化碳模块

 

识别系统把待测物的某一化学参数(常常是浓度)与传导系统连结起来。它主要具有两种功能:选择性地与待测物发生作用,把所测得的化学参数转化成传导系统可以产生响应的信号。分子识别系统是决定整个化学传感器的关键因素。因此,化学传感器研究的主要问题就是分子识别系统的选择以及如何把分子识别系统与合适的传导系统相连续。

化学传感器的传导系统接受识别系统响应信号,并通过电极、光纤或质量敏感元件将响应信号以电压、电流或光强度等的变化形式,传送到电子系统进行放大或进行转换输出,最终使识别系统的响应信号转变为人们所能用作分析的信号,检测出样品中待测物的量。化学一氧化碳气体传感器采用密闭结构设计,其结构是由电极、过滤器、透气膜、电解液、电极引出线(管脚)、壳体等部分组成。

(5)室内温度传感器

    

温度计通过传导或对流达到热平衡,从而使温度计的示值能直接表示被测对象的温度。一般测量精度较高。在一定的测温范围内,温度计也可测量物体内部的温度分布。但对于运动体、小目标或热容量很小的对象则会产生较大的测量误差,常用的温度计有双金属温度计玻璃液体温度计压力式温度计电阻温度计、热敏电阻和温差电偶等。它们广泛应用于工业、农业、商业等部门。在日常生活中人们也常常使用这些温度计。随着低温技术在国防工程、空间技术、冶金、电子、食品、医药和石油化工等部门的广泛应用和超导技术的研究,测量120K以下温度的低温温度计得到了发展,如低温气体温度计、蒸汽压温度计、声学温度计、顺磁盐温度计、量子温度计、低温热电阻和低温温差电偶等。低温温度计要求感温元件体积小、准确度高、复现性和稳定性好。利用多孔高硅氧玻璃渗碳烧结而成的渗碳玻璃热电阻就是低温温度计的一种感温元件,可用于测量1.6~300K范围内的温度。

(6)LED灯、电阻

  

LED 是英文 light emitting diode 的缩写,也就是发光二极管的意思。由于LED灯具有节能、环保、安全多方面的优越特性,现已经被广泛应用于照明领域。小功率LED灯,单颗LED功率只有0.03-0.1瓦的照明灯具。与大功率产品相比具有亮度高、结温低、寿命长、发散度好,节能环保减少碳排放

 

 

4、系统设计

4.1 系统部分重要功能的时序图

 

5 一氧化碳监控反馈时序图

 

6 室内温度监控反馈时序图

 

 

7 用户控制卧室厨房、厕所灯

 

8 超声波自动门时序图

 

         图9   安卓移动端开门时序图

 

 

5、系统调试

1)蓝牙模块无法通信

问题:使用蓝牙模块和安卓之间无法通信

解决方法:首先排除程序问题,检测界限,TX和RX需要接到arduino板上的RX和TX,然后选择正确的波特率,再次尝试通信

 

 

图14 刷新调试

   

2)LED灯始终不亮

问题:LED灯接在面包板上始终无法点亮

解决方法:排除程序IO口是否选择正确,程序高低电平赋值是否正确,通过单一变量法一点点排除原因

 

 

图15 背景音乐调试

 

(3)舵机转动次序混乱

问题:舵机的转动顺序有问题,不断的来回转

解决方法:滞环比控制死区大,一般控制死区范围为±0.4%,滞环可设置为±2%,输入信号和反馈信号的差值在滞环内电机不动作,输入信号和反馈信号的差值进入滞环,电机开始制动-停止。

    

 

图16 页面数据传递调试

 

 

6、硬件接线图

 

  1. 超声波

超声波模块   共有四个引脚,分别为,VCC、GND、TRIG、Echo

VCC接面板板上5V电压,GND接地

TRID接arduino上表示为12的IO口

 

  1. LED灯*4

LED灯四个,一端分别接在arduino板上标识为5、6、7的IO口,一边串联电阻接地。

 

  1. 蓝牙模块

蓝牙模块总共有四个引脚,GND、TXD、RXD、VCC

VCC接面包板上5V电压,GND接地

TXD接arduino板上标识为RXD的IO口,RXD接arduino板上为TXD的IO口

 

  1. 室内温度模块

室内温度模块共有三个引脚,一个是VCC、GND和DQ

VCC接面包板上5V电压,GND接地

TXD接arduino板上标识为3的IO口

 

5.一氧化碳模块

一氧化碳共有4个引脚,分别为VCC、GND、AD、DO

VCC接面包板上5V电压,GND接地

AD接arduino板上表示为AD的IO口,DO接在arduino板上表示为2的IO口

 

  1. 舵机*2

 

舵机有三根线,红色接5V,棕色接地,橙色分别arduino上标识为9和10的两个IO口上

 

  1. 安卓界面演示图

超过阈值时

不断提示警报

 

点击查看室内温度

 

 

点击查看气度浓度

 

 

串口数据查看

 

 

 

 

未超过阈值时

 

 

 

7、总结

  经过两个星期的奋斗,终于做出大部分想要的功能,在这个期间,遇到了许多的难题,从硬件到软件。硬件部分,第一是硬件调试困难, arduino连接多个传感器的时候我借用的是面包板,面包板有一半的接地出现了问题,接地之后并不能导通,导致了在接好一个LED灯后接另外三个LED困难,采用了单一变量法一个个排除原因。其次是线尾端宽度较大,需要一定间隔,而面包板空间有限,需要很好的排线,这也是没做好的地方之一。第二,硬件接线问题,为了做这个项目,学习arduino和蓝牙几乎从零开始,所以一开始硬件接线,包括在arduino上,在面包板上,都要花费一点时间。第三是由于硬件设施不齐全,原本想要做血氧心率检测的装置,但是血氧心率检测的传感器坏掉了,导致硬件设施不齐全,最终才修改方案,做多了一个自动门,这期间也耽误乐乐一点时间

  软件方面,第一软件需要自己制作一个安卓蓝牙的收发器,做出来后,因为时间因素,验收的时候借用了其他的调试助手,后期还需要完善自己的安卓蓝牙收发器。第二,arduino的IDE平台编程的时候经常会遇到一些库的问题,需要在网上找一些头文件,大部分是在arduino中文社区里面找到的。第三,软件硬件调试的时候总不可避免地出现因编程原因而导致硬件故障,只能一点点的小心调试,功能无法一次性集成化调试,需要首先打开一个新的IDE,验证传感器是否正常工作,串口是否能正确接收数据,然后才能将相应的代码带入到总工程。期间需要调试很多硬件。

  总而言之,本次课设让我收获很大,是对安卓课程的一个结合和扩展,让我受益匪浅,希望在后面的日子,能够不断的完善自己的系统,学到更加多的东西!

 

 

 

 

 

 

 

 

 

8、源程序清单

Arduino IDE代码

#include <Servo.h>

#include <OneWire.h> //可以不引入,因为DallasTemperature.h中已经引入了OneWire.h

#include <DallasTemperature.h>

#include <NewPing.h>

#define TRIGGER_PIN 13

#define ECHO_PIN 12

#define MAX_DISTANCE 200

#define ONE_WIRE_BUS 4               //1-wire数据总线连接在IO4

OneWire oneWire(ONE_WIRE_BUS);       //声明

DallasTemperature sensors(&oneWire); //声明

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);

 

 

Servo myservo;  // 定义Servo对象来控制

Servo myservo2;

int pos = 0;    // 角度存储变量

int mqAPin=A0;

int mqDPin=2;

int mqBite=0;

int mqVal=0;

float mqVot=0;

int p;

int q;

unsigned long previousMillis = 0; //毫秒时间记录

const long interval = 1000;       //时间间隔

 

void setup()

{

  Serial.begin(9600);

  myservo.attach(9);  // 控制线连接数字9

  myservo2.attach(10);  // 控制线连接数字9

  sensors.begin(); //初始化总线

  //sensors.setWaitForConversion(false); //设置为非阻塞模式

  pinMode(11, OUTPUT);

  pinMode(5, OUTPUT);

  pinMode(6, OUTPUT);

  pinMode(7, OUTPUT);

  pinMode(mqAPin, INPUT);

}

 

 

void loop()

{

   unsigned int distance = sonar.ping_cm();

   //Serial.println(distance);

    if(distance==1){

        for (pos = 0; pos <= 90; pos ++) { // 0°180°

            myservo2.write(pos);              // 舵机角度写入

            delay(5);                       // 等待转动到指定角度

            }

            delay(500);

        for (pos = 90; pos >= 90; pos --) { // 180°

            myservo2.write(pos);              // 舵机角度写入

            delay(5);                       // 等待转动到指定角度

            }  

      }

   float tempC = sensors.getTempCByIndex(0); //获取索引号0的传感器摄氏温度数据

    //Serial.println("怎么回事?");

    mqVal = analogRead(mqAPin);

        // ADC输出值转换为模拟电压值

    mqVot = mqVal*0.0049;

    //Serial.println(mqVot);  

    mqBite = digitalRead(mqDPin);

//  while(Serial.available()>0)

//  {

//    q=Serial.parseInt();

//    if(Serial.read()=='X'){

//      switch(q){

//        case 104:

//               Serial.print("测试");

//               break;

//        default :

//                break;  

//      }

//    }

//  }

 

  

  while(Serial.available()>0)

  { p = Serial.parseInt();           // 在串口数据流中查找一个有效整数。

    if (Serial.read() == 'X') {      // 收到结束符后开始处理数据。

      if(p==104){

        if(mqVot <0.5){

        Serial.println("一氧化碳浓度正常!");

          }

        else{

        Serial.println("一氧化碳浓度超标!!!");

          }

        Serial.print(mqVot);

        delay(500);

      }

      else if(p==105){

        digitalWrite(5,HIGH);       // 点亮厨房灯

        

      }

      else if(p==106){

        digitalWrite(6,HIGH);  //点亮卧室灯

      }

      else if(p==107){

        digitalWrite(7,HIGH);  //厕所灯

      }

       else if(p==108){

        digitalWrite(5,LOW);       //关厨房灯

        

      }

      else if(p==109){

        digitalWrite(6,LOW);  //关卧室灯

      }

      else if(p==110){

        digitalWrite(7,LOW);  //关厕所灯

      }

       else if(p==111){

        digitalWrite(11,LOW);  //关门边灯

      }

       else if(p==112){

//        digitalWrite(11,LOW);  //关灯

//         digitalWrite(7,LOW);  //关灯

//          digitalWrite(6,LOW);  //关灯

//          digitalWrite(5,LOW);       //关灯

        for (pos = 0; pos <= 90; pos ++) { // 0°180°

            myservo2.write(pos);              // 舵机角度写入

            delay(5);                       // 等待转动到指定角度

            }

            delay(500);

        for (pos = 90; pos >= 90; pos --) { // 180°

            myservo2.write(pos);              // 舵机角度写入

            delay(5);                       // 等待转动到指定角度

            }  

        

      }

      else{

        

      }

 

 

switch (p) {                   // 判断数据内容。

      case 101:

        digitalWrite(11,HIGH);       // 点亮LED

       // Serial.println(p);           // 回传数据。

        for (pos = 0; pos <= 90; pos ++) { // 0°180°

            myservo.write(pos);              // 舵机角度写入

            delay(5);                       // 等待转动到指定角度

            }

            delay(500);

        for (pos = 180; pos >= 90; pos --) { // 180°

            myservo.write(pos);              // 舵机角度写入

            delay(5);                       // 等待转动到指定角度

            }     

        break;

//   case 102:

//        digitalWrite(11,LOW);        // 熄灭LED

//       // Serial.println(p);           // 回传数据。

//        break;

   case 103:

          //以下段落相当于每秒读取前次温度,并发起新一次温度转换

        unsigned long currentMillis = millis();         //读取当前时间

        if (currentMillis - previousMillis >= interval) //如果和前次时间大于等于时间间隔

         {

             previousMillis = currentMillis; //更新时间记

                 if (tempC != 0)       //如果获取到的温度正常

                      {

                        Serial.print("\n当前室内温度是: ");

                        Serial.print(tempC);

                        Serial.println(" ℃");

                        }

              if(tempC>18&&tempC<27){

             Serial.println("室内温度正好");

              }

              else{

                Serial.println("室内温度不正常");

              }

             sensors.requestTemperatures(); //发起新的温度转换

          }

            delay(1000);

            //Serial.print(".");

        break;

  

          

      default:

        //p = map(p,0,100,0,255);      // 转换数据范围到PWM输出值。

        //analogWrite(13,p);           // 调整LED亮度。(PWM

        break;

      }

 

 

      if(tempC>=26){

        Serial.print("当前温度较热,黄色警报!");

      }

      if(mqBite >=1){

        Serial.println("一氧化碳浓度不正常!");

          }

      sensors.requestTemperatures();

    }

  }

}

 

 

 

蓝牙接收器代码:

BTClient.java

package com.test.BTClient;

 

 

 

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStream;

import java.util.UUID;

 

import com.test.BTClient.DeviceListActivity;

 

import android.app.Activity;

import android.app.AlertDialog;

import android.bluetooth.BluetoothAdapter;

import android.bluetooth.BluetoothDevice;

import android.bluetooth.BluetoothSocket;

import android.content.DialogInterface;

import android.content.Intent;

import android.os.Bundle;

import android.os.Environment;

import android.os.Handler;

import android.os.Message;

import android.view.LayoutInflater;

//import android.view.Menu;            //如使用菜单加入此三包

//import android.view.MenuInflater;

//import android.view.MenuItem;

import android.view.View;

import android.widget.Button;

import android.widget.EditText;

import android.widget.ScrollView;

import android.widget.TextView;

import android.widget.Toast;

 

public class BTClient extends Activity {

 

private final static int REQUEST_CONNECT_DEVICE = 1;    //宏定义查询设备句柄

 

private final static String MY_UUID = "00001101-0000-1000-8000-00805F9B34FB";   //SPP服务UUID

 

private InputStream is;    //输入流,用来接收蓝牙数据

//private TextView text0;    //提示栏解句柄

    private EditText edit0;    //发送数据输入句柄

    private TextView dis;       //接收数据显示句柄

    private ScrollView sv;      //翻页句柄

    private String smsg = "";    //显示用数据缓存

    private String fmsg = "";    //保存用数据缓存

    public String filename=""; //用来保存存储的文件名

    BluetoothDevice _device = null;     //蓝牙设备

    BluetoothSocket _socket = null;      //蓝牙通信socket

    boolean _discoveryFinished = false;    

    boolean bRun = true;

    boolean bThread = false;

 

private BluetoothAdapter _bluetooth = BluetoothAdapter.getDefaultAdapter();    //获取本地蓝牙适配器,即蓝牙设备

@Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);   //设置画面为主画面 main.xml

        

        //text0 = (TextView)findViewById(R.id.Text0);  //得到提示栏句柄

        edit0 = (EditText)findViewById(R.id.Edit0);   //得到输入框句柄

        sv = (ScrollView)findViewById(R.id.ScrollView01);  //得到翻页句柄

        dis = (TextView) findViewById(R.id.in);      //得到数据显示句柄

 

       //如果打开本地蓝牙设备不成功,提示信息,结束程序

        if (_bluetooth == null){

         Toast.makeText(this, "无法打开手机蓝牙,请确认手机是否有蓝牙功能!", Toast.LENGTH_LONG).show();

            finish();

            return;

        }

        

        // 设置设备可以被搜索  

       new Thread(){

        public void run(){

        if(_bluetooth.isEnabled()==false){

         _bluetooth.enable();

        }

        }       

       }.start();      

    }

 

    //发送按键

public void onSendButtonClicked(View v){  //发送数据,主要通过蓝牙的socket发送,其中需要把edit的换行处理一下。

     int i=0;

     int n=0;

     try{

     OutputStream os = _socket.getOutputStream();   //蓝牙连接输出流

     byte[] bos = edit0.getText().toString().getBytes();

     for(i=0;i<bos.length;i++){

     if(bos[i]==0x0a)n++;  //0x0a是换行符

     }

     byte[] bos_new = new byte[bos.length+n];

     n=0;

     for(i=0;i<bos.length;i++){ //手机中换行为0a,将其改为0d 0a后再发送

     if(bos[i]==0x0a){

     bos_new[n]=0x0d;

     n++;

     bos_new[n]=0x0a;

     }else{

     bos_new[n]=bos[i];

     }

     n++;

     }

    

     os.write(bos_new);

     }catch(IOException e){  

     }  

    }

    

    //接收活动结果,响应startActivityForResult()

    public void onActivityResult(int requestCode, int resultCode, Intent data) {

     switch(requestCode){

     case REQUEST_CONNECT_DEVICE:     //连接结果,由DeviceListActivity设置返回

     // 响应返回结果

            if (resultCode == Activity.RESULT_OK) {   //连接成功,由DeviceListActivity设置返回

                // MAC地址,由DeviceListActivity设置返回

                String address = data.getExtras()

                                     .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);

                // 得到蓝牙设备句柄      

                _device = _bluetooth.getRemoteDevice(address);

 

                // 用服务号得到socket

                try{

                 _socket = _device.createRfcommSocketToServiceRecord(UUID.fromString(MY_UUID));

                }catch(IOException e){

                 Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();

                }

                //连接socket

             Button btn = (Button) findViewById(R.id.Button03);

                try{

                 _socket.connect();

                 Toast.makeText(this, "连接"+_device.getName()+"成功!", Toast.LENGTH_SHORT).show();

                 btn.setText("断开");

                }catch(IOException e){

                 try{

                 Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();

                 _socket.close();

                 _socket = null;

                 }catch(IOException ee){

                 Toast.makeText(this, "连接失败!", Toast.LENGTH_SHORT).show();

                 }

                

                 return;

                }

                

                //打开接收线程

                try{

             is = _socket.getInputStream();   //得到蓝牙数据输入流

             }catch(IOException e){

             Toast.makeText(this, "接收数据失败!", Toast.LENGTH_SHORT).show();

             return;

             }

             if(bThread==false){

             ReadThread.start();

             bThread=true;

             }else{

             bRun = true;

             }

            }

     break;

     default:break;

     }

    }

    

    //接收数据线程

    Thread ReadThread=new Thread(){

    

     public void run(){

     int num = 0;

     byte[] buffer = new byte[1024];

     byte[] buffer_new = new byte[1024];

     int i = 0;

     int n = 0;

     bRun = true;

     //接收线程

     while(true){

     try{

     while(is.available()==0){

     while(bRun == false){}

     }

     while(true){

     num = is.read(buffer);         //读入数据

     n=0;

    

     String s0 = new String(buffer,0,num);

     fmsg+=s0;    //保存收到数据

     for(i=0;i<num;i++){

     if((buffer[i] == 0x0d)&&(buffer[i+1]==0x0a)){

     buffer_new[n] = 0x0a;

     i++;

     }else{

     buffer_new[n] = buffer[i];

     }

     n++;

     }

     String s = new String(buffer_new,0,n);

     smsg+=s;   //写入接收缓存

     if(is.available()==0)break;  //短时间没有数据才跳出进行显示

     }

     //发送显示消息,进行显示刷新

     handler.sendMessage(handler.obtainMessage());            

          }catch(IOException e){

          }

     }

     }

    };

    

    //消息处理队列

    Handler handler= new Handler(){

     public void handleMessage(Message msg){

     super.handleMessage(msg);

     dis.setText(smsg);   //显示数据

     sv.scrollTo(0,dis.getMeasuredHeight()); //跳至数据最后一页

     }

    };

    

    //关闭程序掉用处理部分

    public void onDestroy(){

     super.onDestroy();

     if(_socket!=null)  //关闭连接socket

     try{

     _socket.close();

     }catch(IOException e){}

    // _bluetooth.disable();  //关闭蓝牙服务

    }

    

    //菜单处理部分

  /* @Override

    public boolean onCreateOptionsMenu(Menu menu) {//建立菜单

        MenuInflater inflater = getMenuInflater();

        inflater.inflate(R.menu.option_menu, menu);

        return true;

    }*/

 

  /*  @Override

    public boolean onOptionsItemSelected(MenuItem item) { //菜单响应函数

        switch (item.getItemId()) {

        case R.id.scan:

         if(_bluetooth.isEnabled()==false){

         Toast.makeText(this, "Open BT......", Toast.LENGTH_LONG).show();

         return true;

         }

            // Launch the DeviceListActivity to see devices and do scan

            Intent serverIntent = new Intent(this, DeviceListActivity.class);

            startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);

            return true;

        case R.id.quit:

            finish();

            return true;

        case R.id.clear:

         smsg="";

         ls.setText(smsg);

         return true;

        case R.id.save:

         Save();

         return true;

        }

        return false;

    }*/

    

    //连接按键响应函数

    public void onConnectButtonClicked(View v){

     if(_bluetooth.isEnabled()==false){  //如果蓝牙服务不可用则提示

     Toast.makeText(this, " 打开蓝牙中...", Toast.LENGTH_LONG).show();

     return;

     }

    

    

        //如未连接设备则打开DeviceListActivity进行设备搜索

     Button btn = (Button) findViewById(R.id.Button03);

     if(_socket==null){

     Intent serverIntent = new Intent(this, DeviceListActivity.class); //跳转程序设置

     startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE);  //设置返回宏定义

     }

     else{

      //关闭连接socket

         try{

         

          is.close();

          _socket.close();

          _socket = null;

          bRun = false;

          btn.setText("连接");

         }catch(IOException e){}   

     }

     return;

    }

    

    //保存按键响应函数

    public void onSaveButtonClicked(View v){

     Save();

    }

    

    //清除按键响应函数

    public void onClearButtonClicked(View v){

     smsg="";

     fmsg="";

     dis.setText(smsg);

     return;

    }

    

    //退出按键响应函数

    public void onQuitButtonClicked(View v){

     finish();

    }

    

    //保存功能实现

private void Save() {

//显示对话框输入文件名

LayoutInflater factory = LayoutInflater.from(BTClient.this);  //图层模板生成器句柄

final View DialogView =  factory.inflate(R.layout.sname, null);  //sname.xml模板生成视图模板

new AlertDialog.Builder(BTClient.this)

.setTitle("文件名")

.setView(DialogView)   //设置视图模板

.setPositiveButton("确定",

new DialogInterface.OnClickListener() //确定按键响应函数

{

public void onClick(DialogInterface dialog, int whichButton){

EditText text1 = (EditText)DialogView.findViewById(R.id.sname);  //得到文件名输入框句柄

filename = text1.getText().toString();  //得到文件名

 

try{

if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){  //如果SD卡已准备好

 

filename =filename+".txt";   //在文件名末尾加上.txt

File sdCardDir = Environment.getExternalStorageDirectory();  //得到SD卡根目录

File BuildDir = new File(sdCardDir, "/data");   //打开data目录,如不存在则生成

if(BuildDir.exists()==false)BuildDir.mkdirs();

File saveFile =new File(BuildDir, filename);  //新建文件句柄,如已存在仍新建文档

FileOutputStream stream = new FileOutputStream(saveFile);  //打开文件输入流

stream.write(fmsg.getBytes());

stream.close();

Toast.makeText(BTClient.this, "存储成功!", Toast.LENGTH_SHORT).show();

}else{

Toast.makeText(BTClient.this, "没有存储卡!", Toast.LENGTH_LONG).show();

}

 

}catch(IOException e){

return;

}

 

 

 

}

})

.setNegativeButton("取消",   //取消按键响应函数,直接退出对话框不做任何处理

new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int which) {

}

}).show();  //显示对话框

}

}

 

DeviceListActivity.java

 

package com.test.BTClient;

 

import android.app.Activity;

import android.bluetooth.BluetoothAdapter;

import android.bluetooth.BluetoothDevice;

import android.content.BroadcastReceiver;

import android.content.Context;

import android.content.Intent;

import android.content.IntentFilter;

import android.os.Bundle;

import android.util.Log;

import android.view.View;

import android.view.Window;

import android.view.View.OnClickListener;

import android.widget.AdapterView;

import android.widget.ArrayAdapter;

import android.widget.Button;

import android.widget.ListView;

import android.widget.TextView;

import android.widget.AdapterView.OnItemClickListener;

 

 

public class DeviceListActivity extends Activity {

    // 调试用

    private static final String TAG = "DeviceListActivity";

    private static final boolean D = true;

 

    // 返回时数据标签

    public static String EXTRA_DEVICE_ADDRESS = "设备地址";

 

    // 成员域

    private BluetoothAdapter mBtAdapter;

    private ArrayAdapter<String> mPairedDevicesArrayAdapter;

    private ArrayAdapter<String> mNewDevicesArrayAdapter;

 

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

 

        // 创建并显示窗口

        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);  //设置窗口显示模式为窗口方式

        setContentView(R.layout.device_list);

 

        // 设定默认返回值为取消

        setResult(Activity.RESULT_CANCELED);

 

        // 设定扫描按键响应

        Button scanButton = (Button) findViewById(R.id.button_scan);

        scanButton.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {

                doDiscovery();

                v.setVisibility(View.GONE);

            }

        });

 

        // 初使化设备存储数组

        mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);

        mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);

 

        // 设置已配队设备列表

        

        ListView pairedListView = (ListView) findViewById(R.id.paired_devices);

        pairedListView.setAdapter(mPairedDevicesArrayAdapter);

        pairedListView.setOnItemClickListener(mDeviceClickListener);

 

        // 设置新查找设备列表

        ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);

        newDevicesListView.setAdapter(mNewDevicesArrayAdapter);

        newDevicesListView.setOnItemClickListener(mDeviceClickListener);

 

        // 注册接收查找到设备action接收器

        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);

        this.registerReceiver(mReceiver, filter);

 

        // 注册查找结束action接收器

        filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);

        this.registerReceiver(mReceiver, filter);

 

        // 得到本地蓝牙句柄

        mBtAdapter = BluetoothAdapter.getDefaultAdapter();

 

        // 得到已配对蓝牙设备列表

        //Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();

 

        // 添加已配对设备到列表并显示

       // if (pairedDevices.size() > 0) {

           // findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);

        //    for (BluetoothDevice device : pairedDevices) {

       //         mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());

       //     }

       // } else {

       //     String noDevices = "No devices have been paired";

       //     mPairedDevicesArrayAdapter.add(noDevices);

       // }

    }

 

    @Override

    protected void onDestroy() {

        super.onDestroy();

 

        // 关闭服务查找

        if (mBtAdapter != null) {

            mBtAdapter.cancelDiscovery();

        }

 

        // 注销action接收器

        this.unregisterReceiver(mReceiver);

    }

    

    public void OnCancel(View v){

     finish();

    }

    /**

     * 开始服务和设备查找

     */

    private void doDiscovery() {

        if (D) Log.d(TAG, "doDiscovery()");

 

        // 在窗口显示查找中信息

        setProgressBarIndeterminateVisibility(true);

        setTitle("查找设备中...");

 

        // 显示其它设备(未配对设备)列表

        findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);

 

        // 关闭再进行的服务查找

        if (mBtAdapter.isDiscovering()) {

            mBtAdapter.cancelDiscovery();

        }

        //并重新开始

        mBtAdapter.startDiscovery();

    }

 

    // 选择设备响应函数

    private OnItemClickListener mDeviceClickListener = new OnItemClickListener() {

        public void onItemClick(AdapterView<?> av, View v, int arg2, long arg3) {

            // 准备连接设备,关闭服务查找

            mBtAdapter.cancelDiscovery();

 

            // 得到mac地址

            String info = ((TextView) v).getText().toString();

            String address = info.substring(info.length() - 17);

 

            // 设置返回数据

            Intent intent = new Intent();

            intent.putExtra(EXTRA_DEVICE_ADDRESS, address);

 

            // 设置返回值并结束程序

            setResult(Activity.RESULT_OK, intent);

            finish();

        }

    };

 

    // 查找到设备和搜索完成action监听器

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {

        @Override

        public void onReceive(Context context, Intent intent) {

            String action = intent.getAction();

 

            // 查找到设备action

            if (BluetoothDevice.ACTION_FOUND.equals(action)) {

                // 得到蓝牙设备

                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);

                // 如果是已配对的则略过,已得到显示,其余的在添加到列表中进行显示

                if (device.getBondState() != BluetoothDevice.BOND_BONDED) {

                    mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());

                }else{  //添加到已配对设备列表

                 mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());

                }

            // 搜索完成action

            } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {

                setProgressBarIndeterminateVisibility(false);

                setTitle("选择要连接的设备");

                if (mNewDevicesArrayAdapter.getCount() == 0) {

                    String noDevices = "没有找到新设备";

                    mNewDevicesArrayAdapter.add(noDevices);

                }

             //   if(mPairedDevicesArrayAdapter.getCount() > 0)

              //   findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);

            }

        }

    };

 

 

}

 

Device_list.xml

<?xml version="1.0" encoding="utf-8"?>

 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    >

    <ListView android:id="@+id/paired_devices"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:stackFromBottom="true"

        android:layout_weight="1"

    />

    <TextView android:id="@+id/title_new_devices"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:text="未配对设备"

        android:visibility="gone"

        android:background="#666"

        android:textColor="#fff"

        android:paddingLeft="5dp"

    />

    <ListView android:id="@+id/new_devices"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:stackFromBottom="true"

        android:layout_weight="2"

    />

    <Button android:id="@+id/button_scan"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:text="查找设备"

    />

    <Button android:id="@+id/button_cancel"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:text="取消"

        android:onClick="OnCancel"

    />

</LinearLayout>

 

Device_main.xml

<?xml version="1.0" encoding="utf-8"?>

<ListView xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="match_parent" >

  

</ListView>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Device_name.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    >

 

    <TextView android:id="@+id/title_new_devices"

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:text="请输入保存的文件名"

    />

    <EditText android:id="@+id/sname"

     android:layout_width="match_parent"

     android:layout_height="wrap_content"

     ></EditText>

   

</LinearLayoout>

 

posted on 2021-10-26 22:29  冬枭  阅读(760)  评论(0编辑  收藏  举报