DIY-Bedienfeld für Heimwerker


Hallo liebe Leser!

Eine Idee kam mir hier, aber kein Bedienfeld für ein Raumschiff zusammenzubauen. Zu USB. Mit nativer Treiberunterstützung. Benutzerdefinierte versteckt. Zu kleben und alles funktioniert, ohne Tänze und Tamburine. Als Ergebnis haben wir eine Art monströses „Gamepad“ für Weltraumsimulatoren erhalten. Im Allgemeinen beurteilen Sie selbst.

Anfangs hatte ich keine Ahnung, was am Ende passieren würde. Ich wollte zwei Haupt-Joysticks, wie bei Sojus-MS, ein paar Schalter, Tasten und mehrere Displays.

Nachdem ich die Arbeitsfläche meines Tisches geschätzt hatte, wählte ich die Abmessungen der Konsole in Breite und Tiefe 500 * 300 mm. Und nachdem er auf der Suche nach Baumaterialien durch Baulager und Geschäfte gestöbert hatte, entschied er sich für eine Höhe von 125 mm. Als Ergebnis erwarb ich eine Platte aus 4 mm Sperrholz, Lamellen 20 * 12 mm und eine Platte 120 * 20 mm.

Im Cad wurde schnell eine Skizze der Fernbedienung skizziert. Und ich habe es sehr lange in einem Baum gemacht. Drei Monate. am Wochenende. Und das nicht, weil er so imposant wie eine Säge arbeitete, sondern aus Zeitmangel. Die Platte wurde kittiert, geschliffen und mit Emaille-Farbe bemalt, ähnlich wie echte Platten von Raumschiffen oder Flugzeugen.



Aber lassen Sie die Malerarbeit vorerst beiseite und ich werde über elektronisches Füllen sprechen.

Radioteile wurden bei Ali gekauft. Als Joysticks habe ich diese gefunden. Im Allgemeinen ist die Situation mit solchen Joysticks eine vollständige Naht. Industrielle Lösungen sind zu teuer, aber billig, kommen als Spielzeug und sind daher schlecht. Diese sind von ziemlich hoher Qualität, aber sie werden nicht wissen, wie lange sie dauern werden.


Der Rest des kleinen Dings verursachte keine Probleme. Die Steuerung hat STM32 ausgewählt. Als ADC für Joysticks 16-Bit-ADS1118. Es wurde auch ein 12-V-Netzteil gekauft. Eigentlich erklärt sich diese Spannung dadurch, dass ich vom „shah“ eine Tankanzeige bekommen habe, die ich auch hier anbringen wollte.


Auf dem Foto das Netzteil, Stabilisatoren für 5 und 3,3 V, STM32, MCP23017, ADS1118

Controller 100-poliger STM32F407VET6, angeschlossen:

2 Selektoren auf 4 Positionen
1 variabler Widerstand
2 Achsschalter
4 Hauptachsen
2 Hilfsachsen
2 Steuerachsen
4 Schlüsselschalter, je 2 Tasten
20 Tasten mit LEDs
4 Hauptschalter mit LEDs
2 Pilztasten mit LEDs
2 Timer-Tasten
3 Schalter mit LEDs
13 Schalter
2 ADS1118 (ADC)
4 MAX7219 (8-stellige LED-Anzeigen)
2 TM1637 (Anzeigestunden)
1 PCF8574 (E / A-Expander, an die Zeichensyntheseanzeige angeschlossen)


Die resultierende Struktur

Es wird ein bisschen zu viel für Hunderte von Beinen des MK sein, entschied ich und fügte hier E / A-Expander hinzu: vier Teile des MCP23017 für jeweils 16 Ein- oder Ausgänge. Mit Blick auf die Zukunft werde ich sagen, dass die Verzögerung beim Abrufen der Eingänge des Expanders bei einer I2C-Busgeschwindigkeit von 400 kHz etwa 0,13 ms pro Chip betrug. Das heißt, es deckt mit einem Rand die minimale USB-Abfragezeit von 1 ms ab.

