Python testXxxxxSerial xxx调试助手 代码 存

文章展示了使用PyQt5创建GUI界面的代码,包括串口选择、连接和断开按钮、速度设置等功能。同时,还定义了一个SerialUtile类用于串口操作,如打开、关闭、发送消息等。此外,文中还包含了多个事件处理函数,用于响应用户操作,如设置速度、开始/停止动作等。
摘要由CSDN通过智能技术生成

Log复制过来,略。

ui界面生成:

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'My_ScreenSerial.ui'
#
# Created by: PyQt5 UI code generator 5.15.9
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(590, 470)
        MainWindow.setMouseTracking(False)
        MainWindow.setStyleSheet("background-color: rgb(235, 240,240);")
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 251, 121))
        self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.Serial = QtWidgets.QLabel(self.verticalLayoutWidget)
        self.Serial.setScaledContents(False)
        self.Serial.setAlignment(QtCore.Qt.AlignCenter)
        self.Serial.setWordWrap(False)
        self.Serial.setIndent(-1)
        self.Serial.setObjectName("Serial")
        self.horizontalLayout.addWidget(self.Serial)
        self.Serial_List = QtWidgets.QComboBox(self.verticalLayoutWidget)
        self.Serial_List.setObjectName("Serial_List")
        self.horizontalLayout.addWidget(self.Serial_List)
        self.verticalLayout.addLayout(self.horizontalLayout)
        self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_2.setObjectName("horizontalLayout_2")
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_2.addItem(spacerItem)
        self.pushButton_6 = QtWidgets.QPushButton(self.verticalLayoutWidget)
        self.pushButton_6.setStyleSheet("background-color: rgb(255, 160, 180);")
        self.pushButton_6.setObjectName("pushButton_6")
        self.horizontalLayout_2.addWidget(self.pushButton_6)
        self.pushButton = QtWidgets.QPushButton(self.verticalLayoutWidget)
        self.pushButton.setStyleSheet("background-color: rgb(215, 230, 255);")
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout_2.addWidget(self.pushButton)
        self.verticalLayout.addLayout(self.horizontalLayout_2)
        self.label_4 = QtWidgets.QLabel(self.verticalLayoutWidget)
        self.label_4.setAlignment(QtCore.Qt.AlignCenter)
        self.label_4.setObjectName("label_4")
        self.verticalLayout.addWidget(self.label_4)
        self.verticalLayoutWidget_3 = QtWidgets.QWidget(self.centralwidget)
        self.verticalLayoutWidget_3.setGeometry(QtCore.QRect(310, 10, 251, 121))
        self.verticalLayoutWidget_3.setObjectName("verticalLayoutWidget_3")
        self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_3)
        self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout_4.setObjectName("verticalLayout_4")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.label = QtWidgets.QLabel(self.verticalLayoutWidget_3)
        self.label.setAlignment(QtCore.Qt.AlignCenter)
        self.label.setObjectName("label")
        self.horizontalLayout_3.addWidget(self.label)
        self.verticalLayout_3 = QtWidgets.QVBoxLayout()
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.lineEdit = QtWidgets.QLineEdit(self.verticalLayoutWidget_3)
        self.lineEdit.setObjectName("lineEdit")
        self.verticalLayout_3.addWidget(self.lineEdit)
        self.horizontalLayout_3.addLayout(self.verticalLayout_3)
        self.verticalLayout_2.addLayout(self.horizontalLayout_3)
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_4.addItem(spacerItem1)
        self.pushButton_2 = QtWidgets.QPushButton(self.verticalLayoutWidget_3)
        self.pushButton_2.setStyleSheet("background-color: rgb(220, 220, 255);")
        self.pushButton_2.setObjectName("pushButton_2")
        self.horizontalLayout_4.addWidget(self.pushButton_2)
        self.verticalLayout_2.addLayout(self.horizontalLayout_4)
        self.horizontalLayout_5 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_5.setObjectName("horizontalLayout_5")
        self.label_2 = QtWidgets.QLabel(self.verticalLayoutWidget_3)
        self.label_2.setAlignment(QtCore.Qt.AlignCenter)
        self.label_2.setObjectName("label_2")
        self.horizontalLayout_5.addWidget(self.label_2)
        self.horizontalLayout_7 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_7.addItem(spacerItem2)
        self.label_3 = QtWidgets.QLabel(self.verticalLayoutWidget_3)
        self.label_3.setAlignment(QtCore.Qt.AlignCenter)
        self.label_3.setObjectName("label_3")
        self.horizontalLayout_7.addWidget(self.label_3)
        spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.horizontalLayout_7.addItem(spacerItem3)
        self.horizontalLayout_5.addLayout(self.horizontalLayout_7)
        self.verticalLayout_2.addLayout(self.horizontalLayout_5)
        self.verticalLayout_4.addLayout(self.verticalLayout_2)
        self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_3.setGeometry(QtCore.QRect(310, 140, 251, 61))
        self.pushButton_3.setStyleSheet("background-color: rgb(180, 230, 220);\n"
"font: 12pt \"黑体\";")
        self.pushButton_3.setObjectName("pushButton_3")
        self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_4.setGeometry(QtCore.QRect(310, 210, 251, 61))
        self.pushButton_4.setStyleSheet("background-color: rgb(250, 200, 150);\n"
"font: 12pt \"黑体\";")
        self.pushButton_4.setObjectName("pushButton_4")
        self.pushButton_5 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_5.setGeometry(QtCore.QRect(310, 280, 251, 61))
        self.pushButton_5.setStyleSheet("background-color: rgb(150, 205, 200);\n"
"font: 12pt \"黑体\";")
        self.pushButton_5.setObjectName("pushButton_5")
        self.pushButton_7 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_7.setGeometry(QtCore.QRect(10, 280, 121, 61))
        self.pushButton_7.setStyleSheet("background-color: rgb(255, 255, 255);")
        self.pushButton_7.setObjectName("pushButton_7")
        self.pushButton_8 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_8.setGeometry(QtCore.QRect(140, 280, 121, 61))
        self.pushButton_8.setAutoFillBackground(False)
        self.pushButton_8.setStyleSheet("background-color: rgb(245, 245, 245);")
        self.pushButton_8.setObjectName("pushButton_8")
        self.pushButton_9 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_9.setGeometry(QtCore.QRect(10, 210, 251, 61))
        self.pushButton_9.setAutoFillBackground(False)
        self.pushButton_9.setStyleSheet("background-color: rgb(255, 210, 0);\n"
"font: 12pt \"黑体\";")
        self.pushButton_9.setObjectName("pushButton_9")
        self.pushButton_10 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_10.setGeometry(QtCore.QRect(10, 140, 251, 61))
        self.pushButton_10.setStyleSheet("background-color: rgb(200, 100, 100);\n"
"font: 12pt \"黑体\";")
        self.pushButton_10.setObjectName("pushButton_10")
        self.pushButton_11 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_11.setGeometry(QtCore.QRect(410, 350, 151, 41))
        self.pushButton_11.setAutoFillBackground(False)
        self.pushButton_11.setStyleSheet("background-color: rgb(220, 220, 220);")
        self.pushButton_11.setObjectName("pushButton_11")
        self.pushButton_12 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_12.setGeometry(QtCore.QRect(220, 350, 151, 41))
        self.pushButton_12.setAutoFillBackground(False)
        self.pushButton_12.setStyleSheet("background-color: rgb(225, 225, 225);")
        self.pushButton_12.setObjectName("pushButton_12")
        self.pushButton_13 = QtWidgets.QPushButton(self.centralwidget)
        self.pushButton_13.setGeometry(QtCore.QRect(10, 350, 161, 41))
        self.pushButton_13.setAutoFillBackground(False)
        self.pushButton_13.setStyleSheet("background-color: rgb(230, 230, 230);")
        self.pushButton_13.setObjectName("pushButton_13")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 590, 23))
        self.menubar.setObjectName("menubar")
        self.menu1111 = QtWidgets.QMenu(self.menubar)
        self.menu1111.setObjectName("menu1111")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.menubar.addAction(self.menu1111.menuAction())

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "xxx调试助手"))
        self.Serial.setText(_translate("MainWindow", "串口:"))
        self.pushButton_6.setText(_translate("MainWindow", "断开"))
        self.pushButton.setText(_translate("MainWindow", "连接"))
        self.label_4.setText(_translate("MainWindow", "/ / /"))
        self.label.setText(_translate("MainWindow", "设置速度:"))
        self.pushButton_2.setText(_translate("MainWindow", "确定"))
        self.label_2.setText(_translate("MainWindow", "当前速度:"))
        self.label_3.setText(_translate("MainWindow", "0"))
        self.pushButton_3.setText(_translate("MainWindow", "开始"))
        self.pushButton_4.setText(_translate("MainWindow", "停止"))
        self.pushButton_5.setText(_translate("MainWindow", "归零复位"))
        self.pushButton_7.setText(_translate("MainWindow", "程序版本查询"))
        self.pushButton_8.setText(_translate("MainWindow", "当前位置查询查询"))
        self.pushButton_9.setText(_translate("MainWindow", "原点校准"))
        self.pushButton_10.setText(_translate("MainWindow", "急停回原点"))
        self.pushButton_11.setText(_translate("MainWindow", "电机错误码查询"))
        self.pushButton_12.setText(_translate("MainWindow", "最大翻折速度查询"))
        self.pushButton_13.setText(_translate("MainWindow", "电机位置查询"))
        self.menu1111.setTitle(_translate("MainWindow", "V2.0.0"))

XxxxxxSerialUtile:

import serial
import serial.tools.list_ports
from Logs.log import log


class SerialUtile:
    def __init__(self):
        self.testSerial = serial.Serial()

    @staticmethod
    def get_ports():
        port_list = list(serial.tools.list_ports.comports())
        available_ports = []
        if len(port_list) == 0:
            available_ports.append("No ports!")
        else:
            for port in port_list:
                available_ports.append(str(port))
        return available_ports

    def open_serial(self, port_name):
        try:
            if self.testSerial.is_open:
                log.outputlog("Port has been open!")  # Now closing!
                # self.testSerial.close()
                return 1
            if port_name:
                self.testSerial.port = port_name
                self.testSerial.baudrate = 115200
                self.testSerial.bytesize = 8
                self.testSerial.stopbits = 1
                self.testSerial.timeout = 30
                self.testSerial.open()
                log.outputlog("Port %s is open!" % str(self.testSerial.port))
                return 2
            else:
                log.outputlog("Have no port! Retry!")
                return 3
            # return self.testSerial.is_open
        except Exception as e:
            log.outputlog("Open serial port error : %s" % e)
            self.testSerial.close()
            return e

    def close_serial(self, port_name):
        try:
            if port_name:
                self.testSerial.close()
                if self.testSerial.is_open:
                    log.outputlog("Cant close port! Retry!")
                    # self.testSerial.close()
                    return 1
                else:
                    log.outputlog("Port %s has been closed!" % port_name)
                    return 2
            else:
                log.outputlog("Have no port! Retry!")
                return 3
            # return self.testSerial.is_open
        except Exception as e:
            log.outputlog("Open serial port error : %s" % e)
            self.testSerial.close()
            return e

    def send_message(self, port_name, text):
        try:
            if not self.testSerial.is_open:
                log.outputlog("Port has been closed!Try to open!")
                # self.testSerial.port = port_name
                # self.testSerial.baudrate = 115200
                # self.testSerial.bytesize = 8
                # self.testSerial.stopbits = 1
                # self.testSerial.timeout = 30
                # self.testSerial.open()
                self.open_serial(port_name)
            self.testSerial.write(text)
            a = self.testSerial.read(7)
            log.outputlog("Recv Message : %s" % a)
            return a
        except Exception as e:
            log.outputlog("Send or recv message error: %s" % e)
            self.testSerial.close()


