📄 sd_rw2.c
字号:
//**************************************************
// 项目:PIC单片机对SD卡进行单块数据的读写操作
// 系统:PIC18F877A, 16MHz, SPI(主)
// 编程:2005-12
//**************************************************
#include <pic18.h>
// __CONFIG (HS & PROTECT & PWRTEN & BOREN & WDTDIS);
#define SD_TEST
void crcInit(void);
unsigned int crcCompute(unsigned char * message, unsigned int nBytes);
#define CMD0 0x00 //GO IDLE STATE
#define CMD1 0x01 //SEND OP COND
#define CMD9 0x09 //SEND CSD
#define CMD13 0x0d //SEND STATUS
#define CMD16 0x10 //SET BLOCK LENGTH
#define CMD17 0x11 //READ SINGLE BLOCK
#define CMD24 0x18 //WRITE BLOCK
#define CMD59 0x3B //CRC_ON_OFF
#define W_ADDR 0x00000001 //写地址
#define R_ADDR 0x00000001 //读地址
#define BLOCKlEN 0x000a //设置读写块的长度为10,默认的块长度在CSD中
#define SPICtrl RB0 //SPI片选,待定
#define H_FF 0xff //发送FF,MISO模式
#define NOARG 0x00000000 //命令无参数
#define C_R1 1 //响应字节数1
#define C_R1b 2 //响应字节数1,有busy信号,写操作
#define NSAC 8 //在CSD中设定
#define BL_LEN 12
#define FD_FE 0xfe //发送首字节为0xFE
//开辟两个缓冲区,大小均为一个块地址的大小,对发送缓冲区的前十个数据赋初值
unsigned char w_buf[BL_LEN-2]={0Xfe,1,2,3,4,5,6,7,8,9}; //发送缓冲区
unsigned char r_buf[BL_LEN]; //接受缓冲区,不包括CRC校验值
unsigned int *wr_crc; //缓冲区CRC值存放区
unsigned char * WB_re ; //接收写数据块的响应
unsigned char SW_rst[6] = {0x40,0x0,0x0,0x0,0x0,0x95}; //软件复位命令
#ifdef SD_TEST
unsigned char csd[16] ; //存放CSD寄存器的信息
/***************************************************************************/
// CSD 128bit register P64 definition
// [119:112] TAAC
// [83:80] READ_BL_LEN [79] READ_BL_PARTIAL (allways = 1 in SD Memory Card)最小数据块可为1Byte
// [25:22] WRITE_BL_LEN [21] WRIE_BL_PARTIAL [7:1] CRC
/***************************************************************************/
#endif
bit b_sdw; //写操作完成标志位
bit b_sdr; //读操作完成标志位
bit b_cmdnr; //命令无响应标志位
bit b_dnr; //数据接收无响应标志位
bit b_cmdr_er; //命令响应错误标志位
//系统初始化
void Sys_Init(void)
{
SSPSTAT=0 ; //SMP=0,CKE=0,BF=0
SSPCON1=0b00100010; //SSPEN=1,CKP=0,FOSC/64
TRISB=0b11111100; //RB0,RB1输出
TRISC=0b10010111; //RC3,5,6输出
RBPU=1; //RB弱上拉关闭
b_sdw=0; //写操作完成标志位
b_sdr=0; //读操作完成标志位
b_cmdnr=0; //命令无响应标志
b_dnr=0;
WB_re = 0x00; //清空寄存器
wr_crc = 0x0000;
}
//中断初始化
void Int_Init(void)
{
//SPI中断
SSPIF=0; //清除SPI中断标志
SSPIE=1; //中断允许?采用查询方式
//总中断
PEIE=0; //外围中断禁止
GIE=0; //总中断禁止
}
/************************************************************/
/* PIC发送数据
/************************************************************/
void PIC_W ( char * w_ad , int nByte) //PIC发送,首地址,字节数
{
unsigned char * w_ptr;
unsigned int i;
w_ptr = w_ad;
for ( i = 0; i < nByte; i++ )
{
SSPBUF = * w_ptr;
while (!SSPIF) {;}
SSPIF = 0;
w_ptr ++;
}
}
/************************************************************/
/* PIC接收数据
/************************************************************/
void PIC_R ( char * r_ad , int nByte) //PIC接收,首地址,字节数
{
unsigned char * r_ptr;
unsigned int i;
r_ptr = r_ad;
for ( i = 0; i < nByte; i++ )
{
SSPBUF = H_FF ;
while (!SSPIF) {;}
SSPIF = 0;
* r_ptr = SSPBUF;
r_ptr ++;
}
}
/*****************************************************************/
//In the non-protected mode the CRC bits of the command,
//response and data tokens are still required in the tokens.
// However, they are defined as ‘don’t care’ for the transmitter
// and ignored by the receiver
/*****************************************************************/
unsigned char CMD_CRC(char * cmdcrc)
{
unsigned char crc7;
unsigned int crc_res; //存放crc计算结果
crc_res = crcCompute( cmdcrc, 5); //计算结果为16bit
//////////////////////// //如何取期中的一个字节作为返回值
crc7 = (char)(crc_res>>8 &0xff | 0x01);
return crc7;
}
/************************************************************/
/* 等待周期,表示等待周期
/************************************************************/
void SPI_wt(int n) //SD卡准备好
{
char * busy;
unsigned i;
PIC_R (busy,i);
}
/************************************************************/
/* 发送命令字
/************************************************************/
struct COM1 //命令控制结构
{
char c;
unsigned long l;
char e;
};
union COM2
{
struct COM1 c6;
char c1[6];
};
void SD_CMD ( char CMD, unsigned long ARG ) //发送命令控制,响应类型为R1
{
char c_crc;
char * cmd_r1;
unsigned int tncr;
union COM2 command;
command.c6.c = 0x40 | CMD;
command.c6.l = ARG;
c_crc = CMD_CRC(command.c1); //命令字节的首地址
command.c6.e = c_crc;
tncr = 0;
b_cmdnr = 0; //发送前对标志位进行初始化
b_cmdr_er = 0;
PIC_W( command.c1 , 6 ); //send cmd
while(1)
{
PIC_R ( cmd_r1 , 1);
if( * cmd_r1 != 0xff )
{ break; }
else
if(tncr == 8) { b_cmdnr = 1 ; break;}
else tncr++;
}
if( *cmd_r1 != 0x00)
b_cmdr_er = 1;
}
/************************************************************/
/* SD卡软件复位
/************************************************************/
void SD_Rst ( ) //SD卡软复位
{
unsigned int tncr;
char * cmd_r1;
PIC_W( SW_rst , 6 ); //发送软件复位控制命令
SPICtrl = 0; //复位命令发送过程中片选信号有下降沿SPICtrl
while(1)
{
PIC_R ( cmd_r1 , 1);
if( * cmd_r1 != 0xff )
break;
else
if(tncr == 8) { b_cmdnr = 1 ; break;}
else tncr++;
}
if( *cmd_r1 != 0x00)
b_cmdr_er = 1;
}
/************************************************************/
/* SD卡初始化
/************************************************************/
void SD_Init() //SD卡初始化
{
do
{
SPI_wt(1); //NRC,两次命令间隔
SD_CMD( CMD1 , NOARG ); //CMD1,等待SM卡初始化完毕
}
while( b_cmdr_er | b_cmdnr); //当无响应或者响应有错时继续发送
}
/************************************************************/
/* PIC->SD卡 写入数据块 */
/************************************************************/
void PIC_BL_W ( char * w_ad ) //pic写入single block数据块
{
char * crc_tmp;
*wr_crc = crcCompute( w_ad, BL_LEN ); //调用CRC校验码
crc_tmp = (char * )wr_crc;
PIC_W ( w_ad, BL_LEN ); //发送启示数据块
PIC_W ( crc_tmp, 2); //发送CRC校验码
}
/************************************************************/
/* PIC<-SD卡 读取数据块 */
/************************************************************/
void PIC_BL_R ( char * r_ad ) //pic读出single block数据块
{
PIC_R ( r_ad, BL_LEN -1 ); //接收数据块,起始块已经接收
}
/************************************************************/
// 完整的PIC-SD写入数据,返回值为1表示发送完毕正确写入
/************************************************************/
bit SD_WR ( long SDADR, char * WBUF) //写入单块数据
{
WB_re = 0x00; //清空寄存器
wr_crc = 0x0000;
SPI_wt(1); //NRC,两次命令间隔
SD_CMD ( CMD24, SDADR ); //写命令
if((!b_cmdr_er) & (!b_cmdnr)) //命令响应正确,开始写数据
{
SPI_wt(1); //NWR,插入一个周期
PIC_BL_W ( WBUF ); //写入一个数据块
PIC_R ( WB_re, 1); //接收数据响应
// SD_busy (); //等待SD卡BUSY信号结束,完成本次发送
return 1;
}
else
return 0;
}
/************************************************************/
/* 完整的PIC-SD读取数据,返回值为1表示读取完毕
/************************************************************/
bit SD_RD (long SDADR, char * RBUF)
{
unsigned i ;
wr_crc = 0x0000;
SPI_wt(1); //NRC,两次命令间隔
SD_CMD ( CMD17, SDADR ); //读命令
if(!b_cmdr_er & !b_cmdnr) //命令响应正确,开始写数据
{
SPI_wt(1); //NAC,插入一个周期
while(1)
{
SPI_R( RBUF, 1); //将接收到的数存入RBUF[0]的位置
if( RBUF[0] == 0xfe)
{ RBUF++;
break;
}
else
if(i == NSAC -1) //NSAC表示最大数据响应时间,在CSD中定义
{ b_dnr = 1 ; //超出最大数据响应时间
break;
}
else
i++;
}
if(!b_dnr) //未超过最大响应时间
{
PIC_BL_R( RBUF); //继续接收数据及CRC区
return 1;
}
}
return 0;
}
/************************************************************/
/* 读CSD寄存器操作
/************************************************************/
void SD_CSD (char * csd)
{
unsigned int i;
SPI_wt(1);
SD_CMD( CMD9 , NOARG ); //发送复位命令CMD9
if(!b_cmdr_er & !b_cmdnr) //命令响应正确,开始写数据
{
SPI_wt(1); //NAC,插入一个周期
while(1)
{ SPI_R( csd, 1); //将接收到的数存入RBUF[0]的位置
if( csd[0] != 0xff)
{ csd++;
break;
}
else
if(i == 7) //NCR表示最大数据响应时间,在CSD中定义
{ b_dnr = 1 ; //超出最大数据响应时间
break;
}
else
i++;
}
if(!b_dnr) //未超过最大响应时间
{
PIC_BL_R( csd); //继续接收数据及CRC区
}
}
}
/************************************************************/
/* 主程序
/************************************************************/
void main()
{
static bit w1; //写成功标志位
static bit r2; //读成功标志位
Sys_Init(); //系统初始化
Int_Init(); //中断初始化
SPICtrl=1; //spi片选无效
crcInit(); //生成CRC查询表
SD_Rst(); //SD卡软件初始化,进入SPI模式
SD_Init(); //CMD1,SM卡初始化完毕
// #ifdef SD_TEST
// char csd[16]; //存储128bit的CSD寄存器信息
// SD_CSD (csd); //读取SD卡的CSD信息
// #endif
w1 = SD_WR ( W_ADDR, w_buf); //写数据块
r2 = SD_RD ( R_ADDR, r_buf); //读数据块
//当w1和r2返回值均为1时,表示读写操作正确,如发生错误,可读写内部控制字
//本例中没有对读取的数据块进行CRC校验比较
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -