USB详解,配置及难点

news/2024/9/18 12:38:38/ 标签: 开发语言, 单片机, stm32, 嵌入式硬件

一、USB发展历史

二、USB简介

        USB有USB1.0/1.1/2.0/3.0多个版本,标准USB由4根线组成,VCC,GND,D+,D-,其中D+和D-是数据线,采用差分传输。在USB主机上,D-和D+都是接了15K的电阻到地,所以在没有设备接入的时候,D+、D-均是低电平。而在USB设备中,如果是高速设备,则会在D+上接一个1.5K的电阻到VCC,而如果是低速设备,则会在D-上接一个1.5K的电阻到VCC,当设备接入主机时,主机就可以判断是否有设备接入,并能判断设备是高速设备还是低速设备。

  • DualCore:这通常指的是一个USB设备具有双核处理器,即设备内部有两个处理器核心,可以提高设备的处理性能和效率。
  •  HID(Human Interface Device):这是指一种USB设备类型,用于与人类交互,例如键盘、鼠标、游戏手柄等。
  • MSC(Mass Storage Class):这是指一种USB设备类型,用于存储数据,例如闪存驱动器、移动硬盘等。

        有些芯片内部有两个USB控制器,名称分别为USB_OTG_FS和USB_OTG_HS。其中HS代表实现高速480Mbps速度模式通信。FS意为全速,速度为12Mbps。HS高速模式必须外接PHY芯片才能实现,例如USB3300等。
⭐OTG的意思是既可以做USB HOST,也可以做USB DEVICE。
⭐USB Host是指驱动过后,板子就可以连接USB接口连接的器件,读取和转载数据了。
⭐USB Device是指驱动过后,板子可以当作一个USB移动设备,通过USB连接到电脑上,类似U盘。

三、USB引脚图

主要有两种情况,一种是单片机引脚控制USB电源,一种是USB一直接通5V电源

四、STM32F407库函数配置USB

4.1 资料准备

(1)SD卡带文件系统的基本工程

(2)USB源码

链接:https://pan.baidu.com/s/1Cy1WokfpHBpDONfbqT_wgQ?pwd=8888 
提取码:8888

4.2 移植过程

4.3 修改错误

编译,报12个错误,从第一个错误解决(解决完一个问题可以尝试编译以下)

(1)添加头文件 #include "stm32f4xx.h"

(2)添加宏定义 USE_USB_OTG_FS

(3)修改usbh_usr.c和usbh_usr.h文件

#include "usbh_usr.h" 
#include "ff.h" 
#include "usart.h" static u8 AppState;
extern USB_OTG_CORE_HANDLE  USB_OTG_Core;//USB OTG 中断服务函数
//处理所有USB中断
void OTG_FS_IRQHandler(void)
{USBH_OTG_ISR_Handler(&USB_OTG_Core);
} 
//USB HOST 用户回调函数.
USBH_Usr_cb_TypeDef USR_Callbacks=
{USBH_USR_Init,USBH_USR_DeInit,USBH_USR_DeviceAttached,USBH_USR_ResetDevice,USBH_USR_DeviceDisconnected,USBH_USR_OverCurrentDetected,USBH_USR_DeviceSpeedDetected,USBH_USR_Device_DescAvailable,USBH_USR_DeviceAddressAssigned,USBH_USR_Configuration_DescAvailable,USBH_USR_Manufacturer_String,USBH_USR_Product_String,USBH_USR_SerialNum_String,USBH_USR_EnumerationDone,USBH_USR_UserInput,USBH_USR_MSC_Application,USBH_USR_DeviceNotSupported,USBH_USR_UnrecoveredError
};
/
//以下为各回调函数实现.//USB HOST 初始化 
void USBH_USR_Init(void)
{printf("USB OTG HS MSC Host\r\n");printf("> USB Host library started.\r\n");printf("  USB Host Library v2.1.0\r\n\r\n");}
//检测到U盘插入
void USBH_USR_DeviceAttached(void)//U盘插入
{printf("检测到USB设备插入!\r\n");
}
//检测到U盘拔出
void USBH_USR_DeviceDisconnected (void)//U盘移除
{printf("USB设备拔出!\r\n");
}  
//复位从机
void USBH_USR_ResetDevice(void)
{printf("复位设备...\r\n");
}
//检测到从机速度
//DeviceSpeed:从机速度(0,1,2 / 其他)
void USBH_USR_DeviceSpeedDetected(uint8_t DeviceSpeed)
{if(DeviceSpeed==HPRT0_PRTSPD_HIGH_SPEED){printf("高速(HS)USB设备!\r\n");}  else if(DeviceSpeed==HPRT0_PRTSPD_FULL_SPEED){printf("全速(FS)USB设备!\r\n"); }else if(DeviceSpeed==HPRT0_PRTSPD_LOW_SPEED){printf("低速(LS)USB设备!\r\n");  }else{printf("设备错误!\r\n");  }
}
//检测到从机的描述符
//DeviceDesc:设备描述符指针
void USBH_USR_Device_DescAvailable(void *DeviceDesc)
{ USBH_DevDesc_TypeDef *hs;hs=DeviceDesc;   printf("VID: %04Xh\r\n" , (uint32_t)(*hs).idVendor); printf("PID: %04Xh\r\n" , (uint32_t)(*hs).idProduct); 
}
//从机地址分配成功
void USBH_USR_DeviceAddressAssigned(void)
{printf("从机地址分配成功!\r\n");   
}
//配置描述符获有效
void USBH_USR_Configuration_DescAvailable(USBH_CfgDesc_TypeDef * cfgDesc,USBH_InterfaceDesc_TypeDef *itfDesc,USBH_EpDesc_TypeDef *epDesc)
{USBH_InterfaceDesc_TypeDef *id; id = itfDesc;   if((*id).bInterfaceClass==0x08){printf("可移动存储器设备!\r\n"); }else if((*id).bInterfaceClass==0x03){printf("HID 设备!\r\n"); }    
}
//获取到设备Manufacturer String
void USBH_USR_Manufacturer_String(void *ManufacturerString)
{printf("Manufacturer: %s\r\n",(char *)ManufacturerString);
}
//获取到设备Product String 
void USBH_USR_Product_String(void *ProductString)
{printf("Product: %s\r\n",(char *)ProductString);  
}
//获取到设备SerialNum String 
void USBH_USR_SerialNum_String(void *SerialNumString)
{printf("Serial Number: %s\r\n",(char *)SerialNumString);    
} 
//设备USB枚举完成
void USBH_USR_EnumerationDone(void)
{ printf("设备枚举完成!\r\n\r\n");    
} 
//无法识别的USB设备
void USBH_USR_DeviceNotSupported(void)
{printf("无法识别的USB设备!\r\n\r\n");    
}  
//等待用户输入按键,执行下一步操作
USBH_USR_Status USBH_USR_UserInput(void)
{ printf("跳过用户确认步骤!\r\n");return USBH_USR_RESP_OK;
} 
//USB接口电流过载
void USBH_USR_OverCurrentDetected (void)
{printf("端口电流过大!!!\r\n");
} extern u8 USH_User_App(void);		//用户测试主程序
//USB HOST MSC类用户应用程序
int USBH_USR_MSC_Application(void)
{u8 res=0;switch(AppState){case USH_USR_FS_INIT://初始化文件系统 printf("开始执行用户程序!!!\r\n");AppState=USH_USR_FS_TEST;break;case USH_USR_FS_TEST:	//执行USB OTG 测试主程序res=USH_User_App(); //用户主程序res=0;if(res)AppState=USH_USR_FS_INIT;break;default:break;} return res;
}
//用户要求重新初始化设备
void USBH_USR_DeInit(void)
{AppState=USH_USR_FS_INIT;
}
//无法恢复的错误!!  
void USBH_USR_UnrecoveredError (void)
{printf("无法恢复的错误!!!\r\n\r\n");	
}//用户定义函数,实现fatfs diskio的接口函数 
extern USBH_HOST              USB_Host;//获取U盘状态
//返回值:0,U盘未就绪
//      1,就绪
u8 USBH_UDISK_Status(void)
{return HCD_IsDeviceConnected(&USB_OTG_Core);//返回U盘状态
}//读U盘
//buf:读数据缓存区
//sector:扇区地址
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;		 
u8 USBH_UDISK_Read(u8* buf,u32 sector,u32 cnt)
{u8 res=1;if(HCD_IsDeviceConnected(&USB_OTG_Core)&&AppState==USH_USR_FS_TEST)//连接还存在,且是APP测试状态{  		    do{res=USBH_MSC_Read10(&USB_OTG_Core,buf,sector,512*cnt);USBH_MSC_HandleBOTXfer(&USB_OTG_Core ,&USB_Host);		      if(!HCD_IsDeviceConnected(&USB_OTG_Core)){res=1;//读写错误break;};   }while(res==USBH_MSC_BUSY);}else res=1;		  if(res==USBH_MSC_OK)res=0;	return res;
}//写U盘
//buf:写数据缓存区
//sector:扇区地址
//cnt:扇区个数	
//返回值:错误状态;0,正常;其他,错误代码;		 
u8 USBH_UDISK_Write(u8* buf,u32 sector,u32 cnt)
{u8 res=1;if(HCD_IsDeviceConnected(&USB_OTG_Core)&&AppState==USH_USR_FS_TEST)//连接还存在,且是APP测试状态{  		    do{res=USBH_MSC_Write10(&USB_OTG_Core,buf,sector,512*cnt); USBH_MSC_HandleBOTXfer(&USB_OTG_Core ,&USB_Host);		      if(!HCD_IsDeviceConnected(&USB_OTG_Core)){res=1;//读写错误break;};   }while(res==USBH_MSC_BUSY);}else res=1;		  if(res==USBH_MSC_OK)res=0;	return res;
}

/********************************************************************************* @file    usbh_usr.h* @author  MCD Application Team* @version V2.1.0* @date    19-March-2012* @brief   Header file for usbh_usr.c******************************************************************************* @attention** <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>** Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");* You may not use this file except in compliance with the License.* You may obtain a copy of the License at:**        http://www.st.com/software_license_agreement_liberty_v2** Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.********************************************************************************/ /* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USH_USR_H__
#define __USH_USR_H__/* Includes ------------------------------------------------------------------*/
#include "ff.h"
#include "usbh_core.h"
#include "usb_conf.h"
#include <stdio.h>
#include "usbh_msc_core.h"
#include "usb_hcd_int.h"/** @addtogroup USBH_USER* @{*//** @addtogroup USBH_MSC_DEMO_USER_CALLBACKS* @{*//** @defgroup USBH_USR* @brief This file is the Header file for usbh_usr.c* @{*/ /** @defgroup USBH_USR_Exported_Types* @{*/ extern  USBH_Usr_cb_TypeDef USR_Callbacks;/*** @}*/ /** @defgroup USBH_USR_Exported_Defines* @{*/ 
/* State Machine for the USBH_USR_ApplicationState */
#define USH_USR_FS_INIT       	0
#define USH_USR_FS_TEST   		1  /*** @}*/ /** @defgroup USBH_USR_Exported_Macros* @{*/ 
/*** @}*/ /** @defgroup USBH_USR_Exported_Variables* @{*/ 
extern  uint8_t USBH_USR_ApplicationState ;
/*** @}*/ /** @defgroup USBH_USR_Exported_FunctionsPrototype* @{*/ 
void USBH_USR_ApplicationSelected(void);
void USBH_USR_Init(void);
void USBH_USR_DeInit(void);
void USBH_USR_DeviceAttached(void);
void USBH_USR_ResetDevice(void);
void USBH_USR_DeviceDisconnected (void);
void USBH_USR_OverCurrentDetected (void);
void USBH_USR_DeviceSpeedDetected(uint8_t DeviceSpeed); 
void USBH_USR_Device_DescAvailable(void *);
void USBH_USR_DeviceAddressAssigned(void);
void USBH_USR_Configuration_DescAvailable(USBH_CfgDesc_TypeDef * cfgDesc,USBH_InterfaceDesc_TypeDef *itfDesc,USBH_EpDesc_TypeDef *epDesc);
void USBH_USR_Manufacturer_String(void *);
void USBH_USR_Product_String(void *);
void USBH_USR_SerialNum_String(void *);
void USBH_USR_EnumerationDone(void);
USBH_USR_Status USBH_USR_UserInput(void);
void USBH_USR_DeInit(void);
void USBH_USR_DeviceNotSupported(void);
void USBH_USR_UnrecoveredError(void);
int USBH_USR_MSC_Application(void);u8 USBH_UDISK_Status(void);
u8 USBH_UDISK_Read(u8* buf,u32 sector,u32 cnt);
u8 USBH_UDISK_Write(u8* buf,u32 sector,u32 cnt);/*** @}*/ #endif /*__USH_USR_H__*//*** @}*/ /*** @}*/ /*** @}*/ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

 编译之后只存在3个错误

(4)修改diski.c文件,添加对U盘的访问

/*-----------------------------------------------------------------------*/
/* Low level disk I/O module SKELETON for FatFs     (C)ChaN, 2019        */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be        */
/* attached to the FatFs via a glue function rather than modifying it.   */
/* This is an example of glue functions to attach various exsisting      */
/* storage control modules to the FatFs module with a defined API.       */
/*-----------------------------------------------------------------------*/#include "ff.h"			/* Obtains integer types */
#include "diskio.h"		/* Declarations of disk functions */
#include "sdio_sdcard.h"
#include "usbh_usr.h" /* Definitions of physical drive number for each drive */#define DEV_MMC		1	/* Example: Map MMC/SD card to physical drive 0 */
#define DEV_USB		0	/* Example: Map USB MSD to physical drive 1 */
#define DEV_RAM		2	/* Example: Map Ramdisk to physical drive 2 *//*-----------------------------------------------------------------------*/
/* Get Drive Status                                                      */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (BYTE pdrv		/* Physical drive nmuber to identify the drive */
)
{switch (pdrv) {case DEV_RAM :break;case DEV_MMC :break;case DEV_USB :return 0;}return STA_NOINIT;
}/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/DSTATUS disk_initialize (BYTE pdrv				/* Physical drive nmuber to identify the drive */
)
{int result;switch (pdrv) {case DEV_RAM :break;case DEV_MMC :break;case DEV_USB :if(USBH_UDISK_Status())return 0;	//U盘连接成功,则返回1.否则返回0		  break;}return STA_NOINIT;
}/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/DRESULT disk_read (BYTE pdrv,		/* Physical drive nmuber to identify the drive */BYTE *buff,		/* Data buffer to store read data */LBA_t sector,	/* Start sector in LBA */UINT count		/* Number of sectors to read */
)
{int result;switch (pdrv) {case DEV_RAM :break;case DEV_MMC :break;case DEV_USB :result=USBH_UDISK_Read(buff,sector,count);	  if(result==0)	return 0;}return RES_PARERR;
}/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/#if FF_FS_READONLY == 0DRESULT disk_write (BYTE pdrv,			/* Physical drive nmuber to identify the drive */const BYTE *buff,	/* Data to be written */LBA_t sector,		/* Start sector in LBA */UINT count			/* Number of sectors to write */
)
{int res;switch (pdrv) {case DEV_RAM :break;case DEV_MMC :break;case DEV_USB :res=USBH_UDISK_Write((u8*)buff,sector,count); if(res==0)	return 0;break;}return RES_PARERR;
}#endif/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/DRESULT disk_ioctl (BYTE pdrv,		/* Physical drive nmuber (0..) */BYTE cmd,		/* Control code */void *buff		/* Buffer to send/receive control data */
)
{int res=0;switch (pdrv) {case DEV_RAM :break;case DEV_MMC :break;case DEV_USB :res=1;switch(cmd){case CTRL_SYNC:res = RES_OK; break;	 case GET_SECTOR_SIZE:*(WORD*)buff=512;res = RES_OK;break;	 case GET_BLOCK_SIZE:*(WORD*)buff=512;res = RES_OK;break;	 case GET_SECTOR_COUNT:*(DWORD*)buff=USBH_MSC_Param.MSCapacity;res = RES_OK;break;default:res = RES_PARERR;break;}	}if(res==1) return 0;return RES_PARERR;
}DWORD get_fattime (void)
{				 return 0;
}	

