【开源项目学习】esp8266点阵时钟(四)

相关信息看前面的吧


目录

touchLoop()触摸按键

按键处理函数

Functions::powerUp()功能加,功能切换作用吧

Functions::modeUp()模式加

handlePower()功能处理

showTime(uint8_t showmode)显示时间

DateTimes::getTimes()获取时间信息

showTimeCallback()显示时间回调处理

Lattice::showTime3(uint8_t *arr, void (*callback)())显示时间模式3

offsetData(uint8_t index, int8_t offset)应该是移位吧

Lattice::reversalLR(uint8_t index)左右翻转(图案左右对称)

Lattice::reversalUD(uint8_t index)上下翻转(图案上下对称)

showDate(uint8_t showmode)显示日期

Lattice::showLongNumber(uint8_t *arr)

*Lattice::getNumData(uint8_t number, bool showzero) //得到要显示的数字

showTemperature()显示温度

DateTimes::getTemperature()

showBiliFans()显示bilibili粉丝数量

showUserData(functions.getCurrMode()); // 显示用户自定义的数据

showCountDown(); // 显示倒计时

System::reset_system(); // 重置系统,定义在System.cpp

sleepTimeLoop()休眠


touchLoop()触摸按键

touchLoop()定义在Main.h中

//按键中断处理
void touchLoop()
{
    btnA.tick();
    btnB.tick();
}

在这里,按键初始化函数为:

void initTouch()
{
    btnA.attachClick(singleAClickHandler);       // 添加单击事件函数
    btnA.attachDoubleClick(doubleAClickHandler); // 添加双击事件函数
    btnA.attachLongPressStop(longAClickHandler); // 添加长按事件函数
    btnB.attachClick(singleBClickHandler);       // 按键B注册一个单击事件函数
    // btnA.attachLongPressStart(longAClickStartHandler); // 添加按下事件函数
}

singleAClickHandler()、doubleAClickHandler()、longAClickHandler()、singleBClickHandler()定义在Main.h中。

按键处理函数

singleAClickHandler()

//A按键单机
void singleAClickHandler()
{
    Serial.println("A按键单击");           // 打印日志,便于校验
    if (lattice.latticeSetting.isShutdown) // 如果屏幕是熄灭的话,单击操作则是点亮屏幕不做其他操作
    {
        lattice.shutdown(false); // 让点阵屏重新显示
        return;
    }
    functions.powerUp(); // 功能加一下
    initStatus();        // 初始化一些东西
}

functions.powerUp()定义在Functions.cpp

Functions::powerUp()功能加,功能切换作用吧

void Functions::powerUp()
{
    // 当前功能加到超过最大值时,就重置为默认的功能
    if (currPower == POWER_SIZE - 1)
    {
        currPower = 0;
    }
    else
    {
        ++currPower; // 功能加加
    }
    pilotLight->flashing(50); // 功能处理完闪烁一下状态指示灯
}

doubleAClickHandler()

//A按键双击
void doubleAClickHandler()
{
    Serial.println("A按键双击");           // 打印日志,便于校验
    if (lattice.latticeSetting.isShutdown) // 如果屏幕是熄灭的话,单击操作则是点亮屏幕不做其他操作
    {
        lattice.shutdown(false); // 让点阵屏重新显示
        return;
    }
    pilotLight.flashing(100); // 按键单击时先闪一下LED
    functions.modeUp();       // 功能模式加一下
    initStatus();             // 初始化一些东西
}

functions.modeUp()定义在Functions.cpp

Functions::modeUp()模式加

void Functions::modeUp()
{
    // 如果说当前模式超过最大模式,则设置为初始模式
    if (currMode[currPower] == (modePower[currPower] - 1))
    {
        currMode[currPower] = 0;
    }
    else
    {
        ++currMode[currPower];
    }
    pilotLight->flashing(50); // 功能处理完闪烁一下状态指示灯
}

longAClickHandler()

void longAClickHandler()
{
    Serial.println("A按键长按结束");       // 打印日志,便于校验
    if (lattice.latticeSetting.isShutdown) // 如果屏幕是熄灭的话,单击操作则是点亮屏幕不做其他操作
    {
        lattice.shutdown(false); // 让点阵屏重新显示
        return;
    }
    lattice.shutdown(true); // 否则关闭点阵屏
}

