news 2026/2/27 3:22:19

STM32的SPI外设

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32的SPI外设

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、SPI外设介绍
  • 二,SPI外设读取Flash用到寄存器详解
  • 三、HAL库实现SPI硬件外设读写flash
    • 1.stm32cubemx配置设置
      • 1.1. 选择芯片并配置单线调试模式,+ 配置外部时钟源和时钟树
      • 1.2.打开usart1 配置输出打印
      • 1.3 设置spi1 为主输出模式,同时片选是有pc13 通用推挽输出
      • 1.4 配置工程名称并导出工程等等
      • 1.5 分别新建w25q32.c 和.h 放入core/src 和core/inc里面 并使用keil 导入并引入c库支持
    • 2.编写代码
      • 2.1 usart 重定义
      • 2.2 编写spi.c 和.h
      • 2.3 w25q32.c

前言

提示:这里可以添加本文要记录的大概内容:

介绍SPI外设,说明硬件外设读取flash的需求和寄存器的介绍 以及用HAL库的方式实现


提示:以下是本篇文章正文内容,下面案例可供参考

一、SPI外设介绍

STM32 的 SPI 外设可用作通讯的主机及从机,支持最高的 SCK 时钟频率为 fpclk/2 (STM32F103 型号的芯片默认fpclk1为36MHz,fpclk2为72MHz。),完全支持 SPI 协议的 4 种模式,数据帧长度可设置为 8 位或 16 位,可设置数据 MSB 先行或 LSB 先行。它还支持双线全双工、双线单向以及单线模式。

STM32F103系列提供了3个SPI,SPI1挂在APB2总线,SPI2/3挂在APB1总线。

其中双线单向模式可以同时使用 MOSI 及 MISO 数据线向一个方向传输数据,可以加快一倍的传输速度。而单线模式则可以减少硬件接线,当然这样速率会受到影响。
用的比较多还是双线全双工模式。

什么是SPI
SPI 是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口。是Motorola(摩托罗拉)首先在其MC68HCXX系列处理器上定义的。

SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,主要应用在 EEPROM,FLASH,实时时钟,AD转换器,还有数字信号处理器和数字信号解码器之间。

SPI主从模式
SPI分为主、从两种模式,一个SPI通讯系统需要包含一个(且只能是一个)主设备,一个或多个从设备。提供时钟的为主设备(Master),接收时钟的设备为从设备(Slave),SPI接口的读写操作,都是由主设备发起。当存在多个从设备时,通过各自的片选信号进行管理。

SPI是全双工且SPI没有定义速度限制,一般的实现通常能达到甚至超过10 Mbps

SPI信号线
SPI接口一般使用四条信号线通信:
SDI(数据输入),SDO(数据输出),SCK(时钟),CS(片选)

  • MISO: 主设备输入/从设备输出引脚。该引脚在从模式下发送数据,在主模式下接收数据。
  • MOSI:主设备输出/从设备输入引脚。该引脚在主模式下发送数据,在从模式下接收数据。
  • SCLK:串行时钟信号,由主设备产生。
  • CS/SS:从设备片选信号,由主设备控制。它的功能是用来作为“片选引脚”,也就是选择指定的从设备,让主设备可以单独地与特定从设备通讯,避免数据线上的冲突

硬件上为4根线。

SPI 一对一

SPI 一对多

SPI设备选择
SPI是[单主设备( single-master )]通信协议,这意味着总线中的只有一支中心设备能发起通信。当SPI主设备想读/写[从设备]时,它首先拉低[从设备]对应的SS线(SS是低电平有效),接着开始发送工作脉冲到时钟线上,在相应的脉冲时间上,[主设备]把信号发到MOSI实现“写”,同时可对MISO采样而实现“读”,如下图:


SPI数据发送接收
SPI主机和从机都有一个串行移位寄存器,主机通过向它的SPI串行寄存器写入一个字节来发起一次传输。

首先拉低对应SS信号线,表示与该设备进行通信
主机通过发送SCLK时钟信号,来告诉从机写数据或者读数据
这里要注意,SCLK时钟信号可能是低电平有效,也可能是高电平有效,因为SPI有四种模式,这个我们在下面会介绍
主机(Master)将要发送的数据写到发送数据缓存区(Menory),缓存区经过移位寄存器(0~7),串行移位寄存器通过MOSI信号线将字节一位一位的移出去传送给从机,,同时MISO接口接收到的数据经过移位寄存器一位一位的移到接收缓存区。
从机(Slave)也将自己的串行移位寄存器(0~7)中的内容通过MISO信号线返回给主机。同时通过MOSI信号线接收主机发送的数据,这样,两个移位寄存器中的内容就被交换。

