这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【STM32WBA55CG开发板】QT蓝牙数据通信应用与交互——2、QT上位机设

共5条 1/1 1 跳转至

【STM32WBA55CG开发板】QT蓝牙数据通信应用与交互——2、QT上位机设计与单片机进行数据交互Demo

菜鸟
2024-12-20 21:45:42     打赏

上一章:【STM32WBA55CG开发板】QT蓝牙数据通信应用与交互——1、通信架构搭建

Hi~ 我又回来了。我看了一些其它朋友们做的,都很优秀啊,我也得多多向大佬们学习啊

这次使用Qt Creator设计一个简单的上位机,实现PC和单片机的数据交互,经过了一段时间的踩坑,在正式介绍之前我要说个注意事项:

在windows上开发BT 或者 BLE,必须使用msvc,如果使用MingGW,会搜索不到设备。必须使用QT 5.15.2 或以上的QT版本,不然无法使用高级搜索(有的设备蓝牙搜索不到)

由于仅仅是个通信的框架,所以界面设计的比较简陋,如图:

image.png


由于时间仓促,没有封装蓝牙连接的类,所以直接把代码贴出来吧。

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 的具体应用,敬请期待吧!




关键词: STM32WBA55CG     数据通信     蓝牙    

专家
2024-12-20 21:57:08     打赏
2楼

感谢分享


专家
2024-12-20 21:59:20     打赏
3楼

感谢分享


专家
2024-12-20 22:01:00     打赏
4楼

感谢分享


工程师
2024-12-21 09:32:47     打赏
5楼

666666


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]