移植STM32固件库用于HID双向通信

发布者:Asawen最新更新时间:2018-09-14 来源: eefocus关键字:移植  STM32  固件库  HID双向通信 手机看文章 扫描二维码
随时随地手机看文章

USB的应用中HID类是比较常见的方式。通过修改STM32 USB固件库V4.0的JOYSTICK应用,我们实现一个双向USB通信。
一、移植
使用STM32源程序为点亮LED灯程序。
首先将USB固件库中有用的函数复制到源函数中,建立LIB文件夹其中放入USB2.0协议函数



建立CFG文件夹放入USB应用函数


将两个文件夹都放到源工程目录下将文件添加进来,设置好,配置好KEIL软件设置。

二、修改文件
1、首先修改platform_config.h函数。
    该文件是对于多种芯片对于USB库的支持。我们使用STM32F103ZET6芯片,所以只保留与之相关的ID项,与USB_DISCONNECT线(PG11)的配置。修改之后的头文件如下所示



2、然后修改hw_config.c中Set_System函数

    实际上STM32F103zet6不需要对USB端口进行单独的配置,删掉Set_System函数中没用的部分,只对USB_DISCONNECT线(PG11)进行初始化。修改后的函数如下图所示。


3、接下来修改hw_config.c文件中USB_Cable_Config函数因为我使用的是比较老的神舟III开发板,当PG11为高电平时实现上拉,所以修改后的函数为


4、修改USB_Interrupt_Config函数,配置USB_LP_CAN1_RX0_IRQn和USBWakeUp_IRQn中断修改后的函数如下图所示。


5、接下来删掉hw_config.c文件中GPIO_AINConfig函数,没有什么用,只会报错

6、删掉与按键相关的设置,因为我们并没有用到,主要是先清除JoyState和Joystick_Send函数中内容,不用管。

7、最后我们处理USB挂起相关的问题。在USB固件库中提供挂起相关的处理函数,主要有2个函数需要修改。它们是Suspend函数和Enter_LowPowerMode函数。其中,在Suspend函数中注释掉PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);语句。修改Suspend函数,如下图所示

OK接下来应该就没有什么需要修改的地方了(如果有的话请酌情修改)
三、描述符修改
使用USB HID类进行通信调试。所以要对USB的描述符要做部分修改(usb_desc.c)。下面我们贴程序说明(只对重要修改做说明)

设备描述符
修改idVendor和idProduct的值,为任意其他值,我里我用给的是0x0413和0x5724,修改的时候注意大小端

配置描述符集合

const uint8_t Joystick_ConfigDescriptor[JOYSTICK_SIZ_CONFIG_DESC] =

  {

    0x09, /* bLength: Configuration Descriptor size */

    USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */

    JOYSTICK_SIZ_CONFIG_DESC,

    /* wTotalLength: Bytes returned */

    0x00,

    0x01,         /*bNumInterfaces: 1 interface*/

    0x01,         /*bConfigurationValue: Configuration value*/

    0x00,         /*iConfiguration: Index of string descriptor describing

                                     the configuration*/

    0xE0,         /*bmAttributes: Self powered */

    0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/

 

    /************** Descriptor of Joystick Mouse interface ****************/

    /* 09 */

    0x09,         /*bLength: Interface Descriptor size*/

    USB_INTERFACE_DESCRIPTOR_TYPE,/*bDescriptorType: Interface descriptor type*/

    0x00,         /*bInterfaceNumber: Number of Interface*/

    0x00,         /*bAlternateSetting: Alternate setting*/

    0x02,         /*bNumEndpoints除端点0外,需要1输入1输出*/

    0x03,         /*bInterfaceClass: HID*/

    0x00,         /*bInterfaceSubClass : 1=BOOT, 0=no boot选择no boot*/

    0x00,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse选择none*/

    0,            /*iInterface: Index of string descriptor*/

    /******************** Descriptor of Joystick Mouse HID ********************/

    /* 18 */

    0x09,         /*bLength: HID Descriptor size*/

    HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/

    0x00,         /*bcdHID: HID Class Spec release number*/

    0x01,

    0x00,         /*bCountryCode: Hardware target country*/

    0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/

    0x22,         /*bDescriptorType*/

    JOYSTICK_SIZ_REPORT_DESC,/*wItemLength: Total length of Report descriptor*/

    0x00,

    /******************** Descriptor of Joystick Mouse 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修改最大包大小为64字节 */

    0x00,

    0x0A,          /*bInterval: Polling Interval (10 ms)修改轮询间隔为10ms*/

/******************** Descriptor of Joystick Mouse endpoint ********************/

    /* 34 */

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

    USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/

 

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

    0x03,          /*bmAttributes: Interrupt endpoint*/

    0x40,          /*wMaxPacketSize: 64 Byte max修改最大包大小为64字节 */

    0x00,

    0x20,          /*bInterval: Polling Interval (10 ms) 修改轮询间隔为10ms */

/*41 */

  } ;


