Technologieaustausch

Ein Problem bei der Verwendung von Delphi für die Bluetooth BLE-Entwicklung

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Konzept

Ziehen Sie für die BLE-Entwicklung in Delphi ein TBlueToothLe auf die Schnittstelle und verwenden Sie dieses Steuerelement, um BLE zu entwickeln, z. B. zum Anschließen eines Bluetooth-Armbands.

In der mit Delphi gelieferten Demo gibt es ein BLEScanner-Programm, das als Ausgangspunkt für die Entwicklung verwendet werden kann.

Frage

Wenn das obige Programm unter Windows ausgeführt wird, nachdem das Gerät gescannt wurde und die Maus auf ein Gerät klickt, kann es sein, dass die Schnittstelle einfriert und das Programm nicht reagiert. Ein Blick in den Aufgabenverwaltungsbereich zeigt, dass das Programm nicht reagiert und abgestürzt ist.

Ursachenanalyse

Klicken Sie mit der Maus, um die Dienste des ausgewählten Geräts zu scannen. Wenn dann die Dienste des Geräts erkannt werden, wird das OnServicesDiscovered-Ereignis von TBluetoothLE ausgelöst. In diesem Fall werden mehrere Dienste des Geräts in einer Schleife gelesen, und dann wird für einen bestimmten Dienst sein Zeichenname in einer Schleife gelesen. Beim Absturz lautet die Schleife „Character“.

Warum es abgestürzt ist, weiß ich nicht. Aber ich habe eine Lösung gefunden, der Code lautet wie folgt:

  1. procedure TForm6.BluetoothLE1ServicesDiscovered(const Sender: TObject; const AServiceList: TBluetoothGattServiceList);
  2. var
  3. ServiceIndex: Integer;
  4. Service: TBluetoothGattService;
  5. CharacteristicIndex: Integer;
  6. Characteristic: TBluetoothGattCharacteristic;
  7. begin
  8. //以下代码如果不包到 TTask.Run 里面(原本的代码没有),在 WINDOWS 底下,执行到 for
  9. //CharacteristicIndex := 0 to Service.Characteristics.Count 会界面冻结,而且单步跟踪也停止
  10. //了,没有往下执行。
  11. TTask.Run(
  12. procedure
  13. var
  14. ServiceIndex: Integer;
  15. CharacteristicIndex: Integer;
  16. begin
  17. if AServiceList.Count > 0 then
  18. begin
  19. for ServiceIndex := 0 to AServiceList.Count - 1 do
  20. begin
  21. Service := AServiceList[ServiceIndex];
  22. TThread.Synchronize(nil,
  23. procedure
  24. begin
  25. Listbox2.Items.Add((ServiceIndex + 1).ToString + ' - ' + Service.UUIDName + ' - ' + Service.UUID.ToString);
  26. end
  27. );
  28. //以下代码会导致死机,如果断点跟踪,直接就是停在 for 这一行,不会继续往下执行。
  29. for CharacteristicIndex := 0 to Service.Characteristics.Count - 1 do
  30. begin
  31. Characteristic := Service.Characteristics[CharacteristicIndex];
  32. TThread.Synchronize(nil,
  33. procedure
  34. begin
  35. Listbox2.Items.Add(' - ' + Characteristic.UUIDName + ' - ' + Characteristic.UUID.ToString);
  36. end
  37. );
  38. end;
  39. end;
  40. end
  41. else
  42. TThread.Synchronize(nil,
  43. procedure
  44. begin
  45. Listbox2.Items.Add('- Access not allowed or no service available');
  46. end
  47. );
  48. end
  49. );
  50. //Listbox1.Enabled := True;
  51. end;

Code-Erklärung

Im obigen Code wurde TTask.Run von mir hinzugefügt. TThread.Synchronize wurde auch von mir hinzugefügt. Entfernen Sie TTask.Run und TThread.Synchronize und der verbleibende Code ist der Originalcode der Demo, die mit Delphi geliefert wird.

Fügen Sie zunächst den Originalcode in TTask.Run ein, was bedeutet, dass diese Codes zur Ausführung in einen Thread eingefügt werden. Anstatt den Thread, der ursprünglich das OnServicesDiscovered-Ereignis ausgelöst hat, ausführen zu lassen. Möglicher Grund: Der Thread, der OnServicesDiscovered ausgelöst hat, kann nicht zu viele zeitaufwändige Aufgaben ausführen.

Der Code wird im Thread ausgeführt, wenn Sie Daten in das Schnittstellensteuerelement schreiben müssen, z. B. Listbox2.Items.Add-Code, müssen Sie eine Thread-Synchronisierung durchführen. Fügen Sie also TThread.Synchronize hinzu.

meine Entwicklungsumgebung

In verschiedenen Umgebungen können die Phänomene unterschiedlich sein. Daher hier meine Entwicklungsumgebung:

Delphi 11 Community Edition;

Windows 11 Home Edition;

Das zu kompilierende und auszuführende Zielprogramm ist die Win32-Version.

Es gibt keinen Test, ob diese Demo unter Android die oben genannten Probleme haben wird. Aber ich glaube, dass es unter Android besser ist, TTask.Run hinzuzufügen.

Standort des Demoprogramms

Die hier erwähnte Demo lautet nach der Installation von Delphi, wenn sie standardmäßig installiert ist, das Demo-Programm:

C:\Benutzer\Öffentliche Dokumente\EmbarcaderoStudio22.0\Beispiele\Object Pascal\Beispiele für mehrere Geräte\Gerätesensoren und -dienste\Bluetooth\BLEScanner

abschließend

Es ist kein Problem, Delphi zum Entwickeln von BLE-Programmen zu verwenden, beispielsweise zum Erstellen einer Armband-APP. Es ist jedoch zu beachten, dass es bei vielen Ereignissen des TBluetoothLE-Steuerelements am besten ist, nicht zu viel Code auszuführen. Wenn eine komplexe Geschäftslogik vorliegt, ist es am besten, diese in einem separaten Thread auszuführen. Starten Sie in der Ereignismethode einfach den entsprechenden Thread.

Für Delphi ermöglicht uns das neu hinzugefügte TTask.Run, viel Code in die Thread-Ausführung zu werfen. Die Code-Schreibmethode ist viel einfacher als zuvor, als wir eine Thread-Klasse erstellen mussten.