传统蓝牙配对连接,为何有些蓝牙模块只配对没连接上?
最近调试需求,针对性对某个无屏幕的设备编写了个蓝牙日志传输应用,也很简单,即使把log和log文件通过蓝牙传输到另一台设备查看,不多说,讲下蓝牙配对连接。直接上代码
public class BleLogMonitorAty extends FragmentActivity implements AdapterView.OnItemClickListener, View.OnClickListener {private static final boolean DEBUG = true; public static BleLogMonitorAty logMonitorAty; private static final String TAG = "BleLogMonitorAty"; private ArrayAdapter<String> devAdapter; private List<BluetoothDevice> devices = new ArrayList<>(); private List<BluetoothDevice> bondeDevices = new ArrayList<>(); private List<String> devNames = new ArrayList<>(); // private List<String> bondeDevNames = new ArrayList<>(); private BluetoothAdapter mBluetoothAdapter; private ProgressBar progressBar; // private ArrayAdapter<String> bonDevAdapter; private BluetoothDevice curDevice; private BleLogFragment logFragment; private DevAdapter bonDevAdapter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState); setContentView(R.layout.ble_layout); logMonitorAty = this; ActivityMger.addActivity(this); initView(); initBluetooth(); updateBondDevlist(); Intent intent = new Intent(this, LogService.class); startService(intent); bindService(intent, conn, Context.BIND_AUTO_CREATE); }private void updateBondDevlist() {bondeDevices.clear(); bondeDevices.addAll(mBluetoothAdapter.getBondedDevices()); bonDevAdapter.notifyDataSetChanged(); }private void initBluetooth() {mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); mBluetoothAdapter.enable(); //每搜索到一个设备就会发送一个该广播 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED); filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED); filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST); //配对请求广播 registerReceiver(receiver, filter); }private void discovery() {if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery(); }//开启搜索 mBluetoothAdapter.startDiscovery(); progressBar.setVisibility(View.VISIBLE); devNames.clear(); devices.clear(); }private void initView() {progressBar = findViewById(R.id.progressbar); findViewById(R.id.bt_search).setOnClickListener(this); ListView listView2 = findViewById(R.id.bondDev_list); ListView listView = findViewById(R.id.devices_list); devAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, devNames); listView.setAdapter(devAdapter); listView.setOnItemClickListener(this); bonDevAdapter = new DevAdapter(); // bonDevAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, bondeDevNames); listView2.setAdapter(bonDevAdapter); listView2.setOnItemClickListener(this); listView2.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {@Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {BluetoothDevice device = bondeDevices.get(position); if (device != null && device.getBondState() == 12 || device.getBondState() == 11) {showCancelBondeDialog(device); }return true; }}); }private void showCancelBondeDialog(final BluetoothDevice device) {AlertDialog.Builder builder = new AlertDialog.Builder(this).setMessage("取消配对?" + device.getName()).setNegativeButton("NO", null).setPositiveButton("YES", new DialogInterface.OnClickListener() {@Override public void onClick(DialogInterface dialog, int which) {try {boolean removeBond = ClsUtils.removeBond(device.getClass(), device); if (removeBond) {Toast.makeText(logService, "取消配对成功!", Toast.LENGTH_SHORT).show(); // discovery(); }} catch (Exception e) {e.printStackTrace(); }}}); builder.create().show(); }class DevAdapter extends BaseAdapter {@Override public int getCount() {return bondeDevices == null ? 0 : bondeDevices.size(); }@Override public BluetoothDevice getItem(int position) {return bondeDevices.get(position); }@Override public long getItemId(int position) {return position; }@Override public View getView(int position, View convertView, ViewGroup parent) {DevViewHolder dh = null; if (convertView == null) {convertView = getLayoutInflater().inflate(R.layout.dev_item, null); dh = new DevViewHolder(); dh.tv_name = convertView.findViewById(R.id.tv_name); dh.bt_cnnt = convertView.findViewById(R.id.btn_cnnt); convertView.setTag(dh); } else {dh = (DevViewHolder) convertView.getTag(); }BluetoothDevice device = getItem(position); dh.tv_name.setText(device.getName() + " " + device.getAddress() + " state:" + device.getBondState()); if (LogService.hasCnntAddr != null && LogService.hasCnntAddr.equals(device.getAddress())) {dh.bt_cnnt.setVisibility(View.VISIBLE); dh.bt_cnnt.setText("已连接"); dh.bt_cnnt.setOnClickListener(new View.OnClickListener() {@Override public void onClick(View v) {disConnectDev(); Toast.makeText(logService, "断开连接!", Toast.LENGTH_SHORT).show(); v.setVisibility(View.GONE); }}); }return convertView; }}static class DevViewHolder {TextView tv_name; Button bt_cnnt; }private final BroadcastReceiver receiver = new BroadcastReceiver() {@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)@Override public void onReceive(Context context, Intent intent) {if (DEBUG) Log.v(TAG, "ACTION:" + intent.getAction()); if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); Log.v(TAG, device.getName() + ":" + device.getAddress() + ",state:" + device.getBondState() + "," + device.getType()); if (device.getBondState() != BluetoothDevice.BOND_BONDED || device.getBondState() != BluetoothDevice.BOND_BONDING) {devNames.add(device.getName() + ":" + device.getAddress()); devices.add(device); devAdapter.notifyDataSetChanged(); }updateBondDevlist(); } else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(intent.getAction())) {//开始搜索 } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(intent.getAction())) {//已搜素完成 progressBar.setVisibility(View.GONE); } else if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) {Toast.makeText(context, "" + intent.getAction(), Toast.LENGTH_SHORT).show(); BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR); Log.v(TAG, "PAIRING type=" + type); //3 if (type == BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION || type == 4 || type == 5) {int pairingKey = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_KEY, BluetoothDevice.ERROR); Log.v(TAG, "pairingKey=" + pairingKey); }try {abortBroadcast(); // if (true) return; boolean pair = ClsUtils.setPin(device.getClass(), device, "1234"); //1.确认配对 ClsUtils.setPairingConfirmation(device.getClass(), device, true); if (DEBUG) Log.v(TAG, "pair=" + pair + ",state:" + device.getBondState()); } catch (Exception e) {e.printStackTrace(); }} else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(intent.getAction())) {int connectState = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE, -1); if (DEBUG) Log.v(TAG, "++++connectState=" + connectState); } else if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {if (DEBUG) Log.v(TAG, "++++ACTION_BOND_STATE_CHANGED"); final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); int state = device.getBondState(); if (DEBUG) Log.v(TAG, device.getName() + "+++++bond state:" + state); if (state == BluetoothDevice.BOND_BONDED) {if (Build.VERSION.SDK_INT < 23) {int deviceClass = device.getBluetoothClass().getDeviceClass(); int majorDeviceClass = device.getBluetoothClass().getMajorDeviceClass(); if (DEBUG) Log.v(TAG, "deviceClass=" + deviceClass); if (DEBUG)Log.v(TAG, "MajorDeviceClass=" + majorDeviceClass); if(deviceClass==1344&&majorDeviceClass==1280) // PERIPHERAL_KEYBOARD&&PERIPHERAL 外围设备 PROFILE_HID类型 3 cnntToInputDevice(device); }if (!containsThisDev(bondeDevices, device)) {bondeDevices.add(device); bonDevAdapter.notifyDataSetChanged(); }if (containsThisDev(devices, device)) {int i = devices.indexOf(device); devices.remove(device); devNames.remove(i); devAdapter.notifyDataSetChanged(); }mBluetoothAdapter.cancelDiscovery(); } else if (state == BluetoothDevice.BOND_NONE) {if (containsThisDev(bondeDevices, device)) {bondeDevices.remove(device); bonDevAdapter.notifyDataSetChanged(); }if (!containsThisDev(devices, device)) {devices.add(device); devNames.add(device.getName() + ":" + device.getAddress()); devAdapter.notifyDataSetChanged(); }}}}}; private void cnntToInputDevice(final BluetoothDevice device) {if (DEBUG) Log.v(TAG, "===cnntToInputDevice=="); final int INPUT_DEVICE = 4; // this is hidden memeber in BluetoothDevice // BluetoothAdapter.getDefaultAdapter().closeProfileProxy(); 调用此方法关闭代理服务 BluetoothAdapter.getDefaultAdapter().getProfileProxy(BleLogMonitorAty.this, new BluetoothProfile.ServiceListener() {@Override public void onServiceConnected(int profile, BluetoothProfile proxy) {Class<?> clazz = null; try {clazz = Class.forName("android.bluetooth.BluetoothInputDevice"); Object obj = clazz.cast(proxy); Method connectMethod = clazz.getDeclaredMethod("connect", BluetoothDevice.class); boolean resultCode = (boolean) connectMethod.invoke(obj, device); Method setPriority = clazz.getDeclaredMethod("setPriority", BluetoothDevice.class, int.class); setPriority.invoke(obj, device, 1000); if (DEBUG) Log.v(TAG, "cnntToInputDevice resultCode=" + resultCode); } catch (ClassNotFoundException e) {e.printStackTrace(); } catch (NoSuchMethodException e) {e.printStackTrace(); } catch (InvocationTargetException e) {e.printStackTrace(); } catch (IllegalAccessException e) {e.printStackTrace(); }}@Override public void onServiceDisconnected(int profile) {if (DEBUG) Log.d("wtf", "onservice disconnected " + profile); }}, INPUT_DEVICE); }private boolean containsThisDev(List<BluetoothDevice> deviceList, BluetoothDevice device) {Log.v(TAG, "containsThisDev deviceList=" + deviceList.size()); if (deviceList == null || deviceList.size() < 1) return false; for (int i = 0; i < deviceList.size(); i++) {if (deviceList.get(i).getAddress().equals(device.getAddress()))return true; }return false; }@RequiresApi(api = Build.VERSION_CODES.KITKAT)@Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) {switch (parent.getId()) {case R.id.devices_list:if (mBluetoothAdapter.isDiscovering())mBluetoothAdapter.cancelDiscovery(); curDevice = devices.get(position); try {boolean bond = ClsUtils.createBond(curDevice.getClass(), curDevice); if (bond) {Toast.makeText(logMonitorAty, "配对成功!", Toast.LENGTH_SHORT).show(); updateBondDevlist(); } else {Toast.makeText(logMonitorAty, "配对失败!", Toast.LENGTH_SHORT).show(); }} catch (Exception e) {e.printStackTrace(); }break; case R.id.bondDev_list:BluetoothDevice bondeDev = bondeDevices.get(position); if (logService != null) {if (LogService.hasCnntAddr != null && !bondeDev.getAddress().equals(LogService.hasCnntAddr)) {Toast.makeText(BleLogMonitorAty.this, "请先断开上一个设备", Toast.LENGTH_SHORT).show(); return; }logService.connectDev(bondeDev); }updateBondDevlist(); // logFragment = new BleLogFragment(); // getSupportFragmentManager().beginTransaction().add(R.id.framecontent, logFragment, "LOG_FRAGMENT").addToBackStack("LF").commit(); break; }}@Override protected void onDestroy() {super.onDestroy(); logMonitorAty = null; ActivityMger.removeActivity(this); if (DEBUG) Log.v(TAG, "==onDestroy"); unregisterReceiver(receiver); unbindService(conn); }private LogService logService; public ServiceConnection conn = new ServiceConnection() {@Override public void onServiceConnected(ComponentName name, IBinder service) {logService = ((LogService.MyBinder) service).getService(); logService.setDeviceCallback(new LogService.DeviceCallback() {@Override public void connect(BluetoothDevice remote) {if (DEBUG) Log.v(TAG, "Dev connect ..." + LogService.hasCnntAddr); recLog("Dev connect ..."); runOnUiThread(new Runnable() {@Override public void run() {updateBondDevlist(); logFragment = new BleLogFragment(); getSupportFragmentManager().beginTransaction().add(R.id.framecontent, logFragment, "LOG_FRAGMENT").addToBackStack("LF").commit(); }}); }@Override public void disConnect(BluetoothDevice remote) {if (DEBUG) Log.v(TAG, "Dev disConnect ..."); recLog("Dev disConnect ..."); }@Override public void recLog(final String log) {runOnUiThread(new Runnable() {@Override public void run() {if (logFragment != null)logFragment.recLog(log); }}); }}); }@Override public void onServiceDisconnected(ComponentName name) {}}; public void disConnectDev() {if (logService != null)logService.disConnectDev(); }@Override public void onClick(View v) {switch (v.getId()) {case R.id.bt_search:if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery(); ((Button) v).setText("搜索设备"); } else {discovery(); ((Button) v).setText("停止搜索"); }break; default:break; }}
蓝牙配对流程
1.搜索蓝牙 使用api startDiscovery;
2.绑定使用工具类 ClsUtils的createBond,这个在网上都能找到
boolean bond = ClsUtils.createBond(curDevice.getClass(), curDevice); if (bond) {Toast.makeText(logMonitorAty, "配对成功!", Toast.LENGTH_SHORT).show(); updateBondDevlist(); } else {Toast.makeText(logMonitorAty, "配对失败!", Toast.LENGTH_SHORT).show(); }
我测试用的是一个蓝牙手柄,用于拍照的,类型属于 profile HID,一般输入类型的都是使用这种接口协议,类似蓝牙键盘,游戏手柄,参考博客https://blog.csdn.net/ZBJDSBJ/article/details/47123595
但是我遇到一个情况,就是直接使用绑定createBond的反射方法执行绑定,在MTK6.0上(其他品牌设备6.0没测)可以直接配对并且连接上蓝牙手柄,而5.1上就只能绑定蓝牙手柄而已,没有连接上,就不能对设备进行输入操作,必须还得使用蓝牙Profile ,通过BluetoothAdapter.getDefaultAdapter().getProfileProxy进行连接,但是这种类似蓝牙手柄属于输入蓝牙类型,就是INPUT_DEVICE = 4 ,从BluetoothProfile可以找到,发现是hide类型的,而且还需要用的一个BluetoothInputDevice类,也是个系统hide类型,感谢国外溢出论坛的大佬们,https://stackoverflow.com/questions/27504900/android-bluetooth-paring-input-device ,通过反射得到BluetoothInputDevice并进行连接
private void cnntToInputDevice(final BluetoothDevice device) {if (DEBUG) Log.v(TAG, "===cnntToInputDevice=="); final int INPUT_DEVICE = 4; // this is hidden memeber in BluetoothDevice // BluetoothAdapter.getDefaultAdapter().closeProfileProxy(); 调用此方法关闭代理服务 BluetoothAdapter.getDefaultAdapter().getProfileProxy(BleLogMonitorAty.this, new BluetoothProfile.ServiceListener() {@Override public void onServiceConnected(int profile, BluetoothProfile proxy) {Class<?> clazz = null; try {clazz = Class.forName("android.bluetooth.BluetoothInputDevice"); Object obj = clazz.cast(proxy); Method connectMethod = clazz.getDeclaredMethod("connect", BluetoothDevice.class); boolean resultCode = (boolean) connectMethod.invoke(obj, device); Method setPriority = clazz.getDeclaredMethod("setPriority", BluetoothDevice.class, int.class); setPriority.invoke(obj, device, 1000); if (DEBUG) Log.v(TAG, "cnntToInputDevice resultCode=" + resultCode); } catch (ClassNotFoundException e) {e.printStackTrace(); } catch (NoSuchMethodException e) {e.printStackTrace(); } catch (InvocationTargetException e) {e.printStackTrace(); } catch (IllegalAccessException e) {e.printStackTrace(); }}
还有值得一提的是,当设备收到蓝牙手柄的主动配对请求是,会收到广播BluetoothDevice.ACTION_PAIRING_REQUEST
此时我们可以监听此广播,想要实现自动配对的话就调用以下两句代码就可以了
boolean pair = ClsUtils.setPin(device.getClass(), device, "1234"); //1.确认配对 ClsUtils.setPairingConfirmation(device.getClass(), device, true); if (DEBUG) Log.v(TAG, "pair=" + pair + ",state:" + device.getBondState());
以上博客简单描述,只为了以后记住这些知识点,同时帮助那些还在为经典蓝牙配对有疑问的童鞋,附上ClsUtils代码
public class ClsUtils {/** * 与设备配对 参考源码:platform/packages/apps/Settings.git * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java */ static public boolean createBond(Class btClass, BluetoothDevice btDevice) throws Exception {Method createBondMethod = btClass.getMethod("createBond"); Boolean returnValue = (Boolean) createBondMethod.invoke(btDevice); return returnValue.booleanValue(); }/** * 与设备解除配对 参考源码:platform/packages/apps/Settings.git * /Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java */ static public boolean removeBond(Class<?> btClass, BluetoothDevice btDevice) throws Exception {Method removeBondMethod = btClass.getMethod("removeBond"); Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice); return returnValue.booleanValue(); }static public boolean setPin(Class<? extends BluetoothDevice> btClass, BluetoothDevice btDevice, String str) throws Exception {try {Method removeBondMethod = btClass.getDeclaredMethod("setPin", new Class[]{byte[].class}); Boolean returnValue = (Boolean) removeBondMethod.invoke(btDevice, new Object[]{str.getBytes()}); Log.e("returnValue", "" + returnValue); } catch (SecurityException e) {// throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (IllegalArgumentException e) {// throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (Exception e) {// TODO Auto-generated catch block e.printStackTrace(); }return true; }// 取消用户输入 static public boolean cancelPairingUserInput(Class<?> btClass, BluetoothDevice device) throws Exception {Method createBondMethod = btClass.getMethod("cancelPairingUserInput"); // cancelBondProcess(btClass, device); Boolean returnValue = (Boolean) createBondMethod.invoke(device); return returnValue.booleanValue(); }// 取消配对 static public boolean cancelBondProcess(Class<?> btClass, BluetoothDevice device) throws Exception {Method createBondMethod = btClass.getMethod("cancelBondProcess"); Boolean returnValue = (Boolean) createBondMethod.invoke(device); return returnValue.booleanValue(); }//确认配对 static public void setPairingConfirmation(Class<?> btClass, BluetoothDevice device, boolean isConfirm) throws Exception {Method setPairingConfirmation = btClass.getDeclaredMethod("setPairingConfirmation", boolean.class); setPairingConfirmation.invoke(device, isConfirm); }/** * * @param clsShow */ static public void printAllInform(Class clsShow) {try {// 取得所有方法 Method[] hideMethod = clsShow.getMethods(); int i = 0; for (; i < hideMethod.length; i++) {Log.e("method name", hideMethod[i].getName() + ";and the i is:"+ i); }// 取得所有常量 Field[] allFields = clsShow.getFields(); for (i = 0; i < allFields.length; i++) {Log.e("Field name", allFields[i].getName()); }} catch (SecurityException e) {// throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (IllegalArgumentException e) {// throw new RuntimeException(e.getMessage()); e.printStackTrace(); } catch (Exception e) {// TODO Auto-generated catch block e.printStackTrace(); }} }
忘记还有个蓝牙连接,以上针对蓝牙手柄,配对就自动连接了,对应其他的蓝牙设备模块,还得主动连接
1.先定义好UUID
2.BluetoothSocket socket=remote.createRfcommSocketToServiceRecord(定义的uuid);
3.socket.connect(), socket.getInputstream()获取流来读取对端设备发来的数据
4.当然对端设备需要mBluetoothAdapter.listenUsingRfcommWithServiceRecord (uuid)来监听连接接入,使用同一个UUID即可
传统蓝牙配对连接,为何有些蓝牙模块只配对没连接上?相关推荐
- 电脑无线不显示宽带不能连接服务器,电脑上网为什么只显示宽带连接不显示无线网络连接?...
近日有关于电脑上网时为什么只显示宽带连接不显示无线网络连接的问题受到了很多网友们的关注,大多数网友都想要知道电脑上网时为什么只显示宽带连接不显示无线网络连接的具体情况,那么关于到电脑上网时为什么只显示 ...
- 当esp32连接到蓝牙或者wife时,连接引脚后一些模块(光敏电阻,传感器之类)读不出模拟值的解决方法
我是连接onenet平台上传光敏电阻的模拟值,当连接wife后用analogRead()函数读出来的全是0或者全是4095(就是没有数值变化) 模拟值一直为0的原因:ESP32芯片中有ADC1和ADC ...
- win10台式机 更换蓝牙模块后配对过的蓝牙设备无法连接 且删除失败解决方法
解决win10 之前配对后的蓝牙设备连接不了 并且无法删除的解决办法 事件描述:我的台式机更换蓝牙设备后之前连接后的蓝牙设备都无法连接,并且删除不了 第一种解决方案 打开设备管理器 点击查看 点击显示 ...
- 20220727使用汇承科技的蓝牙模块HC-05配对手机进行蓝牙串口的演示
20220727使用汇承科技的蓝牙模块HC-05配对手机进行蓝牙串口的演示 2022/7/27 18:55 Android11:摩托罗拉 motorola edge s 6GB+128GB 骁龙870 ...
- 20220728使用电脑上的蓝牙和汇承科技的蓝牙模块HC-05配对蓝牙串口传输
20220728使用电脑上的蓝牙和汇承科技的蓝牙模块HC-05配对蓝牙串口传输 2022/7/28 11:27 电脑:DELL Vostro 3888,WIN10系统 五.蓝牙模块如何与电脑连接(从模 ...
- HC-06(ZS-040)蓝牙模块的配置与连接
HC-06(ZS-040.BT04-A)蓝牙模块的配置与连接 简介 引脚说明 AT模式 简介 进入AT模式的方法(无按键) AT常用指令集 手机连接方法 简介 HC06模块是一款高性能从机蓝牙2.0串 ...
- Android开发-连接开发板蓝牙模块发送和接收数据
帮同学写一个连接小车蓝牙模块遥控小车的APP,在网上搜阅了很多资料,大概了解了蓝牙的工作原理,再经历了种种BUG后终于是成功连上了小车蓝牙,并可以发送数据,小车可以接收到,测试的蓝牙是Arduino小 ...
- HC-05蓝牙模块主从配对设置步骤记录
1.主从配置串口调试图片 图1 HC-05配对主机相关命令 图2 HC-05配对从机相关命令 2.主机设置步骤说明 准备两个USB转TTL的串口调试器,连接蓝牙和串口调试器,按住蓝牙模块 ...
- 单片机蓝牙烧录_蓝牙模块与单片机如何连接?
蓝牙模块与单片机如何连接? 首先我们来看看蓝牙模块 蓝牙模块HC-05: TX连接单片机P3.0口,RX连接单片机P3.1口. 在蓝牙模块连接到单片机上前,首先通过USB-TTL转接器,连接到电脑上后 ...
最新文章
- 百度地图,加载顺序异步问题,用定时器解决
- formal method
- cocos2d-x游戏开发(二)开始菜单续
- 使用结构化的标头字段改善HTTP
- 【详解】某企业的培训关系模式 R(培训科目,培训师,学生,成绩,时间,教室), R的函数依赖集 F={培训科目→→培训师,(学生,培训科目)→成绩,(时间,教室)→培训科目,(时间,培训师)→
- java split()方法_Java编程性能优化一些事儿
- w3wp oracle,w3wp.exe占用CPU超过50%的处理
- C语言中函数调用中静态变量的应用
- 基于51单片机的交通灯原理图加代码
- Blender - 武器icon贴图渲染 阴影角度
- 【应用安全】垃圾短信电话不断?手机变卡变慢?可能是共享充电宝的锅……
- 云流化技术应用之K12VR云课堂
- 苹果手机使用计算机网络,苹果安卓手机使用usb共享网络给win10电脑的操作方法...
- TMUX Cheat Table:和那些妖艳贱货不一样的 TMUX 教程
- 基于NLM的插值算法
- Htc vive Unity 新教程
- Windows自定义开关机的音乐
- Bias Variance Tradeoff
- 现在计算机有64位吗,任何电脑都可以装64位系统吗|是不是所有的电脑都可以装64位系统...
- 数据归一化(详解,含代码实现)
热门文章
- 硬件第1城:光猫GE和FE的区别
- msvc和mingw混编
- 有1000枚硬币,其中有10枚是金币,从中取出n枚硬币,求这n枚硬币中有金币的概率。答案保留6位小数
- 编程n的阶乘使用while语句_数控宏程序编程----学习笔记
- adams样条驱动_[转载]Adams之样条函数的应用
- PMAC PDK开发Key相关事项
- python高并发对比java_Java和Python哪个前景更好点呢?
- TensorFlow使用Python自定义op和损失函数
- 10万引大佬分享「写论文10大技巧」,连怎么沟通审稿人都提到了 | 科研党福利...
- 【前端】select标签选择多个option--扩展字段长度,实现换行