Um den I2C-Bus nicht mit unbrauchbaren Anforderungen anzusteuern, verfügt der MCP23017 über Interrupt-Ausgänge, die gesetzt werden, wenn sich der Status der Eingänge ändert. Ich habe sie auch in meinem Projekt angewendet. Wie sich weiter herausstellte, waren diese Unterbrechungen aufgrund des Rasselns der Kontakte nutzlos.

Der ADS1118 ADC hält nicht etwas mit der USB-Geschwindigkeit Schritt, seine deklarierte Leistung beträgt höchstens 820 Samples pro Sekunde, was 1,2 ms entspricht, während er mehrere Eingänge hat, die bereits über den Multiplexer mit dem ADC verbunden sind. Ich habe 2 Eingänge auf einem Chip verwendet, daher beträgt die Aktualisierungszeit der Werte 2,4 ms. Schlecht, aber was kannst du tun? Leider gibt es auf Ali keine anderen schnellen 16-Bit-ADCs.


Im Inneren sieht es so aus, aber nach der Installation der Drähte ist es viel schlimmer

Das CPU-Programm ist im Stil eines SPS-Programms geschrieben. Keine Sperranforderungen. Der Kern wartet nicht auf die Peripherie, hat keine Zeit gehabt und zur Hölle damit, beim nächsten Zyklus wird abgefragt. Es gibt auch kein RTOS im Projekt, ich habe es versucht, ich hatte eine minimale Wartezeit von 1 ms - es stellt sich langsam heraus, wenn wir Daten über USB mit einer Frequenz von 1 ms senden müssen. Als Ergebnis wurde mir klar, dass ich das Betriebssystem ohne osDelay () verwenden würde, und warum dann RTOS? Genau wie in einer SPS reicht es aus, die Programmanweisungen einzeln in einer Endlosschleife zu platzieren.

Verwendet natürlich CubeMX- und HAL-Bibliotheken. Übrigens bin ich kürzlich zu HAL gewechselt und habe mich über die Bequemlichkeit gewundert. Ich weiß nicht, warum es immer noch nicht sehr beliebt ist. Die Hauptsache ist, es zuerst herauszufinden, und dann wird es sehr einfach gehen. Es fühlt sich an, als würdest du Arduino programmieren.

Das Gerät haben wir USB benutzerdefinierte HID. HID ist Maus, Tastatur, Gamepad, Joystick und vieles mehr. Und es gibt Sitte. All dies erfordert keine Treiber vom Betriebssystem. Genauer gesagt, sie wurden bereits vom Entwickler geschrieben. Ein benutzerdefiniertes Gerät ist insofern gut, als wir selbst die Funktionen aller oben genannten Geräte nach unserem Ermessen kombinieren.

Im Allgemeinen ist das USB-Ding sehr kompliziert, es hat ein Handbuch von fast tausend Seiten und Sie können es nicht aus dem Handumdrehen nehmen. Wer keine schweren Handbücher lesen möchte, gibt es einen tollen Artikel USB in a NutShell, google. Sie hat auch eine Übersetzung. Ich werde versuchen, einige Punkte "an den Fingern" zu erklären.

USB - paketierte Datenübertragung mit einer Reihe von Ebenen und Abstraktionen. Das Gerät ist bei uns - es kann keine Daten anfordern, der Host initiiert die gesamte Übertragung. Der Host schreibt und fordert Daten an die sogenannten Endpunkte an. Dies sind physisch einige Puffer im MK-Speicher. Damit der Host versteht, an welchen Endpunkten er schreiben kann, welche Endpunkte er lesen soll und welche Daten er als Schaltflächen und Achsen unseres Geräts interpretieren kann und im Allgemeinen, welche Art von Gerät wir hier haben, fordert er zu Beginn der Verbindung Gerätedeskriptoren an. Es gibt viele dieser Deskriptoren, und es ist schwierig, sie zu verfassen, und Sie können nach Belieben Fehler machen und überall Fehler machen. Physikalisch sind sie ein Array von Bytes.

