文档库 最新最全的文档下载
当前位置:文档库 › 在Windows mobile 6模拟器中实现蓝牙数据采集

在Windows mobile 6模拟器中实现蓝牙数据采集

本文由changesway贡献
pdf文档可能在WAP端浏览体验不佳。建议您优先选择TXT,或下载源文件到本机查看。
在 Windows mobile 6.0 模拟器中实现蓝牙数据采集 一、Windows mobile 6.0 中蓝牙驱动的加载
大家知道,Windows Mobile 6.0 SDK 自带了 cellular emulator 和 fake GPS,使 得我们可以在模拟器上调试 radio 级的 phone call 和基于 GPS 的地理位置应用。 我们来看看实现Bluetooth的架构,参考下图(来源于 Bluetooth for Microsoft Device Emulator),主要包括emulator端和PC端:
1.1 软硬件条件
1. Emulator 端
Bluetooth HCI Transport Driver Serial Port Driver
Microsoft Remote Tools Framework remote agent 2. PC 端 Microsoft Remote Tools Framework desktop plugin FreeBT USB Driver runtime
Driver Connected Bluetooth USB device 注意:作者采用了FreeBT这个开源的工程来控制Bluetooth的接入。 在 Windows Mobile 模拟器上使用蓝牙的必要条件有: 1. Visual studio 2005 with SP1 或者 Visual studio 2008 2. Windows Mobile 5.0 Pocket PC/Smartphone SDK and/or Windows Mobile 6 Standard/Professional SDK emulator images 3. Device Emulator 3.0 4. Microsoft Remote Tools Framework 1.00 5. 一个具有 USB 接口的 Bluetooth dongle
FreeBT USB
1.2 模拟环境搭建 (一)安装 FreeBT 蓝牙驱动
在Windows Mobile模拟器上使用蓝牙,即在PC端安装下载的FreeBT的蓝牙驱 动,方法自然是通过“windows设备管理器” ,为新的硬件设备(也就是连接的 Bluetooth USB device)添加下载过来的驱动(主要是找到fbtusb.inf文件) 。具体 如下: 1、打开 Windows 设备管理器。 2、在设备管理器,找到蓝牙设备将设备用作 FreeBT USB 接口。 3、点击鼠标右键并选择“更新驱动程序……”在弹出的菜单。 4、选择“否,暂时不”,然后点击“下一步>”。 5、选择“安装从列表或指定位置”,然后点击“下一步>”。 6、选择“不要搜索。我将选择要安装的驱动”,然后点击“下一步>”。 7、选择设备驱动程序,然后点击“从磁盘安装…… ”. 8、在查找文件对话框中,浏览到 fbtusb.inf 文件,然后点击“下一步>”。 9、当一个“硬件安装警告”出现后,点击“仍然继续”。 10、一旦安装完毕后,点击“完成”。 11、设备管理器现在应显示“FreeBT USB 驱动”在名单的 USB 控制器。
(二)安装加载 Bluetooth for Microsoft Device Emulator
1、安装 FreeBT USB 驱动中描述了蓝牙 USB 驱动安装部分。 2、安装要求如描述的安装步骤。 3、 在 Remote Tools Framework plugin 中运行 BthEmulManager.cetool,将其 和模拟器建立连接。 4、从列表中选择一个仿真图像。 5、等待模拟器连接。 6、选择“Bluetooth for Microsoft Device Emulator”节点。 7、如果你有一个蓝牙设备连接成功,那

么蓝牙设备信息(地址,制造商, 人机交互版本和 LMP 版本)将被显示。现在,蓝牙应该运行在你的模拟器上。
如果有一个错误代码,则将被显示。如图 9 所示。
8、要清除通讯记录,点击鼠标右键,选择“清除”。 9、当前设备信息复制到剪贴板,选择“蓝牙为微软装置模拟器"节点,点击 鼠标右键,选择“拷贝到剪贴板” 。 10、关掉蓝牙的模拟器,点击“连接”菜单,选择“脱离…模拟器” 。 11、 微软远程工具结构允许你在同一时间启动两个装置模拟器。如果您已经 安装了两个或两个以上 FreeBT USB 设备, 点击“窗口”菜单并选择“切分窗口查看”。
重复步骤 3-6。你将得到两个同时运行的蓝牙驱动仿真器。 12、很可能要启用/禁用设备端日志记录。如果您启用“设备日志记录”复选 框,然后将启用远程登录在模拟器上。关注\ \ Temp 的模拟器目录。应该有建立 btd_bthemul_0.txt,btd_BthEmulAgent_0.txt,btd_bthemulcom_0.txt 文件。 13、很可能要启用/禁用桌面端日志记录。如果您启用“桌面日志记录”复选 框, 那么就将启用本地记录。 查看你的安装目录, 应该有建立 BthEmulManager.txt 文件。 14、很可能要启用/禁用通讯记录。通讯记录可以看到仿真器和蓝牙设备之 间的通信活动。
(三)连通测试
连接建立以后,蓝牙设备的信息(Address, Manufacturer, HCI Version, LMP Version)就会显示在界面上。 在程序启动后,首先搜索附近的蓝牙设备,搜索过程完成以后,将其设备的 名字和蓝牙地址显示在下拉列表中,然后就可以进行双向的消息发送和接收了。 程序运行界面如下图 10 所示: 需要注意的是,在设备蓝牙的时候,如果没有将“对其他设备可见”选项打 上勾,即只是将蓝牙打开,如下图所示。 可能无法正常通信,应用程序会提示无法发送消息。选中“对其他设备可见” 之后,就能够正常通信了,如下图 12 所示: 在蓝牙配对中,当 Windows Mobile 找到了蓝牙设备金瓯,金瓯设置的蓝牙 连接密码是 1234。如图 13 所示。
成功后,选择打开蓝牙时不会出错
正在搜索设备过程中
搜索完成
建立连接过程中要求输入连接密码
选择蓝牙服务——串口连接服务
创建成功 COM 端口
二、Bluetooth 操作的软件实现
由于蓝牙无线协议在手机中的应用较为广泛, 因此, 无论是 Windows Mobile SDK,还是其他第三方商业或开源软件组织,都对蓝牙程序设计有较好的支持。
如 著 名 的 OpenNETCF , 在 其 早 期 的 版 本 中 就 提 供 了 OpenNETCF.Bluetooth.WidComm 库 , 而 微 软 则 有 官 方 版 本 的 Microsoft Bluetooth Stack 提供,目前,比较流行的库有 32feet.ne

