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
相关产品推荐
相关产品推荐