Tatsächlich generiert CubeMX einen benutzerdefinierten HID-Initialisierungscode besser als wir.





Bitte achten Sie auf das letzte Bild unter der Nummer 3. Dies ist die Größe des Deskriptors in Bytes, die bestimmt, welche Achsen und Tasten sich auf unserem Gerät befinden. Dieser Deskriptor wird im HID-Deskriptor-Tool generiert. Es gibt mehrere Beispiele für das Selbststudium. Im Allgemeinen ist hier mein Deskriptor. Zum besseren Verständnis sind noch keine Daten für Anzeigen vorhanden, aber alle Schaltflächen und Achsen der Joysticks sind vorhanden. Es muss in der Datei usbd_custom_hid_if.c abgelegt werden. Standardmäßig macht dieses Handle den Cube leer.

HID-Deskriptor (Größe 104 Byte)
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END = { /* USER CODE BEGIN 0 */ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x09, 0x04, // USAGE (Joystick) 0xa1, 0x01, // COLLECTION (Application) 0x05, 0x02, // USAGE_PAGE (Simulation Controls) 0x09, 0xbb, // USAGE (Throttle) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x27, 0xff, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65535) 0x75, 0x10, // REPORT_SIZE (16) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x01, // USAGE (Pointer) 0xa1, 0x00, // COLLECTION (Physical) 0x09, 0x30, // USAGE (X) 0x09, 0x31, // USAGE (Y) 0x95, 0x02, // REPORT_COUNT (2) 0x81, 0x02, // INPUT (Data,Var,Abs) 0xc0, // END_COLLECTION 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x32, // USAGE (Z) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x33, // USAGE (Rx) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x34, // USAGE (Ry) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x35, // USAGE (Rz) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x36, // USAGE (Slider) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x39, // USAGE (Hat switch) 0x15, 0x01, // LOGICAL_MINIMUM (1) 0x25, 0x08, // LOGICAL_MAXIMUM (8) 0x35, 0x00, // PHYSICAL_MINIMUM (0) 0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270) 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x40, // USAGE_MAXIMUM (Button 64) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x40, // REPORT_COUNT (64) 0x55, 0x00, // UNIT_EXPONENT (0) 0x65, 0x00, // UNIT (None) 0x81, 0x02, // INPUT (Data,Var,Abs) /* USER CODE END 0 */ 0xC0 /* END_COLLECTION */ }; 


Tatsächlich kann es beliebig zusammengestellt werden. Zuerst stellen Sie die USAGE PAGE-Parameter und die erforderliche USAGE ein, z. B. die USAGE-Achse (Gas), und nach dem Wort INPUT (Data, Var, Abs) geht das System davon aus, dass wir die Achse „Gas“ haben. Die Abmessung der variablen Achse und ihre Anzahl werden durch die Parameter LOGICAL_MAXIMUM, MINIMUM, REPORT_SIZE, REPORT_COUNT festgelegt, die vor INPUT liegen müssen.

Weitere Details zu diesen Parametern sowie zu den Funktionen (Data, Var, Abs) finden Sie in der Geräteklassendefinition für Human Interface Devices (HID) v1.11 .

Das Folgende ist ein Beispiel für die Initialisierung der Drosselklappenachse aus meinem Deskriptor. In diesem Beispiel hat Throttle einen Wertebereich von 0-65535, der einer Variablen uint16_t entspricht.

  0x05, 0x02, // USAGE_PAGE (Simulation Controls) 0x09, 0xbb, // USAGE (Throttle) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x27, 0xff, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65535) 0x75, 0x10, // REPORT_SIZE (16) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 

Angenommen, Sie können nicht jedes Mal LOGICAL_MAXIMUM, MINIMUM, REPORT_SIZE, REPORT_COUNT schreiben. Der Host ermittelt diesen Wert anhand des vorherigen Parameters. Dies wird durch die Achsen veranschaulicht, die nacheinander verlaufen, ohne die Größe und Anzahl anzugeben:

  0x09, 0x32, // USAGE (Z) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x33, // USAGE (Rx) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x34, // USAGE (Ry) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x35, // USAGE (Rz) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x36, // USAGE (Slider) 

Die folgende Struktur entspricht all diesem Deskriptor, der unter dem Spoiler höher ist. Es ist in der Tat nicht mehr obligatorisch, es ist nur bequemer, basierend auf Zeigern aufzuzeichnen.

 #pragma pack(push, 1) typedef struct _myReportStruct { uint16_t Throttle; uint16_t X; uint16_t Y; uint16_t Z; uint16_t Rx; uint16_t Ry; uint16_t Rz; uint16_t Slider; uint8_t Hat; // 0 - none, 1 - up, 2 - up-right, 3 - right, 4 - down-right... uint32_t Buttons1; // 32 buttons of 1 bit each uint32_t Buttons2; // 32 buttons of 1 bit each }myReportStruct; #pragma pack(pop) volatile myReportStruct Desk; 

Diese Struktur kann von der Funktion an den Host gesendet werden

 USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, (uint8_t *) &Desk, sizeof(Desk)); 

