nRF52832学习记录(十二、SPI接口的应用 Micro SD卡读写测试)_nrf52832 spi

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

#include “nrf_drv_common.h”
#include “nrf_drv_spi.h”
#include “app_util_platform.h”
#include “app_error.h”
#include “w25q16.h”
#include “nrf_gpio.h”
#include “boards.h”
#include “nrf_delay.h”

#define SPI_INSTANCE 0 /**< SPI instance index. */

static volatile bool spi_xfer_done; //SPI数据传输完成标志
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); /**< SPI instance. */

static uint8_t spi_tx_buf[256]; /**< TX buffer. */
static uint8_t spi_rx_buf[256]; /**< RX buffer. */

/**
* @brief SPI user event handler.
* @param event
*/
void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
void * p_context)
{
spi_xfer_done = true;
}

void hal_spi_init(void)
{
// nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG(SPI_INSTANCE);
// spi_config.ss_pin = SPI_CS_PIN;
// APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler));

nrf\_drv\_spi\_config\_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
spi_config.ss_pin   = SPI_SS_PIN;
spi_config.miso_pin = SPI_MISO_PIN;
spi_config.mosi_pin = SPI_MOSI_PIN;
spi_config.sck_pin  = SPI_SCK_PIN;
APP\_ERROR\_CHECK(nrf\_drv\_spi\_init(&spi, &spi_config, spi_event_handler, NULL));

}

/*****************************************************************************
** 描 述:读出一个字节
** 入 参:无
** 返回值:读出的数据
******************************************************************************/
uint8_t SpiFlash_ReadOneByte(void)
{
uint8_t len = 1;

spi_tx_buf[0] = 0xFF;
spi_xfer_done = false;
APP\_ERROR\_CHECK(nrf\_drv\_spi\_transfer(&spi, spi_tx_buf, len, spi_rx_buf, len));
while(!spi_xfer_done);
return (spi_rx_buf[0]);

}
/*****************************************************************************
** 描 述:写入一个字节
** 入 参:Dat:待写入的数据
** 返回值:无
******************************************************************************/
void SpiFlash_WriteOneByte(uint8_t Dat)
{
uint8_t len = 1;

spi_tx_buf[0] = Dat;
spi_xfer_done = false;
APP\_ERROR\_CHECK(nrf\_drv\_spi\_transfer(&spi, spi_tx_buf, len, spi_rx_buf, len));
while(!spi_xfer_done);

}