t。三方的地址 列表如下: 1. https://www.wendangku.net/doc/a68847182.html,项目(即 https://www.wendangku.net/doc/a68847182.html,) 2. OpenNETCF项目 在.NET Compact Framework 下进行 Bluetooth 开发有几个可选解决方案 ? 可以 P/Invoke 直接调用 Bluetooth 的 API(btdrt.dll) ? 使用 MS 的 Windows Embedded Source Tools for Bluetooth ? 使用 https://www.wendangku.net/doc/a68847182.html, 库 而这些库里, 对蓝牙串口服务的支持均存在一定的缺陷,如 https://www.wendangku.net/doc/a68847182.html, 的作 者甚至声称其中建立串口连接的代码是不安全的。这个问题在模拟器下更显突 出,原因是模拟器下,对串口的支持仅是从 COM0~COM2,而在使用 SDK 中列 举时,得到的结果却是 COM0~COM10,这样,如果随机选择了大于 COM2 的虚 拟端口,程序便会报错。而这个问题,在手动创建蓝牙虚拟串口服务时也会不时 发生。由于暂时没有真实的 Mobile 设备进行测试,不能完全证明,是由于模拟 器的问题还是 SDK 使用不当的问题,留待购置了 Mobile 设备后再来研究。 OpenNETCF 的新版本中,不知何故去除了 WidComm 的包,但仍有网友在其 源代码上进行部分的改造利用, 下文就针对上面所列的两种库的使用进行简要的 说明。
2.1 利用 https://www.wendangku.net/doc/a68847182.html, 实现 Windows Mobile 上的蓝牙数据传输
(一)https://www.wendangku.net/doc/a68847182.html, 简介
https://www.wendangku.net/doc/a68847182.html, 是由 InTheHand 公司所属的一个开源项目组织, 专门针对基于.NET 平台的无线数据传输(如蓝牙,红外等)提供技术支持。目 前已经发布的组件有: ? Bluetooth(蓝牙) ? IrDA(红外) ? ObjectExchange(OBEX 文件交换) 对蓝牙的支持需要设备兼容 Microsoft Bluetooth 协议栈。https://www.wendangku.net/doc/a68847182.html,4.2 或 XP 以
上的操作系统。
(二)https://www.wendangku.net/doc/a68847182.html, 类库结构 表 1:InTheHand 类库结构 名字空间 InTheHand 描述 The InTheHand namespace contains
classes for working with the Uri class for personal area networks. The https://www.wendangku.net/doc/a68847182.html, namespace contains classes for working with addressing on personal area networks. The https://www.wendangku.net/doc/a68847182.html,.Bluetooth namespace contains classes for working with Bluetooth functionality such as Radio hardware.
https://www.wendangku.net/doc/a68847182.html,
https://www.wendangku.net/doc/a68847182.html,.Bluetooth
The https://www.wendangku.net/doc/a68847182.html,.Bluetooth.AttributeIds https://www.wendangku.net/doc/a68847182.html,.Bluetooth.AttributeIds namespace contains definitions of Service Discovery Protocol attributes. The https://www.wendangku.net/doc/a68847182.html,.IrDA namespace contains classes for working with Infrared functionality. The https://www.wendangku.net/doc/a68847182.html,.Mime namespace holds types that are used to represent Multipurpose Internet Mail Exchange (MIME) headers The https://www.wendangku.net/doc/a68847182.html,.Ports namespace contains classes for working with legacy virtual COM ports over Bluetooth. The https://www.wendangku.net/doc/a68847182.html,.Sockets namespace provides added functionality for working with IrDA and Bluetooth Sockets. The InTheHand.Windows.Forms namespace contains forms related to networking functionality.
https://www.wendangku.net/doc/a68847182.html,.IrDA
https://www.wendangku.net/doc/a68847182.html,.Mime
https://www.wendangku.net/doc/a68847182.html,.Ports
https://www.wendangku.net/doc/a68847182.html,.Sockets
In

