前段时间在51上模拟SPI实现了对SD卡的读取,效果还算不错,最近将其移植到STM32上,不过使用硬件SPI和使用软件SPI还是有差别的。

代码如下:

void User_SPIInit(void)
{GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1,ENABLE);  //使能时钟GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);  SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;    //双线全双工SPI_InitStructure.SPI_Mode=SPI_Mode_Master;  //主模式SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;  //8位数据SPI_InitStructure.SPI_CPOL=SPI_CPOL_High;   //这里要注意,一定要配置为上升沿数据有效,因为SD卡为上升沿数据有效SPI_InitStructure.SPI_CPHA=SPI_CPHA_2Edge;  SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_256;SPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial=7; SPI_Init(SPI1,&SPI_InitStructure);SPI_Cmd(SPI1,ENABLE);
}

SPI初始化以后就可以写SPI读写函数了,以下两个函数参照了网上的资料,出处找不到了,但是这两个函数帮了我大忙,再次感谢提供资料的无名者

void SD_WriteByte(unsigned char data)
{uint16_t temp;temp=data;while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE )==RESET);SPI_I2S_SendData(SPI1,temp);while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE )==RESET);SPI_I2S_ReceiveData(SPI1);
}
unsigned char SD_ReadByte(void)
{unsigned char temp;while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE )==RESET);SPI_I2S_SendData(SPI1,0xFF);while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE )==RESET);temp=SPI_I2S_ReceiveData(SPI1);return temp;
}

有了上面两个函数,问题就好解决了,下面实现发送SD命令函数

unsigned char SD_SendCmd(unsigned char *Cmd)  //Cmd为unsigned char Cmd[6]数组,存放SD固定6字节命令
{unsigned char i,temp;temp=0xFF;   //赋予一个初值for(i=0;i<6;i++)SD_WriteByte(CMD[i]);   //发送6字节命令do{temp=SD_ReadByte();  //一直读SD的应答字节,其实应答字节数量不定,这里简化只收取第一个应答字节,赋temp为0xFF主要因为发现所有应答字节序列的第一个字节不  //会是0xFF}while(temp==0xFF);return temp;
}

发送命令函数完成后下面就该是SD_Init()函数了

unsigned char SD_Init(void)
{unsigned char i,temp;for(i=0;i<200;i++)          //SD卡要求复位前至少发送74个clock,这里我发了很多,足够多SD_WriteByte(0xFF);temp=0x00;CMD[0]=0x40;   //发送复位命令CMD0,CMD[1]-CMD[4]初始化为0,这里不用再写了,因为CMD0不需要参数CMD[5]=0x95;do{temp=SD_SendCmd(CMD);  }while(temp!=0x01);     //不断发送CMD0,直到返回0x01,即SD卡的Idle状态(我设置的无论何时SD卡CSS始终为低电平)temp=0x03;  //发送指令CMD55和指令ACMD41CMD[5]=0xFF;do{CMD[0]=0x77;  //CMD55temp=SD_SendCmd(CMD);CMD[0]=0x69;  //ACMD41temp=SD_SendCmd(CMD);}while(temp!=0x00);     //循环发送CMD55和ACMD41,直到SD卡返回0x00,即初始化完成且进入到SPI模式,注意在整个所有的过程中,SD卡的CSS时钟为低电平return temp;  //当然,返回0x00则SD卡初始化成功
}

既然SD卡初始化成功,下面就好说了,下面实现读取一个512字节的块和写入512字节的块

void  SD_Read_SigleBlock(unsigned long addr,unsigned char *ptr)   //addr为4字节地址,这里必须为512的整数倍,ptr为大于512字节的接受缓冲区指针,必须为byte
{unsigned char temp;unsigned int i=0;temp=0xFF;CMD[0]=0x51;CMD[4]=addr;addr=addr>>8;CMD[3]=addr;addr=addr>>8;CMD[2]=addr;addr=addr>>8;CMD[1]=addr;CMD[5]=0xFF;do{temp=SD_SendCmd(CMD);}while(temp!=0x00);         //直到返回读取单块命令的正确应答字节,即返回0x00,说明命令发送成功,发送成功后就要读取SD发送的数据了do{temp=SD_ReadByte();}while(temp!=0xFE&&temp!=0xFC);    //读取SD卡发送的数据,不断的读取,直到读到SD发送的数据开始信号,即0xFE或0xFC,再往下就是512字节的正式数据for(i=0;i<512;i++)ptr[i]=SD_ReadByte();       //读取512字节的正式数据temp=SD_ReadByte();        //下面还要读取两个字节的CRC校验数据,SD的SPI模式下除了CMD0的CRC有效外,其他CRC校验都无效temp=SD_ReadByte();
}
void SD_Write_SigleBlock(unsigned long addr,unsigned char *ptr)  //参数addr为写入数据的地址,必须为512整数倍;ptr为512字节的发送缓冲区指针,必须为byte
{unsigned char temp;unsigned int i=0;temp=0xFF;CMD[0]=0x58;CMD[4]=addr;addr=addr>>8;CMD[3]=addr;addr=addr>>8;CMD[2]=addr;addr=addr>>8;CMD[1]=addr;CMD[5]=0xFF;do{temp=SD_SendCmd(CMD);}while(temp!=0x00);   //循环发送写单块命令,直到返回正确应答信号0x00SD_WriteByte(0xFE);   //给SD卡发送正式数据的开始字节信号0xFE或0xFC,这里我选取0xFEfor(i=0;i<512;i++)SD_WriteByte(ptr[i]);   //给SD卡发送要写的512字节的正式数据SD_WriteByte(0xFF);   //发送两字节的CRC校验数据,虽说没有用,但形式上还是要发送的SD_WriteByte(0xFF);
}

以上都完成后,我们就可以操作SD卡了

unsigned char data[512];unsigned int i=0;void mian()
{for(i=0;i<512;i++)data[i]=0xFF;SD_Write_SigleBlock(0x00000000,data);for(i=0;i<512;i++)data[i]=0;SD_Read_SigleBlock(0x00000000,data);//在这里检查data里的内容是否都为0xFF即可,如果为0xFF,说明一切成功,否则,要检查了while(1);
}

http://www.voidcn.com/article/p-orspydgx-bkz.html

STM32 SPI方式读写SD卡相关推荐

  1. SPI方式读写SD卡速度有多快?

    很久没有写公众号了,一方面忙,另一方面也不知道写些什么内容,大家如果有想了解的(前提是我也懂),可以后台发送给我. 今天主要来测试一下SPI读写SD卡的速度.SD卡是一个嵌入式中非常常用的外设,可以用 ...

  2. STM32使用SPI方式读写SD 卡

    掌握SD卡协议原理,用STM32F103 完成对SD卡的数据读取(FAT文件模式). 文章目录 一.前言 1.SD卡 2.FATFS 二.工程分析 1.代码分析 2.连线 3.编译工程并烧录 4.验证 ...

  3. STM32开发板入门教程(十三) - SPI模式读写SD卡

    功能介绍 :使用SPI模式 读写SD卡block数据 可通过串口发送到PC机查看 SD卡是Secure Digital Card卡的简称,直译成汉语就是"安全数字卡",是由日本松下 ...

  4. STM32CubeMX+SPI+FATFS读写SD卡

    一.软件硬件说明 软件:STM32CubeMX V6.6.1 /KEIL5 V5.29 硬件:正点原子mini开发板,SD卡,通过SPI方式驱动SD卡,用的是SPI1接口 以上内容来源于正点原子min ...

  5. SPI协议读写SD卡介绍

    前言 在前面的文章中,我们主要介绍了如何利用SDIO协议对SD卡进行读写操作的流程及注意事项.虽然SDIO协议读写SD卡的效率很高,但是,操作却比较麻烦,另外,还需要使用的芯片具有SDIO外设.这对于 ...

  6. 以 SPI 方式获取 SD 卡容量(V2.0)

    下面是 SD 卡 V2.0 协议的 CSD 寄存器内容,来自官方手册: 单片机如何确定当前的 SD 卡遵循 V2.0 协议 CSD 寄存器为 128 个位,即 16 个字节.通过检测 CSD 寄存器的 ...

  7. SDIO读写SD卡速度有多快?

    前两天测试了SPI方式读写SD卡的速度<SPI方式读写SD卡速度测试>,今天来测试一下SDIO方式的读写速度. 测试条件: 单片机:STM32F407VET6 编译环境:MDK 5.30+ ...

  8. SPI读写SD卡速度有多快?

    SD卡是一个嵌入式中非常常用的外设,可以用于存储一些大容量的数据.但用单片机读写SD卡速度一般都有限(对于高速SD卡,主要是受限于单片机本身的接口速度),在高速.实时数据存储时可能会有影响.但具体速度 ...

  9. STM32利用SPI读写SD卡的程序详解

    STM32利用SPI读写SD卡的一些程序详解 关于SD卡的基础知识这里不做过多陈述,如果有对这方面感兴趣的朋友可以直接百度一下,有很多讲SD卡的文章,这里主要是针对SD卡的读写程序实现做一些详细说明. ...

最新文章

  1. 关于python3与python2同时存在情况下导入pyqt失败解决记录
  2. Promise 的使用
  3. 【Java 集合】Java 集合的线程安全性 ( 加锁同步 | java.utils 集合 | 集合属性 | java.util.concurrent 集合 | CopyOnWrite 机制 )
  4. Hadoop YARN:调度性能优化实践【转】
  5. 图片任意放大缩小 插件
  6. 翻译题(map使用)
  7. 微信大改版,更新前必看的4个东西
  8. mysql 数据导入导出说明
  9. python 面向对象编程、别人么样用_Python 中的面向对象没有意义
  10. 提高自己社会竞争力的书籍
  11. 来了来了,2020 首场 Meetup ,可!
  12. “拖延症”的良方-对于追求完美,自制力差,情绪化的人很受用
  13. Java 编程练习之:101-200之间的素数
  14. windows搭建nginx + php环境
  15. 【开源夏令营优秀开题报告】专题之三-云与大数据合集
  16. 最后防线:三款开源HIDS应用对比评估
  17. 性能测试工具的 Coordinated Omission 问题
  18. 前端页面复制粘贴插件Clipboard的使用
  19. java计算机毕业设计红色景点自驾游网站管理系统MyBatis+系统+LW文档+源码+调试部署
  20. 汇川AM402、H3U和上位机C#ModebusTcp通讯

热门文章

  1. 【入门】1536- 前端 Flutter 入门指南
  2. 优秀的web前端工程师需要哪些软技能
  3. 计算机服务器排名,2019服务器CPU天梯图 多路CPU性能排名
  4. Synergistic Saliency and Depth Prediction for RGB-D Saliency Detection
  5. python 领英爬虫
  6. python修改sheet名称_openpyxl修改sheet名,sheet颜色,删除sheet的方法
  7. 有了解arm嵌入式主板与x86主板的优势和劣势的吗?
  8. Subversive or Subclipse
  9. 判定一棵二叉树是否是二叉搜索树
  10. 记一次失败的《将视频中的音频转换成文字》的经历