STM32-HAL-SPI-读写W25Q128FV-JEDEC ID(1)

news2025/1/14 20:41:16

文章目录

  • 一、SPI串行通信协议
    • 1.1 SPI通信协议简介
    • 1.2 SPI工作原理
    • 1.3 SPI特性
  • 二、W25Q128FV芯片介绍
    • 2.1 芯片基本参数介绍
    • 2.2 芯片管脚介绍
    • 2.3 技术手册等更多信息
  • 三、开发板的板载Flash的连接电路
  • 四、测试准备
  • 五、初始化片上外设SPI1
    • 5.1 初始化SPI1
    • 5.2 设置片选引脚PB14
    • 5.3 配置串口打印模式
    • 5.4 设置生成Keil- MDK代码文件
  • 六、读写芯片JEDEC ID
    • 6.1 芯片技术手册和读JEDEC ID流程
    • 6.2 编写读芯片JEDEC ID代码

一、SPI串行通信协议

1.1 SPI通信协议简介

SPI是串行外设接口,是Motorola首先在其MC68HCxx系列处理器上定义的。SPI是一种高速的、全双工,同步的通信总线,并且在芯片的管教上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便。

1.2 SPI工作原理

SPI的通信原理很简单,它以主从的方式工作,这种模式通常有一个主设备和一个或者多个从设备,至少需要4根线,事实上3根也可以(片选信号可以直接接地,默认选中)。SPI的4根线是MOSI主设备输出从设备输入),MISO主设备输入从设备输出),CK(时钟信号),CS(片选信号,低电平有效)。
在这里插入图片描述

1.3 SPI特性

  • 三线全双工同步传输
  • 8位或16位传输帧格式选择
  • 主或从操作
  • 8个主模式波特率预分频系数
  • 可编程的时钟极性和相位
  • 可编程的数据顺序,MSB在前或者LSB在前
  • 可触发的中断的专用发送和接收标志
  • SPI总线忙状态标志
  • 支持DMA功能的1字节发送和接收缓冲器,产生发送和接收请求

二、W25Q128FV芯片介绍

2.1 芯片基本参数介绍

W25QXX系列存储芯片是基于SPI接口的串行Flash存储器,主要有W25Q64、W25Q128等。芯片支持工作电压在2.7~3.6V之间,在正常工作时电流小于5mA,掉电时低于1uA。最大支持104MHz的编程速度。支持SPI和QSPI读写方式。

  • W25Q128每页256个字节。页是最小的可读、可写单元,也是编程和擦除的最小单位。
  • W25Q128的块大小为64KB。块是由多个页组成的一个较大的存储单元,每个块通常包含256个页面。
  • 如果需要更改或者擦除某个页、块中的某个数据,那么就要将整个页或者块全部写入或者擦除。
  • W25Q128的扇区大小为4KB。扇区是块的子单元,每个块包含16个扇区。更改或者擦除一个扇区的数据不会影响其他的扇区的数据。
  • 字节是最小的可寻址单元,一个字节是由8个二进制位组成,可以存储一个字符或者数字。

2.2 芯片管脚介绍

  • 芯片管脚图
    在这里插入图片描述
  • 管脚的名称
管脚编号管脚名称功能描述
1/CS片选输入,为低电平时选中,高电平时未选中
2DO(IO1)数据输出(数据输入输出1)
3/WP(IO2)写保护输入(数据输入输出2),低电平写保护
4GND
5DI(IO0)输入输入(数据输入输出0)
6CLK串行时钟
7/HOLD(IO3)数据保持(数据输入输出3)低电平有效
8VCC电源正
  • 不同的SPI模式的引脚作用
标准SPI模式下管脚功能CSDIDPWPHOLD
双倍SPI模式下管脚功能CSIO0IO1WPHOLD
四倍SPI模式下管脚功能CSIO0IO1IO2IO3

2.3 技术手册等更多信息

点击访问官网
在这里插入图片描述

三、开发板的板载Flash的连接电路

在这里插入图片描述
在这里插入图片描述
1、从电路图中可以看出,芯片的供电电压为3.3V

2、芯片的数据线为4线,接在SPI1总线上

3、芯片读写使能用的是软件片选

  • 芯片和MCU引脚对应表