(5)修改ffconf.h文件,将_VOLUME的值改成2,以支持2个磁盘(SD卡和U盘)

#define FF_VOLUMES		2//支持2个磁盘(SD卡和U盘)

(6)修改usb_bsp.c文件

#include "usb_bsp.h"
#include "sys.h"
#include "delay.h"//USB主机电源控制口
#define USB_HOST_PWRCTRL 	PAout(15)	//PA15void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA , ENABLE);  RCC_AHB2PeriphClockCmd( RCC_AHB2Periph_OTG_FS , ENABLE);  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;GPIO_Init(GPIOA, &GPIO_InitStructure);  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;GPIO_Init(GPIOA, &GPIO_InitStructure);    USB_HOST_PWRCTRL=1;			//开启USB HOST电源供电GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_OTG_FS);GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_OTG_FS);
}void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev)
{NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = OTG_FS_IRQn;  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;NVIC_InitStructure.NVIC_IRQChannelSubPriority =0x03;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);  }//USB OTG 中断设置,开启USB FS中断
//pdev:USB OTG内核结构体指针
void USB_OTG_BSP_DisableInterrupt(void)
{ 
}//USB OTG 端口供电设置(本例程未用到)
//pdev:USB OTG内核结构体指针
//state:0,断电;1,上电
void USB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE *pdev, uint8_t state)
{ 
}//USB_OTG 端口供电IO配置(本例程未用到)
//pdev:USB OTG内核结构体指针
void  USB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE *pdev)
{ 
} //USB_OTG us级延时函数
//本例程采用SYSTEM文件夹的delay.c里面的delay_us函数实现
//官方例程采用的是定时器2来实现的.
//usec:要延时的us数.
void USB_OTG_BSP_uDelay (const uint32_t usec)
{ delay_us(usec);
}//USB_OTG ms级延时函数
//本例程采用SYSTEM文件夹的delay.c里面的delay_ms函数实现
//官方例程采用的是定时器2来实现的.
//msec:要延时的ms数.
void USB_OTG_BSP_mDelay (const uint32_t msec)
{  delay_ms(msec);
}

