安卓蓝牙开发——综合实训工作总结

前言

大二暑期参加了学校组织的综合实训,选择的课题是机器人儿童教育,其主要任务是做一个app,实现蓝牙连接机器人并通过蓝牙发送指令使机器人行动的功能。目前综合实训时间过半,我们组已经实现了蓝牙连接的基本功能,能够手机互连蓝牙并发送消息。在此对前半段小组遇到的关键知识点和坑点进行总结。

权限

使用蓝牙首先要在清单文件中添加权限。在AndroidManifest.xml中添加:

    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

因为目前手机都是安卓6.0以上的版本,还需要获得位置权限

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

这里有个小坑,对于写好的app,可能部分机型需要给appGPS定位的权限,不然可能无法使用app的搜索蓝牙功能。我的组员使用小米手机就遇到了这个坑。

查看是否支持蓝牙设备

使用BluetoothAdapter,如果手机能够支持蓝牙,会返回一个BluetoothAdapter的对象

BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if(mBluetoothAdapter == null){
    //Device does not support Bluetooth
}

打开蓝牙

用自动的.enable()方法

public void requestEnableBt() {
if (!mBluetoothAdapter.isEnabled())
//开启蓝牙
mBluetoothAdapter.enable();
}

但是更建议用手动的办法

Intent enableIntent = new Intent(
        BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent,REQUEST_ENABLE_BT);

启动设备可见性

蓝牙为了安全性,在设计的时候有一个可见性,如果蓝牙不可见,那么是连不上的。这个时候我们必须将设备设为可见。
让设备在300s内设为可见的

Intent discoverableIntent = new Intent(BluetoothAdapter  ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdpter EXTRA_DISCOVERABLE_DURATION,300);
startActivity(discoverableIntent);

搜索蓝牙设备

适配器搜索蓝牙设备后将结果以广播形式传出去,所以蓝牙搜索主要是要实现一个BroadcastReceiver 广播接收者。在onReceive方法中获得并处理蓝牙设备的搜索结果。
关键代码如下:

private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    @Override public void onReceive(Context context, Intent intent) {
        String action=intent.getAction();
        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 if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED
                .equals(action)){
            progressBar.setVisibility(View.GONE);
            Toast.makeText(DeviceList.this,"搜索完毕",Toast.LENGTH_SHORT).show();
            if(mNewDevicesArrayAdapter.getCount()==0){
                String noDevices=getResources().getText(
                        R.string.none_found).toString();
                mNewDevicesArrayAdapter.add(noDevices);
            }
        }
    }
};

蓝牙连接功能

这个时候就需要用到线程了,java学得好的同学肯定上手得特快。反正我在这里卡了很久,找了很多资料,学习了很多大佬们的代码,这里要感谢网上的大佬们。按我自己的理解,蓝牙连接和java中基于Socket套接字的低层次Java网络编程类似。这里也用到三个线程,分别是AcceptThread 监听线程、ConnectThread 连接线程和ConnectedThread管理线程。

监听线程

监听线程就是被动等待连接的线程,调用了BluetoothServerSocket.accept()方法

    private class AcceptThread extends Thread{
        private final BluetoothServerSocket mmServerSocket;

        public AcceptThread(){
            BluetoothServerSocket tmp = null;
            try{
                tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME,MY_UUID);
            }catch (IOException e){}
            mmServerSocket = tmp;
        }


        public void run(){
        BluetoothSocket socket= null;
        while(mState != STATE_CONNECTED){
            try{
                socket = mmServerSocket.accept();
            }catch (IOException e) {
                break;
            }
            if(socket != null){
                connected(socket,socket.getRemoteDevice());
                try{
                    mmServerSocket.close();
                }catch (IOException e){}
            }
        }
    }
    
        public void cancel(){
            try{
                mmServerSocket.close();
            }catch (IOException e){}
        }
}

连接线程

连接线程的作用是对外发出连接蓝牙的请求

private class ConnectThread extends Thread{
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;

    public ConnectThread(BluetoothDevice device){
        mmDevice=device;
        BluetoothSocket tmp = null;

        try{
            tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
        }catch (IOException e){}
        mmSocket = tmp;
    }

