PLC上位机程序开发

目标:

1.通过MC协议进行PLC上位机程序的编写

2.将学到的内容:异常捕获,tkinter显示图像

  异常捕获十分方便程序开发时,当未每一个函数添加抛出异常时,可以方便判定错误出现的函数

3.生成exe格式可执行文件

  pyinstaller -F xxx.py 参考文档 https://blog.csdn.net/qq_35203425/article/details/78568141

  通过pyinstaller -F xxx.py -w生成的可执行文件,执行时,没有命令窗口

解决pyinstaller打包发布后的exe文件打开控制台闪退的问题

       1)先打开一个cmd

       2)cd到你的exe文件目录

       3)输入    .\***.exe

4.python-Tkinter图形界面开发

  1.按钮Button   2.文本框 Text  3.书签 notebook  4.单选按钮 Radiobutton  5.文件树 ttk.Treeview

5.数据库开发SQLite

界面:

程序(主要分为 PLC读取模块、PLC写入模块、主界面):

PLC读取模块(read_plc.py):

PLC点位:按所占内存大小分为 字软元件 位软元件按地址增加方式可分为 10进制 16进制

def create_command(start,length):
    """
    :param start: 起始软元件位置 例 L100
    :param length: 批量读取软元件个数
    :return: 返回读取命令
    """
    p=start[0]
    p = p.upper()   #地址转变为大写
    adress_dict={'M':'90','L':'92','F':'93'}                   #10进制——位软元件
    adress_dict_1={"R":"AF"}                                     #字软元件
    adress_dict_2 = {'X':'9C','Y':'9D',}                        #16进制——位软元件
    com='500000FFFF03000C00100001040100'                       #位软元件
    com_1 = '500000FFFF03000C00100001040000'                   #字软元件
    if p in adress_dict.keys():

        sta=str(hex(int(start[1:])))[2:]
        # print(sta)
        if len(sta)<=6:
            c1 = "0"*(6-len(sta))+sta
            c2=[]
            for i in range(0,6,2):
                c2.append(c1[i:i+2])
            c3=c2[::-1]
            sta_str=''.join(c3)
        # print(sta_str)
        l=str(hex(length))[2:]
        if len(l)<=4:
            l1="0"*(4-len(l))+l
            l2=[]
            for i in range(0,4,2):
                l2.append(l1[i:i+2])
            l3=l2[::-1]
            l_str=''.join(l3)
        return  bytes.fromhex(com+sta_str+adress_dict[p]+l_str)
    elif p in adress_dict_1.keys():
        sta = str(hex(int(start[1:])))[2:]
        # print(sta)
        if len(sta) <= 6:
            c1 = "0" * (6 - len(sta)) + sta
            c2 = []
            for i in range(0, 6, 2):
                c2.append(c1[i:i + 2])
            c3 = c2[::-1]
            sta_str = ''.join(c3)
        # print(sta_str)
        l = str(hex(length))[2:]
        if len(l) <= 4:
            l1 = "0" * (4 - len(l)) + l
            l2 = []
            for i in range(0, 4, 2):
                l2.append(l1[i:i + 2])
            l3 = l2[::-1]
            l_str = ''.join(l3)
        return bytes.fromhex(com_1 + sta_str + adress_dict_1[p] + l_str)

    elif p in adress_dict_2.keys():
        # sta = str(hex(int(start[1:])))[2:]
        sta=start[1:]
        # print(sta)
        if len(sta) <= 6:
            c1 = "0" * (6 - len(sta)) + sta
            c2 = []
            for i in range(0, 6, 2):
                c2.append(c1[i:i + 2])
            c3 = c2[::-1]
            sta_str = ''.join(c3)
        # print(sta_str)
        l = str(hex(length))[2:]
        if len(l) <= 4:
            l1 = "0" * (4 - len(l)) + l
            l2 = []
            for i in range(0, 4, 2):
                l2.append(l1[i:i + 2])
            l3 = l2[::-1]
            l_str = ''.join(l3)
        return bytes.fromhex(com + sta_str + adress_dict_2[p] + l_str)

    else:
        raise Exception('读取地址未添加')
        # print('读取地址未添加')

def data_any(data):
    """
    对0401 0001指令返回的数据进行解析
    :param data:  plc返回的指令
    :return:   以列表形式返回软元件的状态
    """
    cur_data=str(data.hex())
    # cur_data=data
    if len(cur_data)>=4 and cur_data[:4]=='d000':
        length=cur_data[14:18]
        err_code=cur_data[18:22]
        if err_code=='0000':
            l1=[]
            for i in range(0,4,2):
                l1.append(length[i:i+2])
            l2=''.join(l1[::-1])
            # print('l2',l2)
            l3=int(l2,16)
            # print('长度',l3)
            result=[int(i) for i in cur_data[22:]]
            if len(result)==(l3*2-4):
                return result
        else:
            return err_code
    else:
        raise Exception('解析数据错误')
def data_any_1(data):
    """
    对0401 0000指令返回的数据进行解析
    :param data:  plc返回的指令
    :return:   以列表形式返回软元件的状态
    """
    cur_data=str(data.hex())
    # cur_data=data
    if len(cur_data)>=4 and cur_data[:4]=='d000':
        length=cur_data[14:18]
        err_code=cur_data[18:22]
        if err_code=='0000':
            l1=[]
            for i in range(0,4,2):
                l1.append(length[i:i+2])
            l2=''.join(l1[::-1])
            # print('l2',l2)
            l3=int(l2,16)
            # print('长度',l3)
            # result=[int(i) for i in cur_data[22:]]
            j=0
            results,cur_result=[],[]
            if len(cur_data[22:])==(l3*2-4):
                for i in range(22,22+l3*2-4,2):
                    cur_result.append(cur_data[i:i+2])
                    j+=1
                    if j%2==0 and j!=0:
                        cur=''.join(cur_result[::-1])
                        results.append(int(cur,16))
                        cur_result=[]
            return results
        else:
            return err_code
    else:
        raise Exception('解析数据错误')