4.4 main.c函数 

USBH_HOST  USB_Host;
USB_OTG_CORE_HANDLE  USB_OTG_Core;FATFS fs[2];//U盘插入以后,实现用户需要实现的功能
//返回值:0,正常
//       1,有问题
u8 USH_User_App(void)
{ u8 result=0;printf("USB设备连接成功\r\n");	 result=f_mount(&fs[1],"1:",1); 	//重新挂载U盘printf("f_mount %d\r\n",result);while(HCD_IsDeviceConnected(&USB_OTG_Core))//只要U盘是连接状态,则一直执行while循环{	}f_mount(0,"1:",1); 	//卸载U盘printf("USB设备连接中\r\n");	 return result;
} main()
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2delay_init(168);  //初始化延时函数uart_init(115200);		//初始化串口波特率为115200//初始化USB主机USBH_Init(&USB_OTG_Core,USB_OTG_FS_CORE_ID,&USB_Host,&USBH_MSC_cb,&USR_Callbacks);  while(1){USBH_Process(&USB_OTG_Core, &USB_Host);//用于实现USB主机通信的核心状态机处理,该函数必须被循环调用,而且调用频率越快越好,以便及时处理各种事务}
}

注意:如果只有一个设备的情况下需要先挂载0磁盘,然后下一个设备挂载1磁盘。因为如果直接挂载1磁盘,他挂载不会报错,但是打开文件时报错,The volume has no work area。 