TheHand.Windows.Forms
现仅列举 https://www.wendangku.net/doc/a68847182.html, 中的 Buletooth 及 Sockets 名字空间,以供参考。 表 2:https://www.wendangku.net/doc/a68847182.html,.Bluetooth 名字空间 类 AttributeIdLookup 描述 Retrieves the name of the SDP Attribute
ID with the given value in the specified Attribute ID class sets. Implementing Enum-like behaviour. Configures what type of element will be added by the ServiceRecordBuilder for the ProtocolDescriptorList attribute. Represents a Bluetooth Radio device. Handles security between bluetooth devices. Standard Bluetooth Profile identifiers. Provides Bluetooth authentication services on desktop Windows.
BluetoothProtocolDescriptorType
BluetoothRadio BluetoothSecurity BluetoothService BluetoothWin32Authentication
Provides data for an authentication BluetoothWin32AuthenticationEventArgs event. Describes the device capabilities of a device. and service
ClassOfDevice
DeviceClass
Class of Device flags as assigned in the Bluetooth specifications. Represents the types that an SDP element can hold. Represents the type of the element in the SDP record binary format, and is stored as the higher 5 bits of the header byte. Specifies the current status of the Bluetooth hardware. Represents a member of the SDP LanguageBaseAttributeIdList, Attribute which provides for
ElementType
ElementTypeDescriptor
HardwareStatus
LanguageBaseItem
multi-language strings in a record. LinkPolicy Manufacturer Flags to describe Link Policy. Manufacturer codes. Gets a list of enum-like classes containing SDP Service Attribute Id definitions for a particular Service Class. Determine all the possible modes of operation of the Bluetooth radio. Holds an attribute from an SDP service record. A Service Attribute Id identifies each attribute within an SDP service record.
MapServiceClassToAttributeIdList
RadioMode
ServiceAttribute
ServiceAttributeId ServiceClass ServiceElement ServiceRecord
Holds an SDP data element. Holds an SDP service record. Provides a simple way to build a ServiceRecord, including ServiceClassIds and ServiceNames attributes etc. Creates a Service Record byte array from the given ServiceRecord object. Some useful methods for working with a SDP ServiceRecord including creating and accessing the ProtocolDescriptorList for an RFCOMM service. Parses an array of bytes into the contained SDP ServiceRecord. Utilities method working on
ServiceRecordBuilder
ServiceRecordCreator
ServiceRecordHelper
ServiceRecordParser ServiceRecordUtilities
SDP ServiceRecords, for instance to produce a 'dump' of the record's contents. Represents the size of the SDP element in the record binary format, and is stored as the lower 3 bits of the header byte. Indicates that the field to which it is applied represents an SDP Attribute that can exist in multiple language instances and thus has a language base offset applied to its numerical ID when added to a record.
SizeInd

