【液晶仪表HMI软件开发与测试案例分析8300字】_第1页
【液晶仪表HMI软件开发与测试案例分析8300字】_第2页
【液晶仪表HMI软件开发与测试案例分析8300字】_第3页
【液晶仪表HMI软件开发与测试案例分析8300字】_第4页
【液晶仪表HMI软件开发与测试案例分析8300字】_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

液晶仪表HMI软件开发与测试案例分析目录TOC\o"1-3"\h\u832液晶仪表HMI软件开发与测试案例分析 1214921.1HMI软件组成结构 142121.2数据处理单元 281431.3消息队列单元 4289561.4图形绘制单元 8218321.4.1图形绘制流程 8240661.4.2文件加载 9112091.4.2.1资源文件加载 9131871.4.2.2XML文件解析 1136691.4.3场景绘制 1262191.4.4文字绘制 1466131.4.5动画效果控制 15109791.5软件单元联合测试 211.1HMI软件组成结构液晶仪表HMI软件承担仪表内信息调度和对外信息显示的任务,需要确保信息显示的实时性、有效性和软件运行的稳定性,液晶仪表相比传统仪表信息呈现形式更加丰富,界面显示更加多样,使软件设计趋于复杂化。根据功能将软件单元化、模块化分割,使各单元仅为与之对应的功能服务,可在降低软件耦合性的同时实现各单元的并行开发,从而提高开发效率。HMI软件单元结构如图1.1所示,软件由数据处理单元、消息队列单元、图形绘制单元组成。图1.1HMI软件单元结构1.2数据处理单元汽车仪表作为车况信息的显示终端,工作时需要接收、转发和处理大量数据,数据来源通常为汽车总线、车身硬线信号和仪表板载外设。汽车总线通常由CAN总线、LIN总线或其他总线构成;车身硬线信号由逻辑电平信号、模拟信号和PWM信号组成;仪表板载外设由实时时钟芯片、通信芯片、音频芯片和各类存储外设构成。由于信号种类过多,若采用单一处理器负责信号采集和界面绘制将无法保证信号响应的实时性。为解决上述问题,液晶汽车仪表通常采用双芯片设计方案[58],低算力MCU负责采集各类信号和数据并按照一定协议对数据整理和封包,高算力MPU负责运行液晶仪表HMI软件,二者之间按照一定协议通过UART总线实现数据通信,通信协议部分内容如表1.1所示,协议标定了各数据所在的字节、数据位、分辨率、偏移量等信息。为满足众多数据的传输需求,协议采用了多数据包顺序发送的方式对数据整理。数据包由包头、数据域和CRC校验值组成,其中包头指示当前发送数据包的编号,接收方可根据当前编号根据对应协议解析数据包;CRC校验值储存在数据包的最后两个字节位,用于校验数据包的正确性和完整性,若CRC值校验不通过,接收方可申请发送方重新发送数据包。表1.1双芯片UART总线通信协议部分内容字节数据位数据名称数据范围分辨率偏移量信号描述00-7包头0xF0-0xF210数据包编号10左转向0x00-0x01100:灭,1:亮11右转向0x00-0x01100:灭,1:亮12-3故障指示灯0x00-0x02100:灭,1:黄色,2:红色14-5行车状态0x00-0x02100:停止,1:准备,2:运行16-7雾灯0x00-0x02100:灭,1:亮,2:故障20-7Odo(高位)0x00-0xFF10总计里程(单位:km)30-7Odo(中位)0x00-0xFF10总计里程(单位:km)40-7Odo(低位)0x00-0xFF10总计里程(单位:km)50-7车速(高位)0x00-0x10410实时车速(单位:km/h)60-7车速(低位)70-7小计(高位)0x00-0xFFFF0.10小计里程(单位km)80-7小计(低位)1560-7CRC(高位)0x00-0xFFFF10数据包CRC校验值1570-7CRC(低位)UART总线的每一次通信将触发MPU中断处理函数,调用数据处理单元对数据包进行拆包和解析处理,完成解析后的数据将赋值到相关变量并更新数据缓冲区中的数据。数据扫描程序由定时器按一定周期循环调用,扫描数据缓冲区中的数据是否满足消息触发条件,若检测到当前数据满足触发状态,数据扫描程序将调用HMI_SendSignal()函数向消息队列发送队列插入请求,相关数据将作为负载(Payload)填充在消息结构体中,通过接口函数形参的方式传递至消息队列。消息结构体中包含的变量和数据如下:typedefstruct__MsgStruct{ uint8_tMainPriority; //主优先级 uint8_tSecondaryPriority; //子优先级 uint16_tLayerID; //图层编号 uint32_tScrID; //场景编号 uint32_tPayload_L; //消息数据负载(低位)uint32_tPayload_H; //消息数据负载(高位)}MsgStruct;1.3消息队列单元汽车仪表的信息呈现需满足实时性和准确性的要求,HMI软件需从大量信息和数据中筛选出最为重要的信息通过屏幕呈现,因此要求软件优化信息调度策略实现对所呈现信息内容的管控,避免非必要信息的主动显示对司乘人员造成干扰。图1.2展示的是消息队列示意图,基于链表的数据结构进行了改进,HMI渲染模块默认调用第一队列项中的渲染回调函数绘制场景,HMI软件允许在人为导航按键操作下强制切换默认显示场景,因此消息队列由双向循环队列构成,可通过指针查找临近节点实现当前显示场景的切换。队列由头结点与后续队列项组成,由于HMI中每一个图层都有自己的队列,为避免队列项在插入时出现错误,队列头结点记录了当前队列的图层编号以示区分,头结点还记录了当前队列的队列项总数,便于子程序读取当前队列数量信息。图1.2场景消息队列示意图消息队列对外预留的接口包括队列初始化、队列项插入、队列项删除等基本操作,详细流程如下:(1)队列初始化HMI软件在初始化的时候需同时初始化各图层对应的消息队列,使队列处于可工作状态,列表初始化代码如下:voidLayerMsgListInit(LayerMsgList*pList){pList->LayerID=LAYER_WARNING; //图层ID为报警图层pList->ScrID=NULL_DATA; //头结点其他值填充无效值pList->ScrID=NULL_DATA;pList->MPri=NULL_DATA;pList->CPri=NULL_DATA;pList->ScrID=NULL_DATA;pList->pPre=pList; //前驱与后继指针均指向自己(头结点)pList->pNext=pList;if(pList->pNext==pList){LayerMsgListInsertDefaultItem(pList); //插入默认队列项}}队列初始化流程包含指针占用空间初始化和相关变量赋值,当队列头部节点被创建时,队列中无后续队列项,因此头部节点的前驱指针和后继指针均指向自己。由于图层在界面绘制时不允许存在空场景的情况,因此队列项同样不允许为空,所以队列初始化时需要向队列中插入默认列表项,使队列正常工作。(2)队列项插入队列项的插入需根据本章第二小结中的消息结构体中涉及的信息进行队列插入操作。首先需要比对消息结构体中的图层ID是否与消息队列所属图层ID吻合,若不吻合则消息插入失败;若吻合则进行主、子优先级对比。优先级由8位无符号整数类型数据表示,其示数越大则优先级越低,头结点优先级为NULL_DATA,即为0,表示此优先级无效,因此最大有效优先级为1。完成对比后,将消息结构体中的数据赋值至初始化后的新队列项中,插入至当前队列项的前端,重新定位各队列项的前驱、后继指针,即可完成当前队列项的插入。详细代码如下:status_tLayerMsgListInsertItem(LayerMsgList*pListHead,MsgStruct*pMsg){if(pMsg->LayerID==pListHead->LayerID) //检查图层是否吻合{ LayerMsgList*pmList=pListHead->pNext; //获取第一队列项指针 while(pmList!=pListHead) { if(pMsg->MainPriority>pmList->MPri) //比对主优先级 { pmList=pmList->pNext; continue; if(pMsg->MainPriority>pmList->CPri) //比对子优先级 { pmList=pmList->pNext; } else { break; } } else { break; } } LayerMsgList*mListItem=(LayerMsgList*)malloc(sizeof(LayerMsgList)); //初始化新队列项指针 mListItem->LayerID=LAYER_WARNING; mListItem->ScrID=pMsg->ScrID; mListItem->MPri=pMsg->MainPriority; mListItem->CPri=pMsg->SecondaryPriority; mListItem->pPre=pmList->pPre; //将新队列项插入双向循环队列 mListItem->pNext=pmList; pmList->pPre->pNext=mListItem; pmList->pPre=mListItem; returnE_OK;} else { returnE_ERROR; }}(3)队列项移除队列项的移除同样需要根据传入接口的消息结构体中的数据进行比对和移除操作。首先进行图层比对,若图层比对成功则遍历链表,比对消息结构体与各队列项中的场景ID。若找到匹配的场景ID,则移除当前队列项以释放失效的内存空间并重新定义临近队列项前驱、后继指针;若队列全部遍历完成仍无法匹配消息结构体中的场景ID,则队列移除失败。队列项移除详细代码如下:status_tLayerMsgListRemoveItem(LayerMsgList*pListHead,MsgStruct*pMsg){ if(pMsg->LayerID==pListHead->LayerID) { LayerMsgList*pmList=pListHead->pNext; while(pmList!=pListHead) { if(pMsg->ScrID==pmList->ScrID) { break; } pmList=pmList->pNext; } if(pmList==pListHead) { returnE_ERROR; } else { pmList->pPre->pNext=pmList->pNext; pmList->pNext->pPre=pmList->pPre; free(pmList); returnE_OK; } } else { returnE_ERROR; }}1.4图形绘制单元1.4.1图形绘制流程本文2.2.1章节中介绍了HMI界面由多层位于不同显示区域的图层堆叠绘制而成,由于每层图层所需显示的内容与信号响应机制有所区别,因此为每层图层设计了与之对应且互相独立的消息队列。图形绘制单元按照图层的顺序由下至上依次扫描各图层所对应的消息队列,在默认状态下队列中索引号为1,有效优先级最高的队列项所对应的场景将被绘制。为便于用户浏览其他优先级的信息,HMI软件允许用户通过导航按键的操作切换为用户指定的显示场景。为实现这一目的,图形绘制单元可通过与各队列项中的索引号进行比对,与目标数值一致的队列项所对应的场景将会被绘制。场景的绘制通过图形绘制单元调用当前队列项中的场景绘制回调函数实现,该函数以函数指针的形式存储在队列项中,在调用时需将当前队列项中的场景ID、音频ID和数据负载作为形参传递至函数原型。场景绘制回调函数负责当前场景的加载和绘制工作,首先根据当前传入的数据负载确定与之匹配的绘制逻辑,不同的数据负载将触发不同的绘制逻辑,使同一场景在不同的信号触发方式下显示不同内容。以如表1.2所示ADAS报警场景为例,根据不同的数据负载,同一场景下绘制出的场景元素不尽相同。然后根据传入的场景ID加载与之匹配的场景资源文件,依照当前的绘制逻辑读取需要绘制的场景元素对应的图片数据。再通过解析布局配置XML文档获取当前场景的布局信息并与场景元素一一对应。最后调用Cairo图形库根据布局信息按照层级顺序逐一绘制场景元素。表1.2ADAS报警场景不同数据负载对应场景元素绘制情况表(●表示元素被绘制)场景元素数据负载(Payload)数值01234背景图片●●●●●红色边框●黄色边框●●●●文字=1\*GB3①●●文字=2\*GB3②●●●图片=1\*GB3①●●图片=2\*GB3②●●动画●1.4.2文件加载本文3.2.5章节详细描述了HMI设计工具可基于当前设计的工程项目生成XML格式的界面布局配置文件和二进制格式的场景资源文件,二者将被导入虚拟HMI开发平台或嵌入式平台文件系统指定路径中,经由HMI软件图形绘制单元加载。1.4.2.1资源文件加载在调用Cairo图形库绘制场景元素前需要将元素的数据传递至Cairo图形库接口创建类型为cairo_surface_t的元素平面,此接口支持三种形式的数据:PNG格式文件、文件数据流和位图像素数据流。本文3.2.6章节中提到的HMI设计工具使用了cairo_image_surface_create_from_png()接口从PNG格式的图片文件中加载,而场景资源文件由多个PNG格式文件按一定规则打包组合而成,不适用此类加载方式,可通过文件数据流或位图像素数据流加载。(1)从位图像素数据流加载首先使用ANSIC标准库函数打开文件并读取文件头部数据,根据场景元素所在的索引号查找当前元素在文件中的地址信息,根据地址信息使用fseek()函数重新定位文件指针,然后将文件指针传递至libpng库png_init_io()接口,按图1.3所示流程调用libpng库中的函数将PNG格式数据解析为图像像素数据流。图1.3libpng库图片解析流程图通过png_get_rows()函数解析后得到的图像像素数据的二维矩阵,矩阵纵向宽度与图片分辨率宽度一致,而横向长度则按照RGB或RGBA颜色类型分别为图片分辨率宽度的三倍或四倍。Cairo图形库无法直接使用此数据,需将矩阵数据按如图1.4所示的方式转换为BGR或BGRA顺序排列的一维数组生成位图图像数据流,最后将数据流指针作为形参传递至Cairo图形库中的cairo_image_surface_create_for_data()函数创建图片平面。a)RGBA颜色类型b)RGB颜色类型图1.4原始二维矩阵数据转换一维像素数据示意图(2)从文件数据流加载从文件数据流加载无需显式地让libpng函数库参与图像数据解析过程,而是在Cairo图形库中隐式调用。首先使用ANSIC标准库函数打开文件并读取文件头部数据,根据场景元素所在的索引号查找当前元素在文件中的地址信息,从对应地址中读取当前图片的文件数据至ImageSource结构体中,结构体内容如下:typedefstruct__ImageSource{ unsignedchar*data; //图像文件数据指针 intsize; //文件数据大小 intoffset; //数据起始位置在文件中的偏移量}ImageSource;同时,还需定义PNG文件读取回调函数原型,函数内容如下:staticcairo_status_tread_func(void*closure,unsignedchar*data,unsignedintlength){ ImageSource*imgsource=(ImageSource*)closure; //指针格式强制转换 if(imgsource->offset+length<=imgsource->size) //文件边际检查 { memcpy(data,imgsource->data+imgsource->offset,length); //读取 imgsource->offset+=length; returnCAIRO_STATUS_SUCCESS; } else { returnCAIRO_STATUS_READ_ERROR; }}最后向Cairo图形库中的cairo_image_surface_create_from_png_stream()函数传入创建好的图片数据结构体和PNG读取回调函数指针两个形参,最终完成图片平面的创建。1.4.2.2XML文件解析 菜单树配置文件与界面布局配置文件均是通过libxml2函数库生成为XML格式的文本文件,其生成方式已在本文3.2.5.1章节中详细说明。界面布局配置文件文件包含了各图层、场景和场景元素在界面中的布局信息,此信息用于指导场景绘制程序在何处绘制场景元素;菜单树配置文件则记录了当前仪表设置菜单的结构、设置项和与之对应的场景ID。菜单树配置文件需在HMI初始化时解析,界面布局配置文件需在场景绘制前完成文件解析,并填充相关数据至PaintInfo结构体中。结构体所包含的内容如下:typedefstruct__PaintInfo{uint32_tpIndex; //场景元素编号doublex; //x轴坐标doubley; //y轴坐标doublescale_x; //x轴缩放比doublescale_y; //y轴缩放比introtation; //旋转角度doublerot_x; //旋转锚点x轴坐标doublerot_y; //旋转锚点y轴坐标doubleAlphaValue; //透明度信息uint8_t*pPngFileData; //文件数据指针uint8_t*pPngRawData; //元素数据指针cairo_surface_tPNGSurface; //图形库Surface指针}PaintInfo;XML文档解析同样依赖libxml2函数库,解析菜单树配置文件需要遍历整个文件,确保设置菜单中的所有节点不会被遗漏,使用libxml2函数库遍历XML文档的详细流程如图1.5所示。程序在遍历节点的同时会构建另一套与其一致的菜单树模型,并逐一拷贝每一节点属性值。对于界面布局配置文件而言,该文件数据较多、体积较大,而嵌入式平台的内存较小,无法实现XML文档的整体遍历。libxml2函数库提供了xmlGetProp()函数,可根据键值名称查找与之匹配的属性值,提取到的属性值默认为字符串格式,需通过ANSIC标准库中的atoi()和atof()函数转换为整形或浮点型再赋值到结构体中,最终完成XML文档的解析。图1.5XML文件解析流程图1.4.3场景绘制场景资源的加载与布局配置文件的解析完成后,即可调用Cairo图形库对场景中需要显示的元素进行绘制。场景元素的绘制分为四步:(1)平移平移不仅可以为场景元素设定显示坐标,还可运用在动画效果中实现物体在某一方向上的移动效果,Cairo图形库提供了cairo_set_source_surface()函数,通过向函数传递与方向的显示坐标设置场景元素绘制的位置。(2)旋转场景元素默认以元素的形状中心为锚点进行旋转,但可使用Cairo提供的cairo_translate()函数自定义当前元素的旋转中心,再调用cairo_rotate()函数实现元素按自定义锚点旋转,需要注意的是向cairo_rotate()中传入的参数单位为弧度,因此需对角度进行弧度单位的转换。(3)缩放Cairo图形库可以按一定比例对图形进行横向或纵向方向的伸缩变换,为此提供了cairo_scale()函数负责元素比例缩放,其原理是基于传入的横向缩放比例和纵向缩放比例缩放用户控件的轴和轴以修改当前的变换矩阵实现图形的放大和缩小。(4)元素绘制图形的变换操作均在内存或显存中处理,相关数据并未与最初创建的Cairo抽象绘制平面绑定,因此可使用cairo_paint()或cairo_paint_with_alph()函数将内存中的数据渲染在上下文上,后者支持绘制透明背景图片。由于场景元素的绘制流程大体一致,因此可将场景元素绘制的代码部分封装为一个函数,供上级程序进行调用,场景元素绘制代码如下:voidPaintScrElement(cairo_t*cr,PaintInfo*info){ cairo_save(cr); if(!(info->rotation==0)) //旋转 { cairo_translate(cr,info->rot_x,info->rot_y); cairo_rotate(cr,info->rotation); cairo_translate(cr,-info->rot_x,-info->rot_y); } if(!(info->scale_x==1.0&&info->scale_y==1.0))//缩放并平移 { cairo_scale(cr,info->scale_x,info->scale_y); cairo_set_source_surface(cr,info->PNGSurface, (int)info->x/info->scale_x, (int)info->y/info->scale_y); } else //仅平移 { cairo_set_source_surface(cr,info->PNGSurface,info->x,info->y); } if(info->AlphaValue==100) cairo_paint(cr); else cairo_paint_with_alph(info->AlphaValue);}1.4.4文字绘制为减小HMI资源文件体积,同时支持多语言文字显示,HMI软件中的文字被HMI设计工具以单个字符图片的形式打包储存在文言资源文件中,其生成方法已在本文3.2.5.2章节中详细阐述。字符图片由字体文件生成,HMI中常用的字体大小为23或25号字体,可兼顾清晰度与页面排版。字符图片的分辨率与当前字符的字身框大小相关,以25号标准字体为例,不同语言字符的字身框大小不同,详细情况如表1.3所示,因此在文字绘制阶段需调整不同种类、不同语言的字符的排列显示坐标,防止文字过于紧密或稀疏。表1.325号标准字体下部分语言字符字身框大小语言类型字体长度(单位:像素)宽度(单位:像素)中文SimHei3231日文SimHei3232阿拉伯数字SimHei2518英文SimHei2518韩文MalgunGothic3331当场景处于绘制状态时,图形绘制单元会从布局配置文件中查找当前场景文本框控件的布局信息,再从字符串编码对照表中依据场景ID和当前的数据负载查找需要显示的字符串,随后调用HMI_Sprintf()函数绘制文字,文字绘制流程如图1.6所示,所有字符按水平居中的方式排列在文本框显示区域中,因此字符的轴显示坐标可通过文本框纵坐标与对应字符的字身框长度数据计算而出,可视为定值。字符串中所有字符的轴显示坐标将存储在动态数组中,传递至图形绘制单元经由Cairo图形库完成文字绘制。图1.6字符绘制流程1.4.5动画效果控制动画效果在HMI中的运用可以增强产品的人机交互性,使用户能更为直观的了解仪表所呈现信息的具体内容和含义。因此在多数重要的场景资源文件中集成了封装好的动画资源文件。HMI软件中常用的动画效果类型通常分为序列帧动画和元素变换动画两种,序列帧动画的构成与原理在本文2.2.2章节中进行了详细阐述,此处不做过多赘述;元素变换动画通过改变当前元素的显示位置、旋转角度、缩放比例或透明度实现。不论上述何种动画类型,动画效果的要素通常由对象本身、动画实施前后的属性值、开始时间、持续时间和控制函数组成,其中控制函数是所有要素的重中之重,负责计算当前时间对象运动属性的变化量。控制函数一般为缓动函数,缓动函数可以模拟现实生活中物体的非线性运动。本文为HMI中的虚拟仪表指针旋转动画设计了基于步进值的减加速缓动函数,同时引入了三次贝塞尔曲线作为缓动函数实现更为复杂的动画控制。(1)基于步进值的减加速缓动函数为确保仪表指针信号出现非连续数据变更时指针仍能实时、平滑且连续地旋转到目标位置,同时满足仪表指针对应数值出现快速变化时仍能快速准确响应的需求,因此要求缓动函数的时间复杂度尽可能的小。为此设计了基于步进值的减加速缓动函数,该函数接受当前属性值、终点位置属性值与步进值作为函数形参。为加快函数的运算速度,所有形参均为无符号整数类型,缓动函数算法如图1.7所示。动画效果启动后,函数将被定时器周期性调用,当检测到当前属性值与终点位置属性值相等后,动画效果结束。图1.7缓动函数算法流程图基于步进值的减加速缓动函数在不同步进值下的缓动曲线如图1.8中(a)所示,从图中可以看出步进值的数值越小曲线收敛越迅速,反之收敛更加平缓,但曲线的平滑程度有所下降,为兼顾动画的平顺性和合适的收敛速度,步进值取值范围为且为正整数。由于动画运行时目标值会出现变动的情况,缓动函数能根据变化的值快速调整当前动画的缓动效果。为此设计了试验测试缓动函数的阶跃响应情况,设定初始值,目标值,步进值,在某一时刻将目标值调整为,随后调整回原先目标值。试验生成的缓动函数图像如图1.8中(b)所示,表明缓动函数能快速响应目标值的变化并能根据目标差值调整响应速度。

a)不同步进值生成的缓动曲线b)步进值为4时的阶跃响应情况图1.8缓动曲线图示(2)三次贝塞尔曲线(CubicBézierCurve)由于减加速缓动函数仅能实现较为简单的缓动效果,在灵活性和函数平滑性上有所欠缺,针对HMI软件中的其他动效场景,选用三次贝塞尔曲线作为缓动函数可实现变加速、变减速以及回弹等动画效果。贝塞尔曲线由法国工程师皮埃尔·贝济埃(PierreBézier)于1962年发表,被广泛运用于图形设计与路径规划领域,近年来在UI动效中应用较多[59]。一次贝塞尔曲线是一条如图1.9中(a)所示由到的直线,若加入时间维度,使点在由向方向移动,则经过时刻出现在点处,则此时可用式(4-1)表示点:(4-1)整理后得到式(4-2):(4-2)二次贝塞尔曲线如图1.9(b)所示,由两条一次贝塞尔曲线构成,在两条直线上取两点使与的距离比和与距离比一致。其中点可由式(4-2)表示,的表示方式为式(4-3):(4-3)而的表示方法为式(4-4):(4-4)联立式(4-2)、(4-3)和(4-4)可得的最终方式为式(4-5):(4-5)由此可以推导出如图1.9中(c)所示三次贝塞尔曲线的表达方式为式(4-6):(4-6)a)一次贝塞尔曲线b)二次贝塞尔曲线c)三次贝塞尔曲线图1.9贝塞尔曲线绘制原理通过上述式子可以得知,在二维平面任意给出四个控制点的坐标,即可得到唯一的三次贝塞尔曲线。得益于贝塞尔曲线可根据控制

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论