在开始QT蓝牙开发之前,我们需要先准备好开发环境。我建议使用QT 5.15.2或更高版本,因为这个版本对蓝牙模块的支持比较完善。首先,在.pro项目文件中添加以下模块依赖:
cmake复制QT += core bluetooth widgets
这里有个坑我踩过:有些教程会建议只写QT += bluetooth,但在某些版本下这会报错找不到模块。正确的做法是同时包含core和widgets模块,因为它们通常是蓝牙应用的基础依赖。
安装完QT后,还需要确认系统蓝牙驱动是否正常。在Windows上,可以打开设备管理器查看蓝牙设备状态;在Linux上,可以使用hciconfig命令检查适配器。我遇到过一个问题:代码明明写对了,但就是扫描不到设备,最后发现是系统蓝牙服务没启动。在Linux下可以用这个命令检查:
bash复制sudo systemctl status bluetooth
首先我们要获取本地蓝牙适配器的信息。QBluetoothLocalDevice类提供了这个功能:
cpp复制QBluetoothLocalDevice localDevice;
if(!localDevice.isValid()) {
qDebug() << "未找到可用的蓝牙适配器";
return;
}
// 开启蓝牙并设置为可被发现模式
localDevice.powerOn();
localDevice.setHostMode(QBluetoothLocalDevice::HostDiscoverable);
// 获取本地设备信息
QString deviceName = localDevice.name();
QBluetoothAddress address = localDevice.address();
这里有个实用技巧:在程序退出时,最好恢复蓝牙的原始状态。我习惯在析构函数中添加:
cpp复制localDevice.setHostMode(QBluetoothLocalDevice::HostConnectableOnly);
设备发现是蓝牙开发的第一步,使用QBluetoothDeviceDiscoveryAgent类:
cpp复制discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::deviceDiscovered,
this, &MainWindow::addDeviceToList);
connect(discoveryAgent, &QBluetoothDeviceDiscoveryAgent::finished,
this, &MainWindow::scanFinished);
// 开始扫描
discoveryAgent->start();
在实际项目中,我发现扫描时间不宜过长,通常10-12秒就足够了。可以通过以下方式设置超时:
cpp复制QTimer::singleShot(12000, [this](){
if(discoveryAgent->isActive()) {
discoveryAgent->stop();
}
});
找到目标设备后,我们需要建立通信连接。QT提供了QBluetoothSocket类:
cpp复制// 使用RFCOMM协议创建socket
socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
// 连接信号槽
connect(socket, &QBluetoothSocket::connected,
this, &MainWindow::socketConnected);
connect(socket, &QBluetoothSocket::readyRead,
this, &MainWindow::readSocketData);
// 连接到服务
socket->connectToService(remoteDeviceAddress, QBluetoothUuid::SerialPort);
这里有个重要细节:SerialPort是标准的SPP UUID(00001101-0000-1000-8000-00805F9B34FB)。如果是自定义服务,需要替换为对应的UUID。
数据收发是蓝牙通信的核心功能。发送数据相对简单:
cpp复制void MainWindow::sendData(const QByteArray &data) {
if(socket && socket->isWritable()) {
qint64 bytesWritten = socket->write(data);
if(bytesWritten == -1) {
qDebug() << "发送失败:" << socket->errorString();
}
}
}
接收数据则需要处理readyRead信号:
cpp复制void MainWindow::readSocketData() {
while(socket->bytesAvailable()) {
QByteArray data = socket->readAll();
processReceivedData(data); // 自定义数据处理函数
}
}
蓝牙开发中会遇到各种连接问题。我总结了几个常见错误及解决方法:
cpp复制QTimer::singleShot(5000, [this](){
if(socket->state() == QBluetoothSocket::ConnectingState) {
socket->abort();
qDebug() << "连接超时";
}
});
cpp复制void processReceivedData(QByteArray &buffer, const QByteArray &newData) {
buffer.append(newData);
while(buffer.contains('\n')) {
int pos = buffer.indexOf('\n');
QByteArray completeMessage = buffer.left(pos);
buffer = buffer.mid(pos+1);
handleCompleteMessage(completeMessage);
}
}
经过多个项目实践,我总结出几点优化建议:
cpp复制QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream << quint32(0x12345678) << QString("蓝牙数据");
socket->write(data);
cpp复制// 每30秒发送心跳包
heartbeatTimer = new QTimer(this);
connect(heartbeatTimer, &QTimer::timeout, [this](){
if(socket->state() == QBluetoothSocket::ConnectedState) {
socket->write("\x00"); // 心跳包内容
}
});
heartbeatTimer->start(30000);
在实际项目中,蓝牙模块的稳定性至关重要。我通常会添加自动重连机制,当连接断开时尝试重新建立连接。同时建议添加信号强度检测(RSSI),当信号弱时提前预警,这对移动设备间的通信特别有用。