这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 有奖活动 » 【分享开发笔记,赚取电动螺丝刀】墨水屏文本显示器

共1条 1/1 1 跳转至

【分享开发笔记,赚取电动螺丝刀】墨水屏文本显示器

助工
2026-03-31 23:25:01     打赏


【摘要】通过将任意文本内容通过MCU串口进行输入读取后,将输入的内容传输到墨水屏模块上进行显示,可以用来自定义文本内容、便携提示牌显示等。



一、硬件介绍

1、开发板

Arduino GIGA R1开发板,提供76个GPIO引脚(3个I2C、2个SPI等)采用双核STM32H747XI微控制器;

(480MHz的Cortex-M7内核和240 MHz的Cortex-M4内核),配备2MB闪存、1MB内存,以及6MB外部闪存和8MB SDRAM;

image-20260125205601548.png



2、墨水屏

2.9英寸三色墨水屏(黑白红),128×296像素,支持1位黑白/红显示功能


image-20260331100351411.png

image-20260331100351411


image.png

















































3、墨水屏转接板



24pinFFC_SPI转接板


image-20260315183634433.png






二、功能实现



1、硬件介绍

Arduino GIGA R1开发板通过硬件SPI接口与连接墨水屏模块的SPI转接板进行连接;



MCU引脚图



image-20260315182852109.png



2、功能效果


功能效果:通过串口读取功能实现文本内容的显示、以及指令控制与低功耗运行等效果;



image-20260331203700046.png



主要功能如下


1、自定义中文字库显示(UTF-8)

GxEPD2库本身不支持中文显示;

因此采用兼容Adafruit_GFX库格式的U8g2_for_Adafruit_GFX库进行UTF-8格式字体适配;

字体采用自定义的中文字体(30pt):支持常用中文、英文、数字、符号等显示;


2、自动换行 / 清屏

自动计算每个文字的宽度,当文本超出当前行宽度时自动换行;

当文本超出屏幕整体高度范围时,自动清屏并重新开始显示;


3、串口指令控制

通过串口工具发送指令 / 文本:


发送 clear:清空全屏显示内容;

发送 del:删除上一次显示的文本内容;

发送 文本内容:屏幕直接显示并自动排版,仅局部刷新文字所在的区域,每次操作后让墨水屏自动进入低功耗休眠模式;





3、实物效果



实物搭建效果图:


image-20260330225527648.png



硬件引脚连接方式


image.png















三、代码编写























三、代码编写




主要用到 GxEPD2 / U8g2_for_Adafruit_GFX 库



主要相关代码(Arduino)


#include "GxEPD2_display_selection_new_style.h"  // 定义 GxEPD2_DRIVER_CLASS / GxEPD2_DISPLAY_CLASS
#include <GxEPD2_3C.h>                           // 3色墨水屏定义

#include <U8g2_for_Adafruit_GFX.h>
#include "u8g2_font_cn_30.c"	// 自定义字体

#define ENABLE_GxEPD2_GFX 1  

U8G2_FOR_ADAFRUIT_GFX u8g2Fonts;

// 自定义SPI引脚
#define EPD_CS 10
#define EPD_DC 8
#define EPD_RST 9
#define EPD_BUSY 7

arduino::MbedSPI SPIn(12, 11, 13);  // Arduino SPI自定义

GxEPD2_DISPLAY_CLASS<GxEPD2_DRIVER_CLASS, GxEPD2_DRIVER_CLASS::HEIGHT> display(
  GxEPD2_DRIVER_CLASS(/*CS=*/EPD_CS, /*DC=*/EPD_DC, /*RST=*/EPD_RST, /*BUSY=*/EPD_BUSY));


// 光标X Y位置
int cursorX = 5;
int cursorY = 5;

// ascent: 文字最高的高度  descent: 文字最低的高度
int ascent, descent, textHeight;
int lastX, lastY, lastW, lastH;


// 文本内容显示
void showText(const char* text) {
  const char* remain = text;        // 剩余未显示文本

  while (*remain != '\0') {
    int availW = display.width() - 5 - cursorX;  // 当前行剩余宽度
    int usedW = 0;
    int charCount = 0;

    // 剩余空间不够 / 换行
    if (availW <= 0) {
      cursorX = 5;
      cursorY += textHeight + 10;
      availW = display.width() - 5 - cursorX;
    }

    // 判断字符
    const char* temp = remain;
    while (*temp != '\0') {
      int step = 1;
      if ((unsigned char)*temp >= 0xC0) step = 3;  // 中文占3字节

      char single[4] = {0};
      strncpy(single, temp, step);
      int w = u8g2Fonts.getUTF8Width(single); //字符宽度

      if (usedW + w > availW) break;
      usedW += w + 2; 
      temp += step;
      charCount = temp - remain;
    }

    // 当前行剩余空间
    if (charCount == 0) {
      cursorX = 5;
      cursorY += textHeight + 10;

      // 超出屏幕底部  清屏
      if (cursorY + textHeight > display.height()) {
        clearScreen();
      }
      continue; 
    }

    // 截取当前行要显示的文本
    char lineBuf[128];
    if (charCount >= (int)sizeof(lineBuf)) charCount = sizeof(lineBuf) - 1;
    strncpy(lineBuf, remain, charCount);
    lineBuf[charCount] = '\0';

    if (cursorY + textHeight > display.height()) {
      clearScreen();
    }

    // 局部刷新范围
    int rx = cursorX;
    int ry = cursorY;
    int rw = usedW + 4;
    int rh = textHeight + 4;

    display.setPartialWindow(rx, ry, rw, rh);
    display.firstPage();
    do {
      u8g2Fonts.drawUTF8(cursorX, cursorY + textHeight, lineBuf);
      lastX = rx; lastY = ry; lastW = rw; lastH = rh;
    } while (display.nextPage());

    cursorX += usedW;
    remain += charCount;
  }
}


// 删除上次显示内容
void deleteLast(){

  display.setPartialWindow(
    lastX,  lastY,
    lastW , lastH
  );

   display.firstPage();
  do {
    display.fillRect(lastX, lastY,lastW, lastH,GxEPD_WHITE);
  } while (display.nextPage());
  cursorX = lastX;
}


// 清屏
void clearScreen() {
  display.setFullWindow();
  display.firstPage();
  do {
    display.fillScreen(GxEPD_WHITE);
  } while (display.nextPage());

  // 重置光标
  cursorX = 5;
  cursorY = 5;

  display.hibernate();
}


void setup() {

  Serial.begin(115200);
  display.epd2.selectSPI(SPIn, SPISettings(4000000, MSBFIRST, SPI_MODE0));
  while (!Serial);

  display.init(115200);  // 初始化屏幕
  display.setRotation(3); // 屏幕显示方向

  // 字体显示设置
  u8g2Fonts.begin(display);
  u8g2Fonts.setFont(u8g2_font_cn_30);
  u8g2Fonts.setForegroundColor(GxEPD_BLACK);
  u8g2Fonts.setBackgroundColor(GxEPD_WHITE);

  display.setFullWindow();
  display.firstPage(); 
  do {
    display.fillScreen(GxEPD_WHITE);  //清屏
  } while (display.nextPage());

  // 获取字体高度
  ascent  = u8g2Fonts.getFontAscent();
  descent = u8g2Fonts.getFontDescent();
  textHeight = ascent - descent;
  display.hibernate();
}


void loop() {
  if (Serial.available()) {
    String buf = Serial.readStringUntil('\n');

    if (buf.length() == 0) return;

    // 清屏指令
    if (buf.equalsIgnoreCase("clear")) {
      clearScreen();
    }else if (buf.equalsIgnoreCase("del")) {    // 删除指令
      deleteLast();
    } else {
      showText(buf.c_str());
      Serial.print("显示内容: ");
      Serial.println(buf);
      display.hibernate();    // 休眠模式
    }
  }
}






四、程序烧录



1、连接USB数据线至开发板;

2、选择端口号对应的开发板;

3、点击 上传 烧录程序到开发板上;



image-20260127231208397.png





五、效果演示




image-20260331211716095.png




E.gif

















关键词: 墨水屏     EPD    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]