Panel kontrol pesawat ruang angkasa DIY do-it-yourself


Halo para pembaca!

Satu ide muncul di sini, tetapi tidak untuk membuat panel kontrol untuk pesawat ruang angkasa. Ke USB. Dengan dukungan pengemudi asli. Kustom HID. Untuk tetap dan semuanya berfungsi, tanpa tarian dan rebana. Hasilnya, kami mendapat semacam "gamepad" mengerikan untuk simulator ruang. Secara umum, nilai sendiri.

Pada awalnya, saya tidak tahu apa yang akan terjadi pada akhirnya. Saya ingin dua joystick utama, seperti pada Soyuz-MS, beberapa sakelar, tombol, dan beberapa tampilan.

Setelah memperkirakan permukaan meja kerja saya, saya memilih dimensi konsol dengan lebar dan kedalaman 500 * 300 mm. Dan setelah mencari-cari gudang konstruksi dan toko-toko untuk mencari bahan bangunan, ia memilih ketinggian 125mm. Sebagai hasilnya, saya memperoleh selembar kayu lapis 4 mm, bilah 20 * 12 mm dan papan 120 * 20 mm.

Dalam cad, sketsa remote control dengan cepat dibuat sketsa. Dan saya melakukannya di pohon untuk waktu yang sangat lama. Tiga bulan. di akhir pekan. Dan bukan karena dia bekerja sangat mengesankan seperti gergaji, tetapi karena kurangnya waktu. Panel itu didudukkan, diampelas, dan dicat dengan cat enamel, serupa warnanya dengan panel pesawat ruang angkasa atau pesawat terbang.



Tetapi untuk sekarang, kesampingkan pekerjaan melukis dan saya akan berbicara tentang isian elektronik.

Bagian radio dibeli pada Ali. Sebagai joystick, saya menemukan ini. Secara umum, situasi dengan joystick seperti itu adalah jahitan yang lengkap. Solusi industri terlalu mahal, tetapi murah, datang sebagai mainan dan karenanya buruk. Ini cukup berkualitas tinggi, tetapi mereka tidak akan menyadari berapa lama mereka akan.


Sisa dari hal kecil itu tidak menimbulkan masalah. Pengontrol memilih STM32. Sebagai ADC untuk joystick, ADS1118 16-bit. Catu daya 12 V juga dibeli. Sebenarnya, tegangan ini dijelaskan oleh fakta bahwa saya mendapat pengukur bahan bakar dari "shah", yang juga ingin saya pasang di sini.


Dalam foto, catu daya, stabilisator untuk 5 dan 3.3 V, STM32, MCP23017, ADS1118

Kontroler 100-pin STM32F407VET6, terhubung ke sana:

2 penyeleksi ke 4 posisi
1 resistor variabel
2 sakelar gandar
4 sumbu utama
2 sumbu bantu
2 as kontrol
4 tombol switch, masing-masing 2 tombol
20 tombol dengan LED
4 sakelar utama dengan LED
2 tombol jamur dengan LED
2 tombol pengatur waktu
3 sakelar dengan LED
13 switch
2 ADS1118 (ADC)
4 MAX7219 (tampilan LED 8 digit)
2 TM1637 (jam tampilan)
1 PCF8574 (I / O expander, dicolokkan ke layar pembuatan karakter)


Struktur yang dihasilkan

Akan terlalu banyak untuk ratusan kaki MK, saya memutuskan, dan menambahkan di sini I / O ekspander: empat potong MCP23017, untuk 16 input atau output masing-masing. Ke depan, saya akan mengatakan bahwa penundaan dalam polling input dari expander ternyata sekitar 0,13 ms per chip, pada kecepatan bus I2C 400 kHz. Artinya, dengan margin mencakup waktu polling USB minimum 1 ms.

Agar tidak mengemudikan bus I2C dengan permintaan yang tidak berguna, MCP23017 memiliki keluaran interupsi yang ditetapkan ketika keadaan input berubah. Saya juga menerapkannya dalam proyek saya. Ternyata, karena keributan kontak, gangguan ini tidak berguna.

ADS1118 ADC tidak mengikuti kecepatan USB, kinerjanya yang dinyatakan paling banyak 820 sampel per detik, yaitu 1,2 ms, sementara itu memiliki beberapa input yang sudah terhubung ke ADC melalui multiplexer. Saya menggunakan 2 input pada satu chip, jadi waktu pembaruan nilainya adalah 2,4 ms. Buruk, tetapi apa yang bisa Anda lakukan? Sayangnya, tidak ada ADC cepat 16-bit lainnya pada Ali.


