注册登录

基于android手机的蓝牙BLE串口开发

1.首先申请相关权限。在manifest.xml

<uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
    <uses-feature android:name="android.bluetooth_le" android:required="true"/>
    <uses-permission-sdk-23 android:name="android.permission.ACCESS_COARSE_LOCATION"/>
    <application>
       .....
    </application>

2.声明蓝牙适配器,申请打开蓝牙

 private  BluetoothAdapter mBluetoothAdapter;
 
        // 判断手机硬件支持蓝牙
        if (!getPackageManager().hasSystemFeature( PackageManager.FEATURE_BLUETOOTH_LE))
        {
            Toast.makeText(this, "手机不支持BLE", Toast.LENGTH_SHORT).show();
            finish();//退出
        }
        
        // 获取手机本地的蓝牙适配器
        final BluetoothManager bluetoothManager = 
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
        // 打开蓝牙权限
        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled())
        {
            //弹出对话框,请求打开蓝牙
            startActivityForResult(new Intent(  BluetoothAdapter.ACTION_REQUEST_ENABLE), REQUEST_ENABLE_BT);
        }

3.扫描蓝牙设备

 mBluetoothAdapter.startLeScan(mLeScanCallback);//开始扫描
    mBluetoothAdapter.stopLeScan(mLeScanCallback);//停止扫描
 
    /**
     * 蓝牙扫描回调函数 回调蓝牙BluetoothDevice,可以获取name MAC rsss 广播等信息
     *
     * **/
    private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback()
    {
        @Override
        public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord)
        {
            // TODO 
            runOnUiThread(new Runnable()
            {
                @Override
                public void run()
                {
                    /* 这里将扫描到设备的信息输出到相应界面显示 */
                }
            });
        }
    };

必须注意的是,android5.0以上,使用BluetoothLeScanner进行扫描,以上函数已经不推荐了。

private BluetoothLeScanner bluetoothLeScanner;
 
bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); 
bluetoothLeScanner.startScan(scanCallback);
 
private ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult results) {
            super.onScanResult(callbackType, results);
            BluetoothDevice device = results.getDevice();
            //BluetoothDevice 包含了蓝牙设备的各种信息,比如名字,MAC,等等
            //可在此添加扫描的设备到显示界面      
	   }
};
//扫描需要一些时间,想停止可使用一下函数
bluetoothLeScanner.stopScan(scanCallback);

4.连接蓝牙

上面手机扫描到其他蓝牙设备(GAP协议),接下来就要建立连接,通讯(GATT协议)。

//蓝牙service,负责后台的蓝牙服务
private static BluetoothLeService mBluetoothLeService;
//蓝牙特征
private ArrayList<ArrayList<BluetoothGattCharacteristic>> mGattCharacteristics = 
new ArrayList<ArrayList<BluetoothGattCharacteristic>>();

蓝牙是通过Characteristic进行数据交互的,详细可百度相关知识点。

绑定服务

  /* 启动蓝牙service */
    Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
    bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
 
	/* BluetoothLeService绑定的回调函数 */
    private final ServiceConnection mServiceConnection = new ServiceConnection()
	{
		@Override
		public void onServiceConnected(ComponentName componentName,
									   IBinder service)
		{
			mBluetoothLeService = ((BluetoothLeService.LocalBinder) service)
					.getService();
			if (!mBluetoothLeService.initialize())
			{
				Log.e(TAG, "Unable to initialize Bluetooth");
				finish();
			}
			// 根据蓝牙地址,连接设备
			mBluetoothLeService.connect(mDeviceAddress);
		}
 
		@Override
		public void onServiceDisconnected(ComponentName componentName)
		{
			mBluetoothLeService = null;
		}
 
	};

