sd 卡读写c8051版本 简单入门版 无文件系统

合集下载

51单片机SD卡读写

51单片机SD卡读写

return temp; //返回读取的数据
}
//复位函数//
uchar sd_reset()
{
uchar i,temp=0xff,time;
uchar table[]={0x40,0x00,0x00,0x00,0x00,0x95};
flag_time=1;
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
//错误码定义//
#define cmd0_error 0x01
#define cmd1_error 0x02
}
write_sd(0xff);
write_sd(0xff); //两字节奇偶校验
temp=read_sd(); //读取返回值
if((temp&0x1f)!=0x05) //如果返回值是 xxx00101 说明数据已经被写入
if(time==100)
{
return read_error;
}
}
while(temp!=0);
write_sd(0xff); //补偿8个时钟
//由于sd卡操作一次性只能写一个扇区也就是512个字节
//所以这里通过将长整型地址左移九位来将地址乘上512
//用于地址操作
table[1]=((add&0xff000000)>>24);
table[2]=((add&0x00ff0000)>>16);

单片机读写SD卡

单片机读写SD卡

单片机读写SD卡最简单最基本的程序处理器:s3c44b0 (arm7)SD卡与处理器的引脚连接:MISO -->SIORxD MOSI -->SIOTxD CLK -->SCLK CS -->PE5包括四个文件:sd_drive.c :用户API函数,移植时不需修改sd_cmd.c:中间层函数,移植时不需修改sd_hard.c:硬件层函数,移植时需修改sd_config.h:一些功能的宏定义,移植时需修改第一次读写SD卡时,需调用SD_Init(void),然后就可以条用Read_Single_Block或者Write_Single_Block进行读写操作注意:进行写操作时,最好不要写前700个扇区,应为这些扇区都是FAT文件系统的重要扇区,一旦误写则可能会导致SD无法被电脑识别,需格式化。

