文号D891220
133
0
收藏
编辑文章
提问求助类话题必须提供充足的已知条件,介绍为了解决问题已经做的工作。凡可以通过简单搜索或查阅教科书解决的问题,不应提问求助。连续发布提问求助、懒惰型提问、上帝式提问等,将受到处罚直至封号。

求助!制作多功能推力采集器时,SH1106显示屏无响应怎么办?

我遇到了一个棘手的问题:在我的Arduino项目中,我无法让OLED显示屏正常工作。无论我怎么调试和修改代码,显示屏始终保持黑屏状态。我需要你们的建议和帮助来解决这个问题。

OLED显示屏在我的Arduino 推力采集器中是至关重要的组成部分。我使用了Arduino NANO作为主控制器,并集成了一块128x64分辨率的SH1106型号的OLED显示屏。尽管我已经仔细检查了硬件连接,并参考了相关文献和示例代码,但我仍然无法使显示屏显示任何内容。

下面是程序代码:

#include <SD.h>
#include <HX711_ADC.h>
#include <EEPROM.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>
#include <splash.h>

// 引脚定义
const int HX711_dout = 5;  // HX711 数据引脚
const int HX711_sck = 4;   // HX711 时钟引脚
const int buttonPin = 3;   // 复位按钮引脚
const int buzzerPin = 8;   // 蜂鸣器引脚
const int redLedPin = 6;   // 红色 LED 引脚
const int greenLedPin = 7; // 绿色 LED 引脚
const int curveButtonPin = 9; // 曲线显示按钮引脚

// 参数设置
const int debounceDelay = 50;           // 按钮去抖动延迟
const int serialPrintInterval = 500;    // 串口打印间隔
const float calibrationValue = 1;   // HX711 校准值
const int bufferSize = 60;              // 缓冲区大小
const float thrustThreshold = 1.0;      // 推力阈值 (牛顿)
const unsigned long recordDuration = 12000; // 记录持续时间 (毫秒)

// OLED 显示屏对象
Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire);

// HX711 对象
HX711_ADC LoadCell(HX711_dout, HX711_sck);

// 卡尔曼滤波器类
class KalmanFilter {
public:
    KalmanFilter(float processNoise, float sensorNoise, float estimatedError, float initialValue) {
        Q = processNoise;
        R = sensorNoise;
        P = estimatedError;
        X = initialValue;
    }

    float updateEstimate(float measurement) {
        P += Q;
        K = P / (P + R);
        X += K * (measurement - X);
        P *= (1 - K);
        return X;
    }

private:
    float Q;  // 过程噪声协方差
    float R;  // 传感器噪声协方差
    float P;  // 估计误差协方差
    float K;  // 卡尔曼增益
    float X;  // 估计值
};

// 变量定义
float maxThrust = 0.0;                // 最大推力
bool displayMode = false;            // 显示模式标志
unsigned long lastDebounceTime = 0;  // 上次去抖动时间
float thrustData[bufferSize] = {0};  // 推力数据缓冲区
int dataIndex = 0;                   // 数据索引
KalmanFilter kalman(0.125, 32, 1023, 0); // 卡尔曼滤波器对象
bool recordThrustCurve = false;      // 记录推力曲线标志
unsigned long thrustStartTime = 0;  // 推力记录开始时间

void setup() {
    Serial.begin(57600);
    pinMode(buttonPin, INPUT_PULLUP);
    pinMode(buzzerPin, OUTPUT);
    pinMode(redLedPin, OUTPUT);
    pinMode(greenLedPin, OUTPUT);
    pinMode(curveButtonPin, INPUT_PULLUP);

    display.begin(0x3C, true);
    display.display(); // 显示启动画面
    delay(1000);
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(SH110X_WHITE);
    display.setCursor(0, 0);
    display.println(F("Checking modules...")); // 检查各模块
    display.display();

    LoadCell.begin();
    LoadCell.start(2000, true);
    LoadCell.setCalFactor(calibrationValue);

    if (LoadCell.getTareTimeoutFlag()) {
        displayError("HX711 initialization failed"); // HX711 初始化失败
    } else {
        display.println(F("HX711 OK")); // HX711 正常
        display.display();
    }

    if (!SD.begin()) {
        displayError("SD card initialization failed"); // SD卡初始化失败
    } else {
        display.println(F("SD card OK")); // SD卡正常
        display.display();
    }

    createDataFile();
    digitalWrite(greenLedPin, HIGH);
}