Der erste Parameter ist ein USB-Handle, der bereits in unserem Cube erstellt wurde. Möglicherweise müssen Sie die erforderliche Datei in das Include einfügen, in dem dieses Handle zum ersten Mal initialisiert wird, und extern USBD_HandleTypeDef hUsbDeviceFS schreiben . damit du mit ihm arbeiten kannst. Der zweite Parameter ist ein Zeiger auf unsere Struktur und der dritte ist die Größe der Struktur in Bytes.

Nach dem Befüllen und Flashen des Controllers werden Sie feststellen, dass sich etwas USB langsam bewegt. Die Daten aus unserem Panel werden nicht schnell aktualisiert. Um schnell zu sein, müssen Sie in den Dateien usbd_customhid.h #define CUSTOM_HID_EPIN_SIZE auf den Maximalwert 0x40 ändern, #define CUSTOM_HID_EPOUT_SIZE auch 0x40. Suchen Sie in der Datei usbd_customhid.c Kommentare im Endpunktdeskriptor "/ * bInterval: Abfrageintervall (20 ms) * /" und ändern Sie das Deskriptorbyte für jeden Endpunkt nur zweimal in 0x01. Dies entspricht einem Datenaustausch von 1 ms.


Es sollte so etwas sein. Standardgerät ohne Installation von Treibern

Im Allgemeinen ist die Verwaltungsfunktion ein wenig verstanden. Es ist ganz einfach und alle Tasten und Achsen funktionieren bereits. Es bleibt, damit die Anzeigen funktionieren. Ich habe es getan, ungefähr sechs Monate, und seit einem halben Jahr sammelt sich das Panel in einer langen Schachtel. Es gibt keine Zeit. Aus diesem Grund habe ich mich entschlossen, den Artikel in dieser Form zu gestalten, da sonst die Gefahr besteht, dass er nicht einmal herauskommt.

Bei Displays ist alles wie bei Achsen. Für sie müssen wir unseren Geräte-HID-Deskriptor ergänzen, nur angeben, dass dies Anzeigen sind, und anstatt Eingabedaten zu akzeptieren, sendet der Host Ausgabedaten.

Der Griff des HID-Geräts ist erheblich gewachsen. Hier habe ich bereits die Report ID-Parameter angewendet, um den Sende- / Empfangspuffer und die Endpunkte nicht mit vollständigen Daten zu verstopfen und um zu unterscheiden, welche Art von Telegramm wir empfangen haben. Die Berichts-ID ist ein uint8_t-Byte mit dem Wert, der am Anfang des Telegramms steht. Der Wert, den wir im Gerätedeskriptor HID festgelegt haben.

