IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> 使用python控制eTM-3020C程控电源 -> 正文阅读

[Python知识库]使用python控制eTM-3020C程控电源

PyCharm Community Edition 2020.3 x64
eTM-3020C程控电源


客服提供的资料合集:eTM-3020C程控电源通信协议(P系列_DP系列_C系列)

基本参数

在这里插入图片描述
在这里插入图片描述

接口

??(摘自客服提供的资料《联机使用步骤》)

??本机可选配RS232或者RS485或者USB传输标准与计算机通信, 仅支持Modbus通讯协议(目前只支持功能码03、06)。

串口参数

??波特率:9600;
??起始位:1;
??数据位:8;
??校验位:无;
??停止位:1;
??地址码:0x01(可修改);

演示上位机串口通信连接步骤

  • 连接通信线、电源线,打开电源;

    • 注:
    1. 如选配的接口是RS232接口时串口线需要使用出厂机器配送的2-3母母交叉线;
    2. 如选配的接口是USB接口时,需要确认插上USB线、打开电源后,在电脑“设备管理器”中能识别到USB对应的串口号,如果没有识别到设备口号则需要安装相应的USB驱动;
  • 打开上位机演示软件;
    在这里插入图片描述

  • 在软件上添加“电源设备”:打开上位机软件后,在电脑桌面右下角的任务栏找到软件图标,右键选择“采样端口设置”,在“设备名称”窗口设置一个设备名称,在“端口号”窗口选择电源联机后对应的串口号(可在电脑的“设备管理器”中查找对应的COM号),其他的选项按需要选择或默认参数即可,设置完参数点“添加设备”, 此时软件窗口这边就会生成对应的电源设备图标;
    在这里插入图片描述
    在这里插入图片描述

  • 双击已添加的电源设备图标,打开串口进行控制;
    在这里插入图片描述

电源地址码修改方法

??(摘自客服提供的资料《电源地址码修改方法》)

??本机出厂默认地址码为0x01,如需要修改本机地址码,可参照下面方法修改:

  • 方法一:连接串口后通过发送指令修改地址码,详细可参照通信资料;
  • 方法二:进入工程模式修改:
    1. 型号P系列电源(功率300W(含)以下的小程控电源)修改方法:
      1. 在电源关机的状态下,按下电源“ON/OFF”小开关不松手再按下橙色电源开关给电源上电,直到电源电压窗口显示“Addr”内容后松开电源“ON/OFF”小开关,此时已进入工程模式;
      2. 电压窗口显示“Addr”的同时,电流窗口显示的就是本机地址码值,此时, 可直接通过按“M3”、“M4”按键增加或者减小地址码值;(地址码可设置范围:0-250);设置完重新开机即开始生效;
    2. 型号C系列电源(大功率双旋钮数控电源)修改方法:
      1. 在电源关机的状态下,按下电源“ON/OFF”小开关不松手再按下橙色电源开关给电源上电,直到电源电压窗口显示“O.U.T.”内容松开电源“ON/OFF”小开关,此时已进入工程模式;
      2. 在电压窗口显示为“O.U.T.” 时,按一次“电压调节旋钮”切换电压窗口显示为“Addr”,此时对应功率窗口显示的就是本机地址码值,然后通过旋转“电压调节旋钮”可增加或者减小地址码值;(地址码可设置范围:0-250);设置完重新开机即开始生效;

通讯协议

??(摘自客服提供的资料《(D)P系列_C系列通讯协议》)

??P系列/C系列仪表采用RS232或者RS485传输标准与计算机通讯(本机只支持功能码03,06 —— 20180611版)

??波特率:9600
??起始位:1
??数据位:8
??校验位:无
??停止位:1

MODBUS_RTU帧结构

??消息发送至少要以3.5个字符时间的停顿间隔开始;整个消息帧必须作为一连续的数据传输流,如果在帧完成之前有超过3.5个字符时间的停顿时间,接收设备将刷新不完整的消息并假定下一字节是一个新消息的地址域。同样地,如果一个新消息在小于3.5个字符时间内接着前个消息开始,接收的设备将认为它是前一消息的延续。
??一帧信息的标准结构如下所示:

开始地址域功能域数据域CRC校验结束
T1-T2-T3-T48Bit8Bitn个8Bit16BitT1-T2-T3-T4

地址域

??主机通过将要联络的从机的地址放入消息中的地址域来选通从设备,单个从机的地址范围是1…15(十进制)。
??地址0是用作广播地址,以使所有的从机都能认识。

功能域

??有效的编码范围是1…255(十进制);当消息从主机发往从机时,功能代码将告之从机需要去干什么。例如:读/写一组寄存器的数据内容等。

