单片机课程设计报告(数字温度计)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

单片机课程设计报告
基于单片机的数字温度计设计
1 绪论 2 方案设计 3 系统的硬件设计
3.1 主控制器 3.2 显示电路
3.3 温度传感器工作原理 3.4 温度传感器接口电路 4 系统的软件设计
4.1 主程序
4.2 温度测量
4.2.1 初始化DS18B20 4.2.2 等待应答信号 4.2.3 DS18B20读字节 4.2.4 DS18B20写字节 4.2.5 启动温度测量 4.2.6 读取测量结果 4.2.7各算法流程图 4.3 数码管显示 5 系统的测试与总结 参考文献 附录1 原理图
附录2 源程序清单源程序清单
1 绪 论
随着人们生活水平的不断提高随着人们生活水平的不断提高,,单片机控制无疑是人们追求的目标之一,它所给人带来的方便也是不可否定的,它所给人带来的方便也是不可否定的,其中数字温度计就是一个典型的其中数字温度计就是一个典型的例子,但人们对它的要求越来越高,要为现代人工作、科研、生活提供更好的更方便的设施就需要从单片机技术入手,的更方便的设施就需要从单片机技术入手,一切向着数字化控制,一切向着数字化控制,智能化控制方向发展。

制方向发展。

现代社会对各种信息参数的准确度和精确度的要求都有了几何级的增现代社会对各种信息参数的准确度和精确度的要求都有了几何级的增
长,而如何准确而又迅速的获得这些参数就需要受制于现代信息基础的发展水平。

在三大信息信息采集在三大信息信息采集((即传感器技术即传感器技术))、信息传输信息传输((通信技术通信技术))和信息处理(计算机技术计算机技术))中,传感器属于信息技术的前沿尖端产品,传感器属于信息技术的前沿尖端产品,尤其是温度传感尤其是温度传感器技术,在我国各领域已经引用的非常广泛,在我国各领域已经引用的非常广泛,可以说是渗透到社会的每一个可以说是渗透到社会的每一个领域,人民的生活与环境的温度息息相关,人民的生活与环境的温度息息相关,在工业生产过程中需要实时测量在工业生产过程中需要实时测量温度,在农业生产中也离不开温度的测量,在农业生产中也离不开温度的测量,因此研究温度的测量方法和装置因此研究温度的测量方法和装置具有重要的意义。

具有重要的意义。

测量温度的关键是温度传感器,温度传感器的发展经历了三个发展阶段:段:
①传统的分立式温度传感器①传统的分立式温度传感器 ②模拟集成温度传感器②模拟集成温度传感器 ③智能集成温度传感器。

③智能集成温度传感器。

目前的智能温度传感器(亦称数字温度传感器)是在20世纪90年代中期问世的,它是微电子技术、计算机技术和自动测试技术(ATE)的结晶,特点是能输出温度数据及相关的温度控制量,适配各种微控制器(MCU)。

社会的发展使人们对传感器的要求也越来越高,现在的温度传感器正在基于单片机的基础上从模拟式向数字式,从集成化向智能化、网络化的方向飞速发展,并朝着高精度、多功能、总线标准化、高可靠性及安全性、安全性、开发虚拟传感器和网络传感器、开发虚拟传感器和网络传感器、开发虚拟传感器和网络传感器、研制单片测温系统等高科技的方向迅速发展,研制单片测温系统等高科技的方向迅速发展,本文将介绍智能集成温度传感器DS18B20的结构特征及控制方法,并对以此传感器,89S51单片机为控制器构成的数字温度测量装置的工作原理及程序设计作了详细的介绍。

与传统的温度计相比,其具有读数方便,测温范围广,测温准确,输出温度采用数字显示,主要用于对测温要求比较准确的场所,或科研实验室使用。

该设计控制器使用ATMEL 公司的AT89S52单片机,测温传感器使用DALLAS 公司DS18B20,用数码管来实现温度显示。

数码管来实现温度显示。

