查看: 37945|回复: 55

STM32自定义USB设备开发详细流程讲解及全套资料源码下载

  [复制链接]
  • TA的每日心情

    2017-11-2 11:47
  • 签到天数: 105 天

    连续签到: 1 天

    [LV.6]常住居民II

    发表于 2015-8-21 12:49:36 | 显示全部楼层 |阅读模式
    分享到:
    前言
    USB的用途就不多说了,下面的内容主要就是讲解如何利用ST提供的USB驱动库和libusb上位机驱动库实现一个USB数据传输功能,为了降低开发难度,我们仅仅讲解Bulk传输模式,当然这也是用得比较多的传输模式。

    开发流程
    1,完成STM32单片机端的USB程序;
    2,利用linusb自带的inf-wizard工具生成USB驱动;
    3,基于libusb编写USB通信程序;
    4,测试PC和单片机的数据通信;

    STM32程序编写
    1,完成描述符的修改,修改后的描述符如下(在usb_desc.c文件中)
    设备描述符:
    1. <pre style="color: rgb(0, 0, 0); line-height: normal; widows: auto;">const uint8_t CustomHID_DeviceDescriptor[CUSTOMHID_SIZ_DEVICE_DESC] =
    2. {
    3.     0x12,                       /*bLength */
    4.     USB_DEVICE_DESCRIPTOR_TYPE, /*bDescriptorType*/
    5.     0x00,                       /*bcdUSB */
    6.     0x02,
    7.     0x00,                       /*bDeviceClass*/
    8.     0x00,                       /*bDeviceSubClass*/
    9.     0x00,                       /*bDeviceProtocol*/
    10.     0x40,                       /*bMaxPacketSize40*/
    11.     LOBYTE(USBD_VID),           /*idVendor*/
    12.     HIBYTE(USBD_VID),           /*idVendor*/
    13.     LOBYTE(USBD_PID),           /*idVendor*/
    14.     HIBYTE(USBD_PID),           /*idVendor*/
    15.     0x00,                       /*bcdDevice rel. 2.00*/
    16.     0x02,
    17.     1,                          /*Index of string descriptor describing manufacturer */
    18.     2,                          /*Index of string descriptor describing product*/
    19.     3,                          /*Index of string descriptor describing the device serial number */
    20.     0x01                        /*bNumConfigurations*/
    21. }; /* CustomHID_DeviceDescriptor */</pre>
    复制代码

    配置描述符:
    1. const uint8_t CustomHID_ConfigDescriptor[CUSTOMHID_SIZ_CONFIG_DESC] =
    2. {
    3.     0x09, /* bLength: Configuation Descriptor size */
    4.     USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
    5.     CUSTOMHID_SIZ_CONFIG_DESC,
    6.     /* wTotalLength: Bytes returned */
    7.     0x00,
    8.     0x01,         /* bNumInterfaces: 1 interface */
    9.     0x01,         /* bConfigurationValue: Configuration value */
    10.     0x00,         /* iConfiguration: Index of string descriptor describing
    11.                                  the configuration*/
    12.     0xE0,         /* bmAttributes: Bus powered */
    13.                   /*Bus powered: 7th bit, Self Powered: 6th bit, Remote wakeup: 5th bit, reserved: 4..0 bits */
    14.     0xFA,         /* MaxPower 500 mA: this current is used for detecting Vbus */
    15.     /************** Descriptor of Custom HID interface ****************/
    16.     /* 09 */
    17.     0x09,         /* bLength: Interface Descriptor size */
    18.     USB_INTERFACE_DESCRIPTOR_TYPE,/* bDescriptorType: Interface descriptor type */
    19.     0x00,         /* bInterfaceNumber: Number of Interface */
    20.     0x00,         /* bAlternateSetting: Alternate setting */
    21.     0x04,         /* bNumEndpoints */
    22.     0xDC,         /* bInterfaceClass: Class code = 0DCH */
    23.     0xA0,         /* bInterfaceSubClass : Subclass code = 0A0H */
    24.     0xB0,         /* nInterfaceProtocol : Protocol code = 0B0H */
    25.     0,            /* iInterface: Index of string descriptor */
    26.     /******************** endpoint descriptor ********************/
    27.     /* 18 */
    28.     0x07,         /* endpoint descriptor length = 07H */
    29.     USB_ENDPOINT_DESCRIPTOR_TYPE, /* endpoint descriptor type = 05H */
    30.     0x81,         /* endpoint 1 IN */
    31.     0x02,                                        /* bulk transfer = 02H */
    32.     0x40,0x00,    /* endpoint max packet size = 0040H */
    33.     0x00,         /* the value is invalid when bulk transfer */

    34.     0x07,         /* endpoint descriptor length = 07H */
    35.     USB_ENDPOINT_DESCRIPTOR_TYPE, /* endpoint descriptor type = 05H */
    36.     0x01,         /* endpoint 1 OUT */
    37.     0x02,                                        /* bulk transfer = 02H */
    38.     0x40,0x00,    /* endpoint max packet size = 0040H */
    39.     0x00,         /* the value is invalid when bulk transfer */
    40.                  
    41.     0x07,         /* endpoint descriptor length = 07H */
    42.     USB_ENDPOINT_DESCRIPTOR_TYPE, /* endpoint descriptor type = 05H */
    43.     0x82,         /* endpoint 2 IN */
    44.     0x02,                                        /* bulk transfer = 02H */
    45.     0x40,0x00,    /* endpoint max packet size = 0040H */
    46.     0x00,         /* the value is invalid when bulk transfer */
    47.                  
    48.     0x07,         /* endpoint descriptor length = 07H */
    49.     USB_ENDPOINT_DESCRIPTOR_TYPE, /* endpoint descriptor type = 05H */
    50.     0x02,         /* endpoint 2 OUT */
    51.     0x02,                                        /* bulk transfer = 02H */
    52.     0x40,0x00,    /* endpoint max packet size = 0040H */
    53.     0x00,         /* the value is invalid when bulk transfer */
    54. }; /* CustomHID_ConfigDescriptor */
    复制代码
    配置描述符就包含了端点描述符,我们用了4个端点,两个BULK-OUT端点,两个BULK-IN端点。

    其他的描述符:
    1. /* USB String Descriptors (optional) */
    2. const uint8_t CustomHID_StringLangID[CUSTOMHID_SIZ_STRING_LANGID] =
    3. {
    4.     CUSTOMHID_SIZ_STRING_LANGID,
    5.     USB_STRING_DESCRIPTOR_TYPE,
    6.     0x09,
    7.     0x04
    8. }; /* LangID = 0x0409: U.S. English */

    9. const uint8_t CustomHID_StringVendor[CUSTOMHID_SIZ_STRING_VENDOR] =
    10. {
    11.     CUSTOMHID_SIZ_STRING_VENDOR, /* Size of Vendor string */
    12.     USB_STRING_DESCRIPTOR_TYPE,  /* bDescriptorType*/
    13.     // Manufacturer: "STMicroelectronics"
    14.     'M', 0, 'y', 0, 'U', 0,'S', 0,'B', 0, '_', 0, 'H', 0,'I',0,'D',0
    15. };

    16. const uint8_t CustomHID_StringProduct[CUSTOMHID_SIZ_STRING_PRODUCT] =
    17. {
    18.     CUSTOMHID_SIZ_STRING_PRODUCT,          /* bLength */
    19.     USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
    20.     'B', 0, 'y', 0, ' ', 0, 'e', 0, 'm', 0, 'b', 0,'e',0,'d',0,'-',0,'n',0,'e',0,'t',0
    21. };
    22. uint8_t CustomHID_StringSerial[CUSTOMHID_SIZ_STRING_SERIAL] =
    23. {
    24.     CUSTOMHID_SIZ_STRING_SERIAL,           /* bLength */
    25.     USB_STRING_DESCRIPTOR_TYPE,        /* bDescriptorType */
    26.     'x', 0, 'x', 0, 'x', 0,'x', 0,'x', 0, 'x', 0, 'x', 0
    27. };
    复制代码
    2,根据端点缓冲区大小配置端点缓冲区地址,配置信息如下(在usb_conf.h文件中):
    1. /* buffer table base address */
    2. #define BTABLE_ADDRESS      (0x00)

    3. /* EP0  */
    4. /* rx/tx buffer base address */
    5. #define ENDP0_RXADDR        (0x18)
    6. #define ENDP0_TXADDR        (0x58)

    7. /* EP1  */
    8. /* tx buffer base address */
    9. //地址为32位对其,位4的倍数,不能超过 bMaxPacketSize
    10. //EP1
    11. #define ENDP1_RXADDR        (0x98)
    12. #define ENDP1_TXADDR        (0x98+64)
    13. ////EP2
    14. #define ENDP2_RXADDR        (0xA0+64+64)
    15. #define ENDP2_TXADDR        (0xA0+64+64+64)
    复制代码
    3,初始化每个端点(在usb_prop.c文件中的CustomHID_Reset函数中)
    1. /* Initialize Endpoint 0 */
    2. SetEPType(ENDP0, EP_CONTROL);
    3. SetEPTxStatus(ENDP0, EP_TX_STALL);
    4. SetEPRxAddr(ENDP0, ENDP0_RXADDR);
    5. SetEPTxAddr(ENDP0, ENDP0_TXADDR);
    6. Clear_Status_Out(ENDP0);
    7. SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);
    8. SetEPRxValid(ENDP0);

    9. /* Initialize Endpoint 1 */
    10.        SetEPType(ENDP1, EP_BULK);
    11.        SetEPRxAddr(ENDP1, ENDP1_RXADDR);
    12.        SetEPTxAddr(ENDP1, ENDP1_TXADDR);
    13.        SetEPRxCount(ENDP1, EP_SIZE);
    14.        SetEPRxStatus(ENDP1, EP_RX_VALID);
    15. SetEPTxStatus(ENDP1, EP_TX_NAK);

    16. /* Initialize Endpoint 2 */
    17.        SetEPType(ENDP2, EP_BULK);
    18.        SetEPRxAddr(ENDP2, ENDP2_RXADDR);
    19.        SetEPTxAddr(ENDP2, ENDP2_TXADDR);
    20.        SetEPRxCount(ENDP2, EP_SIZE);
    21.        SetEPRxStatus(ENDP2, EP_RX_VALID);
    22.        SetEPTxStatus(ENDP2, EP_TX_NAK);
    复制代码
    4,实现端点的回调函数(需要在usb_conf.h中注释掉对应的回调函数宏定义)
    1. /*******************************************************************************
    2. * Function Name  : EP1_OUT_Callback.
    3. * Description    : EP1 OUT Callback Routine.
    4. * Input          : None.
    5. * Output         : None.
    6. * Return         : None.
    7. *******************************************************************************/
    8. void EP1_OUT_Callback(void)
    9. {
    10.         EP1_ReceivedCount = GetEPRxCount(ENDP1);
    11.         PMAToUserBufferCopy(USB_Receive_Buffer, ENDP1_RXADDR, EP1_ReceivedCount);
    12.         SetEPRxStatus(ENDP1, EP_RX_VALID);
    13. }
    14. /*******************************************************************************
    15. * Function Name  : EP2_OUT_Callback.
    16. * Description    : EP2 OUT Callback Routine.
    17. * Input          : None.
    18. * Output         : None.
    19. * Return         : None.
    20. *******************************************************************************/
    21. void EP2_OUT_Callback(void)
    22. {
    23.         EP2_ReceivedCount = GetEPRxCount(ENDP2);
    24.         PMAToUserBufferCopy(USB_Receive_Buffer, ENDP2_RXADDR, EP2_ReceivedCount);
    25.         SetEPRxStatus(ENDP2, EP_RX_VALID);
    26. }
    复制代码
    5,完成主函数的测试程序
    1. int main(void)
    2. {
    3.         uint8_t data[256];
    4.         uint32_t i=0;
    5.         Set_System();//系统时钟初始化
    6.         USART_Configuration();//串口1初始化
    7.         printf("\x0c\0");printf("\x0c\0");//超级终端清屏
    8.         printf("\033[1;40;32m");//设置超级终端背景为黑色,字符为绿色
    9.         printf("\r\n*******************************************************************************");
    10.         printf("\r\n************************ Copyright 2009-2012, EmbedNet ************************");
    11.         printf("\r\n*************************** [url=http://www.embed-net.com]http://www.embed-net.com[/url] **************************");
    12.         printf("\r\n***************************** All Rights Reserved *****************************");
    13.         printf("\r\n*******************************************************************************");
    14.         printf("\r\n");

    15.         USB_Interrupts_Config();
    16.         Set_USBClock();
    17.         USB_Init();

    18.         while(1)
    19.         {
    20.                 if(EP1_ReceivedCount > 0){
    21.                         USB_GetData(ENDP1,data,EP1_ReceivedCount);
    22.                         USB_SendData(ENDP1,data,EP1_ReceivedCount);
    23.                         printf("usb EP1 get data %d byte data\n\r",EP1_ReceivedCount);
    24.                         for(i=0;i<EP1_ReceivedCount;i++){
    25.                                 printf("0x%02X ",data[i]);
    26.                         }
    27.                         printf("\n\r");
    28.                         EP1_ReceivedCount=0;
    29.                 }
    30.                 if(EP2_ReceivedCount > 0){
    31.                         USB_GetData(ENDP2,data,EP2_ReceivedCount);
    32.                         USB_SendData(ENDP2,data,EP2_ReceivedCount);
    33.                         printf("usb EP2 get data %d byte data\n\r",EP2_ReceivedCount);
    34.                         for(i=0;i<EP2_ReceivedCount;i++){
    35.                                 printf("0x%02X ",data[i]);
    36.                         }
    37.                         printf("\n\r");
    38.                         EP2_ReceivedCount=0;        
    39.                 }
    40.         }
    41. }
    复制代码
    到此,STM32的程序基本上编写完成,然后编译下载程序,如果一切顺利,系统会检测到一个新的设备并试图加载对应的驱动,由于我们还没做驱动程序,所以肯定会加载驱动失败,如下图所示:


    驱动程序生成
    下面我们就利用libusb自带的inf-wizard工具生成USB驱动程序,该工具可以到本文章的附件下载,其具体过程如下:


    运行该程序,出现下图对话框,点击“Next”;


    出现下图对话框后选择我们需要生成驱动程序的设备;


    这里可以写该Device Name,我们保持默认值,其他的都不需要修改;


    点击Next后出现下图对话框,我们选择一个目录保存这个inf文件;


    保存后的文件


    若要立即安装驱动,可以点击下面对话框的红色框按钮;


    Win7下可能会出现如下对话框,点击始终安装;


    到此,USB驱动程序自动生成完毕,若安装了驱动,则在设备管理器里面会看到如下信息


    基于libusb的上位机驱动程序编写
    首先建立一个驱动程序工程,然后将libusb的库(附件有下载)添加到工程里面,编写以下几个函数
    设备扫描函数,该函数用来找到插入电脑上的USB设备
    1. /**
    2.   * @brief  扫描设备连接数
    3.   * @param  NeedInit 是否需要初始化,第一次调用该函数需要初始化
    4.   * @retval 识别到的指定设备个数
    5.   */
    6. int __stdcall USBScanDev(int NeedInit)
    7. {
    8.         if(NeedInit){
    9.                 usb_init(); /* initialize the library */
    10.                 usb_find_busses(); /* find all busses */
    11.                 usb_find_devices(); /* find all connected devices */
    12.         }
    13.         return scan_dev(pBoard);
    14. }
    复制代码
    打开设备
    1. /**
    2.   * @brief  打开指定的USB设备
    3.   * @param  devNum        需要打开的设备号
    4.   * @retval 打开状态
    5.   */
    6. int __stdcall USBOpenDev(int DevIndex)
    7. {
    8.         pBoardHandle[DevIndex] = open_dev(DevIndex,pBoard);
    9.         if(pBoardHandle[DevIndex]==NULL){
    10.                 return SEVERITY_ERROR;
    11.         }else{
    12.                 return SEVERITY_SUCCESS;
    13.         }
    14. }
    复制代码
    关闭设备
    1. /**
    2.   * @brief  关闭指定的USB设备
    3.   * @param  devNum        需要关闭的设备号
    4.   * @retval 打开状态
    5.   */
    6. int __stdcall USBCloseDev(int DevIndex)
    7. {
    8.         return close_dev(DevIndex,pBoardHandle);
    9. }
    复制代码
    BULK端点写数据
    1. /**
    2.   * @brief  USB Bulk端点写数据
    3.   * @param  nBoardID 设备号
    4.   * @param  pipenum 端点号
    5.   * @param  sendbuffer 发送数据缓冲区
    6.   * @param  len 发送数据字节数
    7.   * @param  waittime 超时时间
    8.   * @retval 成功发送的数据字节数
    9.   */

    10. int __stdcall USBBulkWriteData(unsigned int nBoardID,int pipenum,char *sendbuffer,int len,int waittime)
    11. {
    12.         int ret=0;
    13.         if(pBoardHandle[nBoardID] == NULL){
    14.                 return SEVERITY_ERROR;
    15.         }
    16. #ifdef TEST_SET_CONFIGURATION
    17.     if (usb_set_configuration(pBoardHandle[nBoardID], MY_CONFIG) < 0)
    18.     {
    19.         usb_close(pBoardHandle[nBoardID]);
    20.         return SEVERITY_ERROR;
    21.     }
    22. #endif

    23. #ifdef TEST_CLAIM_INTERFACE
    24.     if (usb_claim_interface(pBoardHandle[nBoardID], 0) < 0)
    25.     {
    26.         usb_close(pBoardHandle[nBoardID]);
    27.         return SEVERITY_ERROR;
    28.     }
    29. #endif

    30. #if TEST_ASYNC
    31.     // Running an async write test
    32.     ret = transfer_bulk_async(dev, pipenum, sendbuffer, len, waittime);
    33. #else
    34.         ret = usb_bulk_write(pBoardHandle[nBoardID], pipenum, sendbuffer, len, waittime);
    35.         /*if((len%64) == 0){
    36.                 usb_bulk_write(pBoardHandle[nBoardID], pipenum, sendbuffer, 0, waittime);
    37.         }*/
    38. #endif
    39. #ifdef TEST_CLAIM_INTERFACE
    40.     usb_release_interface(pBoardHandle[nBoardID], 0);
    41. #endif
    42.     return ret;
    43. }
    复制代码
    BULK端点读数据
    1. /**
    2.   * @brief  USB Bulk读数据
    3.   * @param  nBoardID 设备号
    4.   * @param  pipenum 端点号
    5.   * @param  readbuffer 读取数据缓冲区
    6.   * @param  len 读取数据字节数
    7.   * @param  waittime 超时时间
    8.   * @retval 读到的数据字节数
    9.   */
    10. int __stdcall USBBulkReadData(unsigned int nBoardID,int pipenum,char *readbuffer,int len,int waittime)
    11. {
    12.         int ret=0;
    13.         if(pBoardHandle[nBoardID] == NULL){
    14.                 return SEVERITY_ERROR;
    15.         }
    16. #ifdef TEST_SET_CONFIGURATION
    17.     if (usb_set_configuration(pBoardHandle[nBoardID], MY_CONFIG) < 0)
    18.     {
    19.         usb_close(pBoardHandle[nBoardID]);
    20.         return SEVERITY_ERROR;
    21.     }
    22. #endif

    23. #ifdef TEST_CLAIM_INTERFACE
    24.     if (usb_claim_interface(pBoardHandle[nBoardID], 0) < 0)
    25.     {
    26.         usb_close(pBoardHandle[nBoardID]);
    27.         return SEVERITY_ERROR;
    28.     }
    29. #endif

    30. #if TEST_ASYNC
    31.     // Running an async read test
    32.     ret = transfer_bulk_async(pGinkgoBoardHandle[nBoardID], pipenum, sendbuffer, len, waittime);
    33. #else
    34.         ret = usb_bulk_read(pBoardHandle[nBoardID], pipenum, readbuffer, len, waittime);
    35. #endif
    36. #ifdef TEST_CLAIM_INTERFACE
    37.     usb_release_interface(pBoardHandle[nBoardID], 0);
    38. #endif
    39.     return ret;
    40. }
    复制代码
    到此,PC端的驱动程序编写基本完成,下面就是驱动程序的测试,我们可以把之前这个程序生成为一个dll文件,然后单独建立一个测试工程来测试这个dll文件中的函数,测试程序如下:
    1. // USB_DriverTest.cpp : 定义控制台应用程序的入口点。
    2. //

    3. #include "stdafx.h"

    4. #define        EP1_OUT_SIZE        64
    5. #define        EP1_IN_SIZE        64

    6. int _tmain(int argc, _TCHAR* argv[])
    7. {
    8.         int DevNum;
    9.         int ret;
    10.         char WriteTestData[256]={1,2,3,4,5,6,7,8,9};
    11.         char ReadTestData[256]={0};
    12.         for(int i=0;i<256;i++){
    13.                 WriteTestData[i] = i;
    14.         }
    15.         //扫描设备连接数,需要初始化
    16.         DevNum = USBScanDev(1);
    17.         printf("设备连接数为:%d\n",DevNum);
    18.         //打开设备0
    19.         ret = USBOpenDev(0);
    20.         if(ret == SEVERITY_ERROR){
    21.                 printf("打开设备失败!\n");
    22.                 return SEVERITY_ERROR;
    23.         }else{
    24.                 printf("打开设备成功!\n");
    25.         }

    26.         //端点1写数据
    27.         ret = USBBulkWriteData(0,EP1_OUT,WriteTestData,EP1_OUT_SIZE,500);
    28.         if(ret != EP1_OUT_SIZE){
    29.                 printf("端点1写数据失败!%d\n",ret);
    30.                 return SEVERITY_ERROR;
    31.         }else{
    32.                 printf("端点1写数据成功!\n");
    33.         }
    34.         //端点1读数据
    35.         ret = USBBulkReadData(0,EP1_IN,ReadTestData,EP1_IN_SIZE,500);
    36.         if(ret != EP1_IN_SIZE){
    37.                 printf("端点1读数据失败!%d\n",ret);
    38.                 return SEVERITY_ERROR;
    39.         }else{
    40.                 printf("端点1读数据成功!\n");
    41.                 for(int i=0;i<EP1_IN_SIZE;i++){
    42.                         printf("%02X ",ReadTestData[i]);
    43.                         if(((i+1)%16)==0){
    44.                                 printf("\n");
    45.                         }
    46.                 }
    47.                 printf("\n");
    48.         }
    49.         Sleep(100);
    50.         //端点2写数据
    51.         ret = USBBulkWriteData(0,EP2_OUT,WriteTestData+64,64,500);
    52.         if(ret != 64){
    53.                 printf("端点2写数据失败!%d\n",ret);
    54.                 return SEVERITY_ERROR;
    55.         }else{
    56.                 printf("端点2写数据成功!\n");
    57.         }
    58.         //端点2读数据
    59.         ret = USBBulkReadData(0,EP2_IN,ReadTestData,64,500);
    60.         if(ret != 64){
    61.                 printf("端点2读数据失败!%d\n",ret);
    62.                 return SEVERITY_ERROR;
    63.         }else{
    64.                 printf("端点2读数据成功!\n");
    65.                 for(int i=0;i<64;i++){
    66.                         printf("%02X ",ReadTestData[i]);
    67.                         if(((i+1)%16)==0){
    68.                                 printf("\n");
    69.                         }
    70.                 }
    71.                 printf("\n");
    72.         }
    73.         getchar();
    74.         return 0;
    75. }
    复制代码
    到此,整个开发流程基本完成,下面是本套程序的测试图片

    串口打印输出


    PC端测试程序输出


    Bus Hound抓取到的USB数据


    程序源码下载
    libusb驱动生成工具下载: inf_tool.rar (778.26 KB, 下载次数: 1192)
    STM32程序源码下载: USB_DriverSTM32F103.rar (677.81 KB, 下载次数: 1017, 售价: 10 金币)
    PC端USB驱动下载: USB Driver.rar (266.56 KB, 下载次数: 860)
    PC端USB驱动程序源码下载: USB_DriverBulk.rar (20.61 KB, 下载次数: 580, 售价: 10 金币)
    PC端USB驱动测试程序源码下载: USB_DriverTest.rar (12.34 KB, 下载次数: 618, 售价: 10 金币)
    libusb驱动包下载: libusb-win32-bin-1.2.6.0.rar (821.57 KB, 下载次数: 981)

    点评

    感谢分享  发表于 2019-1-14 14:44
    楼主把 上位机测试程序补发一下 下载不到 谢谢  发表于 2016-6-15 17:10
    回复

    使用道具 举报

  • TA的每日心情

    2017-11-2 11:47
  • 签到天数: 105 天

    连续签到: 1 天

    [LV.6]常住居民II

     楼主| 发表于 2015-8-21 12:51:36 | 显示全部楼层
    代码图发上去成镜像显示了。。了解的话,自己下源码看
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    慵懒
    2018-3-28 17:24
  • 签到天数: 276 天

    连续签到: 1 天

    [LV.8]以坛为家I

    发表于 2015-8-21 14:51:19 | 显示全部楼层
    谢谢   分享                 
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2022-9-16 05:52
  • 签到天数: 1368 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2015-8-21 20:23:25 | 显示全部楼层
    虽然内容很丰富,但是代码实在看不清
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2019-11-26 15:06
  • 签到天数: 427 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2015-8-22 08:26:44 | 显示全部楼层
    谢谢楼主                 
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2015-9-8 09:07
  • 签到天数: 11 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    发表于 2015-8-22 10:46:28 | 显示全部楼层
    多谢楼主,不过目前还在想怎么看
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2023-7-25 22:49
  • 签到天数: 385 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2015-8-22 15:13:29 | 显示全部楼层
    这TM怎么看哦。一片黑。
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2015-10-14 10:22
  • 签到天数: 40 天

    连续签到: 1 天

    [LV.5]常住居民I

    发表于 2015-8-22 15:31:40 | 显示全部楼层
    多谢楼主分享,只是代码真的很难看清
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2020-9-28 10:10
  • 签到天数: 1018 天

    连续签到: 1 天

    [LV.10]以坛为家III

    发表于 2015-8-24 08:42:01 | 显示全部楼层
    楼主,你这是直接复制别人的帖子吧,附件都没法下载,请麻烦把附件上传了吧
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2017-11-2 11:47
  • 签到天数: 105 天

    连续签到: 1 天

    [LV.6]常住居民II

     楼主| 发表于 2015-8-24 09:01:58 | 显示全部楼层
    小菜儿 发表于 2015-8-24 08:42
    楼主,你这是直接复制别人的帖子吧,附件都没法下载,请麻烦把附件上传了吧 ...

    嗯,那个帖子类型选的不是原创啊,是教程,

    inf_tool.rar

    778.26 KB, 下载次数: 971

    libusb-win32-bin-1.2.6.0.rar

    821.57 KB, 下载次数: 1867

    USB Driver.rar

    266.56 KB, 下载次数: 712

    USB_DriverSTM32F103.rar

    677.81 KB, 下载次数: 1140

    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-3-29 01:00 , Processed in 0.206748 second(s), 34 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.