/*****************************************************************************
** 描 述:写入命令
** 入 参:*CMD:指向待写入的命令
** 返回值:RET_SUCCESS
******************************************************************************/
uint8_t SpiFlash_Write_CMD(uint8_t *CMD)
{
uint8_t len = 3;

spi_tx_buf[0] = \*CMD;
spi_tx_buf[1] = \*(CMD+1);
spi_tx_buf[2] = \*(CMD+2);
spi_xfer_done = false;
APP\_ERROR\_CHECK(nrf\_drv\_spi\_transfer(&spi, spi_tx_buf, len, spi_rx_buf, len));
while(!spi_xfer_done);
return RET_SUCCESS;

}
/*****************************************************************************
** 描 述:写使能
** 入 参:无
** 返回值:无
******************************************************************************/
void SpiFlash_Write_Enable(void)
{
spi_xfer_done = false;
SpiFlash_WriteOneByte(SPIFlash_WriteEnable_CMD);
while(!spi_xfer_done);
}
/*****************************************************************************
** 描 述:擦除扇区,W25Q128FVSIG最小的擦除单位是扇区
** 入 参:Block_Num:块号
** Sector_Number:扇区号
** 返回值:
******************************************************************************/
void SPIFlash_Erase_Sector(uint8_t Block_Num,uint8_t Sector_Number)
{
SpiFlash_Write_Enable();

spi_tx_buf[0] = SPIFlash_SecErase_CMD;
spi_tx_buf[1] = Block_Num;
spi_tx_buf[2] = Sector_Number<<4;
spi_tx_buf[3] = 0x00;
spi_xfer_done = false;
APP\_ERROR\_CHECK(nrf\_drv\_spi\_transfer(&spi, spi_tx_buf, 4, spi_rx_buf, 4));
while(!spi_xfer_done);	
nrf\_delay\_ms(10);    //每次擦除数据都要延时等待写入结束
return ;

}
/*****************************************************************************
** 描 述:向指定的地址写入数据
** *pBuffer:指向待写入的数据
** WriteAddr:写入的起始地址
** WriteBytesNum:读出的字节数
** 返回值:RET_SUCCESS
******************************************************************************/
uint8_t SpiFlash_Write_Page(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t WriteBytesNum)
{
uint8_t len;

SpiFlash\_Write\_Enable();

spi_tx_buf[0] = SPIFlash_PageProgram_CMD;
spi_tx_buf[1] = (uint8\_t)((WriteAddr&0x00ff0000)>>16);
spi_tx_buf[2] = (uint8\_t)((WriteAddr&0x0000ff00)>>8);
spi_tx_buf[3] = (uint8\_t)WriteAddr;

memcpy(&spi_tx_buf[4],pBuffer,WriteBytesNum);

len = WriteBytesNum + 4;
spi_xfer_done = false;
APP\_ERROR\_CHECK(nrf\_drv\_spi\_transfer(&spi, spi_tx_buf, len, spi_rx_buf, 0));
while(!spi_xfer_done);	

return RET_SUCCESS;

}
/*****************************************************************************
** 描 述:从指定的地址读出指定长度的数据
** 入 参:pBuffer:指向存放读出数据的首地址
** ReadAddr:待读出数据的起始地址
** ReadBytesNum:读出的字节数
** 返回值:
******************************************************************************/
uint8_t SpiFlash_Read(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t ReadBytesNum)
{
uint8_t len;

spi_tx_buf[0] = SPIFlash_ReadData_CMD;
spi_tx_buf[1] = (uint8\_t)((ReadAddr&0x00ff0000)>>16);
spi_tx_buf[2] = (uint8\_t)((ReadAddr&0x0000ff00)>>8);
spi_tx_buf[3] = (uint8\_t)ReadAddr;

len = ReadBytesNum + 4;
spi_xfer_done = false;
APP\_ERROR\_CHECK(nrf\_drv\_spi\_transfer(&spi, spi_tx_buf, len, spi_rx_buf, len));
while(!spi_xfer_done);	
memcpy(pBuffer,&spi_rx_buf[4],ReadBytesNum);

return RET_SUCCESS;

}
/********************************************END FILE*******************************************/


### MicroSD卡(TF卡)SPI测试


SD卡往往有多种通讯方式(上电后需要主机告诉SD卡采用什么方式,所以需要SD卡初始化程序):


* 标准的SPI
* SD模式 —— 一根线的SDIO接口
* SD模式 —— 四根线的SDIO接口,一次可以4个数据出,4个数据回


#### Micro SD卡SPI模式基础知识


Micro SD(TF)卡的引脚说明:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/13e1193eff3e473895447ec4ac4a7ac3.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16)  
 Micro SD卡只有8个引脚是比SD卡少了一个Vss。可以买个SD卡套套在Micro SD卡上,这样一来大小就和SD卡一样大,这时候卡套上的9个引脚就和SD卡一样了,可以完全当做SD卡来操作。  
 在《SD卡接口规范》文档中,有SD卡工作在SPI模式的引脚定义:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/9228fcf389d04b9188b1fdba8663c741.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16)SD卡和Micro SD卡的SPI操作方式是一样的。


SD卡的 SPI 时钟空闲时为高电平,在时钟的第二个边沿,也就是时钟线的电平由低变高时 采集数据,所以配置 SPI 的极性和相位: CPOL = 1, CPHA = 1。由上面第一章的内容可知 **读取SD卡 nRF52832工作在模式 3**。