SPI通信的四种模式
SPI的四种模式,简单地讲就是设置SCLK时钟信号线的那种信号为有效信号

SPI通信有4种不同的操作模式,不同的从设备可能在出厂是就是配置为某种模式,这是不能改变的;但我们的通信双方必须是工作在同一模式下,所以我们可以对我们的主设备的SPI模式进行配置,通过CPOL(时钟极性)和CPHA(时钟相位)来
控制我们主设备的通信模式,具体如下:

时钟极性(CPOL)定义了时钟空闲状态电平:

CPOL=0,表示当SCLK=0时处于空闲态,所以有效状态就是SCLK处于高电平时
CPOL=1,表示当SCLK=1时处于空闲态,所以有效状态就是SCLK处于低电平时
时钟相位(CPHA)定义数据的采集时间。

CPHA=0,在时钟的第一个跳变沿(上升沿或下降沿)进行数据采样。,在第2个边沿发送数据
CPHA=1,在时钟的第二个跳变沿(上升沿或下降沿)进行数据采样。,在第1个边沿发送数据
例如:

Mode0:CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在上升沿(准备数据),(发送数据)数据发送是在下降沿。

Mode1:CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据发送是在第1个边沿,也就是SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。

Mode2:CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。

Mode3:CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据发送是在第1个边沿,也就是SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。



它们的区别是定义了在时钟脉冲的哪条边沿转换(toggles)输出信号,哪条边沿采样输入信号,还有时钟脉冲的稳定电平值(就是时钟信号无效时是高还是低)。每种模式由一对参数刻画,它们称为时钟极(clock polarity)CPOL与时钟期(clock phase)CPHA。

SPI的通信协议

主从设备必须使用相同的工作模式——SCLK、CPOL 和 CPHA,才能正常工作。如果有多个从设备,并且它们使用了不同的工作模式,那么主设备必须在读写不同从设备时需要重新修改对应从设备的模式。以上SPI总线协议的主要内容。

是不是感觉,这就完了? SPI就是如此,他没有规定最大传输速率,没有地址方案,也没规定通信应答机制,没有规定流控制规则。

只要四根信号线连接正确,SPI模式相同,将CS/SS信号线拉低,即可以直接通信,一次一个字节的传输,读写数据同时操作,这就是SPI

些通信控制都得通过SPI设备自行实现,SPI并不关心物理接口的电气特性,例如信号的标准电压。

PS:
这也是SPI接口的一个缺点:没有指定的流控制,没有应答机制确认是否接收到数据。

SPI的三种模式
SPI工作在3中模式下,分别是运行、等待和停止。

运行模式(Run Mode)
这是基本的操作模式

等待模式(Wait Mode)
SPI工作在等待模式是一种可配置的低功耗模式,可以通过SPICR2寄存器的SPISWAI位进行控制。在等待模式下,如果SPISWAI位清0,SPI操作类似于运行模式。如果SPISWAI位置1,SPI进入低功耗状态,并且SPI时钟将关闭。如果SPI配置为主机,所有的传输将停止,但是会在CPU进入运行模式后重新开始。如果SPI配置为从机,会继续接收和传输一个字节,这样就保证从机与主机同步。

停止模式(Stop Mode)
为了降低功耗,SPI在停止模式是不活跃的。如果SPI配置为主机,正在进行的传输会停止,但是在CPU进入运行模式后会重新开始。如果SPI配置为从机,会继续接受和发送一个字节,这样就保证了从机与主机同步。

SPI原理图连接

二,SPI外设读取Flash用到寄存器详解

第 1 章配置SPI模式
1.1代码
/* 3.1 配置主模式 0=从设备 1=主设备*/
SPI1->CR1 |= SPI_CR1_MSTR;
1.2寄存器

第 2 章SPI波特率控制
2.1代码
/* 3.2 选择分频系数 000=fpclk/2, 001=fpclk/4 …,我们选择4分频 */
SPI1->CR1 &= ~SPI_CR1_BR;
SPI1->CR1 |= SPI_CR1_BR_0;
2.2寄存器

第 3 章时钟的极性和相位
3.1代码
/* 3.3 时钟极性 0: 空闲状态时,SCK保持低电平;1: 空闲状态时,SCK保持高电平。/
SPI1->CR1 &= ~SPI_CR1_CPOL;
/
3.4 时钟相位 0: 数据采样从第一个时钟边沿开始;1: 数据采样从第二个时钟边沿开始。*/
SPI1->CR1 &= ~SPI_CR1_CPHA;
3.2寄存器

