当前位置: 首页 > news >正文

基于STM32采用CS创世 SD NAND(贴片SD卡)完成FATFS文件系统移植与测试

一、前言

在STM32项目开发中,经常会用到存储芯片存储数据。 比如:关机时保存机器运行过程中的状态数据,上电再从存储芯片里读取数据恢复;在存储芯片里也会存放很多资源文件。比如,开机音乐,界面上的菜单图标,字库文件,方便设备开机加载。

为了让单片机更加方便的读写这些资源文件,通常都会加文件系统,如果没有文件系统,直接读取写扇区的方式,对数据不好管理。 这篇文章就手把手教大家,在STM32上完成FATFS文件系统的移植;主控芯片采用STM32F103ZET6, 存储芯片我这里采用(雷龙) CS创世 SD NAND 。 SD NAND 简单来说就是贴片式SD卡,使用起来与普通的SD卡一样,简单的区别就是:比TF卡稳定,比eMMC便宜。 下面章节里会详细介绍下 CS创世 SD NAND。

下面是CS创世 SD NAND 与STM32开发的板的接线实物图:

这是读写扇区测试的结果:

二、SD NAND 介绍

我当前使用的SD NAND型号是,CSNP32GCR01-AOW,容量是4GB。

下面是通过编写STM32代码读取的存储信息:

  1. Card Type:SDHC V2.0

  2. Card ManufacturerID:102

  3. Card RCA:5000

  4. Card Capacity:3696 MB

  5. Card BlockSize:512

芯片的详细参数如下:

【1】不用写驱动程序自带坏块管理

【2】尺寸小巧,简单易用,兼容性强,稳定可靠,固件可定制,LGA-8封装

【3】标准SDIO接口,兼容SPI,兼容拔插式TF卡/SD卡,可替代普通TF卡/SD卡

【4】尺寸6.2x8mm,直接贴片,不占空间

【5】内置平均读写算法,通过1万次随机掉电测试

【6】耐高低温,机贴手贴都非常方便

【7】速度级别Class10(读取速度23.5MB/S写入速度12.3MB/S)

【8】支持标准的SD 2.0协议,用户可以直接移植标准驱动代码,省去了驱动代码编程环节。支持TF卡启动的SOC都可以用SD NAND

【9】比TF卡稳定,比eMMC便宜

**下面是芯片的实物图: ** 这是官网申请的样品,焊接了转接板,可以直接插在SD卡卡槽上测试。 最终选型之后,设计PCB板时,设计接口,直接贴片上去使用,非常稳定,抖动也不会导致,外置卡TF卡这种容易松动的问题。

这是雷龙的官网: http://www.longsto.com/product/35.html

三、编写SD NAND驱动代码

SD NAND 的驱动代码与正常的SD卡协议是一样的,支持标准的SD 2.0协议,下面我就直接贴出写好的驱动代码。

包括了模拟SPI,硬件SPI,SDIO等3种方式,完成对SD NAND 的读写。我当前使用的主控板子是STM32F103ZET6,如果你使用的板子不是这一款,可能还是其他的CPU也没关系;我这里直接贴出了SPI模拟时序的驱动代码,可以直接移植到任何单片机上使用,代码拷贝过去也只需要修改GPIO口即可,非常方便。

3.1 SPI模拟时序驱动方式

(1)整体工程代码

这是当前工程的截图: 代码采用寄存器风格编写,非常简洁。

当前工程完成SD NAND卡初始化,扇区的读写,测试芯片基本的使用情况。

(2) sd.c

#include "sdcard.h"    

static u8  SD_Type=0;  //存放SD卡的类型

/*

函数功能:SD卡底层接口,通过SPI时序向SD卡读写一个字节

函数参数:data是要写入的数据

返 回 值:读到的数据

*/

u8 SDCardReadWriteOneByte(u8 DataTx)

{  

    u8 i;

    u8 data=0;

    for(i=0;i<8;i++)

    {

        SDCARD_SCK=0;

        if(DataTx&0x80)SDCARD_MOSI=1;

        else SDCARD_MOSI=0;

        SDCARD_SCK=1;

        DataTx<<=1;

        

        data<<=1;

        if(SDCARD_MISO)data|=0x01;

    }

    return data;

}

//4种: 边沿两种、电平是两种