void loop() {
    static bool newDataReady = false;
    static unsigned long lastSerialPrint = 0;

    if (LoadCell.update()) {
        newDataReady = true;
    }

    if (newDataReady) {
        processThrustData(); // 处理推力数据
        newDataReady = false;
    }

    if (millis() - lastSerialPrint >= serialPrintInterval) {
        printThrustData(); // 打印推力数据
        lastSerialPrint = millis();
    }

    checkButtonPress(); // 检查按钮按下状态
    updateDisplay();    // 更新显示

    if (recordThrustCurve && (millis() - thrustStartTime >= recordDuration)) {
        saveThrustDataToFile(); // 保存推力数据到文件
        recordThrustCurve = false;
    }
}

// 处理推力数据
void processThrustData() {
    float rawThrust = LoadCell.getData(); // 获取原始推力数据
    float thrust = kalman.updateEstimate(rawThrust); // 应用卡尔曼滤波器

    if (thrust > maxThrust) {
        maxThrust = thrust; // 更新最大推力
    }

    // 检查推力是否超过阈值
    if (!recordThrustCurve && (thrust / 1000 * 9.8) > thrustThreshold) {
        thrustStartTime = millis(); // 记录推力开始时间
        dataIndex = 0;              // 数据索引重置
        recordThrustCurve = true;   // 开始记录推力曲线
    }

    if (recordThrustCurve) {
        thrustData[dataIndex] = thrust / 1000 * 9.8; // 将推力值存入缓冲区
        dataIndex = (dataIndex + 1) % bufferSize;    // 更新索引
    }
}

// 打印推力数据
void printThrustData() {
    Serial.print(F("Current thrust: ")); // 当前推力
    Serial.print(LoadCell.getData());
    Serial.print(F(" Max thrust: ")); // 最大推力
    Serial.println(maxThrust);
}

// 检查按钮按下状态
void checkButtonPress() {
    if (digitalRead(buttonPin) == LOW) {
        unsigned long currentTime = millis();
        if (currentTime - lastDebounceTime > debounceDelay) {
            LoadCell.tareNoDelay();  // 复位传感器
            maxThrust = 0.0;         // 重置最大推力
            recordThrustCurve = false; // 停止记录推力曲线
        }
        lastDebounceTime = currentTime;
    }

    if (digitalRead(curveButtonPin) == LOW) {
        unsigned long currentTime = millis();
        if (currentTime - lastDebounceTime > debounceDelay) {
            displayMode = !displayMode; // 切换显示模式
        }
        lastDebounceTime = currentTime;
    }
}

// 更新显示
void updateDisplay() {
    display.clearDisplay();
    if (displayMode) {
        plotThrustCurve(); // 绘制推力曲线
    } else {
        displayThrustValue(); // 显示推力值
    }
    display.display();
}

// 显示错误信息
void displayError(const char* message) {
    display.clearDisplay();
    display.setCursor(0, 0);
    display.setTextSize(1); // 使用小字体以适应更多文字
    display.setTextColor(SH110X_WHITE);

    // 将消息拆分为多行显示
    int maxLineLength = 16; // 设定每行最多显示的字符数
    int messageLength = strlen(message);
    int lineCount = (messageLength + maxLineLength - 1) / maxLineLength;

    for (int i = 0; i < lineCount; i++) {
        int startIndex = i * maxLineLength;
        int endIndex = min(startIndex + maxLineLength, messageLength);
        String line = String(message).substring(startIndex, endIndex);
        display.println(line);
    }

    display.display();

    // 红色 LED 闪烁提示
    for (int i = 0; i < 5; i++) {
        digitalWrite(redLedPin, HIGH);
        delay(500);
        digitalWrite(redLedPin, LOW);
        delay(500);
    }

    while (true); // 停止程序执行
}

// 绘制推力曲线并增加坐标轴
void plotThrustCurve() {
    display.drawLine(10, 32, 128, 32, SH110X_WHITE); // 绘制 X 轴中线
    display.drawLine(10, 0, 10, 64, SH110X_WHITE);  // 绘制 Y 轴

    // 绘制 X 轴刻度
    for (int i = 0; i < 120; i += 20) {
        display.drawLine(10 + i, 31, 10 + i, 33, SH110X_WHITE); // 绘制小刻度
        display.setCursor(5 + i, 35);
        display.setTextSize(1);
        display.print(i);
    }

    // 绘制 Y 轴刻度
    for (int i = 0; i < 64; i += 16) {
        display.drawLine(9, i, 11, i, SH110X_WHITE); // 绘制小刻度
        display.setCursor(0, i);
        display.setTextSize(1);
        display.print(64 - i);
    }

    for (int i = 1; i < bufferSize; i++) {
        int x1 = map(i - 1, 0, bufferSize - 1, 11, 127);
        int y1 = map(thrustData[i - 1], 0, maxThrust, 63, 0);
        int x2 = map(i, 0, bufferSize - 1, 11, 127);
        int y2 = map(thrustData[i], 0, maxThrust, 63, 0);
        display.drawLine(x1, y1, x2, y2, SH110X_WHITE);
    }
}

