HAL库 STM32驱动W25QXX驱动例程

news2024/11/26 0:12:27

HAL库 STM32驱动W25QXX驱动例程


  • 📍驱动程序参考:《STM32CubeMX | 基于STM32使用HAL库W25Q128驱动程序》
  • 🔑 驱动方式:硬件SPI方式和SPI DMA方式。
  • 🔖适用于:W25X系列/Q系列芯片:W25Q80、W25Q16、W25Q32、 W25Q64、 W25Q128、
  • 📌W25Q256可以参考《stm32 W25QXX系列驱动 W25Q80 W25Q16 W25Q32 W25Q64 W25Q128 W25Q256》
    • 📘相关应用篇内容《STM32 STD/HAL库驱动W25Q64模块读写字库数据+OLED0.96显示例程》
  • 🍁W25Q64原理图:

在这里插入图片描述

🔨spi方式配置

在这里插入图片描述

🛠SPI DMA配置

在这里插入图片描述

  • 🌿自定义CS引脚:
    在这里插入图片描述

🔰SPI方式和SPI DMA方式软件驱动代码不同之处

//SPI读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
static uint8_t W25QXX_SPI_ReadWriteByte(uint8_t TxData)
{
    uint8_t RxData = 0X00;


    //	if(HAL_SPI_TransmitReceive(W25QXX_SPI_Handle, &TxData, &RxData, 1, 10) != HAL_OK)//普通方式
    if(HAL_SPI_TransmitReceive_DMA(W25QXX_SPI_Handle, &TxData, &RxData, 1) != HAL_OK) { //DMA接收和发送
        RxData = 0XFF;
    }
    return RxData;
}

W25QXX驱动代码

  • W25QXX.h
#ifndef __W25QXX_H
#define __W25QXX_H
/*
W25QXX ID信息
读取命令(0x90)
W25Q80的芯片ID为:0XEF13
W25Q16 的芯片ID为:0XEF14
W25Q32 的芯片ID为:0XEF15
W25Q64 的芯片ID为:0XEF16
W25Q128的芯片ID为:0XEF17
W25Q256的芯片ID为:0XEF18
W25Q512的芯片ID为:0XEF19

*/
#include <main.h>
//可以根据个人需求配置对应的硬件SPIx
#define W25QXX_SPI_Handle (&hspi2)   //使用SPI2

//W25X系列/Q系列芯片列表
//W25Q80  ID  0XEF13
//W25Q16  ID  0XEF14
//W25Q32  ID  0XEF15
//W25Q64  ID  0XEF16
//W25Q128 ID  0XEF17
#define W25Q80 	0XEF13
#define W25Q16 	0XEF14
#define W25Q32 	0XEF15
#define W25Q64 	0XEF16
#define W25Q128	0XEF17


#define W25QXX_CS_L()  HAL_GPIO_WritePin(W25QXX_CS_GPIO_Port, W25QXX_CS_Pin, GPIO_PIN_RESET)
#define W25QXX_CS_H()  HAL_GPIO_WritePin(W25QXX_CS_GPIO_Port, W25QXX_CS_Pin, GPIO_PIN_SET)


extern uint16_t W25QXX_TYPE;
extern uint32_t W25QXX_SIZE;
extern uint8_t  W25QXX_UID[8];


//
//指令表
#define W25X_WriteEnable		0x06
#define W25X_WriteDisable		0x04
#define W25X_ReadStatusReg		0x05
#define W25X_WriteStatusReg		0x01
#define W25X_ReadData			0x03
#define W25X_FastReadData		0x0B
#define W25X_FastReadDual		0x3B
#define W25X_PageProgram		0x02
#define W25X_BlockErase			0xD8
#define W25X_SectorErase		0x20
#define W25X_ChipErase			0xC7
#define W25X_PowerDown			0xB9
#define W25X_ReleasePowerDown	0xAB
#define W25X_DeviceID			0xAB
#define W25X_ManufactDeviceID	0x90
#define W25X_JedecDeviceID		0x9F