报告描述符


const uint8_t Joystick_ReportDescriptor[JOYSTICK_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)*/

    0x95, 0x40,          /*Report Count(3)*/

    0x75, 0x08,          /*Report Size(1)*/

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, 0x40,          /*Report Count(64)*/

    0x75, 0x08,          /*Report Size(8)*/

0x91, 0x02,          /*Input(Data,Var,Abs)*/

0xc0               /*关集合*/

  }; /* Joystick_ReportDescriptor */

上面我们修改了数组内容,导致数组大小发生变化,所以根据变化做响应修改,在usb_desc.c中


#define JOYSTICK_SIZ_CONFIG_DESC                41

#define JOYSTICK_SIZ_REPORT_DESC                39

四、修改函数


    修改设备RESET函数Joystick_Reset,这个函数是在RESET中断中被调用,用于端口的初始化。因为我们增加了端点1的输出,修改了包大小,所以要做响应的修改。这个函数位于usb_prop.c中,修改后的函数为


void Joystick_Reset(void)

{

  /* Set Joystick_DEVICE as not configured */

  pInformation->Current_Configuration = 0;

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

 

  /* Current Feature initialization */

  pInformation->Current_Feature = Joystick_ConfigDescriptor[7];

  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);//修改大小为64

  SetEPTxStatus(ENDP1, EP_TX_NAK);

 

  /* Initialize Endpoint 1 */

  //SetEPType(ENDP1, EP_INTERRUPT);

  SetEPTxAddr(ENDP1, ENDP1_RXADDR);

  SetEPTxCount(ENDP1, 64); //修改大小为64

  SetEPRxStatus(ENDP1, EP_RX_VALID);

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

  SetDeviceAddress(0);

  bDeviceState = ATTACHED;

}

在上面中ENDP1_RXADDR是我们新加的,需要我们在usb_conf.h中添加对于它的定义

/* EP1  */

/* tx buffer base address */

#define ENDP1_TXADDR        (0x100)

#define ENDP1_RXADDR        (0x140)

最后我们编写对于USB输出数据的处理函数,即

void EP1_OUT_Callback(void)

{

    DataLen = USB_SIL_Read(ENDP1,kk);//kk是个64字节的数组

    

    if(kk[0]&&0x01 == 0x01)

        LED(LED1,1);

    else

        LED(LED1,0);

    if(kk[0]&&0x02 == 0x02)

        LED(LED2,1);

    else

        LED(LED2,0);

    if(kk[0]&&0x04 == 0x04)

        LED(LED3,1);

    else

        LED(LED3,0);

    if(kk[0]&&0x08 == 0x08)

        LED(LED4,1);

    else

        LED(LED4,0);   

    SetEPRxValid(ENDP1);

}

在主函数中我们添加USB IN的相关操作,因为设置的是interrupt端点,所以每过10ms主机就是问询设备是否有数据要发送,我们只需要在stm32的主函数中填装数据即可。具体的while循环中代码是


