单片机读写SD卡最简单最基本的程序

发布者:灵感火花最新更新时间:2015-11-09 来源: eefocus关键字:单片机  读写SD卡 手机看文章 扫描二维码
随时随地手机看文章
  单片机读写SD卡最简单最基本的程序
/>
/>  2010-11-01 21:14

  转载自 刀禁凯森

  最终编辑 zlulu2008

  处理器: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无法被电脑识别,需格式化。

  

  

  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); //写命令CMD17

  rsp = Get_rsp(R1); //获取答应

  send_clk();

  }

  if(i > 99) //如果命令超时,则执行超时处理

  {

  SD_desel();

  Uart_Printf("fail in writing CMD17 ");

  return WR_SGL_BLK_ERR;

  }

  spi_ro_mode();

  send_clk(); //发送8个clk

  read_data(rx_buf); //读取512字节

  SD_desel();

  Uart_Printf("succeed in reading the %dst block!!! ", blk_addr);

  return 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); //写命令CMD24

  rsp = Get_rsp(R1); //获取答应

  send_clk();

  }

  if(i > 99) //如果命令超时,则执行超时处理

  {

  SD_desel();

  Uart_Printf("fail in writing CMD17 ");

  return WR_SGL_BLK_ERR;

  }

  spi_ro_mode();

  send_clk(); //发送8个clk

  write_data(tx_buf); //读取512字节

  SD_desel();

  Uart_Printf("succeed in writing a block!!! ");

  return NO_ERR;

  }

  

  U8 SD_Init(void)

  {

  U16 rsp = 1;

  U8 i = 0;

  spi_port_init(); //初始化spi端口

  spi_low_speed(); //初始化时SPI的速度必须低于400khz

  spi_ro_mode(); //只读模式

  SD_sel(); //选择SD卡

  for (i = 0;i < 10; i++) //发送至少75个clk

  send_clk();

  while(rsp && (i++ < 100))

  {

  write_cmd(CMD0, 0); //写命令CMD0

  rsp = Get_rsp(R1); //获取答应

  if (rsp == 1) //rsp为0则初始化成功http://www.tea176.com,为1则继续写CMD0

  break;

  send_clk();

  }

  SD_desel();

  if (i > 99) //初始化超时处理

  {

  Uart_Printf("fail in writing CMD0!!! ");

  return INIT_FAIL;

  }

  i=0;

  SD_sel();

  while(rsp && (i++ < 100))

  {

  write_cmd(CMD1, 0); //写CMD1

  rsp = Get_rsp(R1); //获取答应

  send_clk();

  }

  SD_desel();

  if (i > 99)

  {

  Uart_Printf("fail in writing CMD1!!! ");

  return INIT_FAIL;

  }

  Uart_Printf("SD card init OK!!! ");

  spi_high_speed(); //初始化工作全部完毕,SPI进入模式模式

  spi_rt_mode();

  return NO_ERR;

  }

  

  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!!! ");

  return ;//GET_INFO_ERR;

  }

  if (read_register(16, csd) != NO_ERR)

  {

  SD_desel();

  return ;

  }

  SD_desel();

  Uart_Printf("SD information : ");

  if (csd[0] & 0x40 ==0x40)

  {

  Uart_Printf("version 2.0 ");

  Uart_Printf("size is : %d ",1024 * (csd[8]<<8 + csd[9]));

  }

  else

  {

  Uart_Printf("version 1.x ");

  Uart_Printf("size is : %d MByte ", ((((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 ",1<<(csd[5]&0x0f));

  }

  

  

  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); //命令最高两位必须是01

  for(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=(char)(addr >> (24 - 8 * i));

  spi_write_byte((cmd & 0x3F) | 0x40); //命令最高两位必须是01

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

  spi_write_byte(temp); //发送地址,共4个字节

  spi_write_byte(0xff); //非CMD0,则无需CRC校正,默认为0xFF

  }

  }

  

  U16 Get_rsp(U8 type)

  {

  U16 rsp, temp;

  spi_ro_mode(); //spi只读模式

  send_clk(); //先发送8个clk

  rsp = 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;

  }
[page]
  

  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 = spi_read_byte();

  for(i = 0; i < 2; i++) //读两个CRC校正码

  send_clk();

  send_clk(); //读结束字节

  }

  

  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);

  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!!! ");

  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!!! ");

  return rsp;

  }

  if (rsp != 0xfe)

  {

  buffer[0] = rsp;

  i = 1;

  }

  else

  i = 0;

  for( ; i < len; i++)

  buffer = spi_read_byte();

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

  send_clk();

  send_clk();

  return NO_ERR;

  }

  

  

  void send_clk()

  {

  rSIOCON |= (1 << 3); //使能SPI

  while (!(rINTPND & BIT_SIO)); //等待发送完毕

  rI_ISPC|=BIT_SIO; //清除中断标志

  }

  

  void spi_write_byte(U8 dat)

  {

  rSIODAT = dat;

  send_clk(); //SPI发送

  }

  

  U8 spi_read_byte(void)

  {

  send_clk(); //SPI发送

  return rSIODAT;

  }

  

  void spi_port_init()

  {

  rIVTCNT = 0;

  rPCONF = (rPCONF & 0xe3ff) | 0x1B0C00; //除了CLK,茶叶MISO,MOSI外,不改变其他位

  rPUPF |= 0x160; //使能MISO的上拉电阻

  }

  

  #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卡最简单最基本的程序

上一篇:51 avr pic 单片机比较
下一篇:基于单片机计算器的汇编程序

推荐阅读最新更新时间:2024-03-16 14:38

HMAC认证协议的单片机实现
摘要:HMAC是一种基于密钥的Hash算法的认证协议,可以应用于电子商务领域。我们通过国有自主知识产权的单片机ZQ032SA,实现了以MD5算法为核心的HMAC协议,并把它调用于IP电话计费认证系统。 关键词:HMAC ZQ032SA(6805) MD5 IP电话 引言 在开放的通信和计算机系统中,建立安全可靠的电子商务平台是十分重要的。通常需要通过加密的方法对客户的有关信息,如密码、合同等加以保护,使之不被盗取或篡改。当客户提出服务申请时,必须对客户身份的合法性、报文的完整性进行确认。 HMAC(Keyed-Hashing for Message Authentication)是一个公开的协议。它是一种基于密钥的报文完
[应用]
基于单片机的轨道压力测试仪的设计与实现
  轨道电路是信号联锁的室外重要设备,起着保证行车和调车作业安全的作用。它能监督检查某一固定区段内的线路(包括站线)是否有列车运行、调车作业或车辆占用的情况,并能显示该区段内的钢轨是否完整。它是以钢轨为导线,轨缝间用接续线连续起来,一端接电源,另一端连接受电器,通过轨道电流来工作。   轨道电路能否正常工作直接影响到列车的安全行驶,因此,对轨道电路的检测尤为重要,目前市场上的检测设备还很少,而且普遍存在功耗大,价格昂贵,体积大等不足。为此,本文通过对轨道电路分析研究,设计一种高精度的压力测试仪器来模拟火车对轨道的压力,从而验证轨道电路的性能。    系统的组成及其工作原理   本系统以PIC16F876A单片机为核心,通过软
[测试测量]
基于<font color='red'>单片机</font>的轨道压力测试仪的设计与实现
51单片机解密红外遥控器
在这里我仅把一些关键的带出来 关于硬件电路 那么抛开那么多文字介绍 最后意思就是说 你家里的遥控板 也就是发射部分 是把所有的封装好了的 比如键盘矩阵、编码调制、LED红外发送器 等等 那么接受部分 SM0038 3个脚 一个脚地 一个脚电源 一个脚信号脚 接到 单片机随便个P口上(此处是P3。6) OK 硬件部分就搞定了当然还有数码管显示 ,这些肯定不用说你都能搞定吧,这些东东都有,所以就不用自己去搭电路那么麻烦了),那么 我们想 我们按一下遥控板 大家看到 有个灯闪了一下 然后OVER 那么 我们现在要做的就是在灯闪了那一下之后让 单片机来读它的键码 然后不同的键码来干不同的事 ,本文 是向大家解释一种方法 当然如果你知道
[单片机]
51<font color='red'>单片机</font>解密红外遥控器
STM32单片机的通用定时器
STM32中的定时器有多种,按功能分成2个高级控制器定时器,4个普通定时器,2个基本定时器,2个看门狗定时器,1个系统滴答定时器SysTick。 定时器的关键是定时时间的计算。比如用定时器控制继电器的开关的时候,需要延时一段时间才关闭或者开启,这时候离不开定时器定时。 通用定时器定时时间计算。1秒中断的基本实现: 通用定时器模块的入口时钟经过分频得到计数器的时钟,用CK_CNT表示,预分频器的系数为:TIMx_PSC,当TIMx_PSC=0时,表示不分频,=1时,2分频。以此类推。 公式为:CK_CNT=fclk_PSC/(PSC +1),其中PSC最大为65535. 其次是TIM5计数器的计数值的设置,TIM
[单片机]
STM32单片机常用库函数
1.GPIO初始化函数 用法: voidGPIO_Configuration(void) { GPIO_InitTypeDefGPIO_InitStructure;//GPIO状态恢复默认参数 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_标号|GPIO_Pin_标号; //管脚位置定义,标号可以是NONE、ALL、0至15。 GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//最高输出速度为50MHz GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出 GPIO_Init(GPIOC,&GPIO_I
[单片机]
SEPTNY256型单片机开关电源及其应用
1 TNY256的性能特点   ·内置自动重启电路,不需外接元件,一旦发生输出短路或控制环开路故障,可将占空比降低以保护芯片。   ·在输入直流高压电路中,不需要使用瞬态电压抑制器构成的钳位保护电路,仅用简单的RC吸收回路即可衰减视频噪声。   ·输入欠压检测电路仅需外接1只电阻,目的是在上电时将片内的功率MOSFET关断,直到直流输入电压VI达到欠压保护门限电压(100V)为止;正常工作后若VI突然降低,对芯片也能起到保护作用。   ·开关频率抖动可降低电磁辐射。   ·输入电压范围宽(85~265VAC或120~375VDC)且交、直流两用。效率高,265VAC输入时的空载功耗低于100mW。   ·控制方
[单片机]
单片机与eView触摸屏Modbus协议通信方法
Modbus协议由于其具有开放性、透明性、成本低、易于开发等特点,已成为当今工业领域通信协议的首选。 本文介绍了一种基于Modbus通信协议的eView触摸屏与常用的51单片机的通信方法。该方法通过C51编程实现Modbus通信,在51系列单片机上具有通用性,有一定的借鉴作用。 工业控制中经常需要观察系统的运行状态或者修改运行参数。触摸屏能够直观、生动地显示运行参数和运行状态,而且通过触摸屏画面可以直接修改系统运行参数,人机交互性好。单片机广泛应用于工控领域中,与触摸屏配合,可组成良好的人机交互环境。 触摸屏与单片机通信,需要根据触摸屏采用的通信协议为单片机编写相应的通信程序。Modbus协议是美国Mo
[单片机]
<font color='red'>单片机</font>与eView触摸屏Modbus协议通信方法
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved