USB Host Shield 通过USB Hub 连接多个键盘

2022-03-212.6万
精华项目
AI 快速预览详细 收起
本文介绍了如何使用 USB Host Shield 通过 USB Hub 连接多个键盘。首先,建议运行 USB_Host_Shield_Library_2.0\examples\hub_demo 示例代码进行测试,确保硬件正常工作。然后,编写 KBUnderHub.ino 代码来获取按键信息。代码中声明了三个键盘设备 kb1 到 kb3,并定义了一些结构体来存储每个键盘的数据。通过这种方式,可以分别获得三个设备产生的按键信息。
USB Host Shield 本身是支持USBHub的,这样我们可以方便的一次性连接多个USB设备。这次以USB键盘为例进行测试。
USB Hub 的使用还是比较简单的,连接好之后,建议运行 USB_Host_Shield_Library_2.0\examples\hub_demo 这个示例代码进行测试,它会枚举当前USBHub上的所有 USB 设备的描述符信息,通过这样的方法我们可以知道硬件是否能够工作正常。
前述代码测试通过后,我们就可以编写代码来获得按键信息了。
1. KBUnderHub.ino 代码中必须使用 USBHub ,之后,因为测试有3个键盘,所以要声明 kb1 kb3 三个设备
  1. USB Usb;
  2. USBHub     Hub(&Usb);
  3. KBSET kb1(&Usb);
  4. KBSET kb2(&Usb);
  5. KBSET kb3(&Usb);
复制代码
2. KeyboardSets.h 代码中,申明一些我们需要的结构体如下:

  1. // 当前支持的键盘数量
  2. #define KBNUM 3
  3. class KBSET : public HIDUniversal {
  4.   public:
  5.     KBSET(USB *p) : HIDUniversal(p) {};
  6.     bool connected() {
  7.       return HIDUniversal::isReady();
  8.     };
  9.     // 本次收到数据的键盘编号
  10.     uint8_t  Current;
  11.     // 存放第x个键盘是否有改变发生的标记
  12.     bool     Changed[KBNUM];
  13.     // 存放第x个键盘当前收到的缓冲区长度
  14.     uint8_t  BufferSize[KBNUM];
  15.     // 存放第x个键盘收到的缓冲区数据
  16.     uint8_t  Buffer[KBNUM][64];
  17.     // 存放第x个键盘的PID 和 VID
  18.     uint16_t PID[KBNUM];
  19.     uint16_t VID[KBNUM];
  20.   private:
  21.     void ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); // Called by the HIDUniversal library
  22.     uint8_t  BufferSizeOld[KBNUM];
  23.     uint8_t  BufferOld[KBNUM][64];
  24.     // 当前收到的键盘数据总数
  25.     uint8_t  TotolKB;
  26.     uint8_t OnInitSuccessful() { // Called by the HIDUniversal library on success
  27.       KBSET::TotolKB = 0;
  28.       for (uint8_t j = 0; j < KBNUM; j++) {
  29.         for (uint8_t i = 0; i < 64; i++) {
  30.           KBSET::BufferOld[j][i]=0xFF;
  31.         }
  32.       }
  33.       return 0;
  34.     };
  35. };
复制代码
3. KeyboardSets.cpp
  1. #include "KeyboardSets.h"
  2. void KBSET::ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
  3.   /*
  4.     if (len && buf)  {
  5.       Notify(PSTR("\r\n"), 0x80);
  6.       for (uint8_t i = 0; i < len; i++) {
  7.         D_PrintHex<uint8_t > (buf[i], 0x80);
  8.         Notify(PSTR(" "), 0x80);
  9.       }
  10.     }
  11.   */
  12.   // 在 KBSET 中查找记录
  13.   KBSET::Current = 0xFF;
  14.   for (uint8_t i = 0; i < KBNUM; i++) {
  15.     //
  16.     if ((KBSET::PID[i] == HIDUniversal::PID) && (KBSET::VID[i] == HIDUniversal::VID)) {
  17.       KBSET::Current = i;
  18.     }
  19.   }
  20.   // 如果查找不到
  21.   if (KBSET::Current == 0xFF) {
  22.     KBSET::Current = KBSET::TotolKB;
  23.     KBSET::PID[KBSET::Current] = HIDUniversal::PID;
  24.     KBSET::VID[KBSET::Current] = HIDUniversal::VID;
  25.     KBSET::BufferSize[KBSET::Current] = len;
  26.     KBSET::TotolKB++;
  27.   }
  28.   // 检查本次数据和上次数据是否有差别
  29.   if (memcmp(BufferOld[KBSET::Current], buf, len) == 0) {
  30.     // 没有差别
  31.     KBSET::Changed[KBSET::Current] = false;
  32.   } else {
  33.     memcpy(Buffer[KBSET::Current], buf, len);
  34.     // 有差别
  35.     KBSET::Changed[KBSET::Current] = true;
  36.     memcpy(BufferOld[KBSET::Current], buf, len);
  37.     Serial.print("VID:"); Serial.print(KBSET::VID[KBSET::Current],HEX);
  38.     Serial.print(" PID:"); Serial.println(KBSET::PID[KBSET::Current],HEX);
  39.     for (uint8_t i = 0; i < KBSET::BufferSize[KBSET::Current]; i++) {
  40.       Serial.print((byte)(KBSET::Buffer[KBSET::Current][i]), HEX);
  41.       Serial.print(" ");
  42.     }
  43.     Serial.println("");
  44.   }
  45. }
复制代码

工作流程:当有按键事件发生时,库会调用 ParseHIDData() 这个函数,从设备获得的设备数据放在buf,产生数据的设备PID VID HIDUniversal::PIDHIDUniversal::VID中。之后,我们会在KBSET::PIDVID数组中查找当前产生数据的设备是否已存在,如果没有话,将这个设备的PIDVID 加入数组中。之后再将改设备产生的数据存放到Buffer中。之后,再判断新取得的数据和之前的BufferOld中保存的是否相同,如果相同就打印输出。
这样,我们就能分别获得三个设备产生的按键信息。
我是用了一个大键盘,一个小键盘和一个barcodescanner 作为测试设备,可以看到串口能够输出。







创作许可协议

本项目采用 None(不开放任何权利,保留所有权利) 进行许可。

评论(1)
lrj0331
lrj0331
hello啊,请问usb host shield上的usb端口名称叫什么呢?
- 没有更多了 -