if(GetEPTxStatus(ENDP1)==EP_TX_NAK)

{

    if(DataLen !=0)

    {

        USB_SIL_Write(ENDP1,kk,DataLen);              

        SetEPTxValid(ENDP1);

        DataLen=0;

    }               

}

最后的最后不要忘了在stm32f10x_it.c中添加中断处理

void USB_LP_CAN1_RX0_IRQHandler(void)

{

  USB_Istr();

}  

void USBWakeUp_IRQHandler(void)

{

   EXTI_ClearITPendingBit(EXTI_Line18);

}


至此整个移植过程就完成了,程序实现的功能是,通过电脑给USB设备发送数据,USB设备收到数据,然后再把数据发送回电脑,为了检验USB的发送与接收,使用Labview编写了一个简单的上位机。大概就是这个样子,发送哈哈,收到哈哈。




关键字:移植  STM32  固件库  HID双向通信 引用地址:移植STM32固件库用于HID双向通信

上一篇:STM32F10X的USB固件库说明
下一篇:STM32 USB 之从0开始移植笔记

推荐阅读最新更新时间:2024-03-16 16:14

stm32专题三十:12864 IIC驱动
1 IIC发送数据 / 命令时序 2 12864 图形显示(显存) RAM的大小是128×64位,RAM分为8页,从PAGE0到PAGE7,用于单色128x64点阵显示。 3 行列设置 1 设置起始行坐标(设置页) 命令 0XB0 ~ 0XB7 用于设置分页,所以我们显示的分页要 + 偏移(0XB0) 2 设置起始列坐标 4 制作字模 1 字模软件设置方式: 2 生成的字模的批处理: 生成的字模如图所示,我们要转成 0X00 这种格式: 使用 sublime 这个软件,可以进行批处理(先全选,然后再 快捷键 Ctrl + Shift + L): 字模生成完毕。 驱动程序如下所示
[单片机]
<font color='red'>stm32</font>专题三十:12864 IIC驱动
STM32复习笔记(三)端口复用、映射和中断优先级
一、端口复用: STM32有很多的内置外设,这些外设的外部引脚都是与GPIO复用的。也就是说,一个GPIO如果可以复用为内置外设的功能引脚,那么当这个GPIO作为内置外设使用的时候,就叫做复用。 例如串口1 的发送接收引脚是PA9,PA10,当我们把PA9,PA10不用作GPIO,而用做复用功能串口1的发送接收引脚的时候,叫端口复用。 -----------------------------------------端口复用配置过程------------------------------------------ 端口复用配置过程: 以PA9,PA10配置为串口1为例 GPIO端口时钟使能。 RCC_APB2Peri
[单片机]
<font color='red'>STM32</font>复习笔记(三)端口复用、映射和中断优先级
全网最全STM32 HAL的知识总结
ST 为开发者提供了非常方便的开发库:有标准外设库(SPL库)、HAL 库(Hardware Abstraction Layer,硬件抽象层库)、LL 库(Low-Layer,底层库)三种。前者是ST的老库已经停更了,后两者是ST现在主推的开发库。 相比标准外设库,STM32Cube HAL库表现出更高的抽象整合水平,HAL API集中关注各外设的公共函数功能,这样便于定义一套通用的用户友好的API函数接口,从而可以轻松实现从一个STM32产品移植到另一个不同的STM32系列产品。HAL库是ST未来主推的库,ST新出的芯片已经没有STD库了,比如F7系列。目前,HAL库已经支持STM32全线产品。 通过文字描述可以知道HA
[单片机]
基于STM32和CAN总线的电动车电池管理系统设计
  随着电池能源的广泛应用,石油资源的枯竭和环境污染,电动汽车以其节能环保的优势引起越来越多的重视,在电动汽车的研究和发展上,车载电池及其管理系统的研究与制造占据着重要位置。电动汽车动力电池在应用中的主要问题表现在:生产过程中,电池的工艺,技术以及成组技术还不能保证其初始性能具有良好的一致性;使用过程中,对过充电、过放电、过温度、过电流等非常敏感,这类情况的发生会明显缩短电池寿命,甚至会导致电池报废。电池组是几十个甚至上百个单体电池串联,单体电池之间存在不一致性,随着连续的充放电循环,电池间的不一致性加剧,电池组的可用容量受容量最小的单体电池制约。对于这些情况,电池的初始性能必须要依靠企业生产工艺的优化,生产过程关键参数的控制来改
