如何将 数据 写入 TF 外置存储卡?
为什么要写到 外置存储卡? 容量大,适合大批量数据读写;价格实在!
所以 有必要:
#include <iostm8s103k3.h>
#define uchar unsigned char
#define uint unsigned int
#define SPI_CS PF_ODR_ODR4 //SD卡的片选
// 命令:手册上查找;
uchar CMD0[] = {0x40,0x00,0x00,0x00,0x00,0x95}; // SPI 初始化指令
uchar CMD1[] = {0x41,0x00,0x00,0x00,0x00,0xff}; // SPI 激活指令
uchar CMD17[]= {0x51,0x00,0x00,0x00,0x00,0xff}; // 单块读指令
uchar CMD24[]= {0x58,0x00,0x00,0x00,0x00,0xff}; // 单块写指令
int flag;
// 初始化 时钟;
void CLK_Init(void)
{
CLK_CKDIVR = 0x07; //16M/128
}
// 初始化 IO 口;
/****************************
PF4 片选;
PC7 MISO;
PC6 MOSI
PC5 SCK
*****************************/
void GPIO_Init(void)
{
PC_CR2 = 0x60; // 0110 0000
PC_DDR = 0x60; // 0110 0000
PC_CR1 = 0x80; // 1000 0000
PF_DDR = 0x10; // 0001 0000
PF_CR1 = 0x10; // 0001 0000
}
// 初始化 SPI;
void SPI_Init(void)
{
SPI_CR1 = 0x3f; // 0011 1111 ( 16M/128/256; MSB 先;主设备;CPOL = 1;CPHA= 0 )
SPI_CR2 = 0x03; // 0000 0011 ( 双线全双工;软件管理;无CRC )
SPI_CR1 |= 0x40; // 开启 SPI 总线 0100 0000
}
// 简单延时
void delay(int x)
{
int i,j;
for(i=x;i>0;i--)
for(j=10;j>0;j--);
}
// SPI 写 数据;
void Write_Byte(uchar x) // 向SD卡写入一个字节的数据
{
SPI_DR = x; // 数据写入
while(!(SPI_SR&0x02)); // 等待发送完成,缓冲为空
}
// SPI 读 数据;
uchar Read_Byte(void) // 从SD卡读出一个字节的数据
{
uchar c;
SPI_DR=0xff; // 拉高MOSI电位八个时钟
while(!(SPI_SR&0x02)); // 等待发送完成,缓冲为空
while(!(SPI_SR&0x01)); // 等待接收缓冲区非空
c = SPI_DR; //数据读回
return c;
}
void delay1(void) //延时80个时钟周期
{
int i;
for(i=10;i>0;i--)
{SPI_DR = 0xff;
while(!(SPI_SR&0x02));// 等待发送完成,缓冲为空
}
}
void Write_CMD(uchar *cmd)
{
int i;
SPI_CS = 1;
Read_Byte(); // 延时
SPI_CS = 0;
// 写入 指令的 6 个 字节;
for(i=0; i<6; i++)
{
SPI_DR = (*cmd++);
while(!(SPI_SR & 0x02));// 等待发送完成,缓冲为空
}
}
// SD 卡 初始化
void SD_SPI_Init(void) //
{
int c, r;
while(flag==0) // CMD0 书写成功判断
{
delay1(); // 时钟延时 74 个时钟 周期;
Write_CMD(CMD0); // 书写指令CMD0
Read_Byte(); //读取 第一个 应答信号 ;忽略第一个应答
c = 0;
while((c<100)&&(r!=0x01))
{
c++; // 读回应答信号100次
r = Read_Byte();
}
if(r==0x01) flag = 1; //当我们得到满意应答之后,跳出循环
}
flag =0;
// 初始化 成功之后 操作;
while(flag ==0)
{
c = 0;
Write_CMD(CMD1); // 书写指令CMD1
Read_Byte(); // 忽略第一个应答信号
while((c<100)&&(r!=0x00)) // 返因字节 00;
{
c++; // 读回应答信号100次
r = Read_Byte();
}
if (r ==0) flag =1; //当我们得到满意应答之后,跳出循环
}
}
// SD卡, 写单块 函数
void W_Block(char x)
{
uint n;
int r;
uchar c;
flag = 0;
while(flag==0)
{
{
Write_CMD(CMD24); // 书写指令CMD24 单块写指令
Read_Byte(); // 忽略第一个应答信号
r = 0xff;
while((c<100)&&(r!=0x00)) // 返回信号 0;
{
r = Read_Byte(); // 进行100次地循环
c++;
}
if(r==0x00) flag=1; // 当我们得到满意应答之后,跳出循环
}
for(n =0; n<100; n++) Read_Byte(); // 100和时钟的延时
Write_Byte(0xfe); // 书写发送 数据起始标志
for(n=0; n<512; n++) Write_Byte(x); // 对一个快进行书写
Write_Byte(0xff); // 发送2字节的 CRC 校验码;两个字节的伪CRC
Write_Byte(0xff);
r = Read_Byte(); // 等待 接收 响应;
while(Read_Byte() == 0xff); // 证明数据被接受
SPI_CS = 1; // 拉高片选
}
}
//SD卡, 单块读函数
void R_Block(uchar *dat)
{
int c;
unsigned int count;
uchar r;
c = 0;
flag =0;
while(flag==0)
{
Write_CMD(CMD17); // 读块:指令 17 单块读指令
r = Read_Byte(); // 忽略第一个应答信号
do
{
r = Read_Byte();
c++; //循环100次进行应答信号的读取
}while((r!=0)&&(c<100)); // 应当信号 为 0 ,表示,命令 写入;
c=0;
if(r ==0) flag =1; //直到得到满意的应答
}
while (Read_Byte() != 0xfe); // 读取接收数据的起始 (看是否为 FE )
for (count=0; count<512; count++) // 接收 512 个 字节;
{
*dat++ = Read_Byte(); // 放到这个 dat 数组中;
count++; // 循环读回512次
}
count = 0;
Read_Byte(); // 伪CRC
Read_Byte(); // 伪CRC
SPI_CS=1; // 拉高片选操作结束
}
void main()
{
uchar R_Buffer[512]={0x00}; // 读数据缓冲
CLK_Init(); // 时钟初始化
GPIO_Init(); // 端口初始化
SPI_Init(); // 单片机 SPI总线 初始化
SD_SPI_Init(); // SD卡 的 SPI模式 初始化
W_Block(16); // 写入 数据 16
delay(100); // 延时
R_Block(R_Buffer); // 读回 数据
while(1);
}
联系人:客服在线
手机:全工:13903011251
电话:李R:13530006400
邮箱:729986191@qq.com
地址: GUANGDONG PROVINCE