基于ARM的数码相框设计【开题报告+文献综述+毕业论文】

基于ARM的数码相框设计【开题报告+文献综述+毕业论文】

ID:463623

大小:9.51 MB

页数:77页

时间:2017-08-05

上传者:U-944
基于ARM的数码相框设计【开题报告+文献综述+毕业论文】_第1页
基于ARM的数码相框设计【开题报告+文献综述+毕业论文】_第2页
基于ARM的数码相框设计【开题报告+文献综述+毕业论文】_第3页
基于ARM的数码相框设计【开题报告+文献综述+毕业论文】_第4页
基于ARM的数码相框设计【开题报告+文献综述+毕业论文】_第5页
资源描述:

《基于ARM的数码相框设计【开题报告+文献综述+毕业论文】》由会员上传分享,免费在线阅读,更多相关内容在学术论文-天天文库

本科毕业论文系列开题报告电子信息工程基于ARM的数码相框设计一、课题研究意义及现状随着数码相机、扫描仪的普及,家庭中的数码照片不断增加,数码相框也变的越来越流行,它具备以下优点:⒈欣赏方便:传统的相册在多人欣赏时只好轮流进行,而数码相框可以很多人同时欣赏。  ⒉交互性强:可以像VCD点歌一样,将相册做成不同的标题,比如说:1我的童年,2我的大学生活。这样可以在遥控器上按下“1”键就播放你童年的照片,“2”键播放你大学时代的照片,根据你的照片具体内容可以细分,比如说增加“我的朋友”、“大约在冬季”等等。  ⒊储存量大:一张SD卡可储存几千张照片;  ⒋永久保存:SD卡存储介质寿命长达上百年;⒌欣赏性强:以高科技专业视频处理技术处理照片,并配上多种附加功能,永久保存、轻巧方便、时尚新潮!数码相框具有传统相框无法比拟的优越性:图、文、声、像并茂的表现手法,随意修改编辑的功能,快速的检索方式,永不褪色的恒久保存特性,以及廉价复制分发的优越手段。二、课题研究的主要内容和预期目标本课题是需要设计一个数码相框,能够实现电子相册的功能,并且有时间等信息显示。本系统总体指标及功能要求如下:(1)采用ARM作为主控芯片;(2)从SD卡里读取图片并在TFT液晶上进行显示;(3)实现多种模式的相片显示;(4)能够显示当前时间,环境温度等信息;(5)原理图的绘制和PCB的制作。本设计要求完成系统的软硬件部分并且能够进行实物作品演示。三、课题研究的方法及措施 本专业为工科类专业,实践与理论结合,通过实验的方式研究是此课题的主要方法。利用单片机,PC等设计并调试,测试硬件电路实际效果,以及软件硬件的综合调试效果。研究措施主要是模型设计和设计报告。设计中涉及到两个方面:硬件和软件。在硬件方面主要是电路的布局及布线以及外部框架结构与内部硬件的兼容,想要获得性能优良的硬件必须要兼顾各个方面。电路设计方面(电路原理图设计),AltiumDesigner为主流软件,在设计中线路的交叉和重叠需要极其注意,结合实际情况,用最简单、高效的方式实现。硬件方面外部机械结构的合理布局及机械结构与电路板的合理放置将很大程度上影响设计的难度和精度,设计时应在宏观的角度整体把握布局,兼顾各个部分的设计,这个环节需要多次检查,修改,以避免给今后的设计带来不必要的麻烦。本次设计主要是用到了ARM主控芯片,液晶和SD卡。在软件方面,主要在IAR或Keil集成开发环境下编写。收集大量的开源代码进行参考,程序通过C语言进行调试,按照先分后总的方式在调节单功能程序成功后,再实现整体化程序综合处理。设计报告是对设计的一个介绍和总结。各种文献为我们的设计提供理论上的技术支持,硬件方面通过AltiumDesigner软件设计电路,集成开发环境下编程,最后以实物模型进行展示。四、课题研究进度计划毕业设计期限:自2010年10月8日至2011年4月22日。第一阶段(5周):分析任务,搜集资料,系统总体方案设计,完成开题报告、文献综述、外文翻译。第1周:分析任务,搜集资料。第2,3周:完成对系统整体结构的设计及各模块的区分。第4,5周:完成开题报告、文献综述、外文翻译。第二阶段(5周):设计与写论文,硬件电路与软件程序设计,撰写设计报告与论文。第1周:完成芯片选型,电路设计。第2,3周:实现硬件电路的设计制作。第4周:完成软件部分的设计制作。第5周:将软件与硬件相结合,实现联合调试。第三阶段(2周):设计作品完善,论文修改。第1,2周:完成外壳设计,完善论文。五、参考文献[1]李晗.基于LinuxNFS的Web数码相框设计[J].电子技术与应用.2010.6:27-28.[2]刘艳霞、李淑芬.基于蓝牙通信的电子相框设计[J].微计算机信息,2008,24(30):114-115.[3]韦东山.嵌入式Linux应用开发完全手册[M].北京:人民邮电出版社,2008.[4]高鹏等.电路设计与制版Protel99入门与提高[M].人民邮电出版社.2001年6月. [5]朱振涛,王成儒,崔冬.S3C2410与TFT2LCD接口设计[J].电子测量技 术.2006,29(6):192-204.[6]张恒傅丰林.ARM9芯片EP9315驱动TFT_LCD的研究[J].电子科技.2007,5:4-7.[7]陈溯基于ARM平台的数码相框软件开发[M].人民邮电出版社.2008年12月[8]王伟能吴烁宇陈弟虎魏爱香,基于S3C2410和Qt_Embedded的数码相框设计[J],嵌入式系统应用,200906-2-0081-03[9]田野张浩,UCOS_II操作系统在数码相框中的应用,自动化技术与应用[J]2010年第29卷第8期[10]JouLD,BergerSA.Numericalsimulationoftheflowinthecarotidbifurcation[J].TheoreticalandComputationalFluidDynamics,1998(10):239-248. 毕业论文文献综述电子信息工程基于ARM的数码相框设计摘要:本文综述数码相框的各种方案、对比选择,熟悉和掌握了根据使用场合、具体指标选择合适的方案。关键词:ARM;数码相框;FAT16文件系统;SD卡;TFT液晶引言随着数码相机、扫描仪的普及,家庭中的数码照片不断增加,数码相框也变的越来越流行,它具有传统相框无法比拟的优越性,随意修改编辑的功能,快速的检索方式,永不褪色的恒久保存特性,以及廉价复制分发的优越手段。本文以此为出发点,进行数码框软硬件的开发研究工作。作为一款嵌入式产品,核心部件CPU采用了性能价格比、性能功耗比都很高的ARMv7架构处理器之中的一款----STMicroelectronicsSTM32,采用Cortex-M3内核,最高主频达72MHz,显示器采用了带触摸面板的24位真彩色TFT液晶。软件方面,STMicroelectronics为开发者提供了先进的固件库,大大减小了开发难度,加快了开发速度。同时Micrium为开发者提供了移植好的µC/OS嵌入式操作系统,以及适用于SD卡的文件系统µC/FS,极大的方便了开发者.针对界面设计和图片显示,Micrium还提供了µC/GUI,软件开发工作几乎就是模块的合并,配置和调试。[1]1、数码相框硬件平台结构本数码相框采用的主处理芯片是著名的ST公司生产的STM32F103芯片。STM32F103基于ARMv7架构,使开发者可以低成本设计复杂、低功耗和高度集成的SoC解决方案。它是特别针对创新性消费电子产品开发的。可专门针对嵌入式系统设计研发的。1.1主芯片整体结构 ARM32位的Cortex™-M3CPU最高72MHz工作频率,在存储器的0等待周期访问时可达1.25DMips/MHz(Dhrystone2.1)单周期乘法和硬件除法从256K至512K字节的闪存程序存储器高达64K字节的SRAM带4个片选的静态存储器控制器。支持CF卡、SRAM、PSRAM、NOR和NAND存储器并行LCD接口,兼容8080/6800模式多达2个I2C接口(支持SMBus/PMBus)多达5个USART接口(支持ISO7816,LIN,IrDA接口和调制解调控制)多达3个SPI接口(18M位/秒),2个可复用为I2S接口 CAN接口(2.0B主动)USB2.0全速接口SDIO接口[2]1.1硬件仿真器及相关软件硬件仿真器采用ARMJTAG型硬件仿真器。具有多用途JTAG接口,支持ARM内核全部芯片、支持Keil、IAR等IDE调试仿真。开发环境使用的是IAREWARM,安装调试使用Windows7操作系统。1.3数码相框解决方案系统框图由于这里设计目标是实现多功能的数码相框,故在设计方案中需要考虑以下几个方面的实现:(1)图片显示:需要支持标准和非标准的JPEG、JIF、BMP等式,图片可自动浏览、旋转和缩放。(2)通信:需要支持USB2.0Slave(3)文件系统:支持FAT16/32、EXT2、EXT3等格式(4)时间、温湿度显示等如图1为系统解决方案框图USBSlaveSTM32F103SD卡TFTLCDDS3231MSHT10Keyboard图1系统解决方案框图1.4SD卡接口电路本设计采用了SD卡接口电路来实现数据和外界的交换,SDCard(SecureDigitalCard)由松下、东芝和SanDisk共同开发研制,SD卡有9个引脚,安全性很高。SD卡共支持三种传输模式:SPI模式,1位SD模式和4位SD模式,本设计采用的是4位SD宽总线模式,数据在4根数据线(DAT[3:0])上同时传输,在这种模式下昀高的数据传输速率可达100Mb/s。当初始上电后,SD卡默认使用DAT0。经过初始化之后,主机可以改变线宽到4位。混合的 SD卡连接方式也适合于主机。在混合连接中,VCC,VSS和CLK的信号连接可以公用。而命令(CMD)和数据(DATA0~3)这几根线,各个SD卡必须从主机分开。SD总线上通信的命令和数据比特流从一个起始位开始,以停止位中止。[3]如图2为SD卡的接口原理图图2SD卡的接口原理图1.5实时时钟DS3231MDS3231M是业内首款集成了MEMS谐振器的温补RTC,低成本、高精度I²C实时时钟(RTC)。该器件包含电池输入端,断开主电源时仍可保持精确计时。集成微机电系统(MEMS)提高了器件的长期精确度,并减少了生产线的元件数量。DS3231M采用与流行的DS3231RTC相同的器件封装。[4]如图3为DS3231M与CPU的连接图 图3DS3231M与CPU的连接图如图4为TFT液晶模块接口原理图图4TFT液晶模块接口原理图1软件架构1.1操作系统为了方便在一个芯片上运行多个任务,这里采用了µC/OS作为嵌入式操作系统µC/OS和µC/OS-II是专门为计算机的嵌入式应用设计的,绝大部分代码是用C语言编写的。CPU硬件相关部分是用汇编语言编写的、总量约200行的汇编语言部分被压缩到最低限度,为的是便于移植到任何一种其它的CPU上。[5,6] 1.1LCD驱动µC/GUI是美国Micrium公司出品的一款针对嵌入式系统的优秀图形软件。它是为任何使用LCD图形显示的应用提供高效的独立于处理器及LCD控制器而设计的图形用户接口,它适用单任务或是多任务系统环境。架构基于模块化设计,由不同的模块中的不同层组成。包括液晶驱动模块,内存设备模块,窗口系统模块,窗口控件模块,反锯齿模块和触摸屏及外围模块。其主要特性包括丰富图形库,多窗口、多任务机制,窗口管理及丰富窗口控件类(按钮、检验框、单/多行编辑框、列表框、进度条、菜单等),多字符集和多字体支持,多种常见图像文件支持,鼠标、触摸屏支持,灵活自由配制等特性。[7,8]1.2SD卡驱动Micrium公司的µC/FS是高度可移植、可固化的嵌入式FAT文件系统。µC/FS的设备驱动结构非常简单.只需要读写分区的底层函数.所以要支持用户定制的硬件也很简单。[9]1.3RTCDS3231M使用了标准的I2C总线接口2.3.1I2C总线基本操作I2C规程运用主/从双向通讯。器件发送数据到总线上,则定义为发送器,器件接收数据则定义为接收器。主器件和从器件都可以工作于接收和发送状态。总线必须由主器件(通常为微控制器)控制,主器件产生串行时钟(SCL)控制总线的传输方向,并产生起始和停止条件。SDA线上的数据状态仅在SCL为低电平的期间才能改变,SCL为高电平的期间,SDA状态的改变被用来表示起始和停止条件。[10]  (1)控制字节  在起始条件之后,必须是器件的控制字节,其中高四位为器件类型识别符(不同的芯片类型有不同的定义,EEPROM一般应为1010),接着三位为片选,最后一位为读写位,当为1时为读操作,为0时为写操作。  (2)写操作  写操作分为字节写和页面写两种操作,对于页面写根据芯片的一次装载的字节不同有所不同。  (3)读操作   读操作有三种基本操作:当前地址读、随机读和顺序读。图4给出的是顺序读的时序图。应当注意的是:最后一个读操作的第9个时钟周期不是“不关心”。为了结束读操作,主机必须在第9个周期间发出停止条件或者在第9个时钟周期内保持SDA为高电平、然后发出停止条件。总结本数码相框的设计,利用uC/GUI中对图片的处理类已经实现了对BMP、GIF、JPG和PNG等多种格式的相片幻灯片播放的显示,实现了通过SD卡的扩展电路和USB电路和外界数据交换。由于硬件和软件系统的功能强大,二次开发的空间很大,还可以实现万年历,温度显示等等功能。参考文献[1]李晗.基于LinuxNFS的Web数码相框设计[J].电子技术与应用.2010.6:27-28.[2]刘艳霞、李淑芬.基于蓝牙通信的电子相框设计[J].微计算机信息,2008,24(30):114-115.[3]韦东山.嵌入式Linux应用开发完全手册[M].北京:人民邮电出版社,2008.[4]高鹏等.电路设计与制版Protel99入门与提高[M].人民邮电出版社.2001年6月.[5]朱振涛,王成儒,崔冬.S3C2410与TFT2LCD接口设计[J].电子测量技 术.2006,29(6):192-204.[6]张恒傅丰林.ARM9芯片EP9315驱动TFT_LCD的研究[J].电子科技.2007,5:4-7.[7]陈溯基于ARM平台的数码相框软件开发[M].人民邮电出版社.2008年12月[8]王伟能吴烁宇陈弟虎魏爱香,基于S3C2410和Qt_Embedded的数码相框设计[J],嵌入式系统应用,200906-2-0081-03[9]田野张浩,UCOS_II操作系统在数码相框中的应用,自动化技术与应用[J]2010年第29卷第8期[10]JouLD,BergerSA.Numericalsimulationoftheflowinthecarotidbifurcation[J].TheoreticalandComputationalFluidDynamics,1998(10):239-248. 本科毕业设计(20届)基于ARM的数码相框设计 摘要数字摄影的兴起不可避免地引起了数码相框的发展,对于数码相片的欣赏和摆设,人们一般只能通过PC机,极其不方便。数码相框正是迎合这种需求,它体积小,能随时更换相片。数码相框的基本原理就是采用普通相框的造型,把原来相框中间的照片部分换成液晶显示屏,配上电源,存储介质等,使得同一个相框内可以循环播放照片,它比普通的相框灵活,更有动感。本设计方案采用了STM32F103作为主控制器,μC/OS-II作为嵌入式操作系统。μC/GUI作为图形用户界面,相片的存储设备使用SD卡,可以十分方便的把数码相机中的SD卡取下来并在数码相框上播放。关键词:数码相框;μC/OS-II;嵌入式;FatFs;SD卡 AbstractTheriseofdigitalphotographyinevitablyattractedthedevelopmentofdigitalphotoframesfordigitalphotoappreciateanddecoration,peoplegenerallyonlythroughthePCandextremelyinconvenient.Thedigitalphotoframeitismeetthatdemand,itissmall,canchangeatanytimephotos.Thebasicprincipleisdigitalphotoframemodel,usingcommonamongtheoriginalphotographcasingwithLCDdisplay,photopartwithpower,storagemedium,makingthesameframeinsidecanloopingphotos,itthanordinaryframeflexible,morehavemovefeeling.ThisdesignschemeadoptedSTM32F103asthemaincontroller,μC/OS-IIasembeddedoperatingsystem.μC/GUIasthegraphicaluserinterface.PhotostoragedevicesusecanbeveryconvenientSDcard,thedigitalcameraofftheSDcardinthedigitalphotoframeandplay.KeyWords:Digitalpictureframes;μC/OS-II;Embedded;FatFs;SDcard 目录1 引言12 软硬件平台概要22.1嵌入式处理器简介22.1.1ARMCortex-M332位处理器22.2嵌入式操作系统简介32.2.1μC/OS-II实时操作系统52.3文件系统简介52.3.1FAT文件系统52.4GUI简介62.4.1μC/GUI图形用户界面63 总体方案设计83.1软件系统平台需求分析83.2功能分析83.2.1SD卡文件读取83.2.2图片显示功能93.2.3触摸控制功能94 数码相框的应用程序设计104.1μC/OS-II的移植与配置104.1.1Include.h和config.h124.1.2OS_CPU.H124.1.3os_cpu_c.c144.1.4OS_CPU_A.ASM154.1.5时钟节拍164.1.6中断服务程序164.2SD卡驱动程序与FatFs移植174.2.1SD卡初始化和识别过程184.2.2数据传输模式194.2.2FatFs移植214.3TFT液晶驱动与μC/GUI的移植224.3.1液晶驱动224.3.2μC/GUI移植234.4联合编写调试254.4.1任务层的组成和优先级254.4.2消息通信机制和状态机254.4.3整体实现265 结论与展望275.1结论275.2展望27 致谢28参考文献29附录1系统实物图30附录2实验原理图32附录3毕业设计作品说明书34附录4系统源程序35 1 引言随着数码相机的大量普及和人们对多媒体娱乐播放的需求,各种记忆卡越来越多地被运用于存放数码照片和其它多媒体文件。不同用户的电脑中存满各种各样的照片,甚至连桌面背景中照片的更换频率也增加了。输出照片,然后放到普通相框中,这样的过程比较麻烦,往往需要通过电脑显示与欣赏相片。对数码相片进行方便的显示、欣赏、编辑、打印等操作逐渐成为用户的需求。数码相框,电子相册等产品逐渐出现在数码市场,数码相框从概念型产品到进入市场已有八、九年之久。当前,数码相框主要针对礼品市场,但其真正的潜在用户却是非常广泛的,并且它的最终消费者应该是普通的家庭消费者,它的应用的领域将会非常广阔。内陆也有许多电子厂商很早就意识到此类产品的很好的发展趋势,例如曾作为NHJMP4中国地区总代理的北京中电金捷数码科技有限公司,就及时地推出了自有品牌的金捷数码相框,并且以出色的外观设计和良好的口碑,以及亲民的价格赢得了市场的青睐。 2 软硬件平台概要2.1嵌入式处理器简介嵌入式处理器是嵌入式系统的主要组成部分,是控制、辅助系统运行的硬件处理单元。范围非常广阔,嵌入式处理器从最初的4位单片机,到现在还在大量使用的8位单片机,到最新的受到广泛选择的32位,64位嵌入式CPU。全世界现在已有1000种以上的嵌入式处理器,包括微控制器,微处理器等流行体系结构30多个系列。由于看到了嵌入式系统非常好的发展前景,很多半导体制造商都大规模的生产嵌入式处理器,如TI,ST,NXP,Atmel,SAMSUNG等。而且公司自己设计的处理器也已经成为嵌入式领域的其中一个发展方向,其中从MCU、DSP到FPGA都有着各种各样的选择,处理速度越来越快,性能越来越强大,功耗越来越低,价格也越来越便宜。现在的嵌入式处理器最快的处理速度可以达到2000MIPS(如ARM公司的Cortex-A9),封装从8个引脚到144个引脚或更多不等。2.1.1ARMCortex-M332位处理器Cortex-M3是由ARM公司推出的一个32位的内核,在传统的单片机领域中,有一些不同于通用32位CPU应用的要求。在工控领域,由于用户要求具有更快的中断速度,Cortex-M3采用了Tail-Chaining(尾链)中断技术,中断处理完全基于硬件进行,最多可以节约12个时钟周期,在实际项目中可节约70%的中断的时间[1]。Cortex-M3 的其它一个特别之处是调试工具相对比较实惠,不像其它公司的仿真调试器动辄几千上万。对与此特点,ARM公司在早期JTAG调试接口的基础上增加了新设计的单线调试技术,只用两个引脚就可以调试,所以节省了大量的调试设备的支出。而且,Cortex-M3内置了大多数存储控制器,这样设计人员可以直接在MCU外连接Flash,降低了设计复杂度和应用障碍。加快了工程项目的开发速度。Cortex-M3处理器采用ARMv7-M架构,它包括全部的16位Thumb指令集和基础的32位Thumb-2指令集,Cortex-M3处理器不能执行ARM指令集。  Thumb-2在Thumb指令集架构(ISA)上进行了大量的改进,它与Thumb相比,具有更高的代码密度并提供16/32位指令的更高性能[2]。本设计使用的嵌入式处理器是意法半导体公司(ST)基于ARMCortex-M3的32位处理器芯片STM32F103VCT6LQFP100脚,片内具有256KBFLASH,48KBRAM(片上集成12BitA/D、D/A、PWM、CAN、USB、SDIO、FSMC等资源)。STM32系列32位闪存微控制器基于专门为嵌入式应用开发的具有突破性的ARMCortex™-M3内核,受益于Cortex-M3架构的增强型功能及性能改进的代码密度更高的Thumb-2指令集,STM32系列不仅大幅提升了中断响应速度,同时兼具业内最低的功耗。STM32是一个完整的32位系列产品,同时还具有高集成度和易开发性[4]。2.2嵌入式操作系统简介这些年嵌入式系统应用飞速发展的原因主要有几个方面:一是芯片制造技术的发展,使得单个芯片具有更多的功能,更强的处理能力,而且集成多种接口也已经早就实现,很多芯片生产厂商已经在这方面集中注意力。另一个原因就是应用的需要,由于对产品稳定性、功耗、成本等各种要求的提高,使得嵌入式系统从纯硬件实现和使用普通计算机实现的应用中逐渐脱颖而出,很快的被人们关注。从上面的定义,我们可以看到嵌入式系统的几个主要特征:1)系统内核小。因为嵌入式系统一般应用于中小型电子装置,系统资源相对有限,所以内核相对传统的操作系统要小很多。比如Enea公司的OSE系统,只有5K内核,而Windows的内核简直没有可比性。 2)专用性强。嵌入式系统的专用性很强,其中的软件系统和硬件的结合非常紧密,通常需要针对硬件进行系统的移植,即便在同一个品牌、同一系列的产品中也需要根据系统硬件的增减和变化不断地进行修改。同时针对不同的要求,往往需要对系统进行较大程度更改,程序的编译和下载需要和系统硬件结合起来,这种修改和通用软件的“更新”完全是不同的。3)系统简洁。嵌入式系统一般情况不会明显的区分系统软件和应用软件,不要求其实现和功能设计上过于复杂,这样一方面利于系统成本控制,同时也利于系统安全性。4)高实时性的系统软件是嵌入式软件的基本要求。而且软件要求固态存储,以提高速度;软件代码要求高稳定性和高质量。5)要使嵌入式软件标准化,必须得使用多任务的操作系统。嵌入式系统的应用程序可以不需要操作系统直接运行;但是为了利用系统资源更合理、调度多任务、系统以及库函数接口,用户必须自行选配RTOS(Real-TimeOperatingSystem)作为操作系统平台,这样才可以确保程序运行的可靠性、稳定性、实时性,并减少开发时间,增强可读性,保障软件质量。6)嵌入式软件的开发需要编译器和集成开发环境。因为它本身没有独立开发功能,即便设计完成以后用户往往也是不可以修改它的程序功能和实现,必须要有一套完整的开发环境和其它工具才能进行软件开发,这些工具和环境一般是在普通电脑上的各种逻辑分析仪、混合信号示波器和软硬件设备等。开发时往往要有主机和目标的概念,主机(PC)用于软件的开发,目标机执行,开发时往往需要多次交替结合进行。从软件方面划分,主要可以根据操作系统的不同类型。目前嵌入式系统的软件主要有三种操作系统:多道批量处理操作系统,分时系统和实时系统。其中实时系统又可以分成软实时系统和硬实时系统两种。多道批量处理操作系统一般用于计算中心比较大的计算机系统中。由于其硬件设施比较全,价格高,所以此操作系统十分注意CPU及其他设备的充分利用,追求高的吞吐量,不具备实时性。实时嵌入式系统是为执行特定功能而设计的,可以严格的按时序执行功能。其最大的特征就是程序的执行具有确定性。在实时系统中,如果系统在指定的时间内未能实现某个确定的任务,会导致系统的全面失败,则系统被称为硬实时系统。但是在软实时系统中,时间响应虽然也同样重要,但是相对短暂的超时不会导致致命的错误。硬实时系统通常需要添加专门当做时间和优先级管理的芯片来实现,而软实时系统则主要在软件方面通过编程实现时限的管理。比如Windows CE就是一个多任务分时系统,而μC/OS-II则是典型的实时操作系统。2.2.1μC/OS-II实时操作系统μC/OS-II由Micrium公司提供,是一个可移植、可裁剪的、可固化的、抢占式的多任务实时操作系统内核,它适用于绝大多数的微控制器,微处理器和数字处理芯片(已经被移植到至少100种以上的芯片中)。而且,此系统源代码整洁、开放、注释详细,非常适合系统开发。μC/OS-II已经得到联邦航空局(FAA)商用航行器认证,符合航空无线电技术委员会(RTCA)DO-178B标准[3]。在嵌入式系统中使用μC/OS-II将大大增加系统的稳定性,而且使得程序的调试变得更加简单。以往传统的嵌入式开发工作中经常遇到程序跑飞或是陷入死循环。程序跑飞可以用看门狗解决,但对于陷入死循环,尤其是其中使用到复杂的数学计算的话,只能通过设置断点,花费大量的时间来分析。但是如果使用μC/OS-II之后,事情就变得简单许多了。用户可以把原来的一个程序分成多个任务,每个任务彼此独立,在每个任务中设置超时,超时时间到了之后,就会失去CPU的使用权。如果一个低优先级的任务进入死循环,高优先级的任务还可以照样运行。这样既提高了系统的可靠性,程序的调试变得更加容易。2.3文件系统简介文件系统是操作系统用于确定磁盘上的文件的数据结构和方法;就是在磁盘上组织文件的方法。也是用于存储文件的磁盘或分区,或文件系统的种类。操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。文件系统由三部分组成:与文件管理相关软件、实施文件被和管理的文件管理需要的数据结构。用系统的方向去看,文件系统是对文件的存储器区域进行规划和配置,用于文件的存储并对保存的文件进行维护和搜索的系统。具体地说,文件系统是负责为用户创建文件,写入、读取、更改、复制文件,控制文件的读取写入,用户不需要使用的时候撤销文件等操作[7]。2.3.1FAT文件系统PC机使用的文件系统有FAT16,FAT32,NTFS等。像基于MS-DOS,Win 95等系统都采用了FAT16文件系统。在Win9X下,FAT16支持的分区最大为2GB。知道计算机的信息都保存在硬盘上的簇内。使用的簇越小,保存信息的效率就越高。在FAT16的情况下,分区越大簇就相应的要大,存储效率就越低,必然造成存储空间的浪费。随着计算机硬件不断升级和应用范围的不断扩大,FAT16已经不能很好地适应现在的操作系统和硬件。所以,微软推出了增强的文件系统FAT32。跟FAT16比较,FAT32有以下特点:1.与FAT16比较FAT32最大的特点是可以允许的磁盘容量达到2TB(2047GB),但是容量不能小于512MB。*基于FAT32的Win2000可以支持最大为32GB的分区;但是基于FAT16的Win2000可以支持最大为4GB的分区[6]。2.因为采用了更小的簇结构,FAT32文件系统可以更高效地保存信息。比如两个分区的大小都是2GB,一个分区使用了FAT16的文件系统,另外一个分区使用FAT32。使用FAT16的簇大小是32KB,FAT32的簇是4KB。这样的话FAT32就会比FAT16的存储效率要高出好多,一般情况下将会提升15%。2.4GUI简介GUI(GraphicalUserInterface,图形用户界面,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面。与早期计算机使用的命令行界面相比,图形界面对于用户来说在视觉上更易于接受。GUI的广泛应用是当前计算机发展的重大成就之一,它非常大地方便了普通用户的使用,用户从此不需要记住大量的命令,取而代之的是可以通过窗口、菜单、按键等方式来进行方便地操作。而嵌入式GUI具有下面几个方面的基本要求:占用资源少、高可靠性、轻型、可配置、便于移植、高性能等特点。2.4.1μC/GUI图形用户界面μC/GUI是美国Micriμm公司出品的一款针对嵌入式系统的优秀图形软件。与μC/OS一样,μC/GUI具有源码公开、可移植、可裁减、稳定性和可靠性高的特点。采用μ C/GUI,开发人员可以很方便地在液晶上显示文本、曲线、图形以及各种窗口对象如按钮、编辑框、滑动条等,可完全产生类似于Windows的显示效果。另外,μC/GUI提供了在VC下的仿真库,这使得用户完全可以在Windows下仿真μC/GUI的各种效果。采用μC/GUI,可以大大降低嵌入式系统中显示设计的难度,但μC/GUI的使用需针对不同的液晶编写相应的驱动程序才能实现。μC/GUI是一种嵌入式应用中的图形用户界面.它设计针对任何使用LCD图形显示的应用,提供高效的独立于处理器及LCD控制器的图形用户接口,它适用单任务和是多任务系统环境,并适用于任意LCD控制器和CPU下任何尺寸的真实显示或虚拟显示.它是模块化设计架构的,由于不同的模块中由不同层组成,用一个LCD驱动层来包含所有对LCD的具体图形操作,μC/GUI可以在任何的CPU上运行,因为它是用标准C代码编写的,兼容任何开发环境μC/GUI能够适应大多数的使用黑白或彩色LCD的应用,它提供很好的允许处理灰度的颜色管理.还提供一个可扩展的2D图形库及占用极少RAM的窗口管理体系[5]。 3 总体方案设计3.1软件系统平台需求分析本设计选用的STM32处理器,主频最高可达72MHZ,可以流畅运行μC/OS-II,FreeRTOS等嵌入式操作系统。在目前主流的嵌入式操作系统中,开放源码的μC/OS-II的学习资料丰富,学习人数相对较多,很适合作为学习研究的对象。因为用到了操作系统,如何移植操作系统也是学习嵌入式系统的一个重点,它把嵌入式硬件和嵌入式操作系统连接起来,对于嵌入式系统后续软件的开发非常重要,在整个开发中占有一定地比例。本设计采用Micriμm公司官网提供的STM32移植范例。数码相框需要存储大量的图片,本系统采用了SD卡作为存储介质,为方便照片存取,需要支持常见的文件系统。为此,我选用了FatFs,它支持FAT12,FAT16和FAT32文件系统,免费,开源,且遵循ANSIC编写。数码相框的用户群体非常广泛,为了实现产品的各种功能,必须有人性化、易操作的图形用户界面。与已前嵌入式设备简单的黑白用户界面相比,现在的嵌入式GUI软件功能非常强大,图像界面华丽。我选用的是Micriμm公司的μC/GUI。3.2功能分析数码相框就是一个相框,不过它不再用放进相片的方式来展示,而是通过一个液晶的屏幕显示,它可以通过SD卡获取相片,并设置循环显示的方式,比普通的相框更灵活多变,也给现在日益使用的数码相片一个新的展示空间。3.2.1SD卡文件读取支持FAT12,FAT16和FAT32文件系统。自动扫描SD卡所有图片文件。 3.2.2图片显示功能支持常见的图片格式:BMP,JPEG,GIF。3.2.3触摸控制功能支持屏幕触摸操作切换图片,删除图片等操作 4 数码相框的应用程序设计本设计的程序设计主要包括μC/OS-II的移植、配置,在μC/OS-II下编写SD卡驱动程序,TFT液晶驱动程序,FatFs文件系统的移植,μC/GUI的移植配置,以及程序的联合编写,调试。4.1μC/OS-II的移植与配置实时操作系统的使用,大大简化了基于嵌入式系统的应用开发,有效地确保了稳定性和可靠性,便于维护和二次开发。μC/OS-II是一个基于抢占式的实时多任务内核,可剪裁、可固化、具有高可靠性和稳定性,除此以外,μC/OS-II是自由软件,非商业的运用如教学、科研都是免费的。任何人都可以使用其源代码,通过配置和移植,让它满足自己的要求。本设计使用的是STM32F103VCT6,在Micriμm官方的主页上可以找到STM32F103ZE的在IAR平台下的完整移植案例,但实际应用时,还需了解μC/OS-II的总体结构。图4.1.1所示是μC/OS-II的结构及与硬件的关系。 图4.1.1μC/OS-II的结构及与硬件的关系。根据μC/OS-II的要求,移植μC/OS-II到一个新的体系结构上需要提供2个或3个文件:OS_CPU.H(C语言头文件)OS_CPU_C.C(C程序源文件)OS_CPU_A.ASM(汇编程序源文件)其中OS_CPU_A.ASM在某些情况下不需要,但极其罕见。不需要OS_CPU_A.ASM的必须满足以下苛刻条件,而同时满足这些条件的微控制器几乎没有:1.可以用C语言写中断服务程序;2.可以用C语言打开和关闭中断;3.可以用C语言保存所有CPU的寄存器。4.可以用C语言对堆栈指针进行操作; 4.1.1Include.h和config.hμC/OS-II中所有的.C文件都要包含了includes.h头文件,这样使得用户项目中的每个.C文件不用分别去考虑它实际上需要哪些头文件。使用INCLUDES.H的唯一缺点是会增加编译器的负担,但却增强了代码的可移植性。在移植的时候还增加了一个头文件config.h,这里要求所有用户引用程序必须要包含config.h,在config.h中包含includes.h和特定的头文件和配置项。但μC/OS-II系统文件仍然只包含了includes.h,所以μC/OS-II系统文件完全不需要改动。在config.h中进行所有的配置,就不用改动includes.h文件。这样可以加快μC/OS-II的系统文件的编译速度,编译时间相对变短。图4.1.2μC/OS-II文件关系图4.1.2OS_CPU.H(1)可移植性类型定义μCOS-II不使用C语言中的short、int、long等数据类型的定义,因为它们区别于与不同的处理器,不可以在所有平台上移植。用移植性强的整数数据类型代替,这样,既增强了可读性又可移植,不过这就成了必须移植的代码。typedefunsignedcharBOOLEAN;typedefunsignedcharINT8U;typedefsignedcharINT8S;typedefunsignedshortINT16U;typedefsignedshortINT16S; typedefunsignedintINT32U;typedefsignedintINT32S;typedeffloatFP32;typedefdoubleFP64;typedefINT32UOS_STK;(2)软中断底层接口为了与处理器状态无关的底层接口函数,同时在调用任务时对应的函数不用知道函数的具体位置,本移植使用SWI软中断指令作为底层接口,分别用不同的功能号区分开不同的函数。软中断功能号分配表如表4-1-3所示,未列出的为保留功能。表4-1-3软中断功能号分配表功能号接口函数简介0x00VoidOS_TASK_SW(void)切换任务的函数0x01_OSStartHighRdv(void)运行由OSStartHighRdy产生的优先级最高的任务0x02VoidOS_ENTER_CRITICAL(void)关中断0x03VoidOS_EXIT_CRITICAL(void)开中断0x80VoidChangeToSYSMode(void)切换任务到系统模式0x81VoidChangeToUSRMode(void)切换任务到用户模式0x82VoidTaskIsARM(INT8Uprio)ARM代码0x83VoidTaskIsTHUMB(INT8Uprio)THUMB代码用软中断作为操作系统的底层接口就需要在C语言中使用SWI指令。在IAR中,使用__swi关键字,用这个关键字声明一个函数,在调用该函数的地方插入一条SWI指令,然后指定功能号。同时,这个函数也可以有参数和返回值,其传递规则与一般函数一样。 图4.1.4软中断与函数名示例(3)堆栈生长方向μCOS-II使用常量OS_STK_GROWTH指定堆栈的生长方向:配置OS_STK_GROWTH为0表示堆栈从下往上长。配置OS_STK_GROWTH为1表示堆栈从上往下长。虽然ARM处理器核对于两种方式均支持,但IAR的C语言编译器仅支持一种方式,即从上往下长,并且必须是满递减堆栈,所以OS_STK_GROWTH的值为1。#defineOS_STK_GROWTH14.1.3os_cpu_c.cOSTaskStkInit()接口这是初始化任务堆栈函数,让任务的堆栈变成像刚发生中断一样。即任务被执行时,就好像从中断返回。编写这个函数,需要先确定任务的堆栈结构。而任务的堆栈结构跟CPU的体系结构、编译器有非常大的关联。本设计移植的堆栈结构如图4.1.6所示 图4.1.6堆栈结构图软件中断服务程序操作系统与硬件相关的底层函数使用软件中断作为接口。移植代码的其中一个重要的环节就是为这些软件中断编写服务程序。Hook()函数在Os_cpu_c.c文件中还有许多钩子函数,它们在某个特定的系统动作时被调用,会执行函数中的代码。这些默认是空函数,可以根据实际需要添加代码。4.1.4OS_CPU_A.ASM软中断在Os_cpu_a.s文件中有软件中断的汇编接口程序、任务切换程序、OS启动时运行出于就绪状态的最高优先级的任务的程序。当发生软件中断时,程序通过异常向量表跳转到软中断的汇编与C接口程序SoftwareInterrupt处,图4.1.9为SoftwareInterrupt的流程图。 图4.1.9SoftwareInterrupt流程图4.1.5时钟节拍STM32中的system_tick定时器是专门为操作系统设计的,一般频率设为10-100Hz,频率过高会加重cpu的负担时钟节拍的实际频率取决于用户应用程序的精度。根据system_tick定时器频率修改:os_cfg.h中#defineOS_TICKS_PER_SEC1004.1.6中断服务程序因为中断发生时中断肯定是打开的,所以如果用户在清除中断源之前调用μC/OS-II的系统服务函数就很可能会造成芯片的中断系统工作异常而使程序工作异常。因此在函数开始处执行OS_ENTER_CRITICAL()。如果用户程序没有这种情况,则不需要这个操作。在执行OS_EXIT_CRITICAL()后,中断重新打开,如果在执行下面的用户处理程序中发生了中断,就可以实现中断嵌套。中断服务程序过程示例如下所示: voidISR(void){OS_ENTER_CRITICAL();…………………….OS_EXIT_CRITICAL();}4.2SD卡驱动程序与FatFs移植SecureDigital通常缩写为SD,作为一种存储卡,全名应该是SecureDigitalMemoryCard,中文翻译为安全数码卡或直接称为SD卡,是一种存储卡的标准,它被广泛地于便携式设备上使用,例如数字相机、个人数码助理(PDA)和多媒体播放器等。SD卡的技术建是基于MultiMedia卡(MMC)格式上,但SD卡比MMC卡略厚。而SD卡也有较高的数据传送速度,而且不断地更新标准。大部份SD卡的侧面设有写保护控制,以避免一些数据意外地写入,而少部分的SD卡甚至支持数字版权管理(DRM)的技术。一般SD卡的大小约为32mm×24mm×2.1mm,但可以薄至1.4mm,与MMC卡相同。SD卡支持两种总线协议,SD总线和SPI总线,本设计使用的主控制器STM32F103VCT6自带1个SDIO接口和多个SPI接口,开发板选择了SPI2接口。如下表所示。表4-1STM32SP2接口引脚定义端口功能PB12SPI2_NSSPB13SPI2_SCKPB14SPI2_MISOPB15SPI2_MOSI 图4-2SD卡模块原理图SPI总线协议和SD总线协议的应答行为有下列三处不同点:1.被选中的卡总是对命令做出应答;2.使用的应答结构是8或16位的;3.当这个卡碰到一个数据检索问题,它将用一个错误应答来回答(取代了原先期望的数据块)而不是SD总线协议模式下的超时。SD卡有所谓操作模式(operationmode)的概念,每种操作模式又具体对应一种或多种状态,主机通过发送命令可以使SD卡在不同的状态间转换,SD卡则接受命令,并根据自己现在所处状态做出不同的响应。4.2.1SD卡初始化和识别过程如图4-3,SD卡的初始化开始于接收到ACMD41指令之后,ACMD指令的HCS(HostCapacitySupport)位如果设定为1的话,表明控制器支持SDHC卡,否则表示不支持。在CMD8命令发送之后的ACMD41指令其功能有所扩展,在参数里多了HCS部分,在响应里面多了CCS(CardCapacityStatus)部分。HCS参数会被不响应CMD8命令的SD卡所抛弃。控制器向不响应CMD8的卡发送ACMD41指令时,HCS位应该设置为零0。如果向SDHC卡发送HCS位为0的ACMD41命令,SDHC卡返回的响应,其busy标识位永远为0,代表忙状态。HCS标识位用来表明SD卡是否已经完成初始化,如果未完成,HCS为零,否则为1,如果HCS为0,控制器会重复发送ACMD41指令,SD卡只检查首次接收到的ACMD41指令的HCS位。 响应CMD8的SD卡发送的对于ACMD41指令响应会包含CCS部分,控制器只检查HCS标志位为1的响应所包含的CCS位。CCS=1表明其为SDHC卡,否则为标准SD卡。控制器随后发送ALL_SEND_CID(CMD2)命令,查询各个卡的CID(uniquecardidentification)值,还没有被识别的SD卡(处于Ready状态)会发送CID值作为响应,发送完CID值之后,SD卡进入识别状态(Identificationstate),然后控制器发送CMD3(SEND_RELATIVE_ADDR)命令,要求各个SD卡发送一个新的相对地址(RCA),RCA在之后的数据传输模式中用于寻址。RCA发送完之后。SD卡进入Stand-by状态,在这个状态,如果控制器想要给SD卡分配一个新的RCA,它可以发送另一条CMD3命令给SD卡。最后发布的RCA为SD卡的真实RCA。图4-3SD卡初始化和识别过程4.2.2数据传输模式 在SD卡识别模式结束之前,控制器使用的时钟频率均为Fod。在数据传输模式,控制器可能会使用Fpp频率。控制器发送一条SSEND_CSD(CMD9)命令来获取SD卡CSD寄存器(CardSpecificData)里面的描述值,譬如,块长度,卡容量信息等。广播命令SET_DSR(CMD4)为各个已识别的SD卡配置驱动阶段。它会向SD卡的DSR寄存器写入相关的信息。控制器的时钟频率也在这个时刻从Fod转到Fpp。SET_DSR命令是可选的[8]。CMD7命令用来选择某个SD卡,使其进入Transfer状态,在指定时间段内,只有一个卡能处于Transfer状态。当某个先前被选中的处于Transfer状态的SD卡接收到CMD7之后,会释放与控制器的连接,并进入Stand-by状态。当CMD7使用保留地址0x0000时,所有的SD卡都会进入Stand-by状态。数据传输模式下各个状态的转换关系总结如下: 所有的数据读命令都可以被停止命令(CMD12)在任意时刻终止。数据传输会终止,SD卡返回Transfer状态。读命令有:块读操作(CMD17)、多块读操作(CMD18)、发送写保护(CMD30)、发送scr(ACMD51)以及读模式下的普通命令(CMD56)所有的数据写命令都可以被停止命令(CMD12)在任意时刻终止。写命令也会在取消选择命令(CMD7)之前停止。写命令有:块写操作(CMD24,CMD25)、编程命令(CMD27)、锁定/解锁命令(CMD42)以及写模式下的普通命令(CMD56)数据传输一旦完成,SD卡会退出数据写状态,进入Programming状态(传输成功)或者Transfer状态(传输失败)如果块写操作被叫停,但是写操作包含的最终块其长度和CRC校验是正确的话,数据会被编程到SD卡(从缓存写入到Flash)SD卡可能会提供缓存模式,意思是前次写入块在编程到Flash的时刻,控制器可以接着发送下一块的数据当写缓存为满时刻,并且SD卡处于Programming状态,DAT0会保持为低电平(BUSY),表明其为忙状态写CSD,写保护,擦除这些操作没有缓存的功能,当SD卡正在处理这些命令的时候,其余的数据传输命令会被忽略。当SD卡为忙,并且处于Programming状态的时候,DAT0也会被SD卡拉低,在SD卡处于Programming状态时候,不允许控制器发送设置参数命令。设置参数命令有:设置块长度(CMD16)、擦除块开始(CMD32)以及擦除块结束(CMD33)在SD卡编程时刻,读命令也是不允许的,当把另一个卡从Stand-by状态转换为Transfer状态的时候,正处于erase和Programming状态的卡其操作不会终止,它会自动进入Disconnect状态,释放数据线。处于Disconnect状态的卡可以通过发送CMD7命令使其脱离此状态,并进入Programming状态,并重新激活忙标识符复位SD卡(使用CMD0或者CMD15)会终止任何等待中或正在进行的Programming操作。这可能会损毁SD卡的数据CMD34-37CMD50,CMD57保留[9]2GbyteSD卡:为使用2Gbyte的SD卡,MaximumBlockLength(READ_BL_LEN=WRITE_BL_LEN)参数须设置为1024byte。但是,由CMD6设置的BlockLength须为512byte,从而可与最大仅可使用512byteBlockLength的SD卡相兼容本设计中使用的SD卡驱动程序改写自MartinThomas,ChaN的sd_spi_stm32.c4.2.2FatFs移植FatFs是一个通用的文件系统模块,用于在小型嵌入式系统中实现FAT文件系统[10]。FatFs的编写遵循ANSIC,因此不依赖于硬件平台。它可以嵌入到便宜的微控制器中,如8051,PIC,AVR,SH,Z80,H8,ARM等等,不需要做任何修改。特点:FAT12,FAT16与FAT32.多个卷(物理驱动器与分区).两种分区规则:FDISK与Super-floppy.多种配置选项:长文件名支持。可选的编码页,包括DBCS(译者:DBCS为双位元组字元系统DoubleByteCharSystems)多任务支持只读,最小化API,缓冲区配置等等磁盘I/O接口因为FatFs模块完全与磁盘I/O层分开,因此需要下面的函数来实现底层物理磁盘的读写与获取当前时间。底层磁盘I/O模块并不是FatFs的一部分,并且必须由用户提供。资源文件中也包含有范例驱动[11]。 disk_initialize-Initializediskdrive初始化磁盘驱动器disk_status-Getdiskstatus获取磁盘状态disk_read-Readsector(s)读扇区disk_write-Writesector(s)写扇区disk_ioctl-Controldevicedependentfeatures设备相关的控制特性get_fattime-Getcurrenttime获取当前时间本设计中的驱动函数已经包含在sd_spi_stm32.c中。4.3TFT液晶驱动与μC/GUI的移植本设计的用户显示接口硬件上使用一块2.8寸,240x320分辨率,16.7M色的TFT液晶,软件使用μC/GUI作为嵌入式图形用户界面,极大的简化了应用程序的开发。4.3.1液晶驱动TFT液晶使用的驱动芯片为ILI9320。可选接口有18位、16位、9位。8位并行和SPI串行。在本设计中,我根据实际情况,选用16位并行接口。图4.3.1为液晶驱动器框图,图4.3.2为MCU与液晶的连接方案图 图4.3.1液晶驱动器框图图4.3.2MCU与液晶的连接方案图为简化程序设计,加快液晶屏刷屏速度,本设计使用16位单次传输,实际的颜色为65536色,数据格式如图4.3.3 图4.3.3数据格式图其中24位图形点转换为16位的程序如下:#defineRGB565CONVERT(red,green,blue)(WORD)(((red>>3)<<11)|((green>>2)<<5)|(blue>>3))4.3.2μC/GUI移植由于μC/GUI提供了源代码,因此可以很容易的将它移植到当前平台上,使用时,直接解压μC/GUI软件包即可。本设计使用的μC/GUI改写自FireBull开发板示例程序,但实际使用时还需对μC/GUI有一定的了解。如图4.2.1为μC/GUI软件体系结构,μC/GUI函数库为用户的应用程序提供GUI接口,包含的函数有文本、数值、二维图形图4.3.1μC/GUI软件体系结构需要的硬件接口函数如下表:均在文件ili9320_ucgui.c文件中实现表4-3-2需要实现的函数函数名称功能 LCD_L0_InIt()屏幕初始化LCD_L0_ReInIt()重新初始化但不擦除当前显示内容LCD_L0_OFF关显示LCD_L0_ON开显示LCD_L0_DrawBitmap()画图片LCD_L0_DrawPixel()画点(指定颜色)LCD_L0_DrwaVline()画水平线LCD_L0_DrwaVline()画垂直线LCD_L0_FillRect()填充矩形LCD_L0_XorPixel()指定点颜色翻转4.4联合编写调试4.4.1任务层的组成和优先级该系统需要以下几个任务:主任务、SD卡文件读取任务,图片解码任务、GUI界面任务,图片显示任务。每个任务都有以下几部分组成:应用程序、任务的堆栈以及任务的状态。任务堆栈用以存储CPU寄存器和其它的内容。当某任务由运行态变为其他状态时,CPU寄存器内容压入相应任务堆栈,由其它状态转变为运行态时则将相应任务堆栈内容置入CPU寄存器。任务的状态机记录了当前任务的运行状态,每次新的消息传递给任务时,任务可根据状态机来查询对应的状态,用于决定下一步的该怎么操作。任务优先级的分配是根据重要性和实时性需求来确定的。主任务的优先级设置为最高。对于其他几个任务一般没有太多的约束,我们可以任意安排其优先级。优先级从高到底的顺序排列:主任务,SD卡文件读取任务,图片解码任务,图片显示任务,GUI界面任务。 4.4.2消息通信机制和状态机在这个数码相框系统中,消息的类型主要有两种:一是外部输入(触摸屏)转化的消息;二是任务之间互相传递的消息。第一类消息不知道谁来接受,直接由主任务处理,主任务通过查找状态机获得每个任务当前的运行情况后,进行消息转换之后发给目标任务,由目标任务来进行具体处理。目标任务接受到主任务传送过来的消息之后,判断自身的状态机,然后执行预订的处理。每个任务都有一个固定的时间点来查询新的消息。图片显示任务是一个不断循环读取数据和显示的过程,利用每次循环结束的时间查询新的消息。第二类消息是任务与任务之间互相传递的消息,消息的接受方是已知的。所以在两个相互需要通信的任务之间要建立消息邮箱和信号量进行同步和通信。4.4.3整体实现在主函数main中初始化μC/OS-II操作系统,创建总控任务、图片显示任务、GUI界面任务,同时创建信号量和mailbox等系统资源供应用程序调用,启动μC/OS-II操作系统。此后将CPU的控制权交给OS,OS将CPU的控制权首先给予优先级最高的总控任务。优先级最高的总控任务运行后,所有外设的驱动,包括SD卡、LCD、GUI、定时器,打开有需要的中断,然后主任务开始轮询外部消息,有消息进来时通过上面描述的状态机,传递给其他任务,让其他任务运行,同时确保每隔若干个时钟节拍再次轮询一次消息队列,有新的消息则处理,没有新消息则立即执行其它就绪的任务。voidmain(){OSlnit(),//初始化μC/OS-IIMbox_pic=OSMboxCreate((void*)0);Mbox_GUI=OSMboxCreate((void*)O);AppSem[0]=OSSemCreate(1);AppSem[1]=OSSemCreate(1);OSTaskCreate(TaskStart,(void*)O,(OS_STK*)&AppTaskStartStk[0],1);OSTaSkCreate(TaskPic,(void*)O,(OS_STK*)&TaskPicStk[0],4); OSTaskCreate(TaskDis,(void*)O,(OS_STK*)&TaskDisStk[0],5);OSTaskCreate(TaskGUI,(void*)0,(OS_STK*)&TaskGUIStk[0],6);OSStart();} 5 结论与展望5.1结论本设计硬件采用ARMCortex-M3系列的STM32F103为主处理芯片,操作系统采用嵌入式μC/OS-II,结合操作界面μC/GUI开发了ARM的数码相框应用程序,实现了数码相框基本的功能。5.2展望本设计还有很大的发展空间。在硬件上,第一,可以再加一个DSP处理器,可以实现视频播放功能;第二,可以加上一个网络接口或WIFI模块,实现网络获取图片的功能;第三,可以加一个摄像头,实现拍照摄像功能。软件上,第一,μC/OS-II可以再裁剪,优化,减少空间占用,增加更多的应用;第二,实现上面三项硬件增加后对应软件需要的功能。 参考文献[1]百度百科.Cortex-M3[EB/OL],[2010年12月21日].baike.baidu.com/view/1833994.htm[2]邵贝贝.嵌入式实时操作系统UCOS-Ⅱ[M].第二版.北京航空航天大学出版社,2003.6.[3]田野,张浩,UCOS-Ⅱ操作系统在数码相框中的应用[J],自动化技术与应用,2010,29(8):13~16.[4]杜春雷.ARM体系结构与编程[M].清华大学出版社,2005.[5]胥静.嵌入式系统设计与开发实例详解[M].北京航空航天大学出版社,2005[6]王宇行.StudyARMStepbyStep.Ebook[EB/PDF],2008—08[7]温泽宇;刁鸣;张浩基于UC/GUI图形系统在数码相框中的应用[J],应用科技,2008(03):13~16.[8]王田苗主编.嵌入式系统设计与实例开发[M].第二版.北京:清华大学出版社,2002.9.l-260.[9]陈溯.基于ARM平台的数码相框软件开发[D].厦门大学.电子工程,2008.12.01[10]姜换新.ARM嵌入式系统C语言编程[M].TsinghanTongfangOpticalDiscCo.,Ltd.2002[11]郑灵翔.嵌入式系统设计与应用开发[M].北京航空航天大学出版社,2006 附录1系统实物图 附录2实验原理图 附录3毕业设计作品说明书一、作品名称基于ARM的数码相框设计二、作品功能1、SD卡文件自动扫描2、屏幕触摸图片切换三、运行环境硬件环境:STM32开发板软件环境:单片机四、操作步骤1、接上液晶模块,插入SD卡2、将开发板接上5V电源3、触摸屏幕切换图片五、注意事项电路板不可用力按压 附录4系统源程序SD卡驱动程序/*-----------------------------------------------------------------------*//*MMC/SDSC/SDHC(inSPImode)controlmoduleforSTM32Version1.1.6*//*(C)MartinThomas,2010-basedontheAVRMMCmodule(C)ChaN,2007*//*-----------------------------------------------------------------------*//*Copyright(c)2010,MartinThomas,ChaNAllrightsreserved.Redistributionanduseinsourceandbinaryforms,withorwithoutmodification,arepermittedprovidedthatthefollowingconditionsaremet:*Redistributionsofsourcecodemustretaintheabovecopyrightnotice,thislistofconditionsandthefollowingdisclaimer.*Redistributionsinbinaryformmustreproducetheabovecopyrightnotice,thislistofconditionsandthefollowingdisclaimerinthedocumentationand/orothermaterialsprovidedwiththedistribution.*Neitherthenameofthecopyrightholdersnorthenamesofcontributorsmaybeusedtoendorseorpromoteproductsderivedfromthissoftwarewithoutspecificpriorwrittenpermission.THISSOFTWAREISPROVIDEDBYTHECOPYRIGHTHOLDERSANDCONTRIBUTORS"ASIS"ANDANYEXPRESSORIMPLIEDWARRANTIES,INCLUDING,BUTNOTLIMITEDTO,THEIMPLIEDWARRANTIESOFMERCHANTABILITYANDFITNESSFORAPARTICULARPURPOSEAREDISCLAIMED.INNOEVENTSHALLTHECOPYRIGHTOWNERORCONTRIBUTORSBELIABLEFORANYDIRECT,INDIRECT,INCIDENTAL,SPECIAL,EXEMPLARY,ORCONSEQUENTIALDAMAGES(INCLUDING,BUTNOTLIMITEDTO,PROCUREMENTOFSUBSTITUTEGOODSORSERVICES;LOSSOFUSE,DATA,ORPROFITS;ORBUSINESSINTERRUPTION)HOWEVERCAUSEDANDONANYTHEORYOFLIABILITY,WHETHERINCONTRACT,STRICTLIABILITY,ORTORT(INCLUDINGNEGLIGENCEOROTHERWISE)ARISINGINANYWAYOUTOFTHEUSEOFTHISSOFTWARE,EVENIFADVISEDOFTHEPOSSIBILITYOFSUCHDAMAGE.*/#include"stm32f10x.h"#include"ffconf.h"#include"diskio.h"typedefunsignedcharBOOL; #defineFALSE0#defineTRUE1//demousesacommandlineoptiontodefinethis(seeMakefile):#defineSTM32_SD_USE_DMA/*#ifdefSTM32_SD_USE_DMA//#warning"Informationonly:usingDMA"#pragmamessage"***UsingDMA***"#endif*//*setto1toprovideadisk_ioctrlfunctionevenifnotneededbytheFatFs*/#defineSTM32_SD_DISK_IOCTRL_FORCE0//demousesacommandlineoptiontodefinethis(seeMakefile)://#defineUSE_EK_STM32F//#defineUSE_STM32_P103//#defineUSE_MINI_STM32//#defineUSE_KEIL_MCBSTM32#ifdefined(USE_EK_STM32F)#defineCARD_SUPPLY_SWITCHABLE1#defineGPIO_PWRGPIOD#defineRCC_APB2Periph_GPIO_PWRRCC_APB2Periph_GPIOD#defineGPIO_Pin_PWRGPIO_Pin_10#defineGPIO_Mode_PWRGPIO_Mode_Out_OD/*pull-upresistoratpowerFET*/#defineSOCKET_WP_CONNECTED0#defineSOCKET_CP_CONNECTED0#defineSPI_SDSPI1#defineGPIO_CSGPIOD#defineRCC_APB2Periph_GPIO_CSRCC_APB2Periph_GPIOD#defineGPIO_Pin_CSGPIO_Pin_9#defineDMA_Channel_SPI_SD_RXDMA1_Channel2#defineDMA_Channel_SPI_SD_TXDMA1_Channel3#defineDMA_FLAG_SPI_SD_TC_RXDMA1_FLAG_TC2#defineDMA_FLAG_SPI_SD_TC_TXDMA1_FLAG_TC3#defineGPIO_SPI_SDGPIOA#defineGPIO_Pin_SPI_SD_SCKGPIO_Pin_5#defineGPIO_Pin_SPI_SD_MISOGPIO_Pin_6#defineGPIO_Pin_SPI_SD_MOSIGPIO_Pin_7#defineRCC_APBPeriphClockCmd_SPI_SDRCC_APB2PeriphClockCmd#defineRCC_APBPeriph_SPI_SDRCC_APB2Periph_SPI1 /*-forSPI1andfull-speedAPB2:72MHz/4*/#defineSPI_BaudRatePrescaler_SPI_SDSPI_BaudRatePrescaler_4#elifdefined(USE_STM32_P103)//OlimexSTM32-P103nottested!#defineCARD_SUPPLY_SWITCHABLE0#defineSOCKET_WP_CONNECTED1/*write-protectsocket-switch*/#defineSOCKET_CP_CONNECTED1/*card-presentsocket-switch*/#defineGPIO_WPGPIOC#defineGPIO_CPGPIOC#defineRCC_APBxPeriph_GPIO_WPRCC_APB2Periph_GPIOC#defineRCC_APBxPeriph_GPIO_CPRCC_APB2Periph_GPIOC#defineGPIO_Pin_WPGPIO_Pin_6#defineGPIO_Pin_CPGPIO_Pin_7#defineGPIO_Mode_WPGPIO_Mode_IN_FLOATING/*externalresistor*/#defineGPIO_Mode_CPGPIO_Mode_IN_FLOATING/*externalresistor*/#defineSPI_SDSPI2#defineGPIO_CSGPIOB#defineRCC_APB2Periph_GPIO_CSRCC_APB2Periph_GPIOB#defineGPIO_Pin_CSGPIO_Pin_12#defineDMA_Channel_SPI_SD_RXDMA1_Channel4#defineDMA_Channel_SPI_SD_TXDMA1_Channel5#defineDMA_FLAG_SPI_SD_TC_RXDMA1_FLAG_TC4#defineDMA_FLAG_SPI_SD_TC_TXDMA1_FLAG_TC5#defineGPIO_SPI_SDGPIOB#defineGPIO_Pin_SPI_SD_SCKGPIO_Pin_13#defineGPIO_Pin_SPI_SD_MISOGPIO_Pin_14#defineGPIO_Pin_SPI_SD_MOSIGPIO_Pin_15#defineRCC_APBPeriphClockCmd_SPI_SDRCC_APB1PeriphClockCmd#defineRCC_APBPeriph_SPI_SDRCC_APB1Periph_SPI2/*forSPI2andfull-speedAPB1:36MHz/2*//*!!PRESCALE4usedhere-2doesnotwork,maybebecauseofthepoorwiringontheHELI_V1prototypehardware*/#defineSPI_BaudRatePrescaler_SPI_SDSPI_BaudRatePrescaler_4#elifdefined(USE_MINI_STM32)#defineCARD_SUPPLY_SWITCHABLE0#defineSOCKET_WP_CONNECTED0#defineSOCKET_CP_CONNECTED0#defineSPI_SDSPI1#defineGPIO_CSGPIOB#defineRCC_APB2Periph_GPIO_CSRCC_APB2Periph_GPIOB#defineGPIO_Pin_CSGPIO_Pin_6#defineDMA_Channel_SPI_SD_RXDMA1_Channel2 #defineDMA_Channel_SPI_SD_TXDMA1_Channel3#defineDMA_FLAG_SPI_SD_TC_RXDMA1_FLAG_TC2#defineDMA_FLAG_SPI_SD_TC_TXDMA1_FLAG_TC3#defineGPIO_SPI_SDGPIOA#defineGPIO_Pin_SPI_SD_SCKGPIO_Pin_5#defineGPIO_Pin_SPI_SD_MISOGPIO_Pin_6#defineGPIO_Pin_SPI_SD_MOSIGPIO_Pin_7#defineRCC_APBPeriphClockCmd_SPI_SDRCC_APB2PeriphClockCmd#defineRCC_APBPeriph_SPI_SDRCC_APB2Periph_SPI1/*-forSPI1andfull-speedAPB2:72MHz/4*/#defineSPI_BaudRatePrescaler_SPI_SDSPI_BaudRatePrescaler_4#elifdefined(USE_KEIL_MCBSTM32)#defineCARD_SUPPLY_SWITCHABLE0#defineSOCKET_WP_CONNECTED0#defineSOCKET_CP_CONNECTED0#defineSPI_SDSPI1#defineGPIO_CSGPIOA#defineRCC_APB2Periph_GPIO_CSRCC_APB2Periph_GPIOB#defineGPIO_Pin_CSGPIO_Pin_4#defineDMA_Channel_SPI_SD_RXDMA1_Channel2#defineDMA_Channel_SPI_SD_TXDMA1_Channel3#defineDMA_FLAG_SPI_SD_TC_RXDMA1_FLAG_TC2#defineDMA_FLAG_SPI_SD_TC_TXDMA1_FLAG_TC3#defineGPIO_SPI_SDGPIOA#defineGPIO_Pin_SPI_SD_SCKGPIO_Pin_5#defineGPIO_Pin_SPI_SD_MISOGPIO_Pin_6#defineGPIO_Pin_SPI_SD_MOSIGPIO_Pin_7#defineRCC_APBPeriphClockCmd_SPI_SDRCC_APB2PeriphClockCmd#defineRCC_APBPeriph_SPI_SDRCC_APB2Periph_SPI1/*-forSPI1andfull-speedAPB2:72MHz/4*/#defineSPI_BaudRatePrescaler_SPI_SDSPI_BaudRatePrescaler_4#elifdefined(USE_FIRE_BULL_STM32)#defineCARD_SUPPLY_SWITCHABLE0#defineGPIO_PWRGPIOC#defineRCC_APB2Periph_GPIO_PWRRCC_APB2Periph_GPIOC#defineGPIO_Pin_PWRGPIO_Pin_8#defineGPIO_Mode_PWRGPIO_Mode_Out_PP/*pull-upresistoratpowerFET*/#defineSOCKET_WP_CONNECTED0#defineSOCKET_CP_CONNECTED0#defineSPI_SDSPI2#defineGPIO_CSGPIOB#defineRCC_APB2Periph_GPIO_CSRCC_APB2Periph_GPIOB #defineGPIO_Pin_CSGPIO_Pin_12#defineDMA_Channel_SPI_SD_RXDMA1_Channel4#defineDMA_Channel_SPI_SD_TXDMA1_Channel5#defineDMA_FLAG_SPI_SD_TC_RXDMA1_FLAG_TC4#defineDMA_FLAG_SPI_SD_TC_TXDMA1_FLAG_TC5#defineGPIO_SPI_SDGPIOB#defineGPIO_Pin_SPI_SD_SCKGPIO_Pin_13#defineGPIO_Pin_SPI_SD_MISOGPIO_Pin_14#defineGPIO_Pin_SPI_SD_MOSIGPIO_Pin_15#defineRCC_APBPeriphClockCmd_SPI_SDRCC_APB1PeriphClockCmd#defineRCC_APBPeriph_SPI_SDRCC_APB1Periph_SPI2/*-forSPI1andfull-speedAPB2:36MHz/2*/#defineSPI_BaudRatePrescaler_SPI_SDSPI_BaudRatePrescaler_2#else#error"unsupportedboard"#endif/*DefinitionsforMMC/SDCcommand*/#defineCMD0(0x40+0)/*GO_IDLE_STATE*/#defineCMD1(0x40+1)/*SEND_OP_COND(MMC)*/#defineACMD41(0xC0+41)/*SEND_OP_COND(SDC)*/#defineCMD8(0x40+8)/*SEND_IF_COND*/#defineCMD9(0x40+9)/*SEND_CSD*/#defineCMD10(0x40+10)/*SEND_CID*/#defineCMD12(0x40+12)/*STOP_TRANSMISSION*/#defineACMD13(0xC0+13)/*SD_STATUS(SDC)*/#defineCMD16(0x40+16)/*SET_BLOCKLEN*/#defineCMD17(0x40+17)/*READ_SINGLE_BLOCK*/#defineCMD18(0x40+18)/*READ_MULTIPLE_BLOCK*/#defineCMD23(0x40+23)/*SET_BLOCK_COUNT(MMC)*/#defineACMD23(0xC0+23)/*SET_WR_BLK_ERASE_COUNT(SDC)*/#defineCMD24(0x40+24)/*WRITE_BLOCK*/#defineCMD25(0x40+25)/*WRITE_MULTIPLE_BLOCK*/#defineCMD55(0x40+55)/*APP_CMD*/#defineCMD58(0x40+58)/*READ_OCR*//*Card-SelectControls(Platformdependent)*/#defineSELECT()GPIO_ResetBits(GPIO_CS,GPIO_Pin_CS)/*MMCCS=L*/#defineDESELECT()GPIO_SetBits(GPIO_CS,GPIO_Pin_CS)/*MMCCS=H*//*ManleyEK-STM32Fboarddoesnotoffersocketcontacts->dummyvalues:*/#defineSOCKPORT1/*Socketcontactport*/ #defineSOCKWP0/*Writeprotectswitch(PB5)*/#defineSOCKINS0/*Carddetectswitch(PB4)*/#if(_MAX_SS!=512)||(_FS_READONLY==0)||(STM32_SD_DISK_IOCTRL_FORCE==1)#defineSTM32_SD_DISK_IOCTRL1#else#defineSTM32_SD_DISK_IOCTRL0#endif/*--------------------------------------------------------------------------ModulePrivateFunctionsandVariables---------------------------------------------------------------------------*/staticconstDWORDsocket_state_mask_cp=(1<<0);staticconstDWORDsocket_state_mask_wp=(1<<1);staticvolatileDSTATUSStat=STA_NOINIT;/*Diskstatus*/staticvolatileDWORDTimer1,Timer2;/*100Hzdecrementtimers*/staticBYTECardType;/*Cardtypeflags*/enumspeed_setting{INTERFACE_SLOW,INTERFACE_FAST};staticvoidinterface_speed(enumspeed_settingspeed){DWORDtmp;tmp=SPI_SD->CR1;if(speed==INTERFACE_SLOW){/*Setslowclock(100k-400k)*/tmp=(tmp|SPI_BaudRatePrescaler_256);}else{/*Setfastclock(dependsontheCSD)*/tmp=(tmp&~SPI_BaudRatePrescaler_256)|SPI_BaudRatePrescaler_SPI_SD;}SPI_SD->CR1=tmp;} #ifSOCKET_WP_CONNECTED/*Socket'sWrite-ProtectionPin:high=write-protected,low=writable*/staticvoidsocket_wp_init(void){GPIO_InitTypeDefGPIO_InitStructure;/*ConfigureI/Oforwrite-protect*/RCC_APB2PeriphClockCmd(RCC_APBxPeriph_GPIO_WP,ENABLE);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_WP;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_WP;GPIO_Init(GPIO_WP,&GPIO_InitStructure);}staticDWORDsocket_is_write_protected(void){return(GPIO_ReadInputData(GPIO_WP)&GPIO_Pin_WP)?socket_state_mask_wp:0;}#elsestaticvoidsocket_wp_init(void){return;}staticinlineDWORDsocket_is_write_protected(void){return0;/*fakenotprotected*/}#endif/*SOCKET_WP_CONNECTED*/#ifSOCKET_CP_CONNECTED/*Socket'sCard-PresentPin:high=socketempty,low=cardinserted*/staticvoidsocket_cp_init(void){GPIO_InitTypeDefGPIO_InitStructure;/*ConfigureI/Oforcard-present*/RCC_APB2PeriphClockCmd(RCC_APBxPeriph_GPIO_CP,ENABLE);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_CP; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_CP;GPIO_Init(GPIO_CP,&GPIO_InitStructure);}staticinlineDWORDsocket_is_empty(void){return(GPIO_ReadInputData(GPIO_CP)&GPIO_Pin_CP)?socket_state_mask_cp:FALSE;}#elsestaticvoidsocket_cp_init(void){return;}staticinlineDWORDsocket_is_empty(void){return0;/*fakeinserted*/}#endif/*SOCKET_CP_CONNECTED*/#ifCARD_SUPPLY_SWITCHABLEstaticvoidcard_power(BOOLon)/*switchFETforcard-socketVCC*/{GPIO_InitTypeDefGPIO_InitStructure;/*TurnonGPIOforpower-controlpinconnectedtoFET'sgate*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_PWR,ENABLE);/*ConfigureI/OforPowerFET*/GPIO_InitStructure.GPIO_Pin=GPIO_Pin_PWR;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_PWR;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIO_PWR,&GPIO_InitStructure);if(on){GPIO_ResetBits(GPIO_PWR,GPIO_Pin_PWR);}else{/*Chipselectinternalpull-down(toavoidparasitepowering)*/GPIO_InitStructure.GPIO_Pin=GPIO_Pin_CS;GPIO_Init(GPIO_CS,&GPIO_InitStructure); GPIO_SetBits(GPIO_PWR,GPIO_Pin_PWR);}}#if(STM32_SD_DISK_IOCTRL==1)staticintchk_power(void)/*Socketpowerstate:0=off,1=on*/{if(GPIO_ReadOutputDataBit(GPIO_PWR,GPIO_Pin_PWR)==Bit_SET){return0;}else{return1;}}#endif#elsestaticvoidcard_power(BYTEon){on=on;}#if(STM32_SD_DISK_IOCTRL==1)staticintchk_power(void){return1;/*fakepowered*/}#endif#endif/*CARD_SUPPLY_SWITCHABLE*//*-----------------------------------------------------------------------*//*Transmit/ReceiveabytetoMMCviaSPI(Platformdependent)*//*-----------------------------------------------------------------------*/staticBYTEstm32_spi_rw(BYTEout){/*LoopwhileDRregisterinnotempty*////notneeded:while(SPI_I2S_GetFlagStatus(SPI_SD,SPI_I2S_FLAG_TXE)==RESET){;}/*SendbytethroughtheSPIperipheral*/SPI_I2S_SendData(SPI_SD,out);/*Waittoreceiveabyte*/ while(SPI_I2S_GetFlagStatus(SPI_SD,SPI_I2S_FLAG_RXNE)==RESET){;}/*ReturnthebytereadfromtheSPIbus*/returnSPI_I2S_ReceiveData(SPI_SD);}/*-----------------------------------------------------------------------*//*TransmitabytetoMMCviaSPI(Platformdependent)*//*-----------------------------------------------------------------------*/#definexmit_spi(dat)stm32_spi_rw(dat)/*-----------------------------------------------------------------------*//*ReceiveabytefromMMCviaSPI(Platformdependent)*//*-----------------------------------------------------------------------*/staticBYTErcvr_spi(void){returnstm32_spi_rw(0xff);}/*Alternativemacrotoreceivedatafast*/#definercvr_spi_m(dst)*(dst)=stm32_spi_rw(0xff)/*-----------------------------------------------------------------------*//*Waitforcardready*//*-----------------------------------------------------------------------*/staticBYTEwait_ready(void){BYTEres;Timer2=50;/*Waitforreadyintimeoutof500ms*/rcvr_spi();dores=rcvr_spi();while((res!=0xFF)&&Timer2); returnres;}/*-----------------------------------------------------------------------*//*DeselectthecardandreleaseSPIbus*//*-----------------------------------------------------------------------*/staticvoidrelease_spi(void){DESELECT();rcvr_spi();}#ifdefSTM32_SD_USE_DMA/*-----------------------------------------------------------------------*//*Transmit/ReceiveBlockusingDMA(Platformdependent.STM32here)*//*-----------------------------------------------------------------------*/staticvoidstm32_dma_transfer(BOOLreceive,/*FALSEforbuff->SPI,TRUEforSPI->buff*/constBYTE*buff,/*receiveTRUE:512bytedatablocktobetransmittedreceiveFALSE:Databuffertostorereceiveddata*/UINTbtr/*receiveTRUE:Bytecount(mustbemultipleof2)receiveFALSE:Bytecount(mustbe512)*/){DMA_InitTypeDefDMA_InitStructure;WORDrw_workbyte[]={0xffff};/*sharedDMAconfigurationvalues*/DMA_InitStructure.DMA_PeripheralBaseAddr=(DWORD)(&(SPI_SD->DR));DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_BufferSize=btr;DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;DMA_InitStructure.DMA_Priority=DMA_Priority_VeryHigh;DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;DMA_DeInit(DMA_Channel_SPI_SD_RX); DMA_DeInit(DMA_Channel_SPI_SD_TX);if(receive){/*DMA1channel2configurationSPI1RX---------------------------------------------*//*DMA1channel4configurationSPI2RX---------------------------------------------*/DMA_InitStructure.DMA_MemoryBaseAddr=(DWORD)buff;DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;DMA_Init(DMA_Channel_SPI_SD_RX,&DMA_InitStructure);/*DMA1channel3configurationSPI1TX---------------------------------------------*//*DMA1channel5configurationSPI2TX---------------------------------------------*/DMA_InitStructure.DMA_MemoryBaseAddr=(DWORD)rw_workbyte;DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Disable;DMA_Init(DMA_Channel_SPI_SD_TX,&DMA_InitStructure);}else{#if_FS_READONLY==0/*DMA1channel2configurationSPI1RX---------------------------------------------*//*DMA1channel4configurationSPI2RX---------------------------------------------*/DMA_InitStructure.DMA_MemoryBaseAddr=(DWORD)rw_workbyte;DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Disable;DMA_Init(DMA_Channel_SPI_SD_RX,&DMA_InitStructure);/*DMA1channel3configurationSPI1TX---------------------------------------------*//*DMA1channel5configurationSPI2TX---------------------------------------------*/DMA_InitStructure.DMA_MemoryBaseAddr=(DWORD)buff;DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;DMA_Init(DMA_Channel_SPI_SD_TX,&DMA_InitStructure);#endif }/*EnableDMARXChannel*/DMA_Cmd(DMA_Channel_SPI_SD_RX,ENABLE);/*EnableDMATXChannel*/DMA_Cmd(DMA_Channel_SPI_SD_TX,ENABLE);/*EnableSPITX/RXrequest*/SPI_I2S_DMACmd(SPI_SD,SPI_I2S_DMAReq_Rx|SPI_I2S_DMAReq_Tx,ENABLE);/*WaituntilDMA1_Channel3TransferComplete*////notneeded:while(DMA_GetFlagStatus(DMA_FLAG_SPI_SD_TC_TX)==RESET){;}/*WaituntilDMA1_Channel2ReceiveComplete*/while(DMA_GetFlagStatus(DMA_FLAG_SPI_SD_TC_RX)==RESET){;}//samew/ofunction-call://while(((DMA1->ISR)&DMA_FLAG_SPI_SD_TC_RX)==RESET){;}/*DisableDMARXChannel*/DMA_Cmd(DMA_Channel_SPI_SD_RX,DISABLE);/*DisableDMATXChannel*/DMA_Cmd(DMA_Channel_SPI_SD_TX,DISABLE);/*DisableSPIRX/TXrequest*/SPI_I2S_DMACmd(SPI_SD,SPI_I2S_DMAReq_Rx|SPI_I2S_DMAReq_Tx,DISABLE);}#endif/*STM32_SD_USE_DMA*//*-----------------------------------------------------------------------*//*PowerControlandinterface-initialization(Platformdependent)*//*-----------------------------------------------------------------------*/staticvoidpower_on(void){SPI_InitTypeDefSPI_InitStructure;GPIO_InitTypeDefGPIO_InitStructure;volatileBYTEdummyread;/*EnableGPIOclockforCS*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_CS,ENABLE);/*EnableSPIclock,SPI1:APB2,SPI2:APB1*/RCC_APBPeriphClockCmd_SPI_SD(RCC_APBPeriph_SPI_SD,ENABLE); card_power(1);socket_cp_init();socket_wp_init();for(Timer1=25;Timer1;);/*Waitfor250ms*//*ConfigureI/OforFlashChipselect*/GPIO_InitStructure.GPIO_Pin=GPIO_Pin_CS;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIO_CS,&GPIO_InitStructure);/*De-selecttheCard:ChipSelecthigh*/DESELECT();/*ConfigureSPIpins:SCKandMOSIwithdefaultalternatefunction(notre-mapped)push-pull*/GPIO_InitStructure.GPIO_Pin=GPIO_Pin_SPI_SD_SCK|GPIO_Pin_SPI_SD_MOSI;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;GPIO_Init(GPIO_SPI_SD,&GPIO_InitStructure);/*ConfigureMISOasInputwithinternalpull-up*/GPIO_InitStructure.GPIO_Pin=GPIO_Pin_SPI_SD_MISO;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;GPIO_Init(GPIO_SPI_SD,&GPIO_InitStructure);/*SPIconfiguration*/SPI_InitStructure.SPI_Direction=SPI_Direction_2Lines_FullDuplex;SPI_InitStructure.SPI_Mode=SPI_Mode_Master;SPI_InitStructure.SPI_DataSize=SPI_DataSize_8b;SPI_InitStructure.SPI_CPOL=SPI_CPOL_Low;SPI_InitStructure.SPI_CPHA=SPI_CPHA_1Edge;SPI_InitStructure.SPI_NSS=SPI_NSS_Soft;SPI_InitStructure.SPI_BaudRatePrescaler=SPI_BaudRatePrescaler_256;//72000kHz/256=281kHz<400kHzSPI_InitStructure.SPI_FirstBit=SPI_FirstBit_MSB;SPI_InitStructure.SPI_CRCPolynomial=7;SPI_Init(SPI_SD,&SPI_InitStructure);SPI_CalculateCRC(SPI_SD,DISABLE);SPI_Cmd(SPI_SD,ENABLE);/*drainSPI*/while(SPI_I2S_GetFlagStatus(SPI_SD,SPI_I2S_FLAG_TXE)==RESET){;} dummyread=SPI_I2S_ReceiveData(SPI_SD);#ifdefSTM32_SD_USE_DMA/*enableDMAclock*/RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);#endif}staticvoidpower_off(void){GPIO_InitTypeDefGPIO_InitStructure;if(!(Stat&STA_NOINIT)){SELECT();wait_ready();release_spi();}SPI_I2S_DeInit(SPI_SD);SPI_Cmd(SPI_SD,DISABLE);RCC_APBPeriphClockCmd_SPI_SD(RCC_APBPeriph_SPI_SD,DISABLE);/*AllSPI-Pinstoinputwithweakinternalpull-downs*/GPIO_InitStructure.GPIO_Pin=GPIO_Pin_SPI_SD_SCK|GPIO_Pin_SPI_SD_MISO|GPIO_Pin_SPI_SD_MOSI;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;GPIO_Init(GPIO_SPI_SD,&GPIO_InitStructure);card_power(0);Stat|=STA_NOINIT;/*SetSTA_NOINIT*/}/*-----------------------------------------------------------------------*//*ReceiveadatapacketfromMMC*//*-----------------------------------------------------------------------*/staticBOOLrcvr_datablock(BYTE*buff,/*Databuffertostorereceiveddata*/UINTbtr/*Bytecount(mustbemultipleof4)*/) {BYTEtoken;Timer1=10;do{/*Waitfordatapacketintimeoutof100ms*/token=rcvr_spi();}while((token==0xFF)&&Timer1);if(token!=0xFE)returnFALSE;/*Ifnotvaliddatatoken,returnwitherror*/#ifdefSTM32_SD_USE_DMAstm32_dma_transfer(TRUE,buff,btr);#elsedo{/*Receivethedatablockintobuffer*/rcvr_spi_m(buff++);rcvr_spi_m(buff++);rcvr_spi_m(buff++);rcvr_spi_m(buff++);}while(btr-=4);#endif/*STM32_SD_USE_DMA*/rcvr_spi();/*DiscardCRC*/rcvr_spi();returnTRUE;/*Returnwithsuccess*/}/*-----------------------------------------------------------------------*//*SendadatapackettoMMC*//*-----------------------------------------------------------------------*/#if_FS_READONLY==0staticBOOLxmit_datablock(constBYTE*buff,/*512bytedatablocktobetransmitted*/BYTEtoken/*Data/Stoptoken*/){BYTEresp;#ifndefSTM32_SD_USE_DMABYTEwc;#endif if(wait_ready()!=0xFF)returnFALSE;xmit_spi(token);/*transmitdatatoken*/if(token!=0xFD){/*Isdatatoken*/#ifdefSTM32_SD_USE_DMAstm32_dma_transfer(FALSE,buff,512);#elsewc=0;do{/*transmitthe512bytedatablocktoMMC*/xmit_spi(*buff++);xmit_spi(*buff++);}while(--wc);#endif/*STM32_SD_USE_DMA*/xmit_spi(0xFF);/*CRC(Dummy)*/xmit_spi(0xFF);resp=rcvr_spi();/*Receivedataresponse*/if((resp&0x1F)!=0x05)/*Ifnotaccepted,returnwitherror*/returnFALSE;}returnTRUE;}#endif/*_READONLY*//*-----------------------------------------------------------------------*//*SendacommandpackettoMMC*//*-----------------------------------------------------------------------*/staticBYTEsend_cmd(BYTEcmd,/*Commandbyte*/DWORDarg/*Argument*/){BYTEn,res;if(cmd&0x80){/*ACMDisthecommandsequenceofCMD55-CMD*/cmd&=0x7F; res=send_cmd(CMD55,0);if(res>1)returnres;}/*Selectthecardandwaitforready*/DESELECT();SELECT();if(wait_ready()!=0xFF){return0xFF;}/*Sendcommandpacket*/xmit_spi(cmd);/*Start+Commandindex*/xmit_spi((BYTE)(arg>>24));/*Argument[31..24]*/xmit_spi((BYTE)(arg>>16));/*Argument[23..16]*/xmit_spi((BYTE)(arg>>8));/*Argument[15..8]*/xmit_spi((BYTE)arg);/*Argument[7..0]*/n=0x01;/*DummyCRC+Stop*/if(cmd==CMD0)n=0x95;/*ValidCRCforCMD0(0)*/if(cmd==CMD8)n=0x87;/*ValidCRCforCMD8(0x1AA)*/xmit_spi(n);/*Receivecommandresponse*/if(cmd==CMD12)rcvr_spi();/*Skipastuffbytewhenstopreading*/n=10;/*Waitforavalidresponseintimeoutof10attempts*/dores=rcvr_spi();while((res&0x80)&&--n);returnres;/*Returnwiththeresponsevalue*/}/*--------------------------------------------------------------------------PublicFunctions---------------------------------------------------------------------------*//*-----------------------------------------------------------------------*/ /*InitializeDiskDrive*//*-----------------------------------------------------------------------*/DSTATUSdisk_initialize(BYTEdrv/*Physicaldrivenumber(0)*/){BYTEn,cmd,ty,ocr[4];if(drv)returnSTA_NOINIT;/*Supportsonlysingledrive*/if(Stat&STA_NODISK)returnStat;/*Nocardinthesocket*/power_on();/*Forcesocketpoweronandinitializeinterface*/interface_speed(INTERFACE_SLOW);for(n=10;n;n--)rcvr_spi();/*80dummyclocks*/ty=0;if(send_cmd(CMD0,0)==1){/*EnterIdlestate*/Timer1=100;/*Initializationtimeoutof1000milliseconds*/if(send_cmd(CMD8,0x1AA)==1){/*SDHC*/for(n=0;n<4;n++)ocr[n]=rcvr_spi();/*GettrailingreturnvalueofR7response*/if(ocr[2]==0x01&&ocr[3]==0xAA){/*ThecardcanworkatVDDrangeof2.7-3.6V*/while(Timer1&&send_cmd(ACMD41,1UL<<30));/*Waitforleavingidlestate(ACMD41withHCSbit)*/if(Timer1&&send_cmd(CMD58,0)==0){/*CheckCCSbitintheOCR*/for(n=0;n<4;n++)ocr[n]=rcvr_spi();ty=(ocr[0]&0x40)?CT_SD2|CT_BLOCK:CT_SD2;}}}else{/*SDSCorMMC*/if(send_cmd(ACMD41,0)<=1){ty=CT_SD1;cmd=ACMD41;/*SDSC*/}else{ty=CT_MMC;cmd=CMD1;/*MMC*/}while(Timer1&&send_cmd(cmd,0));/*Waitforleavingidlestate*/if(!Timer1||send_cmd(CMD16,512)!=0)/*SetR/Wblocklengthto512*/ty=0; }}CardType=ty;release_spi();if(ty){/*Initializationsucceeded*/Stat&=~STA_NOINIT;/*ClearSTA_NOINIT*/interface_speed(INTERFACE_FAST);}else{/*Initializationfailed*/power_off();}returnStat;}/*-----------------------------------------------------------------------*//*GetDiskStatus*//*-----------------------------------------------------------------------*/DSTATUSdisk_status(BYTEdrv/*Physicaldrivenumber(0)*/){if(drv)returnSTA_NOINIT;/*Supportsonlysingledrive*/returnStat;}/*-----------------------------------------------------------------------*//*ReadSector(s)*//*-----------------------------------------------------------------------*/DRESULTdisk_read(BYTEdrv,/*Physicaldrivenumber(0)*/BYTE*buff,/*Pointertothedatabuffertostorereaddata*/DWORDsector,/*Startsectornumber(LBA)*/BYTEcount/*Sectorcount(1..255)*/){if(drv||!count)returnRES_PARERR;if(Stat&STA_NOINIT)returnRES_NOTRDY; if(!(CardType&CT_BLOCK))sector*=512;/*Converttobyteaddressifneeded*/if(count==1){/*Singleblockread*/if(send_cmd(CMD17,sector)==0){/*READ_SINGLE_BLOCK*/if(rcvr_datablock(buff,512)){count=0;}}}else{/*Multipleblockread*/if(send_cmd(CMD18,sector)==0){/*READ_MULTIPLE_BLOCK*/do{if(!rcvr_datablock(buff,512)){break;}buff+=512;}while(--count);send_cmd(CMD12,0);/*STOP_TRANSMISSION*/}}release_spi();returncount?RES_ERROR:RES_OK;}/*-----------------------------------------------------------------------*//*WriteSector(s)*//*-----------------------------------------------------------------------*/#if_FS_READONLY==0DRESULTdisk_write(BYTEdrv,/*Physicaldrivenumber(0)*/constBYTE*buff,/*Pointertothedatatobewritten*/DWORDsector,/*Startsectornumber(LBA)*/BYTEcount/*Sectorcount(1..255)*/){if(drv||!count)returnRES_PARERR;if(Stat&STA_NOINIT)returnRES_NOTRDY;if(Stat&STA_PROTECT)returnRES_WRPRT; if(!(CardType&CT_BLOCK))sector*=512;/*Converttobyteaddressifneeded*/if(count==1){/*Singleblockwrite*/if((send_cmd(CMD24,sector)==0)/*WRITE_BLOCK*/&&xmit_datablock(buff,0xFE))count=0;}else{/*Multipleblockwrite*/if(CardType&CT_SDC)send_cmd(ACMD23,count);if(send_cmd(CMD25,sector)==0){/*WRITE_MULTIPLE_BLOCK*/do{if(!xmit_datablock(buff,0xFC))break;buff+=512;}while(--count);if(!xmit_datablock(0,0xFD))/*STOP_TRANtoken*/count=1;}}release_spi();returncount?RES_ERROR:RES_OK;}#endif/*_READONLY==0*//*-----------------------------------------------------------------------*//*MiscellaneousFunctions*//*-----------------------------------------------------------------------*/#if(STM32_SD_DISK_IOCTRL==1)DRESULTdisk_ioctl(BYTEdrv,/*Physicaldrivenumber(0)*/BYTEctrl,/*Controlcode*/void*buff/*Buffertosend/receivecontroldata*/){DRESULTres;BYTEn,csd[16],*ptr=buff;WORDcsize;if(drv)returnRES_PARERR; res=RES_ERROR;if(ctrl==CTRL_POWER){switch(*ptr){case0:/*Subcontrolcode==0(POWER_OFF)*/if(chk_power())power_off();/*Poweroff*/res=RES_OK;break;case1:/*Subcontrolcode==1(POWER_ON)*/power_on();/*Poweron*/res=RES_OK;break;case2:/*Subcontrolcode==2(POWER_GET)*/*(ptr+1)=(BYTE)chk_power();res=RES_OK;break;default:res=RES_PARERR;}}else{if(Stat&STA_NOINIT)returnRES_NOTRDY;switch(ctrl){caseCTRL_SYNC:/*Makesurethatnopendingwriteprocess*/SELECT();if(wait_ready()==0xFF)res=RES_OK;break;caseGET_SECTOR_COUNT:/*Getnumberofsectorsonthedisk(DWORD)*/if((send_cmd(CMD9,0)==0)&&rcvr_datablock(csd,16)){if((csd[0]>>6)==1){/*SDCversion2.00*/csize=csd[9]+((WORD)csd[8]<<8)+1;*(DWORD*)buff=(DWORD)csize<<10;}else{/*SDCversion1.XXorMMC*/n=(csd[5]&15)+((csd[10]&128)>>7)+((csd[9]&3)<<1)+2;csize=(csd[8]>>6)+((WORD)csd[7]<<2)+((WORD)(csd[6]&3)<<10)+1;*(DWORD*)buff=(DWORD)csize<<(n-9);}res=RES_OK; }break;caseGET_SECTOR_SIZE:/*GetR/Wsectorsize(WORD)*/*(WORD*)buff=512;res=RES_OK;break;caseGET_BLOCK_SIZE:/*Geteraseblocksizeinunitofsector(DWORD)*/if(CardType&CT_SD2){/*SDCversion2.00*/if(send_cmd(ACMD13,0)==0){/*ReadSDstatus*/rcvr_spi();if(rcvr_datablock(csd,16)){/*Readpartialblock*/for(n=64-16;n;n--)rcvr_spi();/*Purgetrailingdata*/*(DWORD*)buff=16UL<<(csd[10]>>4);res=RES_OK;}}}else{/*SDCversion1.XXorMMC*/if((send_cmd(CMD9,0)==0)&&rcvr_datablock(csd,16)){/*ReadCSD*/if(CardType&CT_SD1){/*SDCversion1.XX*/*(DWORD*)buff=(((csd[10]&63)<<1)+((WORD)(csd[11]&128)>>7)+1)<<((csd[13]>>6)-1);}else{/*MMC*/*(DWORD*)buff=((WORD)((csd[10]&124)>>2)+1)*(((csd[11]&3)<<3)+((csd[11]&224)>>5)+1);}res=RES_OK;}}break;caseMMC_GET_TYPE:/*Getcardtypeflags(1byte)*/*ptr=CardType;res=RES_OK;break;caseMMC_GET_CSD:/*ReceiveCSDasadatablock(16bytes)*/if(send_cmd(CMD9,0)==0/*READ_CSD*/&&rcvr_datablock(ptr,16))res=RES_OK;break; caseMMC_GET_CID:/*ReceiveCIDasadatablock(16bytes)*/if(send_cmd(CMD10,0)==0/*READ_CID*/&&rcvr_datablock(ptr,16))res=RES_OK;break;caseMMC_GET_OCR:/*ReceiveOCRasanR3resp(4bytes)*/if(send_cmd(CMD58,0)==0){/*READ_OCR*/for(n=4;n;n--)*ptr++=rcvr_spi();res=RES_OK;}break;caseMMC_GET_SDSTAT:/*ReceiveSDstatusasadatablock(64bytes)*/if(send_cmd(ACMD13,0)==0){/*SD_STATUS*/rcvr_spi();if(rcvr_datablock(ptr,64))res=RES_OK;}break;default:res=RES_PARERR;}release_spi();}returnres;}#endif/*_USE_IOCTL!=0*//*-----------------------------------------------------------------------*//*DeviceTimerInterruptProcedure(Platformdependent)*//*-----------------------------------------------------------------------*//*Thisfunctionmustbecalledinperiodof10ms*/RAMFUNCvoiddisk_timerproc(void){staticDWORDpv;DWORDns;BYTEn,s; n=Timer1;/*100Hzdecrementtimers*/if(n)Timer1=--n;n=Timer2;if(n)Timer2=--n;ns=pv;pv=socket_is_empty()|socket_is_write_protected();/*Samplesocketswitch*/if(ns==pv){/*Havecontactsstabled?*/s=Stat;if(pv&socket_state_mask_wp)/*WPisH(writeprotected)*/s|=STA_PROTECT;else/*WPisL(writeenabled)*/s&=~STA_PROTECT;if(pv&socket_state_mask_cp)/*INS=H(Socketempty)*/s|=(STA_NODISK|STA_NOINIT);else/*INS=L(Cardinserted)*/s&=~STA_NODISK;Stat=s;}}DWORDget_fattime(void){return0;}SD卡文件扫描函数源程序:FRESULTSD_ScanFiles(char*path){FRESULTres;FILINFOfno;DIRdir;char*fn;#if_USE_LFNstaticcharlfn[_MAX_LFN*(_DF1S?2:1)+1];fno.lfname=lfn;fno.lfsize=sizeof(lfn);#endif res=f_opendir(&dir,path);if(res==FR_OK){for(;;){res=f_readdir(&dir,&fno);if(res!=FR_OK||fno.fname[0]==0)break;if(fno.fname[0]=='.')continue;#if_USE_LFNfn=*fno.lfname?fno.lfname:fno.fname;#elsefn=fno.fname;#endifif(fno.fattrib&AM_DIR){char*temp=malloc(strlen(path)+strlen(fn)+2);strcpy(temp,path);temp[strlen(path)]='\';strcpy(temp+strlen(path)+1,fn);SD_ScanFiles(temp);free(temp);}else{char*temp=malloc(strlen(path)+strlen(fn)+3);strcpy(temp,path);strcpy(temp+strlen(path),"\");strcpy(temp+strlen(path)+1,fn);if(PlayList_Now==NULL){PlayList1.file_name=temp;PlayList1.prev=NULL;PlayList1.next=NULL;PlayList_Now=&PlayList1;}else{PlayList_Now->next=malloc(sizeof(PlayList_t));PlayList_Now->next->prev=PlayList_Now;PlayList_Now=PlayList_Now->next;PlayList_Now->file_name=temp;PlayList_Now->next=NULL;}//printf("%s\%sr ",path,fn); }}}returnres;}

当前文档最多预览五页,下载文档查看全文

此文档下载收益归作者所有

当前文档最多预览五页,下载文档查看全文
温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,天天文库负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。
大家都在看
近期热门
关闭