if __name__ == '__main__':
    # result=create_command('l100',17)
    # print(result)
    d='d00000ffff03000b000000000000000000010000'
    result=data_any(d)
    print(result)

PLC写入模块(write_plc.py)

import socket

def create_command(start,length,data):
    """
    :param start: 起始软元件位置 例 L100
    :param length: 批量读取软元件个数
    :return: 返回读取命令
    """
    p=start[0]
    p = p.upper()   #地址转变为大写
    adress_dict={'M':'90','L':'92','F':'93'}                   #10进制——位软元件
    adress_dict_1={"R":"AF"}                                     #字软元件
    adress_dict_2 = {'X':'9C','Y':'9D',}                        #16进制——位软元件
    com='500000FFFF03000C00100002140100'                       #位软元件
    com_1 = '500000FFFF03000C00100002140000'                   #字软元件
    if p in adress_dict.keys():

        sta=str(hex(int(start[1:])))[2:]
        # print(sta)
        if len(sta)<=6:
            c1 = "0"*(6-len(sta))+sta
            c2=[]
            for i in range(0,6,2):
                c2.append(c1[i:i+2])
            c3=c2[::-1]
            sta_str=''.join(c3)
        # print(sta_str)
        l=str(hex(length))[2:]
        if len(l)<=4:
            l1="0"*(4-len(l))+l
            l2=[]
            for i in range(0,4,2):
                l2.append(l1[i:i+2])
            l3=l2[::-1]
            l_str=''.join(l3)
        return  bytes.fromhex(com+"01"+sta_str+adress_dict[p]+data)
    elif p in adress_dict_2.keys():
        # sta = str(hex(int(start[1:])))[2:]
        sta=start[1:]
        # print(sta)
        if len(sta) <= 6:
            c1 = "0" * (6 - len(sta)) + sta
            c2 = []
            for i in range(0, 6, 2):
                c2.append(c1[i:i + 2])
            c3 = c2[::-1]
            sta_str = ''.join(c3)
        # print(sta_str)
        l = str(hex(length))[2:]
        if len(l) <= 4:
            l1 = "0" * (4 - len(l)) + l
            l2 = []
            for i in range(0, 4, 2):
                l2.append(l1[i:i + 2])
            l3 = l2[::-1]
            l_str = ''.join(l3)
        return bytes.fromhex(com+"01"+sta_str+adress_dict_2[p]+data)
    elif p in adress_dict_1.keys():
        sta = str(hex(int(start[1:])))[2:]
        # print(sta)
        if len(sta) <= 6:
            c1 = "0" * (6 - len(sta)) + sta
            c2 = []
            for i in range(0, 6, 2):
                c2.append(c1[i:i + 2])
            c3 = c2[::-1]
            sta_str = ''.join(c3)
        # print(sta_str)
        d = str(hex(data))[2:]
        if len(d) <= 4:
            l1 = "0" * (4 - len(d)) + d
            l2 = []
            for i in range(0, 4, 2):
                l2.append(l1[i:i + 2])
            l3 = l2[::-1]
            d_str = ''.join(l3)
        # l = str(hex(length))[2:]
        # if len(l) <= 4:
        #     l1 = "0" * (4 - len(l)) + l
        #     l2 = []
        #     for i in range(0, 4, 2):
        #         l2.append(l1[i:i + 2])
        #     l3 = l2[::-1]
        #     l_str = ''.join(l3)
        return bytes.fromhex(com_1 +"0100" +sta_str + adress_dict_1[p] +d_str)
    else:
        raise Exception('读取地址未添加')
        # print('读取地址未添加')

if __name__ == '__main__':
    # 创建 socket 对象
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 获取本地主机名
    # host = socket.gethostname()
    # host = '192.168.0.11'
    # 设置端口号
    # port = 6006
    # 连接服务,指定主机和端口
    # result = s.connect((host, port))
    # print(result)
    # 接收小于 1024 字节的数据
    # msg = s.recv(1024)

    data='01'  #置01 ON 置00 OFF
    com = create_command('l100', 1,data)
    print(com)
    # s.send(com)
    # s.close()

数据库创建、插入、查询:

"""
添加搬送、报警 历史记录表
data:2020-06-29
Auto:sunxiaomin
"""
import os
import sqlite3
import time
import numpy as np

