STM32-USB讲解(一)

USB 的鼠标控制实例验证通过,有主要代码讲解,以及Keil调试过程,容易上手,理清代码架构。适合USB人机交互的开发。经验分享:
“JoyStickMouse”例程结构分析 :
1、例程的结构
(1)底层结构 包括5个文件:
usb_core.c(USB 总线数据处理的核心文件) ,
usb_init.c, usb_int.c 用于端点数据输入输入中断处理)
usb_mem.c 用于缓冲区操作)
usb_regs.c(用于寄存器操作) 。
它们都包含了头文件“usb_lib.h”。
在这个 头文件中,又有以下定义:
#include “usb_type.h”
#include “usb_regs.h”
#include “usb_def.h”
#include “usb_core.h”
#include “usb_init.h”
#include “usb_mem.h”
#include “usb_int.h”
usb_lib.h 中又包含了七个头文件,
其中 usb_type.h 中主要是用 typedef 为 stm32支持的数据类型取一些新的名称。
usb_def.h 中主要是定义一些相关的 数据类型。
还有一个未包含在 usb_lib.h 中的头文件, usb_conf.h 用于 USB 设备的配置。

(2)上层结构 上层结构总共5个文件:
hw_config.c(用于 USB 硬件配置) 、
usb_pwr.c(用 于 USB 连接、断开操作) 、
usb_istr.c (直接处理 USB 中断) 、
usb_prop.c (用 于上层协议处理,比如 HID 协议,大容量存储设备协议) 、usb_desc.c(具体 设备的相关描述符定义和处理) 。 可见,ST 的 USB 操作库结构十分清晰明了,我先不准备直接阅读源代码。
而 是先利用 MDK 的软件模拟器仿真执行,先了解一下设备初始化的流程。

2、设备初始化所做的工作
(1)Set_System(void) 这个是 main 函数中首先调用的函数,它位于 hw_config.c 文件中。它的主要 功能是初始化时钟系统、使能相关的外围设备电源。 配置了 JoyStickMouse 所用到的5个按键,并且配置了两个 EXTI 中断,一个 是用于把 USB 从挂起模式唤醒,还有一个用途未知。

(2)USB_Interrupts_Config(); 这个是 main 函数中调用的第二个函数,它也位于 hw_config.c 文件中。主要 功能是配置 USB 所用到的中断。 跟踪到代码中,主要设配置了 USB 低优先级中断和唤醒中断,又有一个 EXTI 中断功能未知。

(3)Set_USBClock() 这个是 main 函数中调用的第三个函数,它也位于 hw_config.c 文件中。它的 功能是配置和使能 USB 时钟。

(4)USB_Init(void) 这个是 main 函数中调用的第四个函数,它也位于 usb_init.c 文件中。它初始 化了三个全局指针,指向 DEVICE_INFO、USER_STANDARD_REQUESTS 和 DEVICE_PROP 结构体。
后面两个是函数指针结构体,里面都是 USB 请求实现、功能实现的函数指针。
void USB_Init(void) { pInformation = &Device_Info; pInformation->ControlState = 2; pProperty = &Device_Property; pUser_Standard_Requests = &User_Standard_Requests; /* Initialize devices one by one */ pProperty->Init(); } 这三个结构体都是与具体设备枚举和功能实现相关的,定义在 usb_prop.c 和 usb_desc.c 文件中。

DEVICE_PROP Device_Property= { Joystick_init, Joystick_Reset, Joystick_Status_In, Joystick_Status_Out, Joystick_Data_Setup, Joystick_NoData_Setup, Joystick_Get_Interface_Setting, Joystick_GetDeviceDescriptor, Joystick_GetConfigDescriptor, Joystick_GetStringDescriptor, 0, 0x40 /MAX PACKET SIZE/ };

USER_STANDARD_REQUESTS User_Standard_Requests= { Joystick_GetConfiguration, Joystick_SetConfiguration, Joystick_GetInterface, Joystick_SetInterface, Joystick_GetStatus, Joystick_ClearFeature, Joystick_SetEndPointFeature, Joystick_SetDeviceFeature, Joystick_SetDeviceAddress };

Usb_init()函数调用 pProperty->Init()(实质上就是 Joystick_init)完成设 备的初始化。 上层程序调用下次函数是常规性的操作。而下层函数(usb_init 相对于 usb_prop 是输入底层操作文件)调用上层文件函数我们称之为回调。 回调函数的意义在于同一种操作模式、提供不同的回调函数则可以实现不同的 功能。Windows 中处理消息,好像也用到了这种模式。

回调函数的实现方法是函数指针数组。这是指针的高级应用。 这是函数的代码: void Joystick_init(void) {/* Update the serial number string descriptor with the data from the unique ID*/

Get_SerialNum(); //获取设备序列号,转变为 unicode 字符串

pInformation->Current_Configuration = 0; /* Connect the device */

PowerOn(); //连接 USB 设备,实质是能让主机检测到了。

/* USB interrupts initialization / _SetISTR(0);
/
clear pending interrupts / wInterrupt_Mask = IMR_MSK;
_SetCNTR(wInterrupt_Mask); /
set interrupts mask */
bDeviceState = UNCONNECTED; } 实质上,代码执行到这里,开发板已经可以响应主机发来的数据了。但我还是 先把 main()函数的代码看完吧。

(5)SysTick_Config(); 这个函数调用主要是为程序中用到的精确延时作配置。

3、进入主循环 进入主循环的工作就两个:
Joystick_Send(JoyState())。 JoyState()用来获取按键的状态。 Joystick_Send(JoyState())用来把按键状态发到主机。当然这里真正的发送 工作并不是由该代码完成的。它的工作只是将数据写入 IN 端点缓冲区,主机的IN 令牌包来的时候,SIE 负责把它返回给主机。
主要代码如下: UserToPMABufferCopy(Mouse_Buffer, GetEPTxAddr(ENDP1),

4); //从用户复制四个字节到端点1缓冲区,控制端点的输入缓冲区。 SetEPTxValid(ENDP1);/* enable endpoint for transmission */

4、中断处理过程大致理解
(1)usb_istr()函数中的中断处理简单分析 有用的代码大概以下几段,首先是处理复位的代码,调用设备结构中的复位处 理函数。
wIstr = _GetISTR(); if (wIstr & ISTR_RESET & wInterrupt_Mask) { _SetISTR((u16)CLR_RESET); //清复位中断
Device_Property.Reset(); }

处理唤醒的代码: if (wIstr & ISTR_WKUP & wInterrupt_Mask) { _SetISTR((u16)CLR_WKUP); Resume(RESUME_EXTERNAL); }

处理总线挂起的代码: if (wIstr & ISTR_SUSP & wInterrupt_Mask) {if (fSuspendEnabled) /* check if SUSPEND is possible / { Suspend(); } else { / if not possible then resume after xx ms */

Resume(RESUME_LATER); } /* clear of the ISTR bit must be done after setting of CNTR_FSUSP / _SetISTR((u16)CLR_SUSP); } 处理端点传输完成的代码,这段是最重要的,它调用底层 usb_int.c()文件中 的 CTR_LP()函数来处理端点数据传输完成中断。 if (wIstr & ISTR_CTR & wInterrupt_Mask) { CTR_LP();/ servicing of the endpoint correct transfer interrupt */ }

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王先森001

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值