SPI1_SCK时钟线 PB3
F_CS片选(低电平选中)PB14
SPI1_MISO主机输入从机输出 PB4
SPI1_MOSI主机输出从机输入PB5

四、测试准备

  • 基于STM32F407ZET6的正点原子开发板(Flash芯片在左上角W25Q128FV)

../../_images/stm32f407_explorer.png

  • 安装windows系统并安装CubemxKeil MDK的电脑

五、初始化片上外设SPI1

由于硬件原因需要修改成对应硬件的引脚

5.1 初始化SPI1

  • 初始化为全双工模式(因为要进行读写操作)

  • 直接无视软件自动配置的引脚,手动设置硬件对应的引脚为SPI1对应的引脚

在这里插入图片描述

  • 时钟源设置为外部高速时钟

在这里插入图片描述
【重要】查看开发板的板载晶振的频率(根据自己的开发板的晶振频率设置),因此设置输入的时钟的频率为8Hz,经过分频后最后设置频率为最大168MHz

  • 时钟树设置,经过分频、倍频后

在这里插入图片描述

  • 针对SPI1总线进行参数设置

在这里插入图片描述

  • 配置参数说明
ModeFull-Duplex Mater 全双工模式主模式
Frame FormatMotorola(摩托罗拉)
Data Size8 Bit( 查看芯片的技术手册可得)
First Bit高位在前:MSB First ( 查看芯片的技术手册可得)
Prescaler(For BaudRate)可设置为最高速率:2分频 42.0MBts/s ( 查看芯片的技术手册可得)
Clock Polarity时钟极性为上升沿 : Low ( 查看芯片的技术手册可得)
Clock Phase时钟相位为0 : 1 Edge( 查看芯片的技术手册可得)
CRC Calucation不设置CRC校验:Disable
NSS Signal Type设置软件片选:SoftWare
MSBMSB代表“Most Significant Bit”,即最高有效位,是二进制数中权值最高的位,通常位于左侧。在多字节数据传输时,MSB通常是首先传输的字节。
LSBLSB代表“Least Significant Bit”,即最低有效位,是二进制数中权值最低的位,通常位于右侧。在多字节数据传输时,LSB通常是最后传输的字节。

Clock Polarity和Clock Phase的具体设置方式需要依照设备和应用场景进行调整的
在本次测试中,由于W25Q128芯片的读写模式支持Mode 0(0,0)Mode3(1,1) 选择了模式0作为读写模式

在这里插入图片描述

芯片的数据手册第6.1章节

模式CPOL(极性)CPHA(相位)空闲时SCK时钟采样时刻
模式000低电平奇数边沿
模式101低电平偶数边沿
模式210高电平奇数边沿
模式311高电平偶数边沿

一般经常用的就是模式0和模式3。经过测试,设置为模式0或者模式3均可进行正确的读写。

5.2 设置片选引脚PB14

在这里插入图片描述

5.3 配置串口打印模式

参考以前的配置文章进行设置

5.4 设置生成Keil- MDK代码文件

六、读写芯片JEDEC ID

6.1 芯片技术手册和读JEDEC ID流程

在SPI总线上接收三个字节的数据,分别表示制造商ID、设备类型、容量

在这里插入图片描述

芯片的Jedec ID指令

在这里插入图片描述

芯片的Jedec ID介绍
  • 常见的存储芯片的类型和它的Jedec ID
芯片类型Jedec ID
SST25VF016B_ID0xBF2541
MX25L1606E_ID0xC22015
W25Q64BV_ID(BV JV FV)0xEF4017
W25Q128_ID0xEF4018

通过SPI总线读取W25Q128的JEDEC ID,并将JEDEC ID整合为一个32位的数值。具体流程如下:

  1. 通过调用sf_SetCS函数使能W25Q128芯片的片选信号。
  2. 将读取ID命令(0x9F)放入发送缓冲区g_spiTxBuf,并将发送缓冲区长度g_spiLen设置为4(包括一个读取ID命令和3个地址字节)。
  3. 调用bsp_spiTransfer函数发送读取ID命令,并从DO引脚接收3个字节的ID数据,并将接收到的数据存储在g_spiRxBuf接收缓冲区中。
  4. g_spiRxBuf接收缓冲区中读取3个字节的ID数据,并分别存储在id1、id2和id3变量中。
  5. 通过调用sf_SetCS函数禁用W25Q128芯片的片选信号。
  6. 将3个字节的ID数据整合成一个32位的数值uiID,其中id1占据高16位,id2占据中8位,id3占据低8位。
  7. 将整合后的32位ID数值返回。