第 4 章数据帧格式和传输顺序
4.1代码
/* 3.5 数据帧格式 0:8位数据帧;1:16位数据帧/
SPI1->CR1 &= ~SPI_CR1_DFF;
/
3.6 数据传输顺序 0:先发送MSB;1:先发送LSB。/
SPI1->CR1 &= ~SPI_CR1_LSBFIRST; /
高位先行 */
4.2寄存器


第 5 章配置片选方式
5.1代码
/* 3.7 使用软件实现片选(我们自7己控制CS)0:禁止软件从设备管理;1:启用软件从设备管理。/
SPI1->CR1 |= SPI_CR1_SSM;
/
3.8 当SSM=1时,这个时候对SSI的操作无效,必须设置为1 */
SPI1->CR1 |= SPI_CR1_SSI;
5.2寄存器


第 6 章启动SPI
6.1代码
/* 4 启动SPI1 0:禁止SPI设备;1:开启SPI设备。*/
SPI1->CR1 |= SPI_CR1_SPE;
6.2寄存器

第 7 章SPI读写数据
7.1代码
uint8_t SPI_SwapByte(uint8_t byte_sended)
{
/* 1. 等待发送缓冲区为空/
while (!(SPI1->SR & SPI_SR_TXE))
;
/
2. 把数据写入到数据寄存器/
SPI1->DR = byte_sended;
/
3. 等待接收缓冲区非空/
while (!(SPI1->SR & SPI_SR_RXNE))
;
/
4. 返回读到的字节数据 */
return SPI1->DR;
}

7.2寄存器


三、HAL库实现SPI硬件外设读写flash

1.stm32cubemx配置设置

1.1. 选择芯片并配置单线调试模式,+ 配置外部时钟源和时钟树




1.2.打开usart1 配置输出打印

1.3 设置spi1 为主输出模式,同时片选是有pc13 通用推挽输出



片选引脚配置 默认输出拉高,要用的时候拉低

1.4 配置工程名称并导出工程等等


1.5 分别新建w25q32.c 和.h 放入core/src 和core/inc里面 并使用keil 导入并引入c库支持

根据目录放入文件

2.编写代码

2.1 usart 重定义

#include<stdio.h>intfputc(intch,FILE*f){HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,1000);returnch;}

2.2 编写spi.c 和.h

intfputc(intch,FILE*f){HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,1000);returnch;}

2.3 w25q32.c