2方案设计
本设计主要是介绍了单片机控制下的温度检测系统,详细介绍了其硬件和软件设计,并对其各功能模块做了详细介绍,其主要功能和指标如下:
●利用温度传感器(DS18B20)测量某一点环境温度)测量某一点环境温度 ●测量范围为-55℃~+125℃,精度为±0.5℃
●用数码管进行实际温度值显示●用数码管进行实际温度值显示
采用A T89S52单片机P3 .5口控制温度传感器DS18B20的温度测量,以四位数码感形式输出测量温度,原理图如下图1.1所示:所示:
图2.1 DS18B20与单片机接口原理与单片机接口原理
图2.2 总体设计方框图总体设计方框图
3 系统的硬件设计
3.1 主控制器
AT89S52 AT89S52 是一种低功耗、是一种低功耗、高性能CMOS8位微控制器,具有8K 在系统可
编程Flash Flash 存储器。

使用存储器。

使用Atmel Atmel 公司高密度非公司高密度非公司高密度非 易失性存储器技术制造,与工业80C51 80C51 产品指令和引脚完产品指令和引脚完产品指令和引脚完 全兼容。

片上Flash 允许程序存储器在系统可编程,亦适于常规编程器。

在单芯片上,拥有灵巧的8 8 位位CPU CPU 和在系和在系统 可编程Flash Flash,使得,使得AT89S52为众多嵌入式控制应用系统提为众多嵌入式控制应用系统提 供高灵活、超有效的解决方案。

超有效的解决方案。

AT89S52AT89S52具有以下标准功能:具有以下标准功能:
8k 字节Flash Flash,,256字节RAM RAM,, 32 32 位位I/O I/O 口线,看门狗定时器,口线,看门狗定时器,口线,看门狗定时器,2 2 2 个个数据指针,三个16 16 位位 定时器定时器//计数器,一个6向量2级中断结构,全双工串行口,串行口, 片内晶振及时钟电路。

另外,片内晶振及时钟电路。

另外,AT89S52 AT89S52 AT89S52 可降至可降至0Hz 0Hz 静态逻静态逻静态逻 辑操作,支持2种软件可选择节电模式。

空闲模式下,CPU CPU 停止工作,停止工作,允许RAM RAM、、定时器定时器//计数器、串口、中断继续工中断继续工 作。

掉电保护方式下,RAM 内容被保存,
振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。

8 位微控制器位微控制器 8K 8K 8K 字节在系统可编程字节在系统可编程字节在系统可编程 Flash AT89S52 Flash AT89S52
图3.1 时钟电路与复位电路时钟电路与复位电路
3.2显示电路
显示采用4位数码管,图3.2.1为数码管段驱动,图
3.2.2为数码
管位驱动,图3.2.3为温度显示电路为温度显示电路
数码管段驱动 图3.2.1数码管段驱动
数码管位驱动 图3.2.2数码管位驱动
图3.2.3温度显示电路温度显示电路
3.3 温度传感器工作原理
DS18B20温度传感器是美国DALLAS 半导体公司最新推出的一种改进型智能温度传感器,与传统的热敏电阻等测温元件相比,与传统的热敏电阻等测温元件相比,它能直接读出被测温度,它能直接读出被测温度,它能直接读出被测温度,并且可根据实际要求通过并且可根据实际要求通过简单的编程实现9~12位的数字值读数方式。

DS18B20的性能特点如下:的性能特点如下: • 独特的单线接口仅需一个端口引脚进行通讯独特的单线接口仅需一个端口引脚进行通讯 • 简单的多点分布应用简单的多点分布应用 • 无需外部器件无需外部器件 • 可通过数据线供电可通过数据线供电 • 零待机功耗零待机功耗 • 测温范围-55~+125℃,以0.5℃递增。

华氏器件-67~+2570F ,以0.90F 递增递增 • 温度以9 位数字量读出位数字量读出
• 温度数字量转换时间200ms (典型值)(典型值) • 用户可定义的非易失性温度报警设置用户可定义的非易失性温度报警设置
• 报警搜索命令识别并标志超过程序限定温度(温度报警条件)的器件报警搜索命令识别并标志超过程序限定温度(温度报警条件)的器件
DS18B20内部结构主要由四部分组成:64位光刻ROM 、温度传感器、非挥发的温度报警触发器TH 和TL 、配置寄存器。