5.处理蓝牙服务

 /**
	 * @Title: displayGattServices
	 * @Description: 处理蓝牙服务
	 * @param
	 * @return void
	 * @throws
	 */
	private void displayGattServices(List<BluetoothGattService> gattServices)
	{
		if (gattServices == null)
			return;
		String uuid = null;
		String unknownServiceString = "unknown_service";
		String unknownCharaString = "unknown_characteristic";
		// 服务数据,可扩展下拉列表的第一级数据
		ArrayList<HashMap<String, String>> gattServiceData = 
new ArrayList<HashMap<String, String>>();
		// 特征数据(隶属于某一级服务下面的特征值集合)
		ArrayList<ArrayList<HashMap<String, String>>> gattCharacteristicData = 
new ArrayList<ArrayList<HashMap<String, String>>>();
		// 部分层次,所有特征值集合
		mGattCharacteristics = new ArrayList<ArrayList<BluetoothGattCharacteristic>>();
		// Loops through available GATT Services.
		for (BluetoothGattService gattService : gattServices)
		{
			// 获取服务列表
			HashMap<String, String> currentServiceData = new HashMap<String, String>();
			uuid = gattService.getUuid().toString();
 
			// 查表,根据该uuid获取对应的服务名称。SampleGattAttributes这个表需要自定义。
			gattServiceData.add(currentServiceData);
			System.out.println("Service uuid:" + uuid);
			ArrayList<HashMap<String, String>> gattCharacteristicGroupData = 
new ArrayList<HashMap<String, String>>();
			// 从当前循环所指向的服务中读取特征值列表
			List<BluetoothGattCharacteristic> gattCharacteristics = gattService
					.getCharacteristics();
			ArrayList<BluetoothGattCharacteristic> charas = 
new ArrayList<BluetoothGattCharacteristic>();
			// Loops through available Characteristics.
			// 对于当前循环所指向的服务中的每一个特征值
			for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics)
			{
				charas.add(gattCharacteristic);
				HashMap<String, String> currentCharaData = new HashMap<String, String>();
				uuid = gattCharacteristic.getUuid().toString();
 
				if (gattCharacteristic.getUuid().toString()
						.equals(HEART_RATE_MEASUREMENT))
				{
					mhandler.postDelayed(new Runnable()
					{
						@Override
						public void run()
						{
							// TODO Auto-generated method stub
							mBluetoothLeService.readCharacteristic(gattCharacteristic);
						}
					}, 200);
 
					mBluetoothLeService.setCharacteristicNotification(
							gattCharacteristic, true);
					target_chara = gattCharacteristic;
				}
				List<BluetoothGattDescriptor> descriptors = gattCharacteristic
						.getDescriptors();
				for (BluetoothGattDescriptor descriptor : descriptors)
				{
					System.out.println("---descriptor UUID:"
							+ descriptor.getUuid());
					// 获取特征值的描述
					mBluetoothLeService.getCharacteristicDescriptor(descriptor);
				}
				gattCharacteristicGroupData.add(currentCharaData);
			}
			// 按先后顺序,分层次放入特征值集合中,只有特征值
			mGattCharacteristics.add(charas);
			// 构件第二级扩展列表(服务下面的特征值)
			gattCharacteristicData.add(gattCharacteristicGroupData);
		}
	}

当需要发送数据时,注意一次发送的数据是有限制的。

private static BluetoothGattCharacteristic cdata= null;
 
cdata.setValue(str);//str为需要发送的数据
//调用蓝牙服务的写特征值方法实现发送数据
mBluetoothLeService.writeCharacteristic(cdata);

最后定义一个广播接收器专门负责接收处理蓝牙服务。

private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        //...
    }
}

6.实际测试

使用蓝牙串口模块与电脑连接,打开PC串口助手。测试

1.jpg4.jpg2.jpg

电脑端可以正常接收。

3.jpg

这个电脑端的串口软件也是我用C#编写的。

我本来使用XCOM作为串口接收软件,不过XCOM接收是按照GB2312编码接收。

文章最下面.jpg

0条回复

作者
用户头像
文章 0关注 0粉丝 0
相关文章
联系客服