Arduino Mega2560 作为烧录器烧写Mega2560的bootloader

2 篇文章 0 订阅
2 篇文章 1 订阅

本文参考自:http://www.51hei.com/bbs/dpj-48026-1.html

 

打开arduino IDE 软件,菜单栏 文件-->示例-->ArduinoISP,这个就是官方的isp下载器代码。我们直接打开

这里介绍下icsp口的定义

MISO(50引脚)5V
SCK(52引脚)MOSI(51引脚)
RSTGND

实物接线   上面这个电容是10uf的,接地

当然也能这样接,这样要下载的板子就不用再接电源了

 

这里注意下,Arduino UNO和Mega2560的io口定义是不一样的,需要修改。按官方例程直接操作是不行的

改变的地方是 找到这段代码

#define USE_OLD_STYLE_WIRING

#ifdef USE_OLD_STYLE_WIRING

#define PIN_MOSI	11
#define PIN_MISO	12
#define PIN_SCK		13

#endif

改成   这里改成这个是因为mega2560的引脚就是这么定义的,具体可查看手册

 

    #define USE_OLD_STYLE_WIRING   //此处别忘记取消注释
     
    #ifdef USE_OLD_STYLE_WIRING
     
    #define PIN_MOSI        51    //mega2560的MOSI 11
    #define PIN_MISO        50   //mega2560的MISO 12
    #define PIN_SCK         52   //mega2560的SCK 13
     
    #endif

 

