三维字符串数组

时间:2015-06-08 12:08:51

标签: 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] = { 
                      {
                       {"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。我尝试在http://www.arduino.cc/en/Reference/PROGMEM转换arduino字符串教程 从1D阵列到3D阵列但无法使其工作,它无法编译或返回垃圾。以下是我的几次尝试。

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

所以我尝试使用

将原始数组直接转换为progmem
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);
   }
}

这导致了一个几乎可行的例子,但它并不完美:

0 Value1 1 Value 2
2 Value3 3 Value 4
4 Value 5 5 Value 6
6 Value 7 7 Value 8
8 Value 9
10 Value 11 11 Value 12
10 Value 11 11 Value 12
12 Value 13 13 Value 14
14 Value 15 15 Value 16
16 Value 17 17 Value 18
18 Value 19 19 Value 20 19 Value 20 19 Value 20...

您可能会注意到没有显示值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);
    }
  }
}

我得到的当前输出是:&#34; Switchi&#34;没有别的,这是否意味着我的Arduino因为我的代码而悬挂或者我以某种方式杀了它?我还更新了单阵列版本以反映我实际编码它的方式。在复制它时,我错误地复制了它,这有点乱。它的工作方式更像shuttle87建议但仍然返回上面显示的错误。

编辑:刚认识到我错过了:

const char* msgs[][3][2] = {
      {
        {string1, string2 },
        {string3, string4 }
      },
      {
        {string5, string6 },
        {string3, string4 },
        {string1, string2 }
      },
      {
        {string2, string3 }
      }
    };

应该已经开始了:

const char* const messages[][3][2] PROGMEM= {
      {
        {string1, string2 },
        {string3, string4 }
      },
      {
        {string5, string6 },
        {string3, string4 },
        {string1, string2 }
      },
      {
        {string2, string3 }
      }
    };

很抱歉。这似乎已经修复了它。非常感谢您的帮助:)

感谢。

1 个答案:

答案 0 :(得分:0)

您的大多数尝试都有相同的问题,您已将指针存储在progmem中的表中,但实际的表数据本身(在本例中为字符串)未存储在progmem中。不幸的是,GCC属性(从gcc 4.7开始)仅适用于当前声明,因此您必须在每个变量上指定progmem。

所以当你有

 const char message1[][2] PROGMEM = { "Value 1", "Value 2" };

message1存储在progmem中,但字符串"Value 1"不存在。此外,如果我没记错,avr-gcc编译器总是将字符串文字存储在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])));

我建议您查看AVR-GCC tutorial putting data in progmem