/*

函数功能:底层SD卡接口初始化

本程序SPI接口如下:

PC11  片选 SDCardCS

PC12  时钟 SDCardSCLK

PD2   输出 SPI_MOSI--主机输出从机输入

PC8   输入 SPI_MISO--主机输入从机输出

*/

void SDCardSpiInit(void)

{

  /*1. 开启时钟*/

  RCC->APB2ENR|=1<<5;     //使能PORTD时钟

RCC->APB2ENR|=1<<4;     //使能PORTC时钟

  

  /*2. 配置GPIO口模式*/

  GPIOC->CRH&=0xFFF00FF0;

  GPIOC->CRH|=0x00033008;

  

  GPIOD->CRL&=0xFFFFF0FF;

  GPIOD->CRL|=0x00000300;

  

  /*3. 上拉*/

  GPIOC->ODR|=1<<8;

  GPIOC->ODR|=1<<11;

  GPIOC->ODR|=1<<12;

  GPIOD->ODR|=1<<2;

}

/*

函数功能:取消选择,释放SPI总线

*/

void SDCardCancelCS(void)

{

SDCARD_CS=1;

  SDCardReadWriteOneByte(0xff);//提供额外的8个时钟

}

/*

函数 功 能:选择sd卡,并且等待卡准备OK

函数返回值:0,成功;1,失败;

*/

void SDCardSelectCS(void)

{

SDCARD_CS=0;

SDCardWaitBusy();//等待成功

}

/*

函数 功 能:等待卡准备好

函数返回值:0,准备好了;其他,错误代码

*/

void SDCardWaitBusy(void)

{

while(SDCardReadWriteOneByte(0XFF)!=0XFF){}

}

/*

函数功能:等待SD卡回应

函数参数:

Response:要得到的回应值

返 回 值:

0,成功得到了该回应值

其他,得到回应值失败

*/

u8 SDCardGetAck(u8 Response)