ex
StringWithLanguageBaseAttribute
表 3: https://www.wendangku.net/doc/a68847182.html,.Sockets 名字空间 Type
AddressFamily32
Description
Specifies additional addressing schemes that an instance of the Socket class can use. Provides client connections for Bluetooth network services. Provides information about an available device obtained by the client during device discovery. Listens for connections from Bluetooth network clients. Specifies additional protocols that the Socket class supports. Defines additional Bluetooth socket option levels for the SetSocketOption(SocketOptionLevel, SocketOptionName, Int32) and GetSocketOption(SocketOptionLevel, SocketOptionName) methods. Defines Socket configuration option names for the Socket class. Describes the character sets supported by the device. Makes connections to services on peer IrDA devices.
BluetoothClient
BluetoothDeviceInfo
BluetoothListener BluetoothProtocolType
BluetoothSocketOptionLevel
BluetoothSocketOptionName
IrDACharacterSet IrDAClient
IrDADeviceInfo
Provides information about remote devices connected by infrared communications. Describes an enumeration of possible device types, such as Fax. Places a socket in a listening state to monitor infrared connections from a specified service or network address. Defines additional IrDA socket option levels for the SetSocketOption(SocketOptionLevel, SocketOptionName, Int32) and GetSocketOption(SocketOptionLevel, SocketOptionName) methods. Socket option constants to set IrDA specific connection modes, and get/set IrDA specific features.
IrDAHints
IrDAListener
IrDASocketOptionLevel
IrDASocketOptionName
2.2 基于 https://www.wendangku.net/doc/a68847182.html, 的蓝牙程序设计
Bluetooth 的应用十分广泛,基于 Bluetooth 的通信程序开发主要有以下几个 步骤: 1. 服务端 ? 设置本设备为可发现。 ? 公开服务给其他 Bluetooth 设备访问。 ? 接受其他 Bluetooth 设备的链接。 ? 与链接上的 Bluetooth 设备进行通信。 2. 客户端 ? 发现周边 Bluetooth 设备。 ? 主动与被发现的设备发起连接。 ? 与链接上的 Bluetooth 设备进行通信。 (一) 蓝牙功能设置 (1)服务端 开启蓝牙
public static void DisplayBluetoothRadio() { BluetoothRadio myRadio = BluetoothRadio.PrimaryRadio; if (myRadio == null) {
WriteMessage("No radio hardware or unsupported software stack"); return; } // Enable discoverable mode myRadio.Mode = RadioMode.Discoverable; }
开启服务
private static void StartService() { BluetoothListener listener = new BluetoothListener(BluetoothService.SerialPort); listener.Start(); WriteMessage("Service started!"); BluetoothClient client = listener.AcceptBluetoothClient(); WriteMessage("Got a request!"); Stream peerStream = client.GetStream(); string dataToSend = "Hello from service!"; // Convert dataToSend into a byte array byte[] dataBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(dataToSend); // Outpu

t data to stream peerStream.Write(dataBuffer, 0, dataBuffer.Length); byte[] buffer = new byte[2000]; while (true) { if (peerStream.CanRead) { peerStream.Read(buffer, 0, 50); string data = System.Text.ASCIIEncoding.ASCII.GetString(buffer, 0, 50); WriteMessage("Receiving data: " + data); } } }
DisplayBluetoothRadio 用来展现本端设备的信息, 以及把本端 bluetooth 设备 设置为可发现。如果使用 https://www.wendangku.net/doc/a68847182.html, 2.3,也就是当前最新的 release 版本,wince 不支持读取和设置 radio mode。 服务端的侦听 BluetoothListener 还是使用 winsock 实现和 Windows Embedded Source Tools for Bluetooth 的实现类似。
(2)客户端
private static void ConnectService() { BluetoothClient client = new BluetoothClient(); BluetoothDeviceInfo[] devices = client.DiscoverDevices(); BluetoothDeviceInfo device = null; foreach (BluetoothDeviceInfo d in devices) { if (d.DeviceName == "BLUETOOTH_DEVICE") { device = d; break; } } if (device != null) { WriteMessage(String.Format("Name:{0} Address:{1:C}", device.DeviceName, device.DeviceAddress)); client.Connect(device.DeviceAddress, BluetoothService.SerialPort); Stream peerStream = client.GetStream(); // Create storage for receiving data byte[] buffer = new byte[2000]; // Read Data peerStream.Read(buffer, 0, 50); // Convert Data to String string data = System.Text.ASCIIEncoding.ASCII.GetString(buffer, 0, 50); WriteMessage("Receiving data: " + data); int i = 0; while (true) { WriteMessage("Writing: " + i.ToString()); byte[] dataBuffer = System.Text.ASCIIEncoding.ASCII.GetBytes(i.ToString()); peerStream.Write(dataBuffer, 0, dataBuffer.Length); ++i; if (i >= int.MaxValue) { i = 0; } System.Threading.Thread.Sleep(500); }
// Close network stream peerStream.Close(); } }
https://www.wendangku.net/doc/a68847182.html, 2.3 提供了自发现功能,通过 client.DiscoverDevices()寻找附近的 bluetooth 设备。在上述例子中指定连接名字为"BLUETOOTH_DEVICE"的设备。 Winsock 通 信 和 Windows Embedded Source Tools for Bluetooth 类 似 。 client.Connect(device.DeviceAddress, BluetoothService.SerialPort)用于连接名字为 "BLUETOOTH_DEVICE"的设备,同样指定串口服务。传输的数据为字节流(byte[]), 因此可以传输任意类型的数据。 客户端在接收回应信息后,不断的往服务端发送 数据。 (二) 蓝牙配对 Connect() 函数的第二个参数是服务类型,十分重要,通信双方必须使用同 样的服务类型。 如果通信双方的程序都是由我们负责开发,可以使用通用的服务 类型,例如 BluetoothService.SerialPort。但是如果要与第三方设备进行通信,需 要查出该设备的服务类型,在设备端的通信服务类型一般编写在 Firmware(固件) 里 面 , 而 且 会 按 照 规 范 编 写 , 例 如 Bluetooth 耳 机 会 使 用 BluetoothService.Handsfree。
try { BluetoothAddress deviceAddress = deviceAddresses[listBoxDevices.SelectedItem.ToString()]; client.SetPin(d

eviceAddress, textBoxPin.Text.Trim()); //client.Connect(deviceAddress, BluetoothService.Handsfree); //if connect ot Hands free. client.Connect(deviceAddress, BluetoothService.SerialPort); //if connect to cell phone and so forth. MessageBox.Show("Pair successful."); //transfer data.. } catch (Exception ex) { MessageBox.Show(ex.Message); }
SetPin()的功能是设置连接密码的,其函数原型如下:
[DllImport("btdrt.dll", SetLastError=true)] public static extern int BthSetPIN(byte[] pba, int cPinLength, byte[] ppin);
(三) 虚拟串口 所谓 Bluetooth Virtual Serial Port,其实是从软件的角度看,把 Bluetooth 的 通信转化成 Serial Port(串口)。经过这样的转换后,使用 Bluetooth 的 Client 程 序可以像使用串口一样操作 Bluetooth。这个应用方式的出现是为了支持现有应 用(Legacy system,遗产应用)。举个例子,在 Bluetooth 出现以前,大部分移动 设备都是通过串口连接的 GPS receiver 的,基于 GPS 应用程序的开发也就通过的 串口通信取出 NMEA data。 所谓 Bluetooth Virtual Serial Port,其实是从软件的角度看,把 Bluetooth 的 通信转化成 Serial Port(串口)。经过这样的转换后,使用 Bluetooth 的 Client 程 序可以像使用串口一样操作 Bluetooth。这个应用方式的出现是为了支持现有应 用(Legacy system,遗产应用)。举个例子,在 Bluetooth 出现以前,大部分移动 设备都是通过串口连接的 GPS receiver 的,基于 GPS 应用程序的开发也就通过的 串口通信取出 NMEA data。随着 Bluetooth 的普及,移动设备可以通过 Bluetooth 来连接 GPS receiver 了,那么原先基于 GPS 的应用程序需要重新开发通信部分去 读取 NMEA data,这为现有应用带来很多麻烦,所有的现有应用都需要重写通信 部分,因此人们想出解决方法,把 Bluetooth 的通信转化成 Serial Port(串口)。 硬件上使用 Bluetooth 来进行通信,在软件上虚拟一个串口给应用程序,应用程 序不需要任何的修改就可以支持 Bluetooth 的 GPS Receiver 了。这就像设计模式 里面的 Adapter 模式,但是这里是为新设备提供原有的接口,使得原先的 Client 不需要更改。 由于 Bluetooth Virtual Serial Port 的出现基于对现有系统(Legacy System)支持 的需求,所以对于新的系统,MS 不推荐使用 Bluetooth Virtual Serial Port,而是 直接使用 Winsock 进行通信。 在使用 Winsock 进行 Bluetooth 通信需要指定服务, 因此可以指定使用串口服务进行通信。Bluetooth Virtual Serial Port 和 Winsock 的 Bluetooth 通信都是使用 RFCOMM 协议, 所以两者等同。 使用 Winsock 的 Bluetooth 通信比 Bluetooth Virtual Serial Port 更简单,不需要配置。而且更强壮(robust), 因为使用 Winsock 的 Bluetooth 通信可以直接监听到蓝牙设备关闭或者离开通信 范围,而 Blueto

oth Virtual Serial Port 只能通过 Timeout 来检查。 由于支持现有系统(Legacy System),Bluetooth Virtual Serial Port 还是有存在 的价值,下面讲述 Bluetooth Virtual Serial Port 的开发。在 Windows Mobile 下有 两种方法可以建立 Bluetooth Virtual Serial Port:调用 API 建立 Bluetooth Virtual Serial Port 和修改注册表建立 Bluetooth Virtual Serial Port。 (1) 使用 https://www.wendangku.net/doc/a68847182.html, API 在 https://www.wendangku.net/doc/a68847182.html, 里 面 , 创 建 虚 拟 串 口 这 些 API 封 装 在 https://www.wendangku.net/doc/a68847182.html,.Ports.BluetoothSerialPort,可以直接使用。但是 https://www.wendangku.net/doc/a68847182.html, 的作者 提醒这些 API 是不是可信赖的(unreliable),所以在使用之前请要谨慎考虑和详细 测试。我在 wince 5 下测试过,不能成功建立 Bluetooth Virtual Serial Port。 ? 使用 https://www.wendangku.net/doc/a68847182.html, 建立服务端口
public static void CreateIncomingPort() { BluetoothSerialPort port = BluetoothSerialPort.CreateServer(BluetoothService.SerialPort); Console.WriteLine(port.PortName);
}
使用 https://www.wendangku.net/doc/a68847182.html, 建立客户端口
public static void CreateIncomingPort() { BluetoothClient client = new BluetoothClient(); BluetoothDeviceInfo[] devices = client.DiscoverDevices(); BluetoothDeviceInfo device = null; foreach (BluetoothDeviceInfo d in devices) { if (d.DeviceName == "BLUETOOTH_DEVICE") { device = d; break; } } BluetoothEndPoint endPoint = new BluetoothEndPoint(device.DeviceAddress, BluetoothService.SerialPort); BluetoothSerialPort port = BluetoothSerialPort.CreateClient(endPoint); Console.WriteLine(port.PortName); }
(2)使用修改注册表法创建虚拟串口
if (state) { //write registry settings for WM5 Serial Port support //get available ports Microsoft.Win32.RegistryKey rkPorts = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\Micro soft\\Bluetooth\\Serial\\Ports", true); string[] supportedPorts = (string[])rkPorts.GetValue("SupportedPorts"); System.Collections.ArrayList alPorts = new System.Collections.ArrayList(supportedPorts); //check availability foreach (string deviceid in rkPorts.GetSubKeyNames()) { Microsoft.Win32.RegistryKey rkDevice = rkPorts.OpenSubKey(deviceid); //remove port from arraylist if unavailable string port = rkDevice.GetValue("Port").ToString(); int nullPos = port.IndexOf('\0'); if (nullPos > -1)
{ port = port.Substring(0, nullPos); } if (alPorts.Contains(port)) { alPorts.Remove(port); } rkDevice.Close(); } if (alPorts.Count == 0) { throw new InvalidOperationException("No ports available"); } //write port details to registry Microsoft.Win32.RegistryKey rkNewPort = rkPorts.CreateSubKey(this.DeviceAddress.ToString("8")); rkNewPort.SetValue("KeepDCB", 0); rkNewPort.SetValue("RemoteDCB", 0); rkNewPort.SetValue("Encryption", 0); rkNewPort.SetValue("Authentication", 0); rkNewPort.SetValue("Port", alPorts[0]); rkNewPort.SetValue("Server", 0); rkNewPort.Close(); rkPorts.Close(); //try open port now try { https://www.wendangku.net/doc/a68847182.html,.Ports.BluetoothSerialPort.CreateClient(alPorts[0].T oString(),

new BluetoothEndPoint(this.DeviceAddress, BluetoothService.SerialPort)); } catch { } } else { //find and remove registry entries Microsoft.Win32.RegistryKey rkPorts = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("SOFTWARE\\Micro soft\\Bluetooth\\Serial\\Ports", true); foreach (string deviceAddress in rkPorts.GetSubKeyNames()) {
if (deviceAddress == this.DeviceAddress.ToString("8")) { rkPorts.DeleteSubKeyTree(deviceAddress); break; } } rkPorts.Close(); }
当 state 为 true 时为注册,当 state 为 false 时为反注册。
三、蓝牙—串口模块 3.1 蓝牙串口模块简介
蓝牙内嵌模块可以应用于各种家电、仪器(如医疗设备)等电子信息产品。 作为一种线缆取代方案, 它可以直接与单片机或处理器相连,采用即插即用的方 式实现设备间透明的无线数据传输。 蓝牙内嵌模块可以设置为主设备或从设备, 一个主设备与一个从设备配套使 用即可实现线缆替代。当蓝牙内嵌模块硬件电路连接正确,并且加电启动之后, 主从设备会自动建立连接,并且识别与记忆对方设备,之后,用户的设备就可以 像使用一条串口线一样的使用蓝牙内嵌模块。 蓝牙内嵌模块除了一对配套使用之外,也可以独立使用。如用户的设备连接 一个从设备的蓝牙内嵌模块,这样其它的蓝牙设备如蓝牙 PDA 可以搜索到此内 嵌模块,并且发现其提供的服务,通过此服务可以与其建立连接并进行通讯。对 于用户设备的通讯,仍然像使用串口线一样的使用此模块。 蓝牙内嵌模块提供了安全认证功能,当用户设置使用安全认证时,连接的设 备必须要进行鉴权, 只有通过鉴权的用户才能与其进行通讯,如果是一对蓝牙内 嵌模块,这些过程都将自动完成。
蓝牙内嵌模块引脚分配
蓝牙内嵌模块实物图
表 蓝牙内嵌模块引脚说明 序号 1 名称 CLR 描述 状态切换开关(输入) ,当采用正常模式:低电平为参数 设置状态,高电平为正常工作状态;当采用低功耗模式:
2 3 4 5 6 7,8,9,10 11,12,13,14 15 16 17 18 19,20,21,22 23,24
LNK CTS RTS TXD RXD NC
SLP PioA PioB Aio GND VCC
高电平为参数设置状态,低电平为正常工作状态。 连接指示(输出) ,处于连接状态时输出高电平,没有连 接输出低电平。 清除发送(输入) 请求发送(输出) 串行数据输出 串行数据输入 不接 不存在的引脚,是 DIP24(双排直插)删去的引脚,此产 品外型兼容 DIP24。 睡眠/唤醒/清地址(输入) ,当采用正常模式:不用时接 高电平;当采用低功耗模式:不用时接低电平。 输出备用端 0 输出备用端 1 可以用于电池电压监控,当电池最大电压高于 VCC 时, 需要分压(如下图说明) 。不用时可以悬空。 电源地 电源电压(输

入)
3.2 注意事项及使用说明
(一)蓝牙模块间的通讯 启动后,对于主设备,如果没有记忆地址,则首先查询附近的蓝牙设备,如 果查询到蓝牙设备,主设备进入匹配状态,如果鉴权通过,主设备就会记忆(保 存)该设备的地址,并与该设备建立连接,如果连接成功,LINK 灯熄灭;如果 已经记忆地址,则主设备直接与记忆的设备相连,而不会进行查询与匹配。如果 模块没有设置绑定地址的选项, 主设备连接一段时间如果连接不成功,会主动清 除匹配的蓝牙设备地址, 重新查询蓝牙设备进行匹配连接;如果模块设置了绑定 地址的选项,当主设备已经记忆了某个蓝牙设备的地址时,无论是否连接成功, 都会不断进行连接尝试。 对于从设备,则等待其它设备的查询与连接,如果连接成功,LINK 灯熄灭。 如果模块没有设置绑定地址的选项, 只要设备没有被连接都可以被其它主设备查 询到并与其完成匹配连接的过程;如果模块设置了绑定地址的选项,当从设备已 经记忆了某个蓝牙设备的地址时,无论是否被连接,任何主设备都无法查找到该 设备,只有记忆的主设备能够连接上来。 记忆的地址可以通过 AT 指令和 SLP 按键清除。 (二) 蓝牙手机与蓝牙模块的连接 一般的蓝牙手机由于没有连接串口服务的菜单, 因此不能主动连接其它蓝牙 设备的串口服务。 如果要实现蓝牙手机和内嵌模块的串口服务连接,可以将内嵌 模块设置为主设备, 主动连接蓝牙手机。但是如果要与蓝牙内嵌模块进行数据通 信,一般需要自己编写或向手机生产商所要可以在手机上运行的串口通信软件。 (三)蓝牙 PDA 与蓝牙模块的连接 蓝牙 PDA 一般有自己蓝牙管理器,通过菜单或按钮查询蓝牙设备,搜索到 蓝牙内嵌模块后通过双击内嵌模块图标或长按图标等弹出菜单后选择查询蓝牙 内嵌模块的服务,查询到串口服务后,双击或长按图标等弹出菜单后选择连接。 一般蓝牙 PDA 有配置菜单(具体位置不同 PDA 位置不同) ,可以看到连接 串口服务使用的串口号,分为“入栈”和“出栈”两个串口号,当 PDA 主动连 接内嵌模块时,建立连接后数据收发使用“出栈”的串口号;如果是内嵌模块设 为主设备主动连接到 PDA,PDA 的数据收发使用“入栈”的串口号。
3.3 蓝牙—串口模块与 MCU 的连接
(一)接线 根据以上描述,可确定蓝牙模块与 MCU(此处以 Arduino 为例)的连接方式 如下表所示:
蓝牙引脚
1 2
名称
CLR LNK
MCU 引脚
可否悬空
P12(数字 IO) 否 P13 ( 该 引 脚 外 接 可以, 但建议连接, 以方便观 Arduino 板载指示灯) 察连接状