class CreateTables():
    def __init__(self):

        self.init_tran_state = np.zeros(20, dtype=np.int32)
        self.init_alarm_state = np.zeros(450, dtype=np.int32)
        if not os.path.exists('MFLF.db'):
            print('数据库不存在,创建')
            # 建立数据库连接
            con = sqlite3.connect('MFLF.db')
            self.__create_transport_info(con, 'TRANSPORT')
            self.__create_transport_info(con, 'ALARM')
        # else:
        print('数据库已经存在')
        # 建立数据库连接
        self.con = sqlite3.connect('MFLF.db')
        self.cursor=self.con.cursor()
        # self.__select_table(cursor, 'COMMENT')
        # self.__select_table(cursor, 'ALARM')


    def __create_transport_info(self, con, name):
        # 创建cursor对象
        cursor = con.cursor()
        self.__create_tables(cursor, name)
        # 提交当前事物,如果未提交,对数据库的修改不会写入到数据库
        con.commit()

    def trans_data(self, tran_dict):
        # 创建cursor对象
        cursor = self.cursor
        # start = time.time()
        # ————————————搬送历史处理————————————
        cur_tran_state = np.array(list(tran_dict.values()),dtype=np.int32)
            # print('cur_tran_state',cur_tran_state)
        ##————————————MFLF01搬送历史————————————
        if cur_tran_state[0] == 1 and (cur_tran_state - self.init_tran_state)[1] == 1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'create'
            name = 'MFLF01'
            action = 'UP'
            cur_data_1 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_1)
                # print("插入数据",cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[0] == 1 and (cur_tran_state - self.init_tran_state)[2] == 1 and \
                    (cur_tran_state - self.init_tran_state)[1] == -1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'complete'
            name = 'MFLF01'
            action = 'UP'
            cur_data_1 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_1)
                # print("插入数据", cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[0] == 1 and (cur_tran_state - self.init_tran_state)[3] == 1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'create'
            name = 'MFLF01'
            action = 'DOWN'
            cur_data_1 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_1)
                # print("插入数据", cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[0] == 1 and (cur_tran_state - self.init_tran_state)[4] == 1 and \
                    (cur_tran_state - self.init_tran_state)[3] == -1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'complete'
            name = 'MFLF01'
            action = 'DOWN'
            cur_data_1 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_1)
                # print("插入数据", cur_data_1)
        ##————————————MFLF02搬送历史————————————
        if cur_tran_state[5] == 1 and (cur_tran_state - self.init_tran_state)[6] == 1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'create'
            name = 'MFLF02'
            action = 'UP'
            cur_data_2 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_2)
                # print("插入数据",cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[5] == 1 and (cur_tran_state - self.init_tran_state)[7] == 1 and \
                    (cur_tran_state - self.init_tran_state)[6] == -1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'complete'
            name = 'MFLF02'
            action = 'UP'
            cur_data_2 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_2)
                # print("插入数据", cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[5] == 1 and (cur_tran_state - self.init_tran_state)[8] == 1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'create'
            name = 'MFLF02'
            action = 'DOWN'
            cur_data_2 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_2)
                # print("插入数据", cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[5] == 1 and (cur_tran_state - self.init_tran_state)[9] == 1 and \
                    (cur_tran_state - self.init_tran_state)[8] == -1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'complete'
            name = 'MFLF02'
            action = 'DOWN'
            cur_data_2 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_2)
        ##————————————MFLF03搬送历史————————————
        if cur_tran_state[10] == 1 and (cur_tran_state - self.init_tran_state)[11] == 1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'create'
            name = 'MFLF03'
            action = 'UP'
            cur_data_3 = [data, name, state, action]
            # print("插入数据", cur_data_3)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_3)
                # print("插入数据",cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[10] == 1 and (cur_tran_state - self.init_tran_state)[12] == 1 and \
                    (cur_tran_state - self.init_tran_state)[11] == -1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'complete'
            name = 'MFLF03'
            action = 'UP'
            cur_data_3 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_3)
                # print("插入数据", cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[10] == 1 and (cur_tran_state - self.init_tran_state)[13] == 1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'create'
            name = 'MFLF03'
            action = 'DOWN'
            cur_data_3 = [data, name, state, action]
            # print("插入数据", cur_data_3)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_3)
                # print("插入数据", cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[10] == 1 and (cur_tran_state - self.init_tran_state)[14] == 1 and \
                    (cur_tran_state - self.init_tran_state)[13] == -1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'complete'
            name = 'MFLF03'
            action = 'DOWN'
            cur_data_3 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_3)
        ##————————————MFLF04搬送历史————————————
        if cur_tran_state[15] == 1 and (cur_tran_state - self.init_tran_state)[16] == 1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'create'
            name = 'MFLF04'
            action = 'UP'
            cur_data_4 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_4)
                # print("插入数据",cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[15] == 1 and (cur_tran_state - self.init_tran_state)[17] == 1 and \
                    (cur_tran_state - self.init_tran_state)[16] == -1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'complete'
            name = 'MFLF04'
            action = 'UP'
            cur_data_4 = [data, name, state, action]
            # print("插入数据", cur_data_4)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_4)
                # print("插入数据", cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[15] == 1 and (cur_tran_state - self.init_tran_state)[18] == 1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'create'
            name = 'MFLF04'
            action = 'DOWN'
            cur_data_4 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_4)
                # print("插入数据", cur_data_1)
            # self.init_tran_state = cur_tran_state
        elif cur_tran_state[15] == 1 and (cur_tran_state - self.init_tran_state)[19] == 1 and \
                    (cur_tran_state - self.init_tran_state)[18] == -1:
            data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            state = 'complete'
            name = 'MFLF04'
            action = 'DOWN'
            cur_data_4 = [data, name, state, action]
            # print("插入数据", cur_data_1)
            self.__insert_table(cursor, 'TRANSPORT', cur_data_4)
        self.init_tran_state = cur_tran_state

        # 提交当前事物,如果未提交,对数据库的修改不会写入到数据库
        self.con.commit()
        # end = time.time()
        # time.sleep(1 - (end - start))

    def alarm_data(self,result,alarm_dict):
        cur_result_1 = np.array(result[:450], dtype=np.int32)
        # cur_result_1 = np.array([0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0], dtype=np.int32)
        cur_result = cur_result_1 - self.init_alarm_state
        self.init_alarm_state = cur_result_1

        result = [str(i) for i in cur_result]
        result_alarm, result_reset = result, result
        "------获取报警序列------"
        indexs_alarm = []
        l_a = 0
        while len(result_alarm) > 0 and ('1' in result_alarm):
            # ind=result_alarm.find('1')
            ind = result_alarm.index('1')
            # if ind!=-1:
            indexs_alarm.append(ind + l_a)
            result_alarm = result_alarm[ind + 1:]
            l_a += ind + 1
        "------获取恢复序列------"
        indexs_reset = []
        l_r = 0
        while len(result_reset) > 0 and ('-1' in result_reset):
            # ind = indexs_reset.find('-1')
            ind = result_reset.index('-1')
            # if ind != -1:
            indexs_reset.append(ind + l_r)
            result_reset = indexs_reset[ind + 1:]
            l_r += ind + 1
        "------数据库插入报警信息------"
        if len(indexs_alarm) > 0:
            for index in indexs_alarm:
                index = "F" + str(int(index))
                # 向表中查询数据
                alarm_text = alarm_dict[index]
                data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                state = 'alarm'
                # cur_data = ["{}".format(data),"{}".format(state) , "{}".format(index), "{}".format(list(alarm_text)[0][2]) ]
                cur_data = [data, state, index, alarm_text]
                print('插入数据为', cur_data)
                self.__insert_table(self.cursor, 'ALARM', cur_data)
        "------数据库插入恢复信息------"
        if len(indexs_reset) > 0:
            for index in indexs_reset:
                index =  "F" + str(int(index))
                # 向表中查询数据
                alarm_text =alarm_dict[index]
                data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
                state = 'reset'
                # cur_data = ["{}".format(data), "{}".format(state), "{}".format(index),
                #             "{}".format(list(alarm_text)[0][2])]
                cur_data = [data, state, index, alarm_text]
                print('插入数据为', cur_data)
                self.__insert_table(self.cursor, 'ALARM', cur_data)


    def __create_tables(self, cursor, name):
        # 创建表
        try:
            if name == 'COMMENT':
                cursor.execute(
                    """
                    CREATE TABLE {}(
                    ID    INTEGER PRIMARY KEY AUTOINCREMENT,
                    NAME  TEXT,
                    ALARM TEXT)
                    """.format(name)
                )
            elif name == 'ALARM':
                cursor.execute(
                    """
                    CREATE TABLE {}(
                    DATA      TEXT,
                    STATE     TEXT,
                    NAME      TEXT,
                    ALARM     TEXT)
                    """.format(name)
                )
            elif name == 'TRANSPORT':
                cursor.execute(
                    """
                    CREATE TABLE {}(
                    DATA      TEXT,
                    NAME      TEXT,
                    STATE     TEXT,
                    ACTION     TEXT
                    )
                    """.format(name)
                )

        except Exception as err:
            print(err)
            print('{}表删除中...'.format(name))
            cursor.execute(
                """
                DROP TABLE {}
                """.format(name)
            )
            print('{}表已经删除,正在重新创建...'.format(name))
            if name == 'COMMENT':
                cursor.execute(
                    """
                    CREATE TABLE {}(
                    ID    INTEGER PRIMARY KEY AUTOINCREMENT,
                    NAME  TEXT,
                    ALARM TEXT)
                    """.format(name)
                )
            elif name == 'ALARM':
                cursor.execute(
                    """
                    CREATE TABLE {}(
                    DATA TEXT,
                    STATE  TEXT,
                    NAME      TEXT,
                    ALARM     TEXT)
                    """.format(name)
                )
            elif name == 'TRANSPORT':
                cursor.execute(
                    """
                    CREATE TABLE {}(
                    DATA      TEXT,
                    NAME      TEXT,
                    STATE     TEXT,
                    ACTION     TEXT
                    )
                    """.format(name)
                )
            print('{}表创建成功'.format(name))

    def __insert_table(self, cursor, name, data):
        # 表中添加数据
        if name == 'COMMENT':
            # print('正常插入')
            cursor.execute(
                """
                INSERT INTO {}(NAME,ALARM)
                VALUES ({},{})
                """.format(name, data[0], data[1])
            )
        elif name == 'ALARM':
            cursor.execute(
                """
                INSERT INTO {}(DATA,STATE,NAME,ALARM)
                VALUES ("{}","{}","{}","{}")
                """.format(name, data[0], data[1], data[2], data[3])
            )
        elif name == 'TRANSPORT':
            cursor.execute(
                """
                INSERT INTO {}(DATA,NAME,STATE,ACTION)
                VALUES ("{}","{}","{}","{}")
                """.format(name, data[0], data[1], data[2], data[3])
            )
    def insert_table_test(self, name, data):
        cursor = self.cursor
        # 表中添加数据
        if name == 'COMMENT':
            # print('正常插入')
            cursor.execute(
                """
                INSERT INTO {}(NAME,ALARM)
                VALUES ({},{})
                """.format(name, data[0], data[1])
            )
        elif name == 'ALARM':
            cursor.execute(
                """
                INSERT INTO {}(DATA,STATE,NAME,ALARM)
                VALUES ("{}","{}","{}","{}")
                """.format(name, data[0], data[1], data[2], data[3])
            )
        elif name == 'TRANSPORT':
            cursor.execute(
                """
                INSERT INTO {}(DATA,NAME,STATE,ACTION)
                VALUES ("{}","{}","{}","{}")
                """.format(name, data[0], data[1], data[2], data[3])
            )
        self.con.commit()
    def select_table(self, name,start,end):
        cursor = self.cursor
        # 向表中查询数据
        result = cursor.execute(
            """
            SELECT * FROM {} WHERE DATA BETWEEN "{}" AND "{}"
            """.format(name,start,end)
        )
        # result = cursor.execute(
        #     """
        #     SELECT * FROM {}
        #     """.format(name)
        # )
        # print(list(result))
        return list(result)