4.5 测试结果

4.6 完整工程代码

链接:https://pan.baidu.com/s/1-zBpkGQRTFZnnn-ZNXB3dg
提取码:生日

五、STM32Cubemx配置USB

下面配置USB为存储设备,单片机对U盘数据进行读写

5.1 配置时钟

 5.2 配置USB为全速模式(没有PHY芯片只能配置为全速模式)

5.3 配置USB电源控制引脚,看原理图,然后将该引脚配置为输出,并输出高低电平使USB开启供电 

5.4 配置USB_HOST模式 

 5.5 配置FATFS文件系统

 5.6 配置USB时钟,USB时钟必须使48Mhz

 5.7 将堆栈设置大一些,防止USB调用malloc申请内存空间时失败进入硬件中断错误。

 5.7 生成文件

 5.8 加入测试代码

1、 在main.c文件中前面加入如下代码

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
extern ApplicationTypeDef Appli_state;
extern USBH_HandleTypeDef hUsbHostFS;
extern char USBHPath[4]; // USBH logical drive pathFATFS FatfsUDisk; // File system object for USB disk logical drive
FIL myFile; // File objectstatic void MSC_Application(void)
{FRESULT fres; // FatFs function common result codeuint32_t byteswrite;uint8_t str[] = "hello world!";/* Register the file system object to the FatFs module */if( f_mount(&FatfsUDisk, (TCHAR const*)USBHPath, 0) != FR_OK){Error_Handler(); //FatFs Initialization Error}else{/* Create and Open a new text file object with write access */if(f_open(&myFile, "test.txt", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK){Error_Handler(); //'STM32.TXT' file Open for write Error}else{fres = f_write(&myFile, str, sizeof(str), (void *)&byteswrite);if(byteswrite == 0 || (fres != FR_OK)){Error_Handler();}else{f_close(&myFile); //Close the open text file}}}
}
/* USER CODE END 0 */

 2、 在main.c文件中  int main(void) 函数中 while(1)内加入如下代码

while (1){MX_USB_HOST_Process();switch(Appli_state){case APPLICATION_READY:MSC_Application();Appli_state = APPLICATION_DISCONNECT;break;case APPLICATION_DISCONNECT:f_mount(NULL, "", 0);break;default:break;}}

3、 插上U盘,运行代码一小段时间后,取下U盘,插入电脑看是否有代码中建立的文件及写入文件的内容!有则成功啦! 

 

六、STM32F407实现USB在线升级