DS18B20DS18B20的管脚排列、各种封装形式如图的管脚排列、各种封装形式如图的管脚排列、各种封装形式如图 3.3.13.3.1所示,所示,所示,DQ DQ DQ 为数据输入为数据输入为数据输入//输出引脚。

开漏单总线接口引脚。

当被用着在寄生电源下,也可以向器件提供电源;电源下,也可以向器件提供电源;GND GND GND为地信号;为地信号;为地信号;VDD VDD VDD为可选择的为可选择的为可选择的VDD VDD VDD引脚。

当工引脚。

当工作于寄生电源时,此引脚必须接地。

其电路图 3.3.2 3.3.2所示所示所示..。

图图 3.3.1外部封装形式外部封装形式 图图3.3.23.3.2传感器电路图传感器电路图传感器电路图
DS18B20的测温原理如图3.3.3所示,所示,图中低温度系数晶振的振荡频率受温图中低温度系数晶振的振荡频率受温度的影响很小用于产生固定频率的脉冲信号送给减法计数器1,高温度系数晶振随温度变化其震荡频率明显改变,所产生的信号作为减法计数器2的脉冲输入,图中还隐含着计数门,当计数门打开时,图中还隐含着计数门,当计数门打开时,DS18B20DS18B20就对低温度系数振荡器产生的时钟脉冲后进行计数,进而完成温度测量时钟脉冲后进行计数,进而完成温度测量..计数门的开启时间由高温度系数振荡器来决定,每次测量前,首先将-55 ℃所对应的基数分别置入减法计数器1和温度寄存器中,减法计数器1和温度寄存器被预置在和温度寄存器被预置在--55 ℃所对应的一个基数值。

减法计数器1对低温度系数晶振产生的脉冲信号进行减法计数,当减法计数器1的预置值减到0时温度寄存器的值将加1,减法计数器减法计数器 1 1的预置将重新被装入,减法计数器1重新开始对低温度系数晶振产生的脉冲信号进行计数,如此循环直到减法计数器2计数到0时,停止温度寄存器值的累加,停止温度寄存器值的累加,此时温度寄存器中此时温度寄存器中的数值即为所测温图2中的斜率累加器用于补偿和修正测温过程中的非线性其输出用,输出用,于修正减法计数器的预置值,于修正减法计数器的预置值,于修正减法计数器的预置值,只要计数门仍未关闭就重复上述过程,只要计数门仍未关闭就重复上述过程,只要计数门仍未关闭就重复上述过程,直直至温度寄存器值达到被测温度值,这就是DS18B20的测温原理。

的测温原理。

另外,另外,由于由于DS18B20单线通信功能是分时完成的,单线通信功能是分时完成的,他有严格的时隙概念,他有严格的时隙概念,他有严格的时隙概念,因因此读写时序很重要。

系统对DS18B20的各种操作必须按协议进行。

操作协议为:
预置
低温度系数振荡器
高温度系数振荡器
斜率增加器
计数器 1
比较
预置
= 0
温度寄存器计数器 2
= 0
T x
加 1
停止
τ1
τ2
图3.4.1温度传感器接口电路温度传感器接口电路
4 系统的软件设计
4.1 主程序
/*------------------ 主函数主函数 --------------------*/ void main() { while(1) { Convert(); ////调用启动温度转换函数调用启动温度转换函数调用启动温度转换函数 RdTemp(); // //调用读取温度值函数调用读取温度值函数调用读取温度值函数
} 
} 
4.2 温度测量
4.2.1 初始化DS18B20 
/*--------------- 初始化DS18B20 ----------------*/ void TxReset() { uint i; 
 DQ=0; DQ=0; ////发送复位脉冲发送复位脉冲 i=100; 
 while(i>0) i--; ////拉低拉低900us 900us DQ=1; // //释放总线释放总线释放总线 i=4; 
 while(i>0) i--; } 