/*******************************************************文件名:sd_drive.c作用:用户API函数,包括四个函数,读取一块扇区(512字节)U8 Read_Single_Block(U32 blk_addr, U8 *rx_buf)写一个扇区(512字节)U8 Write_Single_Block(U32 blk_addr, U8 *tx_buf)获取SD卡基本信息,即读CSD寄存器信息(16字节):void SD_info()SD卡初始化:U8 SD_Init(void)********************************************************//********************************************功能:读取一个block输入:blk_addr为第几个block,rx_buf为数据缓存区首地址输出:返回NO_ERR则成功,其它则读取失败********************************************/U8 Read_Single_Block(U32 blk_addr, U8 *rx_buf){U16 rsp = 1;U8 i = 0;SD_sel(); //使能SD卡while(rsp && (i < 100)){write_cmd(CMD17, blk_addr << 9); //写命令CMD17rsp = Get_rsp(R1); //获取答应send_clk();}if(i > 99) //如果命令超时,则执行超时处理{SD_desel();Uart_Printf("fail in writing CMD17\n");return WR_SGL_BLK_ERR;}spi_ro_mode();send_clk(); //发送8个clkread_data(rx_buf); //读取512字节SD_desel();Uart_Printf("succeed in reading the %dst block!!!\n", blk_addr); return NO_ERR;}/********************************************功能:写一个block输入:blk_addr为要写第几个block,tx_buf为数据区输出:返回NO_ERR则成功,其它则读取失败********************************************/U8 Write_Single_Block(U32 blk_addr, U8 *tx_buf){U16 rsp = 1;U8 i = 0;SD_sel(); //使能SD卡while(rsp && (i < 100)){write_cmd(CMD24, blk_addr << 9); //写命令CMD24rsp = Get_rsp(R1); //获取答应send_clk();}if(i > 99) //如果命令超时,则执行超时处理{SD_desel();Uart_Printf("fail in writing CMD17\n");return WR_SGL_BLK_ERR;}spi_ro_mode();send_clk(); //发送8个clkwrite_data(tx_buf); //读取512字节SD_desel();Uart_Printf("succeed in writing a block!!!\n");return NO_ERR;}/********************************************功能:SD卡初始化输入:无输出:返回NO_ERR则成功,其它则读取失败********************************************/U8 SD_Init(void){U16 rsp = 1;U8 i = 0;spi_port_init(); //初始化spi端口spi_low_speed(); //初始化时SPI的速度必须低于400khzspi_ro_mode(); //只读模式SD_sel(); //选择SD卡for (i = 0;i < 10; i++) //发送至少75个clksend_clk();while(rsp && (i++ < 100)){write_cmd(CMD0, 0); //写命令CMD0rsp = Get_rsp(R1); //获取答应if (rsp == 1) //rsp为0则初始化成功,为1则继续写CMD0 break;send_clk();}SD_desel();if (i > 99) //初始化超时处理{Uart_Printf("fail in writing CMD0!!!\n");return INIT_FAIL;}i=0;SD_sel();while(rsp && (i++ < 100)){write_cmd(CMD1, 0); //写CMD1rsp = Get_rsp(R1); //获取答应send_clk();}SD_desel();if (i > 99){Uart_Printf("fail in writing CMD1!!!\n");return INIT_FAIL;}Uart_Printf("SD card init OK!!!\n");spi_high_speed(); //初始化工作全部完毕,SPI进入模式模式spi_rt_mode();return NO_ERR;}/********************************************功能:获取SD卡信息输入:输出:********************************************/void SD_info(){U8 rsp=0;U8 csd[16];SD_sel();write_cmd(CMD9, 0);rsp = Get_rsp(R1);if (rsp != 0){SD_desel();Uart_Printf("error in getting SD info!!!\n");return ;//GET_INFO_ERR;}if (read_register(16, csd) != NO_ERR){SD_desel();return ;}SD_desel();Uart_Printf("SD information :\n");if (csd[0] & 0x40 ==0x40){Uart_Printf("version 2.0\n");Uart_Printf("size is : %d\n",1024 * (csd[8]<<8 + csd[9]));}else{Uart_Printf("version 1.x \n");Uart_Printf("size is : %d MByte\n", ((((csd[6]&0x03)<<10) | (csd[7]<<2) |((csd[8]&0xC0)>>6) + 1) * (1 << ((((csd[9]&0x03)<<1) | ((csd[10]&0x80)>>7)) + 2)))>>11); }Uart_Printf("max block lenght is : %d\n",1<<(csd[5]&0x0f));}/****************************************************************************文件名:sd_cmd.c作用:中间层函数****************************************************************************//********************************************功能:向SD写入一个命令输入:cmd为命令,addr为SD卡片内地址输出:无********************************************/void write_cmd(U8 cmd, U32 addr){U8 i = 0;U8 temp[4];spi_rt_mode(); //spi发送与接收模式if (cmd <= 13) //前13个命令与地址无关{spi_write_byte((cmd & 0x3F) | 0x40); //命令最高两位必须是01for(i = 0; i < 4; i++) //发送4个0,协议规定的spi_write_byte(0);if (cmd == 0)spi_write_byte(0x95); //如果是CMD0,则要发送CRC校正else spi_write_byte(0xff); //非CMD0,则无需CRC校正,默认为0xFF}else{for(i = 0; i < 4; i++) //将32位的地址分割成4个字节,准备发送temp[i]=(char)(addr >> (24 - 8 * i));spi_write_byte((cmd & 0x3F) | 0x40); //命令最高两位必须是01for(i =0; i < 4; i++)spi_write_byte(temp[i]); //发送地址,共4个字节spi_write_byte(0xff); //非CMD0,则无需CRC校正,默认为0xFF}}/********************************************功能:获取SD卡的答应字节,可能是一个或者两个字节输入:type为答应类型输出:答应字节,个数有答应类型而定********************************************/U16 Get_rsp(U8 type){U16 rsp, temp;spi_ro_mode(); //spi只读模式send_clk(); //先发送8个clkrsp = spi_read_byte(); //用spi读取答应字节if (rsp & 0x8)rsp = spi_read_byte();if (type == R2) //如果是R2类型,则答应为两个字节,须再次读取{temp = rsp << 8;rsp = spi_read_byte();rsp = temp | rsp;}return rsp;}/********************************************功能:读取SD的一个block的内容,一般为512字节输入:buffer为数据缓存区头地址输出:无********************************************/void read_data(U8 *buffer){U32 i;U8 rsp = 0;while(!(rsp == 0xfe)) //答应字节的最低为0则代表起始位rsp = spi_read_byte();for(i = 0;i < BLOCK_LEN; i++) //读一个block的内容,一般为512字节buffer[i] = spi_read_byte();for(i = 0; i < 2; i++) //读两个CRC校正码send_clk();send_clk(); //读结束字节}/********************************************功能:写入SD的一个block的内容,一般为512字节输入:buffer为数据缓存区头地址输出:********************************************/U8 write_data(U8 *buffer){U16 rsp = 0, tmp = 0, busy = 0, i = 6;spi_rt_mode();spi_write_byte(0xfe); //起始位for(i = 0; i < 512; i++) //发送512个字节spi_write_byte(buffer[i]);for(i = 0; i < 2; i++) //发送16位的CRC校正spi_write_byte(0xff);spi_ro_mode(); //等待答应while(!(rsp == 0x1)){rsp =(U16)spi_read_byte();tmp = rsp;rsp &= 0x11;}while(!(busy == 0xff)) //判忙{busy = spi_read_byte();}tmp &= 0xe;if (tmp == 4)return NO_ERR;else{Uart_Printf("writing error!!!\n");return WR_SGL_BLK_ERR;}}/********************************************功能:输入:输出:********************************************/U8 read_register(U8 len, U8 *buffer){U8 rsp = 0xff, i = 0;spi_ro_mode();while((rsp == 0xff) && (i < 100)){rsp=spi_read_byte();}if (i > 99){Uart_Printf("ERR in readding register!!!\n");return rsp;}if (rsp != 0xfe){buffer[0] = rsp;i = 1;}elsei = 0;for( ; i < len; i++)buffer[i] = spi_read_byte();for(i = 0; i < 2; i++ )send_clk();send_clk();return NO_ERR;}/*******************************************************************文件名:sd_hard.c作用:硬件层函数,移植时需根据处理器或者硬件结构的不同,对该文件的函数进行修改********************************************************************//********************************************功能:使能SPI,发送CLK输入:无输出:无********************************************/void send_clk(){rSIOCON |= (1 << 3); //使能SPIwhile (!(rINTPND & BIT_SIO)); //等待发送完毕rI_ISPC|=BIT_SIO; //清除中断标志}/********************************************功能:用SPI发送一个字节输入:dat为要发送的字节输出:无********************************************/void spi_write_byte(U8 dat){rSIODAT = dat;send_clk(); //SPI发送}/********************************************功能:用SPI读取外设一个字节输入:无输出:读到的一个字节********************************************/U8 spi_read_byte(void){send_clk(); //SPI发送return rSIODAT;}/********************************************功能:初始化SPI的端口输入:无输出:无********************************************/void spi_port_init(){rIVTCNT = 0;rPCONF = (rPCONF & 0xe3ff) | 0x1B0C00; //除了CLK,MISO,MOSI外,不改变其他位rPUPF |= 0x160; //使能MISO的上拉电阻}/***************************************************************文件名:sd_config.h作用:相关功能的宏定义,以便被以上三个文件调用,便于移植移植时需修改***************************************************************/#ifndef _SD_CONG#define _SD_CONG#define BLOCK_LEN (512) //一个block的长度#define CMD0 0#define CMD1 1 // 读OCR寄存器#define CMD9 9 // 读CSD寄存器#define CMD10 10 // 读CID寄存器#define CMD12 12 // 停止读多块时的数据传输#define CMD13 13 // 读Card_Status 寄存器#define CMD16 16 // 设置块的长度#define CMD17 17 // 读单块#define CMD18 18 // 读多块,直至主机发送CMD12#define CMD24 24 // 写单块#define CMD25 25 // 写多块#define CMD27 27 // 写CSD寄存器#define CMD28 28 // Set the write protection bit of the addressed group#define CMD29 29 // Clear the write protection bit of the addressed group#define CMD30 30 // Ask the card for the status of the write protection bits#define CMD32 32 // 设置擦除块的起始地址#define CMD33 33 // 设置擦除块的终止地址#define CMD38 38 //擦除所选择的块#define CMD42 42 // 设置/复位密码或上锁/解锁卡#define CMD55 55 // 禁止下一个命令为应用命令#define CMD56 56 // 应用命令的通用I/O#define CMD58 58 // 读OCR寄存器#define CMD59 59 // 使能或禁止//错误返回#define INIT_FAIL 0#define NO_ERR 1#define WR_SGL_BLK_ERR 2#define GET_INFO_ERR 3#define R1 1 //SD卡答应类型,表示一个字节#define R2 2 //SD卡答应类型,表示两个字节//一下是移植时需修改的内容#define SD_desel() rPDATE=0x20; //使能SD卡#define SD_sel() rPDATE=0x00; //放开SD卡#define spi_high_speed() rSBRDR = 5; //spi高速模式#define spi_low_speed() rSBRDR = 99; //spi低速模式#define spi_ro_mode() rSIOCON = (0x0 << 7) | (0x0 << 6) | (0x0 << 5) | (0x0 << 4) | (0x0 << 3) | (0x0 << 2) | 0x1 //只读模式#define spi_rt_mode() rSIOCON = (0x0 << 7) | (0x0 << 6) | (0x1 << 5) | (0x0 << 4) | (0x0 << 3) | (0x0 << 2) | 0x1 //读写模式#endif。

如何解决sd卡无文件系统或文件系统不受支持问题

如何解决sd卡无文件系统或文件系统不受支持问题

如何解决sd卡无文件系统或文件系统不受支持问题我们想管理sd卡,却显示sd卡无文件系统或文件系统不受支持,怎么回事呢?似乎是sd卡损坏了,下面是店铺收集整理的sd卡无文件系统或文件系统不受支持如何解决,希望对大家有帮助~~sd卡无文件系统或文件系统不受支持的解决办法如果是用在手机上的内存卡突然出现这种错误,你可以试试关机稍等一些再开机。

如果这样OK了,则有可能是你的卡没有插好,此问题将卡插好即可;也有的是CPU问题或新安装的软件或优化导致,这些问题导致的你可以通过刷系统来解决;如果在手机或相机上可以检测到但无法使用的,可以通过手机或相机来格式化,如我的松下ZS10相机用的原产东芝8G卡就有这问题用相机格式化后就再也没有问题了;如若不行,可以将SD卡插在别的手机上或电脑读卡器上试试,在电脑上格式化下;有时某些病毒也会造成这问题,你可以在电脑安全模式或WINPE 下对卡进行格式化操作;如果手机和电脑都不能识别该卡,或者都不能对该卡进行格式化,就可以确定是卡损坏了;卡损坏也并非完全没有修复的可能,通过一些u盘修复软件来进行尝试修复,建议先用diskgenius修复处理;相关阅读:TF存储卡常见的12种故障及解决方法【问题一】:将内存卡插在电脑上,内存卡无法识别的问题。

这种情况往往是因为内存卡在电脑上进行格式化,但是格式化与手机不兼容造成的。

解决方法:把卡放回手机,用手机中的格式化存储卡功能重新格式化一遍即可。

【问题二】:手机插上内存卡不能打开网页,拔掉却可以。

解决方法:无法打开网页,或者网络无反映都有可能是因为第三方输入法引起的,切换回原来的输入法,问题就解决了。

【问题三】:手机提示“拔出内存卡请按确定"按照提示将卡拔出来,一会再插入手机就可以继续使用,但是过不了多久又再一次提示拔卡,如此反复。

出现此种情况的原因是经常插拔内存卡导致手机存储卡槽松动接触不良所致。

解决方法:可以考虑去客服检修一下手机,并且注意以后热插拔卡时不要用力过猛或者只用手机读取而不要插拔内存卡。

C8051F020中Flash存储器的在线擦写方法

C8051F020中Flash存储器的在线擦写方法
用软件对 F l a s h 编程的过程中应该注意如下几点 Flash 存储器用 MOVC A, @A+DPTR 指令读取 Flash 存储器用 MOVX @DPTR, A 指令写入 Flash 页以 512 字节分界 0200h, 0400h, 依此类推 Flash 写操作只能写入 0 因此在写一个 Flash 字
须是 C O D E 类型 下面是将 F l a s h 存储器中的数据拷贝
到存放于内部 R A M 的数组 a [ t ] 中的样例程序
void Flash_READ void
{ unsigned char code *pread;
/*程序存储器空间的指针
Flash 指向待读地址 */
pread=0x1000;
调用这些函数时的参数为 f r o m 表示所申请 I / O 端 口的起始地址 extent 为所要申请的从 from 开始的端口 数 name 为设备名 将会出现在 /proc/ioports 文件里 check_region 返回 0 表示 I/O 端口空闲 否则为正在被使 用 在申请了 I / O 端口之后 就可以用如下几个函数来
PSCTL=0X01;
/*禁止对Flash的擦除*/
pgen=&a[0];
/*将数组值写入Flash中*/
for(i=0;i<t;i++) { *pwrite++=*pgen++; } FLSCL=0X00; PSCTL=0X00; EA=1; }
/*禁止对Flash的写操作*/ /*开中断*/
EXPERIENCE EXCHANGE 经 验 交 流
C8051F020 中 Flash 存储器的在线擦写方法
哈尔滨工程大学 韩红芳 பைடு நூலகம்孙守昌

SD卡读写学习-----使用文档

SD卡读写学习-----使用文档

SD 卡读写学习使用文档一、 概述SD 卡是基于 flash 的存储卡,其和 MMC 卡的区别在于初始化过程不同。

SD 卡的通信协议包括 SD 和 SPI 两类。

SD 卡使用卡内智能控制模块进行 FLASH 操作控制,包括协议、安全算法、数据存取、 ECC 算法、缺陷处理和分析、电源管理、时钟管理。

二、SD 卡读写操作读操作的块长度受设备 sector 大小 (512 bytes)的限制,但是可以最小为一个字节。

51单片机读写SD 卡一般使用SD 卡的SPI 模式 0、CMD 命令格式:First Byte Byte 2-5 Last Byte 参数:4Byte---32bit ,指向要写入的字节地址,所以限制了SD 卡可以最大写入4g 数据bit7 bit6 bit5~0 Databit7~1 bit0 01命令参数(高位在前)CRC 校验1示例: CMD0号命令,CMD24(0x40+24=0x58)号命令时,参数为要写入的地址。

固定 CMD0命令 参数(2-5) CRC 校验 固定01 | 00 0000 | 0000 0000 ........ 0000 | 1001 010 | 1 0x40, 0x00,0x00,0x00,0x00, 0x95 adr<<=9;//取512的整数倍,因一个扇区为512字节。

CMD[1]=(addr>>24); CMD[2]=(addr>>16); CMD[3]=(addr>>8); CMD[4]=(addr>>0); $、SPI 模式:SD 卡启动时处在SD 总线模式下,要进入SPI 模式时,要遵守如下操作。

SD 卡复位及初始化时,时钟频率一定要慢下来,最高不超过400KHZ 。

1)SD 卡复位复位SD 卡:a 、所有引脚拉高,片选CS 为1时,首先往SD 卡写入至少74个时钟信号。

(SD 卡协议规定)b 、片选CS 拉低为0,写入CMD0命令(0x40,0x00,0x00,0x00,0x00,0x95)c 、读取SD 卡MISO 返回数据直到SD 卡返回0x01。

单片机读写SD卡教程

单片机读写SD卡教程

重声明:本实验并不是对所有SD卡都能成功运行第一步:翻开winhe*软件,用读卡器读SD卡,在winhe*中查看SD卡点击查找〔ctrl+F〕Array输入FAT〔找到DBR处〕发现DBR起始于0*11200扇区地址,它必是512所以在程序中读一个扇区时一定要是5120*EB,本程序读一下这个地址的值看看是否正确。

注意有的看看程序吧*include <reg52.h>*define uchar unsigned char*define uint unsigned int//=============================================================//定义SD卡需要的4根信号线sbit SD_CLK = P1^1;sbit SD_DI = P1^2;sbit SD_DO = P1^0;sbit SD_CS = P1^3;sbit Beep=P2^0;//用来调程序标志//===========================================================//===========================================================//定义512字节缓冲区,,89C52直接定义成unsigned char DATA[80];,太大了RAM不够unsigned char *data DATA[512];void delay(unsigned int z){unsigned int *,y;for(*=z;*>0;*--);for(y=110;y>0;y--);}//===========================================================//写一字节到SD卡,模拟SPI总线方式void SdWrite(unsigned char n){unsigned char i;for(i=8;i;i--){SD_CLK=0;SD_DI=(n&0*80);n<<=1;SD_CLK=1;}SD_DI=1;}//===========================================================//从SD卡读一字节,模拟SPI总线方式unsigned char SdRead(){unsigned char n,i;for(i=8;i;i--){SD_CLK=1;SD_CLK=0;n<<=1;if(SD_DO) n|=1;}return n;}//============================================================//检测SD卡的响应unsigned char SdResponse(){uchar i=0,response=0;while(i<=8){response = SdRead();if(response==0*00)break;if(response==0*01)break;i++;}return response;}//=============================================================== =//发命令到SD卡void Sdmand(unsigned char mand, unsigned long argument, unsigned char CRC) {SdWrite(mand|0*40);/*SdWrite(((unsigned char *)&argument)[0]);SdWrite(((unsigned char *)&argument)[1]);SdWrite(((unsigned char *)&argument)[2]);SdWrite(((unsigned char *)&argument)[3]);*/SdWrite(argument>>24);SdWrite(argument>>16);SdWrite(argument>>8);SdWrite(argument);SdWrite(CRC);}//=============================================================== =//初始化SD卡unsigned char SdInit(void){unsigned char i;unsigned char response=0*FF;P3=0*ff;SD_CS=1;for(i=0;i<=0*fe;i++)SdWrite(0*ff);SD_CS=0;Sdmand(0*00,0,0*95);SD_DI=1;response=SdResponse();if(response!=0*01){return 0;}if(response==0*01){ //不管什么SD卡都能进入这一步,同时也说明硬件没问题SD_CS=1;//Beep=0;//while(1);//用来查看程序能否运行到这一步,去掉//即可SdWrite(0*ff);SD_CS=0;while(1){Sdmand(0*01,0,0*ff);//Sdmand(0*01,0*00000000,0*ff);//进SPIresponse=0*ff;SD_DI=1;for(i=0;i<250;i++)//response!=0*00//等待回复{response=SdResponse(); //Beep=0;/if(response==0) break;}if(response==0) {break;}//回复0则通过SPI,只要通过SPI后面的指令才能继//续// Beep=0;}// Beep=0;//看程序能否跳出来,挑不出来则进不了SPISD_CS=1;SdWrite(0*ff);SD_CS=0;// Beep=0;return 1;}}//=============================================================== =//往SD卡指定地址写数据,一次最多512字节最好不要乱写否则fat系统被改掉SD卡打不开unsigned char SdWriteBlock(unsigned char *Block, unsigned long address,int len){unsigned int count;unsigned char dataResp;SD_CS=0;Sdmand(0*18,address,0*ff);if(SdResponse()==00){SdWrite(0*ff);SdWrite(0*ff);SdWrite(0*ff);//mand was a success - now send data//start with DATA TOKEN = 0*FESdWrite(0*fe);//now send datafor(count=0;count<len;count++) SdWrite(*Block++);for(;count<512;count++) SdWrite(0);//data block sent - now send checksumSdWrite(0*ff); //两字节CRC校验, 为0*FFFF 表示不考虑CRCSdWrite(0*ff);//Now read in the DATA RESPONSE tokendataResp=SdRead();while(SdRead()==0);dataResp=dataResp&0*0f; //mask the high byte of the DATA RESPONSE token SD_CS=1;SdWrite(0*ff);if(dataResp==0*0b){return 0;}if(dataResp==0*05)return 1;return 0;}//printf("mand 0*18 (Write) was not received by the SD.\n");return 0;}//=============================================================== ========//从SD卡指定地址读取数据,一次最多512字节unsigned char SdReadBlock(unsigned char *Block, unsigned long address,int len) {unsigned int count,i;uchar response;SD_CS=0;// while(1)// {Sdmand(0*11,address,0*ff);// SD_DO=1;// P0=SdResponse();// P0=0*ff;// while(1);while(response!=0*fe && i<200) {response=SdRead();P0=response;i++;} // if(i>=200) Beep=0;// P0=0*f0;// }// Beep=0;for(count=0;count<512;count++) *Block++=SdRead();SdRead();SdRead();//Now read in the DATA RESPONSE tokenSD_CS=1;SdWrite(0*ff);return 1;}void main(){unsigned int mm;unsigned long AddTemp=0*11200;//70144;//SD卡地址第一个数据物理地址初始值70144是通过winhe*查看,对于你的SD卡肯定要改//可以用winhe*查看,一定要是512整数倍mm=SdInit();//SdReadBlock(DATA,AddTemp,1);delay(10);// Beep=0;if(DATA[0]==0*eb)Beep=0;// 看读的对不对while(1); }。