Di dalamnya terlihat seperti ini, tetapi setelah memasang kabel itu jauh lebih buruk

Program CPU ditulis dengan gaya program PLC. Tidak ada permintaan pemblokiran. Inti tidak menunggu pinggiran, belum punya waktu dan persetan dengan itu, pada siklus berikutnya akan menginterogasi. Tidak ada RTOS dalam proyek ini, saya mencobanya, saya berlari ke waktu tunggu tugas minimum 1 ms - ternyata lambat jika kita perlu mengirim data melalui USB dengan frekuensi 1 ms. Akibatnya, saya menyadari bahwa saya akan menggunakan OS tanpa osDelay (), lalu mengapa RTOS? Sama seperti dalam PLC, menempatkan instruksi program satu per satu di dalam loop tak terbatas sudah cukup.

Pustaka CubeMX dan HAL yang digunakan, tentu saja. Ngomong-ngomong, saya baru saja beralih ke HAL dan bertanya-tanya tentang kenyamanan. Saya tidak tahu mengapa itu masih tidak terlalu populer, hal utama yang harus dipikirkan pada awalnya, dan kemudian akan berjalan sangat sederhana. Rasanya seperti Anda sedang memprogram Arduino.

Perangkat kita akan memiliki USB HID khusus. HID adalah mouse, keyboard, gamepad, joystick, beberapa lainnya. Dan ada kebiasaan. Semua ini tidak memerlukan driver dari sistem operasi. Lebih tepatnya, mereka sudah ditulis oleh pengembang. Perangkat kustom bagus karena kami sendiri menggabungkan kemampuan semua perangkat di atas sesuai kebijakan kami.

Secara umum, hal USB sangat rumit, ia memiliki manual hampir seribu halaman dan Anda tidak dapat mengambilnya dengan mudah. Siapa yang tidak ingin membaca manual berat, ada artikel bagus USB di NutShell, google. Dia juga memiliki terjemahan. Saya akan mencoba menjelaskan beberapa poin "di jari".

USB - transfer data paket dengan sekelompok level dan abstraksi. Perangkat itu bersama kami - tidak dapat meminta data apa pun, tuan rumah yang memulai seluruh transfer. Tuan rumah menulis dan meminta data ke titik akhir yang disebut, secara fisik ini adalah beberapa buffer dalam memori MK. Agar tuan rumah dapat memahami titik akhir mana yang memungkinkan untuk ditulis, titik akhir mana yang harus dibaca dan data apa yang dapat ditafsirkan sebagai tombol dan sumbu perangkat kita dan, secara umum, jenis perangkat apa yang kita miliki di sini, pada awal koneksi ia meminta deskriptor perangkat. Ada banyak deskriptor ini dan sulit untuk menyusunnya dan Anda bisa sesuka Anda, dan juga membuat kesalahan di mana saja. Secara fisik, mereka adalah array byte.

Bahkan, CubeMX akan menghasilkan kode inisialisasi Custom HID lebih baik dari kita.





Perhatikan gambar terakhir di bawah angka 3. Ini adalah ukuran deskriptor dalam byte, yang menentukan sumbu dan tombol mana yang ada pada perangkat kita. Deskriptor ini dihasilkan di Alat Deskriptor HID . Ada beberapa contoh untuk belajar mandiri. Secara umum, inilah deskriptor saya. Belum ada data untuk ditampilkan, untuk kemudahan pemahaman, tetapi semua tombol dan sumbu joystick ada. Itu harus ditempatkan di file usbd_custom_hid_if.c. Secara default, pegangan ini membuat kubus kosong.

Penjelasan HID (ukuran 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 */ }; 


Bahkan, itu dapat dikomposisikan sesuka Anda, pertama-tama Anda mengatur parameter USAGE PAGE dan USAGE yang diperlukan, misalnya, sumbu USAGE (Throttle), dan kemudian setelah kata INPUT (Data, Var, Abs), sistem akan mengasumsikan bahwa kita memiliki sumbu "Gas". Dimensi sumbu variabel dan jumlahnya ditentukan oleh parameter LOGICAL_MAXIMUM, MINIMUM, REPORT_SIZE, REPORT_COUNT, yang harus sebelum INPUT.

Rincian lebih lanjut tentang parameter ini, serta apa (Data, Var, Abs) dapat ditemukan di Definisi Kelas Perangkat untuk Perangkat Antarmuka Manusia (HID) v1.11 .

