liuxiaofei126
认证:VIP会员
所在专题目录 查看专题
STM32定时器的来龙去脉
底层程序如何在STM32上编译运行
从IIC实测波形入手搞懂IIC通信
实例讲解(一)移位寄存器
单片机之USB 硬件和数据的四种传输方式
实例讲解(二)SPI通讯显示电子星球
作者动态 更多
stm32知识点总结
2021-11-24 23:12
工程师单片机LED项目
2021-11-11 07:46
电容型负载对跟随器的影响
2021-10-28 23:33
图腾柱和互补推挽两个“小冤家”
2021-10-22 23:15
学习单片机的捷径
2021-10-17 23:07

单片机之USB 硬件和数据的四种传输方式

1.下面是 USB 硬件和数据的四种传输类型

控制传输(Control Transfers)

批量传输(Bulk Data Transfers)

中断传输(Interrupt Data Transfers)

同步传输(Isochronous Data Transfers)

下面我们通过一个例子看一下 USB 的具体工作过程。在此我们用一个比较实用的例子,就是把我们的板子用 USB 连接至 PC,然后在 PC 端出现一个模拟串口,通过串口助手打开这个串口,然后实现数据的双向传输。最后我们聊一下很多工程师都会忽视的 USB 认证问题。

2. 例程我们打开 ST 的 Cube 库中的 CDC 例程:

stm32Cube_FW_F1_V1.8.0\Projects\STM3210C_EVAL\Applications\USB_Device\CDC_Standalone\MDK-ARM\Project.uvprojx

这个例程用到 USB 的同时还会用到 USART,USB 从 PC 端收到数据后会转发到 USART,从 USART 接收到消息会上传至 PC。我们可以把 USART 的 TX 和 RX 短接,这样从 PC 端下发的数据会原样回传给 PC 端。

这个例程使用的硬件是 STM3210C-EVAL,原理图可以在 stmcu.org.cn 找到。如果我们使用的是其它板子,就需要在这个工程基础上做一些改动。比如现在我们使用 STM32F105RBT6,8M 晶振,串口用 PTA2,PTA3,那么我们的要做如下修改:

首先,修改使用的 MCU:

然后修改时钟初始化部分。下图为 STM32F105 时钟模块示意图。USB 工作需要 48MHz 的时钟。

如果板子的晶振是 8M,那么参数需要做如下配置:

(OSC IN = 8M)PREDIV1SRC  =  0b0,

HSE oscillator clock selected as PREDIV1 clock entryPREDIV1 = 0b0,

PREDIV1 input clock not dividedPLLSRC = 0b1,

Clock from PREDIV1 selected as PLL input clockPLLMUL = 0b0111,

PLL input clock x 9(PLLCLK = 72M)SW = 0b10,

PLL selected as system clockPLLVCO = 2*PLLCLK  = 144MUSBPRE = 0,

PLL clock is divided by 1.5 (or PLLVCO/3)USB Clock =  = PLLCLK/1.5 = 72M/1.5 = 48M

例程中的对应代码修改:

最后修改使用的串口引脚即可

终于可以编译运行了,用 USB 线把板子连到 PC 的 USB 口,记得把板子的 PTA2和 PTA3引脚短接起来。在设备管理器我们看到多出来一个串口,看它的属性会看到它的 VID,PID 跟我们程序中设置的一致。

用串口助手打开此串口,发送字符串,会看到返回同样的字符串。

下面我们来看一下具体的工作过程。

3.USB 枚举(Enumeration)当我们给设备上电,程序控制芯片内集成的上拉电阻连接至 USBDP 时,USB 主机(PC 端)会检测到这一变化并向设备供电。此时设备处于 Powered 状态。

主机等待 100ms 设备稳定后复位并使能此端口,此时设备可以从 Vbus 获取不超过 100mA 的电流,其默认地址是 0,处于 Default 状态。

主机通过 0 地址向该设备发送 Get_Descriptor 标准请求,获取设备的描述符。主机再次复位该 PORT,并发送标准请求 Set_Address 给设备分配一个地址,之后的通信都是用此地址,设备进入 Address 状态。

主机通过新地址向设备再次发送 Get_Descriptor 标准请求,获取设备描述符。发送 Get_Configuration 请求,获取配置描述符。一个设备可以有多个配置,主机选择合适配置,通过 Set_Configuration 请求对设备而进行配置,设备进入 Configured 状态。

USB 的枚举过程是标准的,所以库里也有对应的标准处理代码。我们可以不用关心。好了,现在可以开始数据的双向传输了。

4. 数据传输我们已经了解所有 USB 传输都是由 USB 主机(Host)发起的,作为 USB 设备只能是被动的等待。当 Host 下发请求时会在设备中产生各种中断,设备完成各种中断的处理就行了。

其中需要特别关注的有两个:

OEPINT(Output Endpoint Int),表明主机下发了数据。

IEPINT(Output Endpoint Int)。表明主机请求设备上传数据。

那么用户在代码里如何收发 USB 数据的呢?

usbd_cdc_interface.c 里关注下面这些就够了:

uint8_t UserRxBuffer[APP_RX_DATA_SIZE]; //USB 下发数据缓冲区

uint8_t UserTxBuffer[APP_TX_DATA_SIZE]; // 需要发给 USB 上位机的数据缓冲区

下面这个函数是用户用来处理接收缓冲区数据的,在初始化时需要传递给 USB 驱动,然后驱动收到 USB 下发的数据后会回调此函数。在例程中此函数把接收数据转发给了 USART2。当然你也可以什么都不做。

static int8_t CDC_Itf_Receive(uint8_t * Buf, uint32_t * Len);

那么如果有数据需要发给上位机呢?

我们可以用下面这个函数:USBD_CDC_TransmitPacket(&USBD_Device);注意此数据是先放入 IN 端点,然后等待 IEPINT 中断发生时才被取走发送

5. 一个重要又容易被忽视的问题至此好像万事大吉了。

等等,如果产品这样发出去,你可能给公司惹麻烦了!

还有一个很重要的问题我们千万不要忽视,就是 VID 和 PID,既厂商识别符(Vendor ID)和产品识别符(Product ID)。我们例程中使用的是 VID 0x0483, PID 0x5740。这个 VID 是专门分配给 ST 的,虽然我们用这个号程序也能运行,但是不符合规范的。我们的可以在 usb.org/developers 网站查到当前为所有 USB 厂商分配的 VID。如果我们要开发 USB 设备,还要向 USB 组织申请自己的 VID,之后还要做微软徽标认证,就可以畅行无阻了。

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 6
收藏 6
关注 206
成为作者 赚取收益
全部留言
0/200
  • dy-blNlwnWV 2021-02-25 21:45
    学习了
    回复
  • keyhei66 2021-01-03 09:18
    大开眼界,真是好文
    回复
  • 星球居民-YBPLIKJ1 2021-01-02 20:54
    usb设备必须申请?
    回复
  • lihui710884923 2020-12-31 16:44
    USB口
    回复