《摄像头组电子科技大学成电轻扬队技术报告》由会员上传分享,免费在线阅读,更多相关内容在行业资料-天天文库。
第五届“飞思卡尔”杯全国大学生智能汽车竞赛技术报告附:关于舵机臂长和智能车转向性能的关系的研究学校:电子科技大学队伍名称:成电轻扬参赛队员:卜大鹏刁双林孙星海带队教师:程玉华
1关于技术报告和研究论文使用授权的说明本人完全了解第五届“飞思卡尔”杯全国大学生智能汽车邀请赛关保留、使用技术报告和研究论文的规定,即:参赛作品著作权归参赛者本人,比赛组委会和飞思卡尔半导体公司可以在相关主页上收录并公开参赛作品的设计方案、技术报告以及参赛模型车的视频、图像资料,并将相关内容编纂收录在组委会出版论文集中。参赛队员签名:带队教师签名:日期:
2摘要本文详细介绍了我们队为第五届Freescale智能汽车大赛而准备的智能车系统方案。该方案以Freescale公司的MC9s12XS128单片机作为系统的控制核心,采用CMOS摄像头采集赛道信息,根据采集到的数据分析行驶路径以及对起跑线进行检测。采用PID算法对赛车的舵机和直流电机进行闭环控制,并根据跑道的弯曲程度采用不同的控制策略。在机械结构方面,通过对赛车前轮定位参数的优化,和对舵机输出力臂的改造,进一步提高了赛车的性能。在赛车的调试方面,通过采用无线蓝牙模块、SD卡、LED状态指示灯等,大大方便了算法调试和加快了调试进度。经过实际测试,整个赛车系统能在规定的跑道上高速稳定地行驶。在文中将介绍系统的整体方案,具体模块的软硬件设计,机械改造,以及调试等内容。关键词:智能车、寻线、起始线、S12单片机、图像采集、PID、路径拟合
3ABSTRACTABSTRACTInthispaperwewilldemonstratethesmartcarsystemschemefortheFifthnationalsmartcarcontest.Basedonmicrocontrollers,MC9S12XS128,ascontrolunit,thesmartcarsystemruninthespecifiedroadswiftlyandsteady.CMOSimage-sensor,areappliedtoobtainlaneimageinformation.Thenbaseontheinformationfromthesensor,obtaininganoptimizedbycertainalgorithmandtheinformationofStartlaneandtrigonum.P1Dfeedbackalgorithmisappliedtocontroltheangleandspeed.Intheprocessofdebugging,weadoptthewirelessserialport,theSDandthedenotingLED,whichmadetheprogramdebuggingeasierandmoreeffectual.Inanotherhand,byoptimizingtheparameterofthemachineofsystem,thesmartcarhasanexcellenceperform.Inthelaterarticle,wewilldemonstratethesystemscheme,themodulesofsysteminhardwareandsoftwareandthechangeinmachineryofcar.Keyword:IntelligentCar,SearchLane,Startlane,S12Microcontroller,ImageSampling,PID,LaneStrategy
452
5目录第一章引言11.1背景介绍11.2文献综述51.3本文结构6第二章系统方案72.1总体策略72.2系统设计方案72.2.1路径检测总体方案72.2.2速度控制总体方案82.2.3转向控制9第三章机械结构的系统设计与实现103.1车模安装与机械结构改造103.1.1车模安装103.1.2机械结构调整113.2电路板的安装143.3传感器的安装15第四章硬件系统设计与实现184.1硬件系统框图184.2电路板的设计与制作184.3电源模块194.4图像采集模块214.4.2电路设计214.5速度采集模块234.6电机驱动234.7本章小结24第五章软件系统设计与实现255.1软件系统设计255.2资源分配275.3摄像头安装对软件调试的影响275.4图像处理285.4.1黑白阈值提取285.4.2图像滤波285.5软件系统框图30
65.1.1图像采集模块31
7目录5.1.1图像处理模块321.1.3转向控制模块341.1.5速度;集模块371.1.6速度控制模块375.6特殊标记识别375.6.1起跑线识别模块375.7本章小结38第六章系统调试396.1开发调试工具396.1.1软件开发平台396.1.2智能车上位机设计406.1.3无线调试模块406.1.4状态指示灯416.1.5手动设置装置416.1.6蜂鸣器声音指示426.2转向PID参数整定426.3本章小结43第七章总结447.1赛车整体技术指标447.2总结447.2.1赛车制作447.2.2问题与解决447.2.3亮点与特色457.2.4展望与改进46致谢47参考文献47附1:关于舵机臂长和智能车转向性能的关系的研究109
8第一章引言1.1背景介绍“飞思卡尔”杯智能汽车竞赛是受教育部高等教育司委托,高等学校自动化专业教学指导委员会负责主办全国大学生智能车竞赛。该项比赛已列入教育部主办的全国五大竞赛之一。第五届“飞思卡尔”杯全国大学生智能车邀请赛总决赛将于今年八月份在杭州电子科技大学举行。该项赛事已成功举办过四届,其专业知识涉及控制、模式识别、传感技术、汽车电子、电气、计算机、机械等多个学科,对学生的知识融合和动手能力的培养,对高等学校控制及汽车电子学科学术水平的提高,具有良好的推动作用。参赛选手须使用竞赛秘书处统一指定的竞赛车模套件,采用飞思卡尔半导体公司的8位、16位微控制器作为核心控制单元,自主构思控制方案进行系统设计,包括传感器信号采集处理、电机驱动、转向舵机控制以及控制算法软件开发等,完成智能车工程制作及调试,于指定日期与地点参加各分赛区的场地比赛,在获得决赛资格后,参加全国总决赛的场地比赛。参赛队伍的名次(成绩)由赛车现场成功完成赛道比赛时间为主,技术报告、制作工程质量评分为辅来决定。大赛根据车模检测路径方案不同分为电磁、光电与摄像头三个赛题组。车模通过感应由赛道中心电线产生的交变磁场进行路径检测的属于电磁组;车模通过采集赛道图像(一维、二维)进行路径检测的属于摄像头组;车模通过采集赛道上少数孤立点反射亮度进行路径检测的属于光电组。竞赛秘书处制定如下比赛规则适用于各分赛区预赛以及全国总决赛,在实际可操作性基础上力求公正与公平。一、器材限制规定1.须采用统一指定的车模。本届比赛指定采用两种车模:A型车模:广东博思公司提供。限定电磁组比赛使用。B型车模:北京科宇通博科技有限公司提供。限定光电组、摄像头组使用。细节及改动限制见附件一。2.须采用飞思卡尔半导体公司的8位、16位处理器(单核)作为唯•的微控制器。有关细节及其它电子器件使用的限制见附件二;3.参加电磁赛题组不允许使用传感器获取道路的光学信息进行路径检测。
9参加光电赛题组中不允许传感器获取道路图像信息进行路径检测。参加摄像头赛题组可以使用光电管作为辅助检测手段。1.其他事项如果损毁车模中禁止改动的部件,需要使用相同型号的部件替换;车模改装完毕后,尺寸不能超过:250mm宽和400mm长。二、有关赛场的规定1.赛道基本参数(不包括拐弯点数、位置以及整体布局)见附件三;2.比赛赛道实际布局将在比赛当日揭示,在赛场内将安排采用制作实际赛道的材料所做的测试赛道供参赛队进行现场调试;三、裁判及技术评判竞赛分为分赛区和全国总决赛两个阶段。其中全国总决赛阶段是在全国竞赛组委会秘书处指导下,与决赛承办学校共同成立竞赛执行委员会,下辖技术组、裁判组和仲裁委员会,统一处理竞赛过程中遇到的各类问题。所有竞赛组织委员会工作人员,包括技术评判组及现场裁判组人员均不得参与任何针对个别参赛队的指导或辅导工作(提供微控制器培训除外),不得泄露任何有失公允竞赛的信息。在分赛区预赛阶段中,裁判以及技术评判由各分赛区组委会参照上述决赛阶段组织实施。四、分赛区、全国总决赛比赛规则分赛区和全国总决赛的比赛规则相同,都具有电磁组、光电组和摄像头组比赛。三个赛题组在同一个场馆同时进行比赛,所遵循的比赛规则是相同的。三个赛题组分别独立进行成绩排名。分赛区和全国总决赛的现场比赛均包括预赛与决赛两个阶段。下面列出的现场预赛、决赛阶段的比赛规则适用于各分赛区及全国总决赛的三个赛题组。1.预赛与决赛规则1)预赛阶段规则i.比赛场中有三条赛道。
10i.参赛队根据比赛题目分为三个组,并以抽签形式决定组内比赛次序。ii.比赛分为两轮,三组同时在三个赛道上进行比赛,每支参赛队伍可以在每轮比赛之前有10分钟的现场调整时间。在此期间,参赛队伍只允许对赛车的硬件(不包括微控制器芯片)进行调整。第二轮比赛在同一赛道沿逆向进行。iii.在每轮比赛中,选手首先将赛车放置在起跑区域内赛道上,赛车至少静止两秒钟后自动启动。iv.每辆赛车在赛道上跑一圈,以计时起始线为计时点,跑完一圈后赛车需要自动停止在起始线之后三米之内的赛道内,如果没有停止在规定的区域内,比赛计时成绩增加1秒。v.每辆赛车以在两个单轮成绩中较好的一个作为赛车最终预赛成绩;计时由电子计时器完成并实时显示。vi.根据参赛队伍数量,由比赛组委会根据成绩选取一定比例的队伍晋级决赛。vii.晋级决赛的赛车在决赛前有10分钟的调整时间。在此期间,参赛队伍只允许对赛车的硬件(不包括微控制器芯片)进行调整。技术评判组将对全部晋级的赛车进行现场技术检查,如有违反器材限制规定的(指本规则之第一条)当时取消决赛资格,由后备首名晋级代替。viii.由裁判组申报组织委员会批准公布决赛名单。X.全部车模在整个比赛期间都统一放置在车模的展示区内。2)决赛阶段规则i.参加决赛队伍按照预赛成绩进行排序,比赛顺序按照预赛成绩的倒序进行。ii.决赛的比赛场地使用一个赛道。决赛赛道与预赛赛道形状不同,占地面积增大,赛道长度增加。iii.每支决赛队伍只有一次比赛机会,在跑道上跑一圈,比赛过程与要求同预赛阶段。iv.计时由电子计时器完成并实时显示。v.预赛成绩不记入决赛成绩,只决定决赛比赛顺序。没有参加决赛阶段比赛的队伍,预赛成绩为最终成绩,参加该赛题组的排名。
112.比赛过程规则按照比赛顺序,裁判员指挥参赛队伍顺序进入场地比赛。同一时刻,一个场地上只有一支队伍进行比赛。在裁判员点名后,每队指定一名队员持赛车进入比赛场地。参赛选手有60秒的现场准备时间。准备好后,裁判员宣布比赛开始,选手将赛车放置在起跑区,赛车应在起跑区静止两秒钟以上,然后自动出发。赛车应该在30秒之内离开出发区,沿着赛道跑完一圈。由计时起始线两边传感器进行自动计时。赛车跑完一圈且自动停止后,选手拿起赛车离开场地,将赛车放回指定区域。如果比赛完成,由计算机评分系统自动给出比赛成绩。3.比赛犯规与失败规则比赛过程中,由比赛现场裁判根据统一的规则对于赛车是否冲出跑道进行裁定。赛车前两次冲出跑道时,由裁判员取出赛车交给比赛队员,立即在起跑区重新开始比赛。选手也可以在赛车冲出跑道后放弃比赛。比赛过程中出现下面的情况,算作模型车冲出跑道一次。・裁判点名后,60秒之内,参赛队没有能够进入比赛场地并做好比赛准备;・比赛开始后,赛车在30秒之内没有离开出发区;・赛车在离开出发区之后60秒之内没有跑完一圈;比赛过程中如果出现有如下一种情况,判为比赛失败:・赛车冲出跑道的次数超过两次;・比赛开始后未经裁判允许,选手接触赛车;・决赛前,赛车没有通过技术检验。如果比赛失败,则不计成绩。比赛禁止事项:・不允许在赛车之外安装辅助照明设备及其它辅助传感器等;・选手进入比赛场地后,除了可以更换电池之外,不允许进行任何硬件和软件的修改;
12・比赛场地内,除了裁判与1名队员之外,不允许任何其他人员进入场地;・不允许其它干扰赛车运动的行为;・不允许车模设计方案抄袭,参赛队伍的车模设计的硬软件需要相互之间有明显的不同。4.比赛组织说明:1)现场正式比赛前,每个参赛队伍都有现场环境适应性调试阶段。调试跑道与比赛跑道形状不一样。2)比赛开赛之前,所有车模都由比赛组委会收集并存放在同一保管区域,直到比赛结束。3)在比赛期间,大赛组委会技术处将根据情况对参赛车模进行技术检查。如果违反了比赛规则的禁止事项,大赛组委会有权取消参赛队伍的成绩。4)为了便于进行技术交流全国总决赛之后,获得全国总决赛特等奖、一等奖的车模将由全国竞赛组委会代为保管两年。五.其他1.比赛过程中有其他作弊行为的,取消比赛成绩;2.参加预赛并晋级决赛的队伍人员不允许改变。3.本规则解释权归竞赛秘书处和比赛组织委员会所有。1.2文献综述在模型车制作之前我们主要参考了《学做智能车》《HCS12微控制器原理及应用》《VisualC++6从入门到精通》《Freescale9sl2十六位单片机原理及嵌入式开发技术》等书,同时我们在清华大学的FTP上下载了第四届比赛的一些学校的技术报告,熟悉了S12单片机的资源和开发方法,借鉴往届比赛的经验。在模型车制作期间,我们在网上搜索并参考了关于汽车理论方面的相关论文,为模型车的机械调整提供了理论依据。在硬件和软件的设计中主要参考了各芯片的PDF文档。在算法方面参考了自动控制和数字图像处理方面的一些书。如《数字图像处理》、《CCD传感器检测技术》等等,我们参考过的所有书籍跟文档将会在附录里一一罗列。
131.2本文结构本报告是对参赛的智能汽车制作技术方案、设计思路、制作调试过程以及相关技术研究内容形成的总结性报告。报告采用总一分一总的结构,先对总体方案进行阐述,再分别阐述系统各个模块的实现,最后结合我们实际测试结果对整个智能车系统进行了总结。全文共分七章。第一章为引言,介绍了比赛背景、比赛规则、研究意义和全文的安排。第二章论述了系统的总体方案,对智能车设计原理,思想进行了总的概括。第三章论述了对车模机械结构的一些探索性调整。第四章主要阐述各个模块的原理、实现和调试。第五章主要阐述了系统的软件设计,包括设计中用到的单片机的各种资源和各种控制算法。第六章主要阐述了系统的调试和相关的各种工具。第七章进行了总结,包括我们在制作和调试中得出的一些结论和存在的一些问题及进一步改进的方向。全文穿插了我们制作模型车过程中的一些探索体会,每一章还有一个小结,总结了我们在制作和探索过程中所得出的一些结论。
14第二章系统方案2.1总体策略经历过四届比赛的发展,本届比赛的赛车总体速度有了很大的提高,而且增加了对三角区的要求。为了使赛车沿着赛道的黑线更快更稳地行驶,我们把系统分为高精度路径检测模块、高精度速度控制模块、转向控制模块。通过超频提高CPU的运行频率,合理的处理控制算法,同时加上各高精度模块的检测与控制,赛车能够很好地完成比赛任务。2.2系统设计方案2.2.1路径检测总体方案透镜成像组用摄像头识别路径,同时也可以结合红外传感器辅助摄像头检测路径,从而有两种方案:方案一:单独采用摄像头进行路径检测。摄像头通过面成像,可以对车前方足够的赛道信息进行采集,有利于赛车行驶时对前方赛道进行有效的预测,实现最优路径的选择。摄像头采集图像的这个优点尤其在赛车高速行驶准备入弯时表现得突出,它可以精确判断出不同的弯道从而赛车可采用不同的行驶策略,这对于舵机反应的滞后性有很大的改进。单独采用摄像头检测路径的缺点是摄像头采集路面信息的频率较低,容易受到光线和赛道外物体的干扰,尤其是对起跑线检测时处理算法要进行优化。方案二:采用摄像头和红外传感器进行路径检测。红外传感器的电路和软件设计简单,使用红外传感器对路径的检测受光线的干扰较少而且采集的信息可靠,还可以获得很高的检测频率,弥补了摄像头检测频率不高、易受干扰的缺点,在检测路径和起跑线时可以得到比较可靠的信息。但是对黑线的检测精度有限而且红外传感器的作用距离有限,其前瞻距离不可能很远,同时红外传感器的功耗大,电路的重量也不小,严重影响了赛车的启停能力和速度。通过理论论证和现场测试,我们发现只要我们在起跑线对算法进行优化,完全可以解决起跑线的问题,在其他地方我们只要在算法里进行去干扰处理,可以解决干扰问题,没有必要再用到红外传感器。最终我们采用方案一。
15摄像头方案的选择:1.采用CCD摄像头。CCD摄像头优点是成像质量好,特别是动态效果比CMOS摄像头的效果要好很多。但是CCD摄像头的功耗比CMOS摄像头要高,工作电流有100mA左右。2.采用CMOS数字摄像头。CMOS摄像头功耗较低,工作电流只有10mA左右。并且CMOS摄像头出来直接是数字信号,弥补了XS128单片机AD采样率慢的缺点。综上所述,我们采用CMOS数字摄像头。2.1.1速度控制总体方案在保证赛车稳定性的前提下,提高速度是获胜的关键,也是我们设计的重点。同时赛车的重量和重心的调整也是我们设计时要考虑的问题。对赛乍速度的控制主要有两种方案。即:开环控制和闭环控制。方案一:开环控制开环控制是指没有反馈的控制。即通过预先设定的方案,没有外部反馈地进行操作。优点在于操作和控制比较简单,只需要提供理论运行的过程然后编程调整即可实现。缺点在于理论和实际始终有一定的误差,实践证明开环控制的精度不高,无法切实有效的提高速度。方案二:闭环控制闭环控制是指具有反馈的控制。在系统运行过程中,需要不断检测赛车速度的状态,与预期的状态进行比较,当相差到一定程度时,修正误差,精度很高。但是缺点在于电路的搭建和程序的编制都比开环控制要复杂。实现电机的闭环控制传感器主要是采用旋转编码器,在电机转动一定角度的时候形成脉冲,由外部器件捕获这些脉冲,得出与实际运行的差异。开环速度控制实现起来比较简单,但速度会随着电池电压的变化而变化,不能实现对速度的精确控制。为了使小车能以不同的速度通过不同的弯道,精确的速度控制是关键。而且由于赛道上有斜坡,赛车安全通过斜坡的关键是控制上坡和下坡的速度,所以对于采用速度闭环控制的赛车来说通过斜坡就像是通过普通的直道一样的简单,不需要对斜坡进行专门的检测。综上所述,采用速度闭环控制方案。
162.1.1转向控制转向模块主要由舵机实现,舵机的响应速度和舵机臂长决定了转向控制的实时性。舵机的响应速度与驱动电压和控制舵机的PWM波周期有联系,通过查阅相关资料得知,在电压允许条件下,驱动电压越高舵机的响应速度越快。调试过程中我们发现直接使用电池电压供电舵机也可以正常工作,我们把控制舵机的PWM波周期调整为16ms,把舵机臂长加长,舵机的响应速度有了很大提高,实现了对赛车的快速转向控制。2.2本章小结由以上的分析确定系统的总体方案:采用CMOS摄像头进行路径检测,舵机实现小车的转向控制,速度闭环控制方式对小车的速度实施精确控制。系统的整体框图如图2-1所示:图2-1系统的整体框图本章通过论证和比较,确定了系统的整体方案。在以下章节中我们将对这套方案进行详细介绍。第三章机械结构的系统设计与实现为了让赛车能在直道和弯道上高速稳定的通过,而且转弯比较灵巧,快速,除了有相应的软件和硬件电路的设计之外,赛车的机械结构对其也有很重要的影响。所以我们对赛车的机械结构也做了一些相应的调整。本章的将主要介绍赛车车模的机械特点和调整方案。
173.1车模安装与机械结构改造要使赛车跑出好成绩,除了算法的优化,还要调整赛车的机械结构。机械结构的调整是一个需要通盘考虑的问题,赛车的机械性能对小车行驶性能有很大的影响。安装时需要考虑的要点是:(1)符合组委会规定的赛车的尺寸要求(2)安装的可靠性(3)安装的轻便性(4)方便摄像头准确快速的检测(5)车体各部分重量的分配。质心问题,保证赛车转弯、加速在安装车模与车模结构改造过程中,通过不断的调试摸索,经过对比之后,我们对小车的机械结构进行了改进,提高了小车的过弯性能和行驶的稳定性,达到了满意的效果。下面分别进行介绍。3.1.1车模安装从拿到车模开始,车模安装便是第一项很重要的工作,车模零件比较多并且很繁琐,安装时要有细心和耐心。首先,认真阅读车模安装说明书,从中了解各零件的编号和作用,安装步骤,车模的基本结构蓝图等。其次,根据说明书安装。找一个比较宽敞得桌面并在上铺上一块比较大的抹布,把各零件袋和安装工具准备齐全,还可以把比较小且常用的零件放在桌面上,这样既可以提高安装效率,也可以防止安装过程中零件的滑落,丢失。安装结束后,对小车各部分进行检查和调整,主要是以下几个方面:(1)驱动电机齿轮传动机构,确保齿轮咬合紧密,顺畅。(2)前轮转向机构,传动杆与舵机连接可靠,舵机工作时无晃动。(3)轮胎,胎内海绵垫平铺无褶皱,轮胎轮毂与表面橡胶可靠固定。(4)前后轮主轴合适固定,减少车轮滚动阻力。
183.1.1机械结构调整在比赛规则允许范围内,通过对小车机械结构进行改造,可以减少软件的复杂性,也可以提高小车行驶稳定性和过弯性能。3.1.1.1舵机的安装和改进(1)舵机竖直安装。如图所示:(2)舵机水平安装。如图所示:
19(3)加长并加工舵机输出力臂。其原因主要是舵机转动一定角度有时间延迟,时间延迟正比于旋转过的角度。舵机的响应速度直接影响模型车的过弯的最高速度,加长输出力臂,舵机转动很小的角度便可使前轮转动比较大的转角,提高了舵机的响应速度。这时,两前轮的连杆水平,舵机在转动时有最大的输出力矩,转向很轻便。3.1.1.1前轮的调整在车模过弯时,转向舵机的负载会因为车轮转向角度增大而增大。为了尽可能降低转向舵机负载,对前轮的安装角度,即前轮定位进行了调整。前轮定位的作用是保障汽车直线行驶的稳定性,转向轻便和减少轮胎的磨损。前轮是转向轮,它的安装位置由主销内倾、主销后倾、前轮外倾和前轮前束等4个项目决定,反映了转向轮、主销和前轴等三者在车架上的位置关系。主销后倾角是前轮主销与前轮垂直中心线之间的夹角,也就是主销上端向后倾斜的角度。主销内倾角是前轮主销在赛车水平面内向内倾斜的角度,虽然增大内倾角也可以增大回正的力矩,但增大内倾角会在赛车转向的过程中,增大赛车与路面的滑动,从而加速轮胎的磨损,由于轮胎对地的附着力对防止侧滑有很重要的影响,所以如果轮胎磨损则得不偿失,所以内倾角调整为1°,前轮外倾角是前轮的上端向外倾斜的角度,如果前面两个轮子呈现“V”字形则称正倾角,呈现“八”字则称负倾角。由于前轮外倾可以抵消由于车的重力使车轮向内倾斜的趋势,减少赛车机件的磨损与负重,所以赛车安装了组委会配备的外倾角为1,前轮前束
20是前轮前端向内倾斜的程度,当两轮的前端距离小后端距离大时为内八字,前端距离大后端距离小为外八字。由于前轮外倾使轮子滚动时类似与圆锥滚动,从而导致两侧车轮向外滚开。但由于拉杆的作用使车轮不可能向外滚开,车轮会出现边滚变向内划的现象,从而增加了轮胎的磨损。前轮外八字与前轮外倾搭配,一方面可以抵消前轮外倾的负作用,另一方面由于赛车前进时车轮由于惯性自然的向内倾斜,外八字可以抵消其向内倾斜的趋势。外八字还可以使转向时靠近弯道内侧的轮胎比靠近弯道外侧的轮胎的转向程度更大,则使内轮胎比外轮胎的转弯半径小,有利与转向。3.1.1.1后轮距及后轮差速的调整差速机构的作用是在车模转弯的时候,降低后轮与地面之间的滑动;并且还可以保证在轮胎抱死的情况卜不会损害到电机。当车辆在正常的过弯行进中(假设:无转向不足亦无转向过度),此时4个轮子的转速(轮速)皆不相同,依序为:外侧前轮>外侧后轮,内侧前轮)内侧后轮。差速器的特性是:阻力越大的•侧,驱动齿轮的转速越低;而阻力越小的一侧,驱动齿轮的转速越高以此次使用的后轮差速器为例,在过弯时,因外侧前轮轮胎所遇的阻力较小,轮速便较高;而内侧前轮轮胎所遇的阻力较大,轮速便较低。由于速度高,赛车在转弯时容易翻倒,为了增加整车的平衡能力,通过改装后轮连接臂上的螺孔位置来调节轮距,从而增加的小车的稳定性。3.1.1.2齿轮传动机构的调整车模后轮采用RS-380SH-4045电机驱动,由竞赛主办方提供。齿轮传动机构对车模的驱动能力有很大的影响。齿轮传动部分安装位置的不恰当,会大大增加电机驱动后轮的负载,从而影响到最终成绩。调整的原则是:两传动齿轮轴保持平行,齿轮间的配合间隙要合适,过松容易打坏齿轮,过紧又会增加传动阻力,白白浪费动力;传动部分要轻松、顺畅,容易转动,不能有卡住或迟滞现象。齿轮传动机构的调整就是调整电机输出轴的齿轮与后轮轴上齿轮之间的耦合程度。当耦合比较松时由于两齿轮之间存在较大的缝隙,齿轮转动时会产生很大的两齿轮之间的碰撞声音,这样会大大增加齿轮的磨损。当耦合的比较紧时齿轮之间的摩擦力变大,这样就会使电机分出一部分驱动力克服齿轮之间的摩擦力做功,电机的负载无形中就增强,从而减小了电机对后轮的驱动能力。为了使齿轮的调整比较适当,经过多次的调试,我们发现用听齿轮之间的
21声音的办法来调整其耦合程度效果不错。当齿轮耦合较松或两齿轮之间不平行时的声音很响,也就是齿轮之间撞击的声音很大,当齿轮耦合比较紧时声音很沉闷并且迟滞,最佳状态是基本上没有撞击的声音,声音清脆并且没有迟滞现象。3.1.1.1底盘和重心的调整按照常规,车辆底盘高度越低,车辆重心越低,后轮抓地力越好,前轮转越敏感。因此在很多赛车比赛中,提高速度有效方法就是降低底盘高度。另外,我们将电路板做得非常小,刚好能放在舵机和电池架中间的底板上,这样,不但可以压低模型车的重心,防止高速过弯时翻车,也可以使纵向重心前移,增加转弯性能。同时也可以减轻模型车的质量,让赛车能在最短时间内加到最大速度。原始车模得重心大概在车的中后部,在电池架的中间。我们在调试的过程中发现模型车过弯时,转向往往不足,不够灵敏。我们加工了一个舵机支架和摄像头支架,铝合金材料既有足够的刚性,质量也比较轻,让模型车的重心前移至模型车的中部。除此外,我们在装旋转编码器时也把其装的很低,以降低赛车的重心,提高赛车行驶的稳定性。除了对车辆重心纵向的调整之外,车辆重心的前后方向调整,对赛车行驶性能,也有很大的影响。根据车辆运动学理论,车身重心前移,会增加转向,但降低转向的灵敏度(因为大部分重量压在前轮,转向负载增大),同时降低后轮的抓地力;重心后移,会减少转向,但增大转向灵敏度,后轮抓地力也会增加。因此,调整合适的车身重心,让车模更加适应比赛赛道很关键。为了保证赛车足够的转向和防止在高速入弯时出现甩尾现象,我们让重心大概在赛车的中心,在过弯时,使其前后轮的侧向摩擦力大体相当,从而提高过弯性能和稳定性。3.2电路板的安装电路板是模型车上的核心部分,在安装时,考虑到电路板的稳定性和模型车的重心等问题,我们把电路板做的比较小,安装在舵机和电池支架中间的底板上。我们在底板上打2个螺孔,分别将电路板的2个固定孔固定在底板上,保
22证电路板的牢固性,同时还可以压低重心并使重心前移,提高模型车的过弯性能和稳定性。安装图如下:3.2传感器的安装3.2.1摄像头的安装安装摄像头时,要考虑的因素很多。安装过高时视野比较宽,黑线变得很细甚至在图像的远端根本采集不到黑线。同时受到的干扰和抖动都很强烈,过弯时也容易翻车。安装过低,视野变小,图像变形严重,而且容易反光。在过急弯时“丢线”现象比较严重。摄像头支架安装在模型车的前与后也有不同的效果,安装在前面,过弯时赛车甩的很严重,摄像头抖的厉害,模型车高速行驶时,稳定性能不是很好。安装在中间时,摄像头比较稳定,转弯时几乎不丢线,能正确把握路面信息,提高小车行驶的稳定性和过弯性能。考虑到以上因素,我们将摄像头安装在模型车的中间稍微靠前一点,用铝合金的材料做支架,质轻且刚度较好,抖动不强烈。安装的高度大概在距底板15cm的位置,这样能够满足前瞻性好,图像变形不是很严重,视野足够宽的要求。安装支架AutoCAD图片如下图所示:
23实物图如下:3.2.1旋转编码器的安装旋转编码器在安装时主要考虑其能否和电机齿轮很好的咬合,不至于速度较快时,出现速度检测不准的现象。我们把旋转编码器齿轮通过一个大齿轮传动和电机齿轮直接咬合,减小误差,同时把其安装在靠近底板位置以降低重心位置,增强后轮的抓地能力。
24实物图如下:3.2本章小结本章主要介绍了我们对赛车机械结构进行的安装和改进。根据汽车动力理论将主销后倾角设为3度,使车轮具有自动回正的功能。为了缓解前轮的松动影响,设定了一定的主稍内倾和前轮前束。将舵机力臂加长了2cm,提高了舵机的响应速度。舵机采用竖直安装的方案,使前轮的左右连接杆相等,保证左右转向相同。连接杆和角度调节头几乎垂直,使得转向时舵机有最大的输出力矩,赛车过弯的性能也有了很大的提高。通过调整底盘前部的高度,使赛车的底盘呈现前高后低的姿态,提高了赛车过斜坡的性能。重心的调整,加宽后轮距和前轮的调整,大大的减少了赛车转向不足,侧滑等严重问题,使赛车后轮的抓地力和前轮转向力之间有了一个很好的均衡。对前轮、后轮、和舵机的一系列调整,提高了赛车的行驶性能。
25第四章硬件系统设计与实现4.1硬件系统框图硬件系统主要包括电源模块、单片机模块、升压模块、视频采集模块、速度传感模块和驱动模块。为了使得电路更加紧凑、外部引线更少,我们独立设计了一块核心控制电路板。各硬件模块之间的拓扑框图如图4-1o图4-1硬件系统框图4.2电路板的设计与制作为了使得电路更加紧凑、外部引线更少,我们独立设计了一块核心控制电路板,尺寸为50mm*56mm。电路板上包括了S12单片机工作所必需的稳压模块、时钟模块和复位模块,同时还包括了电机驱动电路、BDM调试接口、以及其他一些
26电路的接口等。PCB图如下所示:4.1电源模块电源是模型车各电器部分的动力来源,我们根据各部分的具体情况,对电源电压进行了分配。其中,考虑到舵机是个滞后性元件,为了提高其转动灵敏性,用电源直接给舵机供电。电源分配如图4-2o
27图4・2电源管理4.1.15V稳压模块智能车系统采用配发的标准的车模用的7.2V2000mAhNi-cd蓄电池进行供电,但各个模块所需要的电压不同,因此需要进行电压调节。电源系统的好坏直接关系到整个系统的稳定性。4.1.1.1稳压芯片选择稳压芯片主要有线性稳压芯片和开关稳压芯片两种。电机和舵机的突然启停会使电池电压骤变,一般会把电源电压拉低IV多,会对系统电源造成干扰。所以系统的电源必须有一定的抗干扰能力。鉴于开关电源纹波比较大,而线性稳压电源纹波很小,我们选择了使用线性电源,其中我们选择LM2940线性稳压芯片。LM2940-5.0,为单片线性稳压芯片,输出电压5.0V,最大输出电流31A,且具有很小的压差功能,模型车突然加减速时不会发生复位,可以满足系统的供电要求。4.1.1.2电路设计为了减少电机部分加减速导致电池电压下降对稳压芯片的影响,我们专门在2940电源输入引脚前串一功率电感,可有效降低电机对5V稳压芯片的干扰。原理图如图4-3所示:FLLI10uHLVVin图4-35V电源
284.1图像采集模块4.1.1摄像头简介摄像头分黑白和彩色两种,为达到寻线目的,只需提取画面的灰度信息,而不必提取其彩色信息,所以我们所使用的CMOS摄像头输出的信号为黑白视频信号。我们所选用的摄像头芯片为OV7620,1/3英寸数字式CMOS图像传感器OV7620,总有效像素单元为664(水平方向)x492(垂直方向)像素;内置10位双通道A/D转换器,输出8位图像数据;具有自动增益和自动白平衡控制,能进行亮度、对比度、饱和度、丫校正等多种调节功能;其视频时序产生电路可产生行同步、场同步、混合视频同步等多种同步信号和像素时钟等多种时序信号;5V电源供电,工作时功耗<120mW,待机时功耗<10pW。可应用于数码相机、电脑摄像头、可视电话、第三代网络摄像机、手机、智能型安全系统、汽车倒车雷达、玩具,以及工业、医疗等多种用途。OV7620是1/3”CMOS彩色/黑白图像传感器。它支持连续和隔行两种扫描方式,VGA与qvga两种图像格式;最高像素为664x492,帧速率为30fps;数据格式包括YUV、YCrCb、RGB三种,能够满足一般图像采集系统的要求。4.1.2电路设计
29由于我们采用的是数字摄像头,相对于CCD来说电路相对简单,而且市场上买的摄像头大多是个人制作,稳定性不好,质量参差不齐,接口不一致,所以我们自己设计摄像头,原理图如44所示:+5VOV1SCl^ujbR图44摄像头原理图实物图(图4-5)如下:图4-5摄像头实物图
304.1速度采集模块1)使用光电对管配合光码盘参照鼠标的原理,在后轴上安装一个光码盘,转动时码盘的齿会遮挡红外线,使红外管输出一系列的脉冲。2)使用霍尔传感器配合稀土磁钢在齿轮上装上几棵稀土磁钢,将霍尔元件安装在附近,将轮子转动时磁场的变化转化为电脉冲,从而获取轮子的转速3)使用旋转编码器。市售的旋转编码器,每转动一圈可以输出几百个脉冲,通过检测脉冲数就可以计算出车速。第一种方案安装比较方便,转动一周能输出几十个脉冲。但是在速度较快时,其精度会逐渐降低,对车速不能进行精确的控制。第二种方案安装比较复杂,而且转动一圈只能输出很少的脉冲,调速时不够精确。第三种方案安装比较方便,输出的是标准的方波,应用时精度非常高,而且几乎不需要辅助电路便可完成速度检测。所以我们选择第三种方案。4.2电机驱动图4-5电机驱动模块
314.1本章小结本章介绍了系统的硬件模块,包括电源模块,单片机模块,视频采集模块,速度传感模块和驱动模块。使用LM2940线性稳压芯片,通过合理的布局设计,为赛车系统构建了一个稳定的电源系统,摄像头采用数字CMOS视频芯片,稳定空考。驱动电路采用BTS7970B的方案,既提高了驱动的能力,又减少了芯片的发热量。经测试整个硬件系统能可靠稳定的工作,为软件系统搭建了一个稳定可靠的硬件平台。整体硬件安装图如下:
32第五章软件系统设计与实现5.1软件系统设计按照比赛规则要求,采用限定的飞思卡尔16位微控制器MC9S12XS128作为唯一控制处理器,MC9S12XS128为16位单片机,内部包含有丰富的外围模块,系统框图如图5-1所示。SPI2orPWMCH4-7SPUorPWMCH0-3SPIOHCS12CPUBKPINTMMISIMCMBDMMEBIPLLprr2KBYTESEEPROM8KSRAMFL1281ASEEFROMPWM8CHANECT8CHANSCI0SCI1InternalBusmsCAN4orIICmsCAN3msCAN2msCAN1msCAN0orBDLCPIMVREGATD1ATD0图5-1MC9S12XS128系统框图5.1.1时钟模块S12单片机中有四个不同的时钟,即外部晶振时钟、锁相环时钟、总线时钟和内核时钟。当前电路板采用的是16MHz的外部晶振,因此外部晶振时钟为16MHz;默认设置下,锁相环时钟为32MHz,总线时钟为8MHz,内核时钟为16MHz。锁相环时钟与外部晶振时钟的倍、分频关系由SYNR,REFDV两寄存器决定。总线时钟用作片上外围设备的同步,而内核时钟则用作CPU的同步,它决定了指令执行的速度。由于采用摄像头作为主要的寻线传感器,为了提高摄像头处理帧数,我们对单片机进行了超频。
335.1.1PWM模块脉宽调制模块有8路独立的可设置周期和占空比的8位PWM通道,每个通道配有专门的计数器。该模块有4个时钟源,能分别控制8路信号。通过配置寄存器可设置PWM的使能与否、每个通道的工作脉冲极性、每个通道输出的对齐方式、时钟源以及使用方式(八个8位通道还是四个16位通道)。为了提高控制精度,我们将PWM6、PWM7两路8位通道合并为一个16位通道来控制舵机,这样可使舵机的控制精度从1/255提高到1/65536。5.1.2外部中断模块视频信号的行同步有两种方式输入S12单片机,一种是通过IRQ外部中断引脚接入,另一种是通过ECT模块接入。实际调试中,通过跳线对这两种方式进行选择。这里先介绍外部中断模块的使用。首先,在初始化程序中应设置外部中断的捕捉边沿,并开启外部中断。INTCR_IRQE=1;//IRQselectedgesensitiveonlyINTCR_IRQEN=1;//externalIRQenable然后,当检测到下一场视频信号的到来时,开启中断,在中断服务程序内完成对所需的行进行扫描,结果记录在一个二维数组中。扫描结束后,关闭中断,对数据进行分析处理。5.1.3ECT模块增强型捕捉定时器模块,顾名思义,通过一系列可供设置的控制寄存器和可供读写的数据寄存器对端口功能进行了扩展。总的来说,ECT模块能实现输入捕捉和输出波形产生两大功能。最终方案中,有3路信号输入ECT端口。首先,是由摄像头输出行同步、场同步信号。利用ECT模块的脉冲捕捉工作方式,并通过查询TFLG1寄存器中的对应标志位来判断是否已获取相应信号,可以准确同步每场视频信号,完成数据点的采集。其次,是速度传感器输出的脉冲信号。采用脉冲累加的LATCH工作方式,可以很准确地获取相同时间间隔内(32ms)的脉冲累加数(PA1H),从而得到小车的当前速度。5.1.4串行口模块串口通信模块设有两个串行通信接口SCI1和SCK),均为TTL电平输出。使用时,可以对波特率、数据格式(8位或9位)、发送输出极性、接收唤醒方式等进行选择。另外,发送和接收可分开使能,模块中还提供了多种避免传输错误的选项。5.1.5SPI模块SPI模块主要用来写SD卡,在试验过程中我们发现蓝牙串口的传输速度有限,不能将图像传回来,所以我们采用速度更快的SD卡来采集图像。
345.1资源分配PTO捕捉场同步信号At.快队PT1捕捉行同步信号ETCPT7速度测量PWM67舵机控制PWMPWM45摄像头曝光控制PWM01、PWM23驱动电机渊naPA0~PA6视频FIFO控制和摄像头控制知ni—i八PA7蜂鸣器控制端口BPBO〜PB7数码管控制显示端口EPEO〜PE7按键控制检测端口SPSO〜PS4LED显示端口PMPMO〜PM1串口控制PM2〜PM5SPI控制端口JPJ6〜PJ7电机驱动控制使能端口ANANO'AN7摄像头数据接受5.2摄像头安装对软件调试的影响图中梯形区域ABCD为道路检测范围。为了克服模型车执行结构的惯性和时间延迟的影响,前方道路检测范围越大,对提高模型车速度越有利。直线AB是道路检测显前端,它距离模型车前端的距离EH为道路检测前瞻距离。它的长度AB是道路检测最大范围,在GH之间是道路检测盲区。调整摄像头的安装位置与方向,能够增加检测前瞻距离,检测范围并减少检测盲区,可以提高模型车的运行速度和稳定性。但是检测范围与检测精度是一对矛盾,检测的前瞻距离与检测盲区也是一对矛盾。因此需权衡利弊,以达到简化代码并获取必要信息。
355.1图像处理5.1.1黑白阈值提取采用概率统计法获取黑白色差值,分别找到黑白值峰值,做差以适应不同环境下的阈值变化,提高适应性。获取数据分布如下:5.1.2图像滤波获取黑线后,由于反光,干扰点等影响,一般很难得到连续的路径曲线,故需要进行滤波处理。可采用中值滤波或邻域平均法进行滤波。对实际黑斑采用不同滤波方法进行滤波处理所得图像如下。可见经处理可明显改善图像质量。邻域平均法:处理前
36处理后中值法:处理前处理后
375.1软件系统框图整个软件系统要实现的功能就是根据采集到的跑道数据和速度数据对赛车的舵机跟电机作出一系列的控制,使赛车沿着跑道高速行驶。按功能划分整个软件系统可以分为图像采集模块、图像处理模块、转向控制模块、速度采集控制模块、速度控制模块这五大模块。各模块之间的关系如下框图所示:软件组织结构如下:UESTC_FLYmcp|unknownconnection勺⑤加Fil"|LinkOrder|Targets|♦Fil*Code.明readme,txtn/a曲tips.txtn/a♦-^Sources0♦+口DRIVER0<>QSCCB0♦40FAT0♦ifCJSD0♦QFIFO0♦+C*1SpeedControl0♦+口debug0“+(JINTERRUPT0■+Q]AutoControl0♦:♦ClImage0阴head.txtn/a■单main,c0助main,h0・单datapage.c0"单main,asm0由main_&sm.h0$+rnSt&rtupCode0于ClFra0+口LinkerMap0--+口Libraries18821+PlDebuggerProjectFile0+ClDebuggerCmdFiles0
38软件流程图如下所示:冲出跑道5.1.1图像采集模块图像采集控制是所有任务中实时性要求最高的任务,第一种方案是在中断服务程序中进行图像采集,这样既可以保证采集的实时性,又可以和其他任务
39相对独立。第二种方案是在XS128上面移植操作系统UCOS,把图像采集的任务作为高优先级,但是考虑到舵机和电机的控制直接影响小车的安全性,应该放在最高优先级。为了提高图像采集的速度,在C语言中嵌入了汇编语言,通过超频到88M可以很好的控制图像采集的速度。S12CPU超频程序:voidBusClock_Init(void)CLKSEL=OxOO;PLLCTL_PLLON=1;SYNR=Oxdc;REFDV=0x46;_asm(nop);_asm(nop);//disengagePLLtosystem//turnonPLL//VCOFRQ[7:61;SYNDIV[5:0];fVCO=2*fOSC*(SYNDIV+1)/(REFDIV+l);fPLL=fVCO/(2xPOSTDIV);BUS=fPLL/2//REFFRQ17:6];REFDIV[5:OJ//BUSCLOCK=24Mwhile(!(CRGFLG_LOCK==l));//whenpllissteady,thenuseit;CLKSEL_PLLSEL=1;//engagePLLtosystem;}5.1.1图像处理模块图像信号处理中提取的赛道信息主要包括:(1)每一行的赛道中心位置(2)每一行的赛道宽度(3)赛道的曲率(4)赛道的变化幅度(5)赛道任一点的导数值(6)赛道形式,包括直道、左弯、右弯、大S弯、小S弯等等每幅图像,我们只对其中的33行进行采样,实际测试中33行的采样点已经能够为赛车提供足够的控制信息。5.5.2.1黑线的提取通过摄像头采集图像,AD数字化后将图像分为256个灰度级,由于光线影响黑线路径的灰度并不是固定的,而是在一定范围内变化,所以单靠灰度值的判断很难分辨出真正的黑线来,但是黑线路径和白色路面的灰度值相差总有30左右,因此可以通过差分的方法进行边缘提取黑线。经过实际分析,发现黑线的宽度10到20个像素,程序从图像左端到右端每隔3个像素进行一次差分运算,即把相隔3个像素的灰度值相比较,如果这两个像素灰度值相差超过设定的阈值就可以判断发现了边缘。提取到由白到黑边缘和由黑到白边缘后这两个边缘的距离就是黑线的宽度,设定一定的黑线宽度限制可以剔除图像中一些小黑点的干扰,如果黑线宽度符合设定条件,两个边缘的中点就是黑线的位置。考虑到每行有160
40个像素,用这种方法提取33行的边缘数据运算量非常巨大,会消耗CPU大量运算时间。实际提取过程只需要在上一行黑线的附近位置进行边缘提取即可,这样不但可以节省大量运算时间,还可以剔除大量的干扰点。下面为往届比赛中用到的二值化算法。算法的思路是:设定一个阈值valve(例如45),对于视频信号矩阵中每一行,从左至右比较各像素值和阈值的大小。若像素值大于等于阈值,则判定该像素对应的是白色赛道;反之,则判定对应的是目标指引线。记下第一次和最后一次出现像素值小于阈值时的像素点的列号,算出两者的平均值,以此作为该行上目标指引线的位置。图5.521黑线提取算法流程图我们在实验了二值化算法和边沿检测算法之后,决定使用边沿检测算法。原因有:二值化算法的黑白阀值很难确定,而且在二值化之后,还是需要通过检索来提取黑线中心位置。图552.2为黑线提取的效果图,黑线上的黑点为提取到黑线的位置。可见
41这种方法提取的黑线很准确。图5.522为黑线提取的效果图1.1.1.2黑线的提取修正实际调试过程中由于环境的不理想,例如跑道的接缝或破损,或者赛道的反光等影响会导致黑线提取不完全,出现断线的情况,此时就要对黑线进行适当还原以保证路径识别的稳定性。如果发现某行黑线提取失败,通过前几行的黑线位置计算出路径的斜率,根据斜率进行此行黑线的补偿。在我们遇到的干扰中进行的黑线补偿非常成功,赛车基本不会因为图像识别错误而跑出赛道。5.2.3转向控制模块摄像头采集的图像可以提供足够的信息用于路径分析,怎样利用好丰富的赛道信息是实现赛车稳定行驶的关键。其实在车速不快的情况下只用车前40cm内的黑线偏差就可以让赛车沿黑线行驶,问题是在赛车高速行驶时需要对前方更远的赛道信息进行预判,例如控制赛车入弯前减速、使赛车走最优路径等。因此我们使用距离车前第21行、22行、23行的黑线平均位置计算赛车离黑线的偏差控制舵机拐向,用更远端的黑线来进行赛道预判。计算相邻两段黑线的斜率还可以判断出小S弯,让赛车在小S弯直冲。PID算法以其结构简单、稳定性好、工作可靠、调整方便而成为工业控制的主要技术之一。其基本结构如图5.5.3.1所示。图5.5.3.1
42如图5.531所示,Mid.Erro为赛车当前的方向偏差,用于控制舵机当前时刻的转向。Top_Erro为图像最远端离中线的偏差,用于进行赛车前方赛道预判,Top_Erro越失,减速越大如图5.5.3.2所示,只要计算相隔S_Row行的黑线的相对斜率Up_Erro和Down_Erro,如果Up_Erro和Down_Erro方向相反而且大于预设的阈值就可以判定出小S弯,让输出的偏移量Erro缩小,减小舵机的转向,使小车减小Row*2行Row行5.5.4PID调节器PID控制是工程实际中应用最为广泛的调节器控制规律。问世至今70年多年来,它以其结构简单、稳定性好、工作可靠、调整方便而成为工业控制的主要技术之一。单位反馈的PID控制原理框图如图5.5.4所示。图5.2.4PID算法示意图
43比例(P)控制比例控制是一种最简单的控制方式。其控制器的输出与输入误差信号成比例关系。当仅有比例控制时系统输出存在稳态误差。积分(I)控制在积分控制中,控制器的输出与输入误差信号的积分成正比关系。对一个自动控制系统,如果在进入稳态后存在稳态误差,则称这个控制系统是有稳态误差的或简称有差系统。为了消除稳态误差,在控制器中必须引入“积分项”。积分项对误差取决于时间的积分,随着时间的增加,积分项会增大。这样,即便误差很小,积分项也会随着时间的增加而加大,它推动控制器的输出增大使稳态误差进一步减小,直到等于零。因此,比例+积分(PI)控制器,可以使系统在进入稳态后无稳态误差。在本系统中赛车要以很高的频率调整转向,舵机的反应也就很快,所以系统的稳态误差不会有足够的时间积累就要进入下一个稳态,加入积分控制不但没有预期效果反而会使系统反应滞后,故实际控制中积分项没有加入。积分项的比列系数为零。微分(D)控制在微分控制中,控制器的输出与输入误差信号的微分(即误差的变化率)成正比关系。自动控制系统在克服误差的调节过程中可能会出现振荡甚至失稳。其原因是由于存在有较大惯性组件(环节)或有滞后组件,具有抑制误差的作用,其变化总是落后于误差的变化。解决的办法是使抑制误差的作用的变化“超前”,即在误差接近零时,抑制误差的作用就应该是零。这就是说,在控制器中仅引入“比例”项往往是不够的,比例项的作用仅是放大误差的幅值,而目前需要增加的是“微分项”,它能预测误差变化的趋势,这样,具有比例+微分的控制器,就能够提前使抑制误差的控制作用等于零,甚至为负值,从而避免了被控量的严重超调。所以对有较大惯性或滞后的被控对象,比例+微分(PD)控制器能改善系统在调节过程中的动态特性。离散pid形式:U(K)=Kp*e(k)+Ki*Ze(k)+Kd*[e(k)-e(k-l)]式中:Kp由比例项系数,Ki为积分项系数,Kd为微分项系数,U(k)是K和K-1时刻的输出量,e(k),e(k-l)分别是k,k-1时刻赛车位置和黑线的偏差值.系统中输出量U(k)为对舵机偏转方向的控制量,输入偏差e(k)为赛车当前的方向偏差,Kp,KI,KD三项系数要根据系统的相应特性不断调试,最后选出合适的大小。经试验发现,比例系数越大转向时能越快达到稳态,但在直道上容易震荡。较小的比例系数在直道上可以获得较好的稳定性,但在弯道上的响应较慢。微分项可以加快转向时的响应速度。
445.5.4速度采集模块利用ECT脉冲累加器对速度传感器送出的脉冲进行计数,计算一定时间内的脉冲数目,就可以得到当前的车速。为了方便提高实时性,我们在行中断中读取4次脉冲累加寄存器的值。累加取平均值。5.5.5速度控制模块速度控制采用传统的增量PID控制,参数在软件上调试,目的是使电机的响应时间最短,稳定误差最小。为了每次速度控制的时间间隔统一,我们在场中断中启动速度控制函数,而且只适用两个速度,直到速度speed_s,弯道速度speed」。如下:if(SPEED_FLAG==1)〃直道速度{if(S_road==0)(Straight_Cnt+=2;)if(Straight_Cnt>30)Straight_Cnt=36;Speed_II(speed_s);)elseif(SPEED_FLAG!=1)//弯道速度{if(Straight_Cnt<2)Straight_Cnt=2;Straight_Cnt—;Speed_II(speed_r);)5.6特殊标记识别5.3.1起跑线识别模块根据比赛规则,起跑线只会出现在直道上,所以只需要在程序判断出赛车在直道上时才进行起跑线的识别。当赛车在直道上行驶时,黑线出现在采集到的35行图像上的每一行上,而且黑线最远端和最近段的横向偏差不大,因此可以较准确地判断出直道来。起跑线如图531.1所示。4.5cid4.5cm
45I图5.3.1.1起跑线的特征是两条横帖的10cm的黑线以及两边黑线间的32.5mm的白色空隙。首先从图像的近端行开始在黑线路径向左边用同样的边缘提取方法搜索由黑到白的边缘,再继续搜索由白到黑的边缘,然后再继续搜索由黑到白的边缘,如果成功搜索到3个边缘则用这3个边缘的位置计算白色空隙和横贴黑线的长度,若长度符合起跑线的要求表明图像左边出现了起跑线的特征,继续搜索路径右边的起跑线特征。如果两边都同时出现了起跑线的特征就可以判定此副图像中有起跑线。由于采集的行数足够多,图像的纵向分辨率足以满足起跑线占1行以上的宽度,无论在图像近端或远端都不会因为分辨率不足导致丢失起跑线的情况出现。因此程序只要在同一行中搜索起跑线即可,不需要在不同的几行中搜索,这样可以避免车身不正时交叉线会在相邻几行中出现起跑线的特征引起误判。5.7本章小结本章介绍了整个软件系统的具体构造和思想,系统由图像处理模块、图像采集模块、特殊路径识别模块、转向控制模块、速度控制模块和速度采集模块组成。第六章系统调试6.1开发调试工具系统的开发调试用到了Metroworks公司的CodeWarrior4.5开发软件,另外为了调试方便,我们开发了无线调试模块、SD卡和外部状态指示单元等。
466.1.1软件开发平台此次智能车大赛的软件开发平台为Metroworks公司的CodeWarrior4.5开发软件。其使用界面如图6—1所示:图6TCodewarrior使用界面CodeWarrior的功能非常强大,可用于绝大部分单片机、嵌入式系统的开
47发。用户可在新建工程时将芯片的类库添加到集成环境开发环境中,工程文件一旦生成就是一个最小系统,用户无需再进行繁琐的初始化操作,就能直接在工程中添加所需的程序代码。“CodeWarriorforsl2”是面向以HC12或S12为CPU的单片机嵌入式应用开发的软件包。包括集成开发环境IDE、处理器专家库、全芯片仿真、可视化参数显示工具、项目工程管理器、C交叉编译器、汇编器、链接器以及调试器。为软件的开发调试提供了极大的方便。6.1.1智能车上位机设计由于单片机处理能力有限,而当我们实验算法时需要大量的计算,由此我们专门设计我智能车上位机,效果如下图所示:6.1.2无线调试模块在智能车的制作和调试过程中,需要将小车检测到的路面信息以及速度等参数实时地发给PC,以便对算法进行有针对性的分析。由于小车在行驶时不能通过有线的方式获得其运行参数,我们使用了无线模块。无线模块介绍:GC—05蓝牙模块,通讯距离达到100米。支持串口(UART)与USB口透明数据传输,适用于串口设备与计算机之间的数据传输。使用此模块S12单片机可以方便地和PC通过RS232协议通信。
48实物图如下:6.1.1状态指示灯出于系统调试方便和便于观察赛车运行状态的考虑,我们在赛车上加装了4个LED作为赛车的状态指示灯,大大的提高了调试的效率。6.1.2手动设置装置由于赛前我们有一定的调试时间,因此可以针对赛道的具体情况,通过按键数码管显示对一些可变参数进行设定,这可以使得小车的适应能力更强。同时这在平常的调试中,也大大方便了我们对参数的重新设置。按键数码管显示部分的电路很简单。实物如图所示:
496.1.1蜂鸣器声音指示当赛车快速行驶时,检测到预设的事件发生(如发现起跑线,直道减速等)时,蜂鸣器立即发出声音提示,在调试过程中非常实用。6.2转向PID参数整定实验结果如下表所示:测试编号PROPOTIONDERIVATIVE直道穹道小S穹130入严重偏西胞道冲出底道260稳定偈离较小优于测试1会抖动390震荡优于测试2优于测试2仍然会抖动46I稳定同测试2优于测试3抖动较小562稳定优于测试3能较流稀通过691震荡优于测试5没有测试5流崎对实验结果进行分析可得:(1)较小的PROPOTION值,有利于直道上行驶的稳定,但弯道上转向滞后,容易冲出跑道。(2)较大的PROPOTION值,容易造成直道上的震荡,弯道上舵机能及时响应。(3)适当的DERIVATIVE值,对提高赛车在S型小弯的稳定性作用明显。为了使赛车在弯道上的响应尽可能的快又能避免在直道上震荡,采用分段pid
50的方式,在直道上设置较小的比例系数,在弯道上设置较大的比例系数。6.1本章小结本章主要介绍了系统调试用到的工具及算法的调试和实验结果。选用CodeWarrior4.5forsi2作为软件开发平台,通过自开发软件对图像采集和图像处算法进行辅助调试,以4个LED以及数码管作为赛车行驶状态及程序运行状态的指示,大大方便了系统的调试。
51第七章总结7.1赛车整体技术指标7.2总结经过长达半年时间的准备,我们梦想号终于完成了设计计划中所需完成的任务。从车模的安装,机械结构的调整,到电路板的制作,传感器方案的制定,从算法的调试改进,到赛道的实际测试,最终确定了我们的最终硬件作品。7.2.1赛车制作从最开始的茫然,到现在的成竹在胸,整个智能车的制作让我们成长了很多,学到了很多。控制、模式识别,传感技术、汽车电子、电子信息、计算机和机械等知识的涉猎,开拓我们的视野,实际的验证提高了我们的动手能力。从整体方案的设计到赛车成型,从传感器安装到机械结构设计,从控制算法研究到模块程序编写,整个过程让我们学到与人合作、协调分工和积极自信的团队精神。7.2.2问题与解决现在对设计开发过程中遇到的一些重点问题进行说明。1)机械改装:在实际的调试中,发现大赛规定的舵机延时很严重,大大影响了赛车的入弯速度。但舵机的输出力矩却很大,所以通过加长舵机输出力臂的方法来提高舵机的响应速度。我们将力臂加长了2cm,前轮摆动相同的角度时,舵机只要转动原来转动角度的60%,所以前轮的摆动速度比原来快了40%。我们将舵机竖直安装。之这所以要这样做的原因是为了保持横拉杆的水平。因为只有舵机使出的力的水平分力才是使前轮转向的有效分力,保持横拉竿水平可以使舵机输出的力就是使前轮转向的有效分力。经实验,对舵机的改动后小车的过弯性能有了很大的提高。2)斜坡比赛赛道中有斜坡,为了验正赛车的可靠性,我们设计了“最坏”的赛道。
52即下坡后接着是一个90度的急弯。实际测试赛车在这样的赛道上,因为速度过快,很容易冲出赛道。但是这样的赛道在实际比赛中是可能会遇到的。最开始我们考虑使用加速度传感器识别上坡和下坡,以便对速度进行控制,避免赛车冲出赛道。实际上解决问题的关键在于速度的控制,最终我们使用速度PingPong控制解决这个问题。3)小“S”弯在开始的校内选拔赛,我们发现赛车在过小“S”的时候因为没有设计相关处理算法,同时因为速度过快,出现赛车剧烈抖动的现象。抖动限制了赛车速度的进一步提高,而且相对而言,走了更多路程。通过分析赛道的图片,我们发现只要根据采样的到赛道信息判断出小S弯,使小S弯时舵机的转向比例变小,这样很简单就解决了赛车过小“S”弯的问题,使我们的赛车的速度有了一个突破。4)摄像头采样在调试摄像头的时候,我们发现S12的I/O读写频率只能达到3M多,并且由于我们算法比较复杂,摄像头只能达到30帧,后来我们通过超频到88M,并且降低摄像头采样的行数,实现了60帧的控制频率。7.1.1亮点与特色“速度与稳定”是赛车设计者永恒的追求,“成电轻扬”基于对这一基本观念的理解,秉承创新的设计理念,通过智能汽车控制理论和应用使赛车呈现更佳的运行状态,使速度更快,系统更稳定。更为充分的资源利用:AN采集负责摄像头视频采集,定时器模块捕获行场同步信号,端口B赛车状态显示,端DA读速度模式状态,ECT采集速度传感器数据,PWM控制舵机和驱动电机。更为合理的机械结构:根据汽车动力理论将主销后倾角设为3度,使车轮具有自动回正的功能。将舵机力臂加长了2cm,使前轮的摆动速度提高了40%o舵机反向安装的方案,使舵机输出的水平分力能被前轮更为充分的利用,使赛车过弯的性能有了很大的提高。通过调整底盘前部的高度,使赛车的底盘呈现高后低的资态,提高了赛车过斜坡的的性能。重心的调整,使赛车后轮的抓地力和前轮转向力之间有了一个很好的均衡。更为精确的信息采集:在硬件上采用超频技术,数据结构上摒弃了通常的
53数组的形式,使采样率提高了近一倍,为赛车提供了更为精确的赛道信息。给视场分区的方案,使赛车不仅能判断出赛道的曲直,还能测出弯道的曲率半径。更为完善的控制策略:速度分级和分段PD调节的策略,既保证了赛车在直道上的稳定性,又保证了赛车在弯道上具有良好的响应。“小S弯直走”和“走内弯'’的策略,更优化了赛车的行驶路径。更为优化的软件算法:线性拟合思想的引入,对采集到的赛道信息进行拟合处理,不仅使赛车具备了直走“小S弯”的能力,还提高了赛车的稳定性。在测试中,赛车在黑线间断的弯道上同样可以稳定的行驶。最后更为出色的硬件设计,所有硬件元器件集中在50mm*56mm的PCB板上,将PCB板做到了极致,稳定的性能(超频到88M)更轻的重量(100g),更少的引线(舵机引线,编码器引线,摄像头引线,电源引线,电机引线),保证了软件的顺畅运行和小车的稳定快速的奔跑。7.1.1展望与改进我们的赛车还有进一步提升的空间:首先,汽车理论知识没有做太深入的研究,赛车的机械性能还有很多提升的空间,赛车的重量及重量分配方案,还有待研究。其次,没有对记忆算法进行研究,如果时间允许,可在此方面深入分析测试,这种算法在现行的比赛规则下也许会有优势。最后,只使用OV7620摄像头和旋转编码器,以后可以尝试其他的更小的COMS摄像头芯片如OV7670,或许会有新的突破。
54致谢经过了近五个月的努力,我们终于完成了赛车制作。在此,对帮助过我们的老师同学表示深深的谢意。感谢飞思卡尔公司和主办方为我们提供了一个展示自我的舞台。感谢我们的指导老师程玉华和带队老师李超,是他们在后面默默无闻的支持我们,在参加比赛的过程中,为我们安排好一切,对我们关爱有加。感谢其他车队的同学,在和他们的交流中,使我们学到了很多东西。感谢电子科技大学为我们提供经费,场地,设备。最后,向审阅本报告的各位专家教授表示深深的谢意。
5514J[5][6][7]18J[91[11]Motorola,[12]Motorola,[13JMotorola,[14]Motorola,[15]Motorola,[16]Motorola,[17]Motorola,[18JFreescale,[19]KenLayne,参考文献[1]Motorola,UMC9S12XS256BDeviceUserGuideVI.09M,2007.10.31[2]National,( 56附1:程序代码:*FileName:main.h*Author:budapcng2000@yahoo.com.cn*Reference:*Date:20103.22*Comment:程序入口#include"main.h"UINT8row=0;UINT8fEnd=2;UINT16center[48];*FunctionName*Description*Parameters*Returnvoiddelay(longnum)longi;for(i=0;i 57/********************************按游程编码发送全图voidScndlmageRunCodeO〃变量定义inti;unsignedcharpixel;unsignedcharcharlbSend=0,用于装载待发送的一字节数据intprePixelColor=-1;〃若为帧的第一个像素,或者上一游雇统计—满需要新的字节发送,为-1〃否则,白色0,黑色1intk;intflag1=1;while(l)while(fEnd==l)if(row+l 58(〃游程已满,标记prePixelColor-1,下一像素重启一字节prePixelColor=-1;lnpulchar(charlbSend);)elseif(prePixelColor=1)〃非新帧,且上一字节为满,上一像素为黑色(if(pixekwhiteblack)//该像素为黑色{charrR>Send++;if(charlbSend>=255){〃游程已满,标记prePixelColor-1,下•像素重启•字节prePixelColor=-1;Inputchar(charlbSend):))else〃该像素为白色(〃开启新字节Inputchar(charlbSend);charlbSend=1;〃白色MSB置0prePixelColor=0;i++;/*******************—■行处理结束****************************/if(row+l>=230)〃判断是否帧结束/********帧结束,必要工作*********/if(prcPixelColor!=-l)(Inputchar(charT3Send);)fEnd=0;//delay(lOOOOO);〃两字节的0x55:0101010101010101作为帧头标志//delay(l(XX)OO);flagl=1;prePixclColor=-1;〃标记prcPixelColor为标志下•像素为帧第•像素TFLGI=0x02;TIEI=TIE_C1I_MASK;/*if((FieldSyncCounter%2)==0)( 59STATE=Oxff;delay(10000);)else{STATE=0x00;delay(KMX)O);************/voidSendAll()(〃变量定义inti;while(l)(while(fEnd=l)(if(row+2 60for(i=0;i<48;i++)(a=center[i];lnputchar(a);delay(50);a=center[i]»8;Inputchar(a);delay(50);voidImagcAndControlO{UINT16preWidth;UINT16preCenter;UINT8baseFound=0;inti;while(l)while(fEnd=l)if(row+1 61FORWARD;SlATE=0x00;BUZZER.OFF; 62Enablclntcrrupts;STATE=Oxff;//SendImageRunCode();//SendAllO;//SendImageBitCode();*FileName*Author*Reference*Date*CommentImageAndControl();:ff.c:budapeng2(XX)@yahoo.com.cn:get_fattime:20l0.3.22FAT应用层/FatFs-FATfilesystemmoduleR0.07e(C)ChaN,2009/--//FatFsmoduleisagenericFATfilesystemmoduleforsmallembeddedsystems./Thisisafreesoftwarethatopenedfbreducation,researchandcommercial/developmentsunderlicensepolicyoffollowingtrems./Copyright(C)2009,ChaN,allrightreserved./*TheFatFsmoduleisafreesoftwareandthereisNOWARRANTY./*Norestrictiononuse.Youcanuse,mcxiifyandredistributeitFor/personal,non-profitorcommercialproductsUNDERYOURRESPONSIBILITY./*Redistributionsofsourcecodemustretaintheabovecopyrightnotice./Feb26;06R0.00Prototype.//Apr29,'06R0.01Firststableversion.//Jun01/06R0.02AddedFAT12support./Removedunbufferedmode./Fixedaproblemonsmall(<32M)patition./Jun10,'06R0.02aAddedaconfigurationoption(_FS_MINIMUM).//Sep22/06R0.03Addedf_rename()./Changedoption_FS_MIN1MUMto_FS_MINIMIZE./Dec11/06R0.03aImprovedclusterscanalgolithmtowritefilesfast./FixedfLmkdir()createsincorrectdirectoryonFAT32.//Feb()4,'07R0.04Supportedmultipledrivesystem./Changedsomeinterfacesformultipledrivesystem./Changedf_mountdrv()tof_mount()./Addedf_mkfs()./Apr01,'07R0.04aSupportedmultiplepartitionsonaplysicaldrive./Addedacapabilityofextendingfilesizetof_lseek()./Addedminimizationlevel3./Fixedanendiansensitivecodeinflmkfs()./May05/07R0.04bAddedaconfigurationoption_USE_NTFLAG/AddedFSInfosupport./FixedDBCSnamecanresultFR_INVALID_NAME./Fixedshortseek(<=csize)collapsesthefileobject./Aug25,'07R0.05Changedargumentsoff_rcad(),f_write()andf_mkfs()./FixedflmkfsOonFAT32createsincorrectFSInfo./Fixedflmkdir()onFAT32createsincorrectdirectory./Feb03,'08R0.05aAddedf_truncate()andflutime()./FixedoffbyoneerroratFATsub-typedetermination./Fixedbtrinflread()canbemistruncated. 63/Fixedcachedsectorisnotflushedwhencreateandclose/withoutwrite.//Apr01/08R0.06Addedfputc(),fputs(),fprintf()andfgets()./Improvedperformanceoff_lseek()onmovingtothesame/orfollowingcluster.//Apr()1,'09R0.07MergedTiny-FatFsasabufferconfigurationoption./Addedlongfilenamesupport./Addedmultiplecodepagesupport./Addedre-entrancyfbrmultitaskoperation./Addedautoclustersizeselectiontof_mkfs()./Addedrewindoptiontof_readdir()./Changedresultcodeofcriticalerrors./Renamedstringfunctionstoavoidnamecollision./Apr14,'09R0.07aSeparatedoutOSdependentcodeonreentrantcfg./Addedmultiplesectorsizesupport./Jun21/09R0.07cFixedf_unlink()canreturnFR_OKonerror./Fixedwrongcachecontrolinfllseek()./Addedrelativepathfeature./Addedf_chdir()andf_chdrive()./Addedpropercaseconversiontoextendedchar./Nov03/09R0.07eSeparatedoutconfigurationoptionsfromff.htoffconf.h./FixedCunlink()failstoremoveasub-diron_FS_RPATH./Fixednamematchingerroronthe13charboundary./Addedaconfigurationoption,_LFN_UNICODE./Changedf_readdir()toreturntheSFNwithalwaysupper/caseonnon-LFNcfg./-*/#include"main.h"ModulePrivateDefinitions*/#if_FATFS!=0x007E#errorWrongincludefile(ff.h).#endif#if_FS_REENTRANT#if_USE_LFN=1#errorStaticLFNworkareamustnotbeusedinre-entrantconfiguration.#endif#defineENTER_FF(fs){if(!lock_fs(fs))returnFR_TIMEOUT;)#dcfincLEAVE_FF(fs,res)(unlock_fs(fs,res);returnres;)#else#dcfineENTER_FF(fs)#defineLEAVE_FF(fs,res)returnres#endif#defineABORT(fs,res){fp->flag1=FA_ERROR;LEAVE_FF(fs,res);) 64#ifndefNULL#defineNULL0#cndif/*Namestatusflags♦/#defineNS11#defineNS.LOSS/♦Offsetofnamestatusbyte*/0x01/*Outof8.3format*/#defineNS_LFN#defineNS_LAST#defineNS.BODY#defineNS_EXT#defineNS.DOT0x02/*ForcetocreateLFNentry*/0x04/*Lastsegment*/0x08/*Lowercaseflag(body)*/0x10/*Lowercaseflag(ext)*/0x20/*Dotentry*/PrivateWorkArea*/#if.DRIVES<1II_DRIVES>9#errorNumberofdrivesmustbe1-9.#endifstaticFATFS*FatFs[_DRIVES];/*Pointertothefilesystemobjects(logicaldrives)*/staticWORDFsid;/♦FilesystemmountID*/#if_FS_RPATHstaticBYTEDrive;/*Currentdrive*/#endif#if_USE_LFN==1/*LFNwithstaticLFNworkingbuffer*/staticWCHARLfnBuf[_MAX_LFN+1];#defineNAMEBUF(sp,lp)BYTEsp[12];WCHAR*lp=LfnBuf#defineINITBUF(dj,sp,lp)dj.fn=sp:dj.lfn=Ip#elif_USE_LFN>1/*LFNwithdynamicLFNworkingbuffer*/#defineNAMEBUF(spJp)BYTEsp[12];WCHARlbuf[_MAX_LFN+l],*lp=Ibuf#defineINITBUF(dj,sp,lp)dj.fn=sp;dj.lfn=Ip#else/*NoLFN*/#defineNAMEBUF(spJp)BYTEsp[l2]#defineINITBUF(dj,sp,lp)dj.fn=sp#endifModulePrivateFunctions■*//*♦//*Stringfunctions*//*Copymemorytomemory*/staticvoidmem_cpy(void*dst,constvoid*src,intent){char*d=(char*)dst;constchar*s=(constchar*)src; 65while(ent—)*d++=*s++;/*Fillmemory*/staticvoidmem_set(void*dst,intval,intent){char*d=(char*)dst;while(ent—)*d++=(char)val;)/*Comparememorytomemory*/staticintmem_cmp(constvoid*dst,constvoid*sre,intent){constchar*d=(constchar*)dst,*s=(constchar*)src;intr=0;while(ent-&&(r=*d++-*s++)=0);returnr;/*Checkifchriscontainedinthestring*/staticintchk_chr(constchar*str,intchr){while(*str&&*str!=chr)str++;return*str;/**//*Request/Releasegranttoaccessthevolume*//**/#if_FS_REENTRANTstaticBOOLlock_fs(FATFS*fs/♦Filesystemobject*/)(returnff_req_grant(fs->sobj);staticvoidunlock_fs(FATFS*fs,/*Filesystemobject*/FRESULTres/*Resultcodetobereturned*/){if(res!=FR_NOT_ENABLED&&res!=FR_INVALID_DRIVE&&res!=FR_INVALID_OBJECT&&res!=FR_TIMEOUT){ffLrel_grant(fs->sobj); 66J)#endif/*Changewindowoffset*//*♦/staticFRESULTmove.window(FATFS*fs,/*Filesystemobject*/DWORDsector/*Sectornumbertomakeapperanceinthefs->win||*/)/*Movetozeroonlywritesbackdirtywindow*/{wsect=fs->winsect;if(wsect!=sector){#if!_FS_READONLYif(fs->wflag){DWORDwsect;/*Changedcurrentwindow*//*Writebackdirtywindowifneeded*/if(disk_write(fs-xlrive,fs->win.wsect,1)!=RES_OK)returnFR_DISK_ERR;fs->wflag=0;if(wsect<(fs->fatbase+fs->sects_fat)){/*InFATarea*/BYTEnf;for(nf=fs->n_fats;nf>1;nf—){/♦RefreclthechangetoallFATcopies*/wsect+=fs->sects_fat;disk_write(fs->drive,fs->win,wsect,1);#endifif(sector){if(disk_rcad(fs->drive,fs->win,sector,1)!=RES_OK)returnFR_DISK_ERR;fs->winsect=sector;returnFR_OK:/*♦//*Clean-upcacheddata*/I**1#if!_FS_READONLYstaticFRESULTsync(/*FR_OK:successful,FR_DISK_ERR:failed*/FATFS*fs/*Filesystemobject*/)(FRESULTres;res=move_window(fs,0);if(res==FR_OK){/*UpdateFSInfosectorifneeded♦/ 67if(fs->fs_typc=FS_FAT32&&fs->fsi_flag){fs->winsect=0;mcm_set(fs->win,0,512);ST_WORD(fs->win+BS_55AA,0xAA55);ST_DWORD(fs->win+FSI_LeadSig,0x41615252);ST_DWORD(fs->win+FSI_StrucSig,0x61417272);ST_DWORD(fs->win+FSI_Free_Count,fs->free_clust);ST_DWORD(fs->win+FSI_Nxt_Free,fs->last_clust);disk_write(fs->drive,fs->win,fs->fsi_sector,1);fs->fsi_flag=0;1/*Makesurethatnopendingwriteprocessinthephysicaldrive*/if(disk_ioctl(fs->drive,CTRL.SYNC,(void*)NULL)!=RES-OK)res=FR_DISK_ERR;returnres;#endif/*/*FATaccess-ReadvalueofaFATentry/*DWORDget_fal(FATFS*fs,DWORDcist/*OxFFFFFFFF:Diskerror,l:Inleralerror,Else:Clusterstatus*//*Filesystemobject*//*Cluster#togetthelinkinformation*/UINTwc,be;DWORDfsect;if(cist<2IIcist>=fs->max_clust)/*Rangecheck*/return1;fsect=fs->fatbase;switch(fs->fs_type)(caseFS_FAT12:be=cist;be+=be/2;if(move_window(fs,fsect+(be/SS(fs))))break;wc=fs->win[bc&(SS(fs)-1)];bc++;if(move_window(fs,fsect+(be/SS(fs))))break;wc1=(WORD)fs->win[bc&(SS(fs)-1)]«8;return(cist&1)?(wc»4):(wc&OxFFF);caseFS_FAT16:if(move_window(fs,fsect+(cist/(SS(fs)/2))))break;returnLD_WORD(&fs->win|((WORD)clst*2)&(SS(fs)-1)]);caseFS_FAT32:if(move_window(fs,fsect+(cist/(SS(fs)/4))))break;returnLD_DWORD(&fs->win[((WORD)clst*4)&(SS(fs)-1)])&OxOFFFFFFF;returnOxFFFFFFFF;/*AnerroroccuredatthediskI/Olayer*/ 68/**//*FATaccess-ChangevalueofaFATentry*//*♦/FRESULTput_fat(FATFS*fs,DWORDcist,DWORDval#if!_FS_READONLY/*Filesystemobject*//*Cluster#tobechangedinrangeof2tofs->max_clust-1*//*Newvaluetomarkthecluster*/UINTbc;BYTE*p;DWORDfsect;FRESULTres;if(cist<2IIcist>=fs->max_clust){/*Rangecheck*/res=FR_INT_ERR;}else(fsect=fs->fatbase;switch(fs->fs_type){caseFS_FAT12:be=cist;be+=be/2;res=move_window(fs,fsect+(be/SS(fs)));if(res!=FR_OK)break;p=&fs->win[bc&(SS(fs)-1)];*p=(cist&l)?((*p&OxOF)I((BYTE)val«4)):(BYTE)val;bc++;fs->wflag=1;res=move_window(fs,fsect+(be/SS(fs)));if(res!=FR_OK)break;p=&fs->win[bc&(SS(fs)-1)];*p=(cist&l)?(BYTE)(val»4):((*p&OxFO)I((BYTE)(val»8)&OxOF));break;caseFS_FAT16:res=move_window(fs,fsect+(cist/(SS(fs)/2)));if(res!=FR_OK)break;ST_WORD(&fs->win[((WORD)clst*2)&(SS(fs)-1)],(WORD)val);break;caseFS_FAT32:res=move_window(fs,fsect+(cist/(SS(fs)/4)));if(res!=FR_OK)break;ST_DWORD(&fs->win[((WORD)clst*4)&(SS(fs)-1)Lval);break;default:res=FR_INT_ERR;(fs->wflag=1;returnres;}#cndif/*!_FS_READONLY*/ 69/*♦//*FAThandling-Removeaclusterchain*//**/#if!_FS_READONLYstaticFRESULTremove_chain(FATFS*fs,/*Filesystemobject♦/DWORDcist/*Cluster#toremoveachainfrom*/FRESULTres;DWORDnxt;if(cist<2IIcist>=fs->max_clust){/*Checktherangeofcluster#*/res=FRJNT.ERR;}else(res=FR_OK;while(cist 70if(ncl>=mcl){/*Wraparound*/ncl=2;if(ncl>scl)return0;/*Nofreecuster*/)cs=get_fat(fs,ncl);/*Gettheclusterstatus*/if(cs=0)break;/*Foundafreecluster*/if(cs=OxFFFFFFFFIIcs==1)/*Anerroroccured*/returncs;if(ncl=scl)return0;/*Nofreecuster*/)if(put_fat(fs,ncl,OxOFFFFFFF))/*Markthenewcluster"inuse"*/returnOxFFFFFFFF;if(cist!=0){/*Linkittothepreviousoneifneeded*/if(put_fat(fs,cist,ncl))returnOxFFFFFFFF;)fs->last_clust=ncl:/*UpdateFSINFO*/if(fs->free_clust!=OxFFFFFFFF){fs->free_clust-;fs->fsi_flag=1;returnncl;/*Returnnewclusternumber*/)#endif/*!_FS_READONLY*//**//*Getsector#fromcluster#*/DWORDclust2sect(/*!=0:Sectornumber,0:Failed-invalidcluster#*/FATFS*fs,/*Filesystemobject*/DWORDcist/*Cluster#tobeconverted*/)(cist-=2;if(cist>=(fs->max_clust-2))return0;/*Invalidcluster#*/returncist*fs->csize+fs->database;/*/*Directoryhandling-Seekdirectoryindex/*staticFRESULTdir_seek(DIR*dj,/*Pointertodirectoryobject*/WORDidx/*Directoryindexnumber*/)(DWORDcist;WORDic;dj->index=idx;cist=dj->sclust;if(cist=1IIcist>=dj->fs->max_clust)/*Checkstartclusterrange*/returnFR_1NT_ERR;if(!clsl&&dj->fs->S_type=FS_FAT32)/*Replacecluster#0withrootcluster#ifinFAT32*/cist=dj->fs->dirbase;if(cist=0){/*Statictable*/dj->clust=cist; 71if(idx>=dj->fs->n_rootdir)/*Indexisoutofrange*/returnFR_INT_ERR;dj->sect=dj->fs-xlirbase+idx/(SS(dj->fs)/32);/*Sector#*/}else{/*Dynamictable*/ic=SS(dj->fs)/32*dj->fs->csize;/*Entriespercluster*/while(idx>=ic)(/*Followclusterchain*/cist=get_fat(dj->fs,cist);/*Getnextcluster*/if(cist=OxFFFFFFFF)returnFR_DISK_ERR;/*Diskerror*/if(cist<2IIcist>=dj->fs->max_clust)/*Reachedtoendoftableorinterror*/returnFR_INT_ERR;idx-=ic;)dj->clust=cist;dj->secl=clust2secl(dj->fs,cist)+idx/(SS(dj->fs)/32);/*Sector#*/dj->dir=dj->fs->win+(idx%(SS(dj->fs)/32))*32;/*Ptrlotheentryinthesector*/returnFR_OK;/*Seeksucceeded*//*Directoryhandling-Movedirectoryindexnext*/staticFRESULTdir.next(/*FR_OK:Succeeded,FR_NO_FILE:Endoftable,FR_DENIED:EOTandcouldnotstreach♦/DIR*dj,/*Pointertodirectoryobject♦/BOOLstreach/*FALSE1:Donotstreachtable,TRUE1:Streachtableifneeded*/DWORDcist;WORDi;i=dj->index+1;if(!iII!dj->sect)/*ReportEOTwhenindexhasreached65535*/returnFR_NO_FILE;if(!(i%(SS(dj->fs)/32))){/*Sectorchanged?*/dj->sect++;/*Nextsector*/ 72if(dj->clust==0){/*Statictable*/if(i>=dj->fs->n_rootdir)/*ReportEOTwhenendoftable*/returnFR_NO_FILE;)else(/*Dynamictable*/if(((i/(SS(dj->fs)/32))&(dj->fs->csize-1))==0){/*Clusterchanged?*/cist=get_fat(dj->fs,dj->clust);/*Getnextcluster*/if(cist<=1)returnFR_INT_ERR;if(cist==OxFFFFFFFF)returnFR_DISK_ERR;if(cist>=dj->fs->max_clust){/*Whenitreachedendofdynamictable*/#if!_FS_READONLYBYTEc;if(!streach)returnFR_NO_FILE;cist=create_chain(dj->fs,dj->clust);if(cist==OfreturnFR.DENIED;if(cist==I)returnFR_INT_ERR;/*Whendonotstreach,reportEOT*//*S(reachclusterchain*//*Nofreecluster*/#elseif(cist==OxFFFFFFFF)returnFR_DISK_ERR;/*Clean-upstreachedtable*/if(move_window(dj->fs,0))returnFR_DISK_ERR;/*Flushactivewindow*/mem_set(dj->fs->win,0,SS(dj->fs));/*Clearwindowbuffer*/dj->fs->winsect=clust2sect(dj->fs,cist);/*Clusterstartsector*/for(c=0;c 73i=((dir[LDIR_Ord]&OxBF)-1)*13;/*GetoffsetintheLFNbuffer*/s=0;wc=1;do{uc=LD_WORD(dir+LfnOfs[s]);/*PickanLFNcharacterfromtheentry*/if(wc){/*Lastcharhasnotbeenprocessed*/wc=ff_wtoupper(uc);/*Convertittouppercase*/if(i>=_MAX_LFNIIwc!=ff_wtoupper(lfnbuf[i++]))/*Compareit*/returnFALSE1;/*Notmatched*/}else{if(uc!=OxFFFF)returnFALSE1;/*Checkfiller*/))while(++s<13);/*Repeatuntilallcharsintheentryarechecked*/if((dir|LDIR_Ord]&0x40)&&wc&&lfnbuf[i])/*Lastsegmentmatchedbutdifferentlength*/returnFALSE1;staticBOOLpick_lfn(WCHAR*lfnbuf,BYTE*dirreturnTRUE1;/*ThepartofLFNmatched*//*TRUE1Succeeded,FALSE1:Bufferoverflow*//♦PointertotheUnicode-LFNbuffer♦//*Pointertothedirectoryentry♦/inti,s;WCHARwc,uc;i=((dir[LDIR_Ord|&0x3F)-1)*13;/*OffsetintheLFNbuffer*/s=0;wc=1;do{uc=LD_WORD(dir+LfnOfs[s]);/*PickanLFNcharacterfromtheentry*/if(wc){/*Lastcharhasnotbeenprocessed*/if(i>=_MAX_LFN)returnFALSE1;/*Bufferoverflow?*/lfnbuf[i++]=wc=uc;/*Storeit*/}else{if(uc!=OxFFFF)returnFALSE1;/*Checkfiller♦/))while(++s<13);/*Readallcharacterintheentry*/if(dir[LDIR_Ord]&0x40){/*PutterminatorifitisthelastLFNpart*/if(i>=_MAX_LFN)returnFALSE1;/*Bufferoverflow?*/lfnbuf[if=0;returnTRUE1;#if!_FS_READONLYstaticvoidfit_lfn(/*PointertotheLFNbuffer*//*Pointertothedirectoryentry*//♦LFNorder(1-20)*//♦SFNsum*/constWCHAR*lfnbuf,BYTE*dir,BYTEord,BYTEsum 74inti,s;WCHARwc;dir[LDIR_Chksum]=sum;/*Setchecksum*/dir[LDIR_Attr]=AM_LFN;/*Setattribute.LFNentry*/dir[LDIR_lype]=0;ST_WORD(dir+LDIR_FstClusLO,0);i=(ord-1)*13;/*GetoffsetintheLFNbuffer*/s=wc=0;do{if(wc!=OxFFFF)wc=Ifnbufli-H-];/*Getaneffectivechar*/ST_WORD(dir+LfnOfs[s],wc);/*Putit*/if(!wc)wc=OxFFFF;/*Paddingcharsfollowinglastchar*/)while(++s<13);if(wc==OxFFFFIIJlfnbufli])ord1=0x40;/*BottomLFNpartisthestartofLFNsequence*/dir|LDIR_Ord]=ord;/*SettheLFNorder*/#cndif*/#endif/*Createnumberedname/**/#if_USE_LFNvoidgen_numname(BYTE*dst,/*PointertogenartatedSFN*/constBYTE*src,/*PointertosourceSFNtobem(xiified*/constWCHAR*lfn,/*PointertoLFN*/WORDnum/*Sequensenumber*/charns[8];intij;mem_cpy(dst,sre,11);if(num>5){/*Onmanycollisions,generateahashnumberinsteadofsequencialnumber*/donum=(num»1)+(num«15)+(WORD)*lfn++;while(*lfn);/*itoa*/i=7;do{ns[i-|=(num%10)+'O';num/=10;)while(num);ns[i]=T/*Appendthenumber*/for(j=0;j 75dst[j++]=(i<8)?ns[i++]:)while(j<8);J#cndif/*♦//*CalculatesumofanSFN*//*♦/#if_USE_LFNstaticBYTEsum_sfn(constBYTE*dir/*Ptrtodirectoryentry*/BYTEsum=0;intn=11;dosum=(sum»1)+(sum«7)+*dir++;while(-n);returnsum;)#endif/**//*Directoryhandling-Findanobjectinthedirectory*/staticFRESULTdir.find(DIR*dj/*Pointertothedirectoryobjectlinkedtothefilename*/FRESULTres;BYTEc,*dir;#if_USE_LFNBYTEa,ord,sum;#endifres=dir_seek(dj,0);/*Rewinddirectoryobject*/sum=dir[LDIR_Chksum];if(res!=FR_OK)returnres;#if_USE_LFNord=sum=OxFF;#endifdo{res=move_window(dj->fs,dj->sect);if(res!=FR_OK)break;dir=dj->dir;c=dir|DIR_Name|;if(c==0){-res=FR_NO_FILE;break#if_USE_LFN/*LFNconfiguration*/a=dir[DIR_Attr]&AM_MASK;if(c=0xE5II((a&AM_VOL)&&aord=OxFF;)else{if(a==AM_LFN){if(dj->lfn){if(c&0x40){/*Ptrtothedirectoryentryofcurrentindex*/;}/*Reachedtoendoftable*/!=AM_LFN)){/*Anentrywithoutvaliddata*//*AnLFNentryisfound*//*IsitstartofLFNsequence?♦/c&=OxBF;ord=c;/*LFNstartorder*/dj->lfn_idx=dj->index;)/*CheckvalidityoftheLFNentryandcompareitwithgivenname*/ord=(c==ord&&sum==dir[LDIR_Chksum]&&cmp_lfn(dj->lfn,dir))?ord-1:OxFF; 76))else{/*AnSFNentryisfound*/if(Jord&&sum==sum_sfn(dir))break:/*LFNmatched?*/ord=OxFF;dj->lfn_idx=OxFFFF;/♦ResetLFNsequence*/if(!(dj->fn[NS]&NS.LOSS)&&!mem_cmp(dir,dj->fn,11))break;/*SFNmatched?*/#else/*NonLFNconfiguration*/if(!(dir[DIR_Attr]&AM_VOL)&&!mem_cmp(dir,dj->fn,11))/*Isitavalidentry?*/break;#endifres=dir_next(dj,FALSE1);/*Nextentry*/}while(res=FR_OK);returnres;/**//*Readanobjectfromthedirectory*//*♦/#if_FS_MINIMIZE<=1staticFRESULTdir.read(DIR*dj/*Pointertothedirectoryobjectthatpointingtheentrytoberead*/FRESULTres;BYTEc,*dir;#if_USE_LFNBYTEa,ord=OxFF,sum=OxFF;#endifres=FR_NO_FILE;while(dj->sect){res=move_window(dj->fs,dj->sect);if(res!=FR_OK)break;dir=dj->dir;/*Ptrtothedirectoryentryofcurrentindex♦/c=dir[DIR_Name];if(c=0){res=FR_NO_FILE;break;}/*Reachedtoendoftable*/#if_USE_LFN/*LFNconfiguration*/-a=dir|DIR_Attr|&AM_MASK;if(c=0xE5II(!_FS_RPATH&&c=7)II((a&AM.VOL)&&a!=AM.LFN)){/*Anentrywithoutvaliddata*/ord=OxFF;)else{if(a==AM_LFN){/*AnLFNentryisfound*/if(c&0x40){/*IsitstartofLFNsequence?*/sum=dir[LDIR_Chksum];c&=OxBF;ord=c;dj->lfn_idx=dj->index;)/*CheckLFNvalidityandcaptureit*/ord=(c==ord&&sum==dir[LDIR_Chksum]&&pick_lfn(dj->lfn,dir))?ord-1:OxFF;)else{/*AnSFNentryisfound*/if(ordIIsum!=sum_sfn(dir))/*IsthereavalidLFN?*/dj->lfn_idx=OxFFFF;/*IthasnoLFN.*/break;#else/*NonLFNconfiguration*/if(c!=0xE5&&(_FS_RPATHIIc!='.')&&!(dir[DIR_Attr]&AM_VOL))/*Isitavalidentry?*/break; 77#endifres=dir_next(dj,FALSE1);/*Nextentry*/if(res!=FR_OK)break;if(res!=FR_OK)dj->sect=0;returnres;1#cndif/*Registeranobjecttothedirectory*//*♦/#if!_FS_READONLYstaticFRESULTdir_register(/*FR_OK:Successful,FR_DENIED:NofreeentryortoomanySFNcollision,FR_DISK_ERR:Diskerror*/DIR*dj/*Targetdirectorywithobjectnametobecreated*/FRESULTres;BYTEc,*dir;#if_USE_LFN/*LFNconfiguration*/WORDn,ne,is;BYTEsn[12],*fn,sum;WCHAR*lfn;fn=dj->fn:Ifn=dj->lfn;mem_cpy(sn,fn,12);if(_FS_RPATH&&(sn[NS]&NS_DOT))returnFR_INVAL1D_NAME;/*Cannotcreatedotentiy*/if(sn[NS]&NS_LOSS)(/*WhenLFNisoutof8.3format,generateanumberedname*/fn[NS]=0;dj->lfn=NULL;/*FindonlySFN*/for(n=1;n<1(X);n++){gen_numname(fn,sn,Ifn,n);/*Generateanumberedname*/res=dir_find(dj);/*CheckifthenamecollideswithexistingSFN*/if(res!=^FR_OK)break;)if(n==100)returnFR_DENIED;/*Abortiftoomanycollisions*/if(res!=FR_NO_FILE)returnres;/*Abortiftheresultisotherthan'notcollided'*/fn[NS]=sn[NS];dj->lfn=Ifn;)if(sn[NS]&NS_LFN){/*WhenLFNistobecreated,reservereserveanSFN+LFNentries.*/for(ne=0;lfn[ne];ne++);ne=(ne+25)/13;)else{/*OtherwisereserveonlyanSFNentry.*/ne=1;)/*Reservecontiguousentries*/res=dir_seek(dj,0);if(res!=FR_OK)returnres;n=is=0;do{res=move_window(dj->fs,dj->sect);if(res!=FR_OK)break;c=*dj->dir;/*Checktheentrystatus*/if(c=0xE5IIc==0)(/*Isitablankentry?*/if(n=0)is=dj->index;/*Firstindexofthecontigulusentry*/ 78if(-H-n=ne)break;/*Acontiguousentrythatrequieredcountisfound*/}else{n=0;/*Notablankentry.Restarttosearch*/)res=dir_next(dj,TRUE1);/*Nextentrywithtabicstreach*/)while(res==FR_OK);if(res==FR_OK&&no1){/*InitializeLFNentryifneeded*/res=dir_seek(dj,is);if(res==FR_OK)(sum=sum_sfn(dj->fn);/*SumoftheSFNtiedtotheLFN*/ne—;do{/*StoreLFNentriesinbottomfirst*/res=move_window(dj->fs,dj->sect);if(res!=FR_OK)break;fit_lfn(dj->lfn,dj->dir,(BYTE)ne,sum);dj->fs->wflag=1;res=dir_next(dj,FALSE1);/*Nextentry*/}while(res==FR_OK&&-ne);#else/*NonLFNconfiguration*/res=dir_seek(dj,0);if(res==FR_OK)(do{/*FindablankentryfortheSFN*/res=move_window(dj->fs,dj->sect);if(res!=FR_OK)break;c=*dj->dir;if(c==0xE5IIc=0)break;/*Isitablankentry?*/res=dir_next(dj,TRUE1);/*Nextentrywithtablestreach*/)while(res=FR_OK);}#endifif(res==FR_OK){/*InitializetheSFNentry*/res=move_window(dj->fs,dj->sect);if(res=FR_OK){dir=dj->dir;mem_set(dir,0,32);/*Cleantheentry*/mem_cpy(dir,dj->fn,11);/*PutSFN*/dir[DIR_NTres]=*(dj->fn+NS)&(NS.BODYINS_EXT);/*PutNTflag*/dj->fs->wflag=1;))returnres;)#cndif/*!_FS_READONLY*//*Removeanobjectfromthedirectory*//**/#if!_FS_READONLY&&!_FS_MINIMIZEstaticFRESULTdir.remove(/*FR_OK:Successful,FR_DISK_ERR:Adiskerror*/DIR*dj/*Directoryobjectpointingtheentrytoberemoved*/FRESULTres;#if_USE_LFN/*LFNconfiguration*/-WORDi;i=dj->index;/*SFNindex*/res=dir_seek(dj,(WORD)((dj->lfn_idx=OxFFFF)?i:dj->lfn_idx));/*GototheSFNortopoftheLFNentries*/ 79if(res==FR_OK){do{res=move_window(dj->fs,dj->sect);if(res!=FR_OK)break;*dj-xiir=0xE5;/*Marktheentry"deleted',♦/dj->fs->wflag=1;if(dj->index>=i)break;/*WhenreachedSFN,allentriesoftheobjecthasbeendeleted.*/res=dir_next(dj,FALSE1);/*Nextentry*/)while(res=FR_OK);if(res=FR_NOJFILE)res=FR_INT_ERR;#else/*NonLFNconfiguration*/res=dir_seek(dj,dj->index);if(res==FR_OK){res=move_window(dj->fs,dj->sect);if(res==FR_OK)[*dj-xiir=0xE5;/*Marktheentry"deleted,1*/dj->fs->wflag=1;))#endifreturnres;)#endif/*!_FS_READONLY*//**//*Pickasegmentandcreatetheobjectnameindirectoryform*//**/staticFRESULTcreate_name(DIR*dj,/*Pointertothedirectoryobject*/constXCHAR**path/*Pointertopointertothesegmentinthepathstring*/)(#ifdef_EXCVTstaticconstBYTEcvt[]=_EXCVT; 80#cndif#if_USE_LFN/*LFNconfiguration*/BYTEb,cf;WCHARw,*lfn;inti,ni,si,di;constXCHAR*p;/*CreateLFNinUnicode♦/si=di=0;p=*path;Ifn=dj->lfn;/*Getacharacter*//*Breakonendofsegment*//*Rejecttoolongname*/for(;;){w=p[si++J;if(w<*1IIw=7*IIw==AV)break;if(di>=_MAX_LFN)returnFR_INVALID_NAME;#if!_LFN_UNICODEw&=OxFF;if(IsDBCSl(w)){b=p[si++];if(!IsDBCS2(b))returnFR」NVALID_NAME;w=(w«8)+b;/*IfitisaDBC1stbyte*//*Get2ndbyte*//*RejectinvalidcodeforDBC*/w=fflconvert(w,1);/*ConvertOEMtoUnicode*/if(!w)returnFR_INVALID_NAME;/*Rejectinvalidcode*/#endifif(w<0x80&&chk_chr('V*:o\?l\x7F';w))/*RejectillegalcharsforLFN*/returnFRJNVALID.NAME;lfn[di++]=w;/*StoretheUnicodechar*/)*path=&p[si];/*Rerumpointertothenextsegment*/cf=(w<**)?NS_LAST:0;/*Setlastsegmentflagifendofpath*/#if_FS_RPATHif((di=1&&lfn|di-1]=7)II/*Isthisadotentry?*/(di==2&&lfn[di-1]='.'&&lfn[di-2]=='.')){lfn[di]=0;for(i=0;i<11;i++)dj->fn[i]=(i 81*/si=di;i=8;ni=11;/*Enterextensionsection*/b«=2;continue;if(w>=0x80){/*NonASCIIchar*/#ifdef_EXCVTw=ff_convert(w,0);/*Unicode->OEMcode*/if(w)w=cvt|w-0x80];/*Convertextendedchartoupper(SBCS)*/#elsew=ff_convert(ff_wtoupper(w),0);/*UpperconvertedUnicode->OEMcode*/#endifcf1=NS_LFN;/*ForcecreateLFNentry*/if(_DF1S&&w>=0x100){/*Doublebytechar*/if(i>=ni-1){cfl=NS.LOSSINS_LFN;i=ni;continue;)dj->fn[i-H-]=(BYTE)(w»8);}else{/*Singlebytechar*/if(!wIIchk_chr("+,;[=]",w)){/*ReplaceillegalcharsforSFN*/w='_•;cfl=NS_LOSSINS_LFN;/*Lossyconversion*/}else(if(IsUpper(w)){/*ASCIIlargecapital*/bl=2;}else{if(IsLower(w))(*ASCIIsmallcapital*/b1=1;w-=0x20;dj->fn[i++]=(BYTE)w;if(dj->fn[O]==0xE5)dj->fn[O]=0x05;/*Ifthefirstcharcollideswithdeletedmark,replaceitwith0x05*/if(ni=8)b«=2;if((b&OxOC)==OxOCII(b&0x03)=0x03)/*CreateLFNentrywhentherearecompositecapitals*/cfl=NS.LFN;if(!(cf&NS_LFN)){/*WhenLFNisin8.3formatwithoutextendedchar,NTflagsarecreated*/if((b&0x03)=0x01)cfl=NS_EXT;/*NTflag(Extensionhasonlysmallcapital)*/if((b&OxOC)==0x04)cfl=NSlBODY;/*NTflag(Filenamehasonlysmallcapital)*/dj->fn[NS]=cf;/*SFNiscreated*/returnFR_OK;#else/*Non-LFNconfiguration*/BYTEb,c,d,*sfn;intni,si,i;constchar*p;/*Createfilenameindirectoryform*/sfn=dj->fn;mem_set(sfn,1\11);si=i=b=0;ni=8;p=*path;#if_FS_RPATHif(p[sij==*.*){/*Isthisadotentry?*/for(;;)1c=p[si++];if(c!=IIsi>=3)break;sfn[i-H-|=c;)if(c!=7*&&c!=N&&c>'')returnFR_INVALID_NAME; 82*path=/*Rerumpointertothenextsegment*/sfn[NS]=(c<=")?NS.LASTINS_DOT:NS_DOT;/*Setlastsegmentflagifendofpath*/returnFR_OK;)#endiffor(;;){c=p[si++];if(c<="IIc==/IIc==\V)break;/*Breakonendofsegment*/if(c==VIIi>=ni){if(ni!=8llc!='.')returnFRJNVALID.NAME;i=8;ni=11;b«=2;continue;Iif(c>=0x80){/*Extendedchar*/#ifdef_EXCVTc=cvt[c-0x801;/*Convertextendchar(SBCS)*/#elseb1=3;/*EliminateNTflagifextcharisexist*/#if!_DF1S/*ASCIIonlycfg*/returnFR_INVALID_NAME;#endif#endif)if(IsDBCS1(c)){/*DBC1stbyte?*/d=p[si++];/♦Get2ndbyte*/if(!IsDBCS2(d)lli>=ni-1)/*RejectinvalidDBC*/returnFRJNVALID_NAME;sfn[i++]=c;sfn[i++]=d;}else{/*Singlebytecode*/if(chk_chr(HV*+,[=]l\x7F,;c))/*RejectillegalchrsforSFN*/returnFRJNVALID.NAME;if(IsUpper(c)){/*ASCIIlargecapital?*/b1=2;}else(if(IsLower(c)){/*ASCIIsmallcapital?*/bl=l;c-=0x20;sfn[i++]=c;))*path=&p[si];/*Rerumpointertothenextsegment*/c=(c<='*)?NS_LAST:0;/♦Setlastsegmentflagifendofpath*/ 83if(!i)returnFR_INVALID_NAME;/*Rejectnullstring*/if(sfn[O]=OxE5)sfn[O|=0x05;/*Whenfirstcharcollideswith0xE5,replaceitwith0x05*/if(ni==8)b«=2;if((b&0x03)=0x01)c1=NS_EXT;/*NTflag(Extensionhasonlysmallcapital)*/if((b&OxOC)==0x04)c1=NS_BODY;/*NTflag(Filenamehasonlysmallcapital)*/sfn[NS]=c;/*StoreNTflag,Filenameiscreated*/returnFR_OK;#endif#if_FS_MINIMIZE<=1staticvoidget_fileinfb(DIR*dj,FILINFO*fno)(inti;BYTEc,nt,*dir;char*p;/*Noreturncode*//*Pointertothedirectoryobject*//*Pointertothefileinformationtobefilled*/p=fno->fname;if(dj->sect)(dir=dj->dir;nt=dir|DIR_NTresl;/*NTflag*/for(i=0;i<8;i++){/*Copynamebody*/c=dir[i];if(c=='')break;if(c=0x05)c=0xE5;if(_USE_LFN&&(nt&NS_BODY)&&IsUpper(c))c+=0x20;*p++=c;)if(dir[8]!=''){/*Copynameextension*/*p++=for(i=8;i<11;i++){c=dir[i];if(c='*)break;ifLUSE-LFN&&(nt&NS.EXT)&&IsUpper(c))c+=0x20;*p-H-=C;fno->fattrib=dir|DIR_Attr];/*Attribute*/fno->fsize=LD_DWORD(dir+DIR-FileSize);/*Size*/fno->fdate=LD_WORD(dir+DIR_WrtDate);/*Date*/fno->ftimc=LD_WORD(dir+DIR_WrtTime);/*Time*/)*p=0;#if_USE_LFNif(fno->lfname){XCHAR*tp=fno->lfname;WCHARw,*lfn; 84i=0;if(dj->sect&&dj->lfn_idx!=OxFFFF)(/*GetLFNifavailable*/Ifn=dj->lfn;while((w=*lfn++)!=0){/*GetanLFNchar*/#if!_LFN_UNICODEw=ff_convert(w,0);/*Unicode->OEMconversion*/if(!w){i=0;break:}/*Couldnotconvert,noLFN*/if(_DF1S&&w>=0x100)/*Put1stbyteifitisaDBC*/tp[i++]=(XCHAR)(w»8);#endifif(i>=fno->lfsize-1){i=0;break;}/*Bufferoverrun,noLFN*/tp[i++]=(XCHAR)w;1)tp[i]=0;/*Terminator*/)#endif}#cndif/*_FS_MINIMIZE<=1*//*/*Followafilepath/*staticFRESULTfollow_path(/*FR_OK(0):successful,!=0:errorcode*/DIR*dj,/*Directoryobjecttoreturnlastdirectoryandfoundobject*/constXCHAR*path/*Full-pathstringtofindafileordirectory*/)(FRESULTres;BYTE*dir,last;while(!_USE_LFN&&*path==#if_FS_RPATHif7*path==TII*path=AV){/*path++;dj->sclust=0;)else{dj->sclust=dj->fs->cdir;)#elseif(*path==,/,ll*path=AV)path++;dj->sclust=0;#endifif((UINT)*path 85Lif(last)break;/*Lastsegmentmatch.Functioncompleted.*/dir=dj-xiir;/*Thereisnextsegment.Followthesubdirectory*/if(!(dir[DIR_Attr]&AM_DIR)){/*Cannotfollowbecauseitisafile*/res=FR_NO_PATH;break;)dj->sclust=((DWORD)LD_WORD(dir+DIR_FstClusHI)«16)ILD_WORD(dir+DIR_FstClusLO);returnres;/*LoadbootrecordandcheckifitisanFATbootrecord*/staticBYTEcheck_fs(/♦0:TheFATbootrecord,kValidbootrecordbutnotanFAX2:Notabootrecord,3:Error*/FATFS*fs,/*Filesystemobject*/DWORDsect/*Sector#(Iba)tocheckifitisanFATbootrecordornot*/)(if(disk_read(fs->drive,fs->win,sect,1)!=RES_OK)/*Loadbootrecord*/return3;if(LD_WORD(&fs->win(BS_55AA])!=0xAA55)/*Checkrecordsignature(alwaysplacedatoffset510evenifthesectorsizeis>512)*/return2;if((LD_DWORD(&fs->win|BS_FilSyslype])&OxFFFFFF)=0x544146)/*Check"FATtstring*/return0;if((LD_DWORD(&fs->win[BS_FilSysType32])&OxFFFFFF)=0x544146)return0;return1;*//*MakesurethatthefilesystemisvalidFRESULTchk_mounted(/*FR_OK(0):successful,!=0:anyerroroccured*/constXCHAR**path,/*Pointertopointertothepathname(drivenumber)*/FATFS**rfs,/*Pointertopointertothefoundfilesystemobject*/BYTEchk_wp/*!=0:Checkmediawriteprotectionforwriteaccess*/)(BYTEfmt,*tbl;UINTvol;DSTATUSstat;DWORDbsect,fsize,tsect,mclst;constXCHAR*p=*path;FATFS*fs; 86/*Getlogicaldrivenumberfromthepathname*/vol=p[0]-'O';/*Isthereadrivenumber?*/if(vol<=9&&p[I]==,:*){*Foundadrivenumber,getandstripit*/p+=2;*path=p;/*Returnpointertothepathname*/)else{/*Nodrivenumberisgiven*/#if_FS_RPATHvol=Drive;/*Usecurrentdrive*/#elsevol=0;/*Usedrive0*/#endif/*Checkifthelogicaldriveisvalidornot*/if(vol>=_DRIVES)/*Isthedrivenumbervalid?*/returnFR_INVALID_DRIVE;*rfs=fs=FatFs|vol];/*Returenpointertothecorrespondingfilesystemobject*/if(!fs)returnFR_NOT_ENABLED;/*Isthefilesystemobjectavailable?*/ENTER.FF(fs);/*Lockfilesystem*/if(fs->fs_type){/*Ifthelogicaldrivehasbeenmounted*/stat=disk_status(fs-xirive);if(!(stat&S1A_NOINIT)){/♦andthephysicaldriveiskeptinitialized(hasnotbeenchanged),♦/#if!_FS_READONLYif(chk_wp&&(stat&STA_PROTECT))/*Checkwriteprotectionifneeded*/returnFR_WRITE_PROTECTED;#endifreturnFR_OK;/*Thefilesystemobjectisvalid*//*Thelogicaldrivemustbemounted.Followingcodeattemptstomountthevolume*/fs->fs_type=0;fs-xirive=(BYTE)LD2PD(vol);stat=disk_initialize(fs->drive);if(stat&STA_NOINIT)returnFR_NOT_READY;/*Clearthefilesystemobject*//*Bindthelogicaldriveandaphysicaldrive*//*InitializelowleveldiskI/Olayer*//*Checkifthedriveisready*/#if_MAX_SS!=512/*Getdisksectorsizeifneeded*/if(disk_ioctl(fs->drive,GET_SECTOR_SIZE,&SS(fs))!=RES_OKIISS(fs)>_MAX_SS)returnFR_NO_FILESYSTEM;#endif#if!_FS_READONLYif(chk_wp&&(stat&STA_PROTECT))/*Checkdiskwriteprotectionifneeded*/returnFR_WRITE_PROTECTED;#endif/*SearchFATpartitiononthedrive*/fmt=check_fs(fs,bsect=0);/*ChecksectorOasanSFDformat*/if(fmt=1){/*NotanFATbootrecord,itmaybepatitioned*//*Checkapartitionlistedintopofthepartitiontable*/tbl=&fs->win|MBR_7able+LD2PT(vol)*16);/*Partitiontable*/if(tbl[4]){/*Isthepartitionexisting?*/bsect=LD_DWORD(&tbl[8]);/*PartitionoffsetinLBA*/fmt=check_fs(fs,bsect);/*Checkthepartition*/))if(fmt=3)returnFR_DISK_ERR;if(fmtIILD_WORD(fs->win+BPB_BytsPerSec)!=SS(fs))/♦NovalidFATpatitionisfound*/returnFR_NO_FILESYSTEM;/*Initializethefilesystemobject*//*NumberofsectorsperFAT*/fsize=LD_WORD(fs->win+BPB_FATSzl6);if(!fsize)fsize=LD_DWORD(fs->win+BPB_FATSz32);fs->sects_fat=fsize; 87fs->n_fats=fs->win[BPB_NumFAIs];/*NumberofFATcopies*/fsize*=fs->n_fats;/*(NumberofsectorsinFATarea)*/fs->fatbase=bsect+LD_WORD(fs->win+BPB_RsvdSecCnt);/*FATstartsector(Iba)*/fs->csize=fs->win[BPB_SecPerClus];/*Numberofsectorspercluster*/fs->n_rootdir=LD_WORD(fs->win+BPB_RootEntCnt);/*Nmuberofrootdirectoryentries♦/tsect=LD_WORD(fs->win+BPB_lbtSec16);/*Numberofsectorsonthevolume*/if(!tsect)tsect=LD_DWORD(fs->win+BPB_lbtSec32);fs->max_clust=mclst=(tsect/*Lastcluster#+1(Numberofclusters+2)-LD_WORD(fs->win+BPB_RsvdSecCnt)-fsize-fs->n_rootdir/(SS(fs)/32))/fs->csize+2;fmt=FS_FAT12;/*DeterminetheFATsubtypeif(mclst>=0xFF7)fmt=FS.FATl6;/*Numberofclusters>=0xFF5*/if(mclst>=0xFFF7)fmt=FS_FAT32;/*Numberofclusters>=0xFFF5*/if(fmt=FS_FAT32)fs->dirbase=LD_DWORD(fs->win+BPB_RootClus);/*Rootdirectorystartcluster*/elsefs->dirbase=fs->fatbase+fsize;/♦Rootdirectorystartsector(Iba)*/fs->database=fs->fatbase+fsize+fs->n_rootdir/(SS(fs)/32);/*Datastartsector(Iba)*/#if!_FS_READONLY/♦Initializeallocationinformation*/fs->free_clust=OxFFFFFFFF;fs->wflag=0;/*Getfsinfoifneeded*/if(fmt=FS_FAT32){fs->fsi_flag=0;fs->fsi_sector=bsect+LD_WORD(fs->win+BPB_FSInfo);if(disk_read(fs->drive,fs->win,fs->fsi_sector,1)==RES_OK&&LD_WORD(fs->win+BS_55AA)==0xAA55&&LD_DWORD(fs->win+FSI_LeadSig)==0x41615252&&LD_DWORD(fs->win+FSI_StrucSig)=0x61417272)(fs->last_clust=LD_DWORD(fs->win+FSI_Nxt_Frec);fs->free_clust=LD_DWORD(fs->win+FSI_Free_Count);))#endiffs->fs_type=fmt;/*FATsub-type*/fs->winsect=0;/*Invalidatesectorcache*/#if_FS_RPATHfs->cdir=0;/*Currentdirectory(rootdir)*/#endiffs->id=++Fsid;/*FilesystemmountID*/returnFR_OK;/**//*Checkifthefile/dirobjectisvalidornot*/staticFRESULTvalidate(/*FR_OK(0):Theobjectisvalid,!=0:Invalid*/FATFS*fs,/*Pointertothefilesystemobject*/WORDid/*Memberidofthetargetobjecttobechecked*/ 88if(!fsII!fs->fs_typeIIfs->id!=id)returnFrIiNVALID.OBJECT;ENTER_FF(fs);/♦Lockfilesystem*/if(disk_status(fs->drive)&STA.NOINIT)returnFR_NOT_READY;returnFR_OK;PublicFunctions/**//*Mount/UnmountaLocicalDriveFRESULTf_mount(BYTEvol,FATFS*fs/*/*Logicaldrivenumbertobemounted/unmounted*//♦Pointertonewfilesystemobject(NULLforunmount)*/FATFS*rfs;if(vol>=_DRIVES)/*Checkifthedrivenumberisvalid*/returnFR_INVALID_DRIVE;rfs=FatFs[vol];/*Getcurrentfsobject*/if(rfs){#if_FS_REENTRANT/*Discardsyncobjectofthecurrentvolume*/if(!ff_del_syncobj(rfs->sobj))returnFR_INT_ERR;#endifrfs->fs_type=0;/*Clearoldfsobject*/)fs->fs_type=0;/*Clearnewfsobject*/#if_FS_REENTRANT/*Createsyncobjectforthenewvolume*/if(!ff_cre_syncobj(vol,&fs->sobj))returnFR_INT_ERR;#endifIFatFs[vol]=fs;/*Registernewfsobject*/returnFR_OK;/*/*OpenorCreateaFile/**/DWORDget_fattime(void){;)FRESULTCopen(FIL*fp,/*Pointertotheblankfileobject*/ 89constXCHAR*path,/*Pointertothefilename*/BYTEmode/*Accessmodeandfileopenmodeflags*/FRESULTres;DIRdj;NAMEBUF(sfn,Ifn);BYTE*dir;fp->fs=NULL;/*Clearfileobject*/#if!_FS_READONLYmode&=(FA_READIFA.WRITEIFA_CREATE_ALWAYSIFA_OPEN_ALWAYSIFA.CREATE.NEW);res=chk_mounted(&path,&dj.fs,(BYTE)(modc&(FA.WRITEIFA_CREATE_ALWAYSIFA_OPEN_ALWAYSIFA_CREATE_NEW)));#clsemode&=FA_READ;res=chk_mounted(&path,&dj.fs,0);#endifif(res!=FR_OK)LEAVE_FF(dj.fs,res);INITBUF(dj,sfn,Ifn);res=follow_path(&dj,path);/*Followthefilepath*/#if!_FS_READONLY/♦CreateorOpenafile*/if(mode&(FA_CREATE_ALWAYSIFA_OPEN_ALWAYSIFA_CREATE_NEW)){DWORDps,cl;if(res!=FR_OK){/*Nofile,createnew*/if(res=FR_NO_FILE)/*Thereisnofiletoopen,createanewentry*/res=dir_register(&dj);if(res!=FR_OK)LEAVE_FF(dj.fs,res);mode1=FA_CREATE_ALWAYS;dir=dj.dir;/*Createdentry(SFNentry)*/)else{/*Anyobjectisalreadyexisting♦/if(mode&FA_CREATE_NEW)/*Cannotcreatenew*/LEAVE_FF(dj.fs,FR_EXIST);dir=dj.dir;if(!dirll(dir[DIR_Attr]&(AM_RDOIAM_DIR)))/*Cannotoverwriteit(R/OorDIR)*/LEAVE_FF(dj.fs,FR_DEN1ED);if(mode&FA_CREATE_ALWAYS)(/*Resizeittozeroonoverwritemode*/cl=((DWORD)LD_WORD(dir+DlR_FstClusHI)«16)1LD_WORD(dir+DIR_FstClusLO):/*Getstartcluster*/ST_WORD(dir+DIR_FstClusHI,0);/*cluster=0*/ST_WORD(dir+DIR_FstClusLO,0);ST_DWORD(dir+DIR_FileSize,0);/*size=0*/dj.fs->wflag=1;ps=dj.fs->winsect;/*Removetheclusterchain*/res=rcmove_chain(dj.fs,cl);if(res)LEAVE_FF(dj.fs,res);dj.fs->last_clust=cl-1;/*Reusetheclusterhole*/)res=move_window(dj.fs,ps);if(res!=FR_OK)LEAVE_FF(dj.fs,res);) 90if(mode&FA_CREATE_ALWAYS)(dir[DIR_Attr]=0;ps=get_fattime();ST_DWORD(dir+DIR_CrtTime,ps);dj.fs->wflag=1;mode1=FA_WRITTEN;)}/br=0;/*Initializebytesread*/Openanexistingfile*/else{#endif/*!_FS_READONLY*//*Resetattribute*//*Createdtime*//♦Setfilechangedflag*/if(res!=FR_OK)LEAVE_FF(dj.fs,res);/*Followfailed*/dir=dj.dir;if(!dirll(dir[D!R_Attr]&AM.D1R))/*Itisadirectory*/LEAVE_FF(dj.fs,FR_NO_FILE);#if!_FS_READONLYif((mode&FA.WRITE)&&(dir|DIR_Attr|&AM_RDO))/*R/Oviolation*/LEAVE_FF(dj.fs,FR.DENIED);)fp->dir_sect=dj.fs->winsect;/*Pointertothedirectoryentry*/fp->dir_ptr=dj.dir;#cndiffp->flag=mode;/*Fileaccessmode*/fp->org_clust=/*Filestartcluster*/((DWORD)LD_WORD(dir+DIR_FstClusHI)«16)ILD_WORD(dir+DIR_FstClusLO);fp->fsize=LD_DWORD(dir+DIR_FileSize);/*Filesize*/fp->fptr=0;fp->csect=255;/*Filepointer*/fp->dsect=0;fp->fs=dj.fs;fp->id=dj.fs->id;/*Ownerfilesystemobjectofthefile*/LEAVE_FF(dj.fs,FR_OK);/*ReadFile*//**/FRESULTCrcad(FIL*fp,/♦Pointertothefileobject*/void*buff,/*Pointertodatabuffer*/UINTbtr,/♦Numberofbytestoread♦/UINT*br/♦Pointertonumberofbytesread*/){FRESULTres;DWORDcist,sect,remain;UINTrent,cc;res=validate(fp->fs,fp->id);if(res!=FR_OK)LEAVE_FF(fp->fs,res);if(fp->flag&FA_ERROR)LEAVE_FF(fp->fs,FR_INT_ERR):if(!(fp->flag&FA.READ))LEAVE_FF(fp->fs,FR.DENIED);remain=fp->fsize-fp->fptr;if(btr>remain)btr=(UINT)remain;/*Checkvalidityoftheobject*//*Checkabortflag*//*Checkaccessmode*//*Truncatebtrbyremainingbytes*/BYTE*rbuff=buff; 91for(;btr;/*Repeatuntilalldatatransferred*/rbuff+=rent,fp->fptr+=rent,*br+=rent,btr-=rent){if((fp->fptr%SS(fp->fs))==0){/*Onthesectorboundary?*/if(fp->csect>=fp->fs->csize)(/*Ontheclusterboundary?*/cist=(fp->fptr=0)?/*Onthetopofthefile?*/fp->org_clust:get_fat(fp->fs,fp->curr_clust);if(cist<=1)ABORT(fp->fs,FR_INT_ERR);if(cist=OxFFFFFFFF)ABORT(fp->fs,FR_DISK_ERR);fp->curr_clust=cist;/*Updatecurrentcluster*/fp->csect=0;/*Resetsectoroffsetinthecluster*/)sect=clust2sect(fp->fs,fp->curr_clust);/*Getcurrentsector*/if(!sect)ABORT(fp->fs,FR_INf.ERR);sect+=fp->csect;cc=btr/SS(fp->fs);/*Whenremainingbytes>=sectorsize,*/if(cc){/*Readmaximumcontiguoussectorsdirectly*/if(fp->csect+cc>fp->fs->csize)/*Clipatclusterboundary*/cc=fp->fs->csize-fp->csect;if(disk_read(fp->fs->drivc,rbuff,sect,(BYTE)cc)!=RES_OK)ABORT(fp->fs,FR_DISK_ERR);#if!_FS_READONLY&&_FS_MINIMIZE<=2#if_FS_TINY/*Replaceoneofthereadif(fp->fs->wflag&&fp->fs->winsect-sect 92LEAVE_FF(fp->fs,FR_OK);#if!_FS_READONLY/*♦//*WriteFileFRESULTf_write(FIL*fp,/*Pointertothefileobject*/constvoid*buff,/*Pointertothedatatobewritten*/UINTbtw,/*Numberofbytestowrite*/UINT*bw/*Pointertonumberofbyteswritten*/)(FRESULTres;DWORDcist,sect:UINTwent,cc;constBYTE*wbuff=buff;*bw=0;/*Initializebyteswritten*/res=validate(fp->fs,fp->id);if(res!=FR_OK)LEAVE_FF(fp->fs,res);if(fp->flag&FA__ERROR)LEAVE_FF(fp->fs,FR_INT_ERR);if(!(fp->flag&FA_WRITE)7LEAVE_FF(fp->fs,FR_DENIED);if(fp->fsize+btw 93#cndifsect=clust2sect(fp->fs,fp->curr_clust);/*Getcurrentsector*/if(!sect)ABORT(fp->fs,FR_INT_ERR);sect+=fp->csect;cc=btw/SS(fp->fs);/*Whenremainingbytes>=sectorsize,*/if(cc){/*Writemaximumcontiguoussectorsdirectly,*/if(fp->csect+cc>fp->fs->csize)/*Clipatclusterboundary*/cc=fp->fs->csize-fp->csect;if(disk_write(fp->fs->drive,wbuff,sect,(BYTE)cc)!=RES-OK)ABORT(fp->fs,FR_DISK_ERR);#if_FS_TINY*/if(fp->fs->winsect-sect 94FRESULTf_sync(FIL*fp/♦Pointertothefileobject*/FRESULTres;DWORDtim;BYTE*dir;res=validate(fp->fs,fp->id);/*Checkvalidityoftheobject*/if(res==FR.OK){if(fp->flag&FA_WRITTEN){/*Hasthefilebeenwritten?*/#if!_FS_TINY/*Write-backdirtybuffer*/if(fp->flag&FA_DIRTY){if(disk_write(fp->fs-xirive,fp->buf,fp->dsect,1)!=RES_OK)LEAVE_FF(fp->fs,FR_DISK_ERR);fp->flag&=工A_DIRTY;)#endif/*Updatethedirectoryentry*/res=movewindow(fp->fs,fp->dirsect);if(res=FR_OK){dir=fp->dir_ptr;dir[DIR_Attr]1=AM_ARC;/*Setarchivebit*/ST_DWORD(dir+DIR_FileSize,fp->fsize);/*Updatefilesize*/ST_WORD(dir+DIR_FstClusLO,fp-x)rg_clust);/*Updatestartcluster*/ST二WORD(dir+DIR二FstClusHI,fp・x)rg_ckist»16);tim=get_fattime();/*Updatedtime*/ST_DWORD(dir+DIR_WrtTime,lim);fp->flag&=-FA_WRITTEN;fp->fs->wflag=1;res=sync(fp->fs);)LEAVE_FF(fp->fs,res);#endif/*!_FS_READONLY*//**//*CloseFile*//**/FRESULTLclose(FIL*fp/*Pointertothefileobjecttobeclosed*/)(FRESULTres;#if_FS_READONLY 95res=validate(fp->fs,fp->id);if(res==FR_OK)fp->fs=NULL;LEAVE_FF(fi)->fs,res);#elseres=f_sync(fp);if(res==FR_OK)fp->fs=NULL;returnres;#endif)/**//*ChangeCurrentDrive/Directory*//**/#if_FS_RPATHFRESULTCchdrive(BYTEdrv/*Drivenumber*/)(if(drv>=.DRIVES)returnFR」NVALID_DRIVE:Drive=drv;returnFR_OK;FRESULTf_chdir(/*Pointertothedirectorypath*/constXCHAR*pathFRESULTres;DIRdj;NAMEBUF(sfn,Ifn);BYTE*dir;res=chk_mounted(&path,&dj.fs,0);if(res==FR_OK){/*Followthefilepath♦//*Followcompleted*//*Pointertotheentry*//*Noentry(rootdir)*/INITBUF(dj,sfn,Ifn);res=followpath(&dj.path);if(res=FR10K){dir=dj.dir;if(!dir){dj.fs->cdir=0;}else(if(dirlDlR_Attr]&AM.DIR)/*Reachedtothedir*/dj.fs->cdir=((DWORD)LD_WORD(dir+DIR_FstClusHI)«16)ILD_WORD(dir+DIR_FstClusLO);res=FR_NO_PATH;/*Couldnotreachthedir(itisafile)*/))if(res==FR_NO_FILE)res=FR_NO_PATH;)LEAVE_FF(dj.fs,res);#cndif#if_FS_MINIMIZE<=2 96/**//*SeekFileR/WPointer*//*♦/FRESULTf_lseek(FIL*fp,/*Pointertothefileobject♦/DWORDofs/*Filepointerfromtopoffile*/FRESULTres;DWORDcist,bcs,nsect,ifptr;res=validate(fp->fs,fp->id);/*Checkvalidityoftheobject*/if(res!=FR_OK)LEAVE_FF(fp->fs,res);if(fp->flag&FA_ERROR)/♦Checkabortflag*/LEAVE_FF(fp->fs,FR_INT_ERR);if(ofs>fp->fsize/*Inread-onlymode,clipoffsetwiththefilesize♦/#if!_FS_READONLY&&!(fp->flag&FA_WRITE)#endif)ofs=fp->fsize;ifptr=fp->fptr;fp->fptr=nsect=0;fp->csect=255;if(ofs>0){bcs=(DWORD)fp->fs->csize*SS(fp->fs);/*Clustersize(byte)*/if(ifptr>0&&(ofs-1)/bcs>=(ifptr-1)/bcs){/*Whenseektosameorfollowingcluster,*/fp->fptr=(ifptr-I)&-(bcs-1);/*startfromthecurrentcluster*/ofs-=fp->fptr;cist=fp->curr_clust;(else{/*Whenseektobackcluster,*/cist=fp->org_clust;/*startfromthefirstcluster*/#if!_FS_READONLYif(cist==0){/*Ifnoclusterchain,createanewchain*/cist=create_chain(fp->fs,0);if(cist==l)ABORT(fp->fs,FR_INT_ERR);if(cist=OxFFFFFFFF)ABORT(fp->fs,FR_DISK_ERR);fp->org_clust=cist;)#endiffp->cuiT_clust=cist;)if(cist!=0){while(ofs>bcs){/*Clusterfollowingloop*/#if!_FS_READONLYif(fp->flag&FA_WRITE){/*Checkifinwritemodeornot*/cist=create_chain(fp->fs,cist);/*Forcestreachedifinwritemode*/if(cist==0){/*Whendiskgetsfull,clipfilesize*/ofs=bcs;break;))else#endifcist=get_fat(fp->fs,cist);/*Followclusterchainifnotinwritemode*/if(cist==OxFFFFFFFF)ABORT(fp->fs,FR_DISK_ERR);if(cist<=1IIcist>=fp->fs->max_clust)ABORT(fp->fs,FR_INT_ERR);fp->curr_clust=cist;fp->fptr+=bcs;ofs-=bcs;)fp->fptr+=ofs;fp->csect=(BYTE)(ofs/SS(fp->fs));/*Sectoroffsetinthecluster*/if(ofs%SS(fp->fs)){ 97nsect=clust2sect(fp->fs,cist);/*Currentsector*/if(Jnsect)ABORT(fp->fs,FR_INT_ERR);nsect+=fp->csect;fp->csect++;if(fp->fplr%SS(fp->fs)&&nsect!=fp-xlsect){#if!_FS_TINY#if!_FS_READONLYif(fp->flag&FA_DIRTY){/*Write-backdirtybufferifneeded*/if(disk_write(fp->fs->drive,fp->buf,fp-xlsect,1)!=RES_OK)ABORT(fp->fs,FR_DISK_ERR);fp->flag&=-FA_DIRTY;}#endifif(disk_read(fp->fs-xlrivc,fp->buf,nsect,1)!=RES_OK)ABORT(fp->fs,FR_DISK_ERR);#endiffp->dsect=nsect;}#if!_FS_READONLYif(fp->fptr>fp->fsize){/*Setchangedflagifthefilesizeisextended*/fp->fsize=fp->fptr;fp->flag1=FA_WRITTEN;}#endifLEAVE_FF(fp->fs,res);#if_FS_MINIMIZE<=1/*/*CreateaDirectroyObject/*FRESULTf_opendir(DIR*dj,/*Pointertodirectoryobjecttocreate*/constXCHAR*path/*Pointertothedirectorypath*/FRESULTres;NAMEBUF(sfn,Ifn);BYTE*dir;res=chk_mounted(&path.&dj->fs,0);if(res==FR_OK){INITBUF((*dj),sfn,Ifn);res=follow_path(dj,path);/*Followthepathtothedirectory*/if(res=FR_OK){/*Followcompleted*/dir=dj-xiir; 98if(dir){/*Itisnottherootdir*/if(dir[DIR_Attr]&AM_DIR){/*Theobjectisadirectory*/dj->sclust=((DWORD)LD_WORD(dir+DIR_FstClusHI)«16)1LD_WORD(dir+DIR_FstClusLO);)else{/*Theobjectisnotadirectory*/res=FR_NO_PATH;if(res==FR_OK){dj->id=dj->fs->id;res=dir_seek(dj,0);/*Rewinddir*/if(res==FR_NO_FILE)res=FR_NO_PATH;LEAVE_FF(dj->fs,res);/*/*ReadDirectoryEntryinSequenseFRESULTflreaddir(DIR*dj,F1LINFO*fno/*/*Pointertotheopendirectoryobject*//*Pointertofileinformationtorelum*/FRESULTres;NAMEBUF(sfn,Ifn);res=validate(dj->fs,dj->id);if(res==FR_OK){INITBUF((*dj),sfn,Ifn);if(!fno){res=dir_seek(dj,0);}else{/*Checkvalidityoftheobject*/res=dir_read(dj);if(res==FR_NO_FILE){dj->sect=0;res=FR_OK;if(res=FR_OK){get_fileinfo(dj,fno);/*Avalidentryisfound*//*Gettheobjectinformation*/res=dir_next(dj,FALSE1);/*Incrementindexfornext♦/if(res=FR_NO_FILE){dj->sect=0;res=FR_OK;LEAVE_FF(dj->fs,res);#if_FS_MINIMIZE==0/**/ 99/*GetFileStatus*//**/FRESULTflstat(constXCHAR*path,/*Pointertothefilepath*/FILINFO*fno/*Pointertofileinformationtoreturn*/)(FRESULTres;DIRdj;NAMEBUF(sfn,Ifn);res=chk_mounted(&path,&dj.fs,0);if(res==^R_OK)[INITBUF(dj,sfn,Ifn);res=follow_path(&dj,path);/*Followthefilepath*/if(res==FR_OK)|/*Follwocompleted*/if(dj.dir)/*Foundanobject*/get_fileinfb(&dj,fno);else/*Itisrootdir*/res=FR_INVALID_NAME;LEAVE_FF(dj.fs,res);#if!_FS_READONLY/**I/*GetNumberofFreeClusters*//**IFRESULTf_getfree(constXCHAR*path,/*Pointertothelogicaldrivenumber(rootdir)*/DWORD*nclst,/*Pointertothevariabletoreturnnumberoffreeclusters*/FATFS**fatfs/*Pointertopointertocorrespondingfilesystemobjecttoreturn*/)(FRESULTres;DWORDn,cist,sect,stat;UINTi;BYTEfat,*p;/♦Getdrivenumber*/res=chk_mounted(&path,fatfs,0);if(res!=FR_OK)LEAVE_FF(*fatfs,res);/*Ifnumberoffreeclusterisvalid,returnitwithoutclusterscan.*/if((*fatfs)->free_clust<=(*fatfs)->max_clust-2){*nclst=(*fatfs)->free_clust;LEAVE_FF(*fatfs,FR_OK);)/*Getnumberoffreeclusters*/fat=(*fatfs)->fs_type;n=0;if(fat=FS_FAT⑵{cist=2;do{stat=get_fat(*fatfs,cist);if(stat==OxFFFFFFFF)LEAVE_FF(*fatfs,FR_DISK_ERR);if(stat==1)LEAVE_FF(*fatfs,FR_INT_ERR);if(stat==0)n++;}while(++clst<(*fatfs)->max_clust); 100)else{cist=(*fatfs)->max_clust;sect=(*fatfs)->fatbase;i=0;p=0;do{ifCi-res=move_window(*fatfs,sect++);if(res!=FR.OK)LEAVE_FF(*fatfs,res);p=(*fatfs)->win;i=SS(*fatfs);)if(fat=FS_FAT16){if(LD_WORD(p)=0)n++;p+=2;i-=2;)else{if((LD_DWORD(p)&OxOFFFFFFF)==0)n++;p+=4;i-=4;)}while(—cist);)(*fatfs)->free_clust=n;if(fat=FSJFAT32)(*fatfs)->fsi_flag=1;*nclst=n;LEAVE_FF(*fatfs,FR_OK);/*TruncateFile*//*♦/FRESULTfltruncate(FIL*fp/*Pointertothefileobject*/){FRESULTres;DWORDncl;res=validate(fp->fs,fp->id);/*Checkvalidityoftheobject*/if(res!=FR_OK)LEAVE_FF(fp->fs,res);if(fp->f1ag&FA_ERROR)/*Checkabortflag*/LEAVE_FF(fi)->fs,FRJNT_ERR);if(!(fp->flag&FA_WRITE))/*Checkaccessmode*/LEAVE_FF(f0->fs,FR_DENIED);if(fp->fsize>fp->fptr){fp->fsize=fp->fptr;/*SetfilesizetocurrentR/Wpoint*/fp->flag1=FA_WRITTEN;if(fp->fptr=0){/*Whensetfilesizetozero,removeentireclusterchain*/res=remove_chain(fp->fs,fp->org_clust);fp->org_clust=0;)else{/*Whentruncateapartofthefile,removeremainingclusters*/ncl=gct_fat(fp->fs.fp->curr_clust);res=FR_OK;if(ncl=OxFFFFFFFF)res=FR_DISK_ERR;if(ncl==l)res=FR_INT_ERR;if(res==FR_OK&&ncl 101LEAVE_FF(fp->fs,res);/*DeleteaFileorDirectory*/FRESULTLunlink(constXCHAR*path/*Pointertothefileordirectorypath*/FRESULTres;DIRdj,sdj;NAMEBUF(sfn,Ifn);BYTE*dir;DWORDdeist;res=chk_mounted(&path,&dj.fs,1);if(res!=FR_OK)LEAVE_FF(dj.fs,res);INITBUF(dj,sfn,Ifn);res=follow_path(&dj,path);/*Followthefilepath*/if(_FS_RPATH&&res=FR_OK&&(dj.fn|NS]&NS_DOT))res=FR_INVALID_NAME;if(res!=FR_OK)LEAV己FF(dj.fs,res);/*Followfailed*/dir=dj.dir;if(!dir)/♦Isittherootdirectory?♦/LEAVE_FF(dj.fs,FR_INVALID_NAME);if(dir[DIR_Attr]&AM_RDO)/*IsitaR/Oobject?*/LEAVE_FF(dj.fs,FR.DENIED);deist=((D\v6RD)LD_WORD(dir+DIR_FstClusHI)«16)1LD_WORD(dir+DIR_FstClusLO);if(dir[DIR_Attr]&AM_DIR){/*Itisasub-directory*/if(deist<2)LEAVE_FF(dj.fs,FR_INT_ERR);mem_cpy(&sdj,&dj.sizeof(DIR));/*Checkifthesub-dirisemptyornot*/sdj.sclust=deist;res=dir_seek(&sdj,2);if(res!=FR_OK)LEAVE_FF(dj.fs,res);res=dir_rcad(&sdj);if(res==FR_OK)res=FR_DENIED;/*Notemptysub-dir*/if(res!=FR_NO_FILE)LEAVE_FF(dj.fs,res);)res=dir_remove(&dj);/*Removedirectoryentry*/if(res==FR_OK){if(deist) 102res=rcmove_chain(dj.fs,deist);/*Removetheclusterchain*/if(res=FR_OK)res=sync(dj.fs);)LEAVE_FF(dj.fs,res);/*♦//*CreateaDirectory*//*♦//*Pointertothedirectorypath*/FRESULTf_mkdir(constXCHAR*path)(FRESULTres;DIRdj;NAMEBUF(sfn,Ifn);BYTE*dir,n;DWORDdsect,deist,pclst,tim;res=chk_mounted(&path,&dj.fs,1);if(res!=FR_OK)LEAVE_FF(dj.fs,res);INITBUF(dj,sfn,Ifn);res=follow_path(&dj,path);/*Followthefilepath*/if(res==FR_OK)res=FR_EXIST;/*Anyfileordirectoryisalreadyexisting♦/if(_FS_RPATH&&res=FR_NO_FILE&&(dj.fn[NS]&NS.DOT))res=FR_INVALID_NAME;if(res!=FR_NO_FILE)/*Anyerroroccured*/LEAVE_FF(dj.fs,res);deist=create_chain(dj.fs,0);/*Allocateanewclusterfornewdirectorytable*/res=FR_OK;if(deist==0)res=FR_DENIED;if(deist==l)res=FR_INT_ERR;if(deist==OxFFFFFFFF)res=FR_DISK_ERR;if(res==FR_OK)res=move_window(dj.fs,0);if(res!=FR_OK)LEAVE_FF(dj.fs,res);dsect=clust2sect(dj.fs,deist);dir=dj.fs->win;/*Initializethenewdirectorytable*/mem_set(dir,0,SS(dj.fs));mem_set(dir+DIR_Name,'8+3);/*CreateH."entry*/dir[DTR_Name]=7;dir|DIR_Attr]=AM_DIR;tim=get_fattime();ST_Dw6RD(dir+DIR_WrtTime,tim);ST_WORD(dir+DIR_FstClusLO,deist);ST_WORD(dir+DIR_FstClusHI,deist»16);mem_cpy(dir+32,dir,32);/*Createentry*/dir[33]=7;pclst=dj.sclust;if(dj.fs->fs_type==FS_FAT32&&pclst=dj.fs->dirbase)pclst=0;ST_WORD(dir+32+DIR_FstClusLO,pclst);ST_WORD(dir+32+DIR_FstClusHI,pclst»16);for(n=0;n 103dj.fs->winsect=dsect++;dj.fs->wflag=1;res=move_window(dj.fs,0);if(res)LEAVE_FF(dj.fs,res);mem_set(dir,0,SS(dj.fs));)res=dir_register(&dj);if(res!=FR_OK){remove_chain(dj.fs,deist);}else{dir=dj.dir;/*Attribute*//*Cratedtime*//*Tablestartcluster*/dir[DIR_Attr]=AM_D!R;ST_DWORD(dir+DIR_WrtTime,lim);ST_WORD(dir+DIR_FstClusLO,deist);ST_WORD(dir+DIR_FstClusHI,deist»16);dj.fs->wflag=1;res=sync(dj.fs);)LEAVE_FF(dj.fs,res);/*ChangeFileAttribute*//**/FRESULTLchmod(constXCHAR*palh,/*Pointertothefilepath*/BYTEvalue./*Attributebits*/BYTEmask/*Attributemasktochange*/FRESULTres;DIRdj;NAMEBUF(sfn,Ifn);BYTE*dir;res=chk_mounted(&path,&dj.fs,1);if(res==FR_OK){INITBUF(dj,sfn,Ifn);res=follow_path(&dj,path);/*Followthefilepath*/if(_FS_RPATH&&res==FR_OK&&(dj.fn[NS]&NS_DOT))res=FR_INVALID_NAME;if(res=FR_OK){dir=dj.dir;if(!dir){/*Isitarootdirectory?*/res=FR_INVALID_NAME;}else{/*Fileorsubdirectory*/mask&=AM_RDOIAM_HIDIAM_SYSIAM_ARC;/*Validattributemask*/dir[DIR_Attr]=(value&mask)I(dir[DIR_Attr]&(BYTE)〜mask);/*Applyattributechange*/dj.fs->wflag=1;res=sync(dj.fs);)}}LEAVE_FF(dj.fs,res);/*ChangeTimestamp*//**/FRESULTf_utime( 104constXCHAR*path,/*Pointertothefile/directoryname*/constFILINFO*fno/*Pointertothetimestamptobeset*/)(FRESULTres;DIRdj;NAMEBUF(sfn,Ifn);BYTE*dir;res=chk_mounted(&path,&dj.fs,1);if(res==FR_OK){INITBUF(dj,sfn,Ifn);res=follow_path(&dj,path);/*Followthefilepath*/if(_FS_RPATH&&res==FR_OK&&(dj.fn[NS]&NS_DOT))res=FR_INVALID_NAME;if(res==FR_OK){dir=dj.dir;if(!dir){/*Rootdirectory*/res=FR_INVAL1D_NAME;}else{/*Fileorsub-directory*/ST_WORD(dir+DIR_WrtTime,fno->ftime);ST_WORD(dir+DIR_WrtDate,fno->fdate);dj.fs->wflag=1;res=sync(dj.fs);LEAVE_FF(dj.fs,res);/**//*RenameFile/Directory/*FRESULTf_rename(constXCHAR*path_old,/*Pointertotheoldname*/constXCHAR*path_new/*Pointerlothenewname*/FRESULTres;DIRdj_old,dj_new;NAMEBUF(sfntIfn);BYTEbufI21],*dir;DWORDdw;INITBUF(dj_old,sfn,Ifn);res=chk_mounted(&path_old,&dj_old.fs,1); 105if(res==FR_OK)(dj_new.fs=dj_old.fs;res=follow_path(&dj_old,path_old);/*Checkoldobject*/if(_FS_RP^TH&&res==FR_OK&&(dj_old.fn[NS]&NS_DOT))res=FR_INVALID_NAME;)if(res!=FR_OK)LEAVE_FF(dj_old.fs,res);/*Theoldobjectisnotfound*/if(!dj_old.dir)LEAVE_FF(dj_old.fs,FR_NO_FILE):/*Isrootdir?*/mem_cpy(buf,dj_old.dir+DIR_Attr,21);/*Savetheobjectinformation*/mem_cpy(&dj_new,&dj_old,sizeof(DIR));res=follow_palh(&dj_new,palh_new);if(res==FR_OK)res=FR_EXIST;if(res==FR_NO_FILE){res=dir_register(&dj_new);if(res=FR_OK){dir=dj_new.dir;mem_cpy(dir+13,buf+2,19);dir[DIR_Attr]=buf[O]IAM_ARC;/*Checknewobject*//*Thenewobjectnameisalreadyexisting*//*Isitavalidpathandnonamecollision?*//*Registerthenewobject*//*Copyobjectinformationintonewentry*/dj_old.fs->wflag=1;if(dir[DIR_Attr]&AM_DIR){/*Update..entryinthedirectoryifneeded*/dw=clust2sect(dj_new.fs,(DWORD)LD_WORD(dir+DIR_FstClusHI)ILD_WORD(dir+DIR_FstClusLO));if(!dw){res=FR_INT_ERR;)else{res=move_window(dj_new.fs,dw);dir=dj_new.fs->win+32;if(res=FR_OK&&dir[ll=={dw=(dj_new.fs->fs_type=FS_FAT32&&dj_new.sclust=dj_new.fs-xlirbase)?0:dj_new.sclust;ST_WORD(dir+DIR_FstClusLO,dw);ST_WORD(dir+DIR_FstClusHI,dw»16);dj_new.fs->wflag=1;if(res=FR_OK){res=dir_remove(&dj_old);/*Removeoldentry*/if(res==FR_OK)res=sync(dj_old.fs);)))LEAVE_FF(dj_old.fs,res);#endif/*!_FS_READONLY*/#endif/*_FS_MINIMIZE=0*/#endif/*_FS_MINIMIZE<=1♦/#endif7*_FS_MINIMIZE<=2*//*Forwarddatatothestreamdirectly(Availableononly_FS_TINYcfg)*//**/#if_USE_FORWARD&&_FS_TINYFRESULTflforward(FIL*fp,/*Pointertothefileobject*/ 106UINT(*func)(constBYTE*,UINT),/*Pointertothestreamingfunction*/UINTbtr,/*Numberofbytestoforward*/UINT*bf/*Pointertonumberofbytesforwarded*/FRESULTres;DWORDremain,cist,sect;UINTrent;*bf=O;res=validate(fp->fs,fp->id);if(res!=FR_OK)LEAVE_FF(fp->fstres);if(fp->flag&FA_ERROR)LEAVE_FF(fp->fs,FR_INT_ERR);if(!(fp->nag&FA_READ))LEAVE_FF(fp->fs,FR_DENIED);/*Checkvalidityoftheobject*//*Checkerrorflag*//*Checkaccessmode*/remain=fp->fsize-fp->fptr;if(btr>remain)btr=(UINT)remain;/*Truncatebtrbyremainingbytes*/for(;btr&&(*func)(NULL,0);busy*/fp->fptr+=rent,*bf+=rent,btr-=rent){if((fp->fptr%SS(fp->fs))==0){if(fp->csect>=fp->fs->csize)(cist=(fp->fptr=0)?/*Repeatuntilalldatatransferredorstreambecomes/*Onthesectorboundary?*//*Ontheclusterboundary?*//*Onthelopofthefile?*/fp->org_clust:get_fat(fp->fs,fp->curr_clust);if(cist<=l)ABORT(fp->fs,FR_INT_ERR);if(cist=OxFFFFFFFF)ABORT(fp->fs,FR_DISK_ERR);fp->cuiT_clust=cist;/*Updatecurrentcluster*/fp->csect=0;/*Resetsectoraddressinthecluster*/)fp->csect-H-;/*Nextsectoraddressinthecluster*/)sect=clust2sect(fp->fs,fp->curr_clust);/*Getcurrentdatasector*/if(!sect)ABORT(fp->fs,FR_IN7LERR);sect+=fp->csect-1;if(move_window(fp->fs,sect))/*Movesectorwindow*/ABORT(fp->fs,FR_DISK_ERR);fp->dsect=sect;rent=SS(fp->fs)-(WORD)(fp->fptr%SS(fp->fs));/*Forwarddatafromsectorwindow*/if(rent>btr)rent=btr;rent=(*func)(&fp->fs->win[(WORD)fp->fptr%SS(fp->fs)],rent);if(!rcnt)ABORT(fp->fs,FR_INT_ERR);LEAVE_FF(fp->fs,FR_OK);)#endif/*_USE_FORWARD*/#if_USE_MKFS&&!_FS_READONLY/**/*//*CreateFileSystemontheDrive#defineN_ROOTDIR512#defineN_FATS1#defineMAX_SECTOR#defineMIN工ECTOR/*Multipleof32and<=2048*//*1or2*/131O72OOOUL/*Maximumpartitionsize*/2000UL/*Minimumpartitionsize*/ 107FRESULTCmkfs(BYTEdrv,BYTEpartition,WORDallocsize/*Logicaldrivenumber*//*PartitioningruleO:FDISK,1:SFD*//*Allocationunitsize[bytes]*/staticconstDWORDsstbl|]=(2048000,1024000,512000,256000,128000,64000,32000,16000,8000,4000,0);staticconstWORDcstbl[]={32768,16384,8192,4096,2048,16384,8192,4096,2048,1024,512};BYTEfmt,m,*tbl;DWORDb_part,b_fat,b_dir,b_data;/*Areaoffset(LBA)*/DWORDn_part,n_rsv,n_fat,n_dir;/*Areasize*/DWORDn_clst,d,n;WORDasjFATFS*fs;DSTATUSstat;/♦Checkvalidityoftheparameters*/if(drv>=.DRIVES)returnFR_INVALID_DRIVE;if(partition>=2)returnFR_MKFS_ABORTED;/♦Checkmounteddriveandclearworkarea*/fs=FatFs[drv];if(!fs)returnFR_NOT_ENABLED;fs->fs_type=0;drv=LD2PD(drv);/*Getdiskstatics*/stat=disk_iniliaiize(drv);if(stat&S1A_NOINIT)returnFR_NOT_READY;if(stat&STA.PROTECT)returnFR_WRITE_PROTECTED;#if_MAX_SS!=512/*Getdisksectorsizeif(disk_ioctl(drv,GET_SECTOR_SIZE,&SS(fs))!=RES_OKIISS(fs)>_MAX_SS)returnFR_MKFS_ABORTED;#cndifif(disk_ioctl(drv.GET_SECTOR_COUNT&n_part)!=RES_OKIIn_part 108n_rsv=1+partition;n_dir=N_ROOTDIR*32/SS(fs);break;caseFS_FAT16:n_fat=((n_clst♦2)+4+SS(fs)-1)/SS(fs);n_rsv=1+partition;n_dir=N_ROOTDIR*32/SS(fs);break;default:n_fat=((n_clst*4)+8+SS(fs)-1)/SS(fs);n_rsv=33-partition;n_dir=0;)b_fat=b_part+n_rsv;/*FAlsstartsector*/b_dir=b_fat+n_fat*N_FATS;/*Directorystartsector*/b_data=b_dir+n_dir;/*Datastartsector*//♦Aligndatastartsectortoeraseblockboundary(fbrflashmemorymedia)*/if(disk_ioctl(drv,GET_BLOCK_SIZE,&n)!=RES_OK)returnFR_MKFS_ABORTED;n=(b_data+n-1)&~(n-1);n_fat+=(n-b_data)/N_FATS;/♦b_dirandb_dataarenolongerusedbelow*//*DeterminenumberofclusterandfinalcheckofvalidityoftheFATtype*/n_clst=(n_part-n_rsv-n_fat*N_FATS-n_dir)/allocsize;if((fmt=FS.FAT16&&n_ckt<0xFF5)II(fmt==FS.FAT32&&n_clst<0xFFF5))returnFR_MKFS_ABORTCD;/*Createpartitiontableifneeded*/if(Jpartition){DWORDn_disk=b_part+n_part;mem_set(fs->win,0,SS(fs));tbl=fs->win+MBR_TabIe;ST_DWORD(tbl,0x00010180);/*PartitionstartinCHS*/if(n_disk<63UL*255*1024)(/*PartitionendinCHS*/n_disk=n_disk/63/255;tbl[7]=(BYTE)n_disk;tbl[6]=(BYTE)((n_disk»2)I63);}else{ST_WORD(&tbl[6],OxFFFF);)tbl[5]=254;if(fmt!=FS_FAT32)/*SystemID*/tbl[4]=(n_part 109mcm_set(tbl,0,SS(fs));ST_DWORD(tbl+BSJmpBoot.0x90FEEB);ST_WORD(tbl+BPB_BytsPcrSec,SS(fs));tbl[BPB_SecPerClus]=(BYTE)allocsize;ST_WORD(tbl+BPB_RsvdSecCnt,n_rsv);tbl[BPB_NumFATs]=N_FATS;ST_WORD(tbl+BPB_RootEntCnt,SS(fs)/32*if(n_part 110if(disk_write(drv.tbl,b_fat++,1)!=RES_OK)returnFR_DISK_ERR:)while(—m);/*CreateFSInforecordifneeded*/if(fmt=FS_FAT32)(ST_WORD(tbl+BS_55AA,OxAA55);ST_DWORD(tbl+FSI_LeadSig,0x41615252);ST_DWORD(tbl+FSl_SlrucSig,0x61417272);ST_DWORD(tbl+FSI_Free_Count,n.clst-1);ST_DWORD(tbl+FSI_Nxt_Free,OxFFFFFFFF);disk_write(drv,tbl,b_part+l,1);disk_write(drv,tbl,b_part+7,1);return(disk_ioctl(drv,CTRL_SYNC,(void*)NULL)=RES_OK)?FR_OK:FR_DISK_ERR;#endif/*_USE_MKFS&&!_FS_READONLY*/#if_USE_STRFUNC/*Getastringfromthefile*/char*f_gets(char*buff,/*Pointertothestringbuffertoread*/intlen,/*Sizeofstringbuffer*/FIL*fil/*Pointertothefileobject*/inti=0;char*p=buff;UINTrc;while(i 111')Cputc(V,fil);/*LF->CRLFconversion*/#endif 112if(!fil){/*Specialvaluemaybeusedtoswitchthedestinationtoanyotherdevice*//*pul_console(chr);*/returnchr;}c=(char)chr;f_write(fil,&c,I,&bw);/*Writeabytetothefile*/returnbw?chr:EOF;/*Returntheresult*//*♦//*Putastringtothefile♦/intf_puts(constchar*str,/*Pointerlothestringtobeoutput*/FIL*fil/*Pointertothefileobject*/)(intn;for(n=0;*str;str++,n++){if(f_putc(*str,fil)==EOF)returnEOF;)returnn;/*Putaformattedstringtothefile*//*♦/intCprintf(FIL*fil,/♦Pointertothefileobject*/constchar*str,/*Pointertotheformatstring*/.../*Optionalarguments...*/){va_listarp;UCHARc,f,r;ULONGval;chars[16];inti,w,res,cc;va_start(arp,str);for(cc=res=0;cc!=EOF;res+=cc){c=*str++; 113if(c==0)break;if(c!='%'){cc=f_putc(c,fil);/*Endofstring*//*Nonescapecahracier*/w=f=0;c=*str++;if(c==,0'){f=1;c=*str++;}while(c>='O'&&cv=9){w=w*10+(c-*0');c=*str++;)if(c=T){f1=2;c=*str++;/♦Flag:'O'padding*//*Precision*//*Prefix:Sizeislongint*/if(cc!=EOF)cc=continue;if(c=='s'){/*Typeisstring*/cc=Lputs(va_arg(arp,char*),fil);continue;if(c=='c'){/*Typeischaracter*/cc=f_putc(va_arg(arp,int),fil);if(cc!=EOF)cc=1;)r=0;if(c=d)r=10;if(c=*u*)r=10;if(c=,X,)r=16;if(r=0)break;if(f&2){continue;/*Typeissigneddecimal*//*Typeisunsigneddecimal*//*Typeisunsignedhexdecimal*//*Unknowntype*//*Gelthevalue*/val=(ULONG)va_arg(arp,long);}else{val=(c=='d1)?(ULONG)(long)va_arg(arp,int):(ULONG)va_arg(arp,unsignedint);I/*Putnumeralstring*/if(c==d){if(val&0x80000000){val=0-val;fl=4;i=sizeof(s)-1;s[i]=0;do{c=(UCHAR)(val%r+,0,);if(c>9)c+=7;s[-i]=c;val/=r;)while(i&&val);if(i&&(f&4))s[-i]=,-r;w=sizeof(s)-1-w;while(i&&i>w)s[-i]=(f&I)?'O':'cc=f_puts(&s[i],fil);va_end(arp);return(cc=EOF)?cc:res;#endif/*!_FS_READONLY♦/#endif/*JjSElSTRFUNC*/ 114*FileName*Author*Reference*Date*Comment:Port_Init.c:budapcng2000@yahoo.com.cn:MC9S12XS256RMVl.pdf408:2010.3.13#includeHmain.h"****FunctionNameDescriptionParametersRelum:PortAD_Init:AD0[7:0]FIFODO[7:0]:None:NonevoidPortAD_Init(void)ATD()DIEN=Oxff;DDROAD()=OxOO:DDRlADO=OxOO;PERlAD0=0xff;*FunctionName*Description*:PortA_lnit****ParametersRelumPortAOFIFOwriteenable;1PortAlFIFOwrst;PortA2FIFOre;PortA3FIFOrrst; 115*FunctionName:PortT_Init*Description♦****Parameters*ReturnPortTOCOMSHREFPortTlCOMSVSYNCPortT7脉冲累加器PortT[6:2]未使用:None:None*******************************************************************************/voidPortT_Init(void)(DDRT=0x00;PTTRR=0x00;//PWM|7:4]toPortP;IOCO[2:OJtoPortT*FunctionName:PortS_Init*Description***Parameters*ReturnPortS[3:0]LEDPortS[7:4]未使用:None:NonevoidPortS_Init(void)(DDRS=Oxff;)/********************************************************************************FunctionName*Description:PortM_Init******PortMOSCIRXD1PortMlSCITXD1PortM2SPIMISOOPortM3SPISSOPortM4SPIMOS10PortM5SPISCKOPortM[7:6]未使用*Parameters:*Return:voidPortM_Init(void)(DDRM=OxOO;MODRR=0x90;//SCIltoPM;SPIOtoPMI*************************************************************”****************FunctionName*Description:PortP_Init**东*Parameters*ReturnPortP67舵机PortP|5:2]电机PortPOlCOMSFREX:None:NonevoidPortP_Init(void)(DDRP=OxOO;)*FunctionName*Description:PortJ_Init*PortJ[7:6]电机方向 116*PoitJ[5:0]未使用*Parameters:None*Return:NonevoidPortJ_Init(void)(DDRJ_DDRJ6=1;DDRJ_DDRJ7=1;)/********************************************************************************FunctionName:Port_Init*Description:*Parameters:None*Return:NonevoidPort_Init(void)(PortAD_Init();PortA」nit();PortB_Init();PortE_Init();PortT_Init();PortS_Init();PortM_Init();PortP_Init();PortJ_Init();1/********************************************************************************FileName*Author*Reference*Date*Comment:BusClock_Inil.c:budapeng2000@yahoo.com.cn:MC9S12XS256RMVl.pdf/233-240:2010.l.l8:XS128总线频率设黄#include"main.h"*FunctionName*Description率率*******Parameters*Return:BusCIock_Init():将单片机雨BUS_CLOCK超频到66.2857MHZfVOC=2*fOSC*(SYNDIV+i)/(REFDIV+1)fPLL=fVCO/(2*POSTDIV)fBUS=fPLL/2NOTE:fVCOmustbewithinthespecifideVCOfrequencylockrange.F.BUS(BUSClock)mustnotexceedthespecifiedmaximum.IfPOSTDIV=$00thenfPLLissameasfVCO(dividebyone).F_osc=16MH乙外部晶振的频率fREF=fOSC/(REFDIV+1)s=28r=6:None:NonevoidBusClock_Init(void)CLKSEL=0X00;//disengagePLLtosystemPLLCTL_PLLON=1;//turnonPLLSYNR=0xdc;//VCOFRQ[7:6];SYNDIV[5:0];fVCO=2*fOSC*(SYNDIV+1)/(REFDIV+l);fPLL=fVCO/(2xPOSTDIV);BUS=fPLL/2REFDV=0x46;//REFFRQ[7:6];REFDIV[5:0]_asm(nop);//BUSCLOCK=24M_asm(nop);while(!(CRGFLG_LOCK=l));//whenpllissteady,thenuseit;CLKSEL_PLLSEL=1;//engagePLLtosystem;) 117附2:关于舵机臂长和智能车转向性能的关系的研究“飞思卡尔”杯智能汽车竞赛是受教育部高等教育司委托,高等学校自动化专业教学指导委员会负责主办全国大学生智能车竞赛。该项比赛已列入教育部主办的全国五大竞赛之一。第五届飞思卡尔智能车竞赛更换的由北京科宇通博科技有限公司提供的B型车模,其中舵机安装位置如下图所示:图1原舵机安装祉置实测此舵机安装方法转弯角度不够,不能个达到比赛要求的最小半径50cm,且转弯时存在虚位,同时加上本次使用的舵机转矩太小,所以舵机安装位置如果不加以改变的话,很难取得很好的成绩,本论文通过分析舵机转动的规律,设计新的舵机安装方法,使之转角达到比赛规定的最小半径的要求,克服本次使用的舵机转矩不够的缺点,并且适当改进了智能车转弯的响应速度。本队采用此种方案在西部赛区取得了摄像头组第一名的好成绩,并且远远快于第二名(三秒多)o1方案简介原车模舵机安装方案结构复杂,传动装置偏多,再加上虚位比较严重,导致舵机响应不及时,最大转角不够。本方案采用舵机直立安装方案,传动机构少,便于安装,并且可根据实际情况改变舵机臂长,使之达到转向要求。2理论研究在这里假设舵机臂输出连杆为一条线,即左右轮连杆连接舵机臂于一点,当舵机转向时,连杆于舵机臂连接点从中心最低点围绕舵机输出轴转圆,示意图如图1所示,舵机在中心时舵机连杆和舵机臂连接图如图2所示,当舵机转到最大时如图3所示。(假设中心时舵机臂末端于车轮转向支点在同一水平线±o) 118舵机臂原始位置舵机臂▲苫轮转向4轮原始•支点转向支点图3舵机在最大转角时示意图假设舵机转矩为T,臂长为L,则舵机输出力F=T/L,车轮两杆长度为L1,车轮转向支点水平移动距离为L2(假设在同一平面上运动),如图4所示:根据上图所示原理,得出方程组:L3=2*L*sin(o/2)⑴Y=p-a⑵L3_Ll_(L1+L2)⑷sinysina/2sin®(兀+a/2—。)Fl=F*sinp(3)根据实际情况,假设舵机输出力矩为1,L2大约等于15mm,连杆长度Ll大约为60mm,由此得出F1跟L之间的关系图如下: 119其中X轴为舵机臂长,y轴为输出力大小。如果考虑到舵机的响应速度时,臂长关系如下所示: 1203实际安装由此可以看出不是臂长越短力越大,当臂长在15mm左右时F1达到最大,当考虑到舵机的响应速度时,臂长越长响应速度约快,所以我们选择大约17mm左右臂长,实际安装支架AutoCAD图如下:采用此种安装方法,即使在半径50cm的弯道上,占空比达到70%时都能转过。 1214结论综上所述,由理论算出的结果能够达到很好的效果,但是计算是在理想的情况下得到的结果,而且安装有误差,并且安装位置必须跟车轮支点在同一平面上,如果不在同一平面上,关系有将是什么,还有没有更好的舵机安装方法,等等,这些都有待我们进一步研究。
此文档下载收益归作者所有