// 显示推力值
void displayThrustValue() {
    display.setCursor(0, 0);
    display.setTextSize(1);
    display.setTextColor(SH110X_WHITE);
    display.print(F("Current thrust: "));
    display.print(LoadCell.getData());
    display.println(F(" g"));

    display.print(F("Max thrust: "));
    display.print(maxThrust);
    display.println(F(" g"));
}

// 创建数据文件
void createDataFile() {
    int fileIndex = 1;
    char fileName[13]; // 8.3 文件名格式
    while (true) {
        snprintf(fileName, sizeof(fileName), "DATA%d.TXT", fileIndex);
        if (!SD.exists(fileName)) {
            break;
        }
        fileIndex++;
    }

    File dataFile = SD.open(fileName, FILE_WRITE);
    if (dataFile) {
        dataFile.println(F("Time (ms), Thrust (N)"));
        dataFile.close();
        Serial.print(F("Created file: "));
        Serial.println(fileName);
    } else {
        displayError("File creation failed"); // 文件创建失败
    }
}

// 保存推力数据到文件
void saveThrustDataToFile() {
    int fileIndex = 1;
    char fileName[13];
    while (true) {
        snprintf(fileName, sizeof(fileName), "DATA%d.TXT", fileIndex);
        if (!SD.exists(fileName)) {
            break;
        }
        fileIndex++;
    }

    File dataFile = SD.open(fileName, FILE_WRITE);
    if (dataFile) {
        for (int i = 0; i < bufferSize; i++) {
            unsigned long timestamp = thrustStartTime + i * (recordDuration / bufferSize);
            dataFile.print(timestamp);
            dataFile.print(F(", "));
            dataFile.println(thrustData[i]);
        }
        dataFile.close();
        Serial.print(F("Data saved to "));
        Serial.println(fileName);
        tone(buzzerPin, 1000, 500); // 发出蜂鸣提示
        digitalWrite(greenLedPin, LOW); // 绿色 LED 熄灭
        digitalWrite(redLedPin, HIGH);  // 红色 LED 亮起
        delay(500);
        digitalWrite(redLedPin, LOW);  // 红色 LED 熄灭
        digitalWrite(greenLedPin, HIGH); // 绿色 LED 亮起
    } else {
        displayError("File write failed"); // 文件写入失败
    }
}

在运行上述代码时,OLED显示屏未能显示任何内容。经过多次测试,显示屏保持黑屏状态。我已经尝试好多次了,但问题依然存在。

为了解决这个问题,我已经尝试了以下多种方法:

检查硬件连接:多次检查引脚连接,确保与示例和数据手册中的建议一致。

调试代码:尝试了不同的初始化序列和显示函数,包括使用Adafruit和U8g2等库,但都没有取得任何进展。

查阅资料和论坛:查阅了官方文档、库文档以及一些Arduino论坛中的类似问题讨论,但未找到适用于我的情况的解决方案

但是我在ARDUINO的测试程序中测试过了,发现这块显示屏可以正常显示如下内容:

/*********************************************************************
  This is an example for our Monochrome OLEDs based on SH110X drivers

  This example is for a 128x64 size display using I2C to communicate
  3 pins are required to interface (2 I2C and one reset)

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Limor Fried/Ladyada  for Adafruit Industries.
  BSD license, check license.txt for more information
  All text above, and the splash screen must be included in any redistribution

  i2c SH1106 modified by Rupert Hirst  12/09/21
*********************************************************************/



#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>

/* Uncomment the initialize the I2C address , uncomment only one, If you get a totally blank screen try the other*/
#define i2c_Address 0x3c //initialize with the I2C addr 0x3C Typically eBay OLED's
//#define i2c_Address 0x3d //initialize with the I2C addr 0x3D Typically Adafruit OLED's

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1   //   QT-PY / XIAO
Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);


#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2


#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000
};