51平台通过SPI方式读写SD

一、总则本文件介绍了在51平台通过SPI方式读写SD/MMC卡,包括软硬件需求, SD/MMC硬件连接, SPI接口软件模拟,SD/MMC上电初始化,写单块,读单块,写多块,读多块,块擦除,上位串口通讯协议,PC上位软件操作说明等。

二、软硬件需求a) 单片机固件编译环境:Keil C51 uVision2b) PC上位软件编译环境:Visual C++ 6.0c) 硬件环境:1)W78E52B一片;2)SD/MMC卡插座一个;3)MAX232一片;4)cross串口线一条;三、SD/MMC硬件连接SD/MMC与51单片机引脚连接如下表1,供参考:51单片机引脚SD/MMC引脚P1_0SPI_CS (PIN1)P1_1SPI_SI(PIN2)P1_2SPI_SCK(PIN5)P1_3SPI_SO(PIN7)PIN4接VDDPIN3/6接GND表1 SD/MMC与51单片机引脚连接表注意:SD/MMC引脚除VDD(PIN4)/VSS(PIN3/6)外,其它引脚连接上拉电阻(47k)至3.3v 电源。

四、SPI接口软件模拟由于W78E52B没有集成硬件SPI接口,所以固件需要通过软件来模拟实现SPI接口;a) SPI接口基本原理:SPI采用HOST/SLAVE结构,HOST与SLA VE以字节为传输单位,支持4种模式;SPI接口定义有4个引脚CS,SI,SO,SCK;SD SPI接口工作于模式0,各引脚功能分别描述如下:1) CS为片选引脚,低电平为有效;2) SI为Host输出Slave输入引脚,空闲为高电平,SCK上升有效,;3) SO为Slave输出Host输入引脚,SCK下降有效;4) SCK为同步时钟;b) SPI HAL:包括4个函数,上层软件通过调用这4个函数,来实现与SD/MMC以SPI方式进行数据交换。

1) SPI_SendByte(INT8U onebyte)――以SPI方式向SD/MMC发送一个字节2) INT8U SPI_RecByte(void)――以SPI方式从SD/MMC接收一个字节3) SPI_CS_Assert(void)――将CS引脚置为低电平有效4) SPI_CS_Deassert(void)――将CS引脚置为高电平无效c) 通过SPI HAL发送的RESET命令CMD0波形图,如下图1,以供参考:图1-RESET命令CMD0波形图一、SD/MMC上电初始化当SD/MMC卡上电后,单片机需要对其进行上电初始化,上电初始化步骤顺序所列如下:1) 置CS为低,至少延时74个CLK,延时波形图,如图2,以供参考:图2-延时波形图1) 发送RESET命令CMD0,其波形图参考图1:2) 发送命令CMD1(SD卡使用命令ACMD41)激活SD/MMC卡, 固件需重复发送命令CMD1直到R1 idle state位为0。

51读写SD卡

一、SD卡的检测:插入时6脚CSS2与中端口相连,同时6脚在卡内部又与3脚地相连,这样利用6脚的低电平触发中断来检测SD卡的插入;SD卡的引脚说明:CLK:空闲时保持高电平;SD卡上电后,默认是关闭的;二、初始化:SPI的时钟不能太快。

刚开始先发送至少74个时钟信号,这是必须的,随后写命令CMD0和CMD1,使SD卡进入SPI模式。

详见附件:《SD卡初始化》i.SD卡和MMC卡:上电后,卡出于IDLE状态,主机用CMD0 复位卡,用CMD55和ACMD 41判别当前电压是否在工作范围内。

因为MMC卡不能正确识别CMD55,所以,通过判别此命令的响应正确与否,来侦知是SD卡还是MMC卡。

ii.SD模式和SPI模式选择:SD卡在上电初期,通过检测引脚1(DAT3)来决定。

如果此脚外界上拉电阻(50k)为高电平,则进入SD模式;此脚接地为低电平,进入SPI模式。

三、命令时序i.高位先发一般情况下降沿发送数据上升沿读取数据ii.发送命令:1.命令字;1字节0x40+命令序号;2.命令参数:4字节地址数:基本单位512;3.响应:R1和R1B(1字节(CRC7+1))R2(2字节)或R3(5字节)4.大部分命令的响应是1个字节,读取状态寄存器响应R2,读取OCR响应R3;四、数据传送:读写以512字节为基本单位;i.读数据:1.MCU发送“读”命令;2.SD卡回应:0x00;3.SD发送起始字节:0xFE;4.SD发送连续的512字节数据;5.SD发送2字节的CRC(任意,但最后一位要是1);ii.写数据:1.MCU发送“写”命令;2.SD卡回应:0x00;3.MCU发送起始字节:0xFE;4.MCU发送连续的512字节数据;5.MCU发送2字节的CRC校验码;6.SD卡发送5位的回应数据:xxx0 0101B (0x05)。

五、擦除操作可以加速写操作,因为在写之前会进行擦除。

六、SD卡的六个寄存器:七、SD卡的命令序号:i.Calss0 :1.CMD0 复位SD卡2.CMD1 读OCR3.CMD9 读CSD4.CMD10 读CID5.CMD12 停止读多块数据传输6.CMD13 读Card_Status 寄存器ii.Calss 21.CMD16 设置块的长度不设的话默认长度512 设的话:4字节所表示的数;2.CMD17 读单块3.CMD18 读多块直到发送CMD12iii.Calss 41.CMD 24 写单块2.CMD 25 写多块iv.Calss 5 擦除卡1.CMD 32 设擦除块的起始地址2.CMD 33 设擦除块的终止地址3.CMD 38 擦除所选块//实验目的:学习SD卡的操作//软件设计// 1、SD卡采用SPI通信// 2、先往SD里顺序写入0-255共256个数据,然后再读回送LCD1602显示//硬件要求:// 拨码开关S11置ON// 跳线J18全部接通#include <p30f6014.h> //dsPIC30F6014标准头文件_FOSC(CSW_FSCM_OFF & XT_PLL4); //4倍频晶振,Failsafe 时钟关闭_FWDT(WDT_OFF); //关闭看门狗定时器_FBORPOR(PBOR_OFF & MCLR_EN); //掉电复位禁止,MCLR复位使能。