singleBClickHandler()

CRGB是FastLED库的

//B按键单机
void singleBClickHandler()
{
    if (colorNums >= 9)
    {
        colorNums = 0;
    }
    else
    {
        colorNums++;
    }

    switch (colorNums)
    {
    case 0:
        lattice.showColor = CRGB::Green;
        break;
    case 1:
        lattice.showColor = CRGB::AliceBlue;
        break;
    case 2:
        lattice.showColor = CRGB::Beige;
        break;
    case 3:
        lattice.showColor = CRGB::Brown;
        break;
    case 4:
        lattice.showColor = CRGB::DarkGray;
        break;
    case 5:
        lattice.showColor = CRGB::DarkOrange;
        break;
    case 6:
        lattice.showColor = CRGB::DarkSeaGreen;
        break;
    case 7:
        lattice.showColor = CRGB::FloralWhite;
        break;
    case 8:
        lattice.showColor = CRGB::Indigo;
        break;
    case 9:
        lattice.showColor = CRGB::LightSalmon;
        break;
    }
}



handlePower()功能处理函数,定义在esp8266-lattice-clock-awtirx.ino

handlePower()功能处理

void handlePower()
{
  switch (functions.getCurrPower()) // 显示数据模式
  {
  case SHOW_TIME:
    showTime(functions.getCurrMode()); // 显示时间
    break;
  case SHOW_DATE:
    showDate(functions.getCurrMode()); // 显示日期
    break;
  case POWER2:
    showTemperature(); // 显示温度
    break;
  case BILIFANS:
    showBiliFans(); // 显示bilibili粉丝数量
    break;
  case CUSTOM:
    showUserData(functions.getCurrMode()); // 显示用户自定义的数据
    break;
  case COUNTDOWN:
    showCountDown(); // 显示倒计时
    break;
  case RESET:
    System::reset_system(); // 重置系统
    break;
  case RESETTIME:
    resetTime(displayData); // 重置时间,这里是随便传的一个参数,不想重新声明参数
    break;
  default:
    break; // 默认不做任何处理
  }
}

showTime(functions.getCurrMode()),显示时间。定义在esp8266-lattice-clock-awtirx.ino

showTime(uint8_t showmode)显示时间

//  显示时间
void showTime(uint8_t showmode)
{
  Times times = datetimes.getTimes();
  if (times.s == powerFlag)
  {
    return; // 如果秒钟数没有改变,则不执行方法
  }
  powerFlag = times.s;
  displayData[0] = times.s;
  displayData[1] = times.m;
  displayData[2] = times.h;
  if (showmode == 0)
  {
    lattice.showTime3(displayData, showTimeCallback);
  }
  else if (showmode == 1)
  {
    lattice.showTime(displayData, showTimeCallback);
  }
  else
  {
    if (times.s == 0 || powerFlag == -1)
    {
      displayData[0] = times.m % 10;
      displayData[1] = times.m / 10;
      displayData[2] = times.h % 10;
      displayData[3] = times.h / 10;
      lattice.showTime2(displayData, showTimeCallback);
    }
    powerFlag = times.s;
    if (times.s % 2 == 0)
    {
      lattice.reversalLR(3);
    }
    else
    {
      lattice.reversalUD(3);
    }
  }
}

datetimes.getTimes()获取时间信息,定义在DateTimes.cpp

DateTimes::getTimes()获取时间信息

DS3231库的东西。

// 获取时间信息
Times DateTimes::getTimes()
{
  datetime = DateTime(currtimestamp);
  times.h = datetime.hour();
  times.m = datetime.minute();
  times.s = datetime.second();
  return times;
}

showTimeCallback()定义在esp8266-lattice-clock-awtirx.ino

showTimeCallback()显示时间回调处理

// 显示时间回调处理
void showTimeCallback()
{
  handleUdpData();
  touchLoop();
  if (WiFi.status() == WL_CONNECTED) // 确保wifi网络是可用的,不可用则忽略
  {
    // Blinker.run();
  }
}

Lattice::showTime3(uint8_t *arr, void (*callback)())显示时间模式3