USB和文件系统移植成功后,就可以开始主函数的书写

首先主函数里面需要循环调用USBH_Process函数,它的作用是:用于实现USB主机通信的核心状态机处理,该函数必须被循环调用,而且调用频率越快越好,以便及时处理各种事务

其次,当设备检测到USB的插入后,会自动跳转到USH_User_App函数,此时我们需要在该函数中加入程序升级的代码,具体思路如下:读.bin文件,然后下载到指令地址,最后跳转到指令地址运行。

最后,总体实现代码如下所示。

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"  
#include "sdio_sdcard.h"    
#include "ff.h"  
#include "string.h"
#include "usbh_usr.h" 
#include "flash.h"//首先对内部Flash空间进行划分,前128K用于存储BootLoader程序,后面的空间用于存储App程序。
#define IAP_SIZE                           ((uint32_t)0x60000)   /* 128Kbytes as IAP size */
#define APPLICATIONADDRESS                 ((uint32_t)0x08060000) /* User start code space */
#define APPLICATIONSIZE                    ((uint32_t)0x080E0000)
#define BUF_SIZE	128u8 buf[BUF_SIZE+5];USBH_HOST  USB_Host;
USB_OTG_CORE_HANDLE  USB_OTG_Core;
int writeNewProgram(void);typedef  void (*pFunction)(void);
pFunction Jump_To_Application;
uint32_t JumpAddress;//跳转到App程序运行 
void jumpToApp(void)
{if ( ( ( * ( __IO uint32_t * ) APPLICATIONADDRESS ) & 0x2FFE0000 ) == 0x20000000 ) //检查栈顶地址是否有数据,FLASH写入成功{printf("正在跳转运行程序\r\n");JumpAddress = *(__IO uint32_t*) (APPLICATIONADDRESS + 4);//用户代码区第二个字为程序开始地址(复位地址)Jump_To_Application = (pFunction) JumpAddress;//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)MSR_MSP(*(vu32*)APPLICATIONADDRESS);					//初始化APP堆栈指针(用户代码区的第一个字用于存放栈顶地址)RCC_AHB2PeriphClockCmd( RCC_AHB2Periph_OTG_FS , DISABLE);  //必须失能USB,不然后续代码会因为USB卡死Jump_To_Application();}
}//U盘插入以后,实现用户需要实现的功能
//返回值:0,正常
//       1,有问题
u8 USH_User_App(void)
{ u8 result=0;printf("USB设备连接成功\r\n");	if(!writeNewProgram())jumpToApp();while(HCD_IsDeviceConnected(&USB_OTG_Core))//只要U盘是连接状态,则一直执行while循环{	}printf("USB设备连接中\r\n");	 return result;
} int writeNewProgram(void)
{FRESULT result;FIL fil;FATFS fs;int isFinish = 0;int bytesread;char *fileName="LED.bin";uint32_t startaddress = APPLICATIONADDRESS;uint32_t endaddress = APPLICATIONSIZE;printf("start write new program");result=f_mount(&fs,"0:",1); 	//重新挂载U盘printf("f_mount %d\r\n",result);result = f_open(&fil,fileName, FA_READ );//打开程序文件printf("f_open %d\r\n",result);if(result){printf("open %s error\r\n",fileName);isFinish=1;}else{printf("open %s sucess\r\n",fileName);}printf("start program\r\n");while( startaddress < endaddress && isFinish == 0){result = f_read(&fil, buf,BUF_SIZE, (UINT*)&bytesread);//读取128Bytes数据if(result){printf("read address  error\r\n");isFinish=1;break;}else{printf("read address sucess ,data is :%d\r\n",bytesread);}if(STMFLASH_Write(startaddress,(uint32_t *)buf,bytesread/4)){printf("STMFLASH_Write err\r\n");}else{printf("STMFLASH_Write OK\r\n");}startaddress += bytesread;if( bytesread < BUF_SIZE )//如果读取数据长度错误或者读取完毕{break;}}result = f_close(&fil);if(result){printf("close %s error:%d\r\n",fileName,result);}else{printf("close %s sucess\r\n",fileName);}printf("end write program\r\n");result=f_mount(NULL,"0:",0); return isFinish;
}int main(void)
{        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2delay_init(168);  //初始化延时函数uart_init(115200);		//初始化串口波特率为115200//初始化USB主机USBH_Init(&USB_OTG_Core,USB_OTG_FS_CORE_ID,&USB_Host,&USBH_MSC_cb,&USR_Callbacks);  while(1){USBH_Process(&USB_OTG_Core, &USB_Host);//用于实现USB主机通信的核心状态机处理,该函数必须被循环调用,而且调用频率越快越好,以便及时处理各种事务}
}

