⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sd_rw2.c

📁 PIC18读取sd卡的程序
💻 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 + -