Stillness_Tr

基于AVR的SD卡操作以及一些注意的地方(原创)

0
阅读(2503)

      最近搞了一下SD卡的一些东西,有很多有意思的地方。所以跟大家一起分享一下。

      其实这个东西没有上FAT也很好搞,网上的程序啊,资料啊一大堆。所以对于程序来说,一般都很容易搞的定。我使用的是AVR的ATMEGA128 所以SD卡用的是SPI模式,如果你不明白我说的SPI模式是什么,建议你先去看一下DATASHEET,也可以去找一些中文的资料看一下。我使用的是AVR自带的SPI接口,所以操作起来很方便。做的过程也碰到了几点问题,所以拿出来说一下。(本人也是初级选手,所以有什么说的不对的地方请包含……)
     SD卡的供电方式是3.3v的供电,而我的MCU用的是5V的供电,在网上搜了一下,据传说SD卡接5V会烧。所以没有敢去尝试(不是不想尝试,主要还是尝试不起)。
 
    在网上找了很久找到一篇关于3.3V转5V文章看了一下,(其实在之前,我也想把AVR用3,3V供电,这样就能解决电源匹配的问题,但是对于我来说平常使用3.3V少,所以就没有考虑)又看了一下MEGA的DATASHEET和SD的DATASHEET,发现AVR发送SD接收(MOSI),片选信号,时钟信号等等,电平应该是没有什么大问题的,可以直接两者接到到一起。但是SD发送到AVR得时候可能会不稳定(MISO)。所以搞了一个转换电平,如图。
       这个东西使用的器件比较少,一个二极管,一个上拉的电阻,电阻接的是5V
SD_DO :SD卡输出
MCU_DI :MCU输入
     工作方式是这样的,当SD_DO=0的时候,MCU_DI也应该是0V+二极管导通电压,这个不用分析,一看
就很清楚。 当SD_DO=1的时候呢 这时候要注意了。D1上加的电压应该是5V-3.3V=1.7V ,所以你在选择二级管的时候,要选导通电压比这个电压值大的二极管,这样 1.7V的电压是导通不了二极管的,所以D1是截止状态的,从而MCU_DI也就得到了高电平了。
    当然也有特殊的情况。在选择测试二极管的时候,把SD_DO接个限流电阻接到3.3V 去量图上节点的电压,如果电压是3.3V+二极管导通电压,而不是5V。则二极管是导通的,但不代表不能用,也要看这个电平够不够AVR去识别数字"1"这你要参考AVR的DATASHEET了。
下面说一下程序。我自己写了一个测试的程序。有些是参考了别人的代码。整个工程就不写了,就把重要的看一下吧,我使用的是ICC编译环境。已经测试可以使用。下面就贴出来。
 