void setup()   {

  Serial.begin(9600);

  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.

  delay(250); // wait for the OLED to power up
  display.begin(i2c_Address, true); // Address 0x3C default
 //display.setContrast (0); // dim display
 
  display.display();
  delay(2000);

  // Clear the buffer.
  display.clearDisplay();

  // draw a single pixel
  display.drawPixel(10, 10, SH110X_WHITE);
  // Show the display buffer on the hardware.
  // NOTE: You _must_ call display after making any drawing commands
  // to make them visible on the display hardware!
  display.display();
  delay(2000);
  display.clearDisplay();

  // draw many lines
  testdrawline();
  display.display();
  delay(2000);
  display.clearDisplay();

  // draw rectangles
  testdrawrect();
  display.display();
  delay(2000);
  display.clearDisplay();

  // draw multiple rectangles
  testfillrect();
  display.display();
  delay(2000);
  display.clearDisplay();

  // draw mulitple circles
  testdrawcircle();
  display.display();
  delay(2000);
  display.clearDisplay();

  // draw a SH110X_WHITE circle, 10 pixel radius
  display.fillCircle(display.width() / 2, display.height() / 2, 10, SH110X_WHITE);
  display.display();
  delay(2000);
  display.clearDisplay();

  testdrawroundrect();
  delay(2000);
  display.clearDisplay();

  testfillroundrect();
  delay(2000);
  display.clearDisplay();

  testdrawtriangle();
  delay(2000);
  display.clearDisplay();

  testfilltriangle();
  delay(2000);
  display.clearDisplay();

  // draw the first ~12 characters in the font
  testdrawchar();
  display.display();
  delay(2000);
  display.clearDisplay();



  // text display tests
  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);
  display.setCursor(0, 0);
  display.println("Failure is always an option");
  display.setTextColor(SH110X_BLACK, SH110X_WHITE); // 'inverted' text
  display.println(3.141592);
  display.setTextSize(2);
  display.setTextColor(SH110X_WHITE);
  display.print("0x"); display.println(0xDEADBEEF, HEX);
  display.display();
  delay(2000);
  display.clearDisplay();

  // miniature bitmap display
  display.drawBitmap(30, 16,  logo16_glcd_bmp, 16, 16, 1);
  display.display();
  delay(1);

  // invert the display
  display.invertDisplay(true);
  delay(1000);
  display.invertDisplay(false);
  delay(1000);
  display.clearDisplay();

  // draw a bitmap icon and 'animate' movement
  testdrawbitmap(logo16_glcd_bmp, LOGO16_GLCD_HEIGHT, LOGO16_GLCD_WIDTH);
}


void loop() {

}


void testdrawbitmap(const uint8_t *bitmap, uint8_t w, uint8_t h) {
  uint8_t icons[NUMFLAKES][3];

  // initialize
  for (uint8_t f = 0; f < NUMFLAKES; f++) {
    icons[f][XPOS] = random(display.width());
    icons[f][YPOS] = 0;
    icons[f][DELTAY] = random(5) + 1;

    Serial.print("x: ");
    Serial.print(icons[f][XPOS], DEC);
    Serial.print(" y: ");
    Serial.print(icons[f][YPOS], DEC);
    Serial.print(" dy: ");
    Serial.println(icons[f][DELTAY], DEC);
  }

  while (1) {
    // draw each icon
    for (uint8_t f = 0; f < NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SH110X_WHITE);
    }
    display.display();
    delay(200);

    // then erase it + move it
    for (uint8_t f = 0; f < NUMFLAKES; f++) {
      display.drawBitmap(icons[f][XPOS], icons[f][YPOS], bitmap, w, h, SH110X_BLACK);
      // move it
      icons[f][YPOS] += icons[f][DELTAY];
      // if its gone, reinit
      if (icons[f][YPOS] > display.height()) {
        icons[f][XPOS] = random(display.width());
        icons[f][YPOS] = 0;
        icons[f][DELTAY] = random(5) + 1;
      }
    }
  }
}


void testdrawchar(void) {
  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);
  display.setCursor(0, 0);

  for (uint8_t i = 0; i < 168; i++) {
    if (i == '\n') continue;
    display.write(i);
    if ((i > 0) && (i % 21 == 0))
      display.println();
  }
  display.display();
  delay(1);
}

void testdrawcircle(void) {
  for (int16_t i = 0; i < display.height(); i += 2) {
    display.drawCircle(display.width() / 2, display.height() / 2, i, SH110X_WHITE);
    display.display();
    delay(1);
  }
}

void testfillrect(void) {
  uint8_t color = 1;
  for (int16_t i = 0; i < display.height() / 2; i += 3) {
    // alternate colors
    display.fillRect(i, i, display.width() - i * 2, display.height() - i * 2, color % 2);
    display.display();
    delay(1);
    color++;
  }
}

