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

USB Host Shield 本身是支持USB Hub的,这样我们可以方便的一次性连接多个USB 设备。这次以USB 键盘为例进行测试。

USB Hub 的使用还是比较简单的,连接好之后,建议运行 USB_Host_Shield_Library_2.0\examples\hub_demo 这个示例代码进行测试,它会枚举当前USB Hub上的所有 USB 设备的描述符信息,通过这样的方法我们可以知道硬件是否能够工作正常。

前述代码测试通过后,我们就可以编写代码来获得按键信息了。

1. KBUnderHub.ino 代码中必须使用 USBHub ,之后,因为测试有3个键盘,所以要声明 kb1 到 kb3 三个设备

USB Usb;

USBHub Hub(&Usb);

KBSET kb1(&Usb);

KBSET kb2(&Usb);

KBSET kb3(&Usb);

2. KeyboardSets.h 代码中,申明一些我们需要的结构体如下:

// 当前支持的键盘数量
#define KBNUM 3

class KBSET : public HIDUniversal {
  public:
    KBSET(USB *p) : HIDUniversal(p) {};
    bool connected() {
      return HIDUniversal::isReady();
    };
    // 本次收到数据的键盘编号
    uint8_t  Current;
    // 存放第x个键盘是否有改变发生的标记
    bool     Changed[KBNUM];
    // 存放第x个键盘当前收到的缓冲区长度
    uint8_t  BufferSize[KBNUM];
    // 存放第x个键盘收到的缓冲区数据
    uint8_t  Buffer[KBNUM][64];
    // 存放第x个键盘的PID 和 VID
    uint16_t PID[KBNUM];
    uint16_t VID[KBNUM];
  private:
    void ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); // Called by the HIDUniversal library
    uint8_t  BufferSizeOld[KBNUM];
    uint8_t  BufferOld[KBNUM][64];
    // 当前收到的键盘数据总数
    uint8_t  TotolKB;
    uint8_t OnInitSuccessful() { // Called by the HIDUniversal library on success
      KBSET::TotolKB = 0;
      for (uint8_t j = 0; j < KBNUM; j++) {
        for (uint8_t i = 0; i < 64; i++) {
          KBSET::BufferOld[j][i]=0xFF;
        }
      }
      return 0;
    };
};

3. KeyboardSets.cpp

#include "KeyboardSets.h"

void KBSET::ParseHIDData(USBHID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
  /*
    if (len && buf)  {
      Notify(PSTR("\r\n"), 0x80);
      for (uint8_t i = 0; i < len; i++) {
        D_PrintHex<uint8_t > (buf[i], 0x80);
        Notify(PSTR(" "), 0x80);
      }
    }
  */

  // 在 KBSET 中查找记录
  KBSET::Current = 0xFF;
  for (uint8_t i = 0; i < KBNUM; i++) {
    //
    if ((KBSET::PID[i] == HIDUniversal::PID) && (KBSET::VID[i] == HIDUniversal::VID)) {
      KBSET::Current = i;
    }
  }
  // 如果查找不到
  if (KBSET::Current == 0xFF) {
    KBSET::Current = KBSET::TotolKB;
    KBSET::PID[KBSET::Current] = HIDUniversal::PID;
    KBSET::VID[KBSET::Current] = HIDUniversal::VID;
    KBSET::BufferSize[KBSET::Current] = len;
    KBSET::TotolKB++;
  }

  // 检查本次数据和上次数据是否有差别
  if (memcmp(BufferOld[KBSET::Current], buf, len) == 0) {
    // 没有差别
    KBSET::Changed[KBSET::Current] = false;
  } else {
    memcpy(Buffer[KBSET::Current], buf, len);
    // 有差别
    KBSET::Changed[KBSET::Current] = true;
    memcpy(BufferOld[KBSET::Current], buf, len);
    Serial.print("VID:"); Serial.print(KBSET::VID[KBSET::Current],HEX);
    Serial.print(" PID:"); Serial.println(KBSET::PID[KBSET::Current],HEX);
    for (uint8_t i = 0; i < KBSET::BufferSize[KBSET::Current]; i++) {
      Serial.print((byte)(KBSET::Buffer[KBSET::Current][i]), HEX);
      Serial.print(" ");
    }
    Serial.println("");
  }
}

工作流程:当有按键事件发生时,库会调用 ParseHIDData() 这个函数,从设备获得的设备数据放在buf,产生数据的设备PID和 VID 在HIDUniversal::PID和HIDUniversal::VID中。之后,我们会在KBSET::PID VID数组中查找当前产生数据的设备是否已存在,如果没有话,将这个设备的PID和VID 加入数组中。之后再将改设备产生的数据存放到Buffer 中。之后,再判断新取得的数据和之前的BufferOld中保存的是否相同,如果相同就打印输出。

这样,我们就能分别获得三个设备产生的按键信息。

我是用了一个大键盘,一个小键盘和一个barcode scanner 作为测试设备,可以看到串口能够输出。

工作测试的视频:

https://www.bilibili.com/video/BV1nu411q7i7?share_source=copy_web

完整代码下载:

使用 MAX3421e 一个潜在的风险是:芯片本身价格高,比如前一段这个芯片价格炒到50以上,并且有假货。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注