4.2.2 等待应答信号
/*-------------- 等待DS18B20应答应答 ---------------*/ void RxWait() { 
 uint i; 
 while(DQ); ////等待等待15-60us 
 while(~DQ); //DS18B20发出存在脉冲60-240us i=4; while(i>0) i--; 
} 
4.2.3 DS18B20读字节
/*---------------- 读取一位数据读取一位数据 ----------------*/ bit RdBit() { uchar i; bit b; 
 DQ = 0; ////读开始读开始1us i++; DQ = 1; // //产生读时间隙产生读时间隙15us 15us i++; i++; 
 b = DQ; ////读位读位读位 i = 8; 
 while(i>0) i--; // // //等待等待60us DQ = 1; ////释放总线释放总线释放总线 return b; } 
/*---------------- 读取字节数据读取字节数据 ----------------*/ uchar RdByte() { 
 uchar i,j,d; d=0; 
 for(i=0;i<8;i++) ////各位由低向高读出各位由低向高读出DS18B20 { j=RdBit(); d=(j<<7)|(d>>1); 
 } return d; } 
4.2.4 DS18B20写字节
/*---------------- 写入字节数据写入字节数据 ----------------*/ void WrByte(uchar d) 
{ 
 uint i; 
 uchar j; 
 bit btmp; 
 for(j=0;j<8;j++) ////各位由低向高写入
各位由低向高写入DS18B20 
 { 
btmp=d&0x01; 
d=d>>1; 
if(btmp) ////写写1
{ 
DQ=0; ////延时
延时15us 
i++; 
i++; 
DQ=1; //
//写写1时隙不低于60u 
i=8; 
while(i>0) i--; 
} 
else ////写写0 
{ 
DQ=0; 
i=8; 
while(i>0) i--; //
保持低电平60us到120us 
//保持低电平
DQ=1; ////释放总线
释放总线
释放总线
i++; 
i++; 
} 
 } 
} 
4.2.5 启动温度测量
/*---------------- 启动温度测量----------------*/ 
void Convert() 
{ 
 uint i; 
 Delay(125); //
延时1ms 
//延时
 TxReset(); ////初始化初始化DS18B20 RxWait(); // //等待等待DS18B20答应答应 Delay(125); // //延时延时延时
 WrByte(0xcc); ////跳过跳过ROM 命令命令 WrByte(0x44); ////温度转换命令温度转换命令温度转换命令 for(i=0;i<250;i++) ////延时延时1s
Display(); 
} 
4.2.6 读取测量结果
/*----------------- 读取温度值读取温度值 -----------------*/ void RdTemp(void) { 
 short int temp; uint x; bit flag = 1; 
 TxReset(); // //初始化初始化DS18B20 RxWait(); // //等待等待DS18B20应答应答 Delay(125); // //延时延时延时 WrByte(0xcc); // //跳过跳过ROM 命令命令 WrByte(0xbe); ////读暂存存储器命令读暂存存储器命令读暂存存储器命令
 templow = RdByte(); // //温度值低字节,低温度值低字节,低4位为小数位为小数 temphigh = RdByte(); // //温度值高字节温度值高字节温度值高字节
 temp = (temphigh << 8) | templow; // //温度为温度为16位补码位补码 if(temp<0) // //负温度负温度负温度 { flag = 0; 
temp = ~temp + 1; 
 } 
 tempzheng = temp >> 4; // //温度值整数温度值整数温度值整数 x = temp & 0x000f; 
 tempxiao = (x*10)/16; ////温度值小数温度值小数温度值小数
 if(flag) ////正温度正温度正温度
disp[0] = tempzheng/100; ////百位百位百位 else // //负温度负温度负温度
disp[0] = 16; // // //负号负号负号
 disp[1] = (tempzheng%100)/10; ////十位十位十位 disp[2] = tempzheng%10; // //个位个位个位 disp[3] = tempxiao; // //小数小数小数 } 