链接:https://pan.baidu.com/s/18uUT0wrLKnioZBnBwAgD6w
提取码:生日

七、STM32 USB DEVICE 复位后 无法识别

现象是,如果USB一直处于插着状态,软件复位后,无法识别USB插入,那么就在USB初始化前强制USB时钟复位,就相当于告诉电脑断开链接。

void USB_Disconnected(void) {__HAL_RCC_USB_FORCE_RESET();HAL_Delay(200);__HAL_RCC_USB_RELEASE_RESET();GPIO_InitTypeDef GPIO_Initure;__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_Initure.Pin = GPIO_PIN_11 | GPIO_PIN_12;GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP;GPIO_Initure.Pull = GPIO_PULLDOWN;GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA, &GPIO_Initure);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_11, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, GPIO_PIN_RESET);HAL_Delay(300);
}


http://www.ppmy.cn/news/1516417.html

相关文章

网络安全场景化解决方案编写教程(大纲)

目录 1.概述 1.1.项目背景 1.2.项目现状 1.3.项目目标 2.需求分析 3.方案设计 3.1设计依据 3.2设计原则 3.3架构设计 3.3产品设计 3.5服务设计 4.方案收益 5.项目预算 附录A&#xff08;案例&#xff09; 附录B&#xff08;公司资质人员资质等&#xff09; 1.概…

UnrealEngine学习(02):虚幻引擎编辑器界面详解

学习一款软件&#xff0c;我个人建议是先学习怎么用&#xff0c;然后是学习怎么用的好&#xff0c;再研究源码。 上一篇文章详细描述了我们该如何安装虚幻5引擎&#xff1a; UnrealEngine学习(01)&#xff1a;安装虚幻引擎https://blog.csdn.net/zuodingquan666/article/deta…

无人机+消防车:高楼灭火系统技术详解

“无人机消防车”高楼灭火系统技术是一种创新的消防解决方案&#xff0c;旨在解决高层建筑灭火难题。以下是对该技术的详细解析&#xff1a; 一、技术背景与需求 高层建筑数量多&#xff0c;火灾隐患多发。根据国家消防救援局发布的数据&#xff0c;高层建筑火灾频发&#xf…

Robot Operating System——兴趣区域信息

大纲 应用场景定义字段解释 案例 sensor_msgs::msg::RegionOfInterest 是 ROS (Robot Operating System) 中的一个消息类型&#xff0c;用于表示图像中的感兴趣区域 (Region of Interest, ROI)。它通常与图像处理和计算机视觉任务相关联&#xff0c;帮助系统聚焦于图像中的特定…

Java并发编程的核心概念--线程与进程

‌原子性‌&#xff1a;‌操作或多个操作要么全部执行且不被打断&#xff0c;‌要么都不执行。‌这保证了线程在执行操作时不会被其他线程干扰。‌‌可见性‌&#xff1a;‌当多个线程访问同一个变量时&#xff0c;‌一个线程修改了这个变量的值&#xff0c;‌其他线程能够立即…

【MySQL】MySQL表的增删改查(初阶)

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 表内容操作 插入内容 按顺序插入 指定某些列插入 一次插入多行记录 插入时间 查询表内容 全列查询 指定列查询 指定表达式查询 用as取别名 ​编辑 去重查询 排序查询…

计算机毕业设计选题推荐-高校学术交流平台-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

基于微信小程序的行李寄存管理系统的设计与实现(论文+源码)_kaic

基于微信小程序的行李寄存管理系统的设计与实现(论文源码)_kaic 摘 要 人们外出旅行的时候&#xff0c;经常会需要到行李寄存的服务。行李寄存处在全国各地都很常见。现存的行李寄存方式很传统&#xff0c;适合小规模的行李寄存&#xff0c;当行李数量较多时&#xff0c;就…

JVM常见面试题总结

文章目录 1 JVM 组成1.1 JVM架构组成&#x1f525;1.2 JVM 内存结构/内存模型&#x1f525;1.3 堆和栈区别&#x1f525;1.4 详细的介绍 Java 堆&#x1f525;1.5 JVM 为什么使用元空间替换了永久代&#xff1f;&#x1f525;1.6 内存溢出与内存泄漏的区别&#x1f525;1.7 OOM…

根据数据库设计开发一套通用的电子商务平台

