自定义字体下OLED局部刷新问题求助(Arduino+Adafruit库)
Arduino OLED自定义字体局部刷新解决方案
问题背景
基于Arduino Nano开发NTC测温+OLED显示项目,使用Adafruit OLED库:
- 默认字体下,通过
setTextColor(WHITE, BLACK)替代clearDisplay()解决了屏幕闪烁问题 - 切换自定义字体后,上述方案失效:温度更新时旧值残留;使用
clearDisplay()则导致℃等固定元素闪烁 - 需求:仅刷新温度数值区域,消除整体闪烁
问题代码示例
默认字体(正常工作)
TRANS_OLED.setTextSize(5); TRANS_OLED.setTextColor(WHITE); TRANS_OLED.setCursor(15, 15); TRANS_OLED.print(tempCelsiusDecimal); TRANS_OLED.display(); TRANS_OLED.setTextSize(1); TRANS_OLED.setTextColor(WHITE); TRANS_OLED.setCursor(80, 10); TRANS_OLED.print("o"); TRANS_OLED.display(); TRANS_OLED.setTextSize(5); TRANS_OLED.setCursor(90, 15); TRANS_OLED.print("C"); TRANS_OLED.display(); TRANS_OLED.setTextSize(5); TRANS_OLED.setTextColor(WHITE, BLACK); TRANS_OLED.setCursor(15, 15); TRANS_OLED.print(tempCelsiusDecimal); TRANS_OLED.display();
自定义字体(存在闪烁/覆盖问题)
TRANS_OLED.setFont(&DSEG7_Classic_Mini_Bold_40); TRANS_OLED.setTextSize(0); TRANS_OLED.setTextColor(WHITE); TRANS_OLED.setCursor(30, 50); TRANS_OLED.print(tempCelsiusDecimal); TRANS_OLED.display(); TRANS_OLED.setFont(&Dialog_plain_12); TRANS_OLED.setTextSize(0); TRANS_OLED.setTextColor(WHITE); TRANS_OLED.setCursor(100, 15); TRANS_OLED.print("o"); TRANS_OLED.display(); TRANS_OLED.clearDisplay();
完整项目代码
#include <Arduino.h> #include <SPI.h> #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <Fonts/DSEG7_Classic_Mini_Bold_40.h> #include <Fonts/Dialog_plain_12.h> #include <Fonts/DejaVu_Sans_Mono_9.h> // 128x32 px OLED 参数 #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 32 #define OLED_RESET -1 #define SCREEN_ADDRESS 0x3C #define THERMISTOR_PIN A0 // 128x64px OLED 参数 #define TRANS_WIDTH 128 #define TRANS_HEIGHT 64 #define TRANS_OLED_MOSI 9 #define TRANS_OLED_CLK 10 #define TRANS_OLED_DC 11 #define TRANS_OLED_CS 12 #define TRANS_OLED_RESET 13 float thermistorResistance, tempKelvin, tempCelsius, flowRate; const float beta = 3977.0; const float tempRef = 298.15; const float R0 = 10000.0; const float R1 = 10000.02; const int sampleNumber = 5; float thermistorVolt[sampleNumber]; float averageThermistor; int tempCelsiusDecimal; void Temperature(); void TRANS_OLED_DISPLAY(); Adafruit_SSD1306 TRANS_OLED(TRANS_WIDTH, TRANS_HEIGHT, TRANS_OLED_MOSI, TRANS_OLED_CLK, TRANS_OLED_DC, TRANS_OLED_RESET, TRANS_OLED_CS); void setup() { Serial.begin(9600); analogReference(EXTERNAL); if (!TRANS_OLED.begin(SSD1306_SWITCHCAPVCC)) { Serial.println(F("SSD1306 allocation failed")); for (;;); } TRANS_OLED.clearDisplay(); TRANS_OLED.dim(0); } void loop() { Temperature(); TRANS_OLED_DISPLAY(); } void TRANS_OLED_DISPLAY() { // Versiyon 1: 默认字体 // TRANS_OLED.setTextSize(5); // TRANS_OLED.setTextColor(WHITE); // TRANS_OLED.setCursor(15, 15); // TRANS_OLED.print(tempCelsiusDecimal); // TRANS_OLED.display(); // TRANS_OLED.setTextSize(1); // TRANS_OLED.setTextColor(WHITE); // TRANS_OLED.setCursor(80, 10); // TRANS_OLED.print("o"); // TRANS_OLED.display(); // TRANS_OLED.setTextSize(5); // TRANS_OLED.setCursor(90, 15); // TRANS_OLED.print("C"); // TRANS_OLED.display(); // TRANS_OLED.setTextSize(5); // TRANS_OLED.setTextColor(WHITE, BLACK); // TRANS_OLED.setCursor(15, 15); // TRANS_OLED.print(tempCelsiusDecimal); // TRANS_OLED.display(); // Version 2: 自定义字体(存在问题) TRANS_OLED.setFont(&DSEG7_Classic_Mini_Bold_40); TRANS_OLED.setTextSize(0); TRANS_OLED.setCursor(30, 50); TRANS_OLED.setTextColor(WHITE); TRANS_OLED.print(tempCelsiusDecimal); TRANS_OLED.display(); TRANS_OLED.setFont(&Dialog_plain_12); TRANS_OLED.setTextSize(0); TRANS_OLED.setTextColor(WHITE); TRANS_OLED.setCursor(100, 15); TRANS_OLED.print("o"); TRANS_OLED.display(); TRANS_OLED.clearDisplay(); } void Temperature() { for (uint8_t i = 0; i < sampleNumber; i++) { thermistorVolt[i] = analogRead(THERMISTOR_PIN); delay(10); } averageThermistor = 0; for (uint8_t j = 0; j < sampleNumber; j++) { averageThermistor += thermistorVolt[j]; } averageThermistor = averageThermistor / sampleNumber; thermistorResistance = R1 / (1023.0 / averageThermistor - 1.0); tempKelvin = (1.0 / tempRef) + (log(thermistorResistance / R0) / beta); tempKelvin = 1.0 / tempKelvin; tempCelsius = tempKelvin - 273.15; tempCelsiusDecimal = (int)tempCelsius; }
解决方案
核心思路:固定元素只绘制一次,温度区域精准清除后重绘,缩小刷新范围
步骤1:初始化时绘制固定元素
在setup()函数末尾添加固定元素绘制代码,之后不再重复绘制:
// 绘制固定的℃符号 TRANS_OLED.setFont(&Dialog_plain_12); TRANS_OLED.setTextSize(0); TRANS_OLED.setTextColor(WHITE); TRANS_OLED.setCursor(100, 15); TRANS_OLED.print("o"); TRANS_OLED.setCursor(110, 15); TRANS_OLED.print("C"); TRANS_OLED.display();
步骤2:修改显示函数,实现局部刷新
重写TRANS_OLED_DISPLAY()函数,仅处理温度区域的清除与重绘:
void TRANS_OLED_DISPLAY() { // 定义温度显示区域的参数(根据字体实际尺寸调整) const int temp_x = 30; const int temp_y = 50; const int temp_width = 60; const int temp_height = 40; // 1. 清除旧温度区域(黑色填充,完全覆盖旧文本) TRANS_OLED.fillRect(temp_x, temp_y - temp_height + 10, temp_width, temp_height, BLACK); // 2. 设置自定义字体并绘制新温度值 TRANS_OLED.setFont(&DSEG7_Classic_Mini_Bold_40); TRANS_OLED.setTextSize(0); TRANS_OLED.setTextColor(WHITE); TRANS_OLED.setCursor(temp_x, temp_y); TRANS_OLED.print(tempCelsiusDecimal); // 3. 仅刷新一次屏幕 TRANS_OLED.display(); }
关键说明
fillRect的宽高参数需根据自定义字体的实际尺寸调整,确保完全覆盖旧温度文本- 固定元素只在初始化时绘制一次,避免重复刷新导致闪烁
- 每次仅更新温度区域,减少屏幕数据传输量,彻底消除整体闪烁
内容的提问来源于stack exchange,提问作者Atahan
相关产品推荐
相关产品推荐