int W25QXX_Init(void);
void W25QXX_ReadUniqueID(uint8_t UID[8]);
uint16_t  W25QXX_ReadID(void);  	    		//读取FLASH ID
uint8_t	 W25QXX_ReadSR(void);        		//读取状态寄存器
void W25QXX_Write_SR(uint8_t sr);  			//写状态寄存器
void W25QXX_Write_Enable(void);  		//写使能
void W25QXX_Write_Disable(void);		//写保护
void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);
void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead);   //读取flash
void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//写入flash
void W25QXX_Erase_Chip(void);    	  	//整片擦除
void W25QXX_Erase_Sector(uint32_t Dst_Addr);	//扇区擦除
void W25QXX_Wait_Busy(void);           	//等待空闲
void W25QXX_PowerDown(void);        	//进入掉电模式
void W25QXX_WAKEUP(void);				//唤醒
uint32_t W25QXX_ReadCapacity(void);

#endif


  • W25Qxx.c

/**
 * @file  w25Qxx.c
 *
 * @brief Create by AnKun on 2020/6/18
 *
 */

#include "W25QXX.h"
#include "spi.h"

uint16_t W25QXX_TYPE = 0;
uint32_t W25QXX_SIZE = 0;
uint8_t W25QXX_UID[8];

static void delay_us(uint32_t us)
{
    uint32_t delay = (HAL_RCC_GetHCLKFreq() / 4000000 * us);
    while(delay--) {
        ;
    }
}

//SPI读写一个字节
//TxData:要写入的字节
//返回值:读取到的字节
static uint8_t W25QXX_SPI_ReadWriteByte(uint8_t TxData)
{
    uint8_t RxData = 0X00;


    //	if(HAL_SPI_TransmitReceive(W25QXX_SPI_Handle, &TxData, &RxData, 1, 10) != HAL_OK)//普通方式
    if(HAL_SPI_TransmitReceive_DMA(W25QXX_SPI_Handle, &TxData, &RxData, 1) != HAL_OK) { //DMA接收和发送
        RxData = 0XFF;
    }
    return RxData;
}

//4Kbytes为一个Sector
//16个扇区为1个Block
//W25Q128
//容量为16M字节,共有128个Block,4096个Sector

//初始化SPI FLASH的IO口
int W25QXX_Init(void)
{
    MX_SPI2_Init();//SPI2初始化
    W25QXX_CS_L(); /* 拉低选中 */
    W25QXX_SPI_ReadWriteByte(0XFF);
    W25QXX_CS_H(); /* 拉高取消 */
    W25QXX_TYPE = W25QXX_ReadID(); // 读取FLASH ID.
    W25QXX_SIZE = W25QXX_ReadCapacity(); // 读取容量
    W25QXX_ReadUniqueID(W25QXX_UID); // 读取唯一ID
    if((W25QXX_TYPE & 0XEF00) != 0XEF00) {
        return -1;
    }
    return 0;
}