下面的图片参考博文:[MicroSD卡(TF卡)SPI模式实现方法](https://bbs.csdn.net/topics/618631832)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/92749f70d052401e92f7126bf3c39fd4.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)![在这里插入图片描述](https://img-blog.csdnimg.cn/3a2d8cd25b484a718ddaafcdd102a99c.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)![在这里插入图片描述](https://img-blog.csdnimg.cn/c77f8c25455b454085a2339b3a4b29d8.jpg?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)


#### Micro SD卡SPI 程序移植测试


研究了这么多,最好还是回到当初STM32正点原子的教程里面有SD的读写,驱动,想着直接移植过来试试,最后应该是成功了,没有做过多的测试读写,只是读了一下扇区大小。


* 程序中主要注意 读取SD卡 nRF52832工作在模式 3;
* 速度设置需要额外更改;


**.h部分**



//省略

typedef unsigned char u8;
typedef unsigned long int u32;
typedef unsigned int u16;

// SD卡类型定义
#define SD_TYPE_ERR 0X00
#define SD_TYPE_MMC 0X01
#define SD_TYPE_V1 0X02
#define SD_TYPE_V2 0X04
#define SD_TYPE_V2HC 0X06
// SD卡指令表
#define CMD0 0 //卡复位
#define CMD1 1
#define CMD8 8 //命令8 ,SEND_IF_COND
#define CMD9 9 //命令9 ,读CSD数据
#define CMD10 10 //命令10,读CID数据
#define CMD12 12 //命令12,停止数据传输
#define CMD16 16 //命令16,设置SectorSize 应返回0x00
#define CMD17 17 //命令17,读sector
#define CMD18 18 //命令18,读Multi sector
#define CMD23 23 //命令23,设置多sector写入前预先擦除N个block
#define CMD24 24 //命令24,写sector
#define CMD25 25 //命令25,写Multi sector
#define CMD41 41 //命令41,应返回0x00
#define CMD55 55 //命令55,应返回0x01
#define CMD58 58 //命令58,读OCR信息
#define CMD59 59 //命令59,使能/禁止CRC,应返回0x00
//数据写入回应字意义
#define MSD_DATA_OK 0x05
#define MSD_DATA_CRC_ERROR 0x0B
#define MSD_DATA_WRITE_ERROR 0x0D
#define MSD_DATA_OTHER_ERROR 0xFF
//SD卡回应标记字
#define MSD_RESPONSE_NO_ERROR 0x00
#define MSD_IN_IDLE_STATE 0x01
#define MSD_ERASE_RESET 0x02
#define MSD_ILLEGAL_COMMAND 0x04
#define MSD_COM_CRC_ERROR 0x08
#define MSD_ERASE_SEQUENCE_ERROR 0x10
#define MSD_ADDRESS_ERROR 0x20
#define MSD_PARAMETER_ERROR 0x40
#define MSD_RESPONSE_FAILURE 0xFF

void hal_spi_init(void);
uint8_t SpiFlash_ReadOneByte(void);
void SpiFlash_WriteOneByte(uint8_t Dat);
void spi_set_highspeed(void);
u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc);
u8 SD_Initialize(void);
u8 SD_GetResponse(u8 Response);
u8 SD_RecvData(u8*buf,u16 len);
u8 SD_GetCSD(u8 *csd_data);
u32 SD_GetSectorCount(void);

//省略


**.c部分**



//省略

#define SPI_INSTANCE 0 /**< SPI instance index. */
#define SDCARD 1
u8 SD_Type=0;//SD卡的类型

static volatile bool spi_xfer_done; //SPI数据传输完成标志
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); /**< SPI instance. */

static uint8_t spi_tx_buf[256]; /**< TX buffer. */
static uint8_t spi_rx_buf[256]; /**< RX buffer. */

static nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
/**
* @brief SPI user event handler.
* @param event
*/
void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
void * p_context)
{
spi_xfer_done = true;
}

void hal_spi_init(void)
{
spi_config.ss_pin = SPI_SS_PIN;
spi_config.miso_pin = SPI_MISO_PIN;
spi_config.mosi_pin = SPI_MOSI_PIN;
spi_config.sck_pin = SPI_SCK_PIN;
spi_config.frequency = NRF_DRV_SPI_FREQ_250K;
#ifdef SDCARD
spi_config.mode = NRF_DRV_SPI_MODE_3;
#endif
APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
}

void spi_set_highspeed(void)
{
nrf_drv_spi_uninit(&spi); //改之前必须uninit
spi_config.frequency = NRF_DRV_SPI_FREQ_4M;
APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
}

/*****************************************************************************
** 描 述:读出一个字节
** 入 参:无
** 返回值:读出的数据
******************************************************************************/
uint8_t SpiFlash_ReadOneByte(void)
{
uint8_t len = 1;

spi_tx_buf[0] = 0xFF;
spi_xfer_done = false;
APP\_ERROR\_CHECK(nrf\_drv\_spi\_transfer(&spi, spi_tx_buf, len, spi_rx_buf, len));
while(!spi_xfer_done);
return (spi_rx_buf[0]);

}

