我有一个在Windows PC上运行的程序,它通过COM端口发送/接收数据。数据通过HM10蓝牙模块通过蓝牙传输。
我能够发现外围设备,连接它,成功地发现它的服务和特性。不过我的问题是发送数据。中央是我的iPhone。 PC充当外围设备。
首先是我的代码。
import CoreBluetooth
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var peripheralNameLabel: UILabel!
@IBOutlet weak var noOfServicesLabel: UILabel!
@IBOutlet weak var sendBytesButton: UIButton!
@IBOutlet weak var sendStringButton: UIButton!
@IBOutlet weak var responseTextView: UITextView!
private let serviceUUID = CBUUID(string: "FFE0")
private var characteristicUUID = CBUUID(string: "FFE1")
private var manager: CBCentralManager!
private var peripheral: CBPeripheral!
private var characteristic: CBCharacteristic!
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil)
}
@IBAction func didTapSendBytesButton(sender: UIButton) {
let bytes: [UInt8] = [0x35, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
let data = NSData(bytes: bytes, length: bytes.count)
peripheral.writeValue(data, forCharacteristic: characteristic, type: .WithResponse)
}
@IBAction func didTapSendStringButton(sender: UIButton) {
let string = "5100000000"
if let data = string.dataUsingEncoding(NSUTF8StringEncoding) {
peripheral.writeValue(data, forCharacteristic: characteristic, type: .WithResponse)
} else {
sendStringButton.enabled = false
sendStringButton.setTitle("", forState: .Normal)
}
}
}
extension ViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(central: CBCentralManager) {
print(#function)
switch central.state {
case .Unsupported:
print("Unsupported")
case .Unauthorized:
print("Unauthorized")
case .PoweredOn:
print("Powered On")
navigationItem.title = "Connecting..."
central.scanForPeripheralsWithServices([serviceUUID], options: nil)
case .Resetting:
print("Resetting")
case .PoweredOff:
print("Powered Off")
case .Unknown:
print("Unknown")
}
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
print(#function)
print("Discovered \(peripheral.name) at \(RSSI)")
peripheralNameLabel.text = peripheral.name
if peripheral.name == nil || peripheral.name == "" {
return
}
if self.peripheral == nil || self.peripheral.state == .Disconnected {
self.peripheral = peripheral
central.connectPeripheral(peripheral, options: nil)
central.stopScan()
}
}
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
print(#function)
navigationItem.title = "Connected!"
sendBytesButton.enabled = true
sendStringButton.enabled = true
peripheral.delegate = self
peripheral.discoverServices([serviceUUID])
}
func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
self.peripheral = nil
central.scanForPeripheralsWithServices(nil, options: nil)
}
func centralManager(central: CBCentralManager, didFailToConnectPeripheral peripheral: CBPeripheral, error: NSError?) {
print(#function)
self.peripheral = nil
}
}
extension ViewController: CBPeripheralDelegate {
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
print(#function)
guard let services = peripheral.services else {
return
}
noOfServicesLabel.text = "\(services.count)"
for service in services {
print(service.UUID)
if service.UUID == serviceUUID {
peripheral.discoverCharacteristics(nil, forService: service)
}
}
}
func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
print(#function)
guard let characteristics = service.characteristics else {
return
}
for characteristic in characteristics {
print("characteristic: \(characteristic.UUID)")
if characteristic.UUID == characteristicUUID {
self.characteristic = characteristic
peripheral.setNotifyValue(true, forCharacteristic: characteristic)
}
}
}
func peripheral(peripheral: CBPeripheral, didWriteValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
print(#function)
print(error)
}
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
print(#function)
if characteristic.UUID == characteristicUUID {
print("Got reply from: \(characteristic.UUID)")
if let data = characteristic.value, let string = String(data: data, encoding: NSUTF8StringEncoding) {
responseTextView.text = string
} else {
print("No response!")
}
}
}
}
我应该发送像这样的字节数组,
0x35 0x31 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
到外围设备,如果外围设备成功接收到它,我会将此作为响应,
0x43 0x41 0x4E 0x20 0x31 0x31 0x2F 0x35 0x30 0x30 0x0D 0x0A
。
它应该是什么样子。
这才是真正发生的事情。
数据包在传输时被分成几部分。因此,我没有得到成功的回应。
奇怪的部分有时很少,它实际上是有效的!数据正确发送(如第一张图片中所示),我收到成功响应。但失败经常发生。像99%的时间一样。
我尝试了两种方式,将数据作为字节数组(didTapSendBytesButton()
)发送,并将其作为转换后的字符串(didTapSendStringButton()
)发送。两者都是相同的。
还使用名为Bluetooth Serial的应用进行了测试。结果相同。
我无法弄清楚为什么会这样。
答案 0 :(得分:1)
您发送的字节少于20个字节,因此蓝牙数据将通过一次传输发送。
问题在于您的接收方,或实际上您的通信方式。
一个串口一次只能发送或接收一个字节,所以即使iOS一次发送所有字节(这是一个副作用,如何通过GATT模拟串口),Windows必须呈现它们一次一个到虚拟COM端口驱动程序。 Windows在COM端口上进行缓冲,以便在程序读取速度不够快时不会丢失字节,这就是为什么每个“RX”看到多个字节的原因,但COM驱动程序中没有“数据包”的概念,因此它不知道发送了多少字节,或者它应该等到收到所有字节并将它们作为一个组传送。
最终的答案是你需要修改你的消息,以便它有某种分隔符(甚至是简单的分隔符),让接收程序知道已收到消息的结尾。然后,它可以验证消息并进行适当的响应。
或者,如果您无法控制接收程序,并且该程序与其他发送代码一起工作,那么我怀疑您发送的数据有问题,因为串行字节被拆分的事实多个RX调用是正常的,必须编写接收程序来处理这个