if __name__ == '__main__':

    creat = CreateTables()
    # creat.select_table("ALARM","2020-06-29 00:00:00", "2020-06-30 00:00:00")
    for i in range(20):
        data = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        state = 'create'
        name = 'MFLF01'
        action = 'UP'
        cur_data_1 = [data, name, state, action]
        creat.insert_table_test("ALARM",cur_data_1)
        time.sleep(1)

主程序:

实际应用中存在多个界面,本处仅列出一个程序样例

# 通过notebook实现窗口切换
from tkinter.dialog import *
# import  tkinter as tk
from tkinter import *
from tkinter import ttk
import os
import sqlite3
import time
import socket
import threading
#import pandas
#import numpy as np
import read_plc as plc
import write_plc as wplc
#from create_table_0628 import CreateTables as tables
class LFT_HOST():
    def __init__(self):
        self.com_path = "comment.csv"
        self.err_dict = {}
        self.trans_dict={}
        # self.create_alarm_info()
        # self.tables=tables()
        self.host = '192.168.0.11'
        self.port = 6006
        # 创建 socket 对象
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 连接服务,指定主机和端口
        result = self.s.connect((self.host, self.port))
        print("连接结果",result)
        self.vars_dict={}
        self.root=Tk()
        self.var1_1,self.var2_1,self.var3_1,self.var4_1=StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_2,self.var2_2,self.var3_2,self.var4_2 = StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_3,self.var2_3,self.var3_3,self.var4_3 = StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_4,self.var2_4,self.var3_4,self.var4_4 = StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_5,self.var2_5,self.var3_5,self.var4_5 = StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_12,self.var2_12,self.var3_12,self.var4_12 = StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_6,self.var2_6,self.var3_6,self.var4_6 = StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_7,self.var2_7,self.var3_7,self.var4_7 = StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_8,self.var2_8,self.var3_8,self.var4_8 = StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_9,self.var2_9,self.var3_9,self.var4_9 = StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_10,self.var2_10,self.var3_10,self.var4_10 = StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_11,self.var2_11,self.var3_11,self.var4_11 = StringVar(),StringVar(),StringVar(),StringVar()
        self.var1_13, self.var2_13, self.var3_13, self.var4_13 = StringVar(), StringVar(), StringVar(), StringVar()
        self.var1_14, self.var2_14, self.var3_14, self.var4_14 = StringVar(), StringVar(), StringVar(), StringVar()
        self.var1_15, self.var2_15, self.var3_15, self.var4_15 = StringVar(), StringVar(), StringVar(), StringVar()
        self.var1_16, self.var2_16, self.var3_16, self.var4_16 = StringVar(), StringVar(), StringVar(), StringVar()
        self.var1_17, self.var2_17, self.var3_17, self.var4_17 = StringVar(), StringVar(), StringVar(), StringVar()
        self.var1_18, self.var2_18, self.var3_18, self.var4_18 = StringVar(), StringVar(), StringVar(), StringVar()
        # self.interface_1()
        # self.home_face()
        #self.data_proces()
        t1=threading.Thread(target=self.data_proces,args=[])
        t1.setDaemon(True)
        t1.start()
        # self.root.mainloop()
    def create_alarm_info(self):
        # 生成报警信息字典
        with open(self.com_path, encoding='utf-16') as f:
            # utf-16与utf-8的区别
            results = f.read().splitlines()
            for data_str in results[2:]:
                result = data_str.split('\t')
                index = result[0].strip(result[0][0])
                if index[0] == "F":
                    self.err_dict[index] = result[1].strip(result[1][0])
    def data_proces(self):
        # 数据处理,显示与保存
        # 创建 socket 对象
        #self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 连接服务,指定主机和端口
        #result = self.s.connect((self.host, self.port))
        #print("连接结果",result)
        while True:
            start=time.time()
            try:
                ##——————状态界面显示——————
                face_adress_1,face_adress_2,face_adress_3,face_adress_4="X70","L2101","M100","R110"
                face_len_1,face_len_2,face_len_3,face_len_4=4720,10,380,310
                ###——————X系列——————
                com_1 = plc.create_command(face_adress_1,face_len_1)
                self.s.send(com_1)
                msg_1 = self.s.recv(5000)
                # s.close()
                result_1 = plc.data_any(msg_1)
                self.data_analysis_x(result_1,face_adress_1)
                ###——————L系列——————
                com_2 = plc.create_command(face_adress_2, face_len_2)
                self.s.send(com_2)
                msg_2 = self.s.recv(1024)
                # s.close()
                result_2 = plc.data_any(msg_2)
                self.data_analysis_l(result_2, face_adress_2)
                ###——————M系列——————
                com_3 = plc.create_command(face_adress_3, face_len_3)
                self.s.send(com_3)
                msg_3 = self.s.recv(1024)
                    # s.close()
                result_3 = plc.data_any(msg_3)
                self.data_analysis_m(result_3, face_adress_3)
                ###——————R系列——————
                com_4 = plc.create_command(face_adress_4, face_len_4)
                self.s.send(com_4)
                msg_4 = self.s.recv(1024)
                    # s.close()
                result_4 = plc.data_any_1(msg_4)
                self.data_analysis_r(result_4, face_adress_4)
            except:
                print("数据读取错误")
            else:
                ###——————MFLF01系列——————
                self.__aflf08_set()

            end = time.time()
            #print(end-start)
            #time.sleep(0.5-(end-start))
            ##——————搬送历史记录——————
            ##——————报警历史记录——————
    def data_analysis_x(self,data,start):
        res_vals=["X74","X77","X78","X79",   "X80","X83","X84","X87", "X88","X89","X8A",  "X8B","X8C","X8D",
                  "X1007", "X1010","X1013"]
        for val in res_vals:
            index=int(val[1:],16)-int(start[1:],16)
            self.vars_dict[val]=data[index]
    def data_analysis_l(self,data,start):
        res_vals =["L2101","L2102","L2105", ]
        for val in res_vals:
            index=int(val[1:])-int(start[1:])
            self.vars_dict[val]=data[index]
    def data_analysis_m(self,data,start):
        res_vals =["M100","M101","M102","M106","M109","M140","M160"]
        for val in res_vals:
            index=int(val[1:])-int(start[1:])
            self.vars_dict[val]=data[index]
    def data_analysis_r(self,data,start):
        res_vals =["R110"]
        for val in res_vals:
            index=int(val[1:])-int(start[1:])
            self.vars_dict[val]=data[index]
    def data_analysis_f(self,data,start):
        # 数据库插入报警内容
        self.tables.alarm_data(data,self.err_dict)
        self.errs_list = []
        data_str=[str(s) for s in data]
        data_str1="".join(data_str)
        start_i=0
        while start_i<len(data_str1):
            index_err=data_str1.find("1",start_i)
            if index_err>=0:
                self.errs_list.append(int(index_err))
                # 数据库插入报警内容
                # alam_index="F"+str(index_err)
                start_i=index_err+1
            else:
                break
    def __aflf08_set(self):
        if self.vars_dict["M100"]:
            self.var1_1.set("1")
        else:
            self.var1_1.set("0")
        # self.alarm_text_1.delete(1.0, "end")
        if self.vars_dict["M101"] or self.vars_dict["M102"] or self.vars_dict["M106"]:
            self.var1_2.set("1")
        else:
            self.var1_2.set("0")
        if self.vars_dict["M109"]:
            self.var1_16.set("1")
        else:
            self.var1_16.set("0")
        self.pos_text_1.delete(1.0, "end")
        self.pos_text_1.insert("insert", self.vars_dict["R110"])
        if self.vars_dict["M160"]:
            self.var1_10.set("1")
        else:
            self.var1_10.set("0")
        if self.vars_dict["X74"]:
            self.var1_11.set("1")
        elif self.vars_dict["X1007"]:
            self.var1_11.set("2")
        else:
            self.var1_11.set("0")
        if self.vars_dict["L2101"]:
            self.var1_13.set("1")
        else:
            self.var1_13.set("0")
        if self.vars_dict["L2102"]:
            self.var1_14.set("1")
        else:
            self.var1_14.set("0")
        if self.vars_dict["L2105"]:
            self.var1_15.set("1")
        else:
            self.var1_15.set("0")
        if self.vars_dict["X87"]:
            self.var1_3.set("2")
        elif self.vars_dict["X84"]:
            self.var1_3.set("1")
        else:
            self.var1_3.set("0")
        if self.vars_dict["X1013"]:
            self.var1_4.set("2")
        elif self.vars_dict["X1010"]:
            self.var1_4.set("1")
        else:
            self.var1_4.set("0")
        if self.vars_dict["X83"]:
            self.var1_5.set("2")
        elif self.vars_dict["X80"]:
            self.var1_5.set("1")
        else:
            self.var1_5.set("0")
        if self.vars_dict["X8C"]:
            self.var1_12.set("2")
        elif self.vars_dict["X8D"]:
            self.var1_12.set("1")
        else:
            self.var1_12.set("0")
        if self.vars_dict["X88"]:
            self.var1_17.set("2")
        elif self.vars_dict["X89"]:
            self.var1_17.set("1")
        else:
            self.var1_17.set("0")
        if self.vars_dict["X8A"]:
            self.var1_18.set("2")
        elif self.vars_dict["X8B"]:
            self.var1_18.set("1")
        else:
            self.var1_18.set("0")
        if self.vars_dict["X77"]:
            self.var1_7.set("1")
        else:
            self.var1_7.set("0")
        if self.vars_dict["X78"]:
            self.var1_8.set("1")
        else:
            self.var1_8.set("0")
        if self.vars_dict["X79"]:
            self.var1_9.set("1")
        else:
            self.var1_9.set("0")
        if self.vars_dict["M140"]:
            self.var1_6.set("1")
        else:
            self.var1_6.set("0")
    def reset(self):
        # 1.manual
        m1_com = wplc.create_command('L11', 1, "01")
        self.s.send(m1_com)
        msg=self.s.recv(1024)
        m2_com = wplc.create_command('L11', 1, "00")
        self.s.send(m2_com)
        msg=self.s.recv(1024)
        # 2.RESET
        r1_com = wplc.create_command('L13', 1, "01")
        self.s.send(r1_com)
        msg=self.s.recv(1024)
        r2_com = wplc.create_command('L13', 1, "00")
        self.s.send(r2_com)
        msg=self.s.recv(1024)
        # 3.AUTO RUN READY
        a1_com = wplc.create_command('L6301', 1, "01")
        self.s.send(a1_com)
        msg=self.s.recv(1024)
        time.sleep(0.5)
        # r_com = wplc.create_command('L10', 1, "00")
        # self.s.send(r_com)
        
    def auto(self):
        # AUTO
        a2_com = wplc.create_command('L10', 1, "01")
        self.s.send(a2_com)
        msg=self.s.recv(1024)
        a3_com = wplc.create_command('L10', 1, "00")
        self.s.send(a3_com)
        msg=self.s.recv(1024)
        # AUTO START
        a4_com = wplc.create_command('X6B', 1, "01")
        self.s.send(a4_com)
        msg=self.s.recv(1024)
        a5_com = wplc.create_command('X6B', 1, "00")
        self.s.send(a5_com)
        msg=self.s.recv(1024)
                

    def home_face(self):
        # 设定主窗口
        self.root.title("电梯上位机监控程序")
        self.root.geometry("750x400+50+100")
        self.root.update()
        self.root.resizable(width=False,height=False)
        notebook=ttk.Notebook(self.root)
        # 创建不同的Frame,相当于不同的桌布
        ##——————编辑状态界面——————
        face1 = Frame(self.root, width=330, height=280)
        face1.grid(row=0, column=0, rowspan=10, columnspan=13, sticky='EW', pady=1, padx=1)
        ###————————MFLF01界面开发——————
        # DOOR=["L1 DOOR","L2 DOOR","L3 DOOR","CLAMP"]
        DOOR = ["L1 DOOR", "L2 DOOR", "Cage DOOR","CLAMP(OFF/ON)","FLOAT(D/U)","CENT(B/F)"]
        labelfrm_1 = LabelFrame(face1, text='AFLF08', width=100, height=55)
        labelfrm_1.grid(row=0, column=0, ipadx=1, ipady=1, padx=1, pady=1)
        mflf01_v = [self.var1_3, self.var1_4, self.var1_5, self.var1_12, self.var1_17,self.var1_18]
        Label(labelfrm_1, text="RUN").grid(row=0, column=0, sticky='EW', pady=5, padx=5)
        Radiobutton(labelfrm_1,variable=self.var1_1, value='1').grid(row=0, column=1, sticky='EW', pady=5, padx=5)
        self.var1_1.set('0')
        Label(labelfrm_1, text="ALARM").grid(row=0, column=2, sticky='EW', pady=5, padx=5)
        Radiobutton(labelfrm_1, variable=self.var1_2, value='1').grid(row=0, column=3, sticky='EW', pady=5, padx=5)
        self.var1_2.set('0')
        # but1 = Button(labelfrm_1, text='MANUAL', command=self.manual, width=16, height=1)
        # but1.grid(row=0, column=4, sticky='EW', pady=5, padx=5)
        but2 = Button(labelfrm_1, text='RESET', command=self.reset, width=16, height=1)
        but2.grid(row=0, column=4, sticky='EW', pady=5, padx=5)
        but3 = Button(labelfrm_1, text='AUTO', command=self.auto, width=16, height=1)
        but3.grid(row=0, column=5, sticky='EW', pady=5, padx=5)
        # Label(labelfrm_1, text="ALARM TEXT").grid(row=0, column=4, sticky='EW', pady=5, padx=5)
        # self.alarm_text_1=Text(labelfrm_1, width=20, height=1, )
        # self.alarm_text_1.grid(row=0, column=5, sticky='EW', pady=5, padx=5,columnspan=5)
        Label(labelfrm_1, text="AUTO RUN READY").grid(row=0, column=6, sticky='EW', pady=5, padx=5)
        Radiobutton(labelfrm_1, variable=self.var1_16, value='1').grid(row=0, column=7, sticky='EW', pady=5, padx=5)
        self.var1_16.set('0')
        labelfrm_1_1 = LabelFrame(labelfrm_1, text='DOOR', width=100, height=55)
        labelfrm_1_1.grid(row=1, column=0,rowspan=5, columnspan=4, ipadx=5, ipady=1, padx=5, pady=1)

        Label(labelfrm_1_1, text="OPEN").grid(row=1, column=1, sticky='EW', pady=5, padx=5)
        Label(labelfrm_1_1, text="CLOSE").grid(row=1, column=2, sticky='EW', pady=5, padx=5)
        Label(labelfrm_1_1, text="NO USE").grid(row=1, column=3, sticky='EW', pady=5, padx=5)
        Radiobutton(labelfrm_1_1, variable=self.var1_13, value='1').grid(row=2 , column=3, sticky='EW', pady=5,
                                                                        padx=5)
        Radiobutton(labelfrm_1_1, variable=self.var1_14, value='1').grid(row=3, column=3, sticky='EW', pady=5,
                                                                         padx=5)
        Radiobutton(labelfrm_1_1, variable=self.var1_15, value='1').grid(row=4, column=3, sticky='EW', pady=5,
                                                                         padx=5)
        self.var1_13.set('0')
        self.var1_14.set('0')
        self.var1_15.set('0')
        for i,text in enumerate(DOOR):
            mflf01_v[i].set("0")
            Label(labelfrm_1_1, text=text).grid(row=2+i, column=0, sticky='EW', pady=5, padx=5)
            Radiobutton(labelfrm_1_1, variable=mflf01_v[i], value='1').grid(row=2+i, column=1, sticky='EW', pady=5, padx=5)
            Radiobutton(labelfrm_1_1, variable=mflf01_v[i], value='2').grid(row=2+i, column=2, sticky='EW', pady=5, padx=5)

        labelfrm_1_2 = LabelFrame(labelfrm_1, text='CST', width=100, height=55)
        labelfrm_1_2.grid(row=1, column=4, rowspan=2, columnspan=6, ipadx=5, ipady=5, padx=5, pady=5)
        Label(labelfrm_1_2, text="good pos").grid(row=0, column=0, sticky='EW', pady=5, padx=5, columnspan=1)
        Radiobutton(labelfrm_1_2, variable=self.var1_6, value='1').grid(row=0, column=1, sticky='EW', pady=5, padx=5)
        self.var1_6.set("0")

        Label(labelfrm_1_2, text="input safty" ,width=10, height=1).grid(row=1, column=0, sticky='EW', pady=5, padx=5)
        Radiobutton(labelfrm_1_2, variable=self.var1_7, value='1').grid(row=1, column=1, sticky='EW', pady=5, padx=5)
        self.var1_7.set("0")
        Label(labelfrm_1_2, text="decel",width=10, height=1).grid(row=1, column=2, sticky='EW', pady=5, padx=5)
        Radiobutton(labelfrm_1_2, variable=self.var1_8, value='1').grid(row=1, column=3, sticky='EW', pady=5, padx=5)
        self.var1_8.set("0")
        Label(labelfrm_1_2, text="stop",width=10, height=1).grid(row=1, column=4, sticky='EW', pady=5, padx=5)
        Radiobutton(labelfrm_1_2, variable=self.var1_9, value='1').grid(row=1, column=5, sticky='EW', pady=5, padx=5)
        self.var1_9.set("0")
        labelfrm_1_3 = LabelFrame(labelfrm_1, text='LFT', width=100, height=55)
        labelfrm_1_3.grid(row=3, column=4,rowspan=2, columnspan=6, ipadx=5, ipady=5, padx=5, pady=5)
        Label(labelfrm_1_3, text="POS OK",width=10, height=1).grid(row=0, column=0, sticky='EW', pady=5, padx=5)
        Radiobutton(labelfrm_1_3, variable=self.var1_10, value='1').grid(row=0, column=1, sticky='EW', pady=5, padx=5)
        self.var1_10.set("0")
        Label(labelfrm_1_3, text="CUR POS ",width=10, height=1).grid(row=0, column=2, sticky='EW', pady=5, padx=5)
        self.pos_text_1 = Text(labelfrm_1_3, width=10, height=1, )
        self.pos_text_1.grid(row=0, column=3,rowspan=1,columnspan=2, sticky='EW', pady=5, padx=5)
        Label(labelfrm_1_3, text="L1",width=10, height=1).grid(row=1, column=0, sticky='EW', pady=5, padx=5)
        Radiobutton(labelfrm_1_3, variable=self.var1_11, value='1').grid(row=1, column=1, sticky='EW', pady=5, padx=5)
        Label(labelfrm_1_3, text="L2",width=10, height=1).grid(row=1, column=2, sticky='EW', pady=5, padx=5)
        Radiobutton(labelfrm_1_3, variable=self.var1_11, value='2').grid(row=1, column=3, sticky='EW', pady=5, padx=5)
        # Label(labelfrm_1_3, text="L3",width=10, height=1).grid(row=1, column=4, sticky='EW', pady=5, padx=5)
        # Radiobutton(labelfrm_1_3, variable=self.var1_11, value='3').grid(row=1, column=5, sticky='EW', pady=5, padx=5)
        self.var1_11.set("0")
        notebook.add(face1, text="LFT 状态")
        notebook.grid()

        self.root.mainloop()