/*****************************************************************************
** 描 述:写入一个字节
** 入 参:Dat:待写入的数据
** 返回值:无
******************************************************************************/
void SpiFlash_WriteOneByte(uint8_t Dat)
{
uint8_t len = 1;

spi_tx_buf[0] = Dat;
spi_xfer_done = false;
APP\_ERROR\_CHECK(nrf\_drv\_spi\_transfer(&spi, spi_tx_buf, len, spi_rx_buf, len));
while(!spi_xfer_done);

}

//向SD卡发送一个命令
//输入: u8 cmd 命令
// u32 arg 命令参数
// u8 crc crc校验值
//返回值:SD卡返回的响应
u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)
{
u8 r1;
u8 Retry=0;
// SD_DisSelect();//取消上次片选
// if(SD_Select())return 0XFF;//片选失效
//发送
SpiFlash_WriteOneByte(cmd | 0x40);//分别写入命令
SpiFlash_WriteOneByte(arg >> 24);
SpiFlash_WriteOneByte(arg >> 16);
SpiFlash_WriteOneByte(arg >> 8);
SpiFlash_WriteOneByte(arg);
SpiFlash_WriteOneByte(crc);
if(cmd==CMD12)SpiFlash_WriteOneByte(0xff);//Skip a stuff byte when stop reading
//等待响应,或超时退出
Retry=0X1F;
do
{
r1=SpiFlash_ReadOneByte();
}while((r1&0X80) && Retry–);
//返回状态值
return r1;
}

