一、新建工程,自定义创建路径与名称,这边自定义ble0507,然后按照 下方步骤一直点next,直至完成。
二、先在.pro文件中 添加蓝牙模块bluetooth
三、设计UI界面并命名其控件名称
四、在widget.h文件中 添加头文件并声明定义
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QBluetoothDeviceDiscoveryAgent> //设备搜寻
#include <QBluetoothLocalDevice> //本地设备信息
#include <QMessageBox> //对话框
#include <QLowEnergyController> //设备连接
#include <QLowEnergyService> //数据接收、发送
#include <QScrollBar>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
QBluetoothLocalDevice *localDevice; //获取本地设备的蓝牙状态信息
QBluetoothDeviceDiscoveryAgent *deviceDiscoveryAgent; //搜索周围蓝牙设备
QBluetoothDeviceInfo deviceInfo; //保存需要连接的设备的信息
QLowEnergyController *m_controller; //用于蓝牙设备连接
QLowEnergyService *m_service; //用于数据接收与发送
QLowEnergyCharacteristic m_readCharacteristic; //“读”服务特性
QLowEnergyCharacteristic m_writeCharacteristic[5]; //“写”服务特性
QLowEnergyService::WriteMode m_writeMode; //“写”特性模式
QLowEnergyDescriptor m_notificationDesc; //用于存储BLE描述符信息
int sendMode;
int sendSelect;
private slots:
void on_pushButton_open_pressed();
void on_pushButton_search_pressed();
void addBlueToothList(const QBluetoothDeviceInfo &info);
void on_pushButton_connect_pressed();
void BlueServiceDiscovered(const QBluetoothUuid &gatt);
void BlueServiceScanDone();
void searchCharacteristic();
void BlueDeviceConnected();
void BlueDeviceDisconnected();
void BleServiceServiceStateChanged(QLowEnergyService::ServiceState s);
void BleServiceCharacteristicChanged(const QLowEnergyCharacteristic &c, const QByteArray &value);
void on_pushButton_disconnect_pressed();
void on_pushButton_send_pressed();
void on_pushButton_clean_pressed();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
五、在widget.cpp中
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//实例化蓝牙相关对象
deviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent();
localDevice = new QBluetoothLocalDevice();
//初始化
m_controller=NULL;
m_service=NULL;
sendSelect=1;
sendMode=0;
//设置显示本地蓝牙名称
QString label_name("本地蓝牙:");
label_name += localDevice->name();
ui->label_blename->setText(label_name);
//关联发现设备的槽函数,当扫描发现周围的蓝牙设备时,会发出deviceDiscovered信号
connect(deviceDiscoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),this,SLOT(addBlueToothList(QBluetoothDeviceInfo)));
//自动打开蓝牙
if(localDevice ->hostMode() == QBluetoothLocalDevice::HostPoweredOff)
{
localDevice->powerOn();
}
}
Widget::~Widget()
{
delete ui;
}
//手动打开蓝牙
void Widget::on_pushButton_open_pressed()
{
localDevice->powerOn();
}
//搜索蓝牙设备
void Widget::on_pushButton_search_pressed()
{
ui->comboBox_name->clear();
deviceDiscoveryAgent->start();
QMessageBox::information(this,"提示","正在搜索中...");
}
//当搜索到周围的设备时会调用当前的槽函数
void Widget::addBlueToothList(const QBluetoothDeviceInfo &info)
{
QString label= QString("%1 %2").arg(info.address().toString()).arg(info.name());
ui->comboBox_name->addItem(label); //添加字符串到comboBox上
}
//断开蓝牙设备
void Widget::on_pushButton_disconnect_pressed()
{
QMessageBox::StandardButton result = QMessageBox::information(this,"连接提示","是否断开蓝牙?",QMessageBox::Yes|QMessageBox::No);
if(result == QMessageBox::Yes)
{
if(m_controller)
{
delete m_controller;
m_controller = NULL;
}
QMessageBox::information(this,"提示","已成功断开蓝牙!");
}
}
//发送信息
void Widget::on_pushButton_send_pressed()
{
QString text=ui->lineEdit_send->text();
QByteArray array=text.toLocal8Bit();
/*写入newValue作为特性的值。
如果操作成功,将发射characteristicWritten()信号;
低功耗设备: 每次最多写20个字节*/
m_service->writeCharacteristic(m_writeCharacteristic[sendSelect],array, m_writeMode);
}
//清除数据
void Widget::on_pushButton_clean_pressed()
{
ui->textEdit_receive->clear();
}
//连接蓝牙
void Widget::on_pushButton_connect_pressed()
{
QString text = ui->comboBox_name->currentText();
int index = text.indexOf(' ');
if(index == -1) return;
QBluetoothAddress address(text.left(index));
QString connect_device="是否开始连接蓝牙设备:\n";
connect_device+=ui->comboBox_name->currentText();
QMessageBox::StandardButton result2 = QMessageBox::information(this,tr("连接提示"),connect_device,QMessageBox::Yes|QMessageBox::No);
/*低功耗蓝牙设备*/
if(result2 == QMessageBox::Yes)
{
if(m_controller!=NULL)
{
m_controller->disconnectFromDevice(); //断开远程设备
delete m_controller;
m_controller= NULL;
}
QList<QBluetoothDeviceInfo> info_list=deviceDiscoveryAgent->discoveredDevices(); //得到扫描的所有设备信息
for(int i=0;i<info_list.count();i++)
{
if(info_list.at(i).address().toString()==text.left(index))
{
deviceInfo=info_list.at(i);
break;
}
}
//创建中央角色设备
m_controller= new QLowEnergyController(deviceInfo, this);
//m_control=QLowEnergyController::createCentral(remoteDevice,this);
if(m_controller==0)
{
QMessageBox::critical(this,"警告","创建中央角色设备失败!");
}
else
{
// ui->plainTextEdit->insertPlainText("创建中央角色设备成功!\n");
}
//每次发现新的服务就会发送此信号
connect(m_controller, SIGNAL(serviceDiscovered(QBluetoothUuid)),this, SLOT(BlueServiceDiscovered(QBluetoothUuid)));
//正在运行的服务发现完成时发出此信号。
connect(m_controller, SIGNAL(discoveryFinished()),this, SLOT(BlueServiceScanDone()));
//当控制器成功连接到远程Low Energy设备时,会发出此信号。
connect(m_controller, SIGNAL(connected()),this, SLOT(BlueDeviceConnected()));
//当控制器从远程低功耗设备断开时发出此信号。
connect(m_controller, SIGNAL(disconnected()),this, SLOT(BlueDeviceDisconnected()));
//该信号在发生错误时发出。
connect(m_controller, static_cast<void(QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
[=](QLowEnergyController::Error error){
if(error==QLowEnergyController::NoError)
{
// ui->plainTextEdit->insertPlainText("没有发生错误\n");
}
else if(error==QLowEnergyController::UnknownError)
{
// ui->plainTextEdit->insertPlainText("出现未知错误。\n");
QMessageBox::critical(this,"警告","出现未知错误!");
}
else if(error==QLowEnergyController::UnknownRemoteDeviceError)
{
// ui->plainTextEdit->insertPlainText("无法找到传递给此类构造函数的远程Bluetooth Low Energy设备。\n");
QMessageBox::critical(this,"警告","无法找到传递给此类构造函数的远程Bluetooth Low Energy设备!");
}
else if(error==QLowEnergyController::NetworkError)
{
// ui->plainTextEdit->insertPlainText("尝试读取或写入远程设备失败\n");
QMessageBox::critical(this,"警告","尝试读取或写入远程设备失败!");
}
else if(error==QLowEnergyController::InvalidBluetoothAdapterError)
{
// ui->plainTextEdit->insertPlainText("传递给此类构造函数的本地蓝牙设备无法找到,或者没有本地蓝牙设备\n");
QMessageBox::critical(this,"警告","传递给此类构造函数的本地蓝牙设备无法找到,或者没有本地蓝牙设备!");
}
else if(error==QLowEnergyController::InvalidBluetoothAdapterError)
{
// ui->plainTextEdit->insertPlainText("尝试连接到远程设备失败。\n");
QMessageBox::critical(this,"警告","尝试连接到远程设备失败!");
}
else
// ui->plainTextEdit->insertPlainText("*****未知错误!******\n");
QMessageBox::critical(this,"警告","*****未知错误!******");
});
//连接到远程蓝牙低功耗设备。
m_controller->connectToDevice();
}
}
//每次发现新的服务,就会调用该槽函数
void Widget::BlueServiceDiscovered(const QBluetoothUuid &gatt)
{
ui->textEdit_receive->insertPlainText(gatt.toString()+"\n");
}
/*默认指定的UUID服务*/
static const QLatin1String serviceUuid("{0000ffe0-0000-1000-8000-00805F9B34FB}");
//正在运行的服务发现完成时发出信号
void Widget::BlueServiceScanDone()
{
//判断之前有没有连接过
if(m_service != NULL)
{
delete m_service;
m_service = NULL;
}
ui->textEdit_receive->insertPlainText("选中的服务:\n"+serviceUuid);
//与设备之间建立服务
m_service = m_controller ->createServiceObject(QBluetoothUuid(serviceUuid),this);
if(m_service == NULL)
{
ui->textEdit_receive->insertPlainText("服务建立失败!");
return;
}
else
{
ui->textEdit_receive->insertPlainText("服务建立成功!");
}
//服务状态改变时发出此信号
connect(m_service,SIGNAL(stateChanged(QLowEnergyService::ServiceState)),this,SLOT(BleServiceServiceStateChanged(QLowEnergyService::ServiceState)));
//特性值由事件改变时发出此信号在外设上。newValue参数包含更新后的值特性
connect(m_service,SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)),this,SLOT(BleServiceCharacteristicChanged(QLowEnergyCharacteristic,QByteArray)));
//错误信号
connect(m_service,static_cast<void (QLowEnergyService::*)(QLowEnergyService::ServiceError)>(&QLowEnergyService::error),
[=](QLowEnergyService::ServiceError newErrorr)
{
if(newErrorr == QLowEnergyService::NoError)
{
ui->textEdit_receive->insertPlainText("没有发生错误!\n");
ui->textEdit_receive->ensureCursorVisible();
}
if(newErrorr == QLowEnergyService::OperationError)
{
ui->textEdit_receive->insertPlainText("错误:当服务没有准备好时尝试进行操作!\n");
ui->textEdit_receive->ensureCursorVisible();
}
if(newErrorr == QLowEnergyService::CharacteristicReadError)
{
ui->textEdit_receive->insertPlainText("尝试读取特征值失败!\n");
ui->textEdit_receive->ensureCursorVisible();
}
if(newErrorr == QLowEnergyService::CharacteristicWriteError)
{
ui->textEdit_receive->insertPlainText("尝试为特性写入新值失败!\n");
ui->textEdit_receive->ensureCursorVisible();
}
if(newErrorr == QLowEnergyService::DescriptorReadError)
{
ui->textEdit_receive->insertPlainText("尝试读取描述符值失败\n");
ui->textEdit_receive->ensureCursorVisible();
}
if(newErrorr == QLowEnergyService::DescriptorWriteError)
{
ui->textEdit_receive->insertPlainText("尝试向描述符写入新值失败!\n");
ui->textEdit_receive->ensureCursorVisible();
}
if(newErrorr == QLowEnergyService::UnknownError)
{
ui->textEdit_receive->insertPlainText("与服务交互时发生未知错误!\n");
ui->textEdit_receive->ensureCursorVisible();
}
});
if(m_service ->state() == QLowEnergyService::DiscoveryRequired)
{
m_service ->discoverDetails(); //启动服务扫描
}
else
searchCharacteristic();
}
//搜索特性
void Widget::searchCharacteristic()
{
if(m_service)
{
QList<QLowEnergyCharacteristic> list = m_service ->characteristics();
//characteristic 获取详细特性
sendMode = list.count(); //设置模式选择上限
for (int i = 0; i < list.count(); i++)
{
QLowEnergyCharacteristic c = list.at(i);
//如果QLowEnergyCharacteristic对象有效,则返回true,否则返回false
if( c.isValid())
{
//返回特征的属性
//这些属性定义了特征的访问权限
if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse || c.properties() & QLowEnergyCharacteristic::Write)
{
ui->textEdit_receive->insertPlainText("具有写权限!\n");
m_writeCharacteristic[i] = c; //保存写权限特性
if(c.properties() & QLowEnergyCharacteristic::WriteNoResponse)
//如果使用此模式写入特性,则远程外设不应发送写入确认。
//无法确定操作的成功,并且有效负载不得超过20个字节。
//一个特性必须设置QLowEnergyCharacteristic::WriteNoResponse属性来支持这种写模式。
//他的优点是更快的写入操作,因为它可能发生在其他设备交互之间。
m_writeMode = QLowEnergyService::WriteWithoutResponse;
else
m_writeMode = QLowEnergyService::WriteWithResponse;
//如果使用此模式写入特性,则外设应发送确认。
//如果操作成功,则通过characteristicWritten()信号发出确认。
//否则,发出CharacteristicWriteError。
//一个特性必须设置QLowEnergyCharacteristic::Write属性来支持这种写模式。
}
if(c.properties() & QLowEnergyCharacteristic::Read)
{
m_readCharacteristic = c; //保存读权限特性
}
//描述符定义特征如何由特定客户端配置
m_notificationDesc = c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration);
//值为真
if(m_notificationDesc.isValid())
{
//写描述符
m_service ->writeDescriptor(m_notificationDesc,QByteArray::fromHex("0100"));
ui->textEdit_receive->insertPlainText("写描述符!\n");
}
}
}
}
}
//当控制器成功连接到远程Low Energy设备时,会发出此信号。
void Widget::BlueDeviceConnected()
{
//启动发现服务Service
m_controller->discoverServices();
}
//当控制器从远程低功耗设备断开此信号。
void Widget::BlueDeviceDisconnected()
{
ui->textEdit_receive->insertPlainText("成功断开!\n");
}
//服务状态改变时发出此信号
void Widget::BleServiceServiceStateChanged(QLowEnergyService::ServiceState s)
{
//所有细节都已同步
if(s == QLowEnergyService::ServiceDiscovered)
{
QMessageBox::information(this,"提示","已成功连接蓝牙!");
searchCharacteristic();
}
}
//读取数据
void Widget::BleServiceCharacteristicChanged(const QLowEnergyCharacteristic &c, const QByteArray &value)
{
ui->textEdit_receive->insertPlainText(QString(value));
//移动滚动条到底部
QScrollBar * scrollbar = ui->textEdit_receive->verticalScrollBar();
if(scrollbar)
{
scrollbar -> setSliderPosition(scrollbar ->maximum());
}
// if(!value.isEmpty())
// {
// QString str = QString(value).toUtf8().data();
// str += tr(value);
// if(str.length() > 12040) //数据超出最大缓冲区
// {
// str.remove(0, str.length() - 12040); //清除超出的部分
// }
// ui->textEdit_receive->insertPlainText(str);
// }
}
效果如下:
QT低功耗蓝牙