//读取W25QXX的状态寄存器
//BIT7  6   5   4   3   2   1   0
//SPR   RV  TB BP2 BP1 BP0 WEL BUSY
//SPR:默认0,状态寄存器保护位,配合WP使用
//TB,BP2,BP1,BP0:FLASH区域写保护设置
//WEL:写使能锁定
//BUSY:忙标记位(1,忙;0,空闲)
//默认:0x00
uint8_t W25QXX_ReadSR(void)
{
    uint8_t byte = 0;
    W25QXX_CS_L(); //使能器件
    W25QXX_SPI_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令
    byte = W25QXX_SPI_ReadWriteByte(0Xff); //读取一个字节
    W25QXX_CS_H(); //取消片选
    return byte;
}
//写W25QXX状态寄存器
//只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
void W25QXX_Write_SR(uint8_t sr)
{
    W25QXX_CS_L(); //使能器件
    W25QXX_SPI_ReadWriteByte(W25X_WriteStatusReg); //发送写取状态寄存器命令
    W25QXX_SPI_ReadWriteByte(sr);	//写入一个字节
    W25QXX_CS_H(); //取消片选
}
//W25QXX写使能
//将WEL置位
void W25QXX_Write_Enable(void)
{
    W25QXX_CS_L(); //使能器件
    W25QXX_SPI_ReadWriteByte(W25X_WriteEnable);	//发送写使能
    W25QXX_CS_H(); //取消片选
}
//W25QXX写禁止
//将WEL清零
void W25QXX_Write_Disable(void)
{
    W25QXX_CS_L(); //使能器件
    W25QXX_SPI_ReadWriteByte(W25X_WriteDisable); //发送写禁止指令
    W25QXX_CS_H(); //取消片选
}
//读取芯片ID
//返回值如下:
//0XEF13,表示芯片型号为W25Q80
//0XEF14,表示芯片型号为W25Q16
//0XEF15,表示芯片型号为W25Q32
//0XEF16,表示芯片型号为W25Q64
//0XEF17,表示芯片型号为W25Q128
uint16_t W25QXX_ReadID(void)
{
    uint16_t Temp = 0;
    W25QXX_CS_L();
    W25QXX_SPI_ReadWriteByte(0x90); //发送读取ID命令
    W25QXX_SPI_ReadWriteByte(0x00);
    W25QXX_SPI_ReadWriteByte(0x00);
    W25QXX_SPI_ReadWriteByte(0x00);
    Temp |= W25QXX_SPI_ReadWriteByte(0xFF) << 8;
    Temp |= W25QXX_SPI_ReadWriteByte(0xFF);
    W25QXX_CS_H();
    return Temp;
}

uint32_t W25QXX_ReadCapacity(void)
{
    int i = 0;
    uint8_t arr[4] = {0, 0, 0, 0};
    W25QXX_CS_L();
    W25QXX_SPI_ReadWriteByte(0x5A);
    W25QXX_SPI_ReadWriteByte(0x00);
    W25QXX_SPI_ReadWriteByte(0x00);
    W25QXX_SPI_ReadWriteByte(0x84);
    W25QXX_SPI_ReadWriteByte(0x00);
    for(i = 0; i < sizeof(arr); i++) {
        arr[i] = W25QXX_SPI_ReadWriteByte(0xFF);
    }
    W25QXX_CS_H();
    return ((((*(uint32_t *)arr)) + 1) >> 3);
}

void W25QXX_ReadUniqueID(uint8_t UID[8])
{
    int i = 0;
    W25QXX_CS_L();
    W25QXX_SPI_ReadWriteByte(0x4B);
    W25QXX_SPI_ReadWriteByte(0x00);
    W25QXX_SPI_ReadWriteByte(0x00);
    W25QXX_SPI_ReadWriteByte(0x00);
    W25QXX_SPI_ReadWriteByte(0x00);
    for(i = 0; i < 8; i++) {
        UID[i] = W25QXX_SPI_ReadWriteByte(0xFF);
    }
    W25QXX_CS_H();
}