CUSTOM_HID_ReportDesc_FS
 //AXIS 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x04, // USAGE (Joystick) 0xa1, 0x01, // COLLECTION (Application)28 0x05, 0x02, // USAGE_PAGE (Simulation Controls) 0x09, 0xbb, // USAGE (Throttle) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x27, 0xff, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65535) 0x75, 0x10, // REPORT_SIZE (16) 0x95, 0x01, // REPORT_COUNT (1) 0x85, 0x01, // REPORT_ID (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x01, // USAGE (Pointer) 0xa1, 0x00, // COLLECTION (Physical) 0x09, 0x30, // USAGE (X) 0x09, 0x31, // USAGE (Y) 0x95, 0x02, // REPORT_COUNT (2) 0x81, 0x02, // INPUT (Data,Var,Abs) 0xc0, // END_COLLECTION 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x32, // USAGE (Z) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x33, // USAGE (Rx) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x34, // USAGE (Ry) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x35, // USAGE (Rz) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x09, 0x36, // USAGE (Slider) 0x81, 0x02, // INPUT (Data,Var,Abs) //HAT 0x09, 0x39, // USAGE (Hat switch) 0x15, 0x01, // LOGICAL_MINIMUM (1) 0x25, 0x08, // LOGICAL_MAXIMUM (8) 0x35, 0x00, // PHYSICAL_MINIMUM (0) 0x46, 0x0e, 0x01, // PHYSICAL_MAXIMUM (270) 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0x81, 0x02, // INPUT (Data,Var,Abs) //Buttons 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x29, 0x40, // USAGE_MAXIMUM (Button 64) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x75, 0x01, // REPORT_SIZE (1) 0x95, 0x40, // REPORT_COUNT (64) 0x55, 0x00, // UNIT_EXPONENT (0) 0x65, 0x00, // UNIT (None) 0x81, 0x02, // INPUT (Data,Var,Abs) //LEDs 0x85, 0x02, // REPORT_ID (2) 0x05, 0x08, // USAGE_PAGE (LEDs) 0x09, 0x4B, // USAGE (Generic Indicator) 0x95, 0x40, // REPORT_COUNT (16) 0x91, 0x02, // OUTPUT (Data,Var,Abs) 0xc0, // END_COLLECTION //LCD Displays 0x05, 0x14, // USAGE_PAGE (Alphnumeric Display) 0x09, 0x01, // USAGE (Alphanumeric Display) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0xa1, 0x02, // COLLECTION (Logical) 0x09, 0x32, // USAGE (Cursor Position Report) 0xa1, 0x02, // COLLECTION (Logical) 0x85, 0x04, // REPORT_ID (4) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x01, // REPORT_COUNT (1) 0x25, 0x13, // LOGICAL_MAXIMUM (19) 0x09, 0x34, // USAGE (Column) 0xb1, 0x22, // FEATURE (Data,Var,Abs,NPrf) 0x25, 0x03, // LOGICAL_MAXIMUM (3) 0x09, 0x33, // USAGE (Row) 0x91, 0x22, // OUTPUT (Data,Var,Abs,NPrf) 0xc0, // END_COLLECTION 0x09, 0x2b, // USAGE (Character Report) 0xa1, 0x02, // COLLECTION (Logical) 0x85, 0x05, // REPORT_ID (5) 0x95, 0x14, // REPORT_COUNT (20) 0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255) 0x09, 0x2c, // USAGE (Display Data) 0x92, 0x02, 0x01, // OUTPUT (Data,Var,Abs,Buf) 0xc0, // END_COLLECTION 0x09, 0x24, // USAGE (Display Control Report) 0x85, 0x06, // REPORT_ID (6) 0x95, 0x01, // REPORT_COUNT (1) 0x91, 0x22, // OUTPUT (Data,Var,Abs,NPrf) 0xc0, // END_COLLECTION //LED Displays 0x05, 0x14, // USAGE_PAGE (Alphnumeric Display) 0x09, 0x01, // USAGE (Alphanumeric Display) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0xa1, 0x02, // COLLECTION (Logical) 0x09, 0x2b, // USAGE (Character Report) 0xa1, 0x02, // COLLECTION (Logical) 0x85, 0x07, // REPORT_ID (7) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x28, // REPORT_COUNT (40) 0x26, 0xFF, 0x00, // LOGICAL_MAXIMUM (255) 0x09, 0x2c, // USAGE (Display Data) 0x92, 0x02, 0x01, // OUTPUT (Data,Var,Abs,Buf) 0xc0, // END_COLLECTION //Other DATA 0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop) 0x09, 0x01, // USAGE (Vendor Usage 1) 0xa1, 0x01, // COLLECTION (Application) 0x85, 0x08, // REPORT_ID (8) 0x09, 0x01, // USAGE (Vendor Usage 1) 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x27, 0xff, 0xff, 0x00, 0x00, // LOGICAL_MAXIMUM (65535) 0x75, 0x10, // REPORT_SIZE (16) 0x95, 0x0A, // REPORT_COUNT (10) 0x91, 0x82, // OUTPUT (Data,Var,Abs,Vol) 