4.2.7各算法流程图
图 4.2.7.1DS18B20 4.2.7.1DS18B20初始化流程图初始化流程图初始化流程图 图图4.2.7.24.2.7.2主程序流程图主程序流程图主程序流程图
发DS18B20复位命令
发跳过ROM 命令 发温度转换开始命令 结束结束
图4.2.7.3 4.2.7.3 温度转换流程图温度转换流程图温度转换流程图
图4.2.7.4 计算温度流程图计算温度流程图
图4.2.7.5 显示数据刷新流程图显示数据刷新流程图
开始开始
温度零下? 
温度值取补码置“—”标志温度值取补码置“—”标志
计算小数位温度BCD 值
计算整数位温度BCD 值
结束结束
置“+”标志”标志
N 
Y 
开始开始 温度零下 
温度值取补码置“—”标志温度值取补码置“—”标志 计算小数位温度BCD 值 计算整数位温度BCD 值
结束结束
置“+”标志标志
N 
Y 
4.3 数码管显示
/*----------------数码管显示
数码管显示 - -----------------*/ 
void Display() 
{ 
uchar i,j; 
j=0x08; 
for(i=0;i<4;i++) 
{ 
P1=j; //
数码管位码输出
//数码管位码输出
数码管位码输出
LOCK=1; //
//打开锁存
打开锁存
打开锁存
if(i==2) P0=led[disp[i]]|0x01; //
显示小数点
//显示小数点
显示小数点
else P0=led[disp[i]]; //
数码管段码输出
//数码管段码输出
数码管段码输出
LOCK=0; //
关闭锁存
//关闭锁存
关闭锁存
j=j>>1; //
//调整位码
调整位码
调整位码
Delay(125); 
P0=0x00; 
} 
} 
5 系统的测试与总结
5.1 测试时的图片
图5.1.1温度传感器
图5.1.2测试时室内温度显示测试时室内温度显示
图5.1.3测试时手握住传感器时的温度显示测试时手握住传感器时的温度显示
5.2总结
通过近两个星期的单片机课程设计,我终于完成了“基于单片机的数字温度计设计”,心中不免有些高兴,但高兴之余也有我值得深思的。

虽然以前做过类似的实验,虽然以前做过类似的实验,
但这次的课程设计还是让我学到了很多东西,单片机课程设计重点就在于软件算法的设计,课程设计重点就在于软件算法的设计,需要有很巧妙的程序算法。

需要有很巧妙的程序算法。

需要有很巧妙的程序算法。

有好多的东西,有好多的东西,只有我们去试着做了,才能真正的掌握,只学习理论有些东西是很难理解的,只学习理论有些东西是很难理解的,更谈不上更谈不上掌握。

通过这次的单片机课程设计我认识到了,通过这次的单片机课程设计我认识到了,学习要理论联系实际,学习要理论联系实际,把学到的理论知识同实际运用相结合,才能是我们的知识融汇贯通,才能是我们的知识融汇贯通,才能真正的学到知识,才能真正的学到知识,才能真正的学到知识,真正的真正的做到学以致用。

做到学以致用。

附录1 原理图
附录2 源程序清单
#include <reg52.h> 
#define ulong unsigned long 
#define uint unsigned int 
#define uchar unsigned char 
uchar code led[]={ 0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0, 
0xfe,0xf6,0xee,0x3e,0x9c,0x7a,0x9e,0x8e,0x02,0x00 }; //数码管码表
数码管码表
数码管码表uchar disp[4]={1,2,3,4}; //数码管显示缓冲区
数码管显示缓冲区
//数码管位选P1低四位,段选P0 sbit LOCK=P1^4; //74573锁存端
锁存端
sbit DQ=P3^5; //DS18B20数据端
数据端
uchar templow; //温度值低字节
温度值低字节
uchar temphigh; //温度值高字节
温度值高字节
char tempzheng; //温度值整数
温度值整数
char tempxiao; //温度值小数
温度值小数
void Delay(uint x); 
void Display(); 
void TxReset(); 
void RxWait(); 
bit RdBit(); uchar RdByte(); void WrBit(bit b); void WrByte(uchar d); void Convert(); void RdTemp(); sbit ACC0 = ACC^0; sbit ACC7 = ACC^7; 
/*------------------ 主函数主函数 --------------------*/ void main() { while(1) { Convert(); //调用启动温度转换函数调用启动温度转换函数
RdTemp(); //调用读取温度值函数调用读取温度值函数
 } } 