//显示时间模式3
void Lattice::showTime3(uint8_t *arr, void (*callback)())
{

  uint8_t mfs[4] = {0x0, 0x0, 0x0, 0x0};
  // 这里判断哪些数字要改变,哪些数字不要改变
  for (int k = 0; k < columnLength; k++)
  {
    if (k == 0 || (k == 1 && arr[0] == 0) ||
        (k == 2 && (arr[1] == 0 && arr[0] == 0)))
    {
      mfs[k] = (arr[k] % 10 == 0) ? 0xff : 0xf;
    }
  }

  if (isReset)
  {
    isReset = false;
    mfs[0] = 0xff;
    mfs[1] = 0xff;
    mfs[2] = 0xff;
    mfs[3] = 0xff;
  }
  // 这里保留不要改变的数字
  for (int i = 0; i < 8; i++)
  {
    // 这里为啥写三行不写循环,因为我觉得循环也是三行,这样也是三行就没必要计较了
    buff[0][i] = mfs[0] == 0x0   ? buff[0][i]
                 : mfs[0] == 0xf ? (buff[0][i] & 0xf0)
                                 : 0x0;
    buff[1][i] = mfs[1] == 0x0   ? buff[1][i]
                 : mfs[1] == 0xf ? (buff[1][i] & 0xf0)
                                 : 0x0;
    buff[2][i] = mfs[2] == 0x0   ? buff[2][i]
                 : mfs[2] == 0xf ? (buff[2][i] & 0xf0)
                                 : 0x0;
    buff[3][i] = 0x0;
  }

  for (int i = 0; i < 16; i++)
  {

    // 判断有几个数字发生了改变
    for (int j = 0; j < 3; j++)
    {
      if (mfs[j] == 0x0)
      {
        // 如果说没有改变则忽略
        break;
      }
      uint8_t gw = arr[j] % 10, sw = arr[j] / 10;
      uint8_t geweibuff = number_font_animations[gw][i],    //个位
              shiweibuff = number_font_animations[sw][i];   //十位
      if (geweibuff != 0x0)
      {
        buff[j][((geweibuff >> 4) & 0xf)] += ((0x80 >> (geweibuff & 0xf)) >> 4);
      }
      if (shiweibuff != 0x0 && mfs[j] == 0xff)
      {
        buff[j][((shiweibuff >> 4) & 0xf)] += ((0x80 >> (shiweibuff & 0xf)));
      }
    }

    for (int i = 0; i < columnLength; i++)
    {
      for (int j = 0; j < rowLength; j++)
      {
        data[i][j] = buff[i][j];
      }
    }

    offsetData(2, (-1 * 6));
    offsetData(1, (-1 * 4));
    offsetData(0, (-1 * 2));

    // 显示点
    data[2][2] = (data[2][2] & ((0x80 >> 2) ^ 0xff)) + (0x80 >> 2);
    data[2][4] = (data[2][4] & ((0x80 >> 2) ^ 0xff)) + (0x80 >> 2);
    data[1][2] = (data[1][2] & ((0x80 >> 4) ^ 0xff)) + (0x80 >> 4);
    data[1][4] = (data[1][4] & ((0x80 >> 4) ^ 0xff)) + (0x80 >> 4);
    refreshLed();
    System::delay_time(50, callback);
  }
}

offsetData()定义在Lattice.cpp中

offsetData(uint8_t index, int8_t offset)应该是移位吧

void Lattice::offsetData(uint8_t index, int8_t offset)
{
  uint8_t os = abs(offset);    //求绝对值
  if (offset < 0)
  {
    // 向左移动显示为
    uint8_t lastindex = (index == 3) ? 0 : (index + 1);
    uint8_t lastoffset = (0xff >> os) << os;
    uint8_t nextoffset = (lastoffset ^ 0xff) << (8 - os);
    for (int i = 0; i < 8; i++)
    {
      data[lastindex][i] = (data[lastindex][i] & lastoffset) +
                           ((data[index][i] & nextoffset) >> (8 - os));
      data[index][i] <<= os;
    }
  }
  else
  {
    // 向右移动显示位
    uint8_t lastindex = (index == 0) ? 3 : index - 1;
    uint8_t lastoffset = (0xff >> os);
    uint8_t nextoffset = (lastoffset ^ 0xff) >> (8 - os);
    for (int i = 0; i < 8; i++)
    {
      data[lastindex][i] = (data[lastindex][i] & lastoffset) +
                           ((data[index][i] & (nextoffset)) << (8 - os));
      data[index][i] >>= os;
    }
  }
}

Lattice::reversalLR(uint8_t index)左右翻转(图案左右对称)

void Lattice::reversalLR(uint8_t index)
{
  for (int j = 0; j < 8; j++)
  {
    // 下面的代码是将数字反转
    uint8_t temp = data[index][j];
    for (int i = 0; i < 4; i++)
    {
      uint8_t t1 = temp & (0x1 << i), t2 = temp & (0x80 >> i);
      temp = (temp & (((0xfe ^ 0xff) << i) ^ 0xff)) + (t2 >> ((8 - 1) - i * 2));
      temp = (temp & (((0x7f ^ 0xff) >> i) ^ 0xff)) + (t1 << ((8 - 1) - i * 2));
    }
    data[index][j] = temp;
  }
  refreshLed();
}

Lattice::reversalUD(uint8_t index)上下翻转(图案上下对称)

void Lattice::reversalUD(uint8_t index)
{
  for (int i = 0; i < 4; i++)
  {
    uint8_t tem = data[index][7 - i];
    data[index][7 - i] = data[index][i];
    data[index][i] = tem;
  }
  refreshLed();
}

showDate(functions.getCurrMode()); // 显示日期,定义在Main.h中

showDate(uint8_t showmode)显示日期

//  显示日期
void showDate(uint8_t showmode)
{
    Dates dates = datetimes.getDates();
    if (dates.d == powerFlag)
    {
        return; // 如果天数没有发生改变,则不更新时间显示
    }
    powerFlag = dates.d;
    displayData[3] = dates.y / 100;
    displayData[2] = dates.y % 100;
    displayData[1] = dates.m;
    displayData[0] = dates.d;
    if (showmode == 1)
    {
        lattice.showLongNumber(displayData);
    }
    else if (showmode == 0)
    {
        lattice.showDate3(displayData);
    }
    else
    {
        displayData[3] = dates.m / 10;
        displayData[2] = dates.m % 10;
        displayData[1] = dates.d / 10;
        displayData[0] = dates.d % 10;
        lattice.showDate2(displayData);
    }
}

Lattice::showLongNumber(uint8_t *arr)

//显示日期
void Lattice::showLongNumber(uint8_t *arr)
{
  if (isReset)
  {
    isReset = false;
    for (int k = 0; k < columnLength; k++)
    {
      // 得到新的要显示的数字
      unsigned char *tmp = getNumData(arr[k], false);
      for (int x = 0; x < 8; x++)
      {
        buff[k][x] = tmp[x];
      }
      free(tmp);
    }
    for (int i = 0; i < rowLength; i++)
    {
      downMoveBuff();
      System::delay_time(80, NULL);
    }
  }
}

*Lattice::getNumData(uint8_t number, bool showzero) //得到要显示的数字

unsigned char *Lattice::getNumData(uint8_t number, bool showzero)
{
  if (number > 99)
  {
    // 超过最大值,返回99
    return getNumData(99, showzero);
  }
  // 分别获取个位数字 和 十位数字
  // const unsigned char *ten = (number / 10) < 1 && showzero ?
  // number_font_small[10] : number_font_small[(number / 10)],  *one = (number %
  // 10) == 0 && showzero ? number_font_small[10] : number_font_small[number %
  // 10];

  const unsigned char *ten = number_font_small[(number / 10)],
                      *one = (number % 10) == 0 && showzero
                                 ? number_font_small[10]
                                 : number_font_small[number % 10];

  unsigned char *arr = new uint8_t[rowLength];
  for (int i = 0; i < rowLength; i++)
  {
    // 将个位数左移,再加上十位数得到完整数字显示
    arr[i] = ten[i] + ((one[i] & 0xF0) >> 4);
  }
  return arr;
}

showTemperature()显示温度,定义在Main.h

showTemperature()显示温度

