You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义字体下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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 18:10:37