Berikut ini adalah contoh menginisialisasi sumbu Throttle dari deskriptor saya. Dalam contoh ini, Throttle memiliki rentang nilai 0-65535, yang sesuai dengan satu variabel uint16_t.

  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) 

Dan ya, katakanlah Anda tidak dapat menulis LOGICAL_MAXIMUM, MINIMUM, REPORT_SIZE, REPORT_COUNT setiap kali, tuan rumah akan menentukan nilai ini dengan parameter sebelumnya. Ini diilustrasikan oleh sumbu yang berjalan satu demi satu, tanpa menentukan ukuran dan nomor:

  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) 

Struktur berikut sesuai dengan semua deskriptor ini, yang lebih tinggi di bawah spoiler. Faktanya, itu tidak lagi wajib, hanya saja lebih nyaman untuk merekam berdasarkan petunjuk.

 #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; 

Struktur ini dapat dikirim ke tuan rumah oleh fungsi

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

Parameter pertama adalah pegangan USB, sudah dibuat di kubus kami. Anda mungkin perlu memasukkan file yang diperlukan dengan menyertakan di mana pegangan ini diinisialisasi untuk pertama kalinya dan menulis eksternal USBD_HandleTypeDef hUsbDeviceFS; sehingga kamu bisa bekerja dengannya. Parameter kedua adalah pointer ke struktur kita dan yang ketiga adalah ukuran struktur dalam byte.

Setelah mengisi dan mem-flash controller, Anda akan melihat sesuatu USB bergerak perlahan. Data dari panel kami tidak diperbarui dengan cepat. Agar cepat, dalam file usbd_customhid.h Anda perlu mengubah #define CUSTOM_HID_EPIN_SIZE ke nilai maksimum 0x40, #define CUSTOM_HID_EPOUT_SIZE juga menetapkan 0x40. Dalam file usbd_customhid.c, cari komentar di deskriptor endpoint "/ * bInterval: Polling Interval (20 ms) * /" dan ubah byte deskriptor menjadi 0x01 untuk setiap endpoint, hanya dua kali. Yang akan sesuai dengan pertukaran data 1 ms.


Seharusnya seperti ini. Perangkat standar tanpa menginstal driver apa pun

Secara umum, fungsi manajemen sedikit dipahami. Ini cukup mudah dilakukan dan semua tombol dan kapak sudah bekerja. Tetap membuat tampilan berfungsi. Saya melakukannya, sekitar enam bulan, dan selama setengah tahun panel telah mengumpulkan debu dalam sebuah kotak panjang. Tidak ada waktu Oleh karena itu, saya memutuskan untuk mengeluarkan artikel dalam bentuk ini, jika tidak maka risikonya tidak akan keluar.

Dengan tampilan, semuanya sama dengan sumbu. Bagi mereka, kita perlu melengkapi deskriptor HID perangkat kita, cukup tunjukkan bahwa ini adalah tampilan dan alih-alih menerima data Input, tuan rumah akan mengirim data Output.

Pegangan perangkat HID telah tumbuh secara signifikan. Di sini saya telah menerapkan parameter ID Laporan agar tidak menyumbat buffer pengiriman / terima dan titik akhir dengan data lengkap dan untuk membedakan jenis telegram yang telah kami terima. ID Laporan adalah byte uint8_t dengan nilai yang muncul di awal telegram. Nilai yang kami atur di deskriptor perangkat HID.

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) 

Output diproses dalam fungsi int8_t statis CUSTOM_HID_OutEvent_FS (uint8_t event_idx, status uint8_t) , yang, secara default, terletak di usbd_custom_hid_if.c.

static 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 */ } 


Tetap menulis program pada PC yang mengirimkan laporan yang diperlukan untuk mengarahkan tampilan. Namun, untuk memeriksa kode MK, program hebat dari ST: USB HID Demonstrator cocok. Ini memungkinkan Anda untuk mengirim laporan dari PC dengan konten apa pun.


Tes tampilan LED

Pada tahap ini, saya sudah selesai sejauh ini. Dan tidak diketahui apakah saya akan mulai lagi.

Dimainkan dalam simulator lebih menarik daripada dengan keyboard. Tetapi tidak begitu banyak sehingga ada efek wow langsung. Keyboardnya, juga terlihat seperti panel kontrol. Tetapi mengendalikan as roda joystick, paling tidak, tidak biasa. Merasa seperti astronot. Benar, pakaian antariksa diperlukan untuk perendaman total.

Saya harap Anda tertarik. Ada kesalahan ketik, ketidakakuratan, dan delusi. Mereka yang ingin menggali lebih dalam kode dapat melihat di sini .

Salam

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


All Articles