/**
 * @brief 显示温度(由于这个温度显示不是很准确,所以我也就没有花很多心思来搞这个,就简单弄一个显示就完事了)
 *
 */
void showTemperature()
{
    int t = datetimes.getTemperature();
    if (t == powerFlag)
    {
        // 温度没有发生改变则忽略
        return;
    }
    powerFlag = t;
    lattice.reset();
    displayData[3] = 0;
    displayData[2] = 0x00;
    displayData[1] = t / 100;
    displayData[0] = t % 100;
    lattice.showTemperature(displayData);
}

DateTimes::getTemperature()

用的HTU21D库

// 获取温度信息
int DateTimes::getTemperature()
{
  if (sensor.measure())
  {
    float temperature = sensor.getTemperature();
    float humidity = sensor.getHumidity();
    Serial.print("获取到的温度为 (°C): ");
    Serial.println(temperature);
    Serial.print("获取到的湿度为 (%RH): ");
    Serial.println(humidity);
    return (int)temperature * 100;
  }
  else
  {
    return 88 * 100;
  }
}

showBiliFans()显示bilibili粉丝数量,定义在Main.h中

showBiliFans()显示bilibili粉丝数量

void showBiliFans()
{
    httptool.bilibiliFans();            // 每次进来判断是否需要更新bilibili粉丝信息,这里是五分钟更新一次
    Times times = datetimes.getTimes(); // 获取系统时间
    if (displayData[0] != times.s && powerFlag < 99999)
    {
        displayData[0] = times.s; // 这里由于没有缓存数组了,所以就用这个缓存数组
        lattice.lightning(3); //bilibili眼睛闪烁
    }
    long fans = httptool.fans;
    if (fans == powerFlag)
    {
        return;
    }
    lattice.reset();
    powerFlag = fans;
    for (int i = 0; i < 4; i++) // 将千万的数字分解成四个数组
    {
        displayData[i] = fans % 100;
        fans = fans / 100;
    }
    if (powerFlag >= 99999)
    {
        lattice.showLongNumber(displayData); // 如果粉丝数量大于这个数量时,就显示全部的粉丝数量
    }
    else
    {
        lattice.showNumAndIcon(2, displayData); // 如果粉丝数量不大于那个数量时,就显示图标加数量
    }
}

showUserData(functions.getCurrMode()); // 显示用户自定义的数据,定义在Main.h中

showUserData(functions.getCurrMode()); // 显示用户自定义的数据

void showUserData(uint8_t showmode)
{
    if (showmode == 0)
    {
        lattice.showUserData(showmode); // 优先模式
        return;
    }
    if (millis() - powerFlag < 100 + (lattice.latticeSetting.speed * 10)) // 如果当前时间减上次刷新时间小于用户设置的速度,则不刷新
    {
        return; // 时间间隔小于100ms就不执行
    }
    powerFlag = millis();
    lattice.showUserData(showmode); // 刷新显示内容
}

showCountDown(); // 显示倒计时,定义在Main.h中

showCountDown(); // 显示倒计时

// * @brief 显示倒计时
void showCountDown()
{
    bool showmode = true, minutechange = false;
    long countdown = datetimes.getCountdownTimestamp();    //获取倒计时时间戳信息
    long timestamp = datetimes.getTimestamp() - 8 * 3600;  //获取时间戳信息
    if (countdown - timestamp == powerFlag2 || powerFlag2 <= 0)
    {
        // 时间没有发生改变,则跳过
        return;
    }
    // 倒计时时间戳 - 当前时间戳时间小于一天则 按 时分秒 来进行倒计时
    if ((countdown - timestamp) < (24 * 3600))
    {
        showmode = false;
        minutechange = true;
        // 倒计时小于一天,则使用时分秒的显示模式
        if ((countdown - timestamp) == powerFlag2)
        {
            // 这里表示秒钟数没有发生改变
            return;
        }
        if (((countdown - timestamp) / 3600) != (powerFlag2 / 3600))
        {
            // 倒计时时钟发生改变
            lattice.reset();
            displayData[0] = 0;
            displayData[1] = 1;
            displayData[2] = 2;
        }
    }
    else
    {
        showmode = true;
        // 这里判断天数是否发生改变,如果天数发生改变则需要重置一下显示
        if (((countdown - timestamp) / 3600 / 24) != (powerFlag2 / 3600 / 24))
        {
            lattice.reset();
            // 倒计时日发生改变
            displayData[0] = 0;
            displayData[1] = 1;
            displayData[2] = 2;
        }
        // 这里判断分钟数是否发生改变,如果分钟数发生改变,则需要刷新显示
        if (((countdown - timestamp) / 60) != (powerFlag2 / 60))
        {
            // 这里表示分钟数值发生改变
            minutechange = true;
        }
    }
    powerFlag2 = (countdown - timestamp) < 1 ? 0 : (countdown - timestamp);
    lattice.showCountDownTime(powerFlag2, displayData, showmode, minutechange);
    for (int i = 0; i < 3; i++)
    {
        displayData[i] = displayData[i] == 6 ? 1 : ++displayData[i];
    }
}