6.2 编写读芯片JEDEC ID代码

代码来自安富莱电子

[bsp_flash.c]

#include "bsp_flash.h"
SFLASH_T g_tSF;  //定义结构体

/*
*********************************************************************************************************
*	函 数 名: sf_SetCS
*	功能说明: 串行FALSH片选控制函数
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void sf_SetCS(uint8_t _Level)
{
	if (_Level == 0)
	{
		bsp_SpiBusEnter();     
		SF_CS_0();
	}
	else
	{		
		SF_CS_1();	
		bsp_SpiBusExit();		
	}
}

/*
*********************************************************************************************************
*	函 数 名: sf_ReadInfo
*	功能说明: 读取器件ID,并填充器件参数
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void sf_ReadInfo(void)
{
	/* 自动识别串行Flash型号 */
	{
		g_tSF.ChipID = sf_ReadID();	/* 芯片ID */

		switch (g_tSF.ChipID)
		{
			case SST25VF016B_ID:
				strcpy(g_tSF.ChipName, "SST25VF016B");
				g_tSF.TotalSize = 2 * 1024 * 1024;	/* 总容量 = 2M */
				g_tSF.SectorSize = 4 * 1024;		/* 扇区大小 = 4K */
				break;

			case MX25L1606E_ID:
				strcpy(g_tSF.ChipName, "MX25L1606E");
				g_tSF.TotalSize = 2 * 1024 * 1024;	/* 总容量 = 2M */
				g_tSF.SectorSize = 4 * 1024;		/* 扇区大小 = 4K */
				break;

			case W25Q64BV_ID:
				strcpy(g_tSF.ChipName, "W25Q64");
				g_tSF.TotalSize = 8 * 1024 * 1024;	/* 总容量 = 8M */
				g_tSF.SectorSize = 4 * 1024;		/* 扇区大小 = 4K */
				break;
			
			case W25Q128_ID:
				strcpy(g_tSF.ChipName, "W25Q128");
				g_tSF.TotalSize = 16 * 1024 * 1024;	/* 总容量 = 8M */
				g_tSF.SectorSize = 4 * 1024;		/* 扇区大小 = 4K */
				break;			

			default:
				strcpy(g_tSF.ChipName, "Unknow Flash");
				g_tSF.TotalSize = 2 * 1024 * 1024;
				g_tSF.SectorSize = 4 * 1024;
				break;
		}
	}
}

/*
*********************************************************************************************************
*	函 数 名: sf_ReadID
*	功能说明: 读取器件ID
*	形    参:  无
*	返 回 值: 32bit的器件ID (最高8bit填0,有效ID位数为24bit)
*********************************************************************************************************
*/
uint32_t sf_ReadID(void)
{
	uint32_t uiID;
	uint8_t id1, id2, id3;

	sf_SetCS(0);							    /* 使能片选 */
	g_spiLen = 0;
	g_spiTxBuf[0] = (CMD_RDID);	  /* 发送读ID命令 0x9F */
	g_spiLen = 4;
	bsp_spiTransfer();
	
	id1 = g_spiRxBuf[1];					/* 读ID的第1个字节 */
	id2 = g_spiRxBuf[2];					/* 读ID的第2个字节 */
	id3 = g_spiRxBuf[3];					/* 读ID的第3个字节 */
	sf_SetCS(1);							    /* 禁能片选 */

	uiID = ((uint32_t)id1 << 16) | ((uint32_t)id2 << 8) | id3;   /*ID整合*/

	return uiID;
}
[bsp_flash.h]
#ifndef __BSP_FLASH_H_
#define __BSP_FLASH_H_

#include "stm32f4xx_hal.h"
#include "main.h"
#include "spi.h"
#include "string.h"