#include"w25q32.h"// // ³õʼ»¯// void W25Q32_Init(void)// {// MX_SPI1_Init();// }// ¶ÁÈ¡Éú²úÉ̺ÍÉ豸IDvoidW25Q32_ReadID(uint8_t*mid,uint16_t*did){// 0. ¿ªÆô SPI ͨµÀ£¬Æ¬Ñ¡ÉúЧSPI_Start();// 1. ·¢ËÍÖ¸ÁîSPI_SwapByte(0x9f);// 2. ÏÂÒ»¸öÖÜÆÚ»ñÈ¡·¢À´µÄµÚÒ»¸ö×Ö½Ú£¬ÖÆÔìÉÌID*mid=SPI_SwapByte(0xff);// 3. ÏÂÁ½¸öÖÜÆÚ£¬»ñÈ¡É豸ID*did=0;*did|=SPI_SwapByte(0xff)<<8;*did|=SPI_SwapByte(0xff)&0xff;SPI_Stop();}// дÈëʹÄÜvoidW25Q32_WriteEnalbe(void){SPI_Start();// ·¢ËÍÖ¸ÁîSPI_SwapByte(0x06);SPI_Stop();}// дÈëʧÄÜvoidW25Q32_WriteDisable(void){SPI_Start();// ·¢ËÍÖ¸ÁîSPI_SwapByte(0x04);SPI_Stop();}// µÈ´ýµ±Ç°×´Ì¬£¬²»ÎªbusyvoidW25Q32_WaitNotBusy(void){SPI_Start();// 1. ·¢ËÍÖ¸ÁîSPI_SwapByte(0x05);// 2. Ñ­»·µÈ´ý£¬Ö±µ½½ÓÊÕÊý¾Ý×îºóһλΪ 0while(SPI_SwapByte(0xff)&0x01){}SPI_Stop();}// ²Á³ýsectorvoidW25Q32_EraseSector(uint8_tblock,uint8_tsector){// 1. Ïȵȴý²»ÎªbusyW25Q32_WaitNotBusy();// 2. ¿ªÆôдʹÄÜW25Q32_WriteEnalbe();// 3. Æ´½ÓÍêÕûµØÖ·£¬sectorÊ×µØÖ·£¬ºó12λ¶¼Îª0uint32_tsectorHeadAddr=block*0x010000+sector*0x001000;// 4. Æô¶¯SPI_Start();// 5. ·¢ËÍÖ¸ÁîSPI_SwapByte(0x20);// 6. ·¢ËÍ24λµØÖ·SPI_SwapByte(sectorHeadAddr>>16&0xff);// È¡Èý¸ö×Ö½ÚÖеÄ×î¸ß×Ö½ÚSPI_SwapByte(sectorHeadAddr>>8&0xff);// È¡µÚ¶þ¸ö×Ö½ÚSPI_SwapByte(sectorHeadAddr>>0&0xff);SPI_Stop();W25Q32_WriteDisable();}// ҳдvoidW25Q32_WritePage(uint8_tblock,uint8_tsector,uint8_tpage,uint8_t*data,uint8_tlen){// 1. Ïȵȴý²»ÎªbusyW25Q32_WaitNotBusy();// 2. ¿ªÆôдʹÄÜW25Q32_WriteEnalbe();// 3. Æ´½ÓÍêÕûµØÖ·£¬pageÊ×µØÖ·£¬ºó8λ¶¼Îª0uint32_tpageHeadAddr=block*0x010000+sector*0x001000+page*0x000100;// 4. Æô¶¯SPI_Start();// 5. ·¢ËÍÖ¸ÁîSPI_SwapByte(0x02);// 6. ·¢ËÍ24λµØÖ·SPI_SwapByte(pageHeadAddr>>16&0xff);// È¡Èý¸ö×Ö½ÚÖеÄ×î¸ß×Ö½ÚSPI_SwapByte(pageHeadAddr>>8&0xff);// È¡µÚ¶þ¸ö×Ö½ÚSPI_SwapByte(pageHeadAddr>>0&0xff);// 7. ¼ÌÐø·¢ËÍÊý¾Ýfor(uint8_ti=0;i<len;i++){SPI_SwapByte(data[i]);}SPI_Stop();W25Q32_WriteDisable();}// ¶ÁÈ¡voidW25Q32_Read(uint8_tblock,uint8_tsector,uint8_tpage,uint8_t*buffer,uint8_tlen){// 1. Ïȵȴý²»ÎªbusyW25Q32_WaitNotBusy();// 2. Æ´½ÓÍêÕûµØÖ·£¬pageÊ×µØÖ·£¬ºó8λ¶¼Îª0uint32_tpageHeadAddr=block*0x010000+sector*0x001000+page*0x000100;// 3. Æô¶¯SPI_Start();// 4. ·¢ËÍÖ¸ÁîSPI_SwapByte(0x03);// 5. ·¢ËÍ24λµØÖ·SPI_SwapByte(pageHeadAddr>>16&0xff);// È¡Èý¸ö×Ö½ÚÖеÄ×î¸ß×Ö½ÚSPI_SwapByte(pageHeadAddr>>8&0xff);// È¡µÚ¶þ¸ö×Ö½ÚSPI_SwapByte(pageHeadAddr>>0&0xff);// 6. ¶ÁÈ¡Êý¾Ýfor(uint8_ti=0;i<len;i++){buffer[i]=SPI_SwapByte(0xff);}SPI_Stop();}// ҳдvoidW25Q32_WritePageRandom(uint32_taddr,uint8_t*data,uint8_tlen){// 1. Ïȵȴý²»ÎªbusyW25Q32_WaitNotBusy();// 2. ¿ªÆôдʹÄÜW25Q32_WriteEnalbe();// 4. Æô¶¯SPI_Start();// 5. ·¢ËÍÖ¸ÁîSPI_SwapByte(0x02);// 6. ·¢ËÍ24λµØÖ·SPI_SwapByte(addr>>16&0xff);// È¡Èý¸ö×Ö½ÚÖеÄ×î¸ß×Ö½ÚSPI_SwapByte(addr>>8&0xff);// È¡µÚ¶þ¸ö×Ö½ÚSPI_SwapByte(addr>>0&0xff);// 7. ¼ÌÐø·¢ËÍÊý¾Ýfor(uint8_ti=0;i<len;i++){SPI_SwapByte(data[i]);}SPI_Stop();W25Q32_WriteDisable();}