//读取SPI FLASH
//在指定地址开始读取指定长度的数据
//pBuffer:数据存储区
//ReadAddr:开始读取的地址(24bit)
//NumByteToRead:要读取的字节数(最大65535)
void W25QXX_Read(uint8_t *pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{
    uint16_t i;
    W25QXX_CS_L(); //使能器件
    W25QXX_SPI_ReadWriteByte(W25X_ReadData);	//发送读取命令
    W25QXX_SPI_ReadWriteByte((uint8_t)((ReadAddr) >> 16));	//发送24bit地址
    W25QXX_SPI_ReadWriteByte((uint8_t)((ReadAddr) >> 8));
    W25QXX_SPI_ReadWriteByte((uint8_t)ReadAddr);
    for(i = 0; i < NumByteToRead; i++) {
        pBuffer[i] = W25QXX_SPI_ReadWriteByte(0XFF);	//循环读数
    }
    W25QXX_CS_H();
}
//SPI在一页(0~65535)内写入少于256个字节的数据
//在指定地址开始写入最大256字节的数据
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
void W25QXX_Write_Page(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint16_t i;
    W25QXX_Write_Enable();	//SET WEL
    W25QXX_CS_L(); //使能器件
    W25QXX_SPI_ReadWriteByte(W25X_PageProgram);	//发送写页命令
    W25QXX_SPI_ReadWriteByte((uint8_t)((WriteAddr) >> 16));	//发送24bit地址
    W25QXX_SPI_ReadWriteByte((uint8_t)((WriteAddr) >> 8));
    W25QXX_SPI_ReadWriteByte((uint8_t)WriteAddr);
    for(i = 0; i < NumByteToWrite; i++)
        W25QXX_SPI_ReadWriteByte(pBuffer[i]); //循环写数
    W25QXX_CS_H(); //取消片选
    W25QXX_Wait_Busy();	//等待写入结束
}
//无检验写SPI FLASH
//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
//具有自动换页功能
//在指定地址开始写入指定长度的数据,但是要确保地址不越界!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
//CHECK OK
void W25QXX_Write_NoCheck(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint16_t pageremain;
    pageremain = 256 - WriteAddr % 256; //单页剩余的字节数
    if(NumByteToWrite <= pageremain)
        pageremain = NumByteToWrite; //不大于256个字节
    while(1) {
        W25QXX_Write_Page(pBuffer, WriteAddr, pageremain);
        if(NumByteToWrite == pageremain)
            break; //写入结束了
        else { //NumByteToWrite>pageremain
            pBuffer += pageremain;
            WriteAddr += pageremain;

            NumByteToWrite -= pageremain; //减去已经写入了的字节数
            if(NumByteToWrite > 256)
                pageremain = 256; //一次可以写入256个字节
            else
                pageremain = NumByteToWrite; //不够256个字节了
        }
    };
}
//写SPI FLASH
//在指定地址开始写入指定长度的数据
//该函数带擦除操作!
//pBuffer:数据存储区
//WriteAddr:开始写入的地址(24bit)
//NumByteToWrite:要写入的字节数(最大65535)
uint8_t W25QXX_BUFFER[4096];
void W25QXX_Write(uint8_t *pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{
    uint32_t secpos;
    uint16_t secoff;
    uint16_t secremain;
    uint16_t i;
    uint8_t *W25QXX_BUF;
    W25QXX_BUF = W25QXX_BUFFER;
    secpos = WriteAddr / 4096; //扇区地址
    secoff = WriteAddr % 4096; //在扇区内的偏移
    secremain = 4096 - secoff; //扇区剩余空间大小
    if(NumByteToWrite <= secremain)
        secremain = NumByteToWrite; //不大于4096个字节
    while(1) {
        W25QXX_Read(W25QXX_BUF, secpos * 4096, 4096); //读出整个扇区的内容
        for(i = 0; i < secremain; i++) { //校验数据
            if(W25QXX_BUF[secoff + i] != 0XFF)
                break; //需要擦除
        }
        if(i < secremain) { //需要擦除
            W25QXX_Erase_Sector(secpos);	//擦除这个扇区
            for(i = 0; i < secremain; i++) {	//复制
                W25QXX_BUF[i + secoff] = pBuffer[i];
            }
            W25QXX_Write_NoCheck(W25QXX_BUF, secpos * 4096, 4096);	//写入整个扇区

        } else
            W25QXX_Write_NoCheck(pBuffer, WriteAddr, secremain); //写已经擦除了的,直接写入扇区剩余区间.
        if(NumByteToWrite == secremain)
            break; //写入结束了
        else { //写入未结束
            secpos++; //扇区地址增1
            secoff = 0; //偏移位置为0

            pBuffer += secremain;	//指针偏移
            WriteAddr += secremain;	//写地址偏移
            NumByteToWrite -= secremain;	//字节数递减
            if(NumByteToWrite > 4096)
                secremain = 4096;	//下一个扇区还是写不完
            else
                secremain = NumByteToWrite;	//下一个扇区可以写完了
        }
    };
}

//擦除整个芯片
//等待时间超长...
void W25QXX_Erase_Chip(void)
{
    W25QXX_Write_Enable();	//SET WEL
    W25QXX_Wait_Busy();
    W25QXX_CS_L(); //使能器件
    W25QXX_SPI_ReadWriteByte(W25X_ChipErase);	//发送片擦除命令
    W25QXX_CS_H(); //取消片选
    W25QXX_Wait_Busy();	//等待芯片擦除结束
}
//擦除一个扇区
//Dst_Addr:扇区地址 根据实际容量设置
//擦除一个山区的最少时间:150ms
void W25QXX_Erase_Sector(uint32_t Dst_Addr)
{
    //监视falsh擦除情况,测试用
    Dst_Addr *= 4096;
    W25QXX_Write_Enable();	//SET WEL
    W25QXX_Wait_Busy();
    W25QXX_CS_L(); //使能器件
    W25QXX_SPI_ReadWriteByte(W25X_SectorErase);	//发送扇区擦除指令
    W25QXX_SPI_ReadWriteByte((uint8_t)((Dst_Addr) >> 16));	//发送24bit地址
    W25QXX_SPI_ReadWriteByte((uint8_t)((Dst_Addr) >> 8));
    W25QXX_SPI_ReadWriteByte((uint8_t)Dst_Addr);
    W25QXX_CS_H(); //取消片选
    W25QXX_Wait_Busy();	//等待擦除完成
}
//等待空闲
void W25QXX_Wait_Busy(void)
{
    while((W25QXX_ReadSR() & 0x01) == 0x01);	// 等待BUSY位清空
}
//进入掉电模式
void W25QXX_PowerDown(void)
{
    W25QXX_CS_L(); //使能器件
    W25QXX_SPI_ReadWriteByte(W25X_PowerDown); //发送掉电命令
    W25QXX_CS_H(); //取消片选
    delay_us(3); //等待TPD
}
//唤醒
void W25QXX_WAKEUP(void)
{
    W25QXX_CS_L(); //使能器件
    W25QXX_SPI_ReadWriteByte(W25X_ReleasePowerDown); // send W25X_PowerDown command 0xAB
    W25QXX_CS_H(); //取消片选
    delay_us(3);	//等待TRES1
}


  • 📝测试代码
int main(void)
{
  /* USER CODE BEGIN 1 */
    uint32_t USART_TIMER ;
  /* 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_DMA_Init();
  MX_SPI2_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
    USART_TIMER = HAL_GetTick();
    printf("SYSCLOCK:%d\r\n", HAL_RCC_GetSysClockFreq()); //HAL_RCC_GetHCLKFreq
    W25QXX_Init();
    printf("FLASH ID=%X\r\n", W25QXX_ReadID());
		HAL_Delay(1000);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    while(1) {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
        if(HAL_GetTick() - USART_TIMER > 1000) {
            USART_TIMER = HAL_GetTick();
            HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
					printf("FLASH ID=%X HCLKFreq:%d\r\n", W25QXX_ReadID(),(uint32_t)HAL_RCC_GetHCLKFreq());
        }
    }
  /* USER CODE END 3 */
}
  • 串口打印:
    在这里插入图片描述

📚程序源码

  • 🌿SPI方式:
链接:https://pan.baidu.com/s/1nNLn-v1OdynznLA2m6hDxg?pwd=ilml 
提取码:ilml
  • 🌿SPI DMA方式
链接:https://pan.baidu.com/s/1acqzZIN4ZNv4DQm7kcVu1w?pwd=ircb 
提取码:ircb

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

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

相关文章

rust函数 stuct struct方法 关联函数

本文结合2个代码实例主要介绍了rust函数定义方法&#xff0c;struct结构体定义、struct方法及关联函数等相关基础知识。 代码1&#xff1a; main.rc #[derive(Debug)]//定义一个结构体 struct Ellipse {max_semi_axis: u32,min_semi_axis: u32, }fn main() {//椭圆&#xff0…

第14集《佛说四十二章经》

好&#xff01;请大家打开讲义第十九面&#xff0c;第三十九章、教诲无差。 佛言&#xff1a;学佛道者&#xff0c;佛所言说&#xff0c;皆应信顺。譬如食蜜&#xff0c;中边皆甜。吾经亦尔。 大智慧的佛陀说&#xff0c;佛弟子们在修学过程中&#xff0c;对佛陀所说的一切佛…

面向对象编程(一)

目录 1. 面向对象编程概述(了解) 1.1 程序设计的思路 1.2 由实际问题考虑如何设计程序 2. Java语言的基本元素&#xff1a;类和对象 2.1 类和对象概述 2.2 类的成员概述 2.3面向对象完成功能的三步骤&#xff08;重要&#xff09; 步骤1&#xff1a;类的定义 步骤2&#xff1a;…

什么是数据同步利器DataX,如何使用?

转载至我的博客 https://www.infrastack.cn &#xff0c;公众号&#xff1a;架构成长指南 今天给大家分享一个阿里开源的数据同步工具DataX&#xff0c;在Github拥有14.8k的star&#xff0c;非常受欢迎&#xff0c;官网地址&#xff1a;https://github.com/alibaba/DataX 什么…

c++类和对象新手保姆级上手教学(上)

前言&#xff1a; c其实顾名思义就是c语言的升级版&#xff0c;很多刚学c的同学第一感觉就是比c语言难学很多&#xff0c;其实没错&#xff0c;c里的知识更加难以理解可以说杂且抽象&#xff0c;光是类和对象&#xff0c;看起来容易&#xff0c;但想完全吃透&#xff0c;真的挺…

(免费领源码)java#springboot#mysql医院自助服务系统74853-计算机毕业设计项目选题推荐

目 录 摘要 1 绪论 1.1研究意义 1.2研究背景 1.3springboot框架介绍 1.3论文结构与章节安排 2 医院自助服务系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分…

java+springboot+vue试题库在线学习系统05umj

技术路线&#xff1a; B/S架构&#xff0c;后端springboot框架&#xff0c;前端Vue.js框架。 主要功能模块&#xff08;至少六大功能&#xff09;&#xff0c;参考任务书并拓展 &#xff08;1&#xff09;用户管理模块&#xff1a;规定不同角色的用户对系统中各个功能模块的使用…

【学网攻】 第(29)节 -- 综合实验二

系列文章目录 目录 系列文章目录 文章目录 前言 一、综合实验 二、实验 1.引入 实验目标 实验设备 实验拓扑图 实验配置 实验验证 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学网攻…

【Make编译控制 06】CMake初步使用

目录 一、概述与安装 二、编译源文件 三、无关文件管理 一、概述与安装 CMake是一个跨平台的项目构建工具&#xff0c;相比于Makefile&#xff0c;CMake更加高级&#xff0c;因为CMake代码在执行的时候是会先翻译生成Makefile文件&#xff0c;再调用Makefile文件完成项目构…

【Python--网络编程之TCP三次握手】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Python开发技术 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; Python网络编程之[TCP三次握手] 往期内容代码见资源&#xff0c;效果图如下一、实验要求二、协…

MySQL数据库基础(六):DDL数据库操作

文章目录 DDL数据库操作 一、MySQL的组成结构 二、数据库的基本操作 1、创建数据库 2、查询数据库 3、删除数据库 4、选择数据库 三、总结 DDL数据库操作 一、MySQL的组成结构 注&#xff1a;我们平常说的MySQL&#xff0c;其实主要指的是MySQL数据库管理软件。 一个M…

django定时任务(django-crontab)

目录 一&#xff1a;安装django-crontab&#xff1a; 二&#xff1a;添加django_crontab到你的INSTALLED_APPS设置&#xff1a; 三&#xff1a;运行crontab命令来创建或更新cron作业&#xff1a; 四&#xff1a;定义你的cron作业 五&#xff1a;创建你的管理命令&#xff…

电源管理芯片是指在电子设备系统中,负责对电能的变换、分配、检测等进行管理的芯片

萨科微半导体宋仕强介绍说&#xff0c;电源管理芯片是指在电子设备系统中&#xff0c;负责对电能的变换、分配、检测等进行管理的芯片&#xff0c;其性能和可靠性直接影响电子设备的工作效率和使用寿命&#xff0c;是电子设备中的关键器件。萨科微slkor&#xff08;www.slkormi…

牛客网SQL进阶128:未完成试卷数大于1的有效用户

官网链接&#xff1a; 未完成试卷数大于1的有效用户_牛客题霸_牛客网现有试卷作答记录表exam_record&#xff08;uid用户ID, exam_id试卷ID, st。题目来自【牛客题霸】https://www.nowcoder.com/practice/46cb7a33f7204f3ba7f6536d2fc04286?tpId240&tqId2183007&ru%2…

【王道数据结构】【chapter5树与二叉树】【P185t4】

编程求以孩子兄弟表示法存储的森林的叶节点数 #include <iostream> typedef struct node{char data;struct node * pchild;struct node * pbrother; }node,*pnode;pnode buynode(char x) {node* tmp(pnode) malloc(sizeof (node));tmp->datax,tmp->pchild nullptr,…

Crypto-RSA1

题目&#xff1a; 已知p,q,dp,dq,c求明文&#xff1a; 首先有如下公式&#xff1a; dp≡d mod (p-1)&#xff0c;dq≡d mod (q-1) &#xff0c; m≡c^d(mod n) &#xff0c; npq python代码解题如下&#xff1a; import libnump 863763376725700856709965348654109117132049…

人工智能学习与实训笔记(三):神经网络之目标检测问题

目录 五、目标检测问题 5.1 目标检测基础概念 5.1.1 边界框&#xff08;bounding box&#xff09; 5.1.2 锚框&#xff08;Anchor box&#xff09; 5.1.3 交并比 5.2 单阶段目标检测模型YOLOv3 5.2.1 YOLOv3模型设计思想 5.2.2 YOLOv3模型训练过程 5.2.3 如何建立输出…

【JS逆向+Python模拟API请求】逆向某一个略微中等的混淆网站,并模拟调用api请求 仅供学习。注:不是源代码混淆,而是一个做代码混淆业务的网站,

逆向日期&#xff1a;2024.02.16 使用工具&#xff1a;Node.js 加密方法&#xff1a;RSA标准库 文章全程已做去敏处理&#xff01;&#xff01;&#xff01; 【需要做的可联系我】 AES解密处理&#xff08;直接解密即可&#xff09;&#xff08;crypto-js.js 标准算法&#xf…

ubuntu22.04@laptop OpenCV Get Started: 012_mouse_and_trackbar

ubuntu22.04laptop OpenCV Get Started: 012_mouse_and_trackbar 1. 源由2. mouse/trackbar应用Demo2.1 C应用Demo2.2 Python应用Demo 3. 鼠标位置跟踪注释3.1 注册回调函数3.2 回调操作3.3 效果 4. 使用轨迹栏调整图像大小4.1 初始化轨迹栏&注册回调函数4.2 回调操作4.3 效…

GEE:如何在下载CSV文件时去除不想要的属性列

作者:CSDN @ _养乐多_ 如下图所示,我们在 Google Earth Engine(GEE)平台上处理完数据,并想以csv文件格式下载属性数据到本地时,GEE会自动添加一些属性,比如用来记录点的坐标的.geo属性。那么我们如何去除.geo列或者其他不想要的列呢?比如,去除下图中index、SR_B3、SR…