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

news2025/1/10 22:36:45

一、前言

在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)运行效果

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

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

相关文章

Selenium + python自动化测试环境搭建

selenium 是一个web的自动化测试工具&#xff0c;不少学习功能自动化的同学开始首选selenium &#xff0c;相因为它相比QTP有诸多有点&#xff1a; 免费&#xff0c;也不用再为破解QTP而大伤脑筋 小巧&#xff0c;对于不同的语言它只是一个包而已&#xff0c;而QTP需要下载安…

JSON字符串解析

目录 依赖 方法 示例 判断JSON是否合格 依赖 方法 JSON.parseObject() JSON.parseArray() 示例 Data public class OrderVo {public String name;public Integer price;public Integer count; } JSON数据 { "name": "苹果手机", "pric…

BIT.8_Linux 多线程

目录Linux线程概念什么是线程线程的优点线程的缺点线程异常线程用途Linux进程VS线程进程和线程总结Linux线程控制POSIX线程库创建线程线程ID及进程地址空间布局进程和线程ID区别内核层面&#xff1a;pid & tgid线程终止线程等待__thread 和 pthread_self()分离线程Linux线程…

《爆肝整理》保姆级系列教程python接口自动化(十七)--Json 数据处理---一次爬坑记(详解)

简介 有些 post 的请求参数是 json 格式的&#xff0c;这个前面发送post 请求里面提到过&#xff0c;需要导入 json模块处理。现在企业公司一般常见的接口因为json数据容易处理&#xff0c;所以绝大多数返回数据也是 json 格式的&#xff0c;我们在做判断时候&#xff0c;往往只…

Guava常用工具类总结

-“Null的含糊语义让人很不舒服。Null很少可以明确地表示某种语义&#xff0c;例如&#xff0c;Map.get(key)返回Null时&#xff0c;可能表示map中的值是null&#xff0c;亦或map中没有key对应的值。Null可以表示失败、成功或几乎任何情况。使用Null以外的特定值&#xff0c;会…

每日学术速递2.17

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.LG 1.Decoupled Model Schedule for Deep Learning Training 标题&#xff1a;深度学习训练的解耦模型时间表 作者&#xff1a;Hongzheng Chen, Cody Hao Yu, Shuai Zheng, Zhen Zhang,…

快速识别台式机的内存条

拿上一根内存条&#xff0c;让一个喜欢IT的识别一下&#xff0c;很多人不一定能说出点内容。 这很正常&#xff0c;IT细分领域太多了&#xff0c;很多搞IT的包括写代码的人可能都没有接触内存条。 硬件的集成度随着硬件技术的提升越来越高&#xff0c;成本也下来了&#xff0c;…

支付宝支付详细流程

1、二维码的生成二维码生成坐标 <!-- zxing生成二维码 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.3</version></dependency><dependency><groupId>co…

nvm 控制 node版本

nvm 官网 https://nvm.uihtm.com/ 1、卸掉nodejs&#xff0c;根据官网操作 2、如果之前安装过的nodejs,且安装的目录改变了&#xff0c;需重新配置系统环境 第一步&#xff1a;打开此电脑 > 右键属性 > 高级系统设置 > 环境变量 第二步&#xff1a; 在系统变量中选中…

新手健身准备哪些物品,健身必备蓝牙运动耳机分享

第一次运动健身应该准备什么&#xff1f;运动耳机是一款必备的装备&#xff0c;可以让我们坚持运动的动力源泉&#xff0c;在健身当中远离枯燥乏味&#xff0c;有音乐的加持下健身能够让我们更具动力&#xff0c;有哪些值得入手的蓝牙运动耳机分享呢&#xff1f;看看下面这写分…

Java反射概述

2 反射 2.1 反射概述 Java反射机制&#xff1a;是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展 2.2 反射获取Class类的对象 …

企业的知识文档管理系统需要注重什么?安全和共享能力很重要!

编者按&#xff1a;本文指出了企业的文档管理系统比较注重的能力&#xff0c;并从知识共享和文档安全两方面介绍了老厂商天翎是如何在这块实践的。关键词&#xff1a;知识共享&#xff0c;知识安全&#xff0c;标签分类&#xff0c;智能检索&#xff0c;资料分享&#xff0c;在…

element ui 下拉菜单组件 结合springboot 实现省市区简易三级联动 动态查询 并修改地点的省市区

目录 前言&#xff1a; 一.数据库表结构&#xff1a; 二.下拉菜单组件 2.1 效果展示 2.2下拉菜单的组件代码&#xff1a; 前言&#xff1a; 本篇博客&#xff0c;通过官网的学习&#xff0c;实现下拉菜单动态数据的传递与点击事件&#xff0c;如果只是按部就班的按照官网来…

29岁从事功能测试被辞,面试2个月都找不到工作吗?

最近一个28岁老同学联系我&#xff0c;因为被公司辞退&#xff0c;找我倾诉&#xff0c;于是写下此文。 他是14年二本毕业&#xff0c;在我的印象里人特别懒&#xff0c;不爱学习&#xff0c;专业不好&#xff0c;毕业前因为都没找到合适工作&#xff0c;直接去创业了&#xf…

03:入门篇 - CTK Plugin Framework 基本原理

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 CTK Plugin Framework 技术是面向 C++ 的动态模型系统。该系统允许插件之间的松散耦合,并且提供了设计良好的方式来进行功能和数据的交互。此外,它没有预先对插件施加限制,这样就可以很容易地将插件的相关…

研报精选230217

目录 【行业230217毕马威】奢侈品行业新气象【行业230217国信证券】医药生物行业2023年2月投资策略&#xff1a;持续关注疫后复苏和创新两大主线【行业230217国金证券】航空锻造&#xff1a;稳定格局筑专业化壁垒&#xff0c;顺势而为拓产业链深度【个股230217西南证券_招商轮船…

javaEE 初阶 — 传输层 TCP 协议 中的延迟应答与捎带应答

文章目录1. 延迟应答2. 捎带应答TCP 工作机制&#xff1a;确认应答机制 超时重传机制 连接管理机制 滑动窗口 流量控制与拥塞控制 1. 延迟应答 延时应答 也是提升效率的机制&#xff0c;也是在滑动窗口基础上搞点事情。 滑动窗口的关键是让窗口大小大一点&#xff0c;传输…

LabVIEW监控实时嵌入式目标上的CPU和内存使用情况

LabVIEW监控实时嵌入式目标上的CPU和内存使用情况NI实时&#xff08;RT&#xff09;控制器上有不同的用于监测CPU和内存使用情况的不同选项。可用内存量取决于多个因素&#xff0c;包括已安装的软件和用户应用程序内存要求。本文将介绍从Windows操作系统访问此信息的不同方法&a…

盘点23大厂互联网秋招技术岗薪资!

2023届秋招形式比起前几年严峻了很多。根据牛客网、offershow小程序、脉脉、qq微信群等渠道收集汇总了一波2023届秋招技术岗薪资情况&#xff0c;发现对比2022届秋招薪资基本没有太大变化&#xff0c;往年秋招出现的倒挂现象在23届的秋招中消失了。一起来看下2023届秋招技术岗薪…

Hashtable底层原理分析

特点 1、存放k-v键值对 2、key\value均不能是null&#xff0c;否则会抛出空指针异常NullPointerException 3、线程安全的&#xff0c;底层使用synchronized 高频问题 1、初始化大小多少&#xff1f;什么时候初始化&#xff1f; 答&#xff1a;默认11&#xff0c;在第一次put…