void testdrawtriangle(void) {
  for (int16_t i = 0; i < min(display.width(), display.height()) / 2; i += 5) {
    display.drawTriangle(display.width() / 2, display.height() / 2 - i,
                         display.width() / 2 - i, display.height() / 2 + i,
                         display.width() / 2 + i, display.height() / 2 + i, SH110X_WHITE);
    display.display();
    delay(1);
  }
}

void testfilltriangle(void) {
  uint8_t color = SH110X_WHITE;
  for (int16_t i = min(display.width(), display.height()) / 2; i > 0; i -= 5) {
    display.fillTriangle(display.width() / 2, display.height() / 2 - i,
                         display.width() / 2 - i, display.height() / 2 + i,
                         display.width() / 2 + i, display.height() / 2 + i, SH110X_WHITE);
    if (color == SH110X_WHITE) color = SH110X_BLACK;
    else color = SH110X_WHITE;
    display.display();
    delay(1);
  }
}

void testdrawroundrect(void) {
  for (int16_t i = 0; i < display.height() / 2 - 2; i += 2) {
    display.drawRoundRect(i, i, display.width() - 2 * i, display.height() - 2 * i, display.height() / 4, SH110X_WHITE);
    display.display();
    delay(1);
  }
}

void testfillroundrect(void) {
  uint8_t color = SH110X_WHITE;
  for (int16_t i = 0; i < display.height() / 2 - 2; i += 2) {
    display.fillRoundRect(i, i, display.width() - 2 * i, display.height() - 2 * i, display.height() / 4, color);
    if (color == SH110X_WHITE) color = SH110X_BLACK;
    else color = SH110X_WHITE;
    display.display();
    delay(1);
  }
}

void testdrawrect(void) {
  for (int16_t i = 0; i < display.height() / 2; i += 2) {
    display.drawRect(i, i, display.width() - 2 * i, display.height() - 2 * i, SH110X_WHITE);
    display.display();
    delay(1);
  }
}

void testdrawline() {
  for (int16_t i = 0; i < display.width(); i += 4) {
    display.drawLine(0, 0, i, display.height() - 1, SH110X_WHITE);
    display.display();
    delay(1);
  }
  for (int16_t i = 0; i < display.height(); i += 4) {
    display.drawLine(0, 0, display.width() - 1, i, SH110X_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();
  for (int16_t i = 0; i < display.width(); i += 4) {
    display.drawLine(0, display.height() - 1, i, 0, SH110X_WHITE);
    display.display();
    delay(1);
  }
  for (int16_t i = display.height() - 1; i >= 0; i -= 4) {
    display.drawLine(0, display.height() - 1, display.width() - 1, i, SH110X_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();
  for (int16_t i = display.width() - 1; i >= 0; i -= 4) {
    display.drawLine(display.width() - 1, display.height() - 1, i, 0, SH110X_WHITE);
    display.display();
    delay(1);
  }
  for (int16_t i = display.height() - 1; i >= 0; i -= 4) {
    display.drawLine(display.width() - 1, display.height() - 1, 0, i, SH110X_WHITE);
    display.display();
    delay(1);
  }
  delay(250);

  display.clearDisplay();
  for (int16_t i = 0; i < display.height(); i += 4) {
    display.drawLine(display.width() - 1, 0, 0, i, SH110X_WHITE);
    display.display();
    delay(1);
  }
  for (int16_t i = 0; i < display.width(); i += 4) {
    display.drawLine(display.width() - 1, 0, i, display.height() - 1, SH110X_WHITE);
    display.display();
    delay(1);
  }
  delay(250);
}

这说明这块显示屏是可以使用的

可是无法显示😭 我的程序到底是有什么问题,OLED无法正确显示内容。这让我的项目进度受到了影响。希望能得到老师或者同学们的帮助,一起找出程序中的错误,并想办法解决。如果有谁能提供任何帮助或建议,请告诉我吧!谢谢大家!

[修改于 3个月10天前 - 2024/08/16 14:00:11]

来自 特殊话题声明:求助提问
0
还没有人评论哦~~

想参与大家的讨论?现在就 登录 或者 注册

WEIZHANGLI
机友
文章
2
回复
13
学术分
-2
2024/06/16注册,10时58分前活动

一名初中生

主体类型:个人
所属领域:无
认证方式:手机号
IP归属地:浙江
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
ID: {{user.uid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
回复
设为精选取消精选
评学术分
鼓励
编辑
查看历史
通过审核
移动文章
加入收藏取消收藏
退修或删除
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}
回复
加入收藏取消收藏