#include <iom128v.h>
#include <macros.h>
#define MMC_CS_PIN     BIT(4)    //PORTB.4
#define MMC_PORT       PORTB  
unsigned char reading=0;
//***************************************************************************
//延时函数
//***************************************************************************
void delay_nus(unsigned int n)
{
unsigned char b;
for (b = 1; b<n; b++);
}
//****************************************************************************
//Send a Command to MMC/SD-Card
//Return: the second byte of response register of MMC/SD-Card
//****************************************************************************
unsigned char SD_Write_Command(unsigned char cmd,unsigned long arg)
{
   unsigned char tmp;
   unsigned char retry=0;
  
   //MMC_PORT|=MMC_CS_PIN;       //SD卡关闭  
   //send 8 Clock Impulse
   Write_Byte_SPI(0xFF);
  
   //set MMC_Chip_Select to low (MMC/SD-Card active)
   MMC_PORT&=~MMC_CS_PIN;       //SD卡使能
   Write_Byte_SPI(cmd|0x40);   //送头命令
   Write_Byte_SPI(arg>>24);
   Write_Byte_SPI(arg>>16);     //send 6 Byte Command to MMC/SD-Card
   Write_Byte_SPI(arg>>8);
   Write_Byte_SPI(arg&0xff);
   Write_Byte_SPI(0x95);       //仅仅对RESET有效的CRC效验码
   //get 8 bit response
   //Read_Byte_MMC(); //read the first byte,ignore it.
   do
   { //Only last 8 bit is used here.Read it out.
      tmp = Read_Byte_SPI();
      retry++;
   }
   while((tmp==0xff)&&(retry<100)); //当没有收到有效的命令的时候
  
   if(reading==0)
   MMC_PORT|=MMC_CS_PIN;            //MMC_CS_PIN=1;
   else MMC_PORT&=~MMC_CS_PIN;      //MMC_CS_PIN=0;  
   return(tmp);
}
//****************************************************************************
//SD卡初始化(SPI-MODE)
//****************************************************************************
unsigned char SD_Init(void)
{
   unsigned char retry,temp;
   unsigned char i;
   MMC_PORT&=~MMC_CS_PIN;      //SD卡使能
delay_nus(250); //Wait MMC/SD ready...
   for (i=0;i<0x0f;i++)
   {
      Write_Byte_SPI(0xff); //send 74 clock at least!!!
   }
   //Send Command CMD0 to MMC/SD Card
   retry=0;
  
   do
   { //retry 200 times to send CMD0 command
     temp=SD_Write_Command(0,0);
     retry++;
     if(retry==100)
     {
      return(1) ;//CMD0 Error!
     }
   }
   while(temp!=1);
  
   //Send Command CMD1 to MMC/SD-Card
   retry=0;
   do
   { //retry 100 times to send CMD1 command
     temp=SD_Write_Command(1,0);
     retry++;
     if(retry==100)
     {
     return(1) ;
     }
   }
   while(temp!=0);
   retry=0;
// SD_Write_Command(16,512);     //设置一次读写BLOCK的长度为512个字节
   MMC_PORT|=MMC_CS_PIN;   //MMC_CS_PIN=1; //set MMC_Chip_Select to high
   return(0); //All commands have been taken.
}
//****************************************************************************
//从SD卡读一个扇区
//long address --SD卡地址
//*P--存储缓冲
//Return 0 if no Error.
//****************************************************************************
unsigned char SD_Read_Block(unsigned long address,unsigned char *P)
{
   unsigned char temp=0;
   unsigned int i,j;
   reading=1;
   temp=SD_Write_Command(17,address);     //读出RESPONSE    
   while (Read_Byte_SPI()!= 0xfe)
   {;} //直到读取到了数据的开始头0XFE,才继续
   for(i=0; i<512; i++)
   {
   *P=Read_Byte_SPI();
    P++;
    }
   Read_Byte_SPI();//CRC - Byte
   Read_Byte_SPI();//CRC - Byte
   reading=0;
   MMC_PORT|=MMC_CS_PIN;        //关闭SD卡
   return(temp);
}
//***************************************************************************
//SD卡写一个扇区
//long address --SD卡地址
//*P--存储缓冲
// Return 0 if no Error.
//***************************************************************************
unsigned char SD_Write_Block(unsigned long address,unsigned char *P)
{
   unsigned char temp,temp1;
   unsigned int i,j;
   reading=1;
   temp=SD_Write_Command(24,address);//读出RESPONSE
   Write_Byte_SPI(0xFF);//Add NWR
   Write_Byte_SPI(0XFE);//Add Start Block
   for(i=0;i<512;i++)
    {
     Write_Byte_SPI(*P);
P++;
    }
   Write_Byte_SPI(0xFF);
   Write_Byte_SPI(0xFF); //2 Bytes CRC
    temp1=Read_Byte_SPI();//Read the Response xxx0 0101 is ok
   if ((temp1&0x1f)!=0x05)
    {
MMC_PORT|=MMC_CS_PIN; //CLOSE CS
return (1);// Error to Response
}
    while(!Read_Byte_SPI());//wait for SD not busy
    MMC_PORT|=MMC_CS_PIN; //CLOSE CS
    Write_Byte_SPI(0XFF);//ADD NDS
return(temp);
}
//******************************************************************************
//设置扇区读取字节设置
//Return 0 if no Error
//******************************************************************************
unsigned char Set_BLlock(unsigned int Choose_count)
{
unsigned char temp,count=0;
do
{
temp=SD_Write_Command(16,Choose_count);
count++;
   if (count==200)
     {
      MMC_PORT|=MMC_CS_PIN; //CLOSE CS
      return(1); //Return Error
     }
}
while(temp!=0);
MMC_PORT|=MMC_CS_PIN; //CLOSE CS
return(temp);  
}