读写SD卡的设计及其程序硬件

合集下载

SD卡读写程序

SD卡读写程序

SD卡读写程序SD卡读写程序//实验目的:学习SD卡的操作//软件设计// 1、SD卡采用SPI通信// 2、先往SD里顺序写入0-255共256个数据,然后再读回送LCD1602显示//硬件要求:// 拨码开关S11置ON// 跳线J18全部接通#include //dsPIC30F6014标准头文件_FOSC(CSW_FSCM_OFF & XT_PLL4); //4倍频晶振,Failsafe 时钟关闭_FWDT(WDT_OFF); //关闭看门狗定时器_FBORPOR(PBOR_OFF & MCLR_EN); //掉电复位禁止,MCLR 复位使能。

_FGS(CODE_PROT_OFF); //代码保护禁止#define cs PORTGbits.RG9 //定义SD卡片选脚#define rs /doc/e62205906.html,TB4 //定义LCD控制位(注意这里只能用LATB寄存器,不能直接用PORTB 寄存器)#define rw /doc/e62205906.html,TB5 #define e /doc/e62205906.html,TB6unsigned char __attribute__((address(0x900))) lcd[3]={0,0,0};void spi_init(); //申明系统初始函数void spi_low(); //申明产生低波特率函数(SD卡初始化使用)void spi_high(); //申明产生高波特率函数(SD卡初始化后使用)unsigned char sd_reset(); //申明SD卡初始化函数unsigned char SD_SendCommand(unsigned char cmd,unsigned long arg); //申明写SD卡命令函数unsigned char SPI_WriteByte(unsigned char val); //申明写一字节函数unsigned char SPI_ReadByte(void); //申明接收一字节函数unsigned char SD_WriteSingleBlock(unsigned long sector); //申明写SD卡单BLOCK数据函数unsigned char SD_ReadSingleBlock(unsigned long sector); //申明读SD卡单BLOCK数据函数void lcd_display(); //申明结果显示函数void delay(); //申明延时函数(显示时用)//系统初始化函数void spi_init(){TRISG="0x00d0"; //设置SDI为输出,其他C口为输出TRISB="0X0000"; //设置B口为输出TRISD="0X0000"; //设置D口为输出SPI2CON=0x0278; //空闲时总线为高电平,fosc/64SPI2STAT=0x8000; // 输出数据的末尾采样输入数据,上升沿发送数据}//*************************写LCD程序****************************************//写一个字节数据函数//在电平发生改变后需要插入一段延时时间,否则LCD反应不过来。

单片机读写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卡读写器制作

摘要随着嵌入式处理器计算机能力的不断提高,32 位MPU 已成为嵌入式系统应用的主流。

在ARM9 嵌入式处理器和mC/OS-II操作系统基础上采用SD 卡设计开发了一种嵌入式文件系统,该系统具有支持多操作系统、易于移植和存储速度快的特点。

本文在三星ARM9-S3C2440上实现了MMC /SD卡的硬件扩展, 设计了此硬件平台上的MMC /SD卡在L inux下的驱动, 并给出了相应的关键代码。

关键词: 嵌入式Linux; MMC /SD卡; Linux设备驱动; S3C2440目录1. 概述 (3)1.1 SD卡简介 (3)1.2 系统研究背景 (3)2. 方案论述 (4)2.1 SD卡工作原理 (4)2.1.1 SD 卡内部结构及引脚如下图所示 (4)2.1.2 SD卡指令数据包 (4)2.1.3 SD卡接口电路 (5)3. 芯片选择 (6)3.1 S3C2440的简介 (6)3.2 硬件资源 (6)3.3物理特性 (6)3.4 核心板展示 (7)4. 总体框图 (7)6.1 源程序代码 (9)6.2 读SD卡流程图 (10)6.3 写SD卡流程图 (11)总结 (12)参考文献 (13)附录1:SD卡命令表 (14)附录2:源代码清单 (16)附录3:原理图 (28)附录4:PCB图 (31)1.概述1.1 SD卡简介●SD卡是基于flash的存储卡。

SD卡和MMC卡的区别在于初始化过程不同。

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

●SD卡使用卡内智能控制模块进行FLASH操作控制,包括协议、安全算法、数据存取、ECC●算法、缺陷处理和分析、电源管理、时钟管理●SD卡(Secure Digital Memory Card)是一种为满足安全性、容量、性能和使用环境等各方面的需求而设计的一种新型存储器件,SD卡允许在两种模式下工作,即SD模式和SPI模式。

1.2 系统研究背景本设计旨在深入对ARM的学习,巩固大学四年所学专业知识,提升动手能力和思考问题解决问题的能力。

SD卡读写程序设计(一)

SD卡读写程序设计(一)

SD卡读写程序设计(一)一、概述在智林STM32开发板上有采用SPI方式的SD卡接口,我手上有一块512M的SD卡,所以接下来就开始SD卡的读写程序设计,学习完了,就可以开始文件系统的移植学习了#####。

二、程序框架设计1、在shell里增加两个命令:sdwr,和sdrd。

2、sdwr在SD卡设定的扇区写入输入数据。

Sdrd是将刚刚写入的数据读出来。

3、sdwr命令输入后,内部执行uartcmdsdwrite()函数。

调用SD_WriteBlock ()函数,将缓冲字符数组写入。

而sdrd命令执行UartCmdSDRead()函数,调用SD_ReadBlock()函数,读入一个扇区,并用十六进制的方式在串口中断上显示。

4、SD的驱动分为三层:应用层、命令层、和驱动层。

分别用sddrive.c,sdcmd.c,和spi.c三个文件来实现。

三、SPI接口的SD卡1、SPI接口SPI是一种全双工、同步串行通信方式接口,这里用到了四个IO口:分别是时钟线SCK、输出口MOSI、输入口MISO、模式从机选择线NSS。

2、SPI接口与SD卡STM32与采用SPI接口的SD卡,就像两个CPU通信一样,STM32处理器通过SPI接口发出命令,SD卡执行命令后返回相应的状态。

命令有读写命令、也有参数设置命令。

3、SD卡的内部结构:几个重要寄存器(1)OCR寄存器:保存着卡的供电允许范围,位31表示卡上电后的状态,1表示空闲。

(2)CSD寄存器:总共128位,表示了卡的大部分配置信息。

(3)状态寄存器:命令响应的状态。

4、常用的SPI模式命令(1)命令由六个字节组成:01-六位命令号-四个字节的命令参数-7位校验码-结束位1。

(2)命令分为10个类:SPI支持:类0基本控制的(0复位、1激活初始化、9读CSD寄存器、10读CID寄存器、12多块过程中停止传输、13读状态寄存器),类2块读的(16设置块长度、17读一个数据块、18读多个数据块,直到发命令12);类4块写的(24写块、25写多个块、27写CSD的可编程为);类5擦除的(32设置擦除块的起始地址、33设置终止块地址、38擦除先前选择的所有块);块6写保护的(可选28设置写保护、29清除写保护、30读写保护状态);类7的锁卡命令(可选42上锁或者解锁);类8的指定应用(55通知SD卡下个是特殊应用命令、56获取或写入一个数据块)。

[整理]SD卡程序设计、流程及操作系统.

[整理]SD卡程序设计、流程及操作系统.

对SD卡进行操作首先要对SD卡进行初始化,初始化的过程中设置SD卡工作在SPI模式,其流程图如图3所示。

在复位成功之后可以通过CMD55和ACMD41判断当前电压是否在工作范围内。

主机还可以继续通过CMD10读取SD卡的CID寄存器,通过CMD16设置数据Block长度,通过CMD9读取卡的CSD寄存器。

从CSD寄存器中,主机可获知卡容量,支持的命令集等重要参数。

SD卡初始化的C语言程序如下:unsigned char SD_Init(void){ unsigned char retry,temp;unsigned char i;for (i=0;i<0x0f;i++){ SPI_TransferByte(0xff); //延迟74个以上的时钟}SD_Enable(); //开片选SPI_TransferByte(SD_RESET); //发送复位命令SPI_TransferByte(0x00);SPI_TransferByte(0x00);SPI_TransferByte(0x00);SPI_TransferByte(0x00);SPI_TransferByte(0x95);SPI_TransferByte(0xff);SPI_TransferByte(0xff);retry=0;do{ temp="Write"_Command_SD(SD_INIT,0);//发送初始化命令retry++;if(retry==100) //重试100次{SD_Disable(); //关片选return(INIT_CMD1_ERROR);//如果重试100次失败返回错误号}}while(temp!=0);SD_Disable(); //关片选return(TRUE); //返回成功}数据块的读写完成SD卡的初始化之后即可进行它的读写操作。

SD卡的读写操作都是通过发送SD 卡命令完成的。

SD卡读写

SD卡读写

SD卡读写(1)系统硬件文件系统只是数据的组织格式的统称,不涉及到硬件,所以系统的硬件与上篇日志中相同,不作修改。

(2)文件系统结构和读写原理带有文件系统的SD卡的内部结构一般如下表:256MSD卡的文件系统结构文件系统结构说明扇区起始号占用扇区数 Partiton Boot Sector 分区记录扇区 0 1 Reserved Sectors 保留扇区 0 4 FAT1 文件分配表1 4 242 FAT2 文件分配表2 246 242 DIR(FDT) 文件根目录区 488 32 User Data 数据区 520 493560 SD卡的保留扇区中一般不要写入数据,否则可能破坏其文件系统结构,导致操作系统不能识别。

在FAT文件系统中,BPB(Bios ParameterBlock)是一个很重要的参数表,该表通常位于0扇区(保留扇区中的第一个扇区)中的12-36字节,它记录了分区中的一些重要数据如总扇区数、每扇区的字节数、每簇的扇区数、保留扇区数、FAT表占用扇区数等,我这里的256M的SD卡中的BPB表如下:名称占用字节数内容说明BPB_BytesPerSec 2 0x0200 扇区大小为512字节 BPB_SecPerChus 1 0x08 每簇有8个扇区 BPB_RsvdSecCnt 2 0x0004 有4个保留扇区 BPB_NumFATs 1 0x02 有2个FAT表BPB_RootEntCnt 2 0x0200 根目录中可有512个登记项 BPB_TotSec16 20x0000 为0表示总扇区数大于65536BPB_MediaType 1 0xF8 磁盘介质为硬盘 BPB_FATSize16 2 0x00F2 每个FAT表占242个扇区 BPB_SecPerTrk 2 0x3F 每个磁道有63个扇区 BPB_NumHeads 2 0x00FF 磁头数为255BPB_HiddSec 4 0x00000000 有0个隐藏扇区 BPB_TotSec32 4 0x00078A00 共有494080个扇区保留扇区之后是文件分配表,FAT16文件系统有两份文件分配表(FAT),FAT的大小可以在BPB中查到。

对SD卡的读写程序

对SD卡的读写程序

SD卡(Secure Digital Memory Card)中文翻译为安全数码卡,是一种基于半导体快闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如数码相机、个人数码助理(PDA)和多媒体播放器等。

SD卡由日本松下、东芝及美国SanDisk公司于1999年8月共同开发研制。

大小犹如一张邮票的SD记忆卡,重量只有2克,但却拥有高记忆容量、快速数据传输率、极大的移动灵活性以及很好的安全性。

贴程序:/*-------------------------------------1.本程序主要为了实现以下功能:1)通过对SPI方式对SD卡进行读与写2)简单的FAT操作3)对写入的数据进行打印2.编写日期:09.10.133.版本号:V1.04.作者:andyluo----------------------------------------*/#include<reg52.h> //添加头文件#define uchar unsigned char //宏定义数据类型#define uint unsigned int/*-------------------------------------与指示灯有关的IO--------------------------------------*/sbit power=P0^4;/*-------------------------------------与SD卡通信有关的IO---------------------------------------*/sbit SCL=P1^5;//时钟信号sbit CS=P1^6;//片选信号sbit SI=P1^7;//数据输入sbit SO=P3^3;//数据输出//错误码定义#define INIT_CMD0_ERROR 0X01#define INIT_CMD1_ERROR 0X02#define WRITE_BLOCK_ERROR 0X03#define READ_BLOCK_ERROR 0X04/*--------------------------------------与通信和定时器相关的变量---------------------------------------- */uchar cn=0;/*--------------------------------------变量定义-----------------------------------------*/uchar is_init;//用于控制SPI的速度,通过为1与0进行选择uchar xdata pbuf[512];//定义512个数据缓冲区/*--------------------------------------函数名称:delay()函数作用:用于某些程序中的延时函数特点:无返回值,带入口参数-----------------------------------------*/void delay(uint k){uint m,n;for(m=0;m<5;m++)for(n=0;n<k;n++);}/*-------------------------------SPI写一个字节----------------------------------*/void spi_write(uchar x)//SPI写一个字节,其中is_init为1 {uchar i;for(i=0;i<8;i++){SI=((x<<i)&0x80);SCL=0;if(is_init){delay(8);}SCL=1;if(is_init){delay(8);}}}/*--------------------------------SPI读一个字节----------------------------------*/uchar spi_read(){uchar temp=0,i;SO=1;for(i=0;i<8;i++){SCL=0;if(is_init){delay(8);}// if(SO)// {// temp+=(0x80>>i);// }temp=(temp<<1)+(uchar)SO;SCL=1;if(is_init)//放慢速度{delay(8);}}return(temp);}/*--------------------------------向SD卡写命令---------------------------------*/uchar write_cmd(uchar *pcmd)//pcmd为命令字{uchar temp,i,time=0;CS=1;spi_write(0XFF);CS=0;for(i=0;i<6;i++) //发送6个字节的命令字节序列{spi_write(*pcmd++);}spi_read();do{temp=spi_read();//一直读,直到读到的不是0XFF或者超时time++;}while((temp==0xff)&&(time<100));return temp;}/*------------------------------------SD卡复位,进入SPI模式,使用CMD0命令-------------------------------------*/uchar SD_Reset()//SD卡复位{uchar time,temp,i;uchar pcmd[]={0x40,0x00,0x00,0x00,0x00,0x95};//0号命令对应的6个字节is_init=1;//set is_init flagCS=1;for(i=0;i<0x0f;i++)//初始化时,首先要发送至少74个时钟信号,这是必须的{spi_write(0xff);//实质发了120个时钟(15*8)}CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==200){return(INIT_CMD0_ERROR );//cmd0写入失败}}while(temp!=0x01);CS=1;spi_write(0xff);//按照SD的操作时序在这里需要补8个时钟return 0;//返回0,说明SD卡复位操作成功}/*-------------------------------------SD卡初始化,使用CMD1号命令---------------------------------------*/uchar SD_Init()//SD卡初始化,使用CMD1号命令{uchar time,temp;uchar pcmd[]={0x41,0x00,0x00,0x00,0x00,0xff};CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(INIT_CMD1_ERROR );}}while(temp!=0x00);is_init=0;//初始化完成,将is_init设置为0,以提高后面数据的传输速度CS=1;spi_write(0xff);return 0;//说明初始化成功}/*-----------------------------向SD卡扇区中写数据,每一个扇区中有512个字节---------------------------------*/uchar SD_write_sector(unsigned long addr,uchar *Buffer){uchar temp,time;uint i;uchar pcmd[]={0x58,0x00,0x00,0x00,0x00,0xff};//向SD卡中写入24号命令addr=addr<<9;//addr=addr+512,将块地址(扇区地址)转化为字节地址pcmd[1]=((addr&0xff000000)>>24);//将字节地址写入到24号命令的时序中pcmd[2]=((addr&0x00ff0000)>>16);pcmd[3]=((addr&0x0000ff00)>>8);//SD卡最大容量4G// pcmd[4]=(addr&0x000000FF);//此行为增加项CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(temp);//命令写入失败}}while(temp!=0);for(i=0;i<100;i++)//这里要插入若干个时钟信号{spi_read();}spi_write(0xfe);//写入开始字节0XFE,后面就要写入512个字节for(i=0;i<512;i++)//将缓冲区中要写入的512个字节写入到SD卡中{spi_write(*Buffer++);}spi_write(0xff);spi_write(0xff);//两个字节CRC校验码temp=spi_read();//读取返回值if((temp&0x1f)!=0x05)//如果返回值为xxx00101,说明数据已经被接收{CS=1;return(WRITE_BLOCK_ERROR );//写块数据失败}while(spi_read()!=0xff);//等待SD卡不忙(数据被接收以后,SD卡要将这些数据写入自身的FLASH// 中,需要一定时间,忙时为0x00,不忙是为0xff, )CS=1;spi_write(0xff);//补8个时钟return 0;}/*--------------------------------读SD卡的一个扇区---------------------------------*/uchar SD_read_sector(unsigned long addr,uchar *Buffer){uint i;uchar time,temp;uchar pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff};//CMD17号命令addr=addr<<9;pcmd[1]=((addr&0xff000000)>>24);pcmd[2]=((addr&0x00ff0000)>>16);pcmd[3]=((addr&0x0000ff00)>>8);CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(READ_BLOCK_ERROR);//读块失败}}while(temp!=0);while(spi_read()!=0xfe);//一直读,当读到0xfe时,说明后面是512个数据字节for(i=0;i<512;i++){Buffer[i]=spi_read();}spi_read();spi_read();CS=1;spi_write(0xff);//补8个时钟return 0;}/*---------------------------------串口初始化-----------------------------------*/void serial_init(void) //{TMOD = 0x21; //使用定时器1工作在方式2,做波率发生器,定时器0方式1 TH0 = 0X3c; //设置定时初值,定时20ms,1s采用20*50算法TL0 = 0Xb0;ET0 = 1; //开定时器0中断标志TR0 = 1; //启动定时器0TH1 = 0xfd; //32M,9600TL1 = 0xfd;TR1 = 1; //启动定时器1SCON=0X40; //串口工作在方式1,不允许接收REN = 1; //允许串口接收ES = 1; //允许串口中断EA = 1; //开总中断}/*-------------------------函数名称:main()函数作用:主函数---------------------------*/void main(){int i=0;SD_Reset();SD_Init();serial_init();for(i=0;i<512;i++){pbuf[i]=i;//向缓冲区中写入数据}SD_write_sector(80,pbuf);//将缓冲区中512个字节的数据写入80扇区for(i=0;i<512;i++){pbuf[i]=0;//清空数据缓冲区}SD_read_sector(80,pbuf);//从SD卡的第80个扇区中读取512个字节的数据for(i=0;i<512;i++){P2=~pbuf[i];//将缓冲区中的数据输出在P2口,delay(1000);}//P2=0X00;while(1);}void timer0_int(void) interrupt 1 //中断程序,注意中断类型号{TH0=0X3c; //重新赋初值,并且必须要这样做,不然的话定时时间会不准确的TL0=0Xb0;cn++; //每当进入中断程序,count++,当有关参数设置正确后,程序会自动进入中断程序if(cn==20){cn=0;power = !power; //本机运行指示灯闪烁}}2009-10-17,09:26:21资料邮件回复引用回复编辑删除【1楼】andyluo324积分:123派别:程序还不够完善,等会改好后上完整版.2009-10-17,09:资料邮件编辑删除---------------------------------------- */uchar cn=0;/*--------------------------------------变量定义-----------------------------------------*/uchar is_init;//用于控制SPI的速度,通过为1与0进行选择uchar xdata pbuf[512];//定义512个数据缓冲区/*--------------------------------------函数名称:delay()函数作用:用于某些程序中的延时函数特点:无返回值,带入口参数-----------------------------------------*/void delay(uint k){uint m,n;for(m=0;m<5;m++)for(n=0;n<k;n++);}/*----------------------------------------函数名称:IO_init()函数作用:对相关IO进行初始化函数特点:无返回值,无入口参数------------------------------------------*/void IO_init(){SCL=1;CS=1;SO=1;power=1;}/*----------------------------------------函数名称:send_byte(uchar i)函数作用:对相关数据进行打印函数特点:无返回值,带入口参数--------------------------------------------*/void send_byte(uchar i){TI=0;SBUF=i;while(!TI);TI=0;}/*-------------------------------------------------------函数名:send_s()功能:用户函数,发送一个字符----------------------------------------------------------*/void send_s(char *s){int len=strlen(s);int i;for(i=0;i<len;i++)send_byte(s[i]);send_byte(0x0d);send_byte(0x0a);}/*-------------------------------SPI写一个字节----------------------------------*/void spi_write(uchar x)//SPI写一个字节,其中is_init为1{uchar i;for(i=0;i<8;i++){SI=((x<<i)&0x80);SCL=0;if(is_init){delay(8);}SCL=1;if(is_init){delay(8);}}}/*--------------------------------SPI读一个字节----------------------------------*/uchar spi_read(){uchar temp=0,i;SO=1;for(i=0;i<8;i++){SCL=0;if(is_init){delay(8);}// if(SO)// {// temp+=(0x80>>i);// }temp=(temp<<1)+(uchar)SO;SCL=1;if(is_init)//放慢速度{delay(8);}}return(temp);}/*--------------------------------向SD卡写命令---------------------------------*/uchar write_cmd(uchar *pcmd)//pcmd为命令字{uchar temp,i,time=0;CS=1;spi_write(0XFF);CS=0;for(i=0;i<6;i++) //发送6个字节的命令字节序列{spi_write(*pcmd++);}spi_read();do{temp=spi_read();//一直读,直到读到的不是0XFF或者超时time++;}while((temp==0xff)&&(time<100));return temp;}/*------------------------------------SD卡复位,进入SPI模式,使用CMD0命令-------------------------------------*/uchar SD_Reset()//SD卡复位{uchar time,temp,i;uchar pcmd[]={0x40,0x00,0x00,0x00,0x00,0x95};//0号命令对应的6个字节send_s("SD_Reset start\n");is_init=1;//set is_init flagCS=1;for(i=0;i<0x0f;i++)//初始化时,首先要发送至少74个时钟信号,这是必须的{spi_write(0xff);//实质发了120个时钟(15*8)}send_s("send 120 clk succeed\n");CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==200){return(INIT_CMD0_ERROR );//cmd0写入失败send_s("send CMD0 ERROR\n");}}while(temp!=0x01);CS=1;spi_write(0xff);//按照SD的操作时序在这里需要补8个时钟send_s("send CMD0 succeed\n");return 0;//返回0,说明SD卡复位操作成功}/*-------------------------------------SD卡初始化,使用CMD1号命令---------------------------------------*/uchar SD_Init()//SD卡初始化,使用CMD1号命令{uchar time,temp;uchar pcmd[]={0x41,0x00,0x00,0x00,0x00,0xff};send_s("SD_Init start\n");CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(INIT_CMD1_ERROR );send_s("CMD1 ERROR\n");}}while(temp!=0x00);is_init=0;//初始化完成,将is_init设置为0,以提高后面数据的传输速度send_s("send CMD1 succeed\n");CS=1;spi_write(0xff);send_s("SD_Init succeed\n");return 0;//说明初始化成功}/*-----------------------------向SD卡扇区中写数据,每一个扇区中有512个字节---------------------------------*/uchar SD_write_sector(unsigned long addr,uchar *Buffer){uchar temp,time;uint i;uchar pcmd[]={0x58,0x00,0x00,0x00,0x00,0xff};//向SD卡中写入24号命令addr=addr<<9;//addr=addr+512,将块地址(扇区地址)转化为字节地址pcmd[1]=((addr&0xff000000)>>24);//将字节地址写入到24号命令的时序中pcmd[2]=((addr&0x00ff0000)>>16);pcmd[3]=((addr&0x0000ff00)>>8);//SD卡最大容量4G// pcmd[4]=(addr&0x000000FF);//此行为增加项send_s("SD_write_sector start\n");CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(temp);//命令写入失败}}while(temp!=0);for(i=0;i<100;i++)//这里要插入若干个时钟信号{spi_read();}spi_write(0xfe);//写入开始字节0XFE,后面就要写入512个字节for(i=0;i<512;i++)//将缓冲区中要写入的512个字节写入到SD卡中{spi_write(*Buffer++);}spi_write(0xff);spi_write(0xff);//两个字节CRC校验码temp=spi_read();//读取返回值if((temp&0x1f)!=0x05)//如果返回值为xxx00101,说明数据已经被接收{CS=1;return(WRITE_BLOCK_ERROR );//写块数据失败}while(spi_read()!=0xff);//等待SD卡不忙(数据被接收以后,SD卡要将这些数据写入自身的FLASH// 中,需要一定时间,忙时为0x00,不忙是为0xff, )send_s("SD_write_sector succeed\n");CS=1;spi_write(0xff);//补8个时钟return 0;}/*--------------------------------读SD卡的一个扇区---------------------------------*/uchar SD_read_sector(unsigned long addr,uchar *Buffer){uint i;uchar time,temp;uchar pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff};//CMD17号命令addr=addr<<9;pcmd[1]=((addr&0xff000000)>>24);pcmd[2]=((addr&0x00ff0000)>>16);pcmd[3]=((addr&0x0000ff00)>>8);send_s("SD_read_sector start\n");CS=0;time=0;do{temp=write_cmd(pcmd);time++;if(time==100){return(READ_BLOCK_ERROR);//读块失败}}while(temp!=0);while(spi_read()!=0xfe);//一直读,当读到0xfe时,说明后面是512个数据字节for(i=0;i<512;i++){Buffer[i]=spi_read();}spi_read();spi_read();CS=1;send_s("SD_read_sector succeed\n");spi_write(0xff);//补8个时钟return 0;}/*---------------------------------串口初始化-----------------------------------*/void serial_init(void) //{TMOD = 0x21; //使用定时器1工作在方式2,做波率发生器,定时器0方式1 TH0 = 0X3c; //设置定时初值,定时20ms,1s采用20*50算法TL0 = 0Xb0;ET0 = 1; //开定时器0中断标志TR0 = 1; //启动定时器0TH1 = 0xfd; //11.0592M,9600TL1 = 0xfd;TR1 = 1; //启动定时器1SCON=0X40; //串口工作在方式1,不允许接收REN = 1; //允许串口接收ES = 1; //允许串口中断EA = 1; //开总中断}/*-------------------------函数名称:main()函数作用:主函数---------------------------*/void main(){int i=0;serial_init();send_s("serial_init!\n");IO_init();send_s("Port Init!\n");SD_Reset();SD_Init();for(i=0;i<512;i++){pbuf[i]=i;//向缓冲区中写入数据}SD_write_sector(80,pbuf);//将缓冲区中512个字节的数据写入80扇区for(i=0;i<512;i++){pbuf[i]=0;//清空数据缓冲区}SD_read_sector(80,pbuf);//从SD卡的第80个扇区中读取512个字节的数据for(i=0;i<512;i++){P2=~pbuf[i];//将缓冲区中的数据输出在P2口,send_byte(pbuf[i]);delay(1000);}//P2=0X00;while(1);}。

读写SD卡的设计及其程序硬件

读写SD卡的设计及其程序硬件

前言长期以来,以Flash Memory为存储体的SD卡因具备体积小、功耗低、可擦写以及非易失性等特点而被广泛应用于消费类电子产品中。

特别是近年来,随着价格不断下降且存储容量不断提高,它的应用范围日益增广。

当数据采集系统需要长时间地采集、记录海量数据时,选择SD卡作为存储媒质是开发者们一个很好的选择。

在电能监测以及无功补偿系统中,要连续记录大量的电压、电流、有功功率、无功功率以及时间等参数,当单片机采集到这些数据时可以利用SD作为存储媒质。

本文主要介绍了SD卡在电能监测及无功补偿数据采集系统中的应用方案。

设计方案应用AT89C52读写SD卡有两点需要注意。

首先,需要寻找一个实现AT89C52单片机与SD卡通讯的解决方案;其次,SD卡所能接受的逻辑电平与AT89C52提供的逻辑电平不匹配,需要解决电平匹配问题。

通讯模式SD卡有两个可选的通讯协议:SD模式和SPI模式。

SD模式是SD卡标准的读写方式,但是在选用SD模式时,往往需要选择带有SD卡控制器接口的MCU,或者必须加入额外的SD 卡控制单元以支持SD卡的读写。

然而,AT89C52单片机没有集成SD卡控制器接口,若选用SD模式通讯就无形中增加了产品的硬件成本。

在SD卡数据读写时间要求不是很严格的情况下,选用SPI模式可以说是一种最佳的解决方案。

因为在SPI模式下,通过四条线就可以完成所有的数据交换,并且目前市场上很多MCU都集成有现成的SPI接口电路,采用SPI模式对SD卡进行读写操作可大大简化硬件电路的设计。

虽然AT89C52不带SD卡硬件控制器,也没有现成的SPI接口模块,但是可以用软件模拟出SPI总线时序。

本文用SPI总线模式读写SD卡。

电平匹配SD卡的逻辑电平相当于3.3V TTL电平标准,而控制芯片AT89C52的逻辑电平为5V CMOS 电平标准。

因此,它们之间不能直接相连,否则会有烧毁SD卡的可能。

出于对安全工作的考虑,有必要解决电平匹配问题。

sd读卡器设计方案

sd读卡器设计方案

sd读卡器设计方案SD读卡器设计方案一、综述SD读卡器是一种能够读取SD卡中数据的设备,通过将SD卡插入读卡器中,可以方便地将SD卡中的数据传输到电脑或其他设备中。

本文将从硬件设计和软件设计两个方面,详细介绍SD读卡器的设计方案。

二、硬件设计方案硬件设计方案主要包括主控芯片、SD卡座、电源模块和连接接口等几个主要模块。

1.主控芯片:选择一款性能稳定、集成度高的主控芯片,如STM32系列芯片,具有较高的处理能力和丰富的外设接口,能够满足SD读卡器的基本需求。

2.SD卡座:选择质量可靠的SD卡座,能够确保良好的接触性能和稳定的数据传输速率。

3.电源模块:设计一个稳定的电源模块,能够为SD读卡器提供稳定的电压和电流,以保证设备的正常运行。

4.连接接口:根据需求选择合适的连接接口,如USB接口、Type-C接口等,以便与不同设备进行连接和数据传输。

三、软件设计方案软件设计方案主要包括驱动程序设计和数据传输管理。

1.驱动程序设计:根据主控芯片的型号和规格进行驱动程序设计,包括引脚配置、时钟配置、中断配置等,以保证主控芯片能够正确地控制SD卡和其他外设。

2.数据传输管理:通过实现数据传输管理程序,使得SD读卡器能够正确地读取SD卡中的数据,并将数据传输到连接的设备中。

其中,需要考虑数据的格式转换、数据的合法性验证等,以提高数据传输的可靠性和稳定性。

四、其他设计要素除了上述主要设计方案外,还需要考虑以下几个要素。

1.电路板设计:根据硬件设计方案,进行电路板的设计和布线,确保各个模块之间的连接正确可靠。

2.外壳设计:设计一个结实、美观的外壳,能够确保SD读卡器在使用过程中不受损坏,并且外壳上应具备合适的接口和指示灯,方便用户操作和状态显示。

3.电磁兼容性设计:考虑到SD读卡器需要与其他设备进行高速数据传输,需对设备进行电磁兼容性设计,以防止干扰对数据传输的影响。

4.软件升级设计:为了方便用户,设计SD读卡器的主控芯片支持在线升级功能,以便后期可以进行固件升级,提高设备的兼容性和稳定性。

SD卡接口设计[附硬件电路和程序]

SD卡接口设计[附硬件电路和程序]

SD卡接口设计[附硬件电路和程序]1标准SD卡标准是SD卡协会针对可移动存储设备设计专利并授权的一种标准,主要用于制定卡的外形尺寸、电气接口和通信协议。

1.1SD卡引脚功能SD卡的外形如图1所示,引脚功能如表1所列。

SD卡的引脚具有双重功能,既可工作在SD模式,也可工作在SPI模式。

不同的模式下,引脚的功能不同。

SD模式多用于对SD卡读写速度要求较高的场合,SPI模式则是以牺牲读写速度换取更好的硬件接口兼容性。

由于SPI协议是目前广泛流行的通信协议,大多数高性能单片机都配备了SPI硬件接口,硬件连接相对简单,因此,在对SD卡读写速度要求不高的情况下,采用SPI模式无疑是一个不错的选择。

1.2SPI模式SPI模式是一种简单的命令响应协议,主控制器发出命令后,SD卡针对不S同的命令返回对应的响应。

SD卡的命令列表都是以CMD和ACMD开头,分别指通用命令和专用命令,后面接命令的编号。

例如,CMD17就是一个通用命令,用来读单块数据。

在SPI模式中,命令都是以如下的6字节形式发送的:每帧命令都以“01”开头,然后是6位命令号和4字节的参数(高位在前,低位在后),最后是7位CRC校验和1位停止位“1”。

SD卡的每条命令都会返回对应的响应类型。

在SPI模式下,共有3种响应类型:R1、R2和R3,分别占1、2和3个字节。

这里仅列出了R1响应的格式,如表2所列。

当出现表中所描述的状态时,相应的位置1。

R2和R3的第1个字节格式与R1完全一样,详细内容请参考SD卡标准。

2硬件设计本设计选用Freescale公司的32位低功耗微控制器MCF51QE128,采用SPI模式实现与SD卡的接口。

由于MCF51QE128是一款低功耗的微控制器,工作电压的典型值为3.6V,与SD卡的工作电压兼容,因而可以直接与SD卡连接,无需电平转换电路。

这里选用的是MCF51QE128的第2个SPI口,硬件连接如图2所示。

3软件实现软件部分主要实现MCF51QE128的初始化、底层SPI通信,以及SD卡的通用写命令、初始化和单块数据的读写等功能。

单片机读写SD卡教程

单片机读写SD卡教程

单片机读写SD卡教程引言:SD卡(Secure Digital Card)是广泛应用于各类数字设备上的一种存储介质。

它小巧轻便,可靠性高,容量大,因此在各种嵌入式系统中都广泛使用。

本教程将介绍如何使用单片机读写SD卡,包括初始化SD卡、读写数据等基本操作。

一、硬件准备在开始之前,我们需要准备以下硬件设备:1.一个支持SPI协议的单片机开发板(例如STC89C51、STM32等);2.一个SD卡插槽,或者是一个带有SD卡插槽的扩展板;3.杜邦线、面包板等连接器。

二、软件准备除了硬件设备,我们还需要准备以下软件工具:1. Keil C51、IAR、Keil MDK等单片机编译工具;2. SD卡相关的库文件,例如FatFs;3.一个用于测试的程序(可以是一个简单的读写数据的程序)。

三、连接SD卡插槽将SD卡插入到对应的插槽中,并将插槽与单片机的硬件SPI接口连接。

根据不同的开发板,连接方式可能有所不同,一般SPI接口包括SCK(时钟线)、MOSI(主机输出从机输入线)、MISO(主机输入从机输出线)和CS(片选线)等。

四、编写读写SD卡的程序在开始编写程序之前,我们需要先了解SD卡的工作原理。

SD卡通过SPI总线与单片机进行通信,通过发送特定的命令和参数实现读写操作。

以下是一个简单的读写SD卡的流程:1.初始化SD卡a.发送CMD0命令,将SD卡设置为SPI模式;b.发送CMD8命令,验证SD卡是否支持高速SPI模式;c.发送ACMD41命令,等待SD卡初始化完成。

2.读写数据a.发送CMD17命令,指定要读取的扇区地址;b.等待SD卡回应,确认读取命令执行成功;c.读取数据;d.发送CMD18命令,继续读取下一个扇区;e.重复步骤c和d,直到读取完所有数据;f.发送CMD12命令,停止读取。

g.发送CMD24命令,指定要写入的扇区地址;h.等待SD卡回应,确认写入命令执行成功;i.写入数据;j.发送CMD25命令,继续写入下一个扇区;k.重复步骤i和j,直到写入完所有数据;l.发送CMD12命令,停止写入。

SD卡读写程序设计三.

SD卡读写程序设计三.

该文章讲述了SD卡读写程序设计三.一、概述今天的主要任务是建立SD操作底层驱动的框架。

二、SD用户层程序的编写这几天看了周立功的《嵌入式软件开发实例》中关于SD卡操作的部分,又加了一个函数void SD_GetCardInfo( void );现在共有5个函数:void SD_Config( void );void SD_GetCardInfo( void );void SD_ReadBlock( u32 BlockIndex, u8* ReadBuf );void SD_WriteBlock( u32 BlockIndex, u8* WriteBuf );void SD_EraseBlock( u32 BlockIndex, u32 BlockNum );1、SD_Config函数的编写(1)主要任务是进行复位、激活、和设置块长度等。

(2)代码框架void SD_Config( void ){SD_Reset(); //命令0使卡复位,并进入SPI模式SD_Activate(); //命令1激活卡进行内部处理退出空闲状态SD_SetBlockLen ( BlockSize );//命令16设置块长度,一般为512字节}2. SD_ReadBlock( u32 BlockIndex, u8* ReadBuf )函数的编写void SD_ReadBlock( u32 BlockIndex, u8* ReadBuf ){u16 i="0"u16 TmpByte;SendCommand:SD_CmdReadSingle ( BlockIndex ); //发出读单块命令17do{ TmpByte = SPI_GetByte ( );i++;} while ( (TmpByte != 0xFE ) && ( i<=1000 ) );if ( i>1000 ) goto SendCommand; //如果在这段时间内没有收到0xFE的令牌,重复读命令for ( i="0"; i<BlockSize; i++ )ReadBuf[i] = SPI_GetByte();TmpByte = SPI_GetByte ( );TmmByte = SPI_GetByte ( ); //不进行CRC校验SPI_PutByte ( 0xFF ); //纯粹只是为了延时。

MCS51 MCU读写SD卡版(单片机论文)

MCS51 MCU读写SD卡版(单片机论文)

摘要摘要近年来, SD存储卡在嵌入式产品中的应用越来越广泛, 但SD卡接口一般仅集成在32位高端处理器中, 一般51单片机则由于资源限制没有该接口。

因此,如何解决51单片机应用系统存取SD卡大容量数据就显得很有实际意义。

本系统使用MXT8051F04A作为单片机与SD卡的接口芯片, 采用SPI串行方式对SD卡的扇区进行读写,读写过程和结果通过串口调试助手在主机上显示。

本论文的核心主要从硬件设计和软件编程两个大的方面介绍了系统的实现。

硬件电路设计主要包括MXT8051F04A最小系统电路、电源电路、串口电路、SD卡接口电路。

程序采用C语言在Keil软件下进行编写、调试,程序主要包括SD卡扇区读写程序、串口程序等软件模块。

系统实现了对SD卡扇区的读写,达到了设计的要求和目的。

关键字:MXT8051F04A,SD卡,KeilIABSTRACTABSTRACTIn recent years, SD memory card applications in the embedded products more widely, but generally only the integrated SD card interface in 32-bit high-end processor, microcontroller 51 is generally not the interface due to resource constraints. Therefore, how to solve the 51 SCM applications to access data on large-capacity SD cards seem very practical.The system uses MXT8051F04A as SCM and SD card interface chip, using SPI mode on the SD card serial read and write sectors, reading and writing process and results through the serial port on the host display debugging assistant. The core of this thesis, the main hardware and software design introduces two major aspects of the system implementation. Hardware design includes MXT8051F04A minimum system circuit, power circuit, the serial port circuitry, SD card interface circuit. Program using C language under the Keil software write, debug, the program includes reading and writing SD card sector program, serial procedures of software modules. System realizes the SD card read and write sectors, meets the design requirements and objectives.Keywords: MXT8051F04A,SD Card,KeilII目录第1章引言 (1)1.1 选题背景 (1)1.2 研究目标和意义 (1)1.3 本文要完成的工作 (1)第2章单片机读写SD卡的硬件电路设计 (3)2.1 系统硬件平台组成 (3)2.2 电源模块 (3)2.3 MXT8051F04A单片机最小系统电路设计 (4)2.3.1 MXT8051F04A简介 (4)2.3.2 晶振复位电路 (8)2.4 SD卡电路设计 (8)2.4.1 通讯模式 (9)2.4.2 电平匹配 (9)2.4.3 硬件接口设计 (10)2.5 串口电路设计 (12)2.6 PCB绘制 (13)2.7 本章小结 (14)第3章单片机读写SD卡的软件设计 (14)3.1 SD卡的扇区读写 (14)3.1.1 模拟SPI协议 (14)3.1.2 SD卡命令 (15)3.1.3 SD卡的初始化 (19)3.1.4 数据块的读写 (20)3.2 串口程序 (25)第4章调试 (26)4.1 系统硬件调试 (26)4.2 软件调试 (27)4.3 软硬件的联合调试 (27)III4.4 本章小结 (29)第5章结束语 (30)5.1 总结 (30)5.2 展望 (30)参考文献 (31)致谢 (32)附录 (33)附录一:单片机读写SD卡的完整原理图 (33)附录二:单片机读写SD卡的完整程序 (36)外文资料原文 (63)译文 (64)IV第1章引言第1章引言1.1选题背景SD卡(Secure Digital Memory Card)中文翻译为安全数码卡,是一种基于半导体快闪记忆器的新一代记忆设备,它被广泛地于便携式装置上使用,例如个人数码助理(PDA)、数码相机和多媒体播放器等。

SD卡文件系统读写

SD卡文件系统读写

SD 文件系统U n R e g i st er ed32514Un R e gd一、SD 卡概述v 1、SD卡简介(1)nSD卡(Secure Digital Memory Card)是一种基于半导体快闪记忆器的新一代记忆设备。

nSD卡数据传送和物理规范由MMC发展而来Un Re gi st er ed一、SD 卡概述v 1、SD卡简介(2)n特点:大容量、高性能、安全性高。

n用途:可用在MP3、移动电话、PDA、数码相机、数码摄像机、电子图书、微型电脑、AV器材等领域。

n数据传输速率:SD卡读写速度比MMC卡要快四倍,最大速率可达到10MB/秒。

n几种SD卡的区分:普通SD,高速SD,SDHC。

Un Re gi st er ed2、SD卡内部结构SD卡由9线接口控制,数据线包括:CMD,CLK,DAT0-st er ed一、SD 卡概述v 3、SD通信模式n一个主机一般情况下可以挂多张SD卡,最大10个堆叠的卡。

n主机访问模式:SD模式;SPI模式Un Re gi st er ed一、SD 卡概述v 4、SD卡通信n主机和SD卡之间的通信是通过命令和数据流实现的,如下图所示:n命令发送/数据传输Un Re gi st er ed二、SD 卡通信协议v 1、SD卡接口可以支持两种操作模式1、SD卡模式2、SPI模式n主机系统可以选择以上其中任一模式,SD卡模式允许4线的高速数据传输。

SPI模式允许简单通用的SPI通道接口,这种模式相对于SD模式的不足之处是丧失了速度。

Un Re gi st er ed二、SD 卡通信协议nSD模式总线连接图n SD模式(1)Un Re gi st er ed二、SD 卡通信协议nSD模式针脚定义nSD总线允许1线和4线数据信号设置。

n SD模式(2)Un Re gi st er ed二、SD 卡通信协议nSPI模式连接图n SPI模式(1)Un Re gi st er ed二、SD 卡通信协议nSPI模式针脚定义n注意:SPI模式时,数据信号需要在主机端用10-100K欧的上拉电阻。

SD卡的初始化和读写程序

SD卡的初始化和读写程序

/****************************************************************************** *****SPI模式读写SD卡SD卡初始化过程:1. 初始化STM32的SPI接口使用低速模式2. 延时至少74clock3. 发送CMD0,需要返回0x01,进入Idle状态4. 循环发送CMD55+ACMD41,直到返回0x00,进入Ready状态5. 设置读写block大小为512byte5. 把STM32的SPI设置为高速模式读一个block块的过程1. 发送CMD17(单块)或CMD18(多块)读命令,返回0x002. 接收数据开始令牌0xfe + 正式数据512Bytes + CRC 校验2Bytes写一个block块的过程1. 发送CMD24(单块)或CMD25(多块)写命令,返回0x002. 发送数据开始令牌0xfe + 正式数据512Bytes + CRC校验2Bytes-----------------------------------------------------------------------------* ----------------------------------------------* | STM32F10x | MSD Pin |* ----------------------------------------------* | PE.3 | ChipSelect 1 |* | PA.7 / MOSI | DataIn 2 |* | | GND 3 (0 V) |* | | VDD 4 (3.3 V) |* | PA.5 / SCLK | Clock 5 |* | | GND 6 (0 V) |* | PA.6 / MISO | DataOut 7 |* -----------------------------------------------******************************************************************************* ****//* Includes ------------------------------------------------------------------*///#include "stm32f10x_lib.h"#include "stm32f10x.h"#include "hardwareinit.h"/* Private typedef -----------------------------------------------------------*//* Private define ------------------------------------------------------------*/#define sd_cs_1 GPIO_SetBits(GPIOB,GPIO_Pin_12)#define sd_cs_0 GPIO_ResetBits(GPIOB,GPIO_Pin_12)#define sd_check GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_15)/* Select MSD Card: ChipSelect pin low *///#define MSD_CS_LOW() GPIO_ResetBits(GPIOE, GPIO_Pin_3)/* Deselect MSD Card: ChipSelect pin high *///#define MSD_CS_HIGH() GPIO_SetBits(GPIOE, GPIO_Pin_3)//SD传输数据结束后是否释放总线宏定义#define NO_RELEASE 0#define RELEASE 1// SD卡类型定义#define SD_TYPE_MMC 0#define SD_TYPE_V1 1#define SD_TYPE_V2 2#define SD_TYPE_V2HC 4// SD卡指令表#define CMD0 0 //卡复位#define CMD1 1#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 ACMD23 23 //命令23,设置多sector写入前预先擦除N个block #define CMD24 24 //命令24,写sector#define CMD25 25 //命令25,写Multi sector#define ACMD41 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_STA TE 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#define Dummy_Byte 0xA5 //0xff/* Private macro -------------------------------------------------------------*//* Private variables ---------------------------------------------------------*///u8 Dummy_Byte = 0xa5; //0xff;u8 SD_Type; //SD卡的类型u8 buf[512];/* Private function prototypes -----------------------------------------------*//* Private functions ---------------------------------------------------------*/FlagStatus sd_insert_check(void);u8 SD_WaitReady(void); //等待SD卡就绪u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc); //SD卡发送一个命令u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc);u8 SD_Init(void); //SD卡初始化u8 SD_Idle_Sta(void); //设置SD卡到挂起模式u8 SD_ReceiveData(u8 *data, u16 len, u8 release);//SD卡读数据u8 SD_GetCID(u8 *cid_data); //读SD卡CIDu8 SD_GetCSD(u8 *csd_data); //读SD卡CSDu32 SD_GetCapacity(void); //取SD卡容量//USB 读卡器SD卡操作函数//u8 MSD_WriteBuffer(u8* pBuffer, u32 WriteAddr, u32 NumByteToWrite);//u8 MSD_ReadBuffer(u8* pBuffer, u32 ReadAddr, u32 NumByteToRead);u8 SD_ReadSingleBlock(u32 sector, u8 *buffer); //读一个sectoru8 SD_WriteSingleBlock(u32 sector, const u8 *buffer); //写一个sectoru8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count); //读多个sectoru8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count);//写多个sectoru8 SD_Read_Bytes(unsigned long address,unsigned char *buf,unsigned int offset,unsigned int bytes);//读取一byte//--------------------------------spi speed setting-------------------------/****************************************************************************** ** Function Name : SPI_Config* Description : Initializes the SPI1 and CS pins.* Input : None* Output : None* Return : None******************************************************************************* /void SPI_Config(u16 BaudRatePrescaler){GPIO_InitTypeDef GPIO_InitStructure;SPI_InitTypeDef SPI_InitStructure;/* GPIOA and GPIOC Periph clock enable */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);/* SPI1 Periph clock enable */RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);/* Configure SPI2 pins: SCK, MISO and MOSI */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);/* Configure PE3 pin: CS pin */GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_12);/* SPI1 Config */SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode = SPI_Mode_Master;SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler = BaudRatePrescaler;SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial = 7;SPI_Init(SPI2, &SPI_InitStructure);/* SPI1 enable */SPI_Cmd(SPI2, ENABLE);}void spi_high_speed(void){//SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;//SPI_BaudRatePrescaler_256;//SPI_Init(SPI2, &SPI_InitStructure);SPI_Config(SPI_BaudRatePrescaler_4);}void spi_low_speed(void){//SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//SPI_BaudRatePrescaler_4;//SPI_Init(SPI2, &SPI_InitStructure);SPI_Config(SPI_BaudRatePrescaler_256);}//---------------sd_insert_check---------------------------FlagStatus sd_insert_check(void){FlagStatus card_exist_state;if(!sd_check){card_exist_state = SET;}else{card_exist_state = RESET;}return card_exist_state;}//-------------------------------------------------------------------------/****************************************************************************** ** Function Name : SPI_FLASH_SendByte* Description : Sends a byte through the SPI interface and return the byte* received from the SPI bus.* Input : byte : byte to send.* Output : None* Return : The value of the received byte.******************************************************************************* /u8 SPIx_ReadWriteByte(u8 byte){/* Loop while DR register in not emplty */while ((SPI2->SR & SPI_I2S_FLAG_TXE) == (uint16_t)RESET);/* Send byte through the SPI1 peripheral *///SPI_I2S_SendData(SPI2, byte);SPI2->DR = byte;/* Wait to receive a byte */while((SPI2->SR &SPI_I2S_FLAG_RXNE) == (uint16_t)RESET);/* Return the byte read from the SPI bus *///return SPI_I2S_ReceiveData(SPI2);return SPI2->DR;}//u8 SPIx_ReadWriteByte(u8 byte)//{/* Loop while DR register in not emplty *///while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); //((SPIx->SR & SPI_I2S_FLAG) != (uint16_t)RESET)/* Send byte through the SPI1 peripheral *///SPI_I2S_SendData(SPI2, byte);/* Wait to receive a byte *///while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);/* Return the byte read from the SPI bus *///return SPI_I2S_ReceiveData(SPI2);//}/****************************************************************************** ** Function Name : SPI_FLASH_ReadByte* Description : Reads a byte from the SPI Flash.* This function must be used only if the Start_Read_Sequence* function has been previously called.* Input : None* Output : None* Return : Byte Read from the SPI Flash.******************************************************************************* /u8 SPI_ReadByte(void){return (SPIx_ReadWriteByte(Dummy_Byte));}//-----------------------------------------------------------------------------------------------------------------------------------//等待SD卡回应//Response:要得到的回应值//返回值:0,成功得到了该回应值// 其他,得到回应值失败u8 SD_GetResponse(u8 Response){u16 Count=0xFFF;//等待次数while ((SPIx_ReadWriteByte(0XFF)!=Response)&&Count) Count--;//等待得到准确的回应if (Count==0){return MSD_RESPONSE_FAILURE;//得到回应失败}else{return MSD_RESPONSE_NO_ERROR;//正确回应}}//------------------------------------------------------------------------//等待SD卡写入完成//返回值:0,成功;// 其他,错误代码;u8 SD_WaitDataReady(void){u8 r1=MSD_DATA_OTHER_ERROR;u32 retry;retry=0;do{r1=SPIx_ReadWriteByte(0xFF)&0X1F; //读到回应if(retry==0xfffe)return 1;retry++;switch (r1){case MSD_DATA_OK: //数据接收正确了r1=MSD_DATA_OK;break;case MSD_DATA_CRC_ERROR: //CRC校验错误return MSD_DATA_CRC_ERROR;case MSD_DATA_WRITE_ERROR: //数据写入错误return MSD_DATA_WRITE_ERROR;default: //未知错误r1=MSD_DATA_OTHER_ERROR;break;}}while(r1==MSD_DATA_OTHER_ERROR); //数据错误时一直等待retry=0;while(SPIx_ReadWriteByte(0XFF)==0) //读到数据为0,则数据还未写完成{retry++;//delay_us(10); //SD卡写等待需要较长的时间if(retry>=0XFFFFFFFE)return 0XFF; //等待失败了};return 0; //成功了}//-----------------------------------------------------------------//向SD卡发送一个命令//输入: u8 cmd 命令// u32 arg 命令参数// u8 crc crc校验值//返回值:SD卡返回的响应u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc){u8 r1;u8 Retry=0;sd_cs_1;SPIx_ReadWriteByte(0xff); //高速写命令延时SPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//片选端置低,选中SD卡sd_cs_0;//发送SPIx_ReadWriteByte(cmd | 0x40); //分别写入命令SPIx_ReadWriteByte(arg >> 24);SPIx_ReadWriteByte(arg >> 16);SPIx_ReadWriteByte(arg >> 8);SPIx_ReadWriteByte(arg);SPIx_ReadWriteByte(crc);//等待响应,或超时退出while((r1=SPIx_ReadWriteByte(0xFF))==0xFF){Retry++;if(Retry>200)break;}//关闭片选sd_cs_1;//在总线上额外增加8个时钟,让SD卡完成剩下的工作SPIx_ReadWriteByte(0xFF);//返回状态值return r1;}//-----------------------------------------------------------//向SD卡发送一个命令(结束是不失能片选,还有后续数据传来)//输入:u8 cmd 命令// u32 arg 命令参数// u8 crc crc校验值//返回值:SD卡返回的响应u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc){u8 Retry=0;u8 r1;SPIx_ReadWriteByte(0xff);//高速写命令延时SPIx_ReadWriteByte(0xff);sd_cs_0;//片选端置低,选中SD卡//发送SPIx_ReadWriteByte(cmd | 0x40); //分别写入命令SPIx_ReadWriteByte(arg >> 24);SPIx_ReadWriteByte(arg >> 16);SPIx_ReadWriteByte(arg >> 8);SPIx_ReadWriteByte(arg);SPIx_ReadWriteByte(crc);//等待响应,或超时退出while((r1=SPIx_ReadWriteByte(0xFF))==0xFF){Retry++;if(Retry>200)break;}//返回响应值return r1;}//------------------------------------------------------------//把SD卡设置到挂起模式//返回值:0,成功设置// 1,设置失败u8 SD_Idle_Sta(void){u16 i;u8 retry;for(i=0;i<0xf00;i++); //纯延时,等待SD卡上电完成//先产生>74个脉冲,让SD卡自己初始化完成for(i=0;i<10;i++)SPIx_ReadWriteByte(0xFF);//-----------------SD卡复位到idle开始-----------------//循环连续发送CMD0,直到SD卡返回0x01,进入IDLE状态//超时则直接退出retry = 0;do{//发送CMD0,让SD卡进入IDLE状态i = SD_SendCommand(CMD0, 0, 0x95);retry++;}while((i!=0x01)&&(retry<200));//跳出循环后,检查原因:初始化成功?or 重试超时?if(retry==200)return 1; //失败return 0; //成功}//---------------------------------------------------------------//初始化SD卡//如果成功返回,则会自动设置SPI速度为18Mhz//返回值:0:NO_ERR// 1:TIME_OUT// 99:NO_CARDu8 SD_Init(void){u8 r1; // 存放SD卡的返回值u16 retry; // 用来进行超时计数u8 buff[6];/*//设置硬件上与SD卡相关联的控制引脚输出//避免NRF24L01/W25X16等的影响RCC->APB2ENR|=1<<2; //PORTA时钟使能GPIOA->CRL&=0XFFF000FF;GPIOA->CRL|=0X00033300;//PA2.3.4 推挽GPIOA->ODR|=0X7<<2; //PA2.3.4上拉SPIx_Init();SPIx_SetSpeed(SPI_SPEED_256);//设置到低速模式*/spi_low_speed();sd_cs_1;if(SD_Idle_Sta()) return 1;//超时返回1 设置到idle 模式失败//-----------------SD卡复位到idle结束-----------------//获取卡片的SD版本信息sd_cs_0;r1 = SD_SendCommand_NoDeassert(8, 0x1aa,0x87);//如果卡片版本信息是v1.0版本的,即r1=0x05,则进行以下初始化if(r1 == 0x05){//设置卡类型为SDV1.0,如果后面检测到为MMC卡,再修改为MMC SD_Type = SD_TYPE_V1;//如果是V1.0卡,CMD8指令后没有后续数据//片选置高,结束本次命令sd_cs_1;//多发8个CLK,让SD结束后续操作SPIx_ReadWriteByte(0xFF);//-----------------SD卡、MMC卡初始化开始-----------------//发卡初始化指令CMD55+ACMD41// 如果有应答,说明是SD卡,且初始化完成// 没有回应,说明是MMC卡,额外进行相应初始化retry = 0;do{//先发CMD55,应返回0x01;否则出错r1 = SD_SendCommand(CMD55, 0, 0);if(r1 == 0XFF)return r1;//只要不是0xff,就接着发送//得到正确响应后,发ACMD41,应得到返回值0x00,否则重试200次r1 = SD_SendCommand(ACMD41, 0, 0);retry++;}while((r1!=0x00) && (retry<400));// 判断是超时还是得到正确回应// 若有回应:是SD卡;没有回应:是MMC卡//----------MMC卡额外初始化操作开始------------if(retry==400){retry = 0;//发送MMC卡初始化命令(没有测试)do{r1 = SD_SendCommand(1,0,0);retry++;}while((r1!=0x00)&& (retry<400));if(retry==400)return 1; //MMC卡初始化超时//写入卡类型SD_Type = SD_TYPE_MMC;}//----------MMC卡额外初始化操作结束------------//设置SPI为高速模式//SPIx_SetSpeed(SPI_SPEED_4);spi_high_speed();SPIx_ReadWriteByte(0xFF);//禁止CRC校验r1 = SD_SendCommand(CMD59, 0, 0x95);if(r1 != 0x00)return r1; //命令错误,返回r1//设置Sector Sizer1 = SD_SendCommand(CMD16, 512, 0x95);if(r1 != 0x00)return r1;//命令错误,返回r1//-----------------SD卡、MMC卡初始化结束-----------------}//SD卡为V1.0版本的初始化结束//下面是V2.0卡的初始化//其中需要读取OCR数据,判断是SD2.0还是SD2.0HC卡else if(r1 == 0x01){//V2.0的卡,CMD8命令后会传回4字节的数据,要跳过再结束本命令buff[0] = SPIx_ReadWriteByte(0xFF); //should be 0x00buff[1] = SPIx_ReadWriteByte(0xFF); //should be 0x00buff[2] = SPIx_ReadWriteByte(0xFF); //should be 0x01buff[3] = SPIx_ReadWriteByte(0xFF); //should be 0xAAsd_cs_1;SPIx_ReadWriteByte(0xFF);//the next 8 clocks//判断该卡是否支持2.7V-3.6V的电压范围//if(buff[2]==0x01 && buff[3]==0xAA) //不判断,让其支持的卡更多{retry = 0;//发卡初始化指令CMD55+ACMD41do{r1 = SD_SendCommand(CMD55, 0, 0);if(r1!=0x01)return r1;r1 = SD_SendCommand(ACMD41, 0x40000000, 0);if(retry>200)return r1; //超时则返回r1状态}while(r1!=0);//初始化指令发送完成,接下来获取OCR信息//-----------鉴别SD2.0卡版本开始-----------r1 = SD_SendCommand_NoDeassert(CMD58, 0, 0);if(r1!=0x00){sd_cs_1;//释放SD片选信号return r1; //如果命令没有返回正确应答,直接退出,返回应答}//读OCR指令发出后,紧接着是4字节的OCR信息buff[0] = SPIx_ReadWriteByte(0xFF);buff[1] = SPIx_ReadWriteByte(0xFF);buff[2] = SPIx_ReadWriteByte(0xFF);buff[3] = SPIx_ReadWriteByte(0xFF);//OCR接收完成,片选置高sd_cs_1;SPIx_ReadWriteByte(0xFF);//检查接收到的OCR中的bit30位(CCS),确定其为SD2.0还是SDHC //如果CCS=1:SDHC CCS=0:SD2.0if(buff[0]&0x40)SD_Type = SD_TYPE_V2HC; //检查CCSelse SD_Type = SD_TYPE_V2;//-----------鉴别SD2.0卡版本结束-----------//设置SPI为高速模式//SPIx_SetSpeed(SPI_SPEED_4);spi_high_speed();}}return r1;}//---------------------------------------------------------------------//从SD卡中读回指定长度的数据,放置在给定位置//输入: u8 *data(存放读回数据的内存>len)// u16 len(数据长度)// u8 release(传输完成后是否释放总线CS置高0:不释放1:释放)//返回值:0:NO_ERR// other:错误信息u8 SD_ReceiveData(u8 *data, u16 len, u8 release){// 启动一次传输sd_cs_0;if(SD_GetResponse(0xFE)) //等待SD卡发回数据起始令牌0xFE {sd_cs_1;return 1;}while(len--)//开始接收数据{*data=SPIx_ReadWriteByte(0xFF);data++;}//下面是2个伪CRC(dummy CRC)SPIx_ReadWriteByte(0xFF);SPIx_ReadWriteByte(0xFF);if(release==RELEASE)//按需释放总线,将CS置高{sd_cs_1;//传输结束SPIx_ReadWriteByte(0xFF);}return 0;}//-----------------------------------------------------------------//获取SD卡的CID信息,包括制造商信息//输入: u8 *cid_data(存放CID的内存,至少16Byte)//返回值:0:NO_ERR// 1:TIME_OUT// other:错误信息u8 SD_GetCID(u8 *cid_data){u8 r1;//发CMD10命令,读CIDr1 = SD_SendCommand(CMD10,0,0xFF);if(r1 != 0x00)return r1; //没返回正确应答,则退出,报SD_ReceiveData(cid_data,16,RELEASE);//接收16个字节的return 0;}//-------------------------------------------------------------------//获取SD卡的CSD信息,包括容量和速度信息//输入:u8 *cid_data(存放CID的内存,至少16Byte)//返回值:0:NO_ERR// 1:TIME_OUT// other:错误信息u8 SD_GetCSD(u8 *csd_data){u8 r1;r1=SD_SendCommand(CMD9,0,0xFF);//发CMD9命令,读CSD if(r1)return r1; //没返回正确应答,则退出,报错SD_ReceiveData(csd_data, 16, RELEASE);//接收16个字节的数据return 0;}//------------------------------------------------------------------------ //获取SD卡的容量(字节)//返回值:0:取容量出错// 其他:SD卡的容量(字节)u32 SD_GetCapacity(void){u8 csd[16];u32 Capacity;u8 r1;u16 i;u16 temp;//取CSD信息,如果期间出错,返回0if(SD_GetCSD(csd)!=0) return 0;//如果为SDHC卡,按照下面方式计算if((csd[0]&0xC0)==0x40){Capacity=((u32)csd[8])<<8;Capacity+=(u32)csd[9]+1;Capacity = (Capacity)*1024;//得到扇区数Capacity*=512;//得到字节数}else{i = csd[6]&0x03;i<<=8;i += csd[7];i<<=2;i += ((csd[8]&0xc0)>>6);//C_SIZE_MULTr1 = csd[9]&0x03;r1<<=1;r1 += ((csd[10]&0x80)>>7);r1+=2;//BLOCKNRtemp = 1;while(r1){temp*=2;r1--;}Capacity = ((u32)(i+1))*((u32)temp);// READ_BL_LENi = csd[5]&0x0f;//BLOCK_LENtemp = 1;while(i){temp*=2;i--;}//The final resultCapacity *= (u32)temp;//字节为单位}return (u32)Capacity;}//--------------------------------------------------------------------//读SD卡的一个block//输入:u32 sector 取地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)//返回值:0:成功// other:失败u8 SD_ReadSingleBlock(u32 sector, u8 *buffer){u8 r1;//设置为高速模式//SPIx_SetSpeed(SPI_SPEED_4);//spi_high_speed();//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type!=SD_TYPE_V2HC){sector = sector<<9;}r1 = SD_SendCommand(CMD17, sector, 0);//读命令if(r1 != 0x00)return r1;r1 = SD_ReceiveData(buffer, 512, RELEASE);if(r1 != 0)return r1; //读数据出错!else return 0;}/*u8 SD_ReadSingleBlock(u32 sector, u8 *buffer){u8 r1;//设置为高速模式//SPIx_SetSpeed(SPI_SPEED_4);spi_high_speed();//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type!=SD_TYPE_V2HC){sector = sector<<9;}r1 = SD_SendCommand(CMD17, sector, 0);//读命令if(r1 != 0x00)return r1;r1 = SD_ReceiveData(buffer, 512, RELEASE);if(r1 != 0)return r1; //读数据出错!else return 0;}*///----------------------------------------------------------------------//写入SD卡的一个block(未实际测试过)//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)//返回值:0:成功// other:失败u8 SD_WriteSingleBlock(u32 sector, const u8 *data){u8 r1;u16 i;u16 retry;//设置为高速模式//SPIx_SetSpeed(SPI_SPEED_4);//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type!=SD_TYPE_V2HC){sector = sector<<9;}r1 = SD_SendCommand(CMD24, sector, 0x00);if(r1 != 0x00){return r1; //应答不正确,直接返回}//开始准备数据传输sd_cs_0;//先放3个空数据,等待SD卡准备好SPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//放起始令牌0xFESPIx_ReadWriteByte(0xFE);//放一个sector的数据for(i=0;i<512;i++){SPIx_ReadWriteByte(*data++);}//发2个Byte的dummy CRCSPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//等待SD卡应答r1 = SPIx_ReadWriteByte(0xff);if((r1&0x1F)!=0x05){sd_cs_1;return r1;}//等待操作完成retry = 0;while(!SPIx_ReadWriteByte(0xff)){retry++;if(retry>0xfffe) //如果长时间写入没有完成,报错退出{sd_cs_1;return 1; //写入超时返回1}}//写入完成,片选置1sd_cs_1;SPIx_ReadWriteByte(0xff);return 0;}//-------------------------------------------------------------------//读SD卡的多个block(实际测试过)//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)// u8 count 连续读count个block//返回值:0:成功// other:失败u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count) {u8 r1;//SPIx_SetSpeed(SPI_SPEED_4);//设置为高速模式//如果不是SDHC,将sector地址转成byte地址if(SD_Type!=SD_TYPE_V2HC)sector = sector<<9;//SD_WaitDataReady();//发读多块命令r1 = SD_SendCommand(CMD18, sector, 0);//读命令if(r1 != 0x00)return r1;do//开始接收数据{if(SD_ReceiveData(buffer, 512, NO_RELEASE) != 0x00)break;buffer += 512;} while(--count);//全部传输完毕,发送停止命令SD_SendCommand(CMD12, 0, 0);//释放总线sd_cs_1;SPIx_ReadWriteByte(0xFF);if(count != 0)return count; //如果没有传完,返回剩余个数else return 0;}//------------------------------------------------------------------------//写入SD卡的N个block(未实际测试过)//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buffer 数据存储地址(大小至少512byte)// u8 count 写入的block数目//返回值:0:成功// other:失败u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count){u8 r1;u16 i;//SPIx_SetSpeed(SPI_SPEED_4);//设置为高速模式if(SD_Type != SD_TYPE_V2HC)sector = sector<<9;//如果不是SDHC,给定的是sector地址,将其转换成byte地址if(SD_Type != SD_TYPE_MMC) r1 = SD_SendCommand(ACMD23, count, 0x00);//如果目标卡不是MMC卡,启用ACMD23指令使能预擦除r1 = SD_SendCommand(CMD25, sector, 0x00);//发多块写入指令if(r1 != 0x00)return r1; //应答不正确,直接返回sd_cs_0;//开始准备数据传输SPIx_ReadWriteByte(0xff);//先放3个空数据,等待SD卡准备好SPIx_ReadWriteByte(0xff);//--------下面是N个sector写入的循环部分do{//放起始令牌0xFC 表明是多块写入SPIx_ReadWriteByte(0xFC);//放一个sector的数据for(i=0;i<512;i++){SPIx_ReadWriteByte(*data++);}//发2个Byte的dummy CRCSPIx_ReadWriteByte(0xff);SPIx_ReadWriteByte(0xff);//等待SD卡应答r1 = SPIx_ReadWriteByte(0xff);if((r1&0x1F)!=0x05){sd_cs_1; //如果应答为报错,则带错误代码直接退出return r1;}//等待SD卡写入完成if(SD_WaitDataReady()==1){sd_cs_1; //等待SD卡写入完成超时,直接退出报错return 1;}}while(--count);//本sector数据传输完成//发结束传输令牌0xFDr1 = SPIx_ReadWriteByte(0xFD);if(r1==0x00){count = 0xfe;}if(SD_WaitDataReady()) //等待准备好{sd_cs_1;return 1;}//写入完成,片选置1sd_cs_1;SPIx_ReadWriteByte(0xff);return count; //返回count值,如果写完则count=0,否则count=1 }//-----------------------------------------------------------------------------//在指定扇区,从offset开始读出bytes个字节//输入:u32 sector 扇区地址(sector值,非物理地址)// u8 *buf 数据存储地址(大小<=512byte)// u16 offset 在扇区里面的偏移量// u16 bytes 要读出的字节数//返回值:0:成功// other:失败u8 SD_Read_Bytes(unsigned long address,unsigned char *buf,unsigned int offset,unsigned int bytes){u8 r1;u16 i=0;r1=SD_SendCommand(CMD17,address<<9,0);//发送读扇区命令if(r1)return r1; //应答不正确,直接返回sd_cs_0;//选中SD卡if(SD_GetResponse(0xFE))//等待SD卡发回数据起始令牌0xFE{sd_cs_1; //关闭SD卡return 1;//读取失败}for(i=0;i<offset;i++)SPIx_ReadWriteByte(0xff);//跳过offset位for(;i<offset+bytes;i++)*buf++=SPIx_ReadWriteByte(0xff);//读取有用数据for(;i<512;i++) SPIx_ReadWriteByte(0xff); //读出剩余字节SPIx_ReadWriteByte(0xff);//发送伪CRC码SPIx_ReadWriteByte(0xff);sd_cs_1;//关闭SD卡return 0;}。

sd卡数据读写流程

sd卡数据读写流程

sd卡数据读写流程SD卡是一种常见的存储媒介,它具有轻便、易携带、容量大、存储速度快等优势。

SD卡数据读写流程是指将数据从SD卡中读取出来或将数据写入SD卡中的整个过程。

一、SD卡的物理结构SD卡主要由控制器、记忆芯片和接口组成。

控制器负责管理SD卡的读写操作;记忆芯片是存储数据的核心部件,它采用闪存技术,可存储数据并保持数据不易丢失;接口是SD卡与主控制器进行通信的桥梁,一般采用SPI(串行外设接口)或SDIO(SD输入输出)接口。

二、SD卡读写流程1.初始化SD卡当主控制器接通SD卡电源时,首先要进行初始化操作。

初始化操作主要包括向SD卡发送复位命令、读取SD卡的OCR(操作条件寄存器)以及设置SPI或SDIO接口的工作参数等操作。

2.读取SD卡信息在SD卡初始化成功后,主控制器通过SPI或SDIO接口向SD 卡发送命令,读取SD卡ID信息、SD卡容量、SD卡速度等重要参数。

这些信息将在数据读写时起到重要作用。

3.读取文件SD卡上的文件存储在文件系统中,主控制器需要先读取文件系统,找到要读取的文件所在的位置。

一般情况下,文件系统采用FAT32格式,主控制器需要读取文件系统启动区扇区信息,从而找到文件所在扇区及其起始地址。

4.读取数据在找到文件所在位置后,主控制器就可以根据文件系统的信息,向SD卡发送读操作指令,读取文件数据。

读取数据时,主控制器需要根据SD卡的速度、数据传输模式等参数设置接口波特率、时序等参数。

5.写入数据SD卡写数据流程与读数据基本相同,只是主控制器需要向SD卡发送写操作指令,将数据写入SD卡中。

写入数据时,主控制器需要根据SD卡的容量、速度等参数设置写入数据的起始位置、写入数据的长度、写入数据的校验和等参数。

6.关闭SD卡当读写操作完成后,主控制器需要向SD卡发送停止指令,将SD卡彻底关闭。

关闭SD卡可以避免SD卡数据丢失、损坏等问题。

三、SD卡的数据保护SD卡存储的数据非常重要,因此在SD卡的读写过程中,需要采取一定的措施保护数据。

单片机读写SD卡电路设计与程序

单片机读写SD卡电路设计与程序

单片机读写SD卡电路设计与程序摘要:本文设计了单片机读写SD卡电路,从硬件设计到软件实现的过程。

本文以ARM 7为例,描述了设计工作原理,并给出连接图和程序。

关键字:SD卡单片机Abstract: the paper presents the design of the single chip computer literacy SD card circuit, from hardware to software implementation process of design. Based on the ARM and for example, describes the design principle, and gives connection diagram and procedures.Key word: SD card microcontroller中图分类号:TN108.7文献标识码:A文章编号:引言近年来,使用半导体存储器作存储媒体是影音器材一个新的发展热点和潮流。

目前已出现了各种各样的存储卡,如多媒体存储卡(MMC)、安全数字(SD)存储卡、记忆棒(MS)等。

SD卡就是Secure Digital Card--安全数码卡,是由日本松下公司,东芝公司和美国SANDISK公司1999年8月共同开发研制的,具有大容量,高性能,尤其是安全等多种特点的多功能存储卡。

随后并成立一家名为SD-3C的公司负责将相关技术规格授权厂商制造。

并于2000年1月正式成立SD Association,向全世界推广SD内存标准规格,并进行制定SD卡相关应用产品规格及检测规范。

1 系统设计方案1.1系统硬件组成图1系统组成本设计硬件电路采用的整体结构如图1所示。

RS232—HOST(单片机)—SD卡。

其中单片机采用流行的ARM 7 PLC2132,串行接口RS232为标准3线制。

由稳定电压器供给5V电压,单片机通过SPI总线:时钟、输入、输出、片选4个I/O接口控制SD卡的读写操作。

SD卡读写程序设计(二)

SD卡读写程序设计(二)

SD卡读写程序设计(二)一、概述上次已经简单描述了SD卡读写程序的层次设计,今天开始一一实现。

二、命令接口程序设计1、首先添加两个命令:sdrd和sdwr.《在文件tast_uartcmd.c中》#define UartCmdMaxCount 10 //现在支持10个内部命令u8* UartCmdStrTable[UartCmdMaxCount]={ //串口命令字符串"help","cls","ledon","ledoff","time","temp","i2cwr","i2crd","sdrd","sdwr"};2、添加命令处理程序:UartCmdTable[8].UartCmdFunc=UartCmdSDRead;UartCmdTable[9].UartCmdFunc=UartCmdSDWrite;《在文件uartcmd.c中》void UartCmdSDRead(void){}void UartCmdSDWrite(void){} 先定义空函数,编译通过再说。

《在文件uartcmd.h中》void UartCmdSDRead(void);void UartCmdSDWrite(void);然后编译,一次性编译通过。

但是输入help,没有显示sdrd和sdwr命令,在帮助命令里还没有完成。

void UartCmdHelp(void){Uart_PutString("cls ");Uart_PutString("ledon ");Uart_PutString("ledoff ");Uart_PutString("time ");Uart_PutString("temp ");Uart_PutString("i2cwr ");Uart_PutString("i2crd \r\n");Uart_PutString("sdrd "); //以下两句为新添加。

SD卡硬件原理图及其读写程序

SD卡硬件原理图及其读写程序

SD卡硬件原理图及其读写程序2011-03-28 17:45转载自sail_007最终编辑sail_007 最近开始整理以前画过原理图和程序今天先整理出了SD卡的硬件和SPI方式的读写程序。

今后会陆续写把DS1302时钟芯片GPRS模块CAN总线通信PWM数控电压也整理出来。

一方面是想帮自己总结一下另外如果还能帮助到其他的单片机爱好者那也就更好了。

当然水平有限整理出来的东西可能也有许多错误的地方也请高手能指出不胜感激。

先发张SD卡的原理图。

说明我用的是5V单片机SD卡则是3.3v如果直接连接引脚长期使用会影响SD卡寿命。

我一开始选用了普通的光耦触发可能是导通速率不够快无法实现SPI通信后来我就改用9013就行了。

下图上US1是SD卡壳其实1到9引脚对应了SD卡的9个引脚10号引脚是卡插入标志也就是说当有SD卡插入时10号引脚会接3.3v的地这样单片机就可以查询是否有卡了。

在SPI总线模式下CS为主控制器向卡发送的片选信号SCLK为主控制器向卡发送的时钟信号INDataIn为主控制器向卡发送的单向数据信号MISODataOut为卡向主控制器发送的单向数据信号。

程序如下说明我用的是freescale的DP256单片机该单片机有SPI 设备接口只要将其初始化成功便可完成通信设置。

uchar CMD0RespCMD1RespCMD59RespCMD16RespCMD9RespC MD17RespCMD24RespCMD58Resp void SD_Initializevoiduchar csdbuf16TempValue ucharcmdparam4recbuf600resp4resptype uchar sendbuf600 ulong len ulong i ulong BlockAdd SD_InsertDetect Pim.pts.bit.pts70 //cs0 SD_SPIDelay25 Pim.pts.bit.pts71 //cs1 SD_SPIDelay2Pim.ddrs.bit.ddrs70 //pin cs direction Spi0.spicr1.bit.spe0 //spi enable Pim.ddrs.bit.ddrs71 //pin cs directionPim.pts.bit.pts70//cs0 Spi0.spibr.byte0x02 //8MHz31.25kHz0x07-0x00 Spi0.spicr1.bit.mstr1 //master modeSpi0.spicr1.bit.ssoe1 //ss output enable Spi0.spicr1.bit.cpol0//cpol0 //cpol1 070215 Spi0.spicr1.bit.cpha0 //cpha0Spi0.spicr2.byte0x18 //normal drive input pullup TempValueSpi0.spisr.byte//clear SPIF first step TempValueSpi0.spidr.byte//clear SPIF second stepSpi0.spicr1.bit.spe1 //spi enable CMD0RespSD_ResetSDCMD1RespSD_ActiveInit whileCMD1Resp0x01CMD1RespSD_ActiveInit 白开水易拉罐主页博客相册个人档案好友i贴吧看看Ta是谁吧页码1/5Ww2011/6/26/wolf9s/blog/item/47e2a620 212d80268744f98c.htmlvoid SD_SPIDelayuint value uint i for i 0 i valuei SPI_SendByte0xFF // 发送0xFF clock out 0xFF uchar SD_ResetSDvoid uchar param4 0000respSD_SendCmdCMD0 param SD_R1 resp return resp / 函数名称:void SPI_SendByte Name: void SPI_SendByte 功能描述: 通过SPI接口发送一个字节Function: send a byte by SPI interface 输入: INT8U byte: 发送的字节Input: INT8U byte: the byte that will be send 输出: 无Output: NULL / voidSPI_SendByteuchar byte uchar TempValue Spi0.spidr.byte byte / 发送数据放入SPI数据寄存器/ while0 Spi0.spisr.byte 0x80 / 等待SPIF置位即等待数据发送完毕/ / wait for SPIF being set that is wait for finishing of data being send / TempValueSpi0.spidr.byte / 函数名称: INT8U SPI_RecByte Name:INT8U SPI_RecByte 功能描述: 从SPI接口接收一个字节Function: receive a byte from SPI interface 输入: 无Input: NULL 输出: 收到的字节Output: the byte that be received / uchar SPI_RecBytevoid uint ReadCounter ReadCounter0Spi0.spidr.byte 0xFF while0 Spi0.spisr.byte 0x80 / 等待SPIF 置位即等待收到数据/ ReadCounter ifReadCounter25 break / wait for SPIF being set that is wait for being received data / returnSpi0.spidr.byte / 读取收到的字节read the byte received / / 函数名称: //INT8U SD_SendCmd Name: INT8USD_SendCmd 功能描述: 向卡发送命令并取得响应Function: send command to the cardand get a response 输入: INT8U cmd : 命令字Input: INT8U cmd : command byteINT8U param : 命令参数长度为4字节INT8U param :command parameterlength is 4 bytes INT8U resptype : 响应类型INT8U resptype: response type INT8U resp : 响应长度为1-5字节INT8U resp : responselength is 1-5 bytes 输出: 0: 正确0: 错误码Output: 0: right 0: error code / voidSD_SendCmduchar cmd uchar paramuchar resptype uchar resp long irlen uchar tmp Pim.pts.bit.pts70//cs0 SPI_SendBytecmd0x3F 0x40 / 发送命令头和命令字send command header and word / for i 3 i 0 i-- SPI_SendByteparami / 发送参数send parameters / SPI_SendByte0x95 / CRC校验码只用于第1个命令CRConly used for the first command / rlen 0 switch resptype / 根据不同的命令得到不同的响应长度/ / according various commandget the various response length / case 1: rlen 1 break case 2: rlen 2 break case 4: rlen 5 break default:SPI_SendByte0xFF Pim.pts.bit.pts71 break i 0 do / 等待响应响应的开始位为0 / / Wait for a responsea response is a start bitzero / tmp SPI_RecByte i while tmp 0x80 0 iSD_CMD_TIMEOUT for i rlen - 1 i 0 i-- respi tmp tmpSPI_RecByte / 循环的最后发送8clock at the last recycleclock out 8 clock / Pim.pts.bit.pts71//cs1 // return SD_NO_ERR //new statement 页码2/5Ww2011/6/26/wolf9s/blog/item/47e2a620 212d80268744f98c.html/ 函数名称: INT8U SD_ReadBlockName: INT8U SD_ReadBlock 功能描述: 从SD卡中读一个块Function: read a single block from sd card 输入: INT32U blockaddr: 块地址Input: INT32U blockaddr: address of block INT8U recbuf : 接收缓冲区长度512Bytes INT8U recbuf : the buffer of receivelength is 512Bytes 输出: 0: 正确0: 错误码Output: 0: right 0: error code / uchar SD_ReadBlockulong blockaddr uchar recbuf uchar param4resp // if blockaddrsds.block_num // return SD_ERR_OVER_CARDRANGE / 操作超出卡容量范围operate over the card range /SD_PackParamparam blockaddr / 将参数转化为字节形式change the parameter to bytes form / SD_SendCmdCMD17 param SD_R1 resp SD_ReadBlockDataSD_BLOCKSIZE recbuf/ 读出数据read data from sd card / return resp / 函数名称: INT8U SD_ReadBlockData Name: INT8USD_ReadBlockData 功能描述: 从SD卡中读取数据块Function: read block data from sd card 输入: INT32U len : 长度Input: INT32U len : length INT8U recbuf : 接收缓冲区INT8U recbuf : the buffer of receive 输出: 0: 正确0: 错误码Output: 0: right 0: error code / voidSD_ReadBlockDataulong len uchar recbuf uchar tmp ulong i 0 Pim.pts.bit.pts70//cs0 do / 等待接收数据开始令牌0xFE wait for receiving data start token 0xFE / tmp SPI_RecByte iwhiletmp 0xFF i SD_CMD_TIMEOUT for i 0 i len i recbufi SPI_RecByte / 接收数据receive data / i SPI_RecByte i i 0:错误码Output: 0: right 0: error code ucharSD_SetBlockLenulong length uchar param4respretSD_PackParamparam length //将参数转化为字节形式change the parameter to bytes form SD_SendCmdCMD16 paramSD_R1 resp return resp / / 函数名称: void SD_PackParam Name: void SD_PackParam 功能描述: 将32位的参数转为字节形式Function: change 32bit parameter to bytes form 输入: INT8U parameter: 字节参数缓冲区Input: INT8U parameter: the buffer of bytes parameter INT32U value : 32位参数INT32U value : 32bit parameter 输出: 无Output: NULL / void SD_PackParamuchar parameter ulong value valuevalue512 parameter3 ucharvalue 24 parameter2 ucharvalue 16 parameter1 ucharvalue 8 parameter0 ucharvalue / 函数名称: INT8USD_WriteBlock Name: INT8U SD_WriteBlock 功能描述: 向SD卡中写入一个块Function: write a block to sd card 输入: INT32U blockaddr: 块地址Input: INT32U blockaddr: address of block INT8U sendbuf : 发送缓冲区长度512Bytes INT8U sendbuf : the buffer of sendlength is 512Bytes 输出: 0: 正确0: 错误码Output: 0: right 0: error code / ucharSD_WriteBlockulong blockaddr uchar sendbuf 页码3/5Ww2011/6/26/wolf9s/blog/item/47e2a620 212d80268744f98c.html uchar param4resprettmp2 ulong i // if blockaddr sds.block_num // returnSD_ERR_OVER_CARDRANGE / 操作超出卡容量范围operate over the card range / SD_PackParamparam blockaddr / 将参数转化为字节形式change the parameter to bytes form / SD_SendCmdCMD24 param SD_R1 resp / 写单块命令write single block / SD_WriteBlockData0 SD_BLOCKSIZE sendbuf / 写入数据write data / return resp / 函数名称: INT8USD_WriteBlockData Name: INT8U SD_WriteBlockData 功能描述: 向sd卡写数据块Function: write block data to sd card 输入: INT8U bmulti : 是否为多块操作1:是0:否Input:INT8U bmulti : multi blocks operate 1:Y 0:N INT32U len : 长度INT32U len : length INT8U sendbuf: 发送缓冲区INT8U sendbuf : the buffer of send 输出: 0: 正确0: 错误码Output: 0: right 0: error code / void SD_WriteBlockDatauchar bmulti ulong len uchar sendbuf uint i uchar tmp Pim.pts.bit.pts70//cs0 SPI_SendByte0xFF / 开始发送数据之前发送8个clock clock out 8 clk before start / if bmulti 1SPI_SendByteSD_TOK_WRITE_STARTBLOCK_M / 写多块开始令牌start token of write multi blocks / elseSPI_SendByteSD_TOK_WRITE_STARTBLOCK / 写单块开始令牌start token of write single block / for i 0 i len iSPI_SendBytesendbufi / 发送数据send data / SPI_SendBytei 8 0xFF SPI_SendBytei 0xFF / 发送CRC16校验码send CRC16 check code / tmp SPI_RecByte Pim.pts.bit.pts71//cs1 SD_WaitBusy void SD_WaitBusy uchar tmpiPim.pts.bit.pts70//cs0 i0 do / 等待忙结束wait for being busy end / tmp SPI_RecByte i while tmp 0xFF i 10000 / 忙时收到的值为0xFF always receive 0xFF when card is busy /Pim.pts.bit.pts71//cs1 / 函数名称: void SD_HardWareInit Name: void SD_HardWareInit 功能描述: 初始化访问SD卡的硬件条件Function: initialize the hardware condiction that access sd card 输入: 无Input: NULL 输出: 无Output: NULL / uchar SD_InsertDetect uchar InflagifPim.ptp.bit.ptp30//sd insert Inflag1 else Inflag0 return Inflag 类别默认分类添加到搜藏分享到i贴吧浏览57 评论0 上一篇sd卡的读写转下一篇一般SD卡和SDHC卡读写函数 .c -... 最近读者网友评论发表评论姓名哦没他发内容插入表情▼ 闪光字页码4/5Ww2011/6/26/wolf9s/blog/item/47e2a620 212d80268744f98c.html 同时将此文章分享给好友验证码请点击后输入四位验证码字母不区分大小写发表评论�0�82011 Baidu看看Ta是谁吧页码5/5Ww2011/6/26/wolf9s/blog/item/47e2a620 212d80268744f98c.html。

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

前言长期以来,以Flash Memory为存储体的SD卡因具备体积小、功耗低、可擦写以及非易失性等特点而被广泛应用于消费类电子产品中。

特别是近年来,随着价格不断下降且存储容量不断提高,它的应用范围日益增广。

当数据采集系统需要长时间地采集、记录海量数据时,选择SD卡作为存储媒质是开发者们一个很好的选择。

在电能监测以及无功补偿系统中,要连续记录大量的电压、电流、有功功率、无功功率以及时间等参数,当单片机采集到这些数据时可以利用SD作为存储媒质。

本文主要介绍了SD卡在电能监测及无功补偿数据采集系统中的应用方案。

设计方案应用AT89C52读写SD卡有两点需要注意。

首先,需要寻找一个实现AT89C52单片机与SD卡通讯的解决方案;其次,SD卡所能接受的逻辑电平与AT89C52提供的逻辑电平不匹配,需要解决电平匹配问题。

通讯模式SD卡有两个可选的通讯协议:SD模式和SPI模式。

SD模式是SD卡标准的读写方式,但是在选用SD模式时,往往需要选择带有SD卡控制器接口的MCU,或者必须加入额外的SD 卡控制单元以支持SD卡的读写。

然而,AT89C52单片机没有集成SD卡控制器接口,若选用SD模式通讯就无形中增加了产品的硬件成本。

在SD卡数据读写时间要求不是很严格的情况下,选用SPI模式可以说是一种最佳的解决方案。

因为在SPI模式下,通过四条线就可以完成所有的数据交换,并且目前市场上很多MCU都集成有现成的SPI接口电路,采用SPI模式对SD卡进行读写操作可大大简化硬件电路的设计。

虽然AT89C52不带SD卡硬件控制器,也没有现成的SPI接口模块,但是可以用软件模拟出SPI总线时序。

本文用SPI总线模式读写SD卡。

电平匹配SD卡的逻辑电平相当于3.3V TTL电平标准,而控制芯片AT89C52的逻辑电平为5V CMOS 电平标准。

因此,它们之间不能直接相连,否则会有烧毁SD卡的可能。

出于对安全工作的考虑,有必要解决电平匹配问题。

要解决这一问题,最根本的就是解决逻辑器件接口的电平兼容问题,原则主要有两条:一为输出电平器件输出高电平的最小电压值,应该大于接收电平器件识别为高电平的最低电压值;另一条为输出电平器件输出低电平的最大电压值,应该小于接收电平器件识别为低电平的最高电压值。

一般来说,通用的电平转换方案是采用类似SN74ALVC4245的专用电平转换芯片,这类芯片不仅可以用作升压和降压,而且允许两边电源不同步。

但是,这个方案代价相对昂贵,而且一般的专用电平转换芯片都是同时转换8路、16路或者更多路数的电平,相对本系统仅仅需要转换3路来说是一种资源的浪费。

考虑到SD卡在SPI协议的工作模式下,通讯都是单向的,于是在单片机向SD卡传输数据时采用晶体管加上拉电阻法的方案,基本电路如图1所示。

而在SD卡向单片机传输数据时可以直接连接,因为它们之间的电平刚好满足上述的电平兼容原则,既经济又实用。

这个方案需要双电源供电(一个5V电源、一个3.3V电源供电),3.3V电源可以用AMS1117稳压管从5V电源稳压获取。

硬件接口设计SD卡提供9Pin的引脚接口便于外围电路对其进行操作,9Pin的引脚随工作模式的不同有所差异。

在SPI模式下,引脚1(DAT3)作为SPI片选线CS用,引脚2(CMD)用作SPI 总线的数据输出线MOSI,而引脚7(DAT0)为数据输入线MISO,引脚5用作时钟线(CLK)。

除电源和地,保留引脚可悬空。

本文中控制SD卡的MCU是ATMEL公司生产的低电压、高性能CMOS 8位单片机AT89C52,内含8K字节的可反复擦写的只读程序存储器和256字节的随机存储数据存储器。

由于AT89C52只有256字节的数据存储器,而SD卡的数据写入是以块为单位,每块为512字节,所以需要在单片机最小系统上增加一片RAM。

本系统中RAM选用存储器芯片HM62256,容量为32K。

对RAM进行读写时,锁存器把低8位地址锁存,与P2口的8位地址数据构成16位地址空间,从而可使SD卡一次读写512字节的块操作。

系统硬件图如图2所示。

软件设计SPI工作模式SD卡在上电初期自动进入SD总线模式,在此模式下向SD卡发送复位命令CMD0。

如果SD卡在接收复位命令过程中CS低电平有效,则进入SPI模式,否则工作在SD总线模式。

对于不带SPI串行总线接口的AT89C52单片机来说,用软件来模拟SPI总线操作的具体做法是:将P1.5口(模拟CLK线)的初始状态设置为1,而在允许接收后再置P1.5为0。

这样,MCU在输出1位SCK时钟的同时,将使接口芯片串行左移,从而输出1位数据至AT89C52单片机的P1.7(模拟MISO线),此后再置P1.5为1,使单片机从P1.6(模拟MOSI线)输出1位数据(先为高位)至串行接口芯片。

至此,模拟1位数据输入输出便完成。

此后再置P1.5为0,模拟下1位数据的输入输出,依此循环8次,即可完成1次通过SPI总线传输8位数据的操作。

本文的实现程序把SPI总线读写功能集成在一起,传递的val变量既是向SPI写的数据,也是从SPI读取的数据。

具体程序如下:(程序是在Keil uVision2的编译环境下编写)sbit CS=P3^5;sbit CLK= P1^5;sbit DataI=P1^7;sbit DataO=P1^6;#define SD_Disable() CS=1 //片选关#define SD_Enable() CS=0 //片选开unsigned char SPI_TransferByte(unsigned char val){unsigned char BitCounter;for(BitCounter=8; BiCounter!=0; BitCounter--){ CLK=0;DataI=0; // writeif(val&0x80) DataI=1;val<<=1;CLK=1;if(DataO)val|=1; // read}CLK=0;return val;}SD卡的初始化对SD卡进行操作首先要对SD卡进行初始化,初始化的过程中设置SD卡工作在SPI模式,其流程图如图3所示。

在复位成功之后可以通过CMD55和ACMD41判断当前电压是否在工作范围内。

主机还可以继续通过CMD10读取SD卡的CID寄存器,通过CMD16设置数据Block长度,通过CMD9读取卡的CSD寄存器。

从CSD寄存器中,主机可获知卡容量,支持的命令集等重要参数。

SD 卡初始化的C语言程序如下:unsigned char SD_Init(void){ unsigned char retry,temp;unsigned char i;for (i=0;i<0x0f;i++){ SPI_TransferByte(0xff); //延迟74个以上的时钟}SD_Enable(); //开片选SPI_TransferByte(SD_RESET); //发送复位命令SPI_TransferByte(0x00);SPI_TransferByte(0x00);SPI_TransferByte(0x00);SPI_TransferByte(0x00);SPI_TransferByte(0x95);SPI_TransferByte(0xff);SPI_TransferByte(0xff);retry=0;do{ temp=Write_Command_SD(SD_INIT,0);//发送初始化命令retry++;if(retry==100) //重试100次{SD_Disable(); //关片选return(INIT_CMD1_ERROR);//如果重试100次失败返回错误号}}while(temp!=0);SD_Disable(); //关片选return(TRUE); //返回成功}数据块的读写完成SD卡的初始化之后即可进行它的读写操作。

SD卡的读写操作都是通过发送SD卡命令完成的。

SPI总线模式支持单块(CMD24)和多块(CMD25)写操作,多块操作是指从指定位置开始写下去,直到SD卡收到一个停止命令CMD12才停止。

单块写操作的数据块长度只能是512字节。

单块写入时,命令为CMD24,当应答为0时说明可以写入数据,大小为512字节。

SD卡对每个发送给自己的数据块都通过一个应答命令确认,它为1个字节长,当低5位为00101时,表明数据块被正确写入SD卡。

在需要读取SD卡中数据的时候,读SD卡的命令字为CMD17,接收正确的第一个响应命令字节为0xFE,随后是512个字节的用户数据块,最后为2个字节的CRC验证码。

可见,读写SD卡的操作都是在初始化后基于SD卡命令和响应完成操作的,写、读SD 卡的程序流程图如图4和图5所示。

结束语实验结果表明单片机使用12MHz的晶体振荡器时,读写速度和功耗都基本令人满意,可以应用于对读写速度要求不高的情况下。

本文详细阐述了用AT89C52单片机对SD卡进行操作的过程,提出了一种不带SD卡控制器,MCU读写SD卡的方法,实现了SD卡在电能监测及无功补偿数据采集系统中的用途。

了解了指令的形式和具体的控制内容,下面主要解决的就是MCU与SD卡的通信问题,通信主要需要注意下面的问题:(1)供电电压:必须是3.3V(2) 通信模式的切换:SD卡有两种通信模式:SPI模式和SD模式,默认情况下的通信模式是SD模式,但是我们常用的模式是SPI模式,这就需要一个切换模式的方法,具体的实现方法在其他地方也都有介绍,其关键的地方就是先上电延时大于74个时钟周期后发送复位命令,复位成功(接收到0x01的响应)后,连续发送CMD55和ACMD41,直到响应0X00为止,此时SD卡已经进入SPI模式。

(3)上面所说的发送复位命令(CMD0)以及CMD55和ACMD41要有具体的实现方法,需要解决的就是时序问题,下图就为复位的时序图,只要能够按照下图的时序进行操作,肯定能够复位成功.本复位分为(1)上电,(2)延时74个周期以上,(3)发送命令CMD0,(4)发送命令参数0X0000,(5)发送CRC校验0X95,(6)等待响应(7)响应0X01此时得到正确响应复位成功,否则重复以上操作直到成功为止。

介绍复位的同时其他的命令也和复位命令类似,只是根据命令的作用不同有着不同的响应类型和不同的后续操作,下面给出集中常用命令的时序图。

(1)读CID寄存器时序图说明:当发送命令并得到响应0X00后就开始准备接收CID寄存器中的内容,此时只要接收到起始标志0XFE后,之后的16个字节的内容即为CID寄存器的内容。

(2)读CSD寄存器内容时序和读CID的类似,只是此时发送的命令为CMD9SD卡数据的读写是以块为单位:默认情况下一块的大小为512字节(3) 读SD卡一个块(512字节)时序(4) 写一个块(512字节)时序图1.SD卡的命令格式:SD卡的指令由6字节(Byte)组成,如下:Byte1:0 1 x x x x x x(命令号,由指令标志定义,如CMD39为100111即16进制0x27,那么完整的CMD39第一字节为01100111,即0x27+0x40)Byte2-5:Command Arguments,命令参数,有些命令没有参数Byte6:前7位为CRC(Cyclic Redundacy Check,循环冗余校验)校验位,最后一位为停止位0 2.SD卡的命令SD卡命令共分为12类,分别为class0到class11,不同的SDd卡,主控根据其功能,支持不同的命令集如下:Class0 :(卡的识别、初始化等基本命令集)CMD0:复位SD 卡.CMD1:读OCR寄存器.CMD9:读CSD寄存器.CMD10:读CID寄存器.CMD12:停止读多块时的数据传输CMD13:读Card_Status 寄存器Class2 (读卡命令集):CMD16:设置块的长度CMD17:读单块.CMD18:读多块,直至主机发送CMD12为止.Class4(写卡命令集) :CMD24:写单块.CMD25:写多块.CMD27:写CSD寄存器.Class5 (擦除卡命令集):CMD32:设置擦除块的起始地址.CMD33:设置擦除块的终止地址.CMD38: 擦除所选择的块.Class6(写保护命令集):CMD28:设置写保护块的地址.CMD29:擦除写保护块的地址.CMD30: Ask the card for the status of the write protection bitsclass7:卡的锁定,解锁功能命令集class8:申请特定命令集。

相关文档
最新文档