• STM32 USB-HID通信移植步骤


    大家可以使用压缩包中的UsbApp.exe调试本软件idVendor为:0483  idProduct为5750。

    今天太晚了,明天还要上半天班,上位机软件找个时间在写一篇文章。请关注我的博客。压缩包中附带了几个编译软件典型的上位机源代码,大家可以参考下。

    本文中源程序的下载网址为:http://download.csdn.net/source/2918553

     

           很久没写过文章了,趁今晚有空出来露一下。最近发现很多人对STM32的USB通信很感兴趣。要将USB的通信协议搞懂确实是一个比较漫长的过程。但是USB的HID通信无论是上位机的设计还是STM32程序的编程都非常的简单。只是我想很多人都不知道而已。这篇文章的目的是让大家以最短的时间将USB加到你的设备中。如果想学得更深就靠大家。

           HID只是适合低速传输,其理论上可以达到64KB/S,但多由于windows系统和硬件的关系一般达不到这个传输数度。但这个速度对于一般系统的控制和数据传输都已经足够了,而且是免驱,省去了很多麻烦。如果您需要高速传输可参考我的另外一篇文章《STM32的USB例程修改步骤》文章在http://blog.csdn.net/cy757/archive/2010/01/01/5117610.aspx

    一、安装完MDK后请打开C:/Keil/ARM/Examples/ST/STM32F10xUSBLib/Demos路径,将Custom_HID在同一个目录下复制一份,如果你要放到其他路径你需要在MDK Options for target的C/C++中添加USB的头文件路径(MDK下的/INC/ST/STM32F10x/USB)。

    二、打开usb_desc.c文件,该文件主要包含的端点描述符、设备描述符、配置描述符和字符描述符等。具体请大家参考其他资料了,这里主要说几个常用。

    u8 DeviceDescriptor[SIZ_DEVICE_DESC]为USB设备描述符。当中的

    0x83,                       /*idVendor (0x0483)*/

    0x04,

    0x50,                       /*idProduct = 0x5750*/

    0x57,

    //idVender字段。厂商ID号,我们这里取0x0483,仅供实验用。

    //实际产品不能随便使用厂商ID号,必须跟USB协会申请厂商ID号。

    //注意小端模式,低字节在先。

    //idProduct字段。产品ID号,我们这里取0x5750。

    //注意小端模式,低字节应该在前。

    const u8 ConfigDescriptor[SIZ_CONFIG_DESC]是配置描述符,注意如下

        USB_ENDPOINT_DESCRIPTOR_TYPE, /* bDescriptorType: */

        0x81,          /* bEndpointAddress: Endpoint Address (IN) */

        0x03,          /* bmAttributes: Interrupt endpoint */

        0x02,          /* wMaxPacketSize: 2 Bytes max */

        0x00,

        0x20,          /* bInterval: Polling Interval (32 ms) */

        /* 34 */

           

        0x07,   /* bLength: Endpoint Descriptor size */

        USB_ENDPOINT_DESCRIPTOR_TYPE,       /* bDescriptorType: */

                      /*    Endpoint descriptor type */

        0x01,   /* bEndpointAddress: */

                      /*    Endpoint Address (OUT) */

        0x03,   /* bmAttributes: Interrupt endpoint */

        0x02,   /* wMaxPacketSize: 2 Bytes max  */

        0x00,

    0x20,  /* bInterval: Polling Interval (20 ms) */

    上面包含了“输入端点描述符”和“输出端点描述符”。

    //wMaxPacketSize字段。该端点的最大包长。

    //bInterval字段。端点查询的时间,

    为了实现更高速的通信我们修改如下:

        /******************** Descriptor of  endpoint ********************/

        /* 27 */

        0x07,          /*bLength: Endpoint Descriptor size*/

        USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/

        0x81,          /*bEndpointAddress: Endpoint Address (IN)*/

        0x03,          /*bmAttributes: Interrupt endpoint*/

        0x40,          /*wMaxPacketSize: 64 Byte max */

        0x00,

        0x0A,          /*bInterval: Polling Interval (10 ms)*/

        /* 34 */

        /******************** Descriptor of  endpoint ********************/

        /* 27 */

        0x07,          /*bLength: Endpoint Descriptor size*/

        USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/

        0x01,          /*bEndpointAddress: Endpoint Address (OUT)*/

        0x03,          /*bmAttributes: Interrupt endpoint*/

        0x40,          /*wMaxPacketSize: 64 Byte max */

        0x00,

        0x0A,          /*bInterval: Polling Interval (10 ms)*/

    const u8 ReportDescriptor[SIZ_REPORT_DESC]为HID专用的报告描述符,具体的大家就参考资料了,这里可以直接复制了。

    const u8 CustomHID_ReportDescriptor[CUSTOMHID_SIZ_REPORT_DESC] =

      {

        0x05, 0xFF,                    // USAGE_PAGE(User define)

        0x09, 0xFF,                    // USAGE(User define)

        0xa1, 0x01,                    // COLLECTION (Application)

        0x05, 0x01,                    // USAGE_PAGE(1)

        0x19, 0x00,                    //   USAGE_MINIMUM(0)

        0x29, 0xFF,                    //   USAGE_MAXIMUM(255)

        0x15, 0x00,                    //   LOGICAL_MINIMUM (0)

        0x25, 0xFF,                    //   LOGICAL_MAXIMUM (255)

        0x75, 0x08,                    //   REPORT_SIZE (8)

        0x95, 0x40,                    //   REPORT_COUNT (64)

        0x81, 0x02,                    //   INPUT (Data,Var,Abs)

        0x05, 0x02,                    // USAGE_PAGE(2)

        0x19, 0x00,                    //   USAGE_MINIMUM (0)

        0x29, 0xFF,                    //   USAGE_MAXIMUM (255)

        0x15, 0x00,                    //   LOGICAL_MINIMUM (0)

        0x25, 0xFF,                    //   LOGICAL_MAXIMUM (255)

        0x95, 0x08,                    //   REPORT_COUNT (8)

        0x75, 0x40,                    //   REPORT_SIZE (64)

        0x91, 0x02,                    //   OUTPUT (Data,Var,Abs)

        0xc0                           // END_COLLECTION

      }; /* ReportDescriptor */

    const u8 CustomHID_StringVendor[CUSTOMHID_SIZ_STRING_VENDOR]

    const u8 StringProduct[SIZ_STRING_PRODUCT]

    const u8 StringSerial[SIZ_STRING_SERIAL]

    分别是“厂商字符”、“产品字符”、“产品序列号”,这些将在USB HID设备加载的时候显示。但是这需要这些字符要求为Unicode编码,你需要将你要显示的字符先转为Unicode编码。你可以到http://computer00.21ic.org/user1/2198/archives/2007/42769.html转换。最好大家还要根据各个数组的长度修改如下定义。

    #define CUSTOMHID_SIZ_REPORT_DESC               39

    #define CUSTOMHID_SIZ_STRING_VENDOR             64

    #define CUSTOMHID_SIZ_STRING_PRODUCT            28

    #define CUSTOMHID_SIZ_STRING_SERIAL             26

    三、打开hw_config.c文件,将那些没有的函数删除,只保留如下函数

    a)         Set_System(void)

    b)        void Set_USBClock(void)

    c)        void USB_Interrupts_Config(void)

    d)        void USB_Cable_Config (FunctionalState NewState)

    特别要注意最后一个函数,其主要作用是控制USB的上拉电阻,让电脑检测USB设备是否连接的。

    四、打开stm32f10x_it.c文件,把EXTI15_10_IRQHandler等中断内的代码删除。

    打开usb_prop.c文件,修改如下:

    void CustomHID_Reset(void)

    {

      /* Set Joystick_DEVICE as not configured */

      pInformation->Current_Configuration = 0;

      pInformation->Current_Interface = 0;/*the default Interface*/

      SetBTABLE(BTABLE_ADDRESS);

      /* Initialize Endpoint 0 */

      SetEPType(ENDP0, EP_CONTROL);

      SetEPTxStatus(ENDP0, EP_TX_STALL);

      SetEPRxAddr(ENDP0, ENDP0_RXADDR);

      SetEPTxAddr(ENDP0, ENDP0_TXADDR);

      Clear_Status_Out(ENDP0);

      SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);

      SetEPRxValid(ENDP0);

      /* Initialize Endpoint 1 */

      SetEPType(ENDP1, EP_INTERRUPT);

      SetEPTxAddr(ENDP1, ENDP1_TXADDR);

      SetEPTxCount(ENDP1, 64);

      SetEPRxStatus(ENDP1, EP_RX_DIS);

      SetEPTxStatus(ENDP1, EP_TX_NAK);

      /* Initialize Endpoint 1 */

     // SetEPType(ENDP1, EP_INTERRUPT);

      SetEPRxAddr(ENDP1, ENDP1_RXADDR);

      SetEPRxCount(ENDP1, 64);

     // SetEPTxStatus(ENDP1, EP_TX_DIS);

      SetEPRxStatus(ENDP1, EP_RX_VALID);

      /* Set this device to response on default address */

      SetDeviceAddress(0);

    }

    五、usb_endp.c文件

    void EP1_OUT_Callback(void)

    {

           这些写接收代码

    }

    六、数据发送和接收,举例说明

    1、数据接收

    u8 DataLen;

      DataLen = GetEPRxCount(ENDP1);

      PMAToUserBufferCopy(TX1_buffer, ENDP1_RXADDR, DataLen);

      SetEPRxValid(ENDP1);

      USART1_Send(DataLen);

      count_out = 1;

    2、数据发送

    UserToPMABufferCopy(InBuffer, GetEPTxAddr(ENDP1), 64);

    SetEPTxCount(ENDP1, 64);                    

    SetEPTxValid(ENDP1);

    如果你发送数据较为频繁,每次发送前应使用GetEPTxStatus(ENDP1)检测上次发送是否完成。如果端点状态处于EP_TX_VALID,说明发送未结束,如果端点状态处于EP_TX_NAK,说明发送结束。

  • 相关阅读:
    Android后台保活实践总结:即时通讯应用无法根治的“顽疾”
    新手入门:史上最全Web端即时通讯技术原理详解
    【原创】NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战
    【原创】NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战
    【原创】NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示
    【原创】NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示
    爱奇艺技术分享:轻松诙谐,讲解视频编解码技术的过去、现在和将来
    网络编程懒人入门(十二):快速读懂Http/3协议,一篇就够!
    美团点评的移动端网络优化实践:大幅提升连接成功率、速度等
    IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总
  • 原文地址:https://www.cnblogs.com/skl374199080/p/3966305.html
Copyright © 2020-2023  润新知