System::reset_system(); // 重置系统,定义在System.cpp

void System::reset_system()
{
    EEPROMTool.clearAll(); // 删除EEPRON信息
    ESP.restart();         // 重启系统
}

sleepTimeLoop()休眠,定义在Main.h

sleepTimeLoop()休眠

//休眠
void sleepTimeLoop()
{
    Times times = datetimes.getTimes();
    uint8_t starttime = sleepTime[0] * 100 + sleepTime[1]; // 开始时间
    uint8_t endtime = sleepTime[2] * 100 + sleepTime[3];   // 结束时间
    if (starttime == endtime)                              // 如果开始时间和结束时间是一样的话,就什么都不做
    {
        return;
    }
    uint8_t currtime = times.h * 100 + times.m; // 当前时间
    if (starttime < endtime)                    // 如果开始时间小于结束时间,则只需要判断当前时间是否在开始时间和结束时间的区间范围内
    {
        if (currtime >= starttime && currtime < endtime) // 如果时间在休眠时间范围内则休眠
        {
            if (!isSleepMode)
            {
                isSleepMode = true;    // 标记进入睡眠模式
                if (sleepTime[4] == 0) // 判断亮度是否为0,如果亮度为0的话,则熄灭屏幕
                {
                    lattice.shutdown(true); // 休眠操作(目前就是把屏幕熄灭)
                }
                else
                {
                    lattice.setBrightness(sleepTime[4], false); // 亮度不为0则将设置屏幕亮度为指定的屏幕亮度
                }
            }
        }
        else
        {
            if (isSleepMode)
            {
                // 这里避免出现误操作,每次都将屏幕点亮,将屏幕亮度设置到预设亮度
                isSleepMode = false;                                             // 标记退出睡眠模式
                lattice.shutdown(false);                                         // 退出休眠操作(目前就是把屏幕点亮)
                lattice.setBrightness(lattice.latticeSetting.brightness, false); // 亮度不为0则将设置屏幕亮度为指定的屏幕亮度
            }
        }
    }
    else // 如果开始时间大于结束时间,表示表示当前时间在反向的范围内则不需要休眠
    {
        if (currtime >= endtime && currtime < starttime) // 如果时间在休眠时间范围内则休眠
        {
            if (isSleepMode)
            {
                // 这里避免出现误操作,每次都将屏幕点亮,将屏幕亮度设置到预设亮度
                isSleepMode = false;                                             // 标记退出睡眠模式
                lattice.shutdown(false);                                         // 退出休眠操作(目前就是把屏幕点亮)
                lattice.setBrightness(lattice.latticeSetting.brightness, false); // 亮度不为0则将设置屏幕亮度为指定的屏幕亮度
            }
        }
        else
        {
            if (!isSleepMode)
            {
                isSleepMode = true;    // 标记进入睡眠模式
                if (sleepTime[4] == 0) // 判断亮度是否为0,如果亮度为0的话,则熄灭屏幕
                {
                    lattice.shutdown(true); // 休眠操作(目前就是把屏幕熄灭)
                }
                else
                {
                    lattice.setBrightness(sleepTime[4], false); // 亮度不为0则将设置屏幕亮度为指定的屏幕亮度
                }
            }
        }
    }
}

loop()看完了,比较潦草。好多函数都没看到,是没用上还是啥

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值