数据域

??主机发给从机的数据域中包含了从机完成功能域的动作时所必要的附加信息;如:寄存器地址等。

CRC校验

??CRC生成之后,低字节在前,高字节在后。

??本仪表通讯时帧与帧之间的响应间隔,通讯速率大于等于9600bps时不大于5ms

序号名称说明范围小数点位数读写参数通讯地址
0ON/OFF电源输出/停止设定1,00r/w0001H
1OP.S保护状态(注1)0-0xFFFF0r0002H
2规格型号规格型号0-655350r0003H
3尾缀分类尾缀分类0-0xFFFF0r0004H
4小数点位数V_A_W位数(注2)0-0xFFFF0r0005H
5U电源的电压显示值0-655352r0010H
6I电源的电流显示值0-655353r0011H
7P电源的功率显示值32位数据3r0012H(高16位),0013H(低16位)
9SetU设置电压0-655352r/w0030H
10SetI设置电流0-655353r/w0031H
12OVP过压保护设定值0-655352r/w0020H
13OCP过流保护设定值0-655352r/w0021H
14OPP过功率保护设定值32位数据2r/w0022H(高16位),0023H(低16位)
15RS-Adder通讯地址设定1~2500r/w9999H

??红注:红色序号部分是公用的。
??蓝色序号部分是可编程专用的。
??黑色序号部分是可选的。

  • 注1:保护状态位定义如下
union _ST
{
	struct
	{
		uint8_t isOVP:1;	//过压保护
		uint8_t isOCP:1;	//过流保护
		uint8_t isOPP:1;	//过功率保护
		uint8_t isOTP:1;	//过温保护
		uint8_t isSCP:1;	//短路保护
	}OP;
	uint8_t Dat;
};
  • 注2:小数点位数信息如下图
case 0x0005://电压电流功率小数点位数
	Dat = ShowPN;// ((2<<8) | (3<<4) | (3<<0)) ;//0.00V 0.000A 0.000W
	break;

??比如读到:0x0233,就是 电压2个小数,电流3个小数,功率3个小数

MODBUS RTU 通讯协议

  • 通讯数据的类型及格式:
    ??信息传输为异步方式,并以字节为单位。在主站和从站之间传递的通讯信息是10位的字格式:
字格式(串行数据)10位二进制
起始位1位
数据位8位
奇偶校验位
停止位1位
  • 通讯数据(信息帧)格式
数据格式地址码功能码数据区CRC校验
数据长度1字节1字节N字节16位CRC码(冗余循环码)

通讯信息传输过程

??当通讯命令由发送设备(主机)发送至接收设备(从机)时,符合相应地址码的从机接收通讯命令,并根据功能码及相关要求读取信息,如果CRC校验无误,则执行相应的任务,然后把执行结果(数据)返送给主机。返回的信息中包括地址码、功能码、执行后的数据以及CRC校验码。如果CRC校验出错就不返回任何信息。

地址码

??地址码是每次通讯信息帧的第一字节(8位),从1到250。这个字节表明由用户设置地址的从机将接收由主机发送来的信息。每个从机都必须有唯一的地址码,并且只有符合地址码的从机才能响应回送信息。当从机回送信息时,回送数据均以各自的地址码开始。主机发送的地址码表明将发送到的从机地址,而从机返回的地址码表明回送的从机地址。相应的地址码表明该信息来自于何处。

功能码

??是每次通讯信息帧传送的第二个字节。ModBus通讯规约可定义的功能码为1到127。作为主机请求发送,通过功能码告诉从机应执行什么动作。作为从机响应,从机返回的功能码与从主机发送来的功能码一样,并表明从机已响应主机并且已进行相关的操作。

M O D B U S 部分功能码 MODBUS部分功能码 MODBUS部分功能码

功能码定 义操 作(二进制)
02读开关量输入DI读取一路或多路开关量状态输入数 (遥信)
01读状态量输出OUT读取一路或多路开关量输出状态数据
03读寄存器数据读取一个或多个寄存器的数据
05写开关量输出OUT控制一路继电器“合/分”输出,遥控
06写单路寄存器把一组二进制数据写入单个寄存器
10写多路寄存器把多组二进制数据写入多个寄存器
数据区

??数据区包括需要由从机返送何种信息或执行什么动作。这些信息可以是数据(如:开关量输入/输出、模拟量输入/输出、寄存器等等)、参考地址等。例如,主机通过功能码03告诉从机返回寄存器的值(包含要读取寄存器的起始地址及读取寄存器的长度),则返回的数据包括寄存器的数据长度及数据内容。对于不同的从机,地址和数据信息都不相同(应给出通讯信息表)。
??电源采用Modbus通讯规约,主机(PLC、RTU、PC机、DCS等)利用通讯命令(功能码03),可以任意读取其数据寄存器(其数据信息表详见附录)。
??响应的命令格式是从机地址、功能码、数据区及CRC码。数据区的数据都是两个字节,并且高位在前。

静止时间要求

??发送数据前要求数据总线静止时间即无数据发送时间大于(5ms 波特率为9600时).

MODBUS功能码简介

功能码“03”:读多路寄存器输入

??例如:
??主机要读取地址为01,起始地址为0001的3个从机寄存器数据。
从机数据寄存器的地址和数据 从机数据寄存器的地址和数据 从机数据寄存器的地址和数据

寄存器地址寄存器数据(16进制)对应参数
00100BB8 (30.00V)U
001101F4 (5.00A)I
00123A98 (150.00W)P

主机发送的报文格式 主机发送的报文格式 主机发送的报文格式

主机发送字节数发送的信息备 注
从机地址101发送至地址为01的从机
功能码103读寄存器
起始地址20010起始地址为0001
读数据长度20003读取3个寄存器(共6个字节)
CRC码2040E由主机计算得到CRC码

从机响应返回的报文格式 从机响应返回的报文格式 从机响应返回的报文格式

从机响应字节数返回的信息备 注
从机地址101来自从机01
功能码103读寄存器
数据长度(字节数)106共6个字节
寄存器1的数据20BB8地址为0001寄存器的内容
寄存器2的数据201F4地址为0002寄存器的内容
寄存器3的数据23A98地址为0003寄存器的内容
CRC码2D311由从机计算得到CRC码
功能码“06”:写单个寄存器

??主机利用这个功能码把数据保存到电源内部数据存储器中去。Modbus通讯规约中的寄存器指的是16位(即2字节),并且高位在前。这样存储器都是二个字节。
??例如:
??主机要把0E10保存到地址为0004的从机寄存器中去(从机地址码为01)。
主机发送的报文格式 主机发送的报文格式 主机发送的报文格式

主机发送字节数发送的信息备 注
从机地址101发送至地址为01的从机
功能码106写单个寄存器
起始地址20004要写入的寄存器的地址
保存数据20E10待写入0004地址的数据
CRC码2CDA7由主机计算得到CRC码

从机响应返回的报文格式 从机响应返回的报文格式 从机响应返回的报文格式

从机响应字节数返回的信息备 注
从机地址101发送至地址为01的从机
功能码106写单个寄存器
起始地址20004要写入的寄存器的地址
保存数据20E100004地址的数据
CRC码2CDA7由从机计算得到CRC码

错误校验码(CRC校验)

??主机或从机可用校验码进行判别接收信息是否正确。由于电子噪声或一些其它干扰,信息在传输过程中有时会发生错误,错误校验码(CRC)可以检验主机或从机在通讯数据传送过程中的信息是否有误,错误的数据可以放弃(无论是发送还是接收),这样增加了系统的安全和效率。
??MODBUS通讯协议的CRC(冗余循环码)包含2个字节,即16位二进制数。CRC码由发送设备(主机)计算,放置于发送信息帧的尾部。接收信息的设备(从机)再重新计算接收到信息的CRC,比较计算得到的CRC是否与接收到的相符,如果两者不相符,则表明出错。

  • CRC码的计算方法
  1. 预置1个16位的寄存器为十六进制FFFF(即全为1);称此寄存器为CRC寄存器;
  2. 把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器;
  3. 把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位;
  4. 如果移出位为0:重复第3步(再次右移一位); 如果移出位为1:CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或;
  5. 重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理;
  6. 重复步骤2到步骤5,进行通讯信息帧下一个字节的处理;
  7. 将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换;
  8. 最后得到的CRC寄存器内容即为:CRC码。

使用python控制

依赖

modbus_tk
pyserial

python脚本

import time
import serial
import serial.tools.list_ports
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu


def connect_serial(keyword: str = "", baud_rate: int = None, timeout: int = 1):
    """
    连接串口
    :param keyword: 串口名关键词
    :param baud_rate: 波特率
    :param timeout: 超时时间
    :return: 串口类
    """
    serial_list = list(serial.tools.list_ports.comports())
    serial_list_len = len(serial_list)
    if serial_list_len <= 0:
        raise ValueError("Can't find a serial port")
    else:
        if not keyword:
            print("找到如下串口:")
            for serial_port in serial_list:
                print("\t", str(serial_port))
            print("请输入要连接的串口关键词:")
            keyword = input()
        if not baud_rate:
            print("请输入使用的波特率:")
            baud_rate = input()
            try:
                baud_rate = int(baud_rate)
            except:
                baud_rate = 9600
        for _ in range(serial_list_len):
            if keyword.lower() in str(serial_list[_]).lower():
                serial_port = serial.Serial(serial_list[_].name, baud_rate, timeout=timeout)
                print("与", serial_list[_], "建立连接!")
                return serial_port
        raise ValueError("Can't find the serial port")


