又到了日经的赛博悬丝诊脉环节,事实证明如果你不会用调试器打断点和串口输出来debug,就算有GPT帮你生成代码甚至求助贴也没用。
我遇到了一个棘手的问题:在我的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 / XIAOAdafruit_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 16static 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个月9天前 - 2024/08/16 19:28:46]
又到了日经的赛博悬丝诊脉环节,事实证明如果你不会用调试器打断点和串口输出来debug,就算有GPT帮你生成代码甚至求助贴也没用。
头一回见提问帖都用AI写的,文字部分几乎未提供任何有效信息,这得懒到什么程度啊!
时段 | 个数 |
---|---|
{{f.startingTime}}点 - {{f.endTime}}点 | {{f.fileCount}} |
200字以内,仅用于支线交流,主线讨论请采用回复功能。