前言
单片机和PC直接如何通信?最常见接口为串口以及USB。本章详细讲解如何配置STM32单片机USB功能。
1.前期准备
1.运行环境windows10;
2.stm32f103x开发板一套;
3.安装好STM32CubeMX;
其中,需配置Clion满足嵌入式开发要求,如果没有安装可以参考《使用 CLion 进行嵌入式开发》
2.预期结果
开发板通过USB插入PC,PC可成功识别到一个U盘并可在U盘中新建、删除文件等。
3.使用CubeMX生成工程
step1:运行 CubeMX
,新建工程并选择芯片 STM32F103RCTx
,如下图。
step2:系统时钟配置为外部时钟,如下图。
step3:使能下载调试接口 SWD
,如下图,后续需要通过该接口下载程序至单片机。
step4:使能 USB
,如下图所示,③处参数保持默认值。
step5:USB配置选择 Mass Storage Class
,并将③处改为 4096
,原因为我们开发板采用外部 Flash
W25Q64
模拟U盘存储数据, W25Q64
一个扇区大小为 4096 Byte
,配置如下图所示。
step6: USB时钟配置为 48MHz
。
step7: 开启 SPI1
,因开发板外部 Flash
W25Q64
和单片机之间通过 SPI1
实现通信。如下图所示,SPI1
模式选择 Full-Duplex-Master
,③处分频系数改为 16
将波特率设置为 4.5Mbit/s
。
step8:配置FLASH
片选引脚PA4为上拉输出,如下图所示。
step9:USB初始化等需要使用堆栈,将堆栈空间改稍大些,并点击右上角 GENERATE CODE
生成工程,如下图。
4.修改工程中USB读写函数代码
step1:将SPI
FLASH
驱动文件bps_spi_flash.h
,bps_spi_flash.c
添加至工程中。
step2:main.c
文件函数static void MX_SPI1_Init(void)
添加SPI
使能代码:
/* USER CODE BEGIN SPI1_Init 2 */
__HAL_SPI_ENABLE(&hspi1);//使能SPI1
/* USER CODE END SPI1_Init 2 */
sep3:修改USB初始化函数int8_t STORAGE_Init_FS(uint8_t lun)
修改读函数:int8_tSTORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
,修改写函数:int8_tSTORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
,代码如下所示。
#include "bsp_spi_flash.h"
#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 256*4 //256*4扇区=4MByte
#define STORAGE_BLK_SIZ 4096 //每个扇区4096Byte
static int8_t STORAGE_Init_FS(uint8_t lun);
static int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size);
static int8_t STORAGE_IsReady_FS(uint8_t lun);
static int8_t STORAGE_IsWriteProtected_FS(uint8_t lun);
static int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);
static int8_t STORAGE_GetMaxLun_FS(void);
/**
* @brief .
* @param lun: .
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Init_FS(uint8_t lun)
{
/* USER CODE BEGIN 2 */
W25QXX_Init();
return (USBD_OK);
/* USER CODE END 2 */
}
/**
* @brief .
* @param lun: .
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 6 */
blk_addr+=SPI_FLASH_START_SECTOR;
SPI_FLASH_BufferRead(buf, blk_addr*SPI_FLASH_SECTOR_SIZE, blk_len*SPI_FLASH_SECTOR_SIZE);
return (USBD_OK);
/* USER CODE END 6 */
}
/**
* @brief .
* @param lun: .
* @retval USBD_OK if all operations are OK else USBD_FAIL
*/
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 7 */
uint32_t write_addr;
blk_addr+=SPI_FLASH_START_SECTOR;
write_addr = blk_addr*SPI_FLASH_SECTOR_SIZE;
SPI_FLASH_SectorErase(write_addr);
SPI_FLASH_BufferWrite((uint8_t *)buf,write_addr,blk_len*SPI_FLASH_SECTOR_SIZE);
return (USBD_OK);
/* USER CODE END 7 */
}
step4:main()
函数中语句SPI_HandleTypeDef hspi1;
前增加extern
关键字,因该变量在bps_spi_flash.h
中已经定义过,引用即可。
extern SPI_HandleTypeDef hspi1;
至此,已完成代码修改。
4.程序下载验证
编译代码,将程序下载至开发板,并通过USB连接至电脑,格式化后,如下图所示显示容量为4MB的U盘。
后续即可当普通U盘使用。FLASH
驱动文件及工程完整代码:github完整代码