1)实验平台:【正点原子】 NANO STM32F103 开发板
2)摘自《正点原子STM32 F1 开发指南(NANO 板-HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子
第三十二章 USB 读卡器实验
上一章我们向大家介绍了如何利用 STM32 的 USB 来做一个 USB 虚拟串口,本章我们将利用 STM32 的 USB 来做一个 USB 读卡器。本章分为如下几个部分:
32.1 USB 读卡器简介
32.2 硬件设计
323 软件设计
32.4 下载验证
32.1 USB 读卡器简介
ALIENTEK NANO STM32 开发板板载了一个 2M 字节的 SPI FLASH 芯片,通过 STM32
的 USB 接口,我们可以实现一个简单的 USB 读卡器,来读写 SPI FLASH。
本章我们还是通过移植官方的 USB Mass_Storage 例程来实现,该例程在 MDK 的安装目录
下可以找到(..\MDK\ARM\Examples\ST\STM32F10xUSBLib\Demos\Mass_Storage)。
USB Mass Storage 类支持两个传输协议:
1)Bulk-Only 传输(BOT)
2)Control/Bulk/Interrupt 传输(CBI)
Mass Storage 类规范定义了两个类规定的请求:Get_Max_LUN 和 Mass Storage Reset,所有
的 Mass Storage 类设备都必须支持这两个请求。
Get_Max_LUN(bmRequestType= 10100001b and bRequest= 11111110b)用来确认设备支持
的逻辑单元数。Max LUN 的值必须是 0~15。注意:LUN 是从 0 开始的。主机不能向不存在的
LUN 发送 CBW,本章我们定义 Max LUN 的值为 1,即代表 2 个逻辑单元。
Mass Storage Reset(bmRequestType=00100001b and bRequest= 11111111b)用来复位 Mass
Storage 设备及其相关接口。
支持 BOT 传输的 Mass Storage 设备接口描述符要求如下:
接口类代码 bInterfaceClass=08h,表示为 Mass Storage 设备;
接口类子代码 bInterfaceSubClass=06h,表示设备支持 SCSI Primary Command-2(SPC-2);
协议代码 bInterfaceProtocol 有 3 种:0x00、0x01、0x50,前两种需要使用中断传输,最后
一种仅使用批量传输(BOT)。
支持 BOT 的设备必须支持最少 3 个 endpoint:Control, Bulk-In 和 Bulk-Out。USB2.0 的规
范定义了控制端点 0。Bulk-In 端点用来从设备向主机传送数据(本章用端点 1 实现)。Bulk-Out
端点用来从主机向设备传送数据(本章用端点 2 实现)。
ST 官方的例程是通过 USB 来读写 SD 卡(SDIO 方式)和 NAND FALSH,支持 2 个逻辑
单元,我们在官方例程的基础上,只需要修改删除 SD 驱动部分代码,并将对 NAND FLASH
的操作修改为对 SPI FLASH 的操作。只要这两步完成了,剩下的就比较简单了,对底层磁盘的
读写,都是在 mass_mal.c 文件实现的,所以我们只需要修改该函数的 MAL_Init、MAL_Write、
MAL_Read 和 MAL_GetStatus 等 4 个函数,使之与我们的 SPI FLASH 对应起来即可。
32.2 硬件设计
本节实验功能简介:开机的时候先检测 SPI FLASH 是否存在,如果存在则获取其容量,
并打印在串口调试助手(如果不存在,则报错)。之后开始 USB 配置,在配置成功之后就可
以在电脑上发现两个可移动磁盘。我们用 DS1 来指示 USB 正在读写 SPI FLASH,并在串口助
手显示出来,同样我们还是用 DS0 来指示程序正在运行。
所要用到的硬件资源如下:
1) 指示灯 DS0 、DS1
2) 串口
3) USB SLAVE 接口
4) SPI FLASH
这几个部分,在之前的实例中都已经介绍过了,我们在此就不多说了。
32.3 软件设计
本章,我们在第二十四章(实验 19)的基础上修改,首先打开实验 19 的工程,在
HARDWARE 文件夹所在的文件夹下新建一个 USB 的文件夹,并拷贝官方 USB 驱动库相关代
码到该文件夹下,即拷贝:光盘 → 8,STM32 参考资料→STM32 USB 学习资料→
STM32_USB-FS-Device_Lib_V4.0.0→Libraries 文件夹下的
STM32_USB-FS-Device_Driver 文件
夹到该文件夹下面。
然后,在 USB 文件夹下面新建 CONFIG 文件夹,用来存放 USB 读卡器实现的相关代码,
拷贝自:
STM32_USB-FS-Device_Lib_V4.0.0→Projects→Mass_Storage→src 和 inc 文件夹。注意:
部分代码是有修改的,并非完全照抄官方代码,具体代码我们就不细说了(详见光盘本例程源
码)。
接下来,我们在工程文件里面新建 USB_CORE 和 USB_CONFIG 分组,分别加入:
USB\
STM32_USB-FS-Device_Driver\src 下面的代码和 USB\CONFIG 下面的代码。然后把
USB\
STM32_USB-FS-Device_Driver\inc 和 USB\CONFIG 文件夹加入头文件包含路径。
打开 main.c 文件,我们修改 main 函数如下:
int main(void)
{
u8 offline_cnt=0;
u8 tct=0;
u8 USB_STA;
u8 Divece_STA;
HAL_Init(); //初始化 HAL 库
Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M
delay_init(72); //初始化延时函数
uart_init(115200);
//串口初始化为 115200
LED_Init();
//初始化与 LED 连接的硬件接口
printf("NANO STM32\r\n");
printf("DHT11 TEST\r\n");
KEY_Init();
//按键初始化
printf("NANO STM32\r\n");
printf("USB Card Reader TEST\r\n");
W25QXX_Init();
if(W25QXX_TYPE!=W25Q16) printf("W25Q16 Error!\r\n");//检测 SPI FLASH 错误
else //SPI FLASH 正常
{
Mass_Memory_Size[0]=2048*1024;//前 2M 字节
Mass_Block_Size[0] =512;
Mass_Block_Count[0]=Mass_Memory_Size[0]/Mass_Block_Size[0];
printf("SPI FLASH Size:2048KB\r\n");
}
delay_ms(1800);
USB_Port_Set(0); //USB 先断开
delay_ms(300);
USB_Port_Set(1); //USB 再次连接
printf("USB Connecting...\r\n");//提示 USB 连接中
Data_Buffer=mymalloc(BULK_MAX_PACKET_SIZE*2*4);
//为 USB 数据缓存区申请内存
Bulk_Data_Buff=mymalloc(BULK_MAX_PACKET_SIZE);
//申请内存
//USB 配置
USB_Interrupts_Config();
Set_USBClock();
USB_Init();
delay_ms(1800);
while(1)
{
delay_ms(1);
if(USB_STA!=USB_STATUS_REG)//状态改变了
{
if(USB_STATUS_REG&0x01)//正在写
{
printf("USB Writing...\r\n");//提示 USB 正在写入数据
}
if(USB_STATUS_REG&0x02)//正在读
{
printf("USB Reading...\r\n");//提示 USB 正在读出数据
}
if(USB_STATUS_REG&0x04)printf("USB Write Err\r\n");//提示写入错误
if(USB_STATUS_REG&0x08)printf("USB Read Err\r\n");//提示读出错误
USB_STA=USB_STATUS_REG;//记录最后的状态
}
if(Divece_STA!=bDeviceState)
{
if(bDeviceState==CONFIGURED) printf("USB Connected\r\n");
//提示 USB 连接已经建立
else printf("USB DisConnected\r\n");//提示 USB 被拔出了
Divece_STA=bDeviceState;
}
tct++;
if(tct==200)
{
tct=0;
LED0=!LED0;//提示系统在运行
if(USB_STATUS_REG&0x10)
{
offline_cnt=0;//USB 连接了,则清除 offline 计数器
bDeviceState=CONFIGURED;
}else//没有得到轮询
{
offline_cnt++;
if(offline_cnt>10)bDeviceState=UNCONNECTED;
//2s 内没收到在线标记,代表 USB 被拔出了
}
USB_STATUS_REG=0;
}
}
}
通过此部分代码就可以实现了我们之前在硬件设计部分描述的功能,这里我们用到了一个
全局变量 USB_STATUS_REG,用来标记 USB 的相关状态,这样我们就可以在串口调试助手查
看当前 USB 的状态了。
软件设计部分就为大家介绍到这里。
32.4 下载验证
在代码编译成功之后,我们通过下载代码 NANO STM32F103 开发板上,在 USB 配置成功
后(注意:USB 数据线,要插在开发板的 USB_SLAVE 口!),串口助手打印如图 32.4.1 所示:
此时,电脑提示发现新硬件,并自动安装驱动,如图 32.4.2 所示:
等 USB 配置成功后,DS1 不亮,DS0 闪烁,并且在电脑上可以看到我们的磁盘,如图 32.4.3
所示:
我们打开设备管理器,在通用串行总线控制器里面可以发现多出了一个 USB Mass Storage
Device,同时看到磁盘驱动器里面多了 1 个磁盘,如图 32.4.4 所示:
此时,我们就可以通过电脑读写 SPI FLASH 里面的内容了。在执行读写操作的时候,就可
以看到 DS1 亮,并且会在串口调试助手上打印当前的读写状态。
注意,在对 SPI FLASH 操作的时候,最好不要频繁的往里面写数据,否则很容易将 SPI
FLASH 写爆!!