/*--------------- 初始化DS18B20 ----------------*/ void TxReset() { uint i; 
 DQ=0; DQ=0; ////发送复位脉冲发送复位脉冲 i=100; 
 while(i>0) i--; //拉低900us DQ=1; //释放总线释放总线 i=4; 
 while(i>0) i--; 
} 
/*-------------- 等待DS18B20应答应答 ---------------*/ void RxWait() { uint i; 
 while(DQ); //等待15-60us 
 while(~DQ); //DS18B20发出存在脉冲60-240us i=4; 
 while(i>0) i--; 
} 
/*---------------- 读取一位数据
读取一位数据 ----------------*/ bit RdBit() 
{ 
 uchar i; 
 bit b; 
 DQ = 0; //读开始1us 
 i++; 
 DQ = 1; //产生读时间隙15us 
 i++; 
 i++; 
 b = DQ; //读位
读位
 i = 8; 
 while(i>0) i--; //等待60us 
 DQ = 1; //释放总线
释放总线
 return b; 
} 
/*---------------- 读取字节数据
读取字节数据 ----------------*/ uchar RdByte() 
{ 
 uchar i,j,d; 
 d=0; 
 for(i=0;i<8;i++) //各位由低向高读出DS18B20 
 { 
j=RdBit(); 
d=(j<<7)|(d>>1); 
 } 
 return d; 
} 
/*---------------- 写入字节数据
写入字节数据 ----------------*/ 
void WrByte(uchar d) 
{ 
 uint i; 
 uchar j; 
 bit btmp; 
 for(j=0;j<8;j++) //各位由低向高写入DS18B20 
 { 
btmp=d&0x01; 
d=d>>1; 
if(btmp) //写1 
{ 
DQ=0; //延时15us 
i++; 
i++; 
DQ=1; //写1时隙不低于60u 
i=8; 
while(i>0) i--; 
} 
else //写0 
{ 
DQ=0; 
i=8; 
while(i>0) i--; //保持低电平60us到120us DQ=1; //释放总线
释放总线
i++; 
i++; 
} 
 } 
} 
/*---------------- 启动温度转换
启动温度转换 ----------------*/ 
void Convert() 
{ 
 uint i; 
 Delay(125); //延时1ms 
 TxReset(); //初始化DS18B20 
 RxWait(); //等待DS18B20应答
应答
 Delay(125); //延时
延时
 WrByte(0xcc); //跳过ROM命令
命令
 WrByte(0x44); //温度转换命令
温度转换命令
 for(i=0;i<250;i++) //延时1s 
Display(); 
} 
/*----------------- 读取温度值
读取温度值 -----------------*/ 
void RdTemp(void) 
{ 
 short int temp; 
 uint x; 
 bit flag = 1; 
 TxReset(); //初始化DS18B20 
 RxWait(); //等待DS18B20应答
应答
 Delay(125); //延时
延时
 WrByte(0xcc); //跳过ROM命令
命令
 WrByte(0xbe); //读暂存存储器命令
读暂存存储器命令
 templow = RdByte(); //温度值低字节,低4位为小数
位为小数 temphigh = RdByte(); //温度值高字节
温度值高字节
//温度为16位补码 temp = (temphigh << 8) | templow; 
位补码 if(temp<0) //负温度
负温度
 { 
flag = 0; 
temp = ~temp + 1; 
 } 
 tempzheng = temp >> 4; //温度值整数
温度值整数
 x = temp & 0x000f; 
 tempxiao = (x*10)/16; //温度值小数
温度值小数
 if(flag) //正温度
正温度
disp[0] = tempzheng/100; //百位
百位
 else //负温度
负温度
disp[0] = 16; //负号
负号
 disp[1] = (tempzheng%100)/10; //十位
十位
 disp[2] = tempzheng%10; //个位
个位
 disp[3] = tempxiao; //小数
小数
} 
/*-------------------- 延时
延时 -------------------*/ void Delay(uint x) 
{ 
 uint i; 
 for(i=x;i>0;i--); 
} 
/*---------------- 数码管显示
数码管显示 -----------------*/ void Display() 
{ 
uchar i,j; 
j=0x08; 
 for(i=0;i<4;i++) 
 { 
P1=j; //数码管位码输出
数码管位码输出
LOCK=1; //打开锁存
打开锁存
if(i==2) P0=led[disp[i]]|0x01; //显示小数点
显示小数点 else P0=led[disp[i]]; //数码管段码输出
数码管段码输出 LOCK=0; //关闭锁存
关闭锁存
j=j>>1; //调整位码
调整位码
Delay(125); 
P0=0x00; 
} 
} 。

相关文档
最新文档