    public void run(){

        mAdapter.cancelDiscovery();
        try{
            mmSocket.connect();
        }catch (IOException e){
            connectionFailed();
            try{
                mmSocket.close();
            }catch (IOException e2){}
           return;
       }
        synchronized(ChatService.this){
            mConnectedThread = null;
       }
        connected(mmSocket,mmDevice);
    }

    public void cancel(){
        try{
            mmSocket.close();
        }catch (IOException e){}
    }
}

管理线程

管理线程的作用是管理连接上的双方。也起到数据传输的作用

private class ConnectedThread extends Thread{
    private final BluetoothSocket mmSocket;
    private final InputStream mmInStream;
    private final OutputStream mmOutStream;

    public ConnectedThread(BluetoothSocket socket){
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut=null;
        try{
            tmpIn=mmSocket.getInputStream();
            tmpOut=mmSocket.getOutputStream();
        }catch (IOException e){}

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    public void run(){
        byte[]buffer=new byte[1024];
        int bytes;
        while (true){
            try{
                bytes = mmInStream.read(buffer);
                mHandler.obtainMessage(MainActivity.MESSAGE_READ,bytes,-1,buffer).sendToTarget();
            }catch (IOException e){
                connectionLost();
                break;
            }
        }
    }

    public void write(byte[]buffer){
        try{
            mmOutStream.write(buffer);
        }catch (IOException e){
            Log.d("MainActivity","Send Fail");
        }
        mHandler.obtainMessage(MainActivity.MESSAGE_WRITE,buffer).sendToTarget();
    }

    public void cancel(){
        try{
            mmSocket.close();
        }catch (IOException e){}
    }
}

一些学习中的“坑点”

1.现在安卓版本大多数比较高,在建工程的时候最低API要选择19
在这里插入图片描述
2.在学习过程中我们时常要借鉴别人大佬优秀的代码,而有的时候下载大佬的代码包在自己AS上运行的时候容易出现这样的错误:
WARNING: The specified Android SDK Build Tools version (27.0.3) is ignored, as it is below the minimum supported version (28.0.3) for Android Gradle Plugin 3.4.1.
Android SDK Build Tools 28.0.3 will be used.
To suppress this warning, remove “buildToolsVersion ‘27.0.3’” from your build.gradle file, as each version of the Android Gradle Plugin now has a default version of the build tools.
Remove Build Tools version and sync project
Affected Modules: app
这个错误的原因是因为版本号和API不匹配,这个时候只需要在Tools/SDK Manager 下载对应的API,然后在build.gradle(Module:app)中的buildToolsVersion '27.0.3’修改对应的版本号就能解决啦。
在这里插入图片描述
3.我在运行代码的过程中有时候出现app闪退的现象,我总结下主要原因可能如下:
有些API在老版本中有,在新版本中没有,造成对象为空引起闪退;
页面布局问题。
4.在代码下载到手机上时,需要把Settings里面Instant Run中的第一个框取消勾选。
在这里插入图片描述

目前遇到的坑点只想到这些,以后还会慢慢总结

注:此文章目的只用于自己学习总结,如有错误的地方还请指正!

班级 研01-12 学号 西安电子科技大学 通信系统综合实验报告 学 院 : 通信工程学院 班 级 : 研01-12 专 业 : 交通信息工程及控制 姓 名 : 2012年11月 目录 实验一 数字基带仿真实验 1 1.1 实验目的 1 1.2 实验原理 1 1.2.1 差错控制原理 1 1.2.2 跳频扩频原理 3 1.2.3 保密通信原理 4 1.3 实验内容 4 1.4 实验结果及数据分析 5 1.4.1 差错控制 5 1.4.2 跳频 7 1.4.3 加密解密 12 实验二 通信传输的有效性与可靠性分析 14 2.1实验目的 14 2.2实验原理 14 2.2.1 数据传输的流量控制 14 2.2.2 误码和差错控制 15 2.2.3 信道共享技术 15 2.3实验内容 16 2.4 实验结果及数据分析 17 2.4.1 性能仿真 17 2.4.2. 速率测试 22 2.4.3. 文件传输 24 实验三 无线多点组网 27 3.1 实验目的 27 3.2 实验原理 27 3.2.1 通信网络拓扑结构 27 3.2.2 路由技术 28 3.2.3 广播和组播 28 3.2.4 Ad hoc网络 28 3.3 实验内容 28 3.4 实验结果及数据分析 29 3.4.1 组网过程 29 3.4.2 单跳与多跳转接 31 3.4.3. 单播(Unicast) 31 3.4.4. 路由协议 32 3.4.5. 广播(Broadcast)与组播(Multicast) 32 实验四 语音传输 34 4.1 实验目的 34 4.2 实验原理 34 4.2.1 脉冲编码调制 34 4.2.2 连续可变斜率增量调制 35 4.2.3 随机错误和突发错误 36 4.2.4 内部通话与数据传输的工作过程 36 4.2.5 蓝牙设备的身份切换 37 4.3 实验内容 37 4.4 实验结果及数据分析 38 4.4.1 参数相同时的波形 38 4.4.2 相同误码率不同频率的波形 39 4.4.3 用蓝牙连接的传输过程 42 实验一 数字基带仿真实验 2 实验目的 此实验软件主要对蓝牙(bluetooth)技术中基带信号处理方法作了仿真,包括差错控 制方法、跳频扩频原理以及保密通信等。本实验要求实验人员利用本软件对通信系统特 别是无线通信系统的基带信号处理方法有较深入的认识和理解,具体有以下几个目的: 1、理解基带传输中的差错控制方法、差错控制编码分类及其纠检错能力;了解差错控制 编码的生成和纠、检错方法。 2、理解扩频通信(特别是跳频扩频通信)的基本概念、原理及其优缺点。 3、理解两种加密体制的异同;了解保密通信的全过程,以及密钥在保密通信中的作用。 1.2 实验原理 本实验原理主要包括差错控制原理,调频扩频原理,保密通信原理等。 1.2.1 差错控制原理 数字信号在传输过程中,由于受到干扰的影响,码元波形将变坏。接收端收到后可能 发生错误判决。一般理论中,合理设计基带信号,选择调制解调方式,采用时域、频域 均衡,以此来降低比特误码率,但是在实际中,许多通信系统的比特误码率并不能满足 实际的需求,因此我们需要进行差错控制。常用的差错控制方法有检错重发(简称ARQ) 、前向纠错(FEC)、混合纠错(HEC)。 通常差错控制编码的实现方法:在发送端将被传输的信息附上一些监督码元,这些多 余的码元与信息码元之间以某种确定的规则相互关联,然后在接收端按照既定的规则校 验信息码元与监督码元之间的关系,一旦传输发生错误,则信息码元与监督码元的关系 就受到破坏,从而接收端可以发现错误乃至纠正错误。蓝牙基带包中采用的差错控制编 码如下: a.包头附加循环冗余校验码以保证包头的完整性,该差错控制通常被称为包头检查 (HEC)。 HEC的生成示意图见图1。在产生HEC前,线性移位反馈寄存器(LFSR)需要 初始化。为易于理解,初始化值采用设备的高8位地址(UAP)。输入数据为10位的包头 信息(低位先入)。输出数据为包头信息(10位,低位先出)+HEC(8位,低位先出)。 在接收端,恢复包头信息的示意图与图1同。此时,输入数据为18位的附加HEC的包头数 据。若8位寄存器的结果值全为0,则说明包头信息传输正确;反之,则说明包头信息传 输错误,需重传。 图1 HEC的生成示意图 b.有效载荷校验(采用CRC,cyclic redundancy check)。添加到有效载荷中的16位CRC循环冗余校验码,用来判断有效载荷数据传送得 是否正确。该16位码通过CRC- CCITT多项式210041(8进制表示)生成,见图2的生成示意图。在生成CRC码前,采用设 备的高8位地址初始化线性反馈移位寄存器。实验中规定输入数据为80位的有效载荷信息 (低位先入)。输出为有效载荷
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值