u8 SD_Initialize(void)
{
u8 r1; // 存放SD卡的返回值
u16 retry; // 用来进行超时计数
u8 buf[4];
u16 i;

hal\_spi\_init();

for(i=0;i<10;i++)SpiFlash\_WriteOneByte(0XFF);//发送最少74个脉冲
retry=20;
do
{
	r1=SD\_SendCmd(CMD0,0,0x95);//进入IDLE状态
}while((r1!=0X01) && retry--);
SD_Type=0;//默认无卡
if(r1==0X01)
{
	if(SD\_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
	{
		for(i=0;i<4;i++)buf[i]=SpiFlash\_ReadOneByte();	//Get trailing return value of R7 resp
		if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V
		{
			retry=0XFFFE;
			do
			{
				SD\_SendCmd(CMD55,0,0X01);	//发送CMD55
				r1=SD\_SendCmd(CMD41,0x40000000,0X01);//发送CMD41
			}while(r1&&retry--);
			if(retry&&SD\_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
			{
				for(i=0;i<4;i++)buf[i]=SpiFlash\_ReadOneByte();//得到OCR值
				if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;    //检查CCS
				else SD_Type=SD_TYPE_V2;   
			}
		}
	}else//SD V1.x/ MMC V3
	{
		SD\_SendCmd(CMD55,0,0X01);		//发送CMD55
		r1=SD\_SendCmd(CMD41,0,0X01);	//发送CMD41
		if(r1<=1)
		{		
			SD_Type=SD_TYPE_V1;
			retry=0XFFFE;
			do //等待退出IDLE模式
			{
				SD\_SendCmd(CMD55,0,0X01);	//发送CMD55
				r1=SD\_SendCmd(CMD41,0,0X01);//发送CMD41
			}while(r1&&retry--);
		}else
		{
			SD_Type=SD_TYPE_MMC;//MMC V3
			retry=0XFFFE;
			do //等待退出IDLE模式
			{											    
				r1=SD\_SendCmd(CMD1,0,0X01);//发送CMD1
			}while(r1&&retry--);  
		}
		if(retry==0||SD\_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;//错误的卡
	}
}
// SD\_DisSelect();//取消片选
spi\_set\_highspeed();//高速
if(SD_Type)return 0;
else if(r1)return r1; 	   
return 0xaa;//其他错误

}

//等待SD卡回应
//Response:要得到的回应值
//返回值:0,成功得到了该回应值
// 其他,得到回应值失败
u8 SD_GetResponse(u8 Response)
{
u16 Count=0xFFFF;//等待次数
while ((SpiFlash_ReadOneByte()!=Response)&&Count)Count–;//等待得到准确的回应
if (Count==0)return MSD_RESPONSE_FAILURE;//得到回应失败
else return MSD_RESPONSE_NO_ERROR;//正确回应
}

//从sd卡读取一个数据包的内容
//buf:数据缓存区
//len:要读取的数据长度.
//返回值:0,成功;其他,失败;
u8 SD_RecvData(u8*buf,u16 len)
{
if(SD_GetResponse(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE
while(len–)//开始接收数据
{
*buf=SpiFlash_ReadOneByte();
buf++;
}
//下面是2个伪CRC(dummy CRC)
SpiFlash_WriteOneByte(0xFF);
SpiFlash_WriteOneByte(0xFF);
return 0;//读取成功
}

//获取SD卡的CSD信息,包括容量和速度信息
//输入:u8 *cid_data(存放CID的内存,至少16Byte)
//返回值:0:NO_ERR
// 1:错误
u8 SD_GetCSD(u8 *csd_data)
{
u8 r1;
r1=SD_SendCmd(CMD9,0,0x01);//发CMD9命令,读CSD
if(r1==0)
{
r1=SD_RecvData(csd_data, 16);//接收16个字节的数据
}
// SD_DisSelect();//取消片选
if(r1)return 1;
else return 0;
}

//获取SD卡的总扇区数(扇区数)
//返回值:0: 取容量出错
// 其他:SD卡的容量(扇区数/512字节)
//每扇区的字节数必为512,因为如果不是512,则初始化不能通过.
u32 SD_GetSectorCount(void)
{
u8 csd[16];
u32 Capacity;
u8 n;
u16 csize;
//取CSD信息,如果期间出错,返回0
if(SD_GetCSD(csd)!=0) return 0;
//如果为SDHC卡,按照下面方式计算
if((csd[0]&0xC0)==0x40) //V2.00的卡
{
csize = csd[9] + ((u16)csd[8] << 8) + 1;
Capacity = (u32)csize << 10;//得到扇区数
}else//V1.XX的卡
{
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
Capacity= (u32)csize << (n - 9);//得到扇区数
}
return Capacity;
}
/********************************************END FILE*******************************************/


最后测试是在主函数调用`SD_GetSectorCount`函数计算扇区大小:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/cad021496eda4c2ab8382ed8078cb16c.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16)![在这里插入图片描述](https://img-blog.csdnimg.cn/10d4832e1510401d82c725f6a3d25b0e.png)  
 换了一个512MB的卡:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/a1511eef9c57434984d83b955daac654.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_19,color_FFFFFF,t_70,g_se,x_16)


#### 最后的疑问


![在这里插入图片描述](https://img-blog.csdnimg.cn/12a5ca8ae37841d394f57239f1e752db.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16)  
 最后还是有一个问题的,我开始读取的是 8G的卡,扇区读出来正常,但是变成 MB 就是3290MB 了,看到网上有个视频教学也是使用的这个驱动,读取8G的卡居然和我这个数据一样 3290 MB。4G和512MB的卡读出来计算出来都正常,感觉是数据类型 低级问题导致的,但是一下子还真不知道,还希望有人能够指点……







![img](https://img-blog.csdnimg.cn/img_convert/08093e7e95ae9bca146dd0b12fb57a2c.png)
![img](https://img-blog.csdnimg.cn/img_convert/acc44da05cacb5688995bf3e6ec42241.png)
![img](https://img-blog.csdnimg.cn/img_convert/74fed897ed5f0add5c6c03c838221c53.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618631832)**

BA55-c6L6w5omA6Ie0,size_20,color_FFFFFF,t_70,g_se,x_16)  
 最后还是有一个问题的,我开始读取的是 8G的卡,扇区读出来正常,但是变成 MB 就是3290MB 了,看到网上有个视频教学也是使用的这个驱动,读取8G的卡居然和我这个数据一样 3290 MB。4G和512MB的卡读出来计算出来都正常,感觉是数据类型 低级问题导致的,但是一下子还真不知道,还希望有人能够指点……







[外链图片转存中...(img-VkkDN3QK-1715811523575)]
[外链图片转存中...(img-Xds1Zyhw-1715811523576)]
[外链图片转存中...(img-PpatS6KM-1715811523576)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!**

**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**

**[需要这份系统化的资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618631832)**

  • 29
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值