C++ 三维字符串数组
我正在尝试制作一个LCD项目(16x2),它可以循环浏览一组消息。其想法是,它将循环浏览当前选定组中的所有消息,并且在手动更改之前不会离开该组。最初我有一个3D数组:级别1是消息组,级别2是要显示的消息,级别3是行C++ 三维字符串数组,c++,arrays,arduino,progmem,C++,Arrays,Arduino,Progmem,我正在尝试制作一个LCD项目(16x2),它可以循环浏览一组消息。其想法是,它将循环浏览当前选定组中的所有消息,并且在手动更改之前不会离开该组。最初我有一个3D数组:级别1是消息组,级别2是要显示的消息,级别3是行 #define WIDTH 16 #define HEIGHT 2 #define NGRP 3 #define MAXGRP 6 String mainMsgs[NGRP][MAXGRP][HEIGHT] = { {
#define WIDTH 16
#define HEIGHT 2
#define NGRP 3
#define MAXGRP 6
String mainMsgs[NGRP][MAXGRP][HEIGHT] = {
{
{"Value 1","Value 2"},
{"Value 3","Value 4"},
{"Value 5","Value 6"},
{"Value 7","Value 8"},
{"Value 9","Value 10"},
},
{
{"Value 1","Value 2"},
{"Value 3","Value 4"},
{"Value 5","Value 6"},
{"Value 7","Value 8"},
{"Value 9","Value 10"},
{"Value 9","Value 10"},
{"Value 11","Value 12"},
},
{
{"Value 1","Value 2"},
{"Value 3","Value 4"},
{"Value 5","Value 6"},
{"Value 7","Value 8"},
}
})
我让它或多或少地工作,但我认为数组太大了,内存不够,因为在第3组进行到一半时,它停止显示消息。当我测试它时,数组索引总是正确的。我假设数组已被截断。在尝试解决此问题时,我遇到了PROGMEM。我尝试在以下位置转换arduino字符串教程:
从一维数组转换为三维数组,但无法使其工作,它要么编译失败,要么返回垃圾。下面是我的几次尝试
const char message1[][2] PROGMEM = { "Value 1", "Value 2" }; // Through to message15
const char* const group1[][5] PROGMEM = { message1, message2, message3, message4, message5 };
const char* const group2[][6] PROGMEM = { message6, message7, message8, message9, message10, message11 };
const char* const group3[][4] PROGMEM = { message12, message13, message14, message15 };
const char* const groups[] PROGMEM = { group1, group2, group3 }; // Attempt 1
const char* const groups[NUMGRP][6] PROGMEM = {
{message1, message2, message3, message4, message5},
{message6, message7, message8, message9, message10, message11},
{message12, message13, message14, message15},
}; // Attempt 2
因此,我尝试使用
const char* const mainMsgs[NUMGRP][6][HEIGHT] = { /* same content as before*/ };
strcpy_P(buff, (char*)pgm_read_word(&(mainMsgs[groupID][msgID][i])));
但它仍然返回垃圾。
因此,我想我应该尝试将数据转换成一维数组,然后使用偏移量访问消息和行
编辑:编辑以下代码以反映我在原始草图中使用的代码
const char message1[] = "Value 1";
const char message2[] = "Value 2"; // Down to message30
const char* const messages[] PROGMEM = { message1, message2,
message3, message4,
// ... ... ...
message29, message30
};
int groupStarts[] = { 0, 10, 22 }; // The first index of each group
int numMsgs[] { 5, 6, 4 };
char buff[WIDTH];
这是我使用的测试循环:
int id = 0;
for( groupID = 0; groupID < NGRP; groupID++ ) {
for( msgID = 0; msgID < numMsgs[groupID]*HEIGHT; msgID+=HEIGHT ) {
for( lineID = 0; lineID < HEIGHT; lineID++ ) {
id = groupStarts[groupID] + msgID + lineID;
strcpy_P(buff, (char*)pgm_read_word(&(messages[id])));
Serial.print(id);
Serial.print(" ");
Serial.print(buff);
}
Serial.println("");
delay(500);
}
}
您可能会注意到,没有显示值10,值11和12重复两次,当它达到值19时,它只是卡在一个无限循环中
我不太清楚最后的循环应该是什么
理想情况下,我更愿意保留3D数组结构,因为我发现它更易于阅读和理解,但我很乐意为这两个版本的代码提供解决方案
编辑以反映shuttle87的建议:
#include <avr/pgmspace.h>
#define WIDTH 16
#define HEIGHT 2
const char string1[] PROGMEM = "Message 1";
const char string2[] PROGMEM = "Message 2";
const char string3[] PROGMEM = "Message 3";
const char string4[] PROGMEM = "Message 4";
const char string5[] PROGMEM = "Message 5";
const char string6[] PROGMEM = "Message 6";
const int groupLen[] = { 2, 3, 1 };
const char* msgs[][3][2] = {
{
{string1, string2 },
{string3, string4 }
},
{
{string5, string6 },
{string3, string4 },
{string1, string2 }
},
{
{string2, string3 }
}
};
char buffer[WIDTH];
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
for( int g = 0; g < 3; g++ ) {
Serial.print("Switching to group: ");
Serial.println(g);
for( int m = 0; m < groupLen[g]; m++ ) {
Serial.print("Switching to message: ");
Serial.println(m);
for( int l = 0; l < HEIGHT; l++ ) {
Serial.print("Switching to line: ");
Serial.println(l);
strcpy_P(buffer, (char*)pgm_read_word(&(msgs[g][m][l])));
Serial.println(buffer);
}
delay(500);
}
}
}
本应开始:
const char* const messages[][3][2] PROGMEM= {
{
{string1, string2 },
{string3, string4 }
},
{
{string5, string6 },
{string3, string4 },
{string1, string2 }
},
{
{string2, string3 }
}
};
很抱歉。这似乎已经解决了这个问题。非常感谢您的帮助:)
谢谢。您的大多数尝试都有相同的问题,您已将指向表的指针存储在progmem中,但实际的表数据本身(在本例中为字符串)未存储在progmem中。不幸的是,GCC属性(从GCC4.7开始)只适用于当前声明,因此必须在每个变量上指定progmem 所以当你有
const char message1[][2] PROGMEM = { "Value 1", "Value 2" };
message1
存储在progmem中,但字符串“Value 1”
不存储。此外,如果我没记错的话,AVRCC编译器总是在SRAM中存储字符串文本。即使您指定了一个位置将它们放在progmem中,它仍然会复制到SRAM中(有一次我试图编写一个库,使用c++11用户定义的字符串文本将它们放在progmem中,但这让我很失望)。一维数组解决方案也会遇到同样的问题
要解决此问题,请将所有内容显式存储在progmem中,例如,1D解决方案如下所示:
const char string_msg0_0[] PROGMEM = "Value 1";
const char string_msg0_1[] PROGMEM = "Value 2";
PGM_P strings_pgm_table[] PROGMEM = {string_msg0_0, string_msg0_1};
char buffer[MAX_STRING_SIZE];
strcpy_P(buffer, (PGM_P)pgm_read_word(&(strings_pgm_table[i])));
我建议您看看。大多数尝试都有相同的问题,您已将指向表的指针存储在progmem中,但实际的表数据本身(在本例中为字符串)未存储在progmem中。不幸的是,GCC属性(从GCC4.7开始)只适用于当前声明,因此必须在每个变量上指定progmem 所以当你有
const char message1[][2] PROGMEM = { "Value 1", "Value 2" };
message1
存储在progmem中,但字符串“Value 1”
不存储。此外,如果我没记错的话,AVRCC编译器总是在SRAM中存储字符串文本。即使您指定了一个位置将它们放在progmem中,它仍然会复制到SRAM中(有一次我试图编写一个库,使用c++11用户定义的字符串文本将它们放在progmem中,但这让我很失望)。一维数组解决方案也会遇到同样的问题
要解决此问题,请将所有内容显式存储在progmem中,例如,1D解决方案如下所示:
const char string_msg0_0[] PROGMEM = "Value 1";
const char string_msg0_1[] PROGMEM = "Value 2";
PGM_P strings_pgm_table[] PROGMEM = {string_msg0_0, string_msg0_1};
char buffer[MAX_STRING_SIZE];
strcpy_P(buffer, (PGM_P)pgm_read_word(&(strings_pgm_table[i])));
我建议您看看。您需要使用progmem指针来指向存储在progmem中的字符串。这不是什么:strcpy_p(buff,(char*)pgm_read_word(&(mainMsgs[groupID][msgID][I]);是吗?如果你已经回答了你的问题,在回答中写出来,而不是编辑问题。此外,编辑内容足够丰富,最好将其作为一个单独的问题发布,以避免将其变成看起来像一个问题的风险。你想要避免这种情况的原因,特别是像这样难以回答的问题,是因为像我这样厌倦了网站的用户会把这看作是一个危险信号,而不太愿意花时间去帮助别人。更清楚的是,我非常乐意帮上忙,以后只需发布其他问题,而不是进行大量编辑。您需要使用progmem指针指向progmem中存储的字符串。这不是什么:strcpy_P(buff,(char*)pgm_read_word(&(mainMsgs[groupID][msgID][i]);是吗?如果你已经回答了你的问题,在回答中写出来,而不是编辑问题。此外,编辑内容足够丰富,最好将其作为一个单独的问题发布,以避免将其变成看起来像一个问题的风险。你想要避免这种情况的原因,特别是像这样难以回答的问题,是因为像我这样厌倦了网站的用户会把这看作是一个危险信号,而不太愿意花时间去帮助别人。更清楚的是,我非常乐意帮上忙,以后只需发布其他问题,而不是进行大量编辑。您需要使用progmem指针指向progmem中存储的字符串。这不是什么:strcpy_P(buff,(char*)pgm_read_word(&(mainMsgs[groupID][msgID][i]);是吗?如果你已经回答了你的问题,在回答中写出来,而不是编辑问题。此外,编辑内容足够丰富,最好将其作为一个单独的问题发布,以避免将其变成看起来像一个问题的风险。你想要避免这种情况的原因,特别是像这样难以回答的问题,是因为像我这样厌倦了网站的用户会把这看作是一个危险信号,而不太愿意花时间去帮助别人