#define SF_CS_0()					F_CS_GPIO_Port->BSRR = ((uint32_t)F_CS_Pin << 16U) 
#define SF_CS_1()					F_CS_GPIO_Port->BSRR = F_CS_Pin
	  
#define CMD_AAI       0xAD  	/* AAI 连续编程指令(FOR SST25VF016B) */
#define CMD_DISWR	    0x04		/* 禁止写, 退出AAI状态 */
#define CMD_EWRSR	    0x50		/* 允许写状态寄存器的命令 */
#define CMD_WRSR      0x01  	/* 写状态寄存器命令 */
#define CMD_WREN      0x06		/* 写使能命令 */
#define CMD_READ      0x03  	/* 读数据区命令 */
#define CMD_RDSR      0x05		/* 读状态寄存器命令 */
#define CMD_RDID      0x9F		/* 读器件ID命令 */
#define CMD_SE        0x20		/* 擦除扇区命令 */
#define CMD_BE        0xC7		/* 批量擦除命令 */
#define DUMMY_BYTE    0xA5		/* 哑命令,可以为任意值,用于读操作 */

#define WIP_FLAG      0x01		/* 状态寄存器中的正在编程标志(WIP) */

typedef struct
{
	uint32_t ChipID;		/* 芯片ID */
	char ChipName[16];		/* 芯片型号字符串,主要用于显示 */
	uint32_t TotalSize;		/* 总容量 */
	uint16_t SectorSize;		/* 扇区大小 */
}SFLASH_T;

/* 定义串行Flash ID */
enum
{
	SST25VF016B_ID = 0xBF2541,
	MX25L1606E_ID  = 0xC22015,
	W25Q64BV_ID    = 0xEF4017, /* BV, JV, FV */
	W25Q128_ID     = 0xEF4018
};

void bsp_InitSFlash(void);
void sf_ReadInfo(void);
uint32_t sf_ReadID(void);
void sf_SetCS(uint8_t _Level);

extern SFLASH_T g_tSF;

#endif

[spi.c]
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    spi.c
  * @brief   This file provides code for the configuration
  *          of the SPI instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 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 "spi.h"

/* USER CODE BEGIN 0 */
enum {
	TRANSFER_WAIT,
	TRANSFER_COMPLETE,
	TRANSFER_ERROR
};


uint32_t g_spiLen;	
uint8_t  g_spi_busy; /* SPI忙状态,0表示不忙,1表示忙 */
__IO uint32_t wTransferState = TRANSFER_WAIT;


uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];  
uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];

/*
*********************************************************************************************************
*	                             选择DMA,中断或者查询方式
*********************************************************************************************************
*/
//#define USE_SPI_DMA    /* DMA方式  */
//#define USE_SPI_INT    /* 中断方式 */
#define USE_SPI_POLL   /* 查询方式 */

/* USER CODE END 0 */

SPI_HandleTypeDef hspi1;

/* SPI1 init function */
void MX_SPI1_Init(void)
{

  /* USER CODE BEGIN SPI1_Init 0 */

  /* USER CODE END SPI1_Init 0 */

  /* USER CODE BEGIN SPI1_Init 1 */

  /* USER CODE END SPI1_Init 1 */
  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 10;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN SPI1_Init 2 */

  /* USER CODE END SPI1_Init 2 */

}

