Qt.5.15
Windows 10
蓝牙设备会以周期为120Hz, 向外发送数据
基于QT GUI 没收到这个信号 characteristicChanged, 换了几台电脑都一样,不能自动收取数据,不得不用一个Timer来读,但偶尔会错过数据
connect(service, &QLowEnergyService::stateChanged, this,&MainWindow::serviceStateChanged);
connect(service, &QLowEnergyService::characteristicChanged, this,&MainWindow::BLEServiceCharacteristicChanged);
connect(service, &QLowEnergyService::characteristicRead, this,&MainWindow::BLEServiceCharacteristicRead);
不得不用一个Timer来读,但偶尔会错过数据
service->readCharacteristic(m_Characteristic[2]);
但是基于 C# .net GUI 能够捕获这个 signal ,C#gui 和安卓都可以自动收到蓝牙设备发出的数据。
private void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
cpp
QBluetoothSocket *socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
socket->connectToService(QBluetoothAddress("00:11:22:33:44:55"), 1); // 连接蓝牙设备
connect(socket, SIGNAL(readyRead()), this, SLOT(readBluetoothData())); // 读取数据
cpp
void MainWindow::readBluetoothData()
{
QByteArray data = socket->readAll();
// 处理数据
}
该回答引用ChatGPT
您好,我认为可能是因为QT GUI在接收数据时的线程不够稳定,或者在接收数据时的处理速度不够快。建议优化线程和处理速度,或者使用C#或安卓的GUI来接收数据。另外,可以尝试调整Timer的时间间隔,或者使用其他方法接收数据,比如使用Notification或Indication来接收数据。
基于最新版ChatGPT4的回答,望采纳!!!有其他问题也可以询问我哦💕(最新版更智能,功能更加强大):
您遇到的问题可能是因为 Qt 的 QLowEnergyCharacteristic 类不会在 Windows 平台上自动接收数据更新通知。相反,它需要手动读取数据,或使用一个计时器轮询。这可能会导致数据丢失或延迟。
为了解决这个问题,您可以考虑使用 Windows 平台特定的 BLE 库,例如 WinRT BLE API。通过使用该库,您可以访问更多平台特定功能,并且可以更直接地与 Windows 平台上的 BLE 设备进行通信。
如果您希望继续使用 Qt BLE 库,您可以考虑使用 QLowEnergyController::readCharacteristic() 函数来读取数据。但是,这将需要您手动控制读取频率和数据处理,以确保不会丢失或延迟数据。
另一个选择是使用 Qt 的 QTimer 类来定期检查是否有新数据可用。这样可以减少不必要的轮询,并使数据接收更加及时。但请注意,这仍然可能会导致数据丢失或延迟,因此请确保在代码中处理这些情况。
以下答案由GPT-3.5大模型与博主波罗歌共同编写:
问题可能是由于 Qt 的事件和线程机制所导致的。QLowEnergyService::characteristicChanged 信号是由 BLE 设备发射出来的,它在后台线程调用,因此您的 GUI 线程可能会错过该信号。在 Android 平台上,这个问题得到了解决,因为 Android 主线程处理事件的速度很快,因此 GATT 事件不会错过。
解决方案是使用 Qt 的事件循环机制来读取 BLE 数据。将 QLowEnergyController 和 QLowEnergyService 对象分别分配到一个线程中,以便它们可以异步执行。在主线程中创建一个 QT 事件队列,并调用 exec() 函数开始事件循环。在 QLowEnergyService::characteristicChanged 信号发射时,它将被排入事件队列,该事件将触发一个处理函数,该函数将读取新的 GATT 特性值。这可以确保事件不会错过,并且可以及时读取和处理新的数据。
下面是示例代码:
#include <QCoreApplication>
#include <QDebug>
#include <QLowEnergyController>
#include <QLowEnergyService>
class BLEController : public QObject {
Q_OBJECT
public:
BLEController(QObject *parent = nullptr) : QObject(parent) {
m_controller = QLowEnergyController::createCentral(this);
m_controller->setRemoteAddressType(QLowEnergyController::RandomAddress);
QObject::connect(m_controller, &QLowEnergyController::connected, this, &BLEController::onConnected);
QObject::connect(m_controller, &QLowEnergyController::disconnected, this, &BLEController::onDisconnected);
QObject::connect(m_controller, &QLowEnergyController::discoveryFinished, this, &BLEController::onDiscoveryFinished);
QObject::connect(m_controller, &QLowEnergyController::errorOccurred, this, &BLEController::onError);
}
void connectToDevice(const QBluetoothDeviceInfo& device) {
m_controller->connectToDevice(device);
}
signals:
void connected();
void disconnected();
void discoveryFinished();
void error(QString error);
private:
QLowEnergyController *m_controller;
private slots:
void onConnected() {
qDebug() << "Connected to GATT server.";
emit connected();
}
void onDisconnected() {
qDebug() << "Disconnected from GATT server.";
emit disconnected();
}
void onDiscoveryFinished() {
qDebug() << "Service discovery finished.";
emit discoveryFinished();
}
void onError(QLowEnergyController::Error error) {
QString errorStr = QString("Error occurred: %1").arg(error);
qDebug() << errorStr;
emit error(errorStr);
}
};
class BLEService : public QObject {
Q_OBJECT
public:
BLEService(QObject *parent = nullptr) : QObject(parent), m_service(nullptr) {}
void setController(QLowEnergyController *controller) {
m_service = controller->createServiceObject(QBluetoothUuid(<SERVICE_UUID>), this);
QObject::connect(m_service, &QLowEnergyService::stateChanged, this, &BLEService::onStateChanged);
}
signals:
void characteristicChanged(const QByteArray &newValue);
void characteristicRead(const QByteArray &value);
private:
QLowEnergyService *m_service;
private slots:
void onStateChanged(QLowEnergyService::ServiceState state) {
if (state == QLowEnergyService::ServiceDiscovered) {
qDebug() << "BLE service discovered.";
QLowEnergyCharacteristic characteristic = m_service->characteristic(QBluetoothUuid(<CHARACTERISTIC_UUID>));
if (characteristic.isValid()) {
QObject::connect(m_service, &QLowEnergyService::characteristicChanged, this, &BLEService::onCharacteristicChanged);
m_service->readCharacteristic(characteristic);
} else {
qDebug() << "Characteristic not found!";
}
}
}
void onCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
if (characteristic.uuid() == QBluetoothUuid(<CHARACTERISTIC_UUID>)) {
emit characteristicChanged(newValue);
m_service->readCharacteristic(characteristic);
}
}
};
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
BLEController controller;
BLEService service;
QObject::connect(&controller, &BLEController::connected, [&service]() {
qDebug() << "Connected to device.";
service.setController(controller.m_controller);
});
QObject::connect(&service, &BLEService::characteristicChanged, [](const QByteArray &newValue) {
qDebug() << "New value: " << newValue;
});
QBluetoothDeviceInfo device(<DEVICE_ADDRESS>);
controller.connectToDevice(device);
return app.exec();
}
请注意,在这个示例代码中,使用了 QLowEnergyController 对象来处理连接和发现的过程,使用 QLowEnergyService 对象来处理 GATT 特性的读取和写入。QBluetoothUuid 类用于表示 BLE 设备中使用的 UUID。您需要将其替换为您的特定 UUID。假设您的 BLE 设备已经处于配对状态,需要将 替换为该设备的 MAC 地址。
这个示例代码将执行一个事件循环,并在 QLowEnergyService::characteristicChanged 信号触发时读取新的 GATT 特性值。这保证了事件不会因为Qt主线程的执行速度而超时。
如果我的回答解决了您的问题,请采纳!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
class Program
{
[DllImport("QtClassLibrary1.dll", EntryPoint = "ImageZoom", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public extern static int ImageZoom(int w,int h,IntPtr Path, CallbackDelegate callback);
//定义委托
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackDelegate(IntPtr Path);
//接收C++回调数据
static void CallBackFunction(IntPtr Path)
{
Console.WriteLine("C++传出来的回调:" + Marshal.PtrToStringAnsi(Path));
}
static void Main(string[] args)
{
string text = "C:\\Users\\11266\\Pictures\\20220425103841.png";
int r_code = ImageZoom(100,100,Marshal.StringToHGlobalAnsi(text), CallBackFunction);
Console.WriteLine("执行状态:" + r_code);
Console.ReadKey();
}
}
}
写完代码,直接运行,会报错找不到模块。很正常,因为代码里填写的库是当前程序运行路径,现在路径下并没有库文件,接下来需要拷贝库到运行目录下即可。