正点原子STM32F407探索者开发板资料连载第56章 USB 读卡器实验
yuyutoo 2025-05-23 21:10 2 浏览 0 评论
1)实验平台:alientek 阿波罗 STM32F767 开发板
2)摘自《STM32F7 开发指南(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子
第五十六章 USB 读卡器(Slave)实验
STM32F407 系列芯片都自带了 USB OTG FS 和 USB OTG HS(HS 需要外扩高速 PHY 芯
片实现,速度可达 480Mbps),支持 USB Host 和 USB Device,探索者 STM32F4 开发板没有外
扩高速 PHY 芯片,仅支持 USB OTG FS(FS,即全速,12Mbps),所有 USB 相关例程,均使
用 USB OTG FS 实现。
本章,我们将向大家介绍如何利用 USB OTG FS 在 ALIENTEK 探索者 STM32F4 开发板实
现一个 USB 读卡器。本章分为如下几个部分:
56.1 USB 简介
56.2 硬件设计
56.3 软件设计
56.4 下载验证
56.1 USB 简介
USB ,是英文 Universal Serial BUS(通用串行总线)的缩写,而其中文简称为“通串线,
是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在 PC 领域的接口技术。
USB 接口支持设备的即插即用和热插拔功能。USB 是在 1994 年底由英特尔、康柏、IBM、
Microsoft 等多家公司联合提出的。
USB 发展到现在已经有 USB1.0/1.1/2.0/3.0 等多个版本。目前用的最多的就是 USB1.1 和
USB2.0,USB3.0 目前已经开始普及。STM32F407 自带的 USB 符合 USB2.0 规范。
标准 USB 共四根线组成,除 VCC/GND 外,另外为 D+和 D-,这两根数据线采用的是差分
电压的方式进行数据传输的。在 USB 主机上,D-和 D+都是接了 15K 的电阻到地的,所以在没
有设备接入的时候,D+、D-均是低电平。而在 USB 设备中,如果是高速设备,则会在 D+上接
一个 1.5K 的电阻到 VCC,而如果是低速设备,则会在 D-上接一个 1.5K 的电阻到 VCC。这样
当设备接入主机的时候,主机就可以判断是否有设备接入,并能判断设备是高速设备还是低速
设备。接下来,我们简单介绍一下 STM32 的 USB 控制器。
STM32F407 系列芯片自带有 USB OTG FS(全速)和 USB OTG HS(高速),其中 HS 需
要外扩高速 PHY 芯片实现,我们这里不做介绍。
STM32F407 的 USB OTG FS 是一款双角色设备 (DRD) 控制器,同时支持从机功能和主机
功能,完全符合 USB 2.0 规范的 On-The-Go 补充标准。此外,该控制器也可配置为“仅主机”
模式或“仅从机” 模式,完全符合 USB 2.0 规范。在主机模式下,OTG FS 支持全速(FS,12
Mb/s)和低速(LS,1.5 Mb/s)收发器,而从机模式下则仅支持全速(FS,12 Mb/s)收发器。
OTG FS 同时支持 HNP 和 SRP。
STM32F407 的 USB OTG FS 主要特性可分为三类:通用特性、主机模式特性和从机模式特
性。
1,通用特性
经 USB-IF 认证,符合通用串行总线规范第 2.0 版
集成全速 PHY,且完全支持定义在标准规范 OTG 补充第 1.3 版中的 OTG 协议
1,支持 A-B 器件识别(ID 线)
2,支持主机协商协议(HNP)和会话请求协议(SRP)
3,允许主机关闭 VBUS 以在 OTG 应用中节省电池电量
4,支持通过内部比较器对 VBUS 电平采取监控
5,支持主机到从机的角色动态切换
可通过软件配置为以下角色:
1, 具有 SRP 功能的 USB FS 从机(B 器件)
2, 具有 SRP 功能的 USB FS/LS 主机(A 器件)
3,USB On-The-Go 全速双角色设备
支持 FS SOF 和 LS Keep-alive 令牌
1,SOF 脉冲可通过 PAD 输出
2,SOF 脉冲从内部连接到定时器 2 (TIM2)
3,可配置的帧周期
3, 可配置的帧结束中断
具有省电功能,例如在 USB 挂起期间停止系统、关闭数字模块时钟、对 PHY 和 DFIFO
电源加以管理
具有采用高级 FIFO 控制的 1.25 KB 专用 RAM
1,可将 RAM 空间划分为不同 FIFO,以便灵活有效地使用 RAM
2,每个 FIFO 可存储多个数据包
3,动态分配存储区
4,FIFO 大小可配置为非 2 的幂次方值,以便连续使用存储单元
一帧之内可以无需要应用程序干预,以达到最大 USB 带宽
2,主机(Host)模式特性
通过外部电荷泵生成 VBUS 电压。
多达 8 个主机通道(管道):每个通道都可以动态实现重新配置,可支持任何类型的
USB 传输。
内置硬件调度器可:
1,在周期性硬件队列中存储多达 8 个中断加同步传输请求
2,在非周期性硬件队列中存储多达 8 个控制加批量传输请求
管理一个共享 RX FIFO、一个周期性 TX FIFO 和一个非周期性 TX FIFO,以有效使用
USB 数据 RAM。
3,从机(Slave/Device)模式特性
1 个双向控制端点 0
3 个 IN 端点 (EP),可配置为支持批量传输、中断传输或同步传输
3 个 OUT 端点(EP),可配置为支持批量传输、中断传输或同步传输
管理一个共享 Rx FIFO 和一个 Tx-OUT FIFO,以高效使用 USB 数据 RAM
管理多达 4 个专用 Tx-IN FIFO(分别用于每个使能的 IN EP),降低应用程序负荷支持
软断开功能。
STM32F407 USB OTG FS 框图如图 56.1.1 所示:
图 56.1.1 USB OTG 框图
对于USB OTG FS功能模块,STM32F4通过AHB总线访问(AHB频率必须大于14.2Mhz),
其中 48Mhz 的 USB 时钟,是来自时钟树图里面的 PLL48CK(和 SDIO 共用)。
STM32F4 USB OTG FS 的其他介绍,请大家参考《STM32F4xx 中文参考手册》第 30 章内
容,我们这里就不再详细介绍了。
要正常使用 STM32F4 的 USB,就得编写 USB 驱动,而整个 USB 通信的详细过程是很复
杂的,本书篇幅有限,不可能在这里详细介绍,有兴趣的朋友可以去看看电脑圈圈的《圈圈教
你玩 USB》这本书,该书对 USB 通信有详细讲解。如果要我们自己编写 USB 驱动,那是一件
相当困难的事情,尤其对于从没了解过 USB 的人来说,基本上不花个一两年时间学习,是没法
搞定的。不过,ST 提供了我们一个完整的 USB OTG 驱动库(包括主机和设备),通过这个库,
我们可以很方便的实现我们所要的功能,而不需要详细了解 USB 的整个驱动,大大缩短了我们
的开发时间和精力。
ST 提供的 USB OTG 库,可以在:
http://www.stmcu.org/download/index.php?act=ziliao
&id=150 这里下载到(UM1021)。不过,我们已经帮大家下载到开发板光盘:8,STM32 参考资料
→STM32 USB 学习资料,文件名:
stm32_f105-07_f2_f4_usb-host-device_lib.zip。该库包含
了 STM32F4 USB 主机(Host)和从机(Device)驱动库,并提供了 10 个例程供我们参考,如
图 56.1.2 所示:
图 56.1.2 ST 提供的 USB OTG 例程
如图 56.1.2 所示,ST 提供了 3 类例程:①即设备类(Device,即 Slave)、②主从一体类
(Host_Device)和③主机类(Host),总共 10 个例程。整个 USB OTG 库还有一个说明文档:
CD00289278.pdf(在光盘有提供),即 UM1021,该文档详细介绍了 USB OTG 库的各个组成部分以
及所提供的例程使用方法,有兴趣学习 USB 的朋友,这个文档是必须仔细看的。
这 10 个例程,虽然都是基于官方 EVAL 板的,但是很容易移植到我们的探索者 STM32F407
开发板上,本章我们就是移植:
STM32_USB-Host-Device_Lib_V2.1.0\Project\USB_Device_
Examples\MSC 这个例程,以实现 USB 读卡器功能。
56.2 硬件设计
本章实验功能简介:开机的时候先检测 SD 卡和 SPI FLASH 是否存在,如果存在则获取其
容量,并显示在 LCD 上面(如果不存在,则报错)。之后开始 USB 配置,在配置成功之后就
可以在电脑上发现两个可移动磁盘。我们用 DS1 来指示 USB 正在读写,并在液晶上显示出来,
同样,我们还是用 DS0 来指示程序正在运行。
所要用到的硬件资源如下:
1) 指示灯 DS0 、DS1
2) 串口
3) TFTLCD 模块
4) SD 卡
5) SPI FLASH
6) USB SLAVE 接口
前面 5 部分,在之前的实例中都介绍过了,我们在此就不介绍了。接下来看看我们电脑 USB
与 STM32 的 USB SLAVE 连接口。ALIENTEK 探索者 STM32F4 开发板采用的是 5PIN 的
MiniUSB 接头,用来和电脑的 USB 相连接,连接电路如图 56.2.1 所示:
图 56.2.1 MiniUSB 接口与 STM32 的连接电路图
从上图可以看出,USB 座没有直接连接到 STM32F4 上面,而是通过 P11 转接,所以我们
需要通过跳线帽将 PA11 和 PA12 分别连接到 D-和 D+,如图 56.2.2 所示:
图 56.2.2 硬件连接示意图
不过这个 MiniUSB 座和 USB-A 座(USB_HOST)是共用 D+和 D-的,所以他们不能同时使
用。这个在使用的时候,要特别注意!!本实验测试时,USB_HOST 不能插入任何 USB 设备!
56.3 软件设计
本章,我们在:实验 38 SD 卡实验 的基础上修改,代码移植自 ST 官方例程:STM32_USB
Host-Device_Lib_V2.1.0\Project\USB_Device_Examples\MSC,我打开该例程即可知道 USB 相关
的代码有哪些,如图 56.3.1 所示:
图 56.3.1 ST 官方例程 USB 相关代码
有了这个官方例程做指引,我们就知道具体需要哪些文件,从而实现本章例程。
首先,在本章例程(即实验 38 SD 卡实验)的工程文件夹下面,新建 USB 文件夹,并拷贝
官方 USB 驱动库相关代码到该文件夹下,即拷贝:光盘→ 8,STM32 参考资料→STM32 USB 学
习资料→
STM32_USB-Host-Device_Lib_V2.1.0→Libraries 文件夹下的 STM32_USB_Device_Libr
ary、STM32_USB_HOST_Library 和 STM32_USB_OTG_Driver 等三个文件夹的源码到该文件夹
下面。
然后,在 USB 文件夹下,新建 USB_APP 文件夹存放 MSC 实现相关代码,即:STM32_USB
-Host-Device_Lib_V2.1.0→Project→USB_Device_Examples→MSC→src 下的部分代码:usb_bsp.c
、usbd_storage_msd.c、usbd_desc.c和 usbd_usr.c等4 个.c 文件,同时拷贝 STM32_USB-Host-Device
_Lib_V2.1.0→Project→USB_Device_Examples→MSC→inc 下面的:usb_conf.h、usbd_conf.h 和
usbd_desc.h 等三个文件到 USB_APP 文件夹下,最后 USB_APP 文件夹下的文件如图 56.3.2 所
示:
图 56.3.2 USB_APP 代码
之后,根据 ST 官方 MSC 例程,在我们本章例程的基础上新建分组添加相关代码,具体细
节,这里就不详细介绍了,添加好之后,如图 56.3.3 所示:
图 56.3.3 添加 USB 驱动等相关代码
移植时,我们重点要修改的就是 USB_APP 文件夹下面的代码。其他代码(USB_OTG 和
USB_DEVICE 文件夹下的代码)一般不用修改。
usb_bsp.c 提供了几个 USB 库需要用到的底层初始化函数,包括:IO 设置、中断设置、VBUS
配置以及延时函数等,需要我们自己实现。USB Device(Slave)和 USB Host 共用这个.c 文件。
usbd_desc.c 提供了 USB 设备类的描述符,直接决定了 USB 设备的类型、断点、接口、字
符串、制造商等重要信息。这个里面的内容,我们一般不用修改,直接用官方的即可。注意,
这里:usbd_desc.c 里面的:usbd 即 device 类,同样:usbh 即 host 类,所以通过文件名我们可
以很容易区分该文件是用在 device 还是 host,而只有 usb 字样的那就是 device 和 host 可以共用
的。
usbd_usr.c 提供用户应用层接口函数,即 USB 设备类的一些回调函数,当 USB 状态机处理
完不同事务的时候,会调用这些回调函数,我们通过这些回调函数,就可以知道 USB 当前状态,
比如:是否枚举成功了?是否连接上了?是否断开了?等,根据这些状态,用户应用程序可以
执行不同操作,完成特定功能。
usbd_storage_msd.c 提供一些磁盘操作函数,包括支持的磁盘个数,以及每个磁盘的初始化
和读写等函数。本章我们设置了 2 个磁盘:SD 卡和 SPI FLASH。
以上 4 个.c 文件里面的函数,基本上都是以回调函数的形式,被 USB 驱动库调用的。这些
代码的具体修改过程,我们这里不详细介绍,请大家参考光盘本例程源码,这里只提几个重点
地方讲解下:
1,要使用 USB OTG FS,必须在 MDK 编译器的全局宏定义里面,定义:USE_USB_OTG_FS
宏,如图 56.3.4 所示:
图 56.3.4 定义全局宏 USE_USB_OTG_FS
2,因为探索者 STM32F407 开发板没有用到 VUSB 电压检测,所以要在 usb_conf.h 里面,
将宏定义:#define VBUS_SENSING_ENABLED,屏蔽掉。
3,通过修改 usbd_conf.h 里面的 MSC_MEDIA_PACKET 定义值大小,可以一定程度提高
USB 读写速度(越大越快),本例程我们设置 12*1024,也就是 12K 大小。
4,官方例程不支持大于 4G 的 SD 卡,得修改 usbd_msc_scsi.c 里面的 SCSI_blk_addr 类型
为 uint64_t,才可以支持大于 4G 的卡,官方默认是 uint32_t,最大只能支持 4G 卡。注意:
usbd_msc_scsi.c 文件,是只读的,得先修改属性,去掉只读属性,才可以更改。
以上 4 点,就是我们移植的时候需要特别注意的,其他我们就不详细介绍了(USB 相关
源码解释,请参考:CD00289278.pdf 这个文档)。
最后修改 main.c 里面代码如下:
USB_OTG_CORE_HANDLE USB_OTG_dev;
extern vu8 USB_STATUS_REG;
//USB 状态
extern vu8 bDeviceState;
//USB 连接 情况
int main(void)
{
u8 offline_cnt=0;
u8 tct=0;
u8 USB_STA;
u8 Divece_STA;
uint64_t CardCap;
//SD 卡容量
HAL_Init();
//初始化 HAL 库
Stm32_Clock_Init(336,8,2,7);
//设置时钟,168Mhz
delay_init(168);
//初始化延时函数
uart_init(115200);
//初始化 USART
usmart_dev.init(84);
//初始化 USMART
LED_Init();
//初始化 LED
KEY_Init();
//初始化 KEY
LCD_Init(); //初始化 LCD
SRAM_Init();
//初始化外部 SRAM
W25QXX_Init();
//初始化 W25Q128
my_mem_init(SRAMIN);
//初始化内部内存池
my_mem_init(SRAMEX);
//初始化外部内存池
my_mem_init(SRAMCCM);
//初始化 CCM 内存池
POINT_COLOR=RED;
LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
LCD_ShowString(30,70,200,16,16,"USB Card Reader TEST");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,110,200,16,16,"2017/5/15");
if(SD_Init())LCD_ShowString(30,130,200,16,16,"SD Card Error!"); //检测 SD 卡错误
else //SD 卡正常
{
CardCap=(uint64_t)(SDCardInfo.LogBlockNbr)*(uint64_t)(
SDCardInfo.LogBlockSize);
//计算 SD 卡容量
LCD_ShowString(30,130,200,16,16,"SD Card Size: MB");
LCD_ShowNum(134,130,CardCap>>20,5,16);
//显示 SD 卡容量
}
if(W25QXX_ReadID()!=W25Q128)
LCD_ShowString(30,130,200,16,16,"W25Q128 Error!"); //检测 W25Q128 错误
else //SPI FLASH 正常
{
LCD_ShowString(30,150,200,16,16,"SPI FLASH Size:25MB");
}
LCD_ShowString(30,190,200,16,16,"USB Connecting..."); //提示正在建立连接
MSC_BOT_Data=mymalloc(SRAMIN,MSC_MEDIA_PACKET); //申请内存
USBD_Init(&USB_OTG_dev,USB_OTG_FS_CORE_ID,&USR_desc,&USBD_MSC_cb,
&USR_cb);
delay_ms(1800);
while(1)
{
delay_ms(1);
if(USB_STA!=USB_STATUS_REG)//状态改变了
{
LCD_Fill(30,210,240,210+16,WHITE);//清除显示
if(USB_STATUS_REG&0x01)//正在写
{
LED1=0;
LCD_ShowString(30,210,200,16,16,"USB Writing...");
//提示 USB 正在写入数据
}
if(USB_STATUS_REG&0x02)//正在读
{
LED1=0;
LCD_ShowString(30,210,200,16,16,"USB Reading...");
//提示 USB 正在读出数据
}
if(USB_STATUS_REG&0x04)
LCD_ShowString(30,230,200,16,16,"USB Write Err ");//提示写入错误
else LCD_Fill(30,230,240,230+16,WHITE);//清除显示
if(USB_STATUS_REG&0x08)
LCD_ShowString(30,250,200,16,16,"USB Read Err ");//提示读出错误
else LCD_Fill(30,250,240,250+16,WHITE);//清除显示
USB_STA=USB_STATUS_REG;//记录最后的状态
}
if(Divece_STA!=bDeviceState)
{
if(bDeviceState==1)
LCD_ShowString(30,190,200,16,16,"USB Connected ");
//提示 USB 连接已经建立
else LCD_ShowString(30,190,200,16,16,"USB DisConnected ");
//提示 USB 被拔出了
Divece_STA=bDeviceState;
}
tct++;
if(tct==200)
{
tct=0;
LED1=1;
LED0=!LED0;//提示系统在运行
if(USB_STATUS_REG&0x10)
{
offline_cnt=0;//USB 连接了,则清除 offline 计数器
bDeviceState=1;
}else//没有得到轮询
{
offline_cnt++;
if(offline_cnt>10)bDeviceState=0;
//2s 内没收到在线标记,代表 USB 被拔出了
}
USB_STATUS_REG=0;
}
}
}
其中,USB_OTG_CORE_HANDLE 是一个全局结构体类型,用于存储 USB 通信中 USB 内
核需要使用的的各种变量、状态和缓存等,任何 USB 通信(不论主机,还是从机),我们都必
须定义这么一个结构体以实现 USB 通信,这里定义成:USB_OTG_dev。
然后,USB 初始化非常简单,只需要调用 USBD_Init 函数即可,顾名思义,该函数是 USB
设备类初始化函数,本章的 USB 读卡器属于 USB 设备类,所以使用该函数。该函数初始化了
USB 设备类处理的各种回调函数,以便 USB 驱动库调用。执行完该函数以后,USB 就启动了,
所有 USB 事务,都是通过 USB 中断触发,并由 USB 驱动库自动处理。USB 中断服务函数在
usbd_usr.c 里面:
//USB OTG 中断服务函数 处理所有 USB 中断
void OTG_FS_IRQHandler(void)
{
USBD_OTG_ISR_Handler(&USB_OTG_dev);
}
该函数调用 USBD_OTG_ISR_Handler 函数来处理各种 USB 中断请求。因此在 main 函数里
面,我们的处理过程就非常简单,main 函数里面通过两个全局状态变量(USB_STATUS_REG
和 bDeviceState),来判断 USB 状态,并在 LCD 上面显示相关提示信息。
USB_STATUS_REG 在 usbd_storage_msd.c 里面定义的一个全局变量,不同的位表示不同状
态,用来指示当前 USB 的读写等操作状态。
bDeviceState 是在 usbd_usr.c 里面定义的一个全局变量,0 表示 USB 还没有连接;1 表示
USB 已经连接。
软件设计部分,就给大家介绍到这里。
56.4 下载验证
在代码编译成功之后,我们下载到探索者 STM32F4 开发板上,在 USB 配置成功后(假设
已经插入 SD 卡,注意:USB 数据线,要插在 USB_SLAVE 口!不是 USB_232 端口!另外,
USB_HOST 接口,也不要插入任何设备,否则会干扰!!),LCD 显示效果如图 56.4.1 所示:
图 56.4.1 USB 连接成功
此时,电脑提示发现新硬件,并开始自动安装驱动,如图 56.4.2 所示:
图 56.4.2 USB 读卡器被电脑找到
等 USB 配置成功后,DS1 不亮,DS0 闪烁,并且在电脑上可以看到我们的磁盘,如图 56.4.3
所示:
图 56.4.3 电脑找到 USB 读卡器的两个盘符
我们打开设备管理器,在通用串行总线控制器里面可以发现多出了一个 USB 大容量存储
设备,同时看到磁盘驱动器里面多了 2 个磁盘,如图 56.4.4 所示:
图 56.4.4 通过设备管理器查看磁盘驱动器
此时,我们就可以通过电脑读写 SD 卡或者 SPI FLASH 里面的内容了。在执行读写操作的
时候,就可以看到 DS1 亮,并且会在液晶上显示当前的读写状态。
注意,在对 SPI FLASH 操作的时候,最好不要频繁的往里面写数据,否则很容易将 SPI
FLASH 写爆!!
相关推荐
- 12、高阶组件:魔法增幅器——React 19 HOC模式
-
一、魔法增幅器的本质"高阶组件是魔法师用咒语叠加的炼金术,"霍格沃茨魔咒研究院院长凝视着发光的增幅器,"通过函数式能量场的嵌套,让基础组件获得预言家日报式的逻辑继承!"...
- 深入理解nodejs的异步IO与事件模块机制
-
一、node为什么要使用异步I/O异步最先诞生于操作系统的底层,在底层系统中,异步通过信号量、消息等方式有广泛的应用。但在大多数高级编程语言中,异步并不多见,这是因为编写异步的程序不符合人习惯的思维逻...
- 前端时间同步利器:React + useEffect 实现高性能动态时钟
-
前言在你奋笔疾敲代码的瞬间,是不是突然一低头,发现时间像偷偷跑路的变量,一眨眼就从上午飘到下午?饭没吃、会没开、工位也快被前端猫霸占了。仿佛你写的不是代码,而是“时间穿梭机”。别慌,咱们今天就来用R...
- JavaScript 异步编程指南 - 聊聊 Node.js 中的事件循环
-
作者:五月君来源:编程界|事件循环是一种控制应用程序的运行机制,在不同的运行时环境有不同的实现,上一节讲了浏览器中的事件循环,它们有很多相似的地方,也有着各自的特点,本节讨论下Node.js中...
- 10个Vue开发技巧「实践」
-
作者:WahFung转发链接:https://juejin.im/post/5e8a9b1ae51d45470720bdfa路由参数解耦一般在组件内使用路由参数,大多数人会这样做:...
- 通过番计时器实例学习 React 生命周期函数 componentDidMount
-
大家好,今天我们将通过一个实例——番茄计时器,学习下如何使用函数生命周期的一个重要函数componentDidMount():componentDidMount(),在组件加载完成,render之后...
- 前端必看!10 个 Vue3 救命技巧,解决你 90% 的开发难题?
-
写Vue3项目时,是不是总被数据更新延迟、组件间传值混乱、页面加载缓慢这些问题折磨得头秃?别担心!作为摸爬滚打多年的老前端,今天掏出压箱底的10个实战技巧,从性能优化到复杂逻辑处理,每一个都能...
- 如何用2 KB代码实现3D赛车游戏?2kPlus Jam大赛了解一下
-
选自frankforce作者:Frank机器之心编译参与:王子嘉、GeekAI控制复杂度一直是软件开发的核心问题之一,一代代的计算机从业者纷纷贡献着自己的智慧,试图降低程序的计算复杂度。然而,将一款...
- 证明你访问的网站是你想访问的,Safari 真的需要
-
安全研究员在Safari上找到了一个新漏洞,能让网站在浏览器的地址栏内将自己伪装成另一个网站——得益于Safari地址栏的“智能缩略”功能。在Deusen最近公开的攻击演示(PoC,P...
- 抓狂!TS 组件性能拉胯到崩溃?4 个绝杀技巧逆风翻盘!
-
前端兄弟姐妹们五一假期快乐,咱们谁还没被TypeScript组件的性能问题折磨过?页面加载转圈圈,点击按钮没反应,代码改了一轮又一轮,性能却还是原地踏步,分分钟想砸电脑!别慌,今天这4个绝杀技...
- 让小球做圆周运动,你有几种办法?
-
最近在阅读外国技术文章中无意中发现了一个神奇的CSS属性motion-path,它可以让Dom元素可以按照自定义的路径移动。又想起了很久之前参加校招面试的时候,面试官问了我一个问题“能不能不借助库实现...
- 前端基础进阶(十四):深入核心,详解事件循环机制
-
EventLoopJavaScript的学习零散而庞杂,很多时候我们学到了一些东西,但是却没办法感受到进步!甚至过了不久,就把学到的东西给忘了。为了解决自己的这个困扰,在学习的过程中,我一直在试图寻...
- 从0搭建一个WebRTC,实现多房间多对多通话,并实现屏幕录制
-
这篇文章开始会实现一个一对一WebRTC和多对多的WebRTC,以及基于屏幕共享的录制。本篇会实现信令和前端部分,信令使用fastity来搭建,前端部分使用Vue3来实现。为什么要使用WebRTCWe...
- Vue2 开发卡壳?这 10 个实战技巧专治各种不服
-
干前端开发的兄弟,谁还没被Vue2折腾过?数据不更新、组件通信乱成麻、性能差到想砸电脑……这些痛点,我都懂!今天直接甩出10个超实用的实战技巧,每一个都是从项目“血坑”里爬出来总结的,专...
你 发表评论:
欢迎- 一周热门
-
-
前端面试:iframe 的优缺点? iframe有那些缺点
-
带斜线的表头制作好了,如何填充内容?这几种方法你更喜欢哪个?
-
漫学笔记之PHP.ini常用的配置信息
-
其实模版网站在开发工作中很重要,推荐几个参考站给大家
-
推荐7个模板代码和其他游戏源码下载的网址
-
[干货] JAVA - JVM - 2 内存两分 [干货]+java+-+jvm+-+2+内存两分吗
-
正在学习使用python搭建自动化测试框架?这个系统包你可能会用到
-
织梦(Dedecms)建站教程 织梦建站详细步骤
-
【开源分享】2024PHP在线客服系统源码(搭建教程+终身使用)
-
2024PHP在线客服系统源码+完全开源 带详细搭建教程
-
- 最近发表
-
- 12、高阶组件:魔法增幅器——React 19 HOC模式
- 深入理解nodejs的异步IO与事件模块机制
- 前端时间同步利器:React + useEffect 实现高性能动态时钟
- JavaScript 异步编程指南 - 聊聊 Node.js 中的事件循环
- 10个Vue开发技巧「实践」
- 通过番计时器实例学习 React 生命周期函数 componentDidMount
- SRE监控四大黄金指标,任何一个有异常都会是灾难……
- 前端必看!10 个 Vue3 救命技巧,解决你 90% 的开发难题?
- 如何用2 KB代码实现3D赛车游戏?2kPlus Jam大赛了解一下
- 证明你访问的网站是你想访问的,Safari 真的需要
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)