[电源管理]
基于<font color='red'>STM32</font>和CAN总线的电动车电池管理系统设计
详解STM32单片机堆栈
学习STM32单片机的时候,总是能遇到“堆栈”这个概念。分享本文,希望对你理解堆栈有帮助。 对于了解一点汇编编程的人,就可以知道,堆栈是内存中一段连续的存储区域,用来保存一些临时数据。堆栈操作由PUSH、POP两条指令来完成。而程序内存可以分为几个区: 栈区(stack) 堆区(Heap) 全局区(static) 文字常亮区程序代码区 程序编译之后,全局变量,静态变量已经分配好内存空间,在函数运行时,程序需要为局部变量分配栈空间,当中断来时,也需要将函数指针入栈,保护现场,以便于中断处理完之后再回到之前执行的函数。 栈是从高到低分配,堆是从低到高分配。 普通单片机与STM32单片机中堆栈的区别 普通单片机启动时,不需要用b
[单片机]
详解<font color='red'>STM32</font>单片机堆栈
Stm32库函数里的断言机制解析
assert_param 在STM32的HAL库函数中的函数中随处可见。那么它的作用是什么呢? 首先看一个它使用的地方: 这里的作用很明显,是对函数输入的参数进行检查。那么它检查的机制是如何实现的呢? 看下assert_param 定义的地方,在定义了宏 USE_FULL_ASSERT 的时候,assert_param 才起作用,否则 assert_param 就背替换成 ((void)0U) ,会被编译器优化掉的,不会产生实际运行的代码。所以我们可以在编写和测试代码时,设置 USE_FULL_ASSERT 这个宏,打开断言的功能,方便我们尽快的调试和定位错误。在 Release 版的时候可以关闭这个宏,关闭断言
[单片机]
<font color='red'>Stm32</font>库函数里的断言机制解析
移植e2fsprogs到arm平台
移植e2fsprogs到arm平台 也就是一般的交叉编译。 由于e2fsprogs通常会用到动态库,这里为了方便起见,采用了静态链接。 这样的话,向arm平台拷贝时,就不需要再关心动态库的问题了。 具体操作过程如下: tar -xzf e2fsprogs-1.42.5.tar.gz cd e2fsprogs-1.42.5 mkdir release cd release/ ../configure --host=arm-linux CC=arm-linux-gcc LDFLAGS=-static make 好了,现在release下面的各个目录下,已经有相应的可执行程序生成了。 将他们直接拷到arm平台下即
[单片机]
RyanMqtt移植指南
测试环境:stm32F401RCT6、RT-Thread版本: v4.1.0、RT-Thread Studio版本: 2.2.6、网络硬件使用ec800m移植at_socket使用sal框架。 1、移植介绍 RyanMqtt 库希望应用程序为以下接口提供实现: system 接口 RyanMqtt 需要 RTOS 支持,必须实现如下接口才可以保证 mqtt 客户端的正常运行 network 接口 RyanMqtt 依赖于底层传输接口 API,必须实现该接口 API 才能在网络上发送和接收数据包 MQTT 协议要求基础传输层能够提供有序的、可靠的、双向传输(从客户端到服务端 和从服务端到客户端)的字节流 time 接口
[单片机]
RyanMqtt<font color='red'>移植</font>指南
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
热门活动
换一批
更多
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

更多精选电路图
换一换 更多 相关热搜器件
更多每日新闻
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved