完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
附上源程序,功能比较简单,只能实现简单的读写一个扇区的字节,后续会附上更完整的功能:
最需要注意的是:在实现硬件连接上,一定要将主芯片的IO接到SD卡的OI,理由自己想吧…… /*写一个字节函数*/ u8 SpiWriteByte(u8 TxData) { u8 RxData; SPI1BUF = TxData; //待发送数据装载待发送寄存器中 while(!SPI1STATbits.SPITBF); //等待接收完成 SPI1BUF = 0xFF; while(!SPI1STATbits.SPIRBF); RxData = SPI1BUF; return RxData; //IFS0bits.SPI1IF = 0; //清零中断标志 } /*发送命令函数*/ u8 SdSendCommand(u8* cmd) { u8 time, r; SpiWriteByte(cmd[0]); //写入序列号 SpiWriteByte(cmd[1]); //数据段第4个字节 SpiWriteByte(cmd[2]); //数据段第3个字节 SpiWriteByte(cmd[3]); //数据段第2个字节 SpiWriteByte(cmd[4]); //数据段第1个字节 SpiWriteByte(cmd[5]); //CRC校验和 /*获取16为的回应*/ SpiWriteByte(0xFF); time = 0; do { r = SpiWriteByte(0xFF); //获取后8位的回应 time ++; }while((r == 0xFF) && (time < 100)); return r; //返回状态位 } /*SD卡的初始化*/ u8 SdInit(void) { u8 i, time, r1 = 0xFF; u8* pcmd; //用于获取数组首地址 /*初始化SPI的IO口和SPI模式*/ Spi1Init(); u8 cmd0[6] = {0x40, 0x00, 0x00, 0x00, 0x00, 0x95}; //CMD0使SD卡进入IDLE状态 u8 cmd16[6] = {0x50, 0x00, 0x00, 0x02, 0x00, 0x01}; //CMD16,设置扇区大小为512字节 u8 cmd55[6] = {0x77, 0x00, 0x00, 0x00, 0x00, 0x01}; //SD卡使用CMD55+ACMD41来进行初始化 u8 acmd41[6] = {0x69, 0x00, 0x00, 0x00, 0x00, 0x01}; /*SD卡复位,进入SPI模式,使用CMD0*/ CS = 1; //发送74个时钟之前要禁止SD卡 for(i = 0; i < 10; i ++) //在向SD卡发送数据之前,必需先SD发送至少74个时钟 { SpiWriteByte(0xFF); //发送了80个时钟 } /*发送CMD0进行复位*/ time = 0; CS = 0; do { pcmd = cmd0; r1 = SdSendCommand(pcmd); //写入CMD0 time ++; //用来计时是否超时 }while((r1 != 0x01) && (time < 200)); if(time >= 200) { return (INIT_CMD0_ERROR); //CMD0写入失败 } CS = 1; r1 = 0xFF; //清楚r1返回标志位 SpiWriteByte(0xFF); //写入指令后附加8个填充时钟 /*发送CMD55+ACMD41对SD卡进行初始化*/ CS = 0; time = 0; do { pcmd = cmd55; SdSendCommand(pcmd); //写入CMD55 pcmd = acmd41; r1 = SdSendCommand(pcmd); //写入命令ACMD41 time ++; }while((r1 != 0) && (time < 200)); if(time >= 200) { return INIT_ACMD41_ERROR; } CS = 1; r1 = 0xFF; SpiWriteByte(0xFF); //写入指令后附加8个填充时钟 /*发送CMD16,设置SD卡块的大小为512字节*/ CS = 0; time = 0; do { pcmd = cmd16; r1 = SdSendCommand(pcmd); time ++; }while((r1 != 0) && (time < 200)); if(time >= 200) { return INIT_CMD16_ERROR; } CS = 1; r1 = 0xFF; SpiWriteByte(0xFF); /*SD卡初始化结束后需要转为高速模式*/ SPI1CON1bits.SPRE = 6; //辅助预分频比为2:1 SPI1CON1bits.PPRE = 2; //主预分频比为4:1 return 0; } /*写一个扇区*/ u8 SDWriteSector(u32 sector, u8* buffer) { u8 r1 = 1; u8* pcmd; u16 retry, i, j; u8 cmd24[6]={0x58, 0x00, 0x00, 0x00, 0x00, 0xFF}; //向SD卡中单个扇区(512字节)写入数据,用CMD24 /*将扇区地址转换为字节地址*/ sector = sector >> 9; /*将字节地址加载到命令CMD24中*/ cmd24[1] = sector >> 24; cmd24[2] = sector >> 16; cmd24[3] = sector >> 8; cmd24[4] = sector; /*发送CMD24写命令*/ CS = 0; retry = 0; do { pcmd = cmd24; r1 = SdSendCommand(pcmd); //写入CMD24 retry ++; }while((r1 != 0x0) && (retry < 200)); if(retry >= 200) { return INIT_CMD24_ERROR; //写入CMD24失败 } //写入3个空数据,等待SD卡准备好 SpiWriteByte(0xFF); SpiWriteByte(0xFF); SpiWriteByte(0xFF); SpiWriteByte(0xFE); //发开始符 /*发送512个字节*/ for(i = 0; i < 4; i ++) { for(j = 0; j < 126; j ++) { SpiWriteByte(*buffer); buffer ++; } } /*16位CRC校验*/ SpiWriteByte(0xFF); SpiWriteByte(0xFF); while((r1 = SpiWriteByte(0xFF)) == 0xFF); //等待SD卡响应 if((r1 & 0x1f) != 0x05) //如果返回值是 XXX00101 说明数据已经被SD卡接收了 { return 1; } /*等到SD卡不忙*/ while(SpiWriteByte(0xFF) != 0xFF); CS = 1; SpiWriteByte(0xFF); //写入指令后附加8个填充时钟 return 0; } /*读一个扇区*/ u8 SDReadSector(u32 sector, u8* buffer) { u8 r1 = 1; u8* pcmd; u16 retry, i, j; u8 cmd17[6] = {0x51, 0x00, 0x00, 0x00, 0x00, 0xFF}; //从SD卡中单个扇区(512字节)读取数据,用CMD17 u8 cmd12[6] = {0x1C, 0x00, 0x00, 0x00, 0x00, 0x01}; //CMD12,强制停止命令 /*将扇区地址转换为字节地址*/ sector = sector >> 9; /*将字节地址加载到命令CMD24中*/ cmd17[1] = sector >> 24; cmd17[2] = sector >> 16; cmd17[3] = sector >> 8; cmd17[4] = sector; /*发送CMD17写命令*/ CS = 0; retry = 0; do { pcmd = cmd17; r1 = SdSendCommand(pcmd); //写入CMD17 retry ++; }while((r1 != 0x0) && (retry < 200)); if(retry >= 200) { return INIT_CMD17_ERROR; //写入CMD17失败 } /*写入3个空数据,等待SD卡准备好*/ SpiWriteByte(0xFF); SpiWriteByte(0xFF); SpiWriteByte(0xFF); while(SpiWriteByte(0xFF) != 0xFE); //等待SD卡读准备 /*读取SD卡buffer扇区中的512个字节*/ for(i = 0; i < 4; i ++) { for(j = 0; j < 128; j ++) { *buffer = SpiWriteByte(0xFF); //获取数据到buffer中 buffer ++; } } /*16位CRC校验*/ SpiWriteByte(0xFF); SpiWriteByte(0xFF); /*写12号命令终止数据读取*/ pcmd = cmd12; SdSendCommand(pcmd); CS = 1; SpiWriteByte(0xFF); //写入指令后附加8个填充时钟 return 0; } |
|
相关推荐
|
|
恩,复杂,这样应该是没有文件系统的
|
|
|
|
|
|
只有小组成员才能发言,加入小组>>
求解外围电路实现的是4脚给持续低电平复位并正常工作,高电平不工作的原因
2076 浏览 1 评论
3484 浏览 3 评论
PIC1946程序有一个变量在运行过程中恢复初始值其他变量保持不变
2329 浏览 2 评论
2754 浏览 0 评论
PIC16F1825的RC5引脚,在主程序中操作无效,在中断中可以改变是为什么?
4011 浏览 5 评论
956浏览 0评论
用XC8编译PIC18F25K80时提示下面Error,求怎么解决这个问题
6342浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 18:23 , Processed in 0.622232 second(s), Total 78, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号