void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(spiHandle->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspInit 0 */

  /* USER CODE END SPI1_MspInit 0 */
    /* SPI1 clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();

    __HAL_RCC_GPIOB_CLK_ENABLE();
    /**SPI1 GPIO Configuration
    PB3     ------> SPI1_SCK
    PB4     ------> SPI1_MISO
    PB5     ------> SPI1_MOSI
    */
    GPIO_InitStruct.Pin = GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI1_MspInit 1 */

  /* USER CODE END SPI1_MspInit 1 */
  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{

  if(spiHandle->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspDeInit 0 */

  /* USER CODE END SPI1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_SPI1_CLK_DISABLE();

    /**SPI1 GPIO Configuration
    PB3     ------> SPI1_SCK
    PB4     ------> SPI1_MISO
    PB5     ------> SPI1_MOSI
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5);

  /* USER CODE BEGIN SPI1_MspDeInit 1 */

  /* USER CODE END SPI1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
/*
*********************************************************************************************************
*	函 数 名: HAL_SPI_TxRxCpltCallback,HAL_SPI_ErrorCallback
*	功能说明: SPI数据传输完成回调和传输错误回调
*	形    参: SPI_HandleTypeDef 类型指针变量
*	返 回 值: 无
*********************************************************************************************************
*/
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
	wTransferState = TRANSFER_COMPLETE;
}


void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
	wTransferState = TRANSFER_ERROR;
}

/*
*********************************************************************************************************
*	函 数 名: bsp_SpiBusEnter
*	功能说明: 占用SPI总线
*	形    参: 无
*	返 回 值: 0 表示不忙  1表示忙
*********************************************************************************************************
*/
void bsp_SpiBusEnter(void)
{
	g_spi_busy = 1;
}

/*
*********************************************************************************************************
*	函 数 名: bsp_SpiBusExit
*	功能说明: 释放占用的SPI总线
*	形    参: 无
*	返 回 值: 0 表示不忙  1表示忙
*********************************************************************************************************
*/
void bsp_SpiBusExit(void)
{
	g_spi_busy = 0;
}

/*
*********************************************************************************************************
*	函 数 名: bsp_SpiBusBusy
*	功能说明: 判断SPI总线忙,方法是检测其他SPI芯片的片选信号是否为1
*	形    参: 无
*	返 回 值: 0 表示不忙  1表示忙
*********************************************************************************************************
*/
uint8_t bsp_SpiBusBusy(void)
{
	return g_spi_busy;
}

/*
*********************************************************************************************************
*	函 数 名: bsp_spiTransfer
*	功能说明: 启动数据传输
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_spiTransfer(void)
{
	if (g_spiLen > SPI_BUFFER_SIZE)
	{
		return;
	}
	
	/* DMA方式传输 */
#ifdef USE_SPI_DMA
	wTransferState = TRANSFER_WAIT;
	
    if(HAL_SPI_TransmitReceive_DMA(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)	
    {
        Error_Handler();
    }
	
	while (wTransferState == TRANSFER_WAIT)
	{
		;
	}
#endif

	/* 中断方式传输 */	
#ifdef USE_SPI_INT
	wTransferState = TRANSFER_WAIT;

    if(HAL_SPI_TransmitReceive_IT(&hspi, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen) != HAL_OK)	
    {
        Error_Handler();
    }
	
	while (wTransferState == TRANSFER_WAIT)
	{
		;
	}
#endif

	/* 查询方式传输 */	
#ifdef USE_SPI_POLL
	if(HAL_SPI_TransmitReceive(&hspi1, (uint8_t*)g_spiTxBuf, (uint8_t *)g_spiRxBuf, g_spiLen, 1000000) != HAL_OK)	
	{
		Error_Handler();
	}	
#endif
}

/* USER CODE END 1 */

[spi.h]
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    spi.h
  * @brief   This file contains all the function prototypes for
  *          the spi.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 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 */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __SPI_H__
#define __SPI_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */
#define	SPI_BUFFER_SIZE		(4 * 1024)			
extern uint8_t g_spiTxBuf[SPI_BUFFER_SIZE];
extern uint8_t g_spiRxBuf[SPI_BUFFER_SIZE];
extern uint32_t g_spiLen;
extern uint8_t g_spi_busy;

/* USER CODE END Includes */

extern SPI_HandleTypeDef hspi1;

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

void MX_SPI1_Init(void);

/* USER CODE BEGIN Prototypes */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi);
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi);
void bsp_SpiBusEnter(void);
void bsp_SpiBusExit(void);
uint8_t bsp_SpiBusBusy(void);
void bsp_spiTransfer(void);


/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __SPI_H__ */

[main.c]

/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "bsp_flash.h"
/* USER CODE END Includes */



/* USER CODE BEGIN 2 */
sf_ReadInfo();//读取芯片的ID
/* 检测串行Flash OK */
printf("检测到串行Flash, ID = %08X, 型号: %s \r\n", g_tSF.ChipID , g_tSF.ChipName);
printf("    容量 : %dM字节, 扇区大小 : %d字节\r\n", g_tSF.TotalSize/(1024*1024), g_tSF.SectorSize);
/* USER CODE END 2 */


[result]

检测到串行Flash, ID = 00EF4018, 型号: W25Q128 
容量 : 16M字节, 扇区大小 : 4096字节


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/468039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【网页小功能 最简单入门!!!表白墙】【html+javaScript+css实现 简易 网页版 表白墙】

网页小功能 最简单入门&#xff01;&#xff01;&#xff01; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"…

详解达梦数据库字符串大小写敏感

检查数据库实例大小写敏感信息 场景一、初始化数据库实例为大小写敏感库 DDL操作 总结&#xff1a; 大小写敏感的数据库中&#xff1a; 创建表时&#xff1a; ①如果不对表名或列名添加""&#xff0c;那么表名和列名都自动转换为大写形式&#xff1b; ②如果对表…

自动化运维工具之Ansible

目录 一、自动化运维 1、通过xshell自动化运维 2、Ansible简介 3、Ansible特点及优势 4、Ansible核心程序 5、Ansible工作原理及流程 6、部署Ansible自动化运维工具 7、Ansible常用模块 (1) ansible命令行模块 (2) command模块 (3) shell模块 (4) cron模块 (5) us…

程序计算任意连续的12个月公里数不超三万公里预警

为了比亚迪的电池终身质保&#xff0c;写了个简单算法&#xff0c;计算任意12个连续的月份公里数加起来不超过3万公里的预警import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner; import java.util.stream.Collectors;/***…

简单看看就会的tomcat全家桶(部署-多实例-监控-远程上传-日志-优化等)

tomcat学习 一&#xff0c;部署Tomcat 1.配置JDK环境 yum -y install java-1.8.0-openjdk-src.x86_64 #yum源安装JDK1.8 &#xff08;无须配置环境变量&#xff09;2.部署tomcat 下载地址&#xff1a;https://dlcdn.apache.org/tomcat/tomcat-8/v8.5.87/bin/apache-tomcat-…

基于STM32+华为云设计的智慧烟感系统

一、概述 当前基于STM32和华为云,设计了一种智慧烟感系统,该系统可以检测烟雾,同时将检测到的数据上传到云端进行处理和分析。系统可用于家庭、办公室等需要安装烟雾报警器场所。 二、系统设计 2.1 系统硬件设计 【1】硬件平台 该系统主要使用STM32F103ZET6微控制器作为…

点成案例丨点成生物为苏州某药企完成水浴IQOQ验证

点成科普 在生物制药、食品卫生相关实验室中&#xff0c;实验室仪器对产品质量具有重要影响&#xff0c;而实验室仪器在投入使用前的3Q验证&#xff08;IQ、OQ、PQ&#xff09;则是通过设备验证进行产品质量保证的重要部分。3Q验证的具体含义如下&#xff1a; 安装验证 Inst…

Windows系统被faust勒索病毒攻击勒索病毒解密服务器与数据库解密恢复

在近期&#xff0c;一种名为faust后缀的勒索病毒威胁已经引起了全球计算机系统安全领域的关注。faust勒索病毒是一种基于RSA加密算法的恶意软件&#xff0c;能够加密目标计算机系统上的所有文件&#xff0c;并向用户勒索赎金来承诺解密恢复操作。下面为大家介绍一下Windows系统…

「 计算机网络 」TCP的粘包拆包问题

「 计算机网络 」TCP的粘包/拆包问题 参考&鸣谢 大病初愈&#xff0c;一分钟看懂TCP粘包拆包 雷小帅 TCP 的粘包拆包以及解决方案 一乐说 文章目录 「 计算机网络 」TCP的粘包/拆包问题一、前言二、为什么UDP没有粘包三、粘包拆包发生场景四、常见的解决方案五、Netty对粘包…

ChatGPT 平替天花板:HuggingFace 版 ChatGPT 来了,无需魔法无需等待直接起飞 ~

文章目录 ChatGPT 平替天花板&#xff1a;HuggingFace 版 ChatGPT 来了&#xff0c;无需魔法无需等待直接起飞 ~HuggingFace 简介HuggingChat 登场展望 ChatGPT 平替天花板&#xff1a;HuggingFace 版 ChatGPT 来了&#xff0c;无需魔法无需等待直接起飞 ~ 二话不说上链接 htt…

