单片机与嵌入式系统期末实验
报告
软件系统测试报告下载sgs报告如何下载关于路面塌陷情况报告535n,sgs报告怎么下载竣工报告下载
深圳大学考试答题纸
(以论文、报告等形式考核专用)
二? 一? ,二? 一一 学年度第 二 学期
23169917课程编号 课程名称 单片机与嵌入式系统 主讲教师 龚向东 评分 01
学 号 姓名 专业
年级
六年级体育公开课教案九年级家长会课件PPT下载六年级家长会PPT课件一年级上册汉语拼音练习题六年级上册道德与法治课件
教师评语:
题目: 基于89C51的多点温度实时检测及重点温度控制系统 一、 实验原理
(1) 实现功能
本实验通过89c51控制三个监测点的DS18B20,读取三个监测点的温度数据,并对DS18B20转换后的数据进行处理,最后在数码管上显示DS18B20的温度,当任意监测点温度过高或过低时对高温或低温分别报警。由于生产上的需要,监测点三温度需要温度维持低于35摄氏度,当温度高于35摄氏度时监测点三风扇开始工作,并对监测点三进行降温。
(2) 系统电路组成
?AT89C51单片机最小系统
?外部设备:按键、led灯、蜂鸣器、共阴极7段数码管显示系统、步进电机、ds18b20温度
传感器等
?接口器件:74ls245锁存器、ULN2003
(3) 系统电路工作原理
?复位电路:
复位是单片机的初始化操作,目的是使CPU以及各个寄存器处于一个确定的初始状态。分
为手动复位方式和上电自动方式。
?时钟电路:
51单片机的时钟信号可由芯片内部的震荡电路产生,也可以由外部产生。
?温度传感器DS18B20:
DS18B20数字温度传感器是达拉斯半导体公司生产的1——Wire器件,即单总线器件,它
与传统的热敏电阻不同的是,它可以直接将被测温度转换成串行数字信号供主机处理,并
且根据具体要求,通关简单的编程实现9位温度度数。具有线路简单,体积小的特点。
它有三个引脚(如图1.1):
GND:接地;
DQ:数据输入输出引脚。开漏单总线接口引脚。当被用在寄生电源下,也可以向器件提供
电源(注:需要在该引脚出加一个上拉电阻)
VDD:可选的VDD引脚,接电源。在工作于寄生电源时,必须接地。
第1页 共22页
图1.1 温度传感器仿真图
?7段共阴极数码管:
用于显示采集到的温度数据给用户。七段数码管有八个片选信号点,分别控制四个7段数码管显示(如图1.2),另外八个引脚接受数据显示段码。由此实现数码管的显示。
图1.2 七段共阴极数码管
?步进电机
步进电机是将电脉冲信号转变为角位移或线位移的开环控制元步进电机件。在非超载的情况下,电机的转速、停止的位置只取决于脉冲信号的频率和脉冲数,而不受负载变化的影响,当步进驱动器接收到一个脉冲信号,它就驱动步进电机按设定的方向转动一个固定的角度,称为“步距角”,它的旋转是以固定的角度一步一步运行的。可以通过控制脉冲个数来控制角位移量,从而达到准确定位的目的;同时可以通过控制脉冲频率来控制电机转动的速度和加速度,从而达到调速的目的。
图1.3 步进电机仿真图
?锁存器74ls245
8路同相三态双向总线收发器,可双向传输数据。 74LS245还具有双向三态功能,既可以输出,也可以输入数据。 当8051单片机的P0口总线负载达到或超过P0最大负载能力时,必须接入74LS245等总线驱动器。 当片选端/CE低电平有效时,DIR=“0”,信号由 B 向 A 传输;(接收) DIR=“1”,信号由 A 向 B 传输;(发送)当CE为高电平时,A、B均为高阻态。 由于P2口始终输出地址的高8位,接口时74LS245的三态控制端1G和2G接地,P2口与驱动器输入线对应相连。P0口与74LS245输入端相连,E端接地,保证数据线畅通。8051的/RD和/PSEN相与后接DIR,使得RD且PSEN有效时,74LS245输入(P0.1?D1),其它时间处于输出(P0.1?D1)。
第2页 共22页
?ULN2003
ULN2003是大电流驱动阵列,多用于单片机、智能仪表、PLC、数字量输出卡等控制电路中。可直接驱动继电器等负载。 输入5VTTL电平,输出可达500mA/50V。ULN2003是高耐压、大电流达林顿陈列,由七个硅NPN达林顿管组成。 该电路的特点如下: ULN2003的每一对达林顿都串联一个2.7K的基极电阻,在5V的工作电压下它能与TTL和CMOS电路 直接相连,可以直接处理原先需要标准逻辑缓冲器。 ULN2003 是高压大电流达林顿晶体管阵列系列产品,具有电流增益高、工作电压高、温度范围宽、带负载能力强等特点,适应于各类要求高速大功率驱动的系统。
图1.4 ULN2003引脚图
二、 硬件结构
第3页 共22页
三、 程序结构
(1)主程序流程图及源程序
void main(void) 开始 {
IE=0x82;
TMOD=0x01; 设置定时器工作方式为0x01
TH0=-1000/256;
TL0=-1000%256;
装入计数初值 TR0=0;
HI_LED=1;
LO_LED=1; 高温警灯,低温警灯关
functionstype(); 关 }
执行functionstype函数
(2)读一字节子程序流程图及源程序
DQ置1 uchar ReadOneByte()
{
uchar i,dat=0; 循环次数i<8 DQ=1;_nop_(); for(i=0;i<8;i++)
短延时 {
DQ=0;
dat>>=1; Y DQ置0 DQ=1; _nop_(); 读入数据右移1位 _nop_();
if(DQ)
dat|=0x80; DQ置1 Delay(30); DQ=1;
} i=i+1;i<8 return dat;
} N
短延时
返回
第4页 共22页
(3)写一字节子程序流程图及源程序
DQ置0
void WriteOneByte(uchar dat)
{
循环次数i<8 uchar i;
for(i=0;i<8;i++)
{ 写入数据最低1位
DQ=0;
DQ=dat&0x01;
Y 短延时 Delay(5);
DQ=1;
dat>>=1; DQ置1
}
}
i=i+1;i<8
N
写入数据右移一位
(4)步进电机驱动流程图及源程序
void SETP_MOTOR_FFW() 声明变量 { uchar j;
for(j=0;j<8;j++) 循环次数j<8
{
N P3 = FFW[j]; 查表启动电机 Display_Temperture(); }
数码管上显示温度
}
Y
j++;j<8
结束
第5页 共22页
(5)读取温度值子程序及流程图
开始
void Read_Temperature()
{
if(Init_DS18B20()==1) DS18B20初始化
DS18B20_IS_OK=0; 成功 N else
{ Y DS18B20_IS_OK置0 WriteOneByte(0xCC);
WriteOneByte(0x44);
写入CCH命令跳过ROM Init_DS18B20();
WriteOneByte(0xCC);
发送温度转换命令44H
WriteOneByte(0xBE);
Temp_Value[0]=ReadOneByte();
DS18B20初始化 Temp_Value[1]=ReadOneByte();
Alarm_Temp_HL[0]=ReadOneByte(); 跳过ROM匹配
Alarm_Temp_HL[1]=ReadOneByte();
DS18B20_IS_OK=1; 发送读温度命令BEH }
}
读取温度寄存器
DS18B20_IS_OK置1
(6)显示温度子程序及流程图
第6页 共22页
void Display_Temperture() 开始
{uchar i;
uchar t=150;
uchar ng=0,np=0; 声明变量及初始化
char Signed_Current_Temp;
if((Temp_Value[1]&0xF8)==0xF8)
温度值是负数, {Temp_Value[1]=~Temp_Value[1];
Temp_Value[0]=~Temp_Value[0]+1; if(Temp_Value[0]==0x00) Temp_Value[1]++; Y N ng=1;np=0xFD; }
Display_Digit[0]=df_Table[Temp_Value[0] & 调整数据
0x0F];
CurrentT=((Temp_Value[0] & 查表得到温度小数部分
0xF0)>>4)|((Temp_Value[1] & 0x07)<<4);
Signed_Current_Temp=ng? 设置有符号的当前温度值 -CurrentT:CurrentT;/
HI_Alarm=Signed_Current_Temp>=Alarm_Temp_H
L[0]?1:0; 整数部分分解为三位待显示
LO_Alarm=Signed_Current_Temp<=Alarm_Temp_数字
HL[1]?1:0; 调整负号位置 Display_Digit[3]=CurrentT/100;
Display_Digit[2]=CurrentT%100/10;
Display_Digit[1]=CurrentT%10; 循环显示次数i<30
if(Display_Digit[3]==0)
{Display_Digit[3]=10; 数码管刷新显示温度 np=0XFB; if(Display_Digit[2]==0)
{Display_Digit[2]=10; Y 显示温度值是 np=0XF7 ; }}
负数, for(i=0;i<30;i++)
{P0=0x39;P2=0x7F;Delay(t);P2=0xFF;
P0=0x63;P2=0xBF;Delay(t);P2=0xFF;
Y P0=DSY_CODE[Display_Digit[0]];
P2=0xDF;Delay(t);P2=0xFF; N P0=(DSY_CODE[Display_Digit[1]])|0x80;
P2=0xEF;Delay(t);P2=0xFF; i=i+1;i<30
P0=DSY_CODE[Display_Digit[2]];
P2=0xF7;Delay(t);P2=0xFF;
P0=DSY_CODE[Display_Digit[3]];
P2=0xFB;Delay(t);P2=0xFF; N if(ng) 结束
{
P0=0x40;P2=np;Delay(t);P2=0xFF;
}
}}
第7页 共22页
(7)功能类型函数流程图及子程序
开始
key()=0x02?
N key()=0x02?
N 设置报警点 Y
Y 设置报警点 读取温度值
读取温度值 延时
延时
While
(key()=0x00?)
While
(key()=0x02?)
N 读取温度值
Y Y 读取温度值
高温报警,低Y 温报警,
N DS18B20初始Y 化成功,
当前温度大于N Y
35,
N 高温报警,低Y 温报警,
电机转动 N Y
显示温度 关中断 高温报警,低Y
温报警,
N Y key()=0x02? 显示温度 关中断
„„ 显示错误
第8页 共22页
(8)实验程序全代码
#include
#include
#define uchar unsigned char #define uint unsigned int
sbit HI_LED=P1^2;
sbit LO_LED=P1^3;
sbit DQ=P1^4;
sbit DQ1=P1^5;
sbit DQ2=P1^6;
sbit BEEP=P1^7;
uchar code FFW[]={0x01,0x03,0x02,0x06,0x04,0x0c,0x08,0x09}; //
uchar code DSY_CODE[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00}; //温度整数
位
uchar code df_Table[]={0,1,1,2,3,3,4,4,5,6,6,7,8,8,9,9};//温度小数位
char Alarm_Temp_HL[2] ={50,-10};
uchar CurrentT=0;//当前读取的温度整数部分
uchar Temp_Value[]={0x00,0x00};//从DS18B20读取的温度值 uchar Display_Digit[]={0,0,0,0};//待显示的各温度数位
bit HI_Alarm=0; //高温报警标志
bit LO_Alarm=0; //低温报警标志
bit DS18B20_IS_OK=1;//传感器正常标志
uint Time0_Count=0;//定时器延时累加
/********************* 延时子程序 *************/ void Delay(uint x)
{
while(--x);
}
/*********************按键检测程序***************/ char key()
{ return(P1 & 0x03); }
/******************初始化DS18B20**********/ uchar Init_DS18B20()
{
uchar status;
DQ=1;Delay(8);//从高拉倒低
DQ=0;Delay(90);
DQ=1;Delay(8);
status=DQ;
Delay(100);
DQ=1;
return status; //初始化成功返回0
第9页 共22页
}
/*****读一字节子程序********/
uchar ReadOneByte()
{
uchar i,dat=0;
DQ=1;_nop_();
for(i=0;i<8;i++)
{
DQ=0;
dat>>=1;
DQ=1;
_nop_();
_nop_();
if(DQ)
dat|=0x80;
Delay(30);
DQ=1;
}
return dat;
}
/*****************************写一字节******************/
void WriteOneByte(uchar dat) {
uchar i;
for(i=0;i<8;i++)
{
DQ=0;
DQ=dat&0x01;
Delay(5);
DQ=1;
dat>>=1;
}
}
/******************读取温度值****************************/
void Read_Temperature() {
if(Init_DS18B20()==1)
DS18B20_IS_OK=0; //DS18B20故障
else
{
WriteOneByte(0xCC); //跳过序列号
WriteOneByte(0x44); //启动温度转换
Init_DS18B20();
WriteOneByte(0xCC); //跳过序列号
WriteOneByte(0xBE); //读取温度寄存器
Temp_Value[0]=ReadOneByte(); //温度低8位
Temp_Value[1]=ReadOneByte(); //温度高8位
Alarm_Temp_HL[0]=ReadOneByte();
第10页 共22页
Alarm_Temp_HL[1]=ReadOneByte();
DS18B20_IS_OK=1;
}
}
/*********设置ds18b20温度报警值 **************/
void Set_Alarm_Temp_Value() {
Init_DS18B20();
WriteOneByte(0xCC); //跳过序列号
WriteOneByte(0x4E); //将设定的温度报警值写入DS18B20
WriteOneByte(Alarm_Temp_HL[0]); //写TH
WriteOneByte(Alarm_Temp_HL[1]); //写TL
WriteOneByte(0x7F); //12位精度
Init_DS18B20();
WriteOneByte(0xCC); //跳过序列号
WriteOneByte(0x48); //温度报警存入ds18b20
}
uchar Init_DS18B201() {
uchar status;
DQ1=1;Delay(8);//从高拉倒低
DQ1=0;Delay(90);
DQ1=1;Delay(8);
status=DQ1;
Delay(100);
DQ1=1;
return status; //初始化成功返回0
}
uchar ReadOneByte1()
{
uchar i,dat=0;
DQ1=1;_nop_();
for(i=0;i<8;i++)
{
DQ1=0;
dat>>=1;
DQ1=1;
_nop_();
_nop_();
if(DQ1)
dat|=0x80;
Delay(30);
DQ1=1;
}
return dat;
}
第11页 共22页
void WriteOneByte1(uchar dat) {
uchar i;
for(i=0;i<8;i++)
{
DQ1=0;
DQ1=dat&0x01;
Delay(5);
DQ1=1;
dat>>=1;
}
}
void Read_Temperature1() {
if(Init_DS18B201()==1)
DS18B20_IS_OK=0; //DS18B20故障
else
{
WriteOneByte1(0xCC); //跳过序列号
WriteOneByte1(0x44); //启动温度转换
Init_DS18B201();
WriteOneByte1(0xCC); //跳过序列号
WriteOneByte1(0xBE); //读取温度寄存器
Temp_Value[0]=ReadOneByte1(); //温度低8位
Temp_Value[1]=ReadOneByte1(); //温度高8位
Alarm_Temp_HL[0]=ReadOneByte1();
Alarm_Temp_HL[1]=ReadOneByte1();
DS18B20_IS_OK=1;
}
}
void Set_Alarm_Temp_Value1() {
Init_DS18B201();
WriteOneByte1(0xCC); //跳过序列号
WriteOneByte1(0x4E); //将设定的温度报警值写入DS18B20
WriteOneByte1(Alarm_Temp_HL[0]); //写TH
WriteOneByte1(Alarm_Temp_HL[1]); //写TL
WriteOneByte1(0x7F); //12位精度
Init_DS18B201();
WriteOneByte1(0xCC); //跳过序列号
WriteOneByte1(0x48); //温度报警存入ds18b20 }
uchar Init_DS18B202()
{
第12页 共22页
uchar status;
DQ2=1;Delay(8);//从高拉倒低
DQ2=0;Delay(90);
DQ2=1;Delay(8);
status=DQ2;
Delay(100);
DQ2=1;
return status; //初始化成功返回0 }
uchar ReadOneByte2() {
uchar i,dat=0;
DQ2=1;_nop_();
for(i=0;i<8;i++)
{
DQ2=0;
dat>>=1;
DQ2=1;
_nop_();
_nop_();
if(DQ2)
dat|=0x80;
Delay(30);
DQ2=1;
}
return dat;
}
void WriteOneByte2(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
DQ2=0;
DQ2=dat&0x01;
Delay(5);
DQ2=1;
dat>>=1;
}
}
void Read_Temperature2()
{
if(Init_DS18B202()==1)
DS18B20_IS_OK=0; //DS18B20故障
else
{
WriteOneByte2(0xCC); //跳过序列号
WriteOneByte2(0x44); //启动温度转换
第13页 共22页
Init_DS18B202();
WriteOneByte2(0xCC); //跳过序列号
WriteOneByte2(0xBE); //读取温度寄存器
Temp_Value[0]=ReadOneByte2(); //温度低8位
Temp_Value[1]=ReadOneByte2(); //温度高8位
Alarm_Temp_HL[0]=ReadOneByte2();
Alarm_Temp_HL[1]=ReadOneByte2();
DS18B20_IS_OK=1;
}
}
void Set_Alarm_Temp_Value2()
{
Init_DS18B202();
WriteOneByte2(0xCC); //跳过序列号
WriteOneByte2(0x4E); //将设定的温度报警值写入DS18B20
WriteOneByte2(Alarm_Temp_HL[0]); //写TH
WriteOneByte2(Alarm_Temp_HL[1]); //写TL
WriteOneByte2(0x7F); //12位精度
Init_DS18B202();
WriteOneByte2(0xCC); //跳过序列号
WriteOneByte2(0x48); //温度报警存入ds18b20 }
/**********************数码管上显示温度****************************/
void Display_Temperture()
{
uchar i;
uchar t=150; //延时值
uchar ng=0,np=0; //负数标识及负号显示位置
char Signed_Current_Temp;
if((Temp_Value[1]&0xF8)==0xF8) //如果为负数则取反加1,并设置负号标识及负号显示位置
{
Temp_Value[1]=~Temp_Value[1];
Temp_Value[0]=~Temp_Value[0]+1;
if(Temp_Value[0]==0x00) Temp_Value[1]++;
ng=1;np=0xFD; //默认负号显示在左边第1位
}
Display_Digit[0]=df_Table[Temp_Value[0] & 0x0F];//查表得到温度小数部分
CurrentT=((Temp_Value[0] & 0xF0)>>4)|((Temp_Value[1] & 0x07)<<4);//获取温度整数部分(高字节中的低3位与低字节中的高4位,无符号)
Signed_Current_Temp=ng? -CurrentT:CurrentT;//有符号的当前温度值
//高低温度报警设置(与定义为char的Alarm_Temp_HL比较,这样可区分正负比较)
HI_Alarm=Signed_Current_Temp>=Alarm_Temp_HL[0]?1:0;
LO_Alarm=Signed_Current_Temp<=Alarm_Temp_HL[1]?1:0;
//将整数部分分解为三位待显示数字
Display_Digit[3]=CurrentT/100;
第14页 共22页
Display_Digit[2]=CurrentT%100/10;
Display_Digit[1]=CurrentT%10;
if(Display_Digit[3]==0)
{
Display_Digit[3]=10;
np=0XFB;
if(Display_Digit[2]==0)
{
Display_Digit[2]=10;
np=0XF7 ; //调整负号位置
}
}
for(i=0;i<30;i++) //刷新显示若干时间
{
P0=0x39;P2=0x7F;Delay(t);P2=0xFF;
P0=0x63;P2=0xBF;Delay(t);P2=0xFF;
P0=DSY_CODE[Display_Digit[0]]; //小数位
P2=0xDF;Delay(t);P2=0xFF;
P0=(DSY_CODE[Display_Digit[1]])|0x80; //个位及小数点
P2=0xEF;Delay(t);P2=0xFF;
P0=DSY_CODE[Display_Digit[2]]; //十位
P2=0xF7;Delay(t);P2=0xFF;
P0=DSY_CODE[Display_Digit[3]]; //百位
P2=0xFB;Delay(t);P2=0xFF;
if(ng) //如果为负,则在调整后的位置显示
{
P0=0x40;P2=np;Delay(t);P2=0xFF;
}
}
}
/**************************风扇电机转动函数****************************/
void SETP_MOTOR_FFW()
{
uchar j;
for(j=0;j<8;j++)
{
P3 = FFW[j];
Display_Temperture();
}
}
/**************************定时器中断 控制报警声音********************/
void T0_INT() interrupt 1 {
TH0=-1000/256;
TL0=-1000%256;
第15页 共22页
BEEP=!BEEP;
if(++Time0_Count==400)
{
Time0_Count=0;
if(HI_Alarm) HI_LED=~HI_LED; else HI_LED=1;
if(LO_Alarm) LO_LED=~LO_LED; else LO_LED=1;
}
}
/**************按键识别 ******************/ void functionstype()
{
while(1)
{
if(key()==0x02)
{
Set_Alarm_Temp_Value();
Read_Temperature();
Delay(50000);
Delay(50000);
while(key()==0x02)
{
Read_Temperature();
if(DS18B20_IS_OK)
{
if(HI_Alarm==1||LO_Alarm==1) TR0=1;
else TR0=0;
Display_Temperture();
}
else P0=P2=0x00;
}
}
else if(key()==0x01)
{
Set_Alarm_Temp_Value1();
Read_Temperature1();
Delay(50000);
Delay(50000);
while(key()==0x01)
{
Read_Temperature1();
if(DS18B20_IS_OK)
{
if(HI_Alarm==1||LO_Alarm==1) TR0=1;
else TR0=0;
Display_Temperture();
}
第16页 共22页
else P0=P2=0x00;
}
}
else if(key()==0x00)
{
Set_Alarm_Temp_Value2();
Read_Temperature2();
Delay(50000);
Delay(50000);
while(key()==0x00)
{
Read_Temperature2();
if(DS18B20_IS_OK)
{
if(CurrentT>35)
SETP_MOTOR_FFW();
if(HI_Alarm==1||LO_Alarm==1)
TR0=1;
else TR0=0;
Display_Temperture();
}
else P0=P2=0x00;
}
}
else
{TR0=0;
P0=0x77;P2=0x7F;Delay(50);P2=0xFF;
P0=0x3F;P2=0xBF;Delay(50);P2=0xFF;
P0=0x77;P2=0xDF;Delay(50);P2=0xFF;
P0=0x77;P2=0xEF;Delay(50);P2=0xFF;
P0=0x79;P2=0xF7;Delay(50);P2=0xFF;
}
}
}
/****************************主程序****************************/
void main(void)
{
IE=0x82;
TMOD=0x01;
TH0=-1000/256;
TL0=-1000%256;
TR0=0;
HI_LED=1;
LO_LED=1;
functionstype();
}
第17页 共22页
四、 软件仿真及实验结果说明
(1) 状态一:温度监控点按键没有按下,数码管显示“ERROR”
(2) 状态二:sw0按键按下,对监控点一进行监测,当监控温度为26.4度时正常显示
第18页 共22页
当温度超过50度上限温度时,高温报警灯闪,蜂鸣器响
(3)状态三:sw1键被按下,对监控点二进行监测,当被监测温度为32时温度时
第19页 共22页
当温度超过-10度温度下限时,低温报警灯闪,蜂鸣器响
(4)sw1,sw2同时被按下时,对温控点三进行监测和温度控制;当温度为22度时正常监测
第20页 共22页
当温控点温度一旦大于35度时,风扇开始转动,对该点进行散热
当温控点温度急剧上升,风扇不足以散热时,系统将会发出报警信号
第21页 共22页
五、 实验心得及体会
1、对51单片机最小化系统有了更加深刻的认识
2、通过本次实验掌握了74ls245和ULN2003芯片的用法;
3、认识了步进电机是如何工作的,通过查阅资料学会了如何使步进电机和51单片机交互工作,特别是在设置步进电机工作脉冲的时候,巧妙的利用数码管显示温度时间作为脉冲时间间隔很巧妙。
、对DS18B20温度传感器的工作原理有了更加深刻的理解,通过查阅资料学会了如何4
使DS18B20和51单片机交互工作
5、掌握了在完成一个实验项目的过程中应当把项目中所要实现的功能拆分,也就是模块化的设计,这样会给设计带来便利。
6、感受到51单片机的功能强大,51单片机的使用,解决了大规模外围复杂电路的设计,给电路设计工作者带来了巨大的便利。
7、在程序编写上用到了一些常用设计程序,如按键检测程序,延时程序,查表程序,定时器终端程序,数码管扫描显示程序,步进电机工作程序等。这些程序不但本次实验中用得到,在设计其他电路时,也经常用到。
在编写程序的过程中还学会了一些硬件专用程序,如DS18B20启动程序,读一字节程序,写一字节程序,读取温度值程序,设置报警值等程序。虽然不一定在其他程序中经常用到但是对做其他项目很有帮助。
第22页 共22页