历史上的今天
返回首页

历史上的今天

今天是:2025年08月21日(星期四)

正在发生

2018年08月21日 | STM32F103测试SD卡串口写入测试

2018-08-21 来源:eefocus

1.硬件引脚介绍:

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


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

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

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

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


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");

}


推荐阅读

史海拾趣

Herotek Inc公司的发展小趣事

随着半导体技术的飞速发展,Henkel公司紧跟行业趋势,不断研发适用于半导体封装的高性能粘合剂。其研发的粘合剂产品不仅满足了半导体封装过程中对于高精度、高可靠性的要求,还显著提升了封装效率。例如,Henkel的某些粘合剂产品能够在极端温度条件下保持稳定的性能,确保半导体器件在各种工作环境中都能正常运行。这一技术突破为Henkel在半导体封装市场赢得了广泛的认可。

Cyrix Corp公司的发展小趣事

在成功推出数学协处理器后,Cyrix于1992年推出了其第一款CPU——486SLC和486DLC。这两款产品旨在与英特尔的486SX和486DX竞争,并因其引脚兼容性和低廉的价格而广受制造商欢迎。尽管其性能略逊于英特尔的同类产品,但Cyrix凭借价格优势在市场上占据了一席之地。

EPCOS (TDK)公司的发展小趣事

自成立以来,EPCOS一直致力于技术创新和产品拓展。公司不断投入研发资源,开发出了一系列高性能、高品质的电子元器件产品。这些产品广泛应用于通信、消费、汽车和工业电子等领域,赢得了众多客户的信赖和好评。同时,EPCOS还积极拓展国际市场,与全球众多知名企业建立了长期稳定的合作关系。

Azoteq公司的发展小趣事

2013年,Azoteq发布了第三条产品线——PowerSense™。这一产品系列主要包括一系列交流LED照明解决方案,为照明行业带来了全新的技术突破。PowerSense™的推出,不仅进一步巩固了Azoteq在半导体行业的地位,也为其在未来的市场竞争中赢得了更多机会。

思瑞浦微电子科技(3PEAK INCORPORATED)公司的发展小趣事

Azoteq公司成立于1998年,由Frederick Bruwer博士创立。作为一家无晶圆厂半导体公司,Azoteq从一开始就致力于开发创新的传感解决方案。其首个产品系列——LightSense™,是针对LED手电筒和穿戴头灯的智能控制而设计的。这一产品系列的推出,为Azoteq在半导体设计制造领域奠定了坚实的基础。

CONTTEK Group GmbH公司的发展小趣事

在技术创新的基础上,CONTTEK Group GmbH公司开始积极拓展市场。公司不仅在国内市场取得了良好的销售业绩,还积极开拓国际市场,与多家国际知名企业建立了合作关系。通过参加国际展览、建立海外销售网络等方式,公司的品牌影响力逐渐提升,产品也远销至全球各地。

问答坊 | AI 解惑

如何学习单片机!

初学者如何学习单片机!请看这个吧!《51单片机C语言快速上手》! http://u.xunzai.com/fileview_46147.html http://pickup.mofile.com/7992587555186412 最好是用迅雷下载 [ 本帖最后由 lgh050706 于 2009-8-5 21:30 编辑 ]…

查看全部问答>

全国大学生电子设计竞赛历年试题

本帖最后由 paulhyde 于 2014-9-15 08:55 编辑 全国大学生电子设计竞赛历年试题  …

查看全部问答>

【招聘】奥笙北京软件招聘信息(新增深圳软件技术支持职位)(论坛xdjm优先)

由于不能删帖,只能重新发一篇招聘信息了,注意哦,论坛的兄弟姐妹们优先。论坛的兄姐妹们有意可以直接发邮件给我:jandy.wang@orpheusys.com, 奥笙公司软件部门招聘信息(北京职位) 公司简介    奥笙时代科技(北京)有限公司(www. ...…

查看全部问答>

3D报纸引领阅读潮流 成本与内容成制约发展瓶颈

本帖最后由 jameswangsynnex 于 2015-3-3 19:57 编辑 自2009年年底起,3D在国内成为了“时尚”的代名词,继3D电影《阿凡达》、《爱丽丝梦游仙境》在中国市场赚得盆满钵满,3D似乎也成为了报刊企业的又一掘金点。   2010年4月16日,湖北《十堰晚 ...…

查看全部问答>

参与芯币兑换的AVR学习板和编程器调试总结

USB型51/AVR编程器   可能大家都已经等不及了,不过“磨刀不误砍柴工”,大家还是耐心等待我们将该学习板调试完,确保大家能够更好的学习     说明:该编程器支持AT89S51/52系列单片机,还支持AVR的全系列单片机。 该编程器使 ...…

查看全部问答>

S3C6410 拍照问题,高手指教

程序预览没问题,拍照800*600也没问题 但是当拍照改为1024*768,1280*1024,1600*1200时,会出现无效数据,随着分辨率的增大,无效数据会越来越多。 当为1600*1200时,有效的部分好像是800*600的两倍。 感觉好像取到的数据一直是800*600,又感觉 ...…

查看全部问答>

请教一个 MSP430+CC1100/CC1101 的问题

我利用MSP430控制CC1101进行两个模块之间的无线通信,发现如果地址控制字PKTCTRL1如果为0x06或0x02,通信没问题,但是如果设置为0,就只能通信几次,之后就不行了。 通信方式:模块A定时循环发送消息,模块B循环等待接收。 CC1101寄存器设置:模 ...…

查看全部问答>

WCE下的ToolTip

我最近研究WCE下的SDK编程的ToolTip的使用,发现同样的代码,VC可以正常,而EVC就是不能正常使用ToolTip,大家有任何关于WCE的ToolTip的代码不,发个来参考下。 贴上来或者发到我邮箱都可以:magic_kaoya@163.com…

查看全部问答>

什么工具开发驱动程序最快最简单

什么工具开发驱动程序最快最简单? 需要那些基本知识? 介绍几本相关的学习资料,谢了!…

查看全部问答>