ChatGPT情商很高,但并不适合当搜索引擎

微软和谷歌正急于使用大型语言模型技术来强化搜索引擎。但有充分的理由认为&#xff0c;相比于提供事实性信息&#xff0c;这项技术更适合作为人们情感上的伴侣。 美媒评论称&#xff0c;目前基于大型语言模型的人工智能工具&#xff0c;例如ChatGPT&#xff0c;更擅长共情而不…

初访Chirper:一个禁止人类发言的人工智能社交网络,AI们居然在吵架,太6了

最近&#xff0c;在网上仅仅用ChatGPT和AI聊天已经不够刺激了&#xff0c;现在&#xff0c;AI已经有了属于自己的专属社区&#xff1a;Chirper 简而言之&#xff0c;这是一个禁止人类发帖、评论、转发的类推特网站。人类进去后只能看见&#xff1a;成千上万个AI聊天机器人在其…

[特征提取与匹配]基于Open CV使用SIFT提取特征,并使用FLANN完成单应性匹配

关于单应性 单应性&#xff1a;当一张图是另一张图的一个透视畸变时&#xff0c;在两张图中寻找彼此的一种情况 实现步骤 导入需要的库&#xff1b;读取两张灰度图像作为匹配对象&#xff1b;创建SIFT对象&#xff0c;用于检测SIFT特征点并计算描述子&#xff1b;在两张图像…

提效篇 |当项目紧急入场,如何先测量后校正?

施工队进场后&#xff0c;设计院还没交桩怎么办&#xff1f; 部分工程由于设计与施工间隔时间较久&#xff0c;导致控制点被破坏、复测未通过怎么办&#xff1f; 工期紧张&#xff0c;难道只能干等吗&#xff1f; 答案是&#xff1a;先测量后校正&#xff01;与常规RTK作业不…

tensorflow基础

tensorflow基础 &#xff08;一&#xff09;编程模型&#xff08;1&#xff09;编程模型中的运行机制&#xff08;2&#xff09;编写hello world程序&#xff08;3&#xff09;使用注入机制进行代码编写&#xff08;4&#xff09;保存和载入模型的方法介绍&#xff08;4.1&…

代码随想录|day58|单调栈part01 ● 739. 每日温度 ● 496.下一个更大元素 I

739. 每日温度 链接&#xff1a;代码随想录 今天正式开始单调栈&#xff0c;这是单调栈一篇扫盲题目&#xff0c;也是经典题。 大家可以读题&#xff0c;思考暴力的解法&#xff0c;然后在看单调栈的解法。 就能感受出单调栈的巧妙 fvfdvsf fdfd ddf fdd fd fsd 496.下一个更…

轻量级服务器nginix:如何实现Spring项目的负载均衡

这里写目录标题 一 生成war包并给数据库导入数据1.1生成war包1.2 向数据库中导入数据 二 启动Tomcat三 配置负载均衡并启动Nginx1.cent121这台虚拟机上2.检测两个tomcat的运行状态3.配置nginx4.启动4.1 nginx报错4.2 成功启动项目 四 命令总结 一 生成war包并给数据库导入数据 …

docker和k8s基础介绍

一 Docker介绍 1.1 docker是什么 Docker 是一个开源项目&#xff0c; 诞生于 2013 年初&#xff0c;最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会&#xff0c;遵从了 Apache 2.0协议&#xff0c; 项目代码在…

SQL——索引

&#x1f4a1; 索引 在关系型数据库中&#xff0c;索引是一种单独的、物理上的对数据库表中的一列或多列的值进行排序的一种存储结构&#xff0c;他是某个表中的一列或着若干列值的集合和相应的指向表中物理标识这些值的数据页的逻辑指针清单&#xff08;类似于图书目录&#x…

RF技术设计的机械数码一体化防盗锁

机械数码一体化防盗锁在传统锁具的基础上增加了一个受控的弹子&#xff0c;只能通过设置过的合法钥匙开启&#xff0c;并且增加了防盗报警功能。本文介绍了基于PIC单片机、RF技术和无线数据传输技术的机械数码一体化防盗锁的设计。 引言 机械锁和数码锁是我们日常生活中最常见的…