下面附上修改的代码

 // ArduinoISP
 //reset引脚接10uf电容 到 gnd ,就是10号引脚
    // Copyright (c) 2008-2011 Randall Bohn
    // If you require a license, see
    //     [url=http://www.opensource.org/licenses/bsd-license.php]http://www.opensource.org/licenses/bsd-license.php[/url]
    //
    // This sketch turns the Arduino into a AVRISP
    // using the following arduino pins:
    //
    // Pin 10 is used to reset the target microcontroller.
    //
    // By default, the hardware SPI pins MISO, MOSI and SCK pins are used
    // to communicate with the target. On all Arduinos, these pins can be found
    // on the ICSP/SPI header:
    //
    //               MISO °. . 5V (!) Avoid this pin on Due, Zero...
    //               SCK   . . MOSI
    //                     . . GND
    //
    // On some Arduinos (Uno,...), pins MOSI, MISO and SCK are the same pins
    // as digital pin 11, 12 and 13, respectively. That is why many tutorials
    // instruct you to hook up the target to these pins. If you find this wiring
    // more practical, have a define USE_OLD_STYLE_WIRING. This will work even
    // even when not using an Uno. (On an Uno this is not needed).
    //
    // Alternatively you can use any other digital pin by configuring software ('BitBanged')
    // SPI and having appropriate defines for PIN_MOSI, PIN_MISO and PIN_SCK.
    //
    // IMPORTANT: When using an Arduino that is not 5V tolerant (Due, Zero, ...)
    // as the programmer, make sure to not expose any of the programmer's pins to 5V.
    // A simple way to accomplish this is to power the complete system (programmer
    // and target) at 3V3.
    //
    // Put an LED (with resistor) on the following pins:
    // 9: Heartbeat   - shows the programmer is running
    // 8: Error       - Lights up if something goes wrong (use red if that makes sense)
    // 7: Programming - In communication with the slave
    //
     
    #include "Arduino.h"
    #undef SERIAL
     
     
    #define PROG_FLICKER true
     
    // Configure SPI clock (in Hz).
    // E.g. for an attiny @128 kHz: the datasheet states that both the high
    // and low spi clock pulse must be > 2 cpu cycles, so take 3 cycles i.e.
    // divide target f_cpu by 6:
    //     #define SPI_CLOCK            (128000/6)
    //
    // A clock slow enough for an attiny85 @ 1MHz, is a reasonable default:
    #define SPI_CLOCK                 (1000000/6)
     
     
    // Select hardware or software SPI, depending on SPI clock.
    // Currently only for AVR, for other archs (Due, Zero,...),
    // hardware SPI is probably too fast anyway.
     
    #if defined(ARDUINO_ARCH_AVR)
     
    #if SPI_CLOCK > (F_CPU / 128)
    #define USE_HARDWARE_SPI
    #endif
     
    #endif
     
    // Configure which pins to use:
     
    // The standard pin configuration.
    #ifndef ARDUINO_HOODLOADER2
     
    #define RESET     10 // Use pin 10 to reset the target rather than SS
    #define LED_HB    9
    #define LED_ERR   8
    #define LED_PMODE 7
     
    // Uncomment following line to use the old Uno style wiring
    // (using pin 11, 12 and 13 instead of the SPI header) on Leonardo, Due...
     
    #define USE_OLD_STYLE_WIRING   //此处别忘记取消注释
     
    #ifdef USE_OLD_STYLE_WIRING
     
    #define PIN_MOSI        51    //mega2560的MOSI 11
    #define PIN_MISO        50   //mega2560的MISO 12
    #define PIN_SCK         52   //mega2560的SCK 13
     
    #endif
     
    // HOODLOADER2 means running sketches on the atmega16u2
    // serial converter chips on Uno or Mega boards.
    // We must use pins that are broken out:
    #else
     
    #define RESET             10
    #define LED_HB            7
    #define LED_ERR           6
    #define LED_PMODE         5
     
    #endif
     
     By default, use hardware SPI pins:
    //#ifndef PIN_MOSI
    //#define PIN_MOSI         MOSI
    //#endif
    //
    //#ifndef PIN_MISO
    //#define PIN_MISO         MISO
    //#endif
    //
    //#ifndef PIN_SCK
    //#define PIN_SCK         SCK
    //#endif
    //
     Force bitbanged SPI if not using the hardware SPI pins:
    //#if (PIN_MISO != MISO) ||  (PIN_MOSI != MOSI) || (PIN_SCK != SCK)
    //#undef USE_HARDWARE_SPI
    //#endif
     
     
    // Configure the serial port to use.
    //
    // Prefer the USB virtual serial port (aka. native USB port), if the Arduino has one:
    //   - it does not autoreset (except for the magic baud rate of 1200).
    //   - it is more reliable because of USB handshaking.
    //
    // Leonardo and similar have an USB virtual serial port: 'Serial'.
    // Due and Zero have an USB virtual serial port: 'SerialUSB'.
    //
    // On the Due and Zero, 'Serial' can be used too, provided you disable autoreset.
    // To use 'Serial': #define SERIAL Serial
     
    #ifdef SERIAL_PORT_USBVIRTUAL
    #define SERIAL SERIAL_PORT_USBVIRTUAL
    #else
    #define SERIAL Serial
    #endif
     
     
    // Configure the baud rate:
     
    #define BAUDRATE        19200
    // #define BAUDRATE        115200
    // #define BAUDRATE        1000000
     
     
    #define HWVER 2
    #define SWMAJ 1
    #define SWMIN 18
     
    // STK Definitions
    #define STK_OK      0x10
    #define STK_FAILED  0x11
    #define STK_UNKNOWN 0x12
    #define STK_INSYNC  0x14
    #define STK_NOSYNC  0x15
    #define CRC_EOP     0x20 //ok it is a space...
     
    void pulse(int pin, int times);
     
    #ifdef USE_HARDWARE_SPI
    #include "SPI.h"
    #else
     
    #define SPI_MODE0 0x00
     
    class SPISettings {
    public:
      // clock is in Hz
      SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) : clock(clock){
        (void) bitOrder;
        (void) dataMode;
      };
     
    private:
      uint32_t clock;
     
    friend class BitBangedSPI;
    };
     
    class BitBangedSPI {
    public:
      void begin() {
        digitalWrite(PIN_SCK, LOW);
        digitalWrite(PIN_MOSI, LOW);
        pinMode(PIN_SCK, OUTPUT);
        pinMode(PIN_MOSI, OUTPUT);
        pinMode(PIN_MISO, INPUT);
      }
     
      void beginTransaction(SPISettings settings) {
        pulseWidth = (500000 + settings.clock - 1) / settings.clock;
        if (pulseWidth == 0)
          pulseWidth = 1;
      }
     
      void end() {}
     
      uint8_t transfer (uint8_t b) {
        for (unsigned int i = 0; i < 8; ++i) {
          digitalWrite(PIN_MOSI, (b & 0x80) ? HIGH : LOW);
          digitalWrite(PIN_SCK, HIGH);
          delayMicroseconds(pulseWidth);
          b = (b << 1) | digitalRead(PIN_MISO);
          digitalWrite(PIN_SCK, LOW); // slow pulse
          delayMicroseconds(pulseWidth);
        }
        return b;
      }
     
    private:
      unsigned long pulseWidth; // in microseconds
    };
     
    static BitBangedSPI SPI;
     
    #endif
     
    void setup() {
      SERIAL.begin(BAUDRATE);
     
      pinMode(LED_PMODE, OUTPUT);
      pulse(LED_PMODE, 2);
      pinMode(LED_ERR, OUTPUT);
      pulse(LED_ERR, 2);
      pinMode(LED_HB, OUTPUT);
      pulse(LED_HB, 2);
     
    }
     
    int error = 0;
    int pmode = 0;
    // address for reading and writing, set by 'U' command
    unsigned int here;
    uint8_t buff[256]; // global block storage
     
    #define beget16(addr) (*addr * 256 + *(addr+1) )
    typedef struct param {
      uint8_t devicecode;
      uint8_t revision;
      uint8_t progtype;
      uint8_t parmode;
      uint8_t polling;
      uint8_t selftimed;
      uint8_t lockbytes;
      uint8_t fusebytes;
      uint8_t flashpoll;
      uint16_t eeprompoll;
      uint16_t pagesize;
      uint16_t eepromsize;
      uint32_t flashsize;
    }
    parameter;
     
    parameter param;
     
    // this provides a heartbeat on pin 9, so you can tell the software is running.
    uint8_t hbval = 128;
    int8_t hbdelta = 8;
    void heartbeat() {
      static unsigned long last_time = 0;
      unsigned long now = millis();
      if ((now - last_time) < 40)
        return;
      last_time = now;
      if (hbval > 192) hbdelta = -hbdelta;
      if (hbval < 32) hbdelta = -hbdelta;
      hbval += hbdelta;
      analogWrite(LED_HB, hbval);
    }
     
    static bool rst_active_high;
     
    void reset_target(bool reset) {
      digitalWrite(RESET, ((reset && rst_active_high) || (!reset && !rst_active_high)) ? HIGH : LOW);
    }
     
    void loop(void) {
      // is pmode active?
      if (pmode) {
        digitalWrite(LED_PMODE, HIGH);
      } else {
        digitalWrite(LED_PMODE, LOW);
      }
      // is there an error?
      if (error) {
        digitalWrite(LED_ERR, HIGH);
      } else {
        digitalWrite(LED_ERR, LOW);
      }
     
      // light the heartbeat LED
      heartbeat();
      if (SERIAL.available()) {
        avrisp();
      }
    }
     
    uint8_t getch() {
      while (!SERIAL.available());
      return SERIAL.read();
    }
    void fill(int n) {
      for (int x = 0; x < n; x++) {
        buff[x] = getch();
      }
    }
     
    #define PTIME 30
    void pulse(int pin, int times) {
      do {
        digitalWrite(pin, HIGH);
        delay(PTIME);
        digitalWrite(pin, LOW);
        delay(PTIME);
      } while (times--);
    }
     
    void prog_lamp(int state) {
      if (PROG_FLICKER) {
        digitalWrite(LED_PMODE, state);
      }
    }
     
    uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
      SPI.transfer(a);
      SPI.transfer(b);
      SPI.transfer(c);
      return SPI.transfer(d);
    }
     
    void empty_reply() {
      if (CRC_EOP == getch()) {
        SERIAL.print((char)STK_INSYNC);
        SERIAL.print((char)STK_OK);
      } else {
        error++;
        SERIAL.print((char)STK_NOSYNC);
      }
    }
     
    void breply(uint8_t b) {
      if (CRC_EOP == getch()) {
        SERIAL.print((char)STK_INSYNC);
        SERIAL.print((char)b);
        SERIAL.print((char)STK_OK);
      } else {
        error++;
        SERIAL.print((char)STK_NOSYNC);
      }
    }
     
    void get_version(uint8_t c) {
      switch (c) {
        case 0x80:
          breply(HWVER);
          break;
        case 0x81:
          breply(SWMAJ);
          break;
        case 0x82:
          breply(SWMIN);
          break;
        case 0x93:
          breply('S'); // serial programmer
          break;
        default:
          breply(0);
      }
    }
     
    void set_parameters() {
      // call this after reading paramter packet into buff[]
      param.devicecode = buff[0];
      param.revision   = buff[1];
      param.progtype   = buff[2];
      param.parmode    = buff[3];
      param.polling    = buff[4];
      param.selftimed  = buff[5];
      param.lockbytes  = buff[6];
      param.fusebytes  = buff[7];
      param.flashpoll  = buff[8];
      // ignore buff[9] (= buff[8])
      // following are 16 bits (big endian)
      param.eeprompoll = beget16(&buff[10]);
      param.pagesize   = beget16(&buff[12]);
      param.eepromsize = beget16(&buff[14]);
     
      // 32 bits flashsize (big endian)
      param.flashsize = buff[16] * 0x01000000
                        + buff[17] * 0x00010000
                        + buff[18] * 0x00000100
                        + buff[19];
     
      // avr devices have active low reset, at89sx are active high
      rst_active_high = (param.devicecode >= 0xe0);
    }
     
    void start_pmode() {
     
      // Reset target before driving PIN_SCK or PIN_MOSI
     
      // SPI.begin() will configure SS as output,
      // so SPI master mode is selected.
      // We have defined RESET as pin 10,
      // which for many arduino's is not the SS pin.
      // So we have to configure RESET as output here,
      // (reset_target() first sets the correct level)
      reset_target(true);
      pinMode(RESET, OUTPUT);
      SPI.begin();
      SPI.beginTransaction(SPISettings(SPI_CLOCK, MSBFIRST, SPI_MODE0));
     
      // See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
     
      // Pulse RESET after PIN_SCK is low:
      digitalWrite(PIN_SCK, LOW);
      delay(20); // discharge PIN_SCK, value arbitrally chosen
      reset_target(false);
      // Pulse must be minimum 2 target CPU clock cycles
      // so 100 usec is ok for CPU speeds above 20KHz
      delayMicroseconds(100);
      reset_target(true);
     
      // Send the enable programming command:
      delay(50); // datasheet: must be > 20 msec
      spi_transaction(0xAC, 0x53, 0x00, 0x00);
      pmode = 1;
    }
     
    void end_pmode() {
      SPI.end();
      // We're about to take the target out of reset
      // so configure SPI pins as input
      pinMode(PIN_MOSI, INPUT);
      pinMode(PIN_SCK, INPUT);
      reset_target(false);
      pinMode(RESET, INPUT);
      pmode = 0;
    }
     
    void universal() {
      uint8_t ch;
     
      fill(4);
      ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]);
      breply(ch);
    }
     
    void flash(uint8_t hilo, unsigned int addr, uint8_t data) {
      spi_transaction(0x40 + 8 * hilo,
                      addr >> 8 & 0xFF,
                      addr & 0xFF,
                      data);
    }
    void commit(unsigned int addr) {
      if (PROG_FLICKER) {
        prog_lamp(LOW);
      }
      spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
      if (PROG_FLICKER) {
        delay(PTIME);
        prog_lamp(HIGH);
      }
    }
     
    unsigned int current_page() {
      if (param.pagesize == 32) {
        return here & 0xFFFFFFF0;
      }
      if (param.pagesize == 64) {
        return here & 0xFFFFFFE0;
      }
      if (param.pagesize == 128) {
        return here & 0xFFFFFFC0;
      }
      if (param.pagesize == 256) {
        return here & 0xFFFFFF80;
      }
      return here;
    }
     
     
    void write_flash(int length) {
      fill(length);
      if (CRC_EOP == getch()) {
        SERIAL.print((char) STK_INSYNC);
        SERIAL.print((char) write_flash_pages(length));
      } else {
        error++;
        SERIAL.print((char) STK_NOSYNC);
      }
    }
     
    uint8_t write_flash_pages(int length) {
      int x = 0;
      unsigned int page = current_page();
      while (x < length) {
        if (page != current_page()) {
          commit(page);
          page = current_page();
        }
        flash(LOW, here, buff[x++]);
        flash(HIGH, here, buff[x++]);
        here++;
      }
     
      commit(page);
     
      return STK_OK;
    }
     
    #define EECHUNK (32)
    uint8_t write_eeprom(unsigned int length) {
      // here is a word address, get the byte address
      unsigned int start = here * 2;
      unsigned int remaining = length;
      if (length > param.eepromsize) {
        error++;
        return STK_FAILED;
      }
      while (remaining > EECHUNK) {
        write_eeprom_chunk(start, EECHUNK);
        start += EECHUNK;
        remaining -= EECHUNK;
      }
      write_eeprom_chunk(start, remaining);
      return STK_OK;
    }
    // write (length) bytes, (start) is a byte address
    uint8_t write_eeprom_chunk(unsigned int start, unsigned int length) {
      // this writes byte-by-byte,
      // page writing may be faster (4 bytes at a time)
      fill(length);
      prog_lamp(LOW);
      for (unsigned int x = 0; x < length; x++) {
        unsigned int addr = start + x;
        spi_transaction(0xC0, (addr >> 8) & 0xFF, addr & 0xFF, buff[x]);
        delay(45);
      }
      prog_lamp(HIGH);
      return STK_OK;
    }
     
    void program_page() {
      char result = (char) STK_FAILED;
      unsigned int length = 256 * getch();
      length += getch();
      char memtype = getch();
      // flash memory @here, (length) bytes
      if (memtype == 'F') {
        write_flash(length);
        return;
      }
      if (memtype == 'E') {
        result = (char)write_eeprom(length);
        if (CRC_EOP == getch()) {
          SERIAL.print((char) STK_INSYNC);
          SERIAL.print(result);
        } else {
          error++;
          SERIAL.print((char) STK_NOSYNC);
        }
        return;
      }
      SERIAL.print((char)STK_FAILED);
      return;
    }
     
    uint8_t flash_read(uint8_t hilo, unsigned int addr) {
      return spi_transaction(0x20 + hilo * 8,
                             (addr >> 8) & 0xFF,
                             addr & 0xFF,
                             0);
    }
     
    char flash_read_page(int length) {
      for (int x = 0; x < length; x += 2) {
        uint8_t low = flash_read(LOW, here);
        SERIAL.print((char) low);
        uint8_t high = flash_read(HIGH, here);
        SERIAL.print((char) high);
        here++;
      }
      return STK_OK;
    }
     
    char eeprom_read_page(int length) {
      // here again we have a word address
      int start = here * 2;
      for (int x = 0; x < length; x++) {
        int addr = start + x;
        uint8_t ee = spi_transaction(0xA0, (addr >> 8) & 0xFF, addr & 0xFF, 0xFF);
        SERIAL.print((char) ee);
      }
      return STK_OK;
    }
     
    void read_page() {
      char result = (char)STK_FAILED;
      int length = 256 * getch();
      length += getch();
      char memtype = getch();
      if (CRC_EOP != getch()) {
        error++;
        SERIAL.print((char) STK_NOSYNC);
        return;
      }
      SERIAL.print((char) STK_INSYNC);
      if (memtype == 'F') result = flash_read_page(length);
      if (memtype == 'E') result = eeprom_read_page(length);
      SERIAL.print(result);
    }
     
    void read_signature() {
      if (CRC_EOP != getch()) {
        error++;
        SERIAL.print((char) STK_NOSYNC);
        return;
      }
      SERIAL.print((char) STK_INSYNC);
      uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
      SERIAL.print((char) high);
      uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00);
      SERIAL.print((char) middle);
      uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
      SERIAL.print((char) low);
      SERIAL.print((char) STK_OK);
    }
    //
    //
     
     
    
    
    void avrisp() {
      uint8_t ch = getch();
      switch (ch) {
        case '0': // signon
          error = 0;
          empty_reply();
          break;
        case '1':
          if (getch() == CRC_EOP) {
            SERIAL.print((char) STK_INSYNC);
            SERIAL.print("AVR ISP");
            SERIAL.print((char) STK_OK);
          }
          else {
            error++;
            SERIAL.print((char) STK_NOSYNC);
          }
          break;
        case 'A':
          get_version(getch());
          break;
        case 'B':
          fill(20);
          set_parameters();
          empty_reply();
          break;
        case 'E': // extended parameters - ignore for now
          fill(5);
          empty_reply();
          break;
        case 'P':
          if (!pmode)
            start_pmode();
          empty_reply();
          break;
        case 'U': // set address (word)
          here = getch();
          here += 256 * getch();
          empty_reply();
          break;
     
        case 0x60: //STK_PROG_FLASH
          getch(); // low addr
          getch(); // high addr
          empty_reply();
          break;
        case 0x61: //STK_PROG_DATA
          getch(); // data
          empty_reply();
          break;
     
        case 0x64: //STK_PROG_PAGE
          program_page();
          break;
     
        case 0x74: //STK_READ_PAGE 't'
          read_page();
          break;
     
        case 'V': //0x56
          universal();
          break;
        case 'Q': //0x51
          error = 0;
          end_pmode();
          empty_reply();
          break;
     
        case 0x75: //STK_READ_SIGN 'u'
          read_signature();
          break;
     
        // expecting a command, not CRC_EOP
        // this is how we can get back in sync
        case CRC_EOP:
          error++;
          SERIAL.print((char) STK_NOSYNC);
          break;
     
        // anything else we will return STK_UNKNOWN
        default:
          error++;
          if (CRC_EOP == getch())
            SERIAL.print((char)STK_UNKNOWN);
          else
            SERIAL.print((char)STK_NOSYNC);
      }
    }