main.c

/* USER CODE BEGIN Header *//** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2024 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** *//* USER CODE END Header *//* Includes ------------------------------------------------------------------*/#include"main.h"#include"spi.h"#include"usart.h"#include"gpio.h"#include"w25q32.h"/* Private includes ----------------------------------------------------------*//* USER CODE BEGIN Includes *//* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*//* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*//* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*//* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV *//* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/voidSystemClock_Config(void);/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 *//* USER CODE END 0 *//** * @brief The application entry point. * @retval int */intmain(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_SPI1_Init();MX_USART1_UART_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop */printf("Hello world\n");// 2. ¶ÁÈ¡ID£¬²âÊÔFlashÊÇ·ñÕý³£uint8_tmid=0;uint16_tdid=0;W25Q32_ReadID(&mid,&did);printf("mid = %#x, did=%#x\n",mid,did);// 3. ¶Î²Á³ýW25Q32_EraseSector(0,0);// 4. ҳд£¨µÚÒ»¸ö¿éµÄµÚÒ»¸ö¶ÎµÄµÚÒ»Ò³£©W25Q32_WritePage(0,0,0,"12345678",8);W25Q32_WritePage(0,0,1,"abcdef",8);// 5. Ò³¶Áuint8_tbuffer[100]={0};W25Q32_Read(0,0,0,buffer,8);printf("read data = %s\n",buffer);W25Q32_Read(0,0,1,buffer,8);printf("read data = %s\n",buffer);// 6. ²âÊÔ£ºËæ»úÍêÕûµØÖ·Ð´ÈëW25Q32_WritePageRandom(0x00022f,"12345678\0",9);W25Q32_Read(0,0,2,buffer,255);printf("read data = %s\n",buffer);while(1){}/* USER CODE END 3 */}/** * @brief System Clock Configuration * @retval None */voidSystemClock_Config(void){RCC_OscInitTypeDef RCC_OscInitStruct={0};RCC_ClkInitTypeDef RCC_ClkInitStruct={0};/** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState=RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue=RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState=RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState=RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource=RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL=RCC_PLL_MUL9;if(HAL_RCC_OscConfig(&RCC_OscInitStruct)!=HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks */RCC_ClkInitStruct.ClockType=RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider=RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider=RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider=RCC_HCLK_DIV1;if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct,FLASH_LATENCY_2)!=HAL_OK){Error_Handler();}}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//** * @brief This function is executed in case of error occurrence. * @retval None */voidError_Handler(void){/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while(1){}/* USER CODE END Error_Handler_Debug */}#ifdefUSE_FULL_ASSERT/** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */voidassert_failed(uint8_t*file,uint32_tline){/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */}#endif/* USE_FULL_ASSERT */

烧录验证效果

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/27 1:46:56

彻底解决大型前端项目痛点:umi模块化拆分与联邦架构完全指南

彻底解决大型前端项目痛点&#xff1a;umi模块化拆分与联邦架构完全指南 【免费下载链接】umi A framework in react community ✨ 项目地址: https://gitcode.com/GitHub_Trending/um/umi 你是否正面临这样的困境&#xff1a;前端项目越来越庞大&#xff0c;构建时间从…

作者头像 李华
网站建设 2026/2/25 15:21:21

Vuetify日历组件终极指南:7天从零打造专业日程管理系统

Vuetify日历组件终极指南&#xff1a;7天从零打造专业日程管理系统 【免费下载链接】vuetify &#x1f409; Vue Component Framework 项目地址: https://gitcode.com/gh_mirrors/vu/vuetify 还在为复杂的日程管理功能发愁吗&#xff1f;Vuetify的VCalendar组件让这一切…

作者头像 李华
网站建设 2026/2/18 4:41:41

《Agentic设计模式》:构建智能系统的实战指南

本文系统介绍AI智能体的概念、五步循环工作法及四个复杂度层级&#xff0c;详细阐述构建智能体系统的21个核心设计模式&#xff0c;涵盖基础模式、高级能力、鲁棒性和系统级模式。同时探讨智能体未来五大假设、市场趋势及实践建议&#xff0c;为开发者提供从理论到实践的完整指…

作者头像 李华
网站建设 2026/2/22 21:53:31

adb命令大全

1、退出终端最常用的退出命令是 exit 或 logout&#xff0c;直接输入后回车即可。使用快捷键 Ctrl D 来达到同样的效果。

作者头像 李华