class power_supply:
    """
    电源类
    """
    def __init__(self, serial_obj: serial.serialwin32.Serial, addr: int):
        """
        构造函数
        :param serial_obj: 串口类
        :param addr: 从机地址
        """
        self.modbus_rtu_obj = modbus_rtu.RtuMaster(serial_obj)
        self.modbus_rtu_obj.set_timeout(1.0)
        self.addr = addr
        self.name = self.read(0x0003)
        self.class_name = self.read(0x0004)

        dot_msg = self.read(0x0005)
        self.W_dot = 10 ** (dot_msg & 0x0F)
        dot_msg >>= 4
        self.A_dot = 10 ** (dot_msg & 0x0F)
        dot_msg >>= 4
        self.V_dot = 10 ** (dot_msg & 0x0F)

        protection_state_int = self.read(0x0002)
        self.isOVP = protection_state_int & 0x01
        self.isOCP = (protection_state_int & 0x02) >> 1
        self.isOPP = (protection_state_int & 0x04) >> 2
        self.isOTP = (protection_state_int & 0x08) >> 3
        self.isSCP = (protection_state_int & 0x10) >> 4

        self.V(0)

    def read(self, reg_addr: int, reg_len: int = 1):
        """
        读取寄存器
        :param reg_addr: 寄存器地址
        :param reg_len: 寄存器个数,1~2
        :return: 数据
        """
        if reg_len <= 1:
            return self.modbus_rtu_obj.execute(self.addr, cst.READ_HOLDING_REGISTERS, reg_addr, reg_len)[0]
        elif reg_len >= 2:
            raw_tuple = self.modbus_rtu_obj.execute(self.addr, cst.READ_HOLDING_REGISTERS, reg_addr, reg_len)
            return raw_tuple[0] << 16 | raw_tuple[1]

    def write(self, reg_addr: int, data: int, data_len: int = 1):
        """
        写入数据
        :param reg_addr: 寄存器地址
        :param data: 待写入的数据
        :param data_len: 数据长度
        :return: 写入状态
        """
        if data_len <= 1:
            self.modbus_rtu_obj.execute(self.addr, cst.WRITE_SINGLE_REGISTER, reg_addr, output_value=data)
            if self.read(reg_addr) == data:
                return True
            else:
                return False
        elif data_len >= 2:
            self.modbus_rtu_obj.execute(self.addr, cst.WRITE_SINGLE_REGISTER, reg_addr, output_value=data >> 16)
            self.modbus_rtu_obj.execute(self.addr, cst.WRITE_SINGLE_REGISTER, reg_addr + 1, output_value=data & 0xFFFF)
            if self.read(reg_addr) == (data >> 16) and self.read(reg_addr + 1) == (data & 0xFFFF):
                return True
            else:
                return False

    def read_protection_state(self):
        """
        读取保护状态
        :return: 保护状态寄存器原始值
        """
        protection_state_int = self.read(0x0002)
        self.isOVP = protection_state_int & 0x01
        self.isOCP = (protection_state_int & 0x02) >> 1
        self.isOPP = (protection_state_int & 0x04) >> 2
        self.isOTP = (protection_state_int & 0x08) >> 3
        self.isSCP = (protection_state_int & 0x10) >> 4
        return protection_state_int

    def V(self, V_input: float = None):
        """
        读取表显电压或写入目标电压
        :param V_input: 电压值,单位:伏特
        :return: 表显电压或目标电压
        """
        if V_input is None:
            return self.read(0x0010) / self.V_dot
        else:
            self.write(0x0030, int(V_input * self.V_dot + 0.5))
            return self.read(0x0030) / self.V_dot

    def A(self, A_input: float = None):
        """
        读取表显电流或写入限制电流
        :param A_input: 电流值,单位:安
        :return: 表显电流或限制电流
        """
        if A_input is None:
            return self.read(0x0011) / self.A_dot
        else:
            self.write(0x0031, int(A_input * self.A_dot + 0.5))
            return self.read(0x0031) / self.A_dot

    def W(self):
        """
        读取表显功率
        :return: 表显功率,单位:瓦
        """
        return self.read(0x0012, 2) / self.W_dot

    def OVP(self, OVP_input: float = None):
        """
        读取或写入过压保护设定值
        :param OVP_input:过压保护设定值
        :return:过压保护设定值
        """
        if OVP_input is None:
            return self.read(0x0020) / self.V_dot
        else:
            self.write(0x0020, int(OVP_input * self.V_dot + 0.5))
            return self.read(0x0020) / self.V_dot

    def OCP(self, OAP_input: float = None):
        """
        读取或写入过流保护设定值
        :param OAP_input:过流保护设定值
        :return:过流保护设定值
        """
        if OAP_input is None:
            return self.read(0x0021) / self.A_dot
        else:
            self.write(0x0021, int(OAP_input * self.A_dot + 0.5))
            return self.read(0x0021) / self.A_dot

    def OPP(self, OPP_input: float = None):
        """
        读取或写入过功率保护设定值
        :param OPP_input:过功率保护设定值
        :return:过功率保护设定值
        """
        if OPP_input is None:
            return self.read(0x0022, 2) / self.W_dot
        else:
            self.write(0x0022, int(OPP_input * self.W_dot + 0.5), 2)
            return self.read(0x0022, 2) / self.W_dot

    def Addr(self, addr_input: int = None):
        """
        读取或改变从机地址
        :param addr_input: 要设成的从机地址, 1~250
        :return: 从机地址
        """
        if addr_input is None:
            self.addr = self.read(0x9999)
            return self.addr
        else:
            self.write(0x9999, addr_input)
            self.addr = addr_input
            return self.read(0x9999)

    def set_volt(self, V_input, error_range: int = 0.05, timeout: int = 60):
        """
        设置目标电压,等待转换完成并测量响应时间
        :param V_input: 目标电压,单位:伏特
        :param error_range: 容许的误差大小
        :param timeout: 超时时间
        :return:
        """
        old_volt = self.V()
        self.V(V_input)
        start_time = time.time()
        while abs(self.V() - V_input) > error_range:
            if (time.time() - start_time) > timeout:
                raise ValueError("Set volt timeout")
        print("从", old_volt, "V跳至", self.V(), "V, 用时", time.time() - start_time, "秒")

    def operative_mode(self, mode_input: int = None):
        """
        读取或写入工作状态
        :param mode_input: 工作状态,1: 开启输出; 0: 关闭输出
        :return: 当前工作状态
        """
        if mode_input is None:
            return self.read(0x0001)
        else:
            if mode_input:
                self.write(0x0001, 1)
            else:
                self.write(0x0001, 0)
            return self.read(0x0001)


