根据DTH11传感器来记录温湿度数据,并以此来控制4个不同的继电器,达到控制不同负载来调节温湿度的目的
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
制作出来的实物图如下:
单片机源程序如下:
- #include <reg52.h>
- #include <intrins.h>
- #include <absacc.h>
- #include <math.h> //包含头文件
-
- #define uchar unsigned char
- #define uint unsigned int //宏定义
- //定义四个输出端口
- sbit Led_jiashi=P3^6; //加湿
- sbit Led_qushi=P3^4; //去湿
- sbit Led_jiangwen=P3^2; //降温
- sbit Led_shengwen=P3^3; //升温
- //定义三个设置按键
- sbit Key_SET = P2^0; //设置按键
- sbit Key_ADD = P2^1; //加按键
- sbit Key_SUB = P2^2; //减按键
- sbit Key_OK = P2^3; //确定按键
- //定义24C02数据口
- sbit SCL = P1^0;
- sbit SDA = P1^1;
- //定义DHT11数据口
- sbit DATA = P1^7;
- sbit buzz=P3^5; //蜂鸣器接口
- //定义LCD1602端口
- sbit E=P1^3; //1602使能引脚
- //sbit RW=P2^6; //1602读写引脚 我们只需要向液晶里写数据,不需要读取数据,所以就把读写引脚直接接地,程序里就不用单独控制了
- sbit RS=P1^2; //1602数据/命令选择引脚
- //定义全局变量
- uchar U8FLAG,U8temp,U8comdata,U8RH_data_H_temp,U8RH_data_L_temp,U8T_data_H_temp,U8T_data_L_temp,U8checkdata_temp; //定义读取温湿度变量
- uchar U8RH_data_H,U8RH_data_L,U8T_data_H,U8T_data_L,U8checkdata;
- uchar Mode,humidity,temperature; //设置模式、读取到的湿度温度数据存储变量
- char TH,TL,HH,HL; //温湿度的上下限变量
- bit bdata FlagStartRH,hot,cold,humid,dry,BJ; //开启转换温湿度标志位、热冷湿干和报警变量
- //定时器0初始化
- void Timer0_Init()
- {
- ET0 = 1; //允许定时器0中断
- TMOD = 0x11; //定时器工作方式选择
- TL0 = 0xb0;
- TH0 = 0x3c; //定时器赋予初值50ms
- TR0 = 1; //启动定时器T0
- }
- //定时器0中断
- void Timer0_ISR (void) interrupt 1 using 0
- {
- uchar RHCounter; //定义计数变量
- TL0 = 0xb0;
- TH0 = 0x3c; //定时器赋予初值
- RHCounter++; //每进一次中断就是50ms,此变量加一
- if(RHCounter%10==0&&BJ==1) //加到10的整数倍,并且报警标志位为1
- buzz=!buzz; //开启报警,每500ms蜂鸣器引脚取反一次,就是蜂鸣器一秒响一次
- else if(BJ==0) //报警标志位为0时
- buzz=1; //关闭报警
- //每2秒钟启动一次温湿度转换
- if (RHCounter >= 40) //计数到40次,就是2s,启动一次温湿度转换
- {
- FlagStartRH = 1; //启动转换变量置1
- RHCounter = 0; //计数变量清零
- }
- }
- /*以下程序为24c02的程序,都是官方的实例程序,可以参考时序图理解,都是固定的*/
- /*********************************
- BASE DRIVE
- **********************************/
- void DELAY(unsigned int t) //延时函数
- {
- while(t!=0)
- t--;
- }
- /******************************
- IIC DRIVE
- ******************************/
- void IICStart(void) //24c02的开始函数,关于24c02的函数多看下24c02的手册
- {
- SCL=0; //SCL引脚拉低
- DELAY(1); //短延时
- SDA=1; SCL=1; DELAY(1); //SDA拉高,SCL拉高,短延时
- SDA=0; DELAY(1); //SDA拉低,短延时
- SCL=0; //SCL拉低
- }
- void IICStop(void) //停止
- {
- SDA=0;SCL=1; DELAY(1); //注释略
- SDA=1; DELAY(1);
- SCL=0;
- }
- void SEND0(void) //发送
- {
- SDA=0;
- SCL=1;
- DELAY(1);
- SCL=0;
- }
- void SEND1(void)
- {
- SDA=1;
- DELAY(1);
- SCL=1;
- DELAY(1);
- SCL=0;
- }
- bit Check_Ack(void) //应答
- {
- unsigned char errtime=250; //定义变量
- DELAY(1);
- SCL=1;
- DELAY(1);
- CY=SDA; //SDA引脚高电平就是1,低电平就是0,赋值给CY
- while(CY) //如果CY为1,就执行此while
- {
- errtime--; //变量减
- CY=SDA; //赋值
- if (!errtime) //判断有没有减到0
- {
- IICStop(); //停止24C02
- return 1; //返回1
- }
- }
- DELAY(1);
- SCL=0;
- return 0;
- }
- void Write_byte(unsigned char dat)
- {
- unsigned char i;
- for(i=0;i<8;i++)
- {
- if((dat<<i)&0x80)
- SEND1();
- else
- SEND0();
- }
- }
- unsigned char Read_byte(void)
- {
- unsigned char i,temp=0;
- for(i=0;i<8;i++)
- {
- SDA=1;
- SCL=1;
- DELAY(1);
- if(SDA==1)
- {
- temp=temp<<1;
- temp=temp|0x01;
- }
- else
- temp=temp<<1;
- SCL=0;
- }
- return temp;
- }
- /************************************
- EEPROM DRIVE
- Addr:from 0x00-->
- *************************************/
- unsigned char rdeeprom(unsigned char addr)
- {
- unsigned char temp=0;
- bit flag=0;
- IICStart();
- Write_byte(0xa0);
- Check_Ack();
- Write_byte(addr);
- Check_Ack();
- IICStart();
- Write_byte(0xa1);
- Check_Ack();
- temp=Read_byte();
- SEND1();
- IICStop();
- return temp;
- }
-
-
- void wrteeprom(unsigned char addr,unsigned char dat)
- {
- IICStart();
- Write_byte(0xa0);
- Check_Ack();
- Write_byte(addr);
- Check_Ack();
- Write_byte(dat);
- Check_Ack();
- IICStop();
- }
- /*以下程序为DHT11温湿度传感器程序,官方的实例程序*/
- void Delay1(uint j) //延时程序
- {
- uchar i;
- for(;j>0;j--)
- {
- for(i=0;i<27;i++);
- }
- }
- void Delay_10us(void) //延时函数,大约10us,不精确
- {
- uchar i;
- i--;
- i--;
- i--;
- i--;
- i--;
- i--;
- }
- void COM(void) //读取温湿度函数
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- U8FLAG=2;
- while((!DATA)&&U8FLAG++);
- Delay_10us();
- Delay_10us();
- Delay_10us();
- U8temp=0;
- if(DATA)U8temp=1;
- U8FLAG=2;
- while((DATA)&&U8FLAG++);
- //超时则跳出for循环
- if(U8FLAG==1)break;
- //判断数据位是0还是1
-
- // 如果高电平高过预定0高电平值则数据位为 1
-
- U8comdata<<=1;
- U8comdata|=U8temp; //0
- }//rof
- }
- //--------------------------------
- //-----温湿度读取子程序 ------------
- //--------------------------------
- //----以下变量均为全局变量--------
- //----温度高8位== U8T_data_H------
- //----温度低8位== U8T_data_L------
- //----湿度高8位== U8RH_data_H-----
- //----湿度低8位== U8RH_data_L-----
- //----校验 8位 == U8checkdata-----
- //----调用相关子程序如下----------
- //---- Delay();, Delay_10us();,COM();
- //--------------------------------
- uchar RH(void)
- {
- //主机拉低18ms
- DATA=0;
- Delay1(180); //原来为5
- DATA=1;
- //总线由上拉电阻拉高 主机延时20us
- Delay_10us();
- Delay_10us();
- Delay_10us();
- Delay_10us();
- //主机设为输入 判断从机响应信号
- DATA=1;
- //判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行
- if(!DATA) //T !
- {
- U8FLAG=2;
- //判断从机是否发出 80us 的低电平响应信号是否结束
- while((!DATA)&&U8FLAG++);
- U8FLAG=2;
- //判断从机是否发出 80us 的高电平,如发出则进入数据接收状态
- while((DATA)&&U8FLAG++);
- //数据接收状态
- COM();
- U8RH_data_H_temp=U8comdata;
- COM();
- U8RH_data_L_temp=U8comdata;
- COM();
- U8T_data_H_temp=U8comdata;
- COM();
- U8T_data_L_temp=U8comdata;
- COM();
- U8checkdata_temp=U8comdata;
- DATA=1;
- //数据校验
- U8temp=(U8T_data_H_temp+U8T_data_L_temp+U8RH_data_H_temp+U8RH_data_L_temp);
- if(U8temp==U8checkdata_temp)
- {
- U8RH_data_H=U8RH_data_H_temp;
- U8RH_data_L=U8RH_data_L_temp;
- U8T_data_H=U8T_data_H_temp;
- U8T_data_L=U8T_data_L_temp;
- U8checkdata=U8checkdata_temp;
- }
- return 1;
- }
- else //传感器不响应
- {
- return 0;
- }
- }
- /********************************************************************
- * 文件名 : 液晶1602显示.c
- * 描述 : 该程序实现了对液晶1602的控制。
- ***********************************************************************/
- /********************************************************************
- * 名称 : delay()
- * 功能 : 延时,延时时间大概为140US。
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void delay()
- {
- int i,j;
- for(i=0; i<=10; i++)
- for(j=0; j<=2; j++);
- }
-
- /********************************************************************
- * 名称 : enable(uchar del)
- * 功能 : 1602命令函数
- * 输入 : 输入的命令值
- * 输出 : 无
- ***********************************************************************/
- void enable(uchar del)
- {
- P0 = del; //数据发送到P0口
- RS = 0; //RS引脚拉低
- E = 1; //E引脚高电平
- delay(); //延时
- E = 0; //E引脚低电平
- delay(); //延时
- }
- /********************************************************************
- * 名称 : write(uchar del)
- * 功能 : 1602写数据函数
- * 输入 : 需要写入1602的数据
- * 输出 : 无
- ***********************************************************************/
- void write(uchar del)
- {
- P0 = del; //同上
- RS = 1;
- E = 1;
- delay();
- E = 0;
- delay();
- }
- /********************************************************************
- * 名称 : L1602_init()
- * 功能 : 1602初始化,请参考1602的资料
- * 输入 : 无
- * 输出 : 无
- ***********************************************************************/
- void L1602_init(void)
- {
-
- enable(0x38); //设置液晶工作模式,意思:16*2行显示,5*7点阵,8位数据
- enable(0x0c); //开显示不显示光标
- enable(0x06); //整屏不移动,光标自动右移
- enable(0x01); //清屏
- }
- /********************************************************************
- * 名称 : L1602_char(uchar hang,uchar lie,char sign)
- * 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符显示"b" ,调用该函数如下
- L1602_char(1,5,'b')
- * 输入 : 行,列,需要输入1602的数据
- * 输出 : 无
- ***********************************************************************/
- void L1602_char(uchar hang,uchar lie,char sign)
- {
- uchar a; //定义变量
- if(hang == 1) a = 0x80; //如果hang变量为1,让地址数据为0x80就是第一行的
- if(hang == 2) a = 0xc0; //如果hang变量为0,让地址数据为0xc0就是第二行的
- a = a + lie - 1; //列数据减一,因为液晶屏的列是从0开始的
- enable(a); //发送行和列数据
- write(sign); //写显示内容
- }
- /********************************************************************
- * 名称 : L1602_string(uchar hang,uchar lie,uchar *p)
- * 功能 : 改变液晶中某位的值,如果要让第一行,第五个字符开始显示"ab cd ef" ,调用该函数如下
- L1602_string(1,5,"ab cd ef;")
- * 输入 : 行,列,需要输入1602的数据
- * 输出 : 无
- ***********************************************************************/
- void L1602_string(uchar hang,uchar lie,uchar *p)
- {
- uchar a;
- if(hang == 1) a = 0x80; //第一行地址
- if(hang == 2) a = 0xc0; //第二行地址
- a = a + lie - 1; //行和列数据加一起
- enable(a); //发送行列数据
- while(1) //进入循环
- {
- if(*p == '\0') break; //发送完字符串后跳出while循环
- write(*p); //没发送完就继续发
- p++; //字符串指针地址加1
- }
- }
- //显示整型的温湿度数据用,共占用4位,其中一位符号位
- void L1602_int(uchar hang, uchar lie, int num)
- {
- uint temp;
- uint gewei,shiwei,baiwei,sign;
- if (num >= 0) //如果温度值大于等于0
- sign = 0; //符号为正
- else //反之
- sign = 1; //符号为负
- temp = abs(num); //温度值取绝对值
- baiwei = temp / 100; //除以100得到温度值百位
- temp = temp - baiwei*100; //温度值减去百位得到十位和个位的数
- shiwei = temp / 10; //除以10得到十位的数据
- gewei = temp - shiwei*10; //减去十位的数据得到个位的数
- num = abs(num); //温度取绝对值
- if (num>=100) //如果温度大于100
- {
- // L1602_char(hang, lie+1, baiwei+48);
- L1602_char(hang, lie+2, shiwei+48); //显示十位和个位
- L1602_char(hang, lie+3, gewei+48);
- }
- else if (num>=10) //温度大于10
- {
- if (sign == 1) //负数时
- L1602_char(hang, lie+1, '-'); //显示负号
- L1602_char(hang, lie+2, shiwei+48); //显示十位和个位数
- L1602_char(hang, lie+3, gewei+48);
- }
- else //温度小于10
- {
- if (sign == 1) //负数时
- L1602_char(hang, lie+2, '-'); //显示负号
- else //正数
- L1602_char(hang, lie+2, ' '); //十位不显示
- L1602_char(hang, lie+3, gewei+48); //显示个位数
- }
- }
- void display() //显示函数
- {
- if(Mode==0) //不是设置状态
- {
- L1602_int(1,3,temperature); //显示温度数据
- L1602_char(1,7,0xdf); //显示摄氏度的°
- L1602_int(1,12,humidity); //显示湿度数据
- if(hot==1&&cold==0&&humid==0&&dry==0) //温度过高
- {L1602_string(2,1," It's very hot! ");BJ=1;} //显示热 ,报警
- else if(hot==1&&cold==0&&humid==1&&dry==0) //温度高,湿度高
- {L1602_string(2,1," Hot and humid! ");BJ=1;} //显示热 ,湿, 报警
- else if(hot==1&&cold==0&&humid==0&&dry==1) //温度高 ,湿度低
- {L1602_string(2,1," Hot and dry! ");BJ=1;} //显示热 ,干, 报警
- else if(hot==0&&cold==1&&humid==0&&dry==0) //温度低
- {L1602_string(2,1," It's very cold!");BJ=1;} //显示冷 ,报警
- else if(hot==0&&cold==1&&humid==1&&dry==0) //温度低 ,湿度高
- {L1602_string(2,1," Cold and humid!");BJ=1;} //显示冷 ,湿,报警
- else if(hot==0&&cold==1&&humid==0&&dry==1) //温度低 ,湿度低
- {L1602_string(2,1," Cold and dry! ");BJ=1;} //显示冷 ,干,报警
- else if(hot==0&&cold==0&&humid==1&&dry==0) //湿度高
- {L1602_string(2,1,"It's very humid!");BJ=1;} //显示潮湿,报警
- else if(hot==0&&cold==0&&humid==0&&dry==1) //湿度低
- {L1602_string(2,1," It's very dry! ");BJ=1;} //显示干燥
- else if(hot==0&&cold==0&&humid==0&&dry==0) //都在范围内
- {L1602_string(2,1,"Good environment");BJ=0;} //显示环境好,关闭报警
- }
- }
- /***按键函数***/
- void KEY() //按键函数
- {
- if(Key_SET==0) //设置按键按下
- {
- Delay1(200); //延时去抖
- if(Key_SET==0) //再次判断按键按下
- {
- Mode++; //显示位加
- TR0=0; //关闭定时器
- Led_shengwen=1;
- Led_jiangwen=1;
- Led_jiashi=1;
- Led_qushi=1; //关闭四路继电器输出
- hot=0;
- cold=0;
- humid=0;
- dry=0; //变量清零
- if(Mode==1) //设置第一个位置
- {
- L1602_string(1,1," TH: C HH: %"); //初始化设置界面,第一行显示温度和湿度上限
- L1602_char(1,8,0xdf); //显示摄氏度的°
- L1602_string(2,1," TL: C HL: %"); //第二行显示温度和湿度的下限
- L1602_char(2,8,0xdf); //显示摄氏度的°
- L1602_int(1,4,TH); //显示温度上限
- L1602_int(1,12,HH); //显示湿度上限
- L1602_int(2,4,TL); //显示温度下限
- L1602_int(2,12,HL); //显示湿度下限
- enable(0x80+6); //选中第一个位置闪烁
- enable(0x0f); //开启闪烁
- }
- else if(Mode==2) //第二个位置
- {
- enable(0x80+0x40+6); //温度上限位置闪烁
- enable(0x0f);
- }
- else if(Mode==3)
- {
- enable(0x80+14); //湿度上限位置闪烁
- enable(0x0f);
- }
- else if(Mode==4)
- {
- enable(0x80+0x40+14); //湿度下限位置闪烁
- enable(0x0f);
- }
- else if(Mode>=5) //设置完最后一位,回到第一位
- {
- Mode=1; //回到第一位置
- enable(0x80+6); //第一个位置闪烁
- enable(0x0f);
- }
- while(!Key_SET); //按键释放
- }
- }
- else if(Key_ADD==0) //加按键
- {
- Delay1(200);
- if(Key_ADD==0)
- {
- if(Mode==1) //设置温度上限
- {
- TH++; //温度上限加
- if(TH>=100) //加到100
- TH=99; //赋值99,也就是最大能加到99
- L1602_int(1,4,TH); //显示温度上限
- enable(0x80+6); //因为送显示数据了,闪烁的位置会自动右移,所以这里要指定要闪烁的位置
- wrteeprom(0,TH); //将上限值写入AT24C02芯片
- }
- else if(Mode==2) //设置温度下限
- {
- TL++; //加
- if(TL>=TH) //下限不能比上限高
- TL=TH-1; //下限只能加到比上限小一
- L1602_int(2,4,TL); //下面注释同上,略
- enable(0x80+0x40+6);
- wrteeprom(1,TL);
- }
- else if(Mode==3)
- {
- HH++;
- if(HH>=100)
- HH=99;
- L1602_int(1,12,HH);
- enable(0x80+14);
- wrteeprom(2,HH);
- }
- else if(Mode==4)
- {
- HL++;
- if(HL>=HH)
- HL=HH-1;
- L1602_int(2,12,HL);
- enable(0x80+0x40+14);
- wrteeprom(3,HL);
- }
- while(!Key_ADD);
- }
- }
- else if(Key_SUB==0) //减按键
- {
- Delay1(200);
- if(Key_SUB==0)
- {
- if(Mode==1)
- {
- TH--;
- if(TH<=TL)
- TH=TL+1;
- L1602_int(1,4,TH);
- enable(0x80+6);
- wrteeprom(0,TH);
- }
- else if(Mode==2)
- {
- TL--;
- if(TL<=0)
- TL=0;
- L1602_int(2,4,TL);
- enable(0x80+0x40+6);
- wrteeprom(1,TL);
- }
- else if(Mode==3)
- {
- HH--;
- if(HH<=HL)
- HH=HL+1;
- L1602_int(1,12,HH);
- enable(0x80+14);
- wrteeprom(2,HH);
- }
- else if(Mode==4)
- {
- HL--;
- if(HL<=0)
- HL=0;
- L1602_int(2,12,HL);
- enable(0x80+0x40+14);
- wrteeprom(3,HL);
- }
- while(!Key_SUB);
- }
- }
- if(Key_OK==0&&Mode!=0) //确认按键
- {
- Delay1(200);
- if(Key_OK==0)
- {
- L1602_string(1,1,"Tem: C Hum: %"); //退出设置状态,恢复待机显示界面
- L1602_string(2,1,"Good environment");
- Mode=0; //清零
- TR0=1; //打开定时器
- enable(0x0c); //光标不闪烁
- while(Key_OK==0); //按键释放
- }
- }
- }
- //数据初始化
- void Data_Init()
- {
- Led_qushi = 1;
- Led_jiashi=1;
- Led_jiangwen = 1;
- Led_shengwen = 1; //熄灭四个继电器
- }
- /********************************************************************
- * 名称 : Main()
- * 功能 : 主函数
- ***********************************************************************/
- void main()
- {
- uint i, j, testnum;
- EA = 0; //关闭定时器
- Timer0_Init(); //定时器0初始化
- Data_Init(); //数据初始化
- EA = 1; //打开定时器
- L1602_init(); //液晶屏初始化
- L1602_string(1,1," Welcome to T&H ");
- L1602_string(2,1," Control System!"); //开机显示界面
- //延时
- for (i=0;i<1000;i++) //延时
- for (j=0;j<100;j++)
- {;}
- /***载入温度上限和湿度上限设定值***/
- TH=rdeeprom(0); //从AT24C02读取温度上限数据
- Delay1(20); //加延时可以存取稳定
- TL=rdeeprom(1); //温度下限
- Delay1(20);
- HH=rdeeprom(2); //湿度上限
- Delay1(20);
- HL=rdeeprom(3); //湿度下限
- Delay1(20);
-
- if(TH<=0&&TL<=0&&HH<=0&&HL<=0) //如果是新单片机,温湿度数据都是小于0
- {
- wrteeprom(0,30); //那么就给温湿度的报警值赋初值,30 20 60 50
- Delay1(20); //加延时可以存取稳定
- TH=rdeeprom(0); //写进去再读出来
- Delay1(20); //加延时可以存取稳定
- wrteeprom(1,20);
- Delay1(20); //加延时可以存取稳定
- TL=rdeeprom(1);
- Delay1(20); //加延时可以存取稳定
- wrteeprom(2,60);
- Delay1(20); //加延时可以存取稳定
- HH=rdeeprom(2);
- Delay1(20); //加延时可以存取稳定
- wrteeprom(3,50);
- Delay1(20); //加延时可以存取稳定
- HL=rdeeprom(3);
- }
- //清屏
- L1602_string(1,1," ");
- L1602_string(2,1," ");
- L1602_string(1,1,"Tem: C Hum: %");
- L1602_string(2,1,"Good environment"); //显示待机界面
-
- while(1) //进入while循环
- {
-
- if (FlagStartRH == 1) //温湿度转换标志检查
- {
- TR0 = 0; //关闭定时器
- testnum = RH(); //读取温湿度
- FlagStartRH = 0; //转换标志清零
- TR0 = 1; //打开定时器
- humidity = U8RH_data_H; //读出湿度,只取整数部分
- temperature = U8T_data_H; //读出温度
-
- if(Mode==0) //温湿度控制
- {
- if (temperature > TH) //温度大于上限
- {
- Led_jiangwen = 0; //控制降温继电器打开
- hot=1; //温度高变量置1
- Led_shengwen = 1; //升温继电器关闭
- cold=0; //温度低变量置0
- // BJ=1;
- }
- else if(temperature<TL) //注释同上,略
- {
- Led_shengwen = 0;
- cold=1;
- Led_jiangwen = 1;
- hot=0;
- buzz=0;
- // BJ=1;
- }
- else //温度上下都不超限
- {
- Led_jiangwen=1;
- Led_shengwen=1;
- hot=0;
- cold=0;
- buzz=1;
- }
- if (humidity > HH)
- {
- Led_qushi = 0;
- humid=1;
- Led_jiashi = 1;
- dry=0;
- // BJ=1;
- }
- else if(humidity<HL)
- {
- Led_jiashi = 0;
- dry=1;
- Led_qushi = 1;
- humid=0;
- // BJ=1;
- }
- else //湿度上限都不超限
- {
- Led_qushi=1;
- Led_jiashi=1;
- humid=0;
- dry=0;
- }
- }
- else //所有数据都不超限
- {
- Led_shengwen=1;
- Led_jiangwen=1;
- Led_jiashi=1;
- Led_qushi=1; //关闭所有继电器
- hot=0;
- cold=0;
- humid=0;
- dry=0; //变量清零
- BJ=0; //关闭报警
- }
- }
- display(); //调用显示函数
- KEY(); //调用按键扫描函数
- }
- }
复制代码
所有资料51hei提供下载(Proteus7.5版本的仿真+程序):
4个继电器的温湿度控制器.7z
(424.6 KB, 下载次数: 171)
|