Arduino如何将程序空间中的指针作为参数传递给函数
Arduino PROGMEM菜单指针传参实现方案
你的Menu_Principal是存储在Flash程序空间的常量字符串指针数组,受AVR架构Flash与RAM地址空间分离的限制,传参和读取时必须匹配专用的PROGMEM操作规则,具体实现如下:
1. 修正原定义的类型匹配问题
你原代码中Menu_Principal的元素类型和前面声明的const字符串不匹配,会触发编译警告,先修正声明:
const char _str_opcion_0[] PROGMEM = "Opción Menú 1"; const char _str_opcion_1[] PROGMEM = "Opción Menú -2"; const char _str_opcion_2[] PROGMEM = "Opción Menú --3"; const char _str_opcion_3[] PROGMEM = "Opción Menú ---4"; const char _str_opcion_4[] PROGMEM = "Opción Menú ----5"; const char _str_opcion_5[] PROGMEM = "Opción Menú -----6"; const char _str_opcion_6[] PROGMEM = "Opción Menú ------7"; const char _str_opcion_7[] PROGMEM = "Opción Menú -------8"; const char _str_opcion_8[] PROGMEM = "Opción Menú --------9"; const char _str_opcion_9[] PROGMEM = "Opción Menú ---------A"; const char _str_opcion_A[] PROGMEM = "Opción Menú ----------B"; const char _str_opcion_B[] PROGMEM = "Opción Menú -----------C"; // 修正为const char*类型匹配字符串常量 const char* const Menu_Principal [] PROGMEM = { _str_opcion_0, _str_opcion_1, _str_opcion_2, _str_opcion_3, _str_opcion_4, _str_opcion_5, _str_opcion_6, _str_opcion_7, _str_opcion_8, _str_opcion_9, _str_opcion_A, _str_opcion_B, NULL };
2. 声明接收菜单参数的函数
引入avr/pgmspace.h头文件,使用官方定义的PROGMEM指针类型作为形参,读取时必须用pgm_read_*系列函数从Flash取数据,不能直接解引用:
#include <avr/pgmspace.h> /** * @brief 打印/显示PROGMEM存储的菜单 * @param menuItems 存在PROGMEM的菜单指针数组,类型为PGM_P* */ void showMenu(PGM_P *menuItems) { uint8_t itemIndex = 0; PGM_P currentItemStr; char strBuffer[64]; // 缓冲区长度根据你最长的菜单项调整 // 遍历到NULL结束标记为止 while ((currentItemStr = (PGM_P)pgm_read_ptr(&menuItems[itemIndex])) != NULL) { // 把Flash里的字符串拷贝到RAM缓冲区 strcpy_P(strBuffer, currentItemStr); // 这里替换成你的屏幕显示逻辑,示例用串口输出 Serial.println(strBuffer); itemIndex++; } }
3. 调用传参
数组名会自动退化为指向首元素的指针,直接传入Menu_Principal即可,不需要额外加取地址符:
void setup() { Serial.begin(115200); // 传入菜单指针 showMenu(Menu_Principal); } void loop() { // 其他业务逻辑 }
关键注意事项
- 禁止直接读取PROGMEM地址的内容,比如直接写
Serial.println(menuItems[itemIndex])会读取RAM区的乱码,所有Flash数据访问必须走pgm_read_*、strcpy_P这类专用函数。 - 上述写法兼容AVR(Uno、Mega2560)和ESP32/ESP8266等非AVR架构的Arduino开发板,跨平台编译不需要修改代码。
- 缓冲区大小要大于最长菜单项的长度,避免字符串拷贝溢出。
内容的提问来源于stack exchange,提问作者Luis Fernando Ruiz Pereira
相关产品推荐
相关产品推荐