态,或者监听连接状 态
3 4 5 6 15 19,20,21,22 23,24
CTS RTS TXD RXD SLP GND VCC
P11(数字 IO) P10(数字 IO) P0(串口 RXD) P0(串口 TXD) P9(数字 IO) GND 3.3V
否 否 可以,但建议连接,以方便控 制数据采集端为低功耗模式 否 否
(二)连接步骤 ① 首先确认模块在数据模式下指示灯是否闪烁,闪烁表示模块工作正常; ② 使模块进入参数设置状态,此时指示灯全部熄灭;单片机串口是否收到 蓝牙内嵌模块发出的数据“+OPEN:0\r\n”或“+OPEN:1\r\n” ; ③ 确认单片机串口与内嵌模块的连线是否正常,单片机的 TXD 应该接 内嵌模块的 RXD,单片机的 RXD 应该接内嵌模块的 TXD,单片机与内嵌模块之 间是否使用了流控线 (RTS、 CTS) 如果没有使用流控线应该将内嵌模块的 RTS 和 , CTS 脚之间用 1k 的电阻连接起来;如果使用了流控线,可以用万用表测试内嵌 模块的 CTS 脚是否为低电平,不是低电平需要将其置为低电平。
3.4 蓝牙—串口模块指令及其测试
(一)蓝牙 AT 指令表 序号 1 2 3 4 5 6 指令 AT\r\n AT+BAUD=
\r\n AT+BAUD?\r\n AT+AUTH=< Para1>\r\n AT+AUTH?\r\n AT+PASSWORD=< Para1>\r\n AT+PASSWORD?\r\n AT+NAME=< Para1>\r\n AT+NAME?\r\n AT+CLASS=< Para1>\r\n AT+CLASS? \r\n AT+ROLE=< Para1>\r\n AT+ROLE? \r\n AT+CLEARADDR\r\n AT+SNIFF=
,
,
,
\r\n AT+SNIFF? \r\n 指令说明 测试指令。 设置/查询波特率。 Para1:波特率。 设置/查询是否鉴权。 Para1: 不需鉴权, 0 否则需要鉴权。 设置鉴权密码。 Para1:密码。 设置/查询名称。 Para1:设备名称。 设置/查询设备类型。 Para1:设备类型(长度必须为 6 个字节) 。 设置/查询设备角色。 Para1: 为从设备, 0 否则为主设备。 清除记忆地址。 设置/查询 Sniff 节能方式。 Para1:最大时间;Para2:最小时 间。 Para3:尝试时间;Para4:超时时
7 8 9
10 11
AT+RESET\r\n AT+SCANTIME=
,
,
,
\r\n AT+SCANTIME? \r\n
12
AT+BIND=< Para1>\r\n AT+BIND? \ r \n
13 14
AT+VERSION? \r\n AT+LED=
,
\r\n AT+LED?\r\n
15 16 17 18
AT+RADDR=
\r\n AT+ RADDR?\r\n AT+LADDR?\r\n AT+ RESTART\r\n AT+UARTMODE=
,< Para2>\r\n AT+ UARTMODE?\r\n AT+INQ\r\n AT+CANCEL\r\n AT+LOWPOWER=
\r\n AT+ LOWPOWER?\r\n AT+ DATAMODE=
\r\n AT+ DATAMODE?\r\n
19 20 21
22
23
AT+ FLOWCONTROL=
\r\n AT+ FLOWCONTROL?\r\n ATZ?\r\n
24
间。 恢复默认设置。 设置/查询: 查询扫描与连接扫描参 数。此参数将影响系统的功耗。 Para1:连接间隔时间;Para2:连 接持续时间。 Para3:查询间隔时间;Para4:查 询持续时间。 设置/查询是否绑定。 Para1:0 没有绑定地址,否则绑定 地址。 默认:不绑定地址。 查询程序版本号。 设置/