Die Ausgabe wird in der statischen Funktion int8_t CUSTOM_HID_OutEvent_FS (Status uint8_t event_idx, Status uint8_t) verarbeitet , die sich standardmäßig in usbd_custom_hid_if.c befindet.

statisch int8_t CUSTOM_HID_OutEvent_FS ()
 static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state) { /* USER CODE BEGIN 6 */ uint8_t dataReceiveArray[USBD_CUSTOMHID_OUTREPORT_BUF_SIZE]; USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef*)hUsbDeviceFS.pClassData; for (uint8_t i = 0; i < USBD_CUSTOMHID_OUTREPORT_BUF_SIZE; i++) { dataReceiveArray[i] = hhid->Report_buf[i]; } if (dataReceiveArray[0] == 2) //report ID 2 leds { //  Report id == 2,   -     dataReceiveArray[1 + N], ,  LED } if (dataReceiveArray[0] == 4) //report ID 4 cursor position { //  Report id == 4,   -,     LCD } if (dataReceiveArray[0] == 5) //report ID 5 display data { //  Report id == 5,   -,     USB  LCD } //   ,   ID     return (USBD_OK); /* USER CODE END 6 */ } 


Es bleibt nur ein Programm auf einem PC zu schreiben, das die erforderlichen Berichte zur Steuerung der Anzeigen sendet. Um den MK-Code zu überprüfen, ist jedoch ein großartiges Programm von ST: USB HID Demonstrator geeignet. Sie können Berichte von einem PC mit beliebigen Inhalten senden.


LED-Anzeigetest

Zu diesem Zeitpunkt bin ich bisher fertig. Und es ist nicht bekannt, ob ich wieder anfangen werde.

Es wird in Simulatoren gespielt, die interessanter sind als mit einer Tastatur. Aber nicht so sehr, dass es einen direkten Wow-Effekt gab. Die Tastatur sieht auch aus wie ein Bedienfeld. Die Steuerung von Joystickachsen ist jedoch zumindest ungewöhnlich. Fühlen Sie sich wie ein Astronaut. Zwar wird zum vollständigen Eintauchen ein Raumanzug benötigt.

Ich hoffe du warst interessiert. Tippfehler, Ungenauigkeiten und Wahnvorstellungen sind vorhanden. Diejenigen, die tiefer in den Code eintauchen möchten, können hier sehen .

Mit freundlichen Grüßen.

Source: https://habr.com/ru/post/de434854/


All Articles