复制好上面的程序后,直接通过usb烧到板子里,它就变成了一个isp烧写器了,按上面的图接好线后

接下来就要把bootloader通过这个板子烧到目标板子里面,首先在菜单里面 工具->编程器->arduino as isp 选中

选择开发板型号  菜单的->工具 -> 开发板: -> arduino/genuino mega or mega 2560

选择处理器  菜单->工具->处理器->atmega2560(Mega 2560)

烧写引导程序 菜单->工具->烧录引导程序

 

好了指示灯会一闪一闪的,就在烧写了,电容一定要接上,不然烧不了,我是这样

 

 

 

要制作一个基于Arduino Mega2560的烟雾报警器,你需要以下材料: - 一个Arduino Mega2560控制板 - 一个烟雾传感器模块 - 一个蜂鸣器 - 杜邦线 - 面包板 - 9V电池 接下来是制作步骤: 1. 将烟雾传感器模块连接到Arduino Mega2560的数字引脚2上,将蜂鸣器连接到数字引脚3上。接线方法可以参考传感器模块和蜂鸣器的说明书,也可以通过搜索引擎来获取连接图。 2. 将Arduino Mega2560连接到电脑,并打开Arduino IDE软件。 3. 在Arduino IDE中,新建一个空白工程,并编写代码。代码的主要逻辑如下: - 首先定义数字引脚2为输入模式,数字引脚3为输出模式。 - 然后通过循环读取数字引脚2的值,如果检测到烟雾,则将数字引脚3输出高电平,同时蜂鸣器发出警报声音。 4. 完成代码编写后,将代码上传到Arduino Mega2560控制板上。 5. 将面包板和电池连接起来,将Arduino Mega2560控制板插入面包板上,用杜邦线连接好电池、烟雾传感器模块和蜂鸣器。 6. 将面包板上的杜邦线插入Arduino Mega2560控制板上对应的引脚。 7. 打开电源,测试烟雾报警器是否正常工作。如果检测到烟雾,则蜂鸣器应该会发出声音,同时数字引脚3也会输出高电平。 以上就是制作一个基于Arduino Mega2560的烟雾报警器的步骤。注意,这只是一个简单的示例,实际应用中还需要考虑更多的因素,例如如何调整传感器的灵敏度、如何处理误报等问题。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值