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

Arduino读取Waveshare Eink头文件String乱码问题求助

问题分析与解决方案

你遇到的乱码问题核心原因是错误地将Arduino的String对象存储到了PROGMEM中,以及对PROGMEM的使用逻辑有误。下面一步步拆解问题并给出修复方案:

为什么会出现乱码?

PROGMEM是AVR单片机(比如Arduino Uno)用来把常量数据存储到**闪存(程序存储器)**的机制,而String是Arduino的动态字符串对象——它的内部字符数据是存放在SRAM中的,并且包含动态内存管理的元数据。

你在头文件中直接把String数组标记为PROGMEM,实际存储的只是String对象的指针和元数据(而非字符串的实际内容),这些数据在从PROGMEM读取时,指向的SRAM地址是无效的,自然就会输出乱码。

另外,头文件里的extern和初始化不能同时写在一起,这会导致重复定义的编译问题(虽然你现在没遇到,但后续会出问题)。

修复步骤

1. 修正头文件的常量定义

把String换成const char*(C风格字符串),这才是适合存到PROGMEM的类型。同时分开声明和定义:

list.h(头文件)

#ifndef LIST_H
#define LIST_H

#include <avr/pgmspace.h>  // 必须包含PROGMEM的头文件

// 仅声明外部常量
extern const char* const DATA_1[] PROGMEM;
extern const char* const DATA_2[] PROGMEM;
extern const char* const DATA_3[] PROGMEM;
extern const char* const DATA_4[] PROGMEM;
extern const char* const DATA_5[] PROGMEM;
extern const char* const DATA_6[] PROGMEM;
extern const char* const DATA_7[] PROGMEM;

#endif

list.cpp(单独的实现文件,在Arduino中可以新建一个tab)

#include "list.h"

// 实际定义并初始化PROGMEM中的字符串数组
const char* const DATA_1[] PROGMEM = { "bat", "2244"};
const char* const DATA_2[] PROGMEM = { "bmp", "15662"};
const char* const DATA_3[] PROGMEM = { "docx", "16670"};
const char* const DATA_4[] PROGMEM = { "jpg", "150645"};
const char* const DATA_5[] PROGMEM = { "mp3", "9882324"};
const char* const DATA_6[] PROGMEM = { "txt", "807"};
const char* const DATA_7[] PROGMEM = { "url", "118"};

2. 修改Arduino代码中的读取逻辑

不能直接把PROGMEM中的指针转成String,需要用专门的PROGMEM读取函数把字符串内容复制到SRAM中,再转成String:

修改后的setup()关键部分

void setup() {
  Serial.begin(9600);
  Serial.print("port test");

  Epd epd;
  if (epd.Init() != 0) {
    Serial.println("e-Paper init failed");
    return;
  }

  // 方法1:用char数组中转(更稳妥,适合长字符串)
  char buffer[20];  // 大小根据你的最长字符串调整,要留足结束符空间
  strcpy_P(buffer, (char*)pgm_read_ptr(&DATA_1[0]));  // 从PROGMEM复制到SRAM
  test1 = String(buffer);
  Serial.println(test1);

  // 方法2:直接转成String(Arduino 1.6.0+支持)
  test2 = String((const __FlashStringHelper*)pgm_read_ptr(&DATA_1[1]));
  Serial.println(test2);

  // 后面的e-Paper代码保持不变...
}

额外注意事项

  • 如果你的.bat脚本是自动生成这些数组的,需要修改脚本,把String替换成const char* const,并分开声明和定义。
  • 缓冲区buffer的大小要足够容纳你最长的字符串(比如你的mp3对应的字符串是"9882324",长度7,所以20的大小完全足够)。
  • 如果你使用的是Arduino Uno这类SRAM很小的板子,用PROGMEM存储常量字符串能有效节省SRAM,这是个很好的习惯,只是要注意正确的使用方式。

内容的提问来源于stack exchange,提问作者LuigiKraken

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:34:07