{

u16 Count=0xFFFF;//等待次数       

while((SDCardReadWriteOneByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应     

if(Count==0)return SDCard_RESPONSE_FAILURE;//得到回应失败   

else return SDCard_RESPONSE_NO_ERROR;//正确回应

}

/*

函数功能:从sd卡读取一个数据包的内容

函数参数:

buf:数据缓存区

len:要读取的数据长度.

返回值:

0,成功;其他,失败;

*/

u8 SDCardRecvData(u8*buf,u16 len)

{      

if(SDCardGetAck(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE

    while(len--)//开始接收数据

    {

        *buf=SDCardReadWriteOneByte(0xFF);

        buf++;

    }

    //下面是2个伪CRC(dummy CRC)

    SDCardReadWriteOneByte(0xFF);

    SDCardReadWriteOneByte(0xFF);        

    return 0;//读取成功

}

/*

函数功能:向sd卡写入一个数据包的内容 512字节

函数参数:

buf 数据缓存区

cmd 指令

返 回 值:0表示成功;其他值表示失败;

*/

u8 SDCardSendData(u8*buf,u8 cmd)

{

u16 t;      

SDCardWaitBusy();  //等待忙状态

SDCardReadWriteOneByte(cmd);

if(cmd!=0XFD)//不是结束指令

{

for(t=0;t<512;t++)SDCardReadWriteOneByte(buf[t]);//提高速度,减少函数传参时间

    SDCardReadWriteOneByte(0xFF); //忽略crc

    SDCardReadWriteOneByte(0xFF);

  t=SDCardReadWriteOneByte(0xFF); //接收响应

if((t&0x1F)!=0x05)return 2;   //响应错误        

}          

    return 0;//写入成功

}

/*

函数功能:向SD卡发送一个命令

函数参数:

u8 cmd   命令 

u32 arg  命令参数

u8 crc   crc校验值

返回值:SD卡返回的响应

*/   

u8 SendSDCardCmd(u8 cmd, u32 arg, u8 crc)

{

u8 r1;

SDCardCancelCS();               //取消上次片选

SDCardSelectCS(); //选中SD卡

//发送数据

SDCardReadWriteOneByte(cmd | 0x40);//分别写入命令

SDCardReadWriteOneByte(arg >> 24);

SDCardReadWriteOneByte(arg >> 16);

SDCardReadWriteOneByte(arg >> 8);

SDCardReadWriteOneByte(arg);   

SDCardReadWriteOneByte(crc); 

if(cmd==SDCard_CMD12)SDCardReadWriteOneByte(0xff);//Skip a stuff byte when stop reading

do

{

r1=SDCardReadWriteOneByte(0xFF);

}while(r1&0x80);   //等待响应,或超时退出

   return r1; //返回状态值

}

/*

函数功能:获取SD卡的CID信息,包括制造商信息

函数参数:u8 *cid_data(存放CID的内存,至少16Byte)   

返 回 值:

0:成功,1:错误

*/

u8 GetSDCardCISDCardOutnfo(u8 *cid_data)

{

    u8 r1;    

    //发SDCard_CMD10命令,读CID

    r1=SendSDCardCmd(SDCard_CMD10,0,0x01);

    if(r1==0x00)

  {

r1=SDCardRecvData(cid_data,16);//接收16个字节的数据  

    }

SDCardCancelCS();//取消片选

if(r1)return 1;

else return 0;

}

/*

函数说明:

获取SD卡的CSD信息,包括容量和速度信息

函数参数:

u8 *cid_data(存放CID的内存,至少16Byte)     

返 回 值:

0:成功,1:错误

*/

u8 GetSDCardCSSDCardOutnfo(u8 *csd_data)

{

u8 r1;  

r1=SendSDCardCmd(SDCard_CMD9,0,0x01);    //发SDCard_CMD9命令,读CSD

if(r1==0)

{

r1=SDCardRecvData(csd_data, 16);//接收16个字节的数据 

}

SDCardCancelCS();//取消片选

if(r1)return 1;

else return 0;

}  

/*

函数功能:获取SD卡的总扇区数(扇区数)   

返 回 值:

0表示容量检测出错,其他值表示SD卡的容量(扇区数/512字节)

说   明:

每扇区的字节数必为512字节,如果不是512字节,则初始化不能通过.

*/

u32 GetSDCardSectorCount(void)

{

    u8 csd[16];

    u32 Capacity;  

  u16 csize;       

    if(GetSDCardCSSDCardOutnfo(csd)!=0) return 0; //取CSD信息,如果期间出错,返回0

    if((csd[0]&0xC0)==0x40)  //SDHC卡,按照下面方式计算

    {

csize = csd[9] + ((u16)csd[8] << 8) + 1;

Capacity = (u32)csize << 10;//得到扇区数      

    }

    return Capacity;

}

/*

函数功能: 初始化SD卡

返 回 值: 非0表示初始化失败!

*/

u8 SDCardDeviceInit(void)

{

  u8 r1;      // 存放SD卡的返回值

  u8 buf[4];  

u16 i;

SDCardSpiInit();//初始化底层IO口

  for(i=0;i<10;i++)SDCardReadWriteOneByte(0xFF); //发送最少74个脉冲

do

{

r1=SendSDCardCmd(SDCard_CMD0,0,0x95);//进入IDLE状态 闲置

}while(r1!=0X01);

  SD_Type=0;   //默认无卡

if(r1==0X01)

{

if(SendSDCardCmd(SDCard_CMD8,0x1AA,0x87)==1)  //SD V2.0

{

for(i=0;i<4;i++)buf[i]=SDCardReadWriteOneByte(0XFF);

if(buf[2]==0X01&&buf[3]==0XAA)    //卡是否支持2.7~3.6V

{

do

{

SendSDCardCmd(SDCard_CMD55,0,0X01);     //发送SDCard_CMD55

r1=SendSDCardCmd(SDCard_CMD41,0x40000000,0X01);//发送SDCard_CMD41

}while(r1);

if(SendSDCardCmd(SDCard_CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始

{

for(i=0;i<4;i++)buf[i]=SDCardReadWriteOneByte(0XFF);//得到OCR值

if(buf[0]&0x40)SD_Type=SDCard_TYPE_V2HC;    //检查CCS

else SD_Type=SDCard_TYPE_V2;   

}

}

}

}

printf("SD_Type=0x%X\r\n",SD_Type);

SDCardCancelCS();       //取消片选

if(SD_Type)return 0;  //初始化成功返回0

else if(r1)return r1; //返回值错误值    

return 0xaa;          //其他错误

}

/*

函数功能:读SD卡

函数参数:

buf:数据缓存区

sector:扇区

cnt:扇区数

返回值:

0,ok;其他,失败.

说  明:

SD卡一个扇区大小512字节

*/

u8 SDCardReadData(u8*buf,u32 sector,u32 cnt)

{

u8 r1;

if(SD_Type!=SDCard_TYPE_V2HC)sector<<=9;//转换为字节地址

if(cnt==1)

{

r1=SendSDCardCmd(SDCard_CMD17,sector,0X01);//读命令

if(r1==0)   //指令发送成功

{

r1=SDCardRecvData(buf,512); //接收512个字节    

}

}else

{

r1=SendSDCardCmd(SDCard_CMD18,sector,0X01);//连续读命令

do

{

r1=SDCardRecvData(buf,512);//接收512个字节  

buf+=512;  

}while(--cnt && r1==0); 

SendSDCardCmd(SDCard_CMD12,0,0X01); //发送停止命令

}   

SDCardCancelCS();//取消片选

return r1;//

}

/*

函数功能:向SD卡写数据

函数参数:

buf:数据缓存区

sector:起始扇区

cnt:扇区数

返回值:

0,ok;其他,失败.

说  明:

SD卡一个扇区大小512字节

*/

u8 SDCardWriteData(u8*buf,u32 sector,u32 cnt)

{

u8 r1;

if(SD_Type!=SDCard_TYPE_V2HC)sector *= 512;//转换为字节地址

if(cnt==1)

{

r1=SendSDCardCmd(SDCard_CMD24,sector,0X01);//读命令

if(r1==0)//指令发送成功

{

r1=SDCardSendData(buf,0xFE);//写512个字节    

}

}

else

{

if(SD_Type!=SDCard_TYPE_MMC)

{

SendSDCardCmd(SDCard_CMD55,0,0X01);

SendSDCardCmd(SDCard_CMD23,cnt,0X01);//发送指令

}

  r1=SendSDCardCmd(SDCard_CMD25,sector,0X01);//连续读命令

if(r1==0)

{

do

{

r1=SDCardSendData(buf,0xFC);//接收512个字节  

buf+=512;  

}while(--cnt && r1==0);

r1=SDCardSendData(0,0xFD);//接收512个字节 

}

}   

SDCardCancelCS();//取消片选

return r1;//

}

(3) sd.h

#ifndef SD_H

#define SD_H_  

#include "stm32f10x.h"

#include "led.h"

#include "usart.h"

/*----------------------------------------------

本程序SPI接口如下:

PC11  片选 SDCardCS

PC12  时钟 SDCardSCLK

PD2   输出 SPI_MOSI--主机输出从机输入

PC8   输入 SPI_MISO--主机输入从机输出

------------------------------------------------*/

#define SDCARD_CS PCout(11)

#define SDCARD_SCK PCout(12)

#define SDCARD_MOSI PDout(2)

#define SDCARD_MISO PCin(8)

// SD卡类型定义  

#define SDCard_TYPE_ERR     0X00  //卡类型错误

#define SDCard_TYPE_MMC     0X01  //MMC卡

#define SDCard_TYPE_V1      0X02

#define SDCard_TYPE_V2      0X04

#define SDCard_TYPE_V2HC    0X06    

// SD卡指令表      

#define SDCard_CMD0    0       //卡复位

#define SDCard_CMD1    1

#define SDCard_CMD8    8       //命令8 ,SEND_IF_COND

#define SDCard_CMD9    9       //命令9 ,读CSD数据

#define SDCard_CMD10   10      //命令10,读CID数据

#define SDCard_CMD12   12      //命令12,停止数据传输

#define SDCard_CMD13   16      //命令16,设置扇区大小 应返回0x00

#define SDCard_CMD17   17      //命令17,读扇区

#define SDCard_CMD18   18      //命令18,读Multi 扇区

#define SDCard_CMD23   23      //命令23,设置多扇区写入前预先擦除N个block

#define SDCard_CMD24   24      //命令24,写扇区

#define SDCard_CMD25   25      //命令25,写多个扇区

#define SDCard_CMD41   41      //命令41,应返回0x00

#define SDCard_CMD55   55      //命令55,应返回0x01

#define SDCard_CMD58   58      //命令58,读OCR信息

#define SDCard_CMD59   59      //命令59,使能/禁止CRC,应返回0x00、

/*SD卡回应标记字*/

#define SDCard_RESPONSE_NO_ERROR      0x00   //正确回应

#define SDCard_SD_IN_IDLE_STATE       0x01   //闲置状态

#define SDCard_SD_ERASE_RESET         0x02   //擦除复位

#define SDCard_RESPONSE_FAILURE       0xFF   //响应失败

  

//函数声明              

u8 SDCardReadWriteOneByte(u8 data);                 //底层接口,SPI读写字节函数

void SDCardWaitBusy(void);             //等待SD卡准备

u8 SDCardGetAck(u8 Response);         //获得应答

u8 SDCardDeviceInit(void);             //初始化

u8 SDCardReadData(u8*buf,u32 sector,u32 cnt);     //读块(扇区)

u8 SDCardWriteData(u8*buf,u32 sector,u32 cnt);   //写块(扇区)

u32 GetSDCardSectorCount(void);            //读扇区数

u8 GetSDCardCISDCardOutnfo(u8 *cid_data);           //读SD卡CID

u8 GetSDCardCSSDCardOutnfo(u8 *csd_data);           //读SD卡CSD

#endif

(4)运行效果

3.2 SPI硬件时序方式

上面的3.1小节是采用SPI模拟时序驱动SD NAND,STM32本身集成有SPI硬件模块,可以直接利用STM32硬件SPI接口读写。

下面贴出底层的适配代码。 上面贴出的驱动代码里,已经将驱动接口部分和协议逻辑部分区分开了,替换底层的SIP读写代码非常方便。

(1)主要替换的代码

/*

函数功能:SPI初始化(模拟SPI)

硬件连接:

MISO--->PB14

MOSI--->PB15

SCLK--->PB13

*/

void SPI_Init(void)

{

/*开启时钟*/

RCC->APB1ENR|=1<<14;   //开启SPI2时钟

RCC->APB2ENR|=1<<3;    //PB

GPIOB->CRH&=0X000FFFFF; //清除寄存器

GPIOB->CRH|=0XB8B00000;

GPIOB->ODR|=0X7<<13;     //PB13/14/15上拉--输出高电平

/*SPI2基本配置*/

SPI2->CR1=0X0;  //清空寄存器

SPI2->CR1|=0<<15; //选择“双线双向”模式

SPI2->CR1|=0<<11; //使用8位数据帧格式进行发送/接收;

SPI2->CR1|=0<<10; //全双工(发送和接收);

SPI2->CR1|=1<<9;  //启用软件从设备管理

SPI2->CR1|=1<<8;  //NSS

SPI2->CR1|=0<<7;  //帧格式,先发送高位

SPI2->CR1|=0x0<<3;//当总线频率为36MHZ时,SPI速度为18MHZ,高速。

SPI2->CR1|=1<<2;  //配置为主设备

SPI2->CR1|=1<<1;  //空闲状态时, SCK保持高电平。

SPI2->CR1|=1<<0;  //数据采样从第二个时钟边沿开始。

SPI2->CR1|=1<<6;  //开启SPI设备。

}

/*

函数功能:SPI读写一个字节

*/

u8 SPI_ReadWriteOneByte(u8 data_tx)

{

    u16 cnt=0;  

    while((SPI2->SR&1<<1)==0)  //等待发送区空--等待发送缓冲为空

    {

      cnt++;

      if(cnt>=65530)return 0;    //超时退出  u16=2个字节

    }

    SPI2->DR=data_tx;            //发送一个byte 

    cnt=0;

    while((SPI2->SR&1<<0)==0)  //等待接收完一个byte   

    {

      cnt++;

      if(cnt>=65530)return 0;    //超时退出

    }        

    return SPI2->DR;           //返回收到的数据

}

函数功能:SD卡底层接口,通过SPI时序向SD卡读写一个字节

函数参数:data是要写入的数据

返 回 值:读到的数据

*/

u8 SDCardReadWriteOneByte(u8 DataTx)

{  

    return SPI_ReadWriteOneByte(DataTx);

}

(2)运行效果

相关文章:

基于STM32采用CS创世 SD NAND(贴片SD卡)完成FATFS文件系统移植与测试

一、前言 在STM32项目开发中&#xff0c;经常会用到存储芯片存储数据。 比如&#xff1a;关机时保存机器运行过程中的状态数据&#xff0c;上电再从存储芯片里读取数据恢复&#xff1b;在存储芯片里也会存放很多资源文件。比如&#xff0c;开机音乐&#xff0c;界面上的菜单图…...

K_A12_007 基于STM32等单片机驱动AS608光学指纹识别模块 OLED0.96显示

K_A12_007 基于STM32等单片机驱动AS608光学指纹识别模块 OLED0.96显示一、资源说明二、基本参数参数引脚说明三、驱动说明对应程序:四、部分代码说明1、接线引脚定义1.1、STC89C52RCAS608光学指纹模块1.2、STM32F103C8T6AS608光学指纹模块五、基础知识学习与相关资料下载六、视…...

map和set介绍及其底层模拟实现

致努力前行的人&#xff1a; 要努力&#xff0c;但不要着急&#xff0c;繁花锦簇&#xff0c;硕果累累都需要过程&#xff01; 目录 1.关联式容器 2.键值对 3.树形结构的关联式容器 3.1set的介绍 3.2set的使用 3.3multiset的使用 3.4map的使用 3.5multimap的使用 4.常见的面试题…...

实现一个比ant功能更丰富的Modal组件

普通的modal组件如下&#xff1a; 我们写的modal额外支持&#xff0c;后面没有蒙版&#xff0c;并且Modal框能够拖拽 还支持渲染在文档流里&#xff0c;上面的都是fixed布局&#xff0c;我们这个正常渲染到文档下面&#xff1a; render部分 <RenderDialog{...restState}visi…...

2023美赛F题思路数据代码分享

文章目录赛题思路2023年美国大学生数学建模竞赛选题&论文一、关于选题二、关于论文格式三、关于论文提交四、论文提交流程注意不要手滑美赛F题思路数据代码【最新】赛题思路 (赛题出来以后第一时间在CSDN分享) 最新进度在文章最下方卡片&#xff0c;加入获取一手资源 202…...

Flutter如何与Native(Android)进行交互

前言 上一篇文章《Flutter混合开发&#xff1a;Android中如何启动Flutter》中我们介绍了如何在Native&#xff08;Android项目&#xff09;中启动Flutter&#xff0c;展示Flutter页面。但是在开发过程中&#xff0c;很多时候并不是简单的展示一个页面即可&#xff0c;还会涉及…...

数据库主从复制和读写分离

主从数据库和数据库集群的一些问题 数据库集群和主从数据库最本质的区别&#xff0c;其实也就是data-sharing和nothing-sharing的区别。集群是共享存储的。主从复制中没有任何共享。每台机器都是独立且完整的系统。 什么是主从复制? 主从复制&#xff0c;是用来建立一个和主数…...

Java并发编程面试题——线程安全(原子性、可见性、有序性)

文章目录一、原子性高频问题1.1 Java中如何实现线程安全?1.2 CAS底层实现1.3 CAS的常见问题1.4 四种引用类型 ThreadLocal的问题&#xff1f;二、可见性高频问题2.1 Java的内存模型2.2 保证可见性的方式2.3 volatile修饰引用数据类型2.4 有了MESI协议&#xff0c;为啥还有vol…...

DialogFragment内存泄露问题能不能一次性改好

孽缘 自DialogFragment在Android3.0之后作为一种特殊的Fragment引入&#xff0c;官方建议使用DialogFragment代替Dialog或者AllertDialog来实现弹框的功能&#xff0c;因为它可以更好的管理Dialog的生命周期以及可以更好复用。 然而建议虽好&#xff0c;实用须谨慎&#xff0c…...

java学习--多线程

多线程 了解多线程 ​ 多线程是指从软件或者硬件上实现多个线程并发执行的技术。 ​ 具有多线程能力的计算机因有硬件支持而能够在同一时间执行多个线程&#xff0c;提升性能。 并发和并行 并行&#xff1a;在同一时刻&#xff0c;有多个指令在CPU上同时执行并发&#xff1…...

90后阿里P7技术专家晒出工资单:狠补了这个,真香...

最近一哥们跟我聊天装逼&#xff0c;说他最近从阿里跳槽了&#xff0c;我问他跳出来拿了多少&#xff1f;哥们表示很得意&#xff0c;说跳槽到新公司一个月后发了工资&#xff0c;月入5万多&#xff0c;表示很满足&#xff01;这样的高薪资着实让人羡慕&#xff0c;我猜这是税后…...

2023美赛C题:Wordle筛选算法

Wordle 规则介绍 Wordle 每天会更新一个5个字母的单词&#xff0c;在6次尝试中猜出单词就算成功。每个猜测必须是一个有效的单词&#xff08;不能是不能组成单词的字母排列&#xff09;。 每次猜测后&#xff0c;字母块的颜色会改变&#xff0c;颜色含义如下&#xff1a; 程…...

SpringBoot 集成 Kafka

SpringBoot 集成 Kafka1 安装 Kafka2 创建 Topic3 Java 创建 Topic4 SpringBoot 项目4.1 pom.xml4.2 application.yml4.3 KafkaApplication.java4.4 CustomizePartitioner.java4.5 KafkaInitialConfig.java4.6 SendMessageController.java5 测试1 安装 Kafka Docker 安装 Kafk…...

OpenCV 图像金字塔算子

本文是OpenCV图像视觉入门之路的第14篇文章&#xff0c;本文详细的介绍了图像金字塔算子的各种操作&#xff0c;例如&#xff1a;高斯金字塔算子 、拉普拉斯金字塔算子等操作。 高斯金字塔中的较高级别&#xff08;低分辨率&#xff09;是通过先用高斯核对图像进行卷积再删除偶…...

【自学Linux】Linux一切皆文件

Linux一切皆文件 Linux一切皆文件教程 Linux 中所有内容都是以文件的形式保存和管理的&#xff0c;即一切皆文件&#xff0c;普通文件是文件&#xff0c;目录是文件&#xff0c;硬件设备&#xff08;键盘、监视器、硬盘、打印机&#xff09;是文件&#xff0c;就连套接字&…...

CUDA C++扩展的详细描述

CUDA C扩展的详细描述 文章目录CUDA C扩展的详细描述CUDA函数执行空间说明符B.1.1 \_\_global\_\_B.1.2 \_\_device\_\_B.1.3 \_\_host\_\_B.1.4 Undefined behaviorB.1.5 __noinline__ and __forceinline__B.2 Variable Memory Space SpecifiersB.2.1 \_\_device\_\_B.2.2. \_…...

为什么重写equals必须重写hashCode

关于这个问题&#xff0c;看了网上很多答案&#xff0c;感觉都参差不齐&#xff0c;没有答到要点&#xff0c;这次就记录一下&#xff01; 首先我们为什么要重写equals&#xff1f;这个方法是用来干嘛的&#xff1f; public boolean equals &#xff08;Object object&#x…...

< 每日小技巧:N个很棒的 Vue 开发技巧, 持续记录ing >

每日小技巧&#xff1a;6 个很棒的 Vue 开发技巧&#x1f449; ① Watch 妙用> watch的高级使用> 一个监听器触发多个方法> watch 监听多个变量&#x1f449; ② 自定义事件 $emit() 和 事件参数 $event&#x1f449; ③ 监听组件生命周期常规写法hook写法&#x1f44…...

数据结构与算法之二分查找分而治之思想

决定我们成为什么样人的&#xff0c;不是我们的能力&#xff0c;而是我们的选择。——《哈利波特与密室》二分查找是查找算法里面是很优秀的一个算法&#xff0c;特别是在有序的数组中&#xff0c;这种算法思想体现的淋漓尽致。一.题目描述及其要求请实现无重复数字的升序数组的…...

训练自己的中文word2vec(词向量)--skip-gram方法

训练自己的中文word2vec&#xff08;词向量&#xff09;–skip-gram方法 什么是词向量 ​ 将单词映射/嵌入&#xff08;Embedding&#xff09;到一个新的空间&#xff0c;形成词向量&#xff0c;以此来表示词的语义信息&#xff0c;在这个新的空间中&#xff0c;语义相同的单…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

【Oracle APEX开发小技巧12】

有如下需求&#xff1a; 有一个问题反馈页面&#xff0c;要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据&#xff0c;方便管理员及时处理反馈。 我的方法&#xff1a;直接将逻辑写在SQL中&#xff0c;这样可以直接在页面展示 完整代码&#xff1a; SELECTSF.FE…...

工程地质软件市场:发展现状、趋势与策略建议

一、引言 在工程建设领域&#xff0c;准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具&#xff0c;正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

06 Deep learning神经网络编程基础 激活函数 --吴恩达

深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...