#
if __name__ == '__main__':
    lft=LFT_HOST()
    lft.home_face()

 

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 三菱PLC上位机开发以太网是一种基于以太网通信的软件开发技术,用于与三菱PLC进行远程通信和监控控制。以太网是一种网络通信协议,可以实现高速、可靠的数据传输。 在三菱PLC上位机开发中,以太网通信可以通过网络连接将PLC上位机进行数据交换和控制操作。通过以太网通信,上位机可以监控PLC的运行状态、读取和写入PLC的内部寄存器和数据等。 3VC是三菱公司推出的一种PLC编程软件开发平台,可以用于开发和管理三菱PLC的程序和数据。在VC开发环境下,可以实现与三菱PLC之间的以太网通信。开发人员可以使用VC编写程序,通过以太网与PLC进行通信和控制。通过VC开发以太网通信功能,可以实现对PLC的远程监控和控制,提高生产效率和智能化程度。 在PLC上位机开发中,以太网通信具有很多优势。首先,以太网通信速度快,可以实现高效的数据传输。其次,以太网具有较高的稳定性和可靠性,可以保证数据传输的安全性。此外,以太网通信还支持多种通信协议,可以与其他设备进行互联互通。 总之,三菱PLC上位机开发以太网是一种重要的技术手段,能够实现对PLC的远程监控和控制。通过VC开发环境和以太网通信功能,可以提高生产自动化水平,提高工作效率,实现智能化生产。 ### 回答2: VC是Visual C++(可视化C++)的简称,是一种集成开发环境(IDE),用于开发使用C++语言编写的应用程序。Visual C++可以用于开发各种不同类型的软件,包括上位机软件。 三菱PLC是三菱电机公司生产的一种可编程逻辑控制器,广泛应用于工业自动化领域。通过使用VC开发的上位机软件,可以实现与三菱PLC之间的通讯和数据交互。 现在,随着以太网技术的发展,越来越多的上位机软件开始采用以太网作为与PLC通讯的接口。以太网能够提供更高的数据传输速率和更广泛的网络覆盖范围,从而提高了上位机PLC之间的通讯效率和可靠性。 在使用VC开发以太网通讯功能时,我们可以利用VC提供的网络编程接口和相关库函数进行开发。通过网络编程,可以实现基于TCP/IP协议的数据传输和通讯。 具体开发步骤包括:首先,要建立起上位机PLC之间的网络连接,可以通过PLC的IP地址和端口号进行连接。然后,我们需要编写相应的代码来实现通讯协议和数据交换的功能。这些代码可以包括建立连接、发送数据、接收数据等操作。 通过VC开发的上位机软件可以实现与三菱PLC之间的实时数据监控、数据采集、参数配置、远程控制等功能。这些功能可以提高生产环境中的自动化水平和生产效率。 总结起来,使用VC开发三菱PLC上位机软件,结合以太网技术,可以实现高效、可靠的通讯和数据交互。这对于工业自动化领域来说是非常重要的,能够提高生产效率和质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值