用51单片机读写SD卡


引脚号 1 2 3 4 5 6 7 8 9
图 1 SD 卡外形 表 1 SD 卡引脚功能
名称
功能 (SD 模式) 功能 (SPI 模式)
DAT3/CS
数据线 3
片选/从选 (SS)
CMD/DI
命令线
主出从入 (MOSI)
VSS1 VDD CLK VSS2 DAT0/DO DAT1/IRQ DAT2/NC
DAT2 / NC DAT3 / CS CMD / DI VSS1 VDD CLK / SCK VSS2 DAT0 / DO DAT1 / IRQ
图2
3 软件实现
软件部分 主 要 实 现 底 层 SPI 通 信 , SD 卡 的 复 位 , SD 卡 的 初始化、 以及 SD 卡的通用写命令和单块数据的读写等功能。
3.1 底层 SPI 通信函数
//======================================= //写一字节到 SD 卡,模拟 SPI 总线方式 void SD_spi_write(unsigned char n) {
unsigned char i;
for(i=0;i<8;i++) { SD_CLK=0; if(is_init) delay(DELAY_TIME); SD_DI=(n&0x80)>>7; SD_CLK=1; if(is_init) delay(DELAY_TIME);
在 SPI 模式中, 命令都是以如表 2 的 6 字节形式发送的。 表2
第一字节
第 2-5 字节
第 6 字节
0
1
命令号
参数
CRC 校验 1
每帧命令都以 “01” 开头, 然后是 6 位命令号和 4 字节的 参 数 (高 位 在 前 , 低 位 在 后), 最 后 是 7 位 CRC 校 验 和 1 位 停 止位 “1”。

SDMMC卡初始化及读写流程

二、MMC/SD卡的模型和工作原理PIN脚、SD卡总线、SD卡结构、SD卡寄存器、上电过程SD卡寄存器:OCR:操作电压寄存器: 只读,32位第31位:表示卡上电的状态位CID: 卡身份识别寄存器只读128位生产厂商、产品ID,生产日期和串号等CSD:部分可写128位卡的容量、擦出扇区大小、读写最大数据块的大小、读操作的电流、电压等等 CSR: 卡配置寄存器64位数据位宽RCA:16位相关的卡地址寄存器,卡识别过程中主控器和卡协商出来的一个地址三、SD卡命令和响应格式命令和相应格式SD卡命令,命令类型,ACMD命令响应类型、卡类型、卡状态转换表命令的格式:48位起始位0 方向位(host to card: 1, card to host: 0)内容CRC7 结束位1·响应的格式:48位或者136位卡命令:命令的类型:bc: broadcast without Response 无响应的广播bcr: broadcast with Response 有响应的广播ac: Address(point-to-point) Command: 点对点,DATA0~DATA3数据线上无数据adtc: Adress(point-to-point) Data Transfer Commands 点对点,DATA0~DATA3数据线上有数据CMD0, CMD2, CMD3, CMD55, ACMD41 命令可能会导致卡的状态发生变化响应类型:R1,R1b, R2, R3,R6(SD2.0扩展了R7)扩展内容:SPI工作模式:要知道的特点:只支持一个卡,没有RCA,命令只是MMC/SD的基本的子集SDHC:(支持2GB~32GB):理解CMD8的作用,命令格式和响应,了解CSDV2.0寄存器做了扩展SDIO WIFI:增加CMD52,CMD53CMD8可以通过重新定义先前保留的位,来扩展一些已经存在的命令的新功能。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

QQ群欢迎你加入164238254 我们一起进步
#include<C8051F020.h>
#define TRY_TIME 800 //向SD卡写入命令之后,读取SD卡的回应次数,即读TRY_TIME //SD卡同步时钟输入P0^0//SD卡同步数据输入p0^2
sbit SD_CS=P0^4;//SD卡片选//SD卡同步数据输出P0^1
typedef unsigned char uchar;
typedef unsigned int uint;
unsigned long laddr;
unsigned char SD_Reset();
unsigned char SD_Init();
unsigned char SD_Read_Sector(unsigned long addr);
unsigned char pbuf[10]; //数据缓冲区
unsigned char pbu[10];
uchar k;
void delay(unsigned int time)
{
while(time--);
}
void spi_cfg(uchar spicfg,uchar spickr,uchar spicn)
{SPI0CFG=spicfg;
SPI0CKR=spickr;
SPI0CN=spicn;
P0=0xff;
SPIEN=1;
}
void inti(void)
{WDTCN=0xde;
WDTCN=0xad;
XBR0=0x02;
XBR1=0x00;
XBR2=0x40;
OSCICN=0x17;
P0MDOUT=0x1f;
P1MDOUT=0xff;
}
void SD_spi_write(unsigned char x)
{
SPIF=0;
SPI0DA T=x;
while(TXBSY);
//P1=0x00;
}
unsigned char SD_spi_read() //SPI读一个字节
{SD_CS=1;
SPI0DA T=0x00;
SD_CS=0;
// SPIF=0;
k=SPI0DA T;
// P1=k;
//while(==0);
return k;
}
/******************************************************************
- 功能描述:向SD卡写命令
- 隶属模块:SD卡模块
- 函数属性:内部
- 参数说明:SD卡的命令是6个字节,pcmd是指向命令字节序列的指针
- 返回说明:命令写入后,SD卡的回应值,调用不成功,将返回0xff
******************************************************************/
unsigned char SD_Write_Cmd(unsigned char *pcmd) //向SD卡写命令,pcmd是命令字节序列的首地址
{
unsigned int temp,tim,i;
tim=0;
SD_CS=1;
for(i=0;i<10;i++) SD_spi_write(0xFF); //提高兼容性,如果没有这里,有些SD卡可能不支持
SD_CS=0;
SD_spi_write(pcmd[0]);
SD_spi_write(pcmd[1]);
SD_spi_write(pcmd[2]);
SD_spi_write(pcmd[3]);
SD_spi_write(pcmd[4]);
SD_spi_write(pcmd[5]);
do
{
temp = SD_spi_read();//一直读,直到读到的不是0xff或超时
tim++;
//P1=temp;
}while((temp==0xff)&&(tim<2000));
//P1=0x42;
return(temp);
}
/******************************************************************
- 功能描述:初始化SD卡,使用CMD1
- 隶属模块:SD卡模块
- 函数属性:外部,供用户调用
- 参数说明:无
- 返回说明:调用成功,返回0x00,否则返回INIT_CMD1_ERROR (sd.h中有定义)
******************************************************************/
unsigned char SD_Init() //初始化,使用CMD1(命令1)
{
unsigned char temp;
unsigned char pcmd[] = {0x41,0x00,0x00,0x00,0x00,0xff}; //命令1的字节序列
SD_CS=0; //打开片选
temp=SD_Write_Cmd(pcmd);
SD_CS=1; //关闭片选
SD_spi_write(0xff); //按照SD卡的操作时序在这里补8个时钟
return(temp); //返回0,说明初始化操作成功
}
/**************************************************************************** - 功能描述:读取addr扇区的512个字节到buffer指向的数据缓冲区
- 隶属模块:SD卡模块
- 函数属性:外部,供用户调用
- 参数说明:addr:扇区地址
buffer:指向数据缓冲区的指针
- 返回说明:调用成功,返回0x00,否则返回READ_BLOCK_ERROR (sd.h中有定义)
- 注:SD卡初始化成功后,读写扇区时,尽量将SPI速度提上来,提高效率
****************************************************************************/
unsigned char SD_Read_Sector(unsigned long addr)//从SD卡的指定扇区中读出512个字节,使用CMD17(17号命令)
{unsigned char temp;
unsigned char pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff}; //CMD17的字节序列
addr<<=9; //addr=addr*512 将块地址(扇区地址)转为字节地址
pcmd[1]=((addr&0xff000000)>>24);//将字节地址写入到CMD17字节序列中
pcmd[2]=((addr&0x00FF0000)>>16);
pcmd[3]=((addr&0x0000FF00)>>8);
SD_CS=0;//打开片选
temp=SD_Write_Cmd(pcmd); //写入CMD17
return (temp);
}
unsigned char SD_Reset()//SD卡复位,进入SPI模式,使用CMD0(命令0)
{
unsigned char temp,i;
unsigned char pcmd[] = {0x40,0x00,0x00,0x00,0x00,0x95}; //命令0的字节序列
SD_CS=1; //关闭片选
for(i=0;i<0x0f;i++) //复位时,首先要发送最少74个时钟信号,这是必须的!!!
{
SD_spi_write(0xff);//120个时钟
}
SD_CS=0; //打开片选
temp=SD_Write_Cmd(pcmd);//写入CMD0
SD_CS=1; //关闭片选
//按照SD卡的操作时序在这里补8个时钟
return (temp);//返回0,说明复位操作成功
}
void main()
{unsigned char t;
unsigned int j,s;
laddr=1892;
inti();
spi_cfg(0xc7,0x41,0x02);
// P1=0xf1;
t=0x00;
while(t!=0x01)
{t=SD_Reset();
}
SD_spi_write(0xff);
while(t!=0x00)
{t=SD_Init();}
t=0xff;
while(t!=0x00)
{t=SD_Read_Sector(laddr);}//从SD卡的第ADDR扇区中读取512个字节的数据到数据缓冲区
while (t!=0xfe){t=SD_spi_read(); //一直读,当读到0xfe时,说明后面的是512字节的数据了
}
for(j=0;j<10;j++) //将数据写入到数据缓冲区中
{
pbuf[j]=SD_spi_read();
}
for(j=0;j<10;j++) //将数据写入到数据缓冲区中
{
pbu[j]=pbuf[j];
}
SD_spi_read();
SD_spi_read();//读取两个字节的CRC校验码,不用关心它们SD_CS=1; //SD卡关闭片选
SD_spi_write(0xff);//按照SD卡的操作时序在这里补8个时钟while(1);
}。

相关文档
最新文档