STM32F103测试SD卡串口写入测试

1.硬件引脚介绍:

本测试采用SPI模式读写SD卡,相关引脚配置如下:

片选:SD_CS->PB13,对应SD卡的1脚,低电平有效

时钟:SPI1_SCK->PA5,对应SD卡的5脚 

主入从出:MISO->PA6,对应SD卡的7脚 

主出从入:MOSI->PA7,对应SD卡的2脚

STM32F103测试SD卡串口写入测试_第1张图片

2.初始化步骤:

while(SD_Initialize())

{

//提示检查SD卡

}

//初始化SD卡
u8 SD_Initialize(void)
{
  u8 r1;      // 存放SD卡的返回值
  u16 retry;  // 用来进行超时计数
  u8 buf[4];  
	u16 i;
	SD_SPI_Init();		//初始化IO
 	SD_SPI_SpeedLow();	//设置到低速模式 
 	for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);//发送最少74个脉冲
	retry=20;
	do
	{
		r1=SD_SendCmd(CMD0,0,0x95);//进入IDLE状态
	}while((r1!=0X01) && retry--);
 	SD_Type=0;//默认无卡
	if(r1==0X01)
	{
		if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
		{
			for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);	//Get trailing return value of R7 resp
			if(buf[2]==0X01&&buf[3]==0XAA)//卡是否支持2.7~3.6V
			{
				retry=0XFFFE;
				do
				{
					SD_SendCmd(CMD55,0,0X01);	//发送CMD55
					r1=SD_SendCmd(CMD41,0x40000000,0X01);//发送CMD41
				}while(r1&&retry--);
				if(retry&&SD_SendCmd(CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
				{
					for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//得到OCR值
					if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;    //检查CCS
					else SD_Type=SD_TYPE_V2;   
				}
			}
		}else//SD V1.x/ MMC	V3
		{
			SD_SendCmd(CMD55,0,0X01);		//发送CMD55
			r1=SD_SendCmd(CMD41,0,0X01);	//发送CMD41
			if(r1<=1)
			{		
				SD_Type=SD_TYPE_V1;
				retry=0XFFFE;
				do //等待退出IDLE模式
				{
					SD_SendCmd(CMD55,0,0X01);	//发送CMD55
					r1=SD_SendCmd(CMD41,0,0X01);//发送CMD41
				}while(r1&&retry--);
			}else//MMC卡不支持CMD55+CMD41识别
			{
				SD_Type=SD_TYPE_MMC;//MMC V3
				retry=0XFFFE;
				do //等待退出IDLE模式
				{											    
					r1=SD_SendCmd(CMD1,0,0X01);//发送CMD1
				}while(r1&&retry--);  
			}
			if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;//错误的卡
		}
	}
	SD_DisSelect();//取消片选
	SD_SPI_SpeedHigh();//高速
	if(SD_Type)return 0;
	else if(r1)return r1; 	   
	return 0xaa;//其他错误
}
如果返回值为正常类型,则跳出初始化循环,接下来介绍该函数中的SD_SPI_Init()函数及其内部调用的SPI_Init()函数
SD_SPI_Init()配置片选引脚PB13并拉低电平设置片选有效,然后调用SPI_Init()函数,代码略

SPI_Init()函数初始化单片机的SPI1外设,具体配置为PA5.6.7三个引脚的设置

//以下是SPI模块的初始化代码,配置成主机模式,访问SD Card							  

SPI_InitTypeDef  SPI_InitStructure;

void SPI1_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
  
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA|RCC_APB2Periph_SPI1, ENABLE );	
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

 	GPIO_SetBits(GPIOA,GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);

	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI工作模式:设置为主SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//设置SPI的数据大小:SPI发送接收8位帧结构
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;		//选择了串行时钟的稳态:时钟悬空高
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//数据捕获于第二个时钟沿
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//定义波特率预分频的值:波特率预分频值为256
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
	SPI_InitStructure.SPI_CRCPolynomial = 7;	//CRC值计算的多项式
	SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
 
	SPI_Cmd(SPI1, ENABLE); //使能SPI外设
	
	SPI1_ReadWriteByte(0xff);//启动传输		 
}   

3.主函数部分:

int main(void)
 { 
 	u32 total,free;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2 
	delay_init();	    	 //延时函数初始
	LED_Init();
	uart_init(19200);	 	//串口初始化为19200
 	exfuns_init();		//为fatfs相关变量申请内存				 				
 	mem_init();			//初始化内存池	
	printf ("程序初始化结束:->\r\n");	
	if(SD_Initialize())					//检测SD卡
	{
		printf ("未检测到SD卡:->\r\n");
		while(SD_Initialize())
		{
			printf("别看着了,滚去找原因,根本没插卡:\r\n");
			LED1=!LED1;
			delay_ms(500);
		}
		LED1=1;
	}								   	
	printf("SD卡正常加载:\r\n");
	printf("申请内存结果:%d\r\n",(unsigned int)exfuns_init());//为fatfs相关变量申请内存,返回0成功				 
  	f_mount(fs[0],"0:",1); 					//挂载SD卡 
	exf_getfree((u8*)"0",&total,&free);//得到SD卡的总容量和剩余容量
	printf("SD卡的容量是:%d\r\n",free);
	printf("开始扫描串口数据**************************\r\n");
	while(1)	//测试使用串口输入函数名是成功的
	{
	if(USART_RX_STA&0x8000)//不断检测串口接收完成?这里可以去串口中断服务函数中做一些if判断来限制串口的数据格式,数据大小
	{			
		WriteData();	//串口接收完成开始写入SD卡,该函数是自己封装的,详细请看下面介绍的SD卡写入步骤
		USART_RX_STA=0;		//清零标志位
	}
	LED0=!LED0;//程序运行指示灯
	delay_ms(500);
	}
}

4.向SD卡中写入的步骤:(采用库函数)

由于里面的函数都是SD驱动函数封装起来的,所以要了解底层写入过程,还要参考SD卡的通讯时序等等,不在此赘述,以后会另做记录

void WriteData(void)			//一旦在串口中断标志置位,则调用该函数,开始启动创建文件的步骤:
{
	//*********写入SD卡****************************
	mf_mount(0,1);	//注册工作区域
	mf_open(fileName,4);	//创建文件
	mf_close();
	mf_open(fileName,2);										//以可写方式打开文件
	mf_lseek(mf_size());										//将指针移动到文件末尾,以便追加数据
	mf_write(USART_RX_BUF,142);											//追加写入串口发来的数据到SD卡
	mf_close();															//关闭文件
	printf("WriteData()执行完毕,数据写入成功\r\n");
}



 
 

你可能感兴趣的:(非纯笔记)