目录 案例 【题目】 【问题 1】(9 分) 【问题 2】(9 分) 【问题 3】(7 分) 【答案】 【问题 1】解析 【问题 2】解析 【问题 3】解析 相关推荐 案例 阅读以下关于数据库设计的叙述&#xff0c;在答题纸上回答问题 1 至问题 3。 【题目】 某制造企业为拓展网上销售业…

河南萌新联赛2024第(六)场:郑州大学(补题ABCDFGIL)

文章目录 河南萌新联赛2024第&#xff08;六&#xff09;场&#xff1a;郑州大学A 装备二选一&#xff08;一&#xff09;简单介绍&#xff1a;思路&#xff1a;代码&#xff1a; B 百变吗喽简单介绍&#xff1a;思路&#xff1a;代码&#xff1a; C 16进制世界简单介绍&#x…

es相关概念、索引操作(相当于mysql中的数据库操作)

文章目录 1、概念2、索引操作&#xff08;index&#xff09;2.1、查询索引&#xff08;数据库&#xff09;2.2、创建索引&#xff08;数据库&#xff09;2.3、查看单个索引&#xff08;数据库&#xff09;2.4、删除索引&#xff08;数据库&#xff09; 1、概念 RDBMSesMongoDB…

Manim实现目标的移动和出现速度控制

一&#xff0c;介绍 缓动函数 自定义参数随时间变化的速率。 现实生活中&#xff0c;物体并不是突然启动或者停止&#xff0c; 当然也不可能一直保持匀速移动。就像我们 打开抽屉的过程那样&#xff0c;刚开始拉的那一下动作很快&#xff0c; 但是当抽屉被拉出来之后我们会不自…

【操作系统】实验:进程死锁

目录 一、实验目的 二、实验要求 三、实验步骤 四、核心代码 五、记录与处理 六、思考 七、完整报告和成果文件提取链接 一、实验目的 1掌握死锁的基本概念&#xff1b; 2理解死锁的必要条件&#xff1b; 3理解避免死锁的方法、安全状态等重要概念&#xff1b; 4了解银…

Windows环境如何安装maven并配置IDEA

运行Springboot项目时&#xff0c;出现了依赖错误&#xff0c;最后排查可能是maven安装出错了。 MAVEN版本要和IDEA版本对应&#xff0c;maven发行版本不能比idea版本高&#xff0c;可以在idea查看内置的maven版本。 点击 File–>Settings,在设置页面搜索maven&#xff0c;如…

2024牛客暑期多校训练营7 D.Interval Selection(异或哈希+双指针)

原题链接&#xff1a;D.Interval Selection 题目大意&#xff1a; 给你一个长度为 n n n 的数组 a a a&#xff0c;定义一个区间 [ l , r ] [l,r] [l,r] 内的连续子数组为好的&#xff0c;当且仅当这个子数组内的所有元素 a l , a l 1 , . . . , a r a_{l},a_{l1},...,a_{…

虚幻5|暴击攻击和释放技能,造成伤害

玩家数据的Actor组件制作&#xff1a;虚幻5|制作玩家血量&#xff0c;体力-CSDN博客 造成伤害时&#xff0c;显示暴击及暴击字体颜色和未暴击的字体颜色&#xff0c;还有释放技能连击 一.编辑暴击数据 1.打开之前创建的玩家数据Actor组件 创建一个浮点变量&#xff0c;命名…

Python实现贪心算法

目录 贪心算法简介贪心算法的基本思想贪心算法的应用场景活动选择问题 Python实现活动选择问题代码解释活动选择问题的解贪心算法的正确性分析贪心算法的其他应用贪心算法的局限性贪心算法的优化与变种总结 贪心算法简介 贪心算法&#xff08;Greedy Algorithm&#xff09;是一…

10天速通Tkinter库——Day7:主菜单及图鉴

本篇博客我将介绍Tkinter实践项目《植物杂交实验室》中的杂交实验室主菜单、基础植物图鉴、杂交植物图鉴、杂交植物更多信息四个页面的制作。 它们作为主窗口的子页面实例&#xff0c;除了继承主窗口的基础设置&#xff08;如图标、标题、尺寸等等&#xff09;、还可以使用主窗…

使用C++开发黑神话悟空类似3A如何避免内存泄漏

智能指针&#xff1a;使用C11或更高版本中的智能指针&#xff08;如std::unique_ptr、std::shared_ptr和std::weak_ptr&#xff09;来自动管理内存。这些智能指针在超出作用域时会自动释放它们所管理的内存。 RAII&#xff08;Resource Acquisition Is Initialization&#xf…