中级会员
- 积分
- 281
- 威望
- 193
- 贡献
- 58
- 兑换币
- 0
- 注册时间
- 2012-3-6
- 在线时间
- 15 小时
- 毕业学校
- 西安文理学院
|
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
#include <mc9s12xs128.h> //128
#define INIT_CMD0_ERROR 0X01
#define INIT_CMD1_ERROR 0X02
#define Write_Block_ERROR 0X03
#define Read_Block_ERROR 0X04
uchar is_init; //初始化数据为1
uchar pbuf[512] ; //数据缓存区
//#include "SD_Card.h"
#define CS PTS_PTS7
#define SD_IDLE 0X01
#define SD_OK 0X00
#define SD_CMD0 0X40
#define SD_CMD55 0X79
#define SD_CMD41 0X41
#define SD_CMD16 0X50
#define SD_CMD9 0X49
#define SD_CMD17 0X51
#define SD_CMD24 0X58
void delay_0(uint z) //延时函数
{
uint x,y;
for(z;z>0;z--)
for(x=110;x>0;x--)
for(y=25;y>0;y--);
}
//PLL初始化
void PLL_Init(void) //PLLCLK=2*OSCCLK*(SYNR+1)/(REFDV+1)
{
//PLLCLK=2*16M*(2+1)/(0+1)= 96M
SYNR = 0xC2; //总线频率为PLL频率的一半48M
REFDV = 0xC0;
ECLKCTL &= ~0x80;
while(!(CRGFLG&0x08)); //自循环语句,等待时钟频率稳定后允许锁相环时钟作为系统时钟
CLKSEL=0x80; //选择锁相环频率为系统时钟频率
}
/****************************************************
//功 能: IO口初始化()函数
//入口参数: 无
//出口函数: 无
****************************************************/
void IO_INIT(void)
{
DDRM=0XFF;
DDRS=0XEF;
PTM=0XFF;
}
//SPI初始化
void SPI_Init(void)
{
MODRR = 0x00;
MODRR_MODRR4=0; //使用PM 口
//DDRM |= 0x38; //可知SCK0=1,MOSI=1,SS0=1 本步可以忽略,这样做复位可以抗干扰下,并且直接让
//片选无效
SPI0CR1 = 0x5e; //CPOL=1,时钟选择低有效,spsck空闲时为高电平
//CPHA=1 会在发送 8 位数据开始 sck就发生一次跳变
SPI0CR2 = 0x10; //modfen=1 .和上面 ssoe=1 确定 spi在 master 模式下 ss 位从机选择输出。并允许 modf标志设置
SPI0BR = 0x17; //波特率设置波特率= BR=busclk/((SPPR + 1)· 2^(SPR + 1))=48M / (1+1)*2^(7+1) = 93KHz
}
//设置 spi 高速
void SPI_High(void)
{
SPI0BR = 0x01; //BR=busclk/((SPPR + 1)· 2^(SPR + 1))=48M / 4= 12m
}
//用SPI写1byte
void SPI_Write(unsigned char date)
{
while (!SPI0SR_SPTEF); //等待发送器空
(void)SPI0SR;
SPI0DRL = date;
while (!SPI0SR_SPIF); //等待发送完成
(void)SPI0DRL;
}
//用SPI读1byte
unsigned char SPI_Read(void)
{
while (!SPI0SR_SPTEF); //等待发送器空
(void)SPI0SR;
SPI0DRL = 0xff;
while (!SPI0SR_SPIF); //等待发送完成
(void)SPI0DRL;
return SPI0DRL;
}
uchar Write_Cmd(uchar *pcmd)
{
uchar temp,time=0,i;
for(i=0;i<6;i++) //写6个命令字节
{
SPI_Write(pcmd[i]); //写SD卡的8个命令
}
do
{
temp=SPI_Read(); //读字节,直道读出数不是0xff 或者 超时
time++;
}
while((temp==0xff)&&(time<100));
return temp;
}
uchar SD_Reset() //SD卡复位 ,进入SPI协议,写入CMD0号命令
{
uchar temp=0,time,i;
uchar pcmd[]={0x40,0x00,0x00,0x00,0x00,0x95};
CS=1; //高电平,等待时钟
for(i=0;i<15;i++)
{
SPI_Write(0xff); //必须至少保持74个时钟,才可以读写SD卡
}
CS=0; //低电平,片选成功,
time=0; //次数清零
do
{
temp=Write_Cmd(pcmd); //写入6个命令字节,写入CMD0号命令
time++;
if(time==200)
{
return (INIT_CMD0_ERROR); //写入CMD0失败
}
}
while(temp!=0x01);
CS=1;
SPI_Write(0xff); //高电平,补8个时钟
return 0; //写入成功
}
uchar SD_INIT() //SD卡初始化,写入CMD1号命令
{
uchar temp=0,time;
uchar pcmd[]={0x41,0x00,0x00,0x00,0x00,0xff};//CMD1号命令
CS=0; //低电平,片选成功,
time=0; //次数清零
do
{
temp=Write_Cmd(pcmd); //写入6个命令字节,写入CMD1号命令
time++;
if(time==100)
{
return (INIT_CMD1_ERROR); //写入CMD1失败
}
}
while(temp!=0);
SPI_High(); // 高速模式
CS=1; //关闭片选
SPI_Write(0xff); //高电平,补8个时钟
return 0; //成功初始化
}
uchar SD_Write_Sector(ulong add,uchar *Buffer)//SD卡写扇区地址add,
{
uchar temp=0,time;
uint i;
uchar pcmd[]={0x58,0x00,0x00,0x00,0x00,0xff} ; //CMD24号命令
add<<=9; //add=add*512;每个扇区是512字节,
pcmd[1]=((add&0xff000000)>>24); //把扇区地址转化为字节地址
pcmd[2]=((add&0xff000000)>>16);
pcmd[3]=((add&0xff000000)>>8);
CS=0; //低电平,片选成功,
time=0; //次数清零
do
{
temp=Write_Cmd(pcmd); //写入6个命令字节,写入CMD24号命令
time++;
if(time==100)
{
return temp; //写入命令失败
}
}
while(temp!=0);
for(i=0;i<100;i++)
{
SPI_Read(); //这里插入若干个时钟
}
SPI_Write(0xfe); //写入开始标志,然后写512字节
for(i=0;i<512;i++)
{
SPI_Write(*Buffer++); // 写512字节
}
SPI_Write(0xff); //写入两个CRC校验
SPI_Write(0xff);
temp=SPI_Read(); //读取值
if((temp&0x1f)!=0x05)
{
CS=1; //关闭片选
return (Write_Block_ERROR); //返回写错误
}
while(SPI_Read()!=0xff); //等待高电平为不忙状态,低电平为忙线
CS=1; //关闭片选
SPI_Write(0xff); //高电平,补8个时钟
return 0; //成功写入块数据
}
uchar SD_Read_Sector(ulong add,uchar *Buffer)//SD卡写扇区地址add,
{
uchar temp=0,time;
uint j;
uchar pcmd[]={0x51,0x00,0x00,0x00,0x00,0xff} ; //CMD17号命令
add<<=9; //add=add*512;每个扇区是512字节,
pcmd[1]=((add&0xff000000)>>24); //把扇区地址转化为字节地址
pcmd[2]=((add&0xff000000)>>16);
pcmd[3]=((add&0xff000000)>>8);
CS=0; //低电平,片选成功,
time=0; //次数清零
do
{
temp=Write_Cmd(pcmd); //写入6个命令字节,写入CMD17号命令
time++;
if(time==100)
{
return (Read_Block_ERROR); //读块失败
}
}
while(temp!=0);
while(SPI_Read()!=0xfe); //一直在读取数据,直道数据为0xfe 后面就是512个字节读数据了
for(j=0;j<512;j++)
{
Buffer[j]=SPI_Read(); //读取512字节
}
SPI_Read(); //读取 两个字节CRC校验
SPI_Read();
CS=1; //关闭片选
SPI_Write(0xff); //高电平,补8个时钟
return 0; //成功写入块数据
}
void main()
{
PLL_Init();
IO_INIT();
SPI_Init();
SD_Reset();
if(SD_INIT()==0)PTM=0X00;
else PTM=0Xf3;
while(1)
{
SD_Read_Sector(80,pbuf);
}
}
|
|