上一章:【STM32WBA55CG开发板】QT蓝牙数据通信应用与交互——1、通信架构搭建
Hi~ 我又回来了。我看了一些其它朋友们做的,都很优秀啊,我也得多多向大佬们学习啊

这次使用Qt Creator设计一个简单的上位机,实现PC和单片机的数据交互,经过了一段时间的踩坑,在正式介绍之前我要说个注意事项:
在windows上开发BT 或者 BLE,必须使用msvc,如果使用MingGW,会搜索不到设备。必须使用QT 5.15.2 或以上的QT版本,不然无法使用高级搜索(有的设备蓝牙搜索不到)
由于仅仅是个通信的框架,所以界面设计的比较简陋,如图:

由于时间仓促,没有封装蓝牙连接的类,所以直接把代码贴出来吧。
1、首先需要搜索蓝牙设备
void Widget::on_pushButtonScan_clicked()
{
discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);
//discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::NoMethod);
//discoveryAgent->start();
}
//=================================Agent Scan Device==================================
//find device...
void Widget::BT_deviceDiscovered(const QBluetoothDeviceInfo &device){
QString deviceName=device.name().toUtf8();
QString deviceAddress=device.address().toString();
qDebug("device name:%s\r\n",qPrintable(deviceName));
qDebug("device address:%s\r\n",qPrintable(deviceAddress));
//判断是否是ESP BLE设备
if ((deviceName.indexOf("ST")!=-1)
//||(deviceName.indexOf("ESP")!=-1)
)
{
QString label = QString("%1 %2").arg(deviceName).arg(deviceAddress);//按顺序显示地址和设备名称
deviceList.append(label);
//QList<QListWidgetItem *> items = ui->comboBoxDevice->findItems(label, Qt::MatchExactly);//检查设备是否已存在,避免重复添加
//if (items.empty())
{//不存在则添加至设备列表
//QListWidgetItem *item = new QListWidgetItem(label);
ui->comboBoxDevice->addItems(deviceList);
bleDevInfoList.append(device);
}
}
}
//find finished
void Widget::BT_scanFinished(){
qDebug("BT discover finished ");
isFinishDiscover=true;
}蓝牙搜索到之后,会自动的将搜索到的设备添加到列表中。
2、连接蓝牙,如果连接成功,会将Services添加到第二个列表里。
void Widget::on_pushButtonConnect_clicked()
{
QThread::msleep(1000);
if(isFinishDiscover){
connect_device(!deviceIsConnected);
}
}
//按下连接按键的操作
void Widget::connect_device(bool isConnect){
if(isConnect){
qDebug("正在连接...");
btController=QLowEnergyController::createCentral(bleDevInfoList.at(ui->comboBoxDevice->currentIndex()),this);
//扫描目标BLE服务,获取一次触发一次
connect(btController, &QLowEnergyController::serviceDiscovered,this, &Widget::ble_ServiceDiscovered);
//扫描完成之后会触发此信号
connect(btController, &QLowEnergyController::discoveryFinished,this, &Widget::ble_ServiceScanDone);
//连接出错
connect(btController, static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
this, [this](QLowEnergyController::Error error) {
qDebug("connect device error!!");
Q_UNUSED(error);
QMessageBox::information(this,tr("Info"),tr("Cannot connect to remote device."));
});
//连接成功
connect(btController, &QLowEnergyController::connected, this, [this]() {
qDebug("connected device successed!!");
QMessageBox::information(this,tr("Info"),tr("Controller connected. Search services..."));
btController->discoverServices();
});
//断开连接
connect(btController, &QLowEnergyController::disconnected, this, [this]() {
qDebug("disconnected device!!");
QMessageBox::information(this,tr("Info"),tr("LowEnergy controller disconnected"));
});
//事件更新信号
connect(btController, &QLowEnergyController::stateChanged, this, &Widget::ble_SeviceStateChanged);
//建立连接,若连接没有出错,会自动搜索连接设备的服务
btController->connectToDevice();
}else{
btController->disconnectFromDevice();
delete btController;
ui->comboBoxDevice_Service->clear();
ui->comboBoxDevice_Char->clear();
}
}
//获取Service服务被找到
void Widget::ble_ServiceDiscovered(const QBluetoothUuid & serviceUuid)
{
bleServiceUUIDList.append(serviceUuid);
QString uuid =serviceUuid.toString();
ui->comboBoxDevice_Service->addItem(uuid);
qDebug("Service find %s!",qPrintable(uuid));
}
//Service 获取完毕
void Widget::ble_ServiceScanDone(){
qDebug("Service scan done!");
}3、通过Services 创建服务。如果创建成功,会自动扫描特征,并且再次添加到列表
//服务状态值改变会触发此槽函数
//当蓝牙服务被扫描到时状态值会发生改变,改变为QLowEnergyService::ServiceDiscovered
void Widget::ble_ServiceStateChanged(QLowEnergyService::ServiceState s)
{
Q_UNUSED(s);
QLowEnergyCharacteristic bleCharacteristic;
if(s == QLowEnergyService::ServiceDiscovered)
{
//QMessageBox::information(NULL,"tips",QObject::tr("Service synchronization"));
//TODO....
m_charList = m_service->characteristics();
for(int i=0; i<m_charList.size(); i++){
QString uuid=m_charList.at(i).value();
QString charName=m_charList.at(i).name();
ui->comboBoxDevice_Char->addItem(charName+uuid);
}
}
}
//创建服务
void Widget::on_pushButtonCreatService_clicked()
{
QThread::msleep(1000);
QBluetoothUuid m_serviceUUID;
m_serviceUUID=bleServiceUUIDList.at(ui->comboBoxDevice_Service->currentIndex());
m_service=btController->createServiceObject(m_serviceUUID);
if(m_service==NULL){
qDebug("创建ble服务失败");
}else{
qDebug("创建ble服务成功");
//同步服务
if (!m_service)
{
QMessageBox::information(NULL,"error","Cannot create service for uuid");
return;
}
//监听服务状态值发生改变
connect(m_service, &QLowEnergyService::stateChanged, this,&Widget::ble_ServiceStateChanged);
//特征值发生改变
connect(m_service, &QLowEnergyService::characteristicChanged, this,&Widget::ble_CharacteristicChanged);
//char 成功读
connect(m_service, &QLowEnergyService::characteristicRead, this,&Widget::ble_ServiceCharacteristicRead);
//char 成功写
connect(m_service, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)),this, SLOT(ble_ServiceCharacteristicWrite(QLowEnergyCharacteristic,QByteArray)));
QThread::msleep(1000);
//服务详情发现函数
m_service->discoverDetails();
}
}4、最后就是特征的一些操作了,包括读写,notify等等
//=================================Char operation==================================
void Widget::on_pushButton_Read_clicked()
{
m_character=m_charList.at(ui->comboBoxDevice_Char->currentIndex());
m_service->readCharacteristic(m_character);
}
void Widget::on_pushButton_Write_clicked()
{
QString str=ui->lineEdit_Write->text();
QByteArray byte = str.toLatin1();
m_character=m_charList.at(ui->comboBoxDevice_Char->currentIndex());
m_service->writeCharacteristic(m_character,byte);
}
void Widget::ble_CharacteristicChanged(QLowEnergyCharacteristic characteristic, QByteArray newValue)
{
Q_UNUSED(characteristic);
int len = newValue.size();
if(len > 0){
qDebug(qPrintable(QString("rec:").append(newValue.toHex())));
int val=newValue.data()[0];
QString nowValueStr=QString::number(val);
//ui->label_Notification->setText(nowValueStr);
}
}
//void QLowEnergyService::writeCharacteristic(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue, QLowEnergyService::WriteMode mode = WriteWithResponse)
//参数:characteristic -- 当前服务的某个特性值 newValue -- 写入数据 WriteMode mode -- 写入模式
//返回值:无
//功能:发送信息给BLE
//currentService->writeCharacteristic(m_Characteristic[0], QByteArray(text.toUtf8()));
//发送消息成功触发此槽函数
void Widget::ble_ServiceCharacteristicWrite(const QLowEnergyCharacteristic &c, const QByteArray &value)
{
QString str(c.uuid().toString());
QString str2("instructions %1 send to success!");
QString str3 = str + QString(":") + str2.arg(QString(value));
QMessageBox::information(NULL,"tips",str3);
}
//void QLowEnergyService::readCharacteristic(const QLowEnergyCharacteristic &characteristic)
//参数:characteristic -- 当前服务的某个特性值
//返回值:无
//功能:从BLE中读取信息
//currentService->readCharacteristic(m_Characteristic[1]);
//读到消息触发此槽函数
void Widget::ble_ServiceCharacteristicRead(const QLowEnergyCharacteristic &c, const QByteArray &value)
{
QString charUUID = c.uuid().toString();
QString valuetoHexString = value.toHex();//16进制输出信息
QString readStr = QString(value);
qDebug(qPrintable("read char:"+readStr));
qDebug(qPrintable("read char raw:"+value));
ui->label_Read->setText(readStr);
}
/*
*
* Unknown = 0x00,
Broadcasting = 0x01,
Read = 0x02,
WriteNoResponse = 0x04,
Write = 0x08,
Notify = 0x10,
Indicate = 0x20,
WriteSigned = 0x40,
ExtendedProperty = 0x80
*
*/
void Widget::on_pushButtonNotify_clicked()
{
int index=ui->comboBoxDevice_Char->currentIndex();
if(m_service!=NULL){
if(ui->pushButtonNotify->text()=="打开通知"){
ui->pushButtonNotify->setText("关闭通知");
ui->pushButtonNotify->setStyleSheet("color: rgb(255, 0, 0);");
m_descriptor = m_charList.at(index).descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
if(m_descriptor.isValid()){
m_service->writeDescriptor(m_descriptor,QByteArray::fromHex("0100"));
}
}else if(ui->pushButtonNotify->text()=="关闭通知"){
ui->pushButtonNotify->setText("打开通知");
ui->pushButtonNotify->setStyleSheet("color: rgb(0, 0 0);");
m_descriptor = m_charList.at(index).descriptor(QBluetoothUuid::DescriptorType::ClientCharacteristicConfiguration);
if(m_descriptor.isValid()){
m_service->writeDescriptor(m_descriptor,QByteArray::fromHex("0000"));
}
}
}else{
}
}目前已经可以实现基本通信。完整代码已经上传到gitee上了,需要的可以参考一下:https://gitee.com/enderman1/eepw/tree/master/ble_rw_base
基于此,下一个帖子我会做一个QT + STM32 的具体应用,敬请期待吧!
我要赚赏金