查询指示灯。 Para1: ”连接指示”的 PIO 口,默 认为 PIO0(黄灯);Para2: ”电源指示” 的 PIO 口,默认为 PIO1(红灯) 。 设置/查询远端蓝牙地址。 Para1:远端的蓝牙地址。 查询本地蓝牙地址。 软件复位:发出该命令后内嵌模块 程序将重新启动,无须断电复位。 设置/查询串口通讯模式。
: 停止位。0:1 位停止位;1:2 位停止 位
:校验位。0:无校验;1:奇 校验;2:偶校验 在查询远端蓝牙设备。
:蓝 牙地址。 取消查询远端蓝牙设备。 设置/查询低功耗模式。
:0:不支持低功耗;1:支 持低功耗。 设置/查询未连接时数据处理模式。
:0:数据保存在缓冲中, 待连接建立后发送到对方蓝牙设备。 1:未连接时收到的数据直接丢掉。 设置/查询流量控制模式。
:0:无流控;1:采用硬件 流控。 查询所有命令。
(二)指令测试
此例中,发送 AT+NAME?\r\n 共 10 个字符,应答收到: +NAME:my-jinou 其他命令就不一一举例了。
3.5 PC 蓝牙 dongle 与蓝牙模块之间的串口连接测试
PC 机 COM 端口示意图
如 PC 串口图中所示,COM20 为 PC 蓝牙选配器与蓝牙模块连接后的虚拟串口
COM2 为 USB 转串口设备 CP21xx 虚拟的串口
3.6 蓝牙模块 MCU 驱动
驱动程序即是对蓝牙模块 AT 指令集的软件封装。本例中,使用 Arduino 中 方便的串口操作实现了部分本例中所用到的 AT 命令。核心代码如下,这里仅以 ByaudRate 的设置与读取为例,其他的命令,可根据相应的代码,简单的修改完 成。
/* Bluetooth module serial Driver capsulate BT module. Receives from serial port 1, sends to the main serial (Serial 0). This example works only on the Arduino Duemi The circuit: * Jinou BTM0704 BT-UART Module * Arduino: created 24 May. 2010 by Changesway@zju */ const int CLR = 12; const char ping[] = "AT"; const char baudSet[] = "AT+BAUD="; const char baudRead[] = "AT+BAUD?"; const char roleSet[] = "AT+ROLE="; const char clearAddr[] = "AT+CLEARADDR"; const char bindSet[] = "AT+BIND="; const char authSet[] = "AT+AUTH="; void setup() { // initialize both serial ports: Serial.begin(9600); pinMode(CLR, OUTPUT); Init(); } boolean isConnected() { Serial.println(ping);//Send Ping Command delay(1000); return isOK(); }
void setBaud(long baudRate){ Serial.flush(); Serial.print(baudSet); Serial.println(baudRate); delay(2000); } void setAuth(int auth){ Serial.flush(); Serial.print(authSet); Serial.println(auth); delay(2000); } void setRole(int role) { Serial.flush(); Serial.print(roleSet); Serial.println(role); delay(2000); } void setBind(int bind) { Serial.flush(); Serial.print(bindSet); Serial.println(bind); delay(2000); } void clearAddress(){ Serial.flush(); Serial.print(clearAddr); delay(2000); } long readBaud(){ int byteCount = 0; char re

cBuf[20]; char baudRate[8]; boolean readOK = false; long baudRateValue = 0; Serial.println(baudRead);//Send Ping Command
delay(1000); byteCount = Serial.available(); //Serial.println(byteCount); if (byteCount > 0) { for(int i = 0; i < byteCount; i++){ recBuf[i] = Serial.read(); if((char)recBuf[i]== ':'){ //Serial.println("find :"); for(int j= 0; j< sizeof(baudRate); j++){ baudRate[j] = Serial.read(); if((char)baudRate[j] == '\r'){ readOK = true; break; } else{ byte onebit = (byte)baudRate[j] - 48;//ASCII to DEC //Serial.println(onebit, DEC); baudRateValue *= 10; baudRateValue += onebit; } } } if(readOK) break; } } Serial.println(baudRateValue,DEC); return baudRateValue; } boolean isOK() { boolean is_connect = false; int byteCount = 0; char recBuf[10]; byteCount = Serial.available(); Serial.println(byteCount); if (byteCount > 0 && byteCount <= 10) { for(int i = 0; i < byteCount; i++){ recBuf[i] = Serial.read(); if((char)recBuf[i] == 'O'){ recBuf[++i] = Serial.read(); if((char)recBuf[i] == 'K') is_connect = true;
} } } Serial.println(recBuf); return is_connect; }
3.7 蓝牙模块的初始化
初始化过程: ? 打开串口 ? 判断蓝牙模块连接状态 ? 设置蓝牙通信速率 ? 设置蓝牙模块为无安全验证状态 ? 清除绑定地址 ? 设置蓝牙模块为需绑定 ? 设置蓝牙模块为客户端并等待连接 ? 等待连接成功后(得到 LINK 信号) ? 初始化过程完毕 注意: 驱动使用前,必须保证将 CLR 位“拉低”才可将蓝牙模块设置为“参数设置 状态”。
void Init() { digitalWrite(CLR, LOW); delay(5000);
// sets the BT module in Setting Mode
if(isConnected()){ Serial.println("Connected"); long baud = readBaud(); if(baud != 115200){ setBaud(115200); Serial.begin(115200); } else{ Serial.begin(baud); } clearAddress(); // Clear binded Address setBind(0);// needn't binding setRole(0);// Client Mode setAuth(0);// needn't Auth }
digitalWrite(CLR, HIGH); delay(5000); }
3.8 蓝牙数据采集
(一) MCU 端 以 Arduino 为例:
void loop() { int an0 = analogRead(0); Serial.println(an0); delay(2000); }
连接成功后,便直接采集某一模块通道的数据,并通过串口发送到蓝牙模块,远 进无线发送到远端的设备。 如下图所示:
搜索设备 (二) Mobile 端
接收到的数据加入 ListBox
private void menuItem_seek_Click(object sender, EventArgs e) { Cursor.Current = Cursors.WaitCursor; if (BluetoothClient.RadioMode == RadioMode.PowerOff) {
BluetoothClient.RadioMode = RadioMode.Connectable; } client = new BluetoothClient(); devices = client.DiscoverDevices(); Cursor.Current = Cursors.Default; this.listBox1.Items.Clear(); if (devices != null && devices.Length > 0) { for (int i = 0; i < devices.Length; i++) { if (devices[i].DeviceName != null) { this.listBox1.Items.Add(devices[i].DeviceName); } } } } private void menuItem_close_Click(object sender, EventArgs e) { this.timer1.Enabled

= false; client.Close(); BluetoothClient.RadioMode = RadioMode.PowerOff; } private void menuItem_connect_Click(object sender, EventArgs e) { this.EpGps = new BluetoothEndPoint(this.address, BluetoothService.SerialPort); this.client.Connect(this.EpGps); } private void menuItem_ReadData_Click(object sender, EventArgs e) { this.timer1.Enabled = true; timer1_Tick(null, null); } private void listBox1_SelectedIndexChanged(object sender, EventArgs e) { if (this.listBox1.SelectedIndex >= 0) { int index = this.listBox1.SelectedIndex; this.address = new BluetoothAddress(devices[index].DeviceID); } } private void timer1_Tick(object sender, EventArgs e) { byte[] buffer1 = new byte[0x200]; Stream GpsStream = this.client.GetStream();
int num1 = GpsStream.Read(buffer1, 0, 0x200); string gpsinfo = Encoding.ASCII.GetString(buffer1, 0, num1); listBox1.Items.Add(gpsinfo); } ? menuItem_seek_Click——完成搜索功能 ? menuItem_connect_Click——完成连接功能 ? timer1_Tick——定时接收数据

相关文档
相关文档 最新文档