if __name__ == '__main__':
    print()
    eTM_3020C = power_supply(connect_serial("CH340", 9600), 1)
    eTM_3020C.operative_mode(1)
    eTM_3020C.set_volt(0)
    eTM_3020C.set_volt(12)
    eTM_3020C.set_volt(0)
    eTM_3020C.set_volt(16)
    eTM_3020C.set_volt(0)
    eTM_3020C.set_volt(32)
    print("当前表显电压:", eTM_3020C.V())
    print("当前表显电流:", eTM_3020C.A())
    print("当前表显功率:", eTM_3020C.W())
    eTM_3020C.set_volt(0)
    eTM_3020C.operative_mode(0)

运行效果

??可见,该电源升压较快,降压较慢:

D:\Anaconda3\envs\eTM-3020C\python.exe D:/Work/Python/eTM-3020C/main.py

与 COM3 - USB-SERIAL CH340 (COM3) 建立连接!
从 0.0 V跳至 0.0 V, 用时 0.0859994888305664 秒
从 0.0 V跳至 11.97 V, 用时 1.754119634628296 秒
从 11.97 V跳至 0.05 V, 用时 6.720765113830566 秒
从 0.05 V跳至 15.96 V, 用时 1.924328327178955 秒
从 15.96 V跳至 0.05 V, 用时 7.704945802688599 秒
从 0.05 V跳至 31.96 V, 用时 1.5403895378112793 秒
当前表显电压: 31.96
当前表显电流: 0.0
当前表显功率: 0.031.96 V跳至 0.05 V, 用时 10.615259647369385 秒

进程已结束,退出代码0

??对比官方演示上位机的响应曲线:
0 V ? > 16 V 0V->16V 0V?>16V
在这里插入图片描述
16 V ? > 0 V 16V->0V 16V?>0V

在这里插入图片描述
在这里插入图片描述

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-09-21 00:24:34  更:2022-09-21 00:25:20 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/26 13:40:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计