一个最简的 USB HID(Keyboard) 示例 [使用STM32F3 Discovry]

[复制链接]
8876|8
 楼主| lxyppc 发表于 2013-6-13 17:15 | 显示全部楼层 |阅读模式
使用 USB 协议栈框架做的最简洁的 HID 示例,基于Lee老师的这个例子修改而来 。
hid.zip (3.28 KB, 下载次数: 97) 附件中是生成的 hex 文件,可以运行在STM32F3 Discovry上,烧写使用ST-Link Utility。使用USER按键启动“我的电脑”。
代码空间开销:
  1.    text    data     bss     dec     hex filename
  2.    2948       0     324    3272     cc8 out/hid.elf
flash 占用 3.2K。上程序:
  1. #include <usbd/hal/stmfsmicro.hpp>                              // USB HAL(Hardware Abstract Layer),STM32
  2. #include <usbd/hid.hpp>                                         // USB HID Class
  3. #include <stm32/stm32f30x/flash.hpp>
  4. #include <stm32/stm32f30x/exti.hpp>

  5. using namespace usbd;                                        // 使用 usb 名空间
  6. using namespace hid;                                        // 使用 hid 名空间
  7. using namespace sfr::exti;
  8. using namespace sfr::flash;

  9. template<typename PARENT, uint32_t PARAM>                   // 定式
  10. class ep_t : public in::ep_impl_t<                          // 定义 Endpoint 类
  11.             ep_t, PARENT, PARAM,                            // 定式
  12.             10                                              // 指定 bInterval
  13.         > { };

  14. template<typename PARENT, uint32_t PARAM>                   // 定式
  15. class if_t : public if_impl_t<                              // 定义 Interface 类
  16.             if_t, PARENT, PARAM,                            // 定式
  17.             0,                                              // 指定 bInterfaceSubClass
  18.             1,                                              // 指定 bInterfaceProtocol
  19.             0,                                              // 指定 String ID
  20.             0x110,                                          // 指定 bcdHID
  21.             0,                                              // 指定 bCountryCode
  22.             optional_t<                                     // 定义 hid optional descriptor
  23.                 report_t<                                   // 定义 hid report descriptor
  24.                     usage_page_t<CONSUMER_DEVICE>,          // 0x05, 0x0C,      //  Usage Page (Consumer Devices),
  25.                     usage_t<1>,                             // 0x09, 0x06,      //  Usage (Consumer Control),
  26.                     collection_t<APPLICATION,               // 0xA1, 0x01,      //  Collection (Application),
  27.                         logical_extremum_t<0, 1>,           // 0x15, 0x00,      //      Logical Minimum (0),
  28.                                                             // 0x25, 0x65,      //      Logical Maximum (101),
  29.                         report_size_t<1>,                   // 0x75, 0x08,      //      Report Size (1),
  30.                         report_count_t<2>,                  // 0x95, 0x01,      //      Report Count (2),
  31.                         usage_t<0x23, 2>,                   // 0x0A, 0x23, 0x02,//      USAGE (0x223),      // WWW Browser
  32.                         usage_t<0x94, 1>,                   // 0x0A, 0x94, 0x01,//      USAGE (0x194),      // My Computer
  33.                         input_t<DATA, VARIABLE, ABSOLUTE>,  // 0x81, 0x02,      //      Input (Data, Variable, Absolute),
  34.                         report_count_t<6>,                  // 0x95, 0x07,      //      Report Count (6),
  35.                         input_t<CONSTANT>                   // 0x81, 0x01,      //      Input (Constant)
  36.                     >                                       // 0xC0         //  End Collection
  37.                 >
  38.             >,
  39.             ep_t                                            // 指定本 Interface 包含的 Endpoint
  40.         > {
  41. public:
  42.     __INLINE void config()          // Interface 初始化,当 Set Configuration 时被调用
  43.     {
  44.         if_t::if_impl_t::config();  // 使用默认的 config 处理
  45.         // TODO
  46.         RCC.AHBENR().IOPAEN(1);
  47.         // Set GPIOA.0 as input
  48.         GPIOA.MODER().MODER0(GPIO_Mode_IN);
  49.         GPIOA.PUPDR().PUPDR0(GPIO_PuPd_NOPULL);
  50.         
  51.         // Enable interrupt of EXTI0
  52.         NVIC->IP[EXTI0_IRQn] = (3<<2) | 0;
  53.         NVIC->ISER[EXTI0_IRQn >> 0x05] =
  54.         (uint32_t)0x01 << (EXTI0_IRQn & (uint8_t)0x1F);
  55.         // Enable EXTI0 rising and falling edge interrupt
  56.         EXTI.IMR1().MR0(1);
  57.         EXTI.RTSR1().TR0(1);
  58.         EXTI.FTSR1().TR0(1);
  59.     }
  60. };

  61. class usbd_t : public core::usbd_impl_t<        // 定义 USB 类
  62.         usbd_t,                                 // 定式
  63.         0x110,                  // bcdUSB
  64.         0,                      // bDeviceClass
  65.         0,                      // bDeviceSubClass
  66.         0,                      // bDeviceProtocol
  67.         0x0416,                 // idVendor
  68.         0x5011,                 // idProduct
  69.         0x100,                  // bcdDevice
  70.         1,                      // iManufacture
  71.         2,                      // iProduct
  72.         3,                      // iSerialNumber
  73.         true,                   // bmAttributes, Bus Powered
  74.         false,                  // bmAttributes, Self Powered
  75.         false,                  // bmAttributes, Remote Wakeup
  76.         10_mA,                  // bMaxPower
  77.         0,                      // iConfiguration
  78.         if_t> {                 // 指定 usb 包含的 Interface,可连续加入多个 Function 和 Interface

  79. public:
  80.     __INLINE usbd_t() { }

  81. #if 1
  82.     __INLINE bool data_out(uint_fast8_t type, uint_fast8_t request, uint_fast16_t value, uint_fast16_t index, uint_fast16_t length)
  83.     {
  84.         out();
  85.         return true;
  86.     }
  87.     __INLINE bool data_in(uint_fast8_t type, uint_fast8_t request, uint_fast16_t value, uint_fast16_t index, uint_fast16_t length)
  88.     {
  89.         in();
  90.         return true;
  91.     }
  92. #endif

  93.     __INLINE const uint8_t* get_string_descriptor(uint_fast8_t index, uint_fast16_t lang_id)    // GetDescriptor(String) 处理
  94.     {
  95.         static const string_langid_t<langid_t::English_UnitedStates> desc0;
  96.         static const string_t<u'j', u'.', u'y', u'.', u'l', u'e', u'e', u'@', u'y', u'e', u'a', u'h', u'.', u'n', u'e', u't'> desc1;
  97.         static const string_t<u'U', u'S', u'B', u' ', u'渭', u'K', u'e', u'y'> desc2;
  98.         static const string_t<u'0', u'0', u'0', u'0'> desc3;
  99.         static const uint8_t* const descriptor[] {
  100.             reinterpret_cast<const uint8_t*>(&desc0),
  101.             reinterpret_cast<const uint8_t*>(&desc1),
  102.             reinterpret_cast<const uint8_t*>(&desc2),
  103.             reinterpret_cast<const uint8_t*>(&desc3)
  104.         };
  105.         return index < sizeof(descriptor) / sizeof(descriptor[0]) ? descriptor[index] : nullptr;
  106.     }
  107. };

  108. usbd_t usbdx;                // 定义 USB 类对象

  109. extern "C"  void USB_LP_CAN1_RX0_IRQHandler(void){
  110.         usbdx.isr();
  111. }

  112. extern "C" void SystemInitHpp(void)
  113. {
  114.     // set system clock to 72MHz
  115.     RCC.CR().HSEBYP(1).HSEON(1);
  116.     while(! RCC.CR().HSERDY );
  117.     FLASH.ACR().PRFTBE(1).LATENCY(2);
  118.     RCC.CFGR().HPRE(0).PPRE2(0).PPRE1(1).PLLSRC(1).PLLMUL(9-2).PLLXTPRE(0);
  119.     RCC.CR().PLLON(1);
  120.     while(! RCC.CR().PLLRDY);
  121.     RCC.CFGR().SW(2);
  122.     while( RCC.CFGR().SWS != 2 );
  123. }

  124. extern "C" void EXTI0_IRQHandler(void)
  125. {
  126.     static uint8_t code;
  127.     EXTI.PR1().PR0(1);
  128.     if(GPIOA.IDR().IDR0){
  129.         code = 2;
  130.     }else{
  131.         code = 0;
  132.     }
  133.     get_if<0>(usbdx).write(&code, sizeof(code));
  134. }

  135. extern "C" int main()
  136. {
  137.     usbdx.open(true);        // 初始化 usb 对象
  138.     while (true);
  139. }

  140. extern "C" {
  141.     void abort(void){
  142.         
  143.     }
  144. }
  145.    
  146.    
  147.    


 楼主| lxyppc 发表于 2013-6-13 17:22 | 显示全部楼层
沙发自己坐
mmuuss586 发表于 2013-6-13 17:38 | 显示全部楼层
chen282220981 发表于 2013-6-13 17:41 | 显示全部楼层
先下来看看
缥缈九哥 发表于 2013-6-13 19:29 | 显示全部楼层
elec921 发表于 2013-6-13 19:57 | 显示全部楼层
牛X。USB 是个好东西
cjhk 发表于 2013-6-13 21:59 | 显示全部楼层
学习一下   谢谢了   楼主  顶一个   很不错哦     顶一个
john_lee 发表于 2013-6-13 22:20 | 显示全部楼层
  1. get_if<0>(usbdx).write(&code, sizeof(code));
这里给出的模板参数 0,是直接按序号取得 usb 对象中的 interface 的引用的访问方式,觉得不友好,可以改成按 interface 的名字来访问:
  1. static_cast<usbd_t::if_t>(usbdx).write(&code, sizeof(code));
是不是要好些?
cailantu 发表于 2013-8-30 14:27 | 显示全部楼层
感谢楼主分享如此好东西
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:代码发BBS不好看?你需要它 代码着色https://bbs.21ic.com/icview-135254-1-1.html

27

主题

2249

帖子

19

粉丝
快速回复 在线客服 返回列表 返回顶部