if __name__ == '__main__':
    print('')

testXxxxxxSerial:

import sys
import re

from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QApplication, QMainWindow, QShortcut
from My_ScreenSerial import Ui_MainWindow
from Logs.log import log
from ScreenSerialUtile import SerialUtile as Ser

# 固定格式(字节流……)的转换


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.msg = {'head': 0xFF, 'key': 0x00, 'data1': 0x00, 'data2': 0x00, 'id': 0x00, 'end': 0xFE, 'check': 0x00}
        self.text = None
        self.selectPort = None
        self.openSelectPort = None
        self.closeSelectPort = None
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.initialize_ui()
        self.ui.pushButton.clicked.connect(self.open_port)
        self.ui.pushButton_6.clicked.connect(self.close_port)
        self.ui.pushButton_2.clicked.connect(self.set_speed)
        QShortcut(QKeySequence("Enter"), self.ui.lineEdit, self.set_speed)  # 小Enter
        QShortcut(QKeySequence("Return"), self.ui.lineEdit, self.set_speed)  # 大Enter
        self.ui.pushButton_3.clicked.connect(self.move_y)  # 开始
        self.ui.pushButton_4.clicked.connect(self.xy_return)  # 停止
        self.ui.pushButton_5.clicked.connect(self.xy_return)  # 归零复位
        self.ui.pushButton_7.clicked.connect(self.search_v)  # 程序版本查询
        self.ui.pushButton_8.clicked.connect(self.get_xy_location)  # 当前位置查询
        # self.ui.pushButton_9.clicked.connect(self.xxxx)  # 原点校准
        self.ui.pushButton_10.clicked.connect(self.back_to_zero)  # 急停回原点
        self.ui.pushButton_11.clicked.connect(self.search_state2)  # 电机错误码查询
        self.ui.pushButton_12.clicked.connect(self.search_state1)  # 最大翻折速度查询
        self.ui.pushButton_13.clicked.connect(self.search_state0)  # 电机位置查询


    def initialize_ui(self):
        available_ports = Ser().get_ports()
        for port in available_ports:
            self.ui.Serial_List.addItem(port)

    def open_port(self):
        self.selectPort = re.split(" - | ' ' ", self.ui.Serial_List.currentText())
        self.openSelectPort = Ser().open_serial(self.selectPort[0])
        if self.openSelectPort == 1:
            self.ui.label_4.setText("Port has been open!")
        elif self.openSelectPort == 2:
            self.ui.label_4.setText("Port %s is open!" % str(self.selectPort[0]))
        elif self.openSelectPort == 3:
            self.ui.label_4.setText("Have no port! Retry!")
        else:
            self.ui.label_4.setText("Open serial port error : %s" % self.openSelectPort)

    def close_port(self):
        # self.selectPort = re.split(" - | ' ' ", self.ui.Serial_List.currentText())
        self.closeSelectPort = Ser().close_serial(self.selectPort[0])
        if self.closeSelectPort == 1:
            self.ui.label_4.setText("Can't close port! Retry!")
        elif self.closeSelectPort == 2:
            self.ui.label_4.setText("Port has been closed!")
        elif self.closeSelectPort == 3:
            self.ui.label_4.setText("Have no port! Retry!")
        else:
            self.ui.label_4.setText("Close serial port error : %s" % self.closeSelectPort)

    @staticmethod
    def sum_check(key, d1, d2, pid):
        c = (0xFF+0xFE+key+d1+d2+pid) % 0x100
        return c

    # FF00000100FE00
    def send_msg(self, s):
        t = bytearray()
        for v in s.values():
            t.append(v)
        a = Ser().send_message(self.selectPort[0], t)
        r = []
        for i in a:
            r.append('%02X ' % i)
        rr = ''.join(r)
        log.outputlog("Send Message : %s" % t)
        log.outputlog("Recv Message : %s" % rr)
        return rr
        # test = bytes.fromhex(msg)

    def search_v(self):
        s = self.msg
        s.update({'key': 0xQQ})
        c = self.sum_check(s['key'], s['data1'], s['data2'], s['id'])
        s.update({'check': c})
        log.outputlog("Operation:search_v;Send Message : %s" % s)
        self.send_msg(s)

    def move_y(self, d):
        s = self.msg
        if d < 0 or d > 200:
            print("Out of range! Please retry!")
        else:
            d1 = d//256
            d2 = d % 256
            s.update({'key': 0xQQ, 'data1': d1, 'data2': d2})
            c = self.sum_check(s['key'], s['data1'], s['data2'], s['id'])
            s.update({'check': c})
            log.outputlog("Operation:move_y;Send Message : %s" % s)
            self.send_msg(s)

    def get_xy_location(self):
        s = self.msg
        s.update({'key': 0xQQ, 'data1': 0xQQ})
        c = self.sum_check(s['key'], s['data1'], s['data2'], s['id'])
        s.update({'check': c})
        log.outputlog("Operation:get_xy_location;Send Message : %s" % s)
        r = self.send_msg(s)
        print(r)

    def xy_return(self):
        s = self.msg
        s.update({'key': 0xQQ})
        c = self.sum_check(s['key'], s['data1'], s['data2'], s['id'])
        s.update({'check': c})
        log.outputlog("Operation:xy_return;Send Message : %s" % s)
        self.send_msg(s)

    def set_speed(self):
        s = self.msg
        self.text = int(self.ui.lineEdit.text())
        if self.text > 100 or self.text < 10:
            self.ui.label_3.setText("Out of range! Retry!")
            log.outputlog("Speed %s out of range! Retry!" % str(self.text))
        else:
            self.ui.label_3.setText(str(self.text))
            s.update({'key': 0xQQ, 'data1': self.text})
            c = self.sum_check(s['key'], s['data1'], s['data2'], s['id'])
            s.update({'check': c})
            log.outputlog("Speed %s set success!" % str(self.text))
            log.outputlog("Operation:set_speed;Send Message : %s" % s)
            self.send_msg(s)

    def search_state0(self):
        s = self.msg
        s.update({'key': 0xQQ, 'data1': 0xqq})
        c = self.sum_check(s['key'], s['data1'], s['data2'], s['id'])
        s.update({'check': c})
        log.outputlog("Operation:search_state0;Send Message : %s" % s)
        self.send_msg(s)

    def search_state1(self):
        s = self.msg
        s.update({'key': 0xQQ, 'data1': 0xqq})
        c = self.sum_check(s['key'], s['data1'], s['data2'], s['id'])
        s.update({'check': c})
        log.outputlog("Operation:search_state1;Send Message : %s" % s)
        self.send_msg(s)

    def search_state2(self):
        s = self.msg
        s.update({'key': 0xQQ, 'data1': 0xQQ})
        c = self.sum_check(s['key'], s['data1'], s['data2'], s['id'])
        s.update({'check': c})
        log.outputlog("Operation:search_state2;Send Message : %s" % s)
        self.send_msg(s)

    def back_to_zero(self):
        s = self.msg
        s.update({'key': 0xQQ})
        c = self.sum_check(s['key'], s['data1'], s['data2'], s['id'])
        s.update({'check': c})
        log.outputlog("Operation:back_to_zero;Send Message : %s" % s)
        self.send_msg(s)

    # def check_zero_p(self):
    #     s = self.msg
    #     s.update({'key': 0xQQ, 'data1': 0xqq, 'data2': 0xqq})
    #     c = self.sum_check(s['key'], s['data1'], s['data2'], s['id'])
    #     s.update({'check': c})
    #     self.send_msg(s)
    #
    # def check_zero_m(self):
    #     s = self.msg
    #     s.update({'key': 0xQQ, 'data1': 0xqq, 'data2': 0xqq})
    #     c = self.sum_check(s['key'], s['data1'], s['data2'], s['id'])
    #     s.update({'check': c})
    #     self.send_msg(s)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    # 创建 QApplication 对象(当前运行地址)

    w = MainWindow()
    # 创建窗口
    # w.setWindowTitle("串口调试")
    # # 设窗口标题
    w.show()
    # 展示窗口

    sys.exit(app.exec_())
    # 系统,退出,QApplication程序的(事件检测)循环等待状态
    # print((0x01 << 8) + 0x68)

码掉了,存。数据看文档。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值