PROGMEM中的Arduino结构数组

时间:2016-08-11 20:00:06

标签: c++ arrays struct arduino progmem

我正在使用带有两个压电元件的独立Atmega328P来产生一些音乐。 我已经用音符的频率定义了一些常数。 然后我定义了一个结构,其中包含第一个和第二个压电元素的音符以及音符的长度。 然后我制作了更多这些结构的数组来描述每首歌曲。 问题是这样我很快就会耗尽内存。 我试图在PROGMEM中存储结构数组,以避免这个问题。 我试图使用一个名为PROGMEM_readAnything的小库,memcpy_P()或pgm_read_word()和pgm_read_byte()函数,但在所有情况下我都会遇到同样的问题。

当我遍历NOTES数组时,它会跳过一些元素,同时正确地读取和播放其他元素。 它总是跳过相同的元素,而不仅仅是随机元素。 我甚至试图更换微控制器,认为芯片的某些部分可能已被某些东西损坏,但上传相同的草图我得到了相同的结果,因此微控制器可能完好无损。

以下是代码:

#include <Tone.h>
#include <avr/pgmspace.h>

//Define the notes frq
#define G2 98
#define Gs2 104
#define Ab2 104
#define A2 110
#define As2 116

//... and so on with many other music notes ...

#define Fs7 2960
#define Gb7 2960
#define G7 3136

//Rest
#define R 0

typedef struct {
  int n1;
  int n2;
  byte units;
} NOTES;

Tone buzzer1;  
Tone buzzer2;

int myTempo = 100;

//Walkyrie
const NOTES walkyrie[] PROGMEM = {

                          {Fs3, Fs4, 2}, 
                          {B3, B4,3}, 
                          {Fs3, Fs4, 1}, 
                          {B3, B4, 2},
                          {D4, D5, 6},
                          {B3, B4, 6}, 
                          {D4, D5, 3},
                          {B3, B4, 1},
                          {D4, D5, 2},
                          {Fs4, Fs5, 6},
                          {D4, D5, 6},
                          {Fs4, Fs5, 3},
                          {D4, D5, 1},
                          {Fs4, Fs5, 2},
                          {A4, A5, 6},
                          {A3, A4, 6},
                          {D4, D5, 3},
                          {A3, A4, 1},
                          {D4, D5, 2},
                          {Fs4, Fs5, 6},
                          {R, 0, 4},
                          {A3, A4, 2},
                          {D4, D5, 3},
                          {A3, A4, 1},
                          {D4, D5, 2},
                          {Fs4, Fs5, 6},
                          {D4, D5, 6},
                          {Fs4, Fs5, 3},
                          {D4, D5, 1},
                          {Fs4, Fs5, 2},
                          {A4, A5, 6},
                          {Fs4, Fs5, 6},
                          {A4, A5, 3},
                          {Fs4, Fs5, 1},
                          {A4, A5, 2},
                          {Cs5, Cs6, 6},
                          {Cs4, Cs5, 6},
                          {Fs4, Fs5, 3},
                          {Cs4, Cs5, 1},
                          {Fs4, Fs5, 2},
                          {As4, As5, 6}



                        };

void playSong()
{
  //We store the frq of the second pizo in this variable
  int secondFrq = 0;
  Serial.println(sizeof(walkyrie)/sizeof(walkyrie[0]));
  //Walk through the array of music
  for(int i = 0; i < sizeof(walkyrie)/sizeof(walkyrie[0]); i++) 
  {

      int n1;
      int n2;
      byte units;
      // Only play if it is not a rest
      if(walkyrie[i].n1 > 0) 
        {


          n1 = pgm_read_word(&(walkyrie[i].n1));
          n2 = pgm_read_word(&(walkyrie[i].n2));
          units = pgm_read_byte(&(walkyrie[i].units));

          Serial.print("Row ");
          Serial.print(i);
          Serial.print(": Frq1: ");
          Serial.print(n1);
          Serial.print(" Frq2: ");
          Serial.print(n2);
          Serial.print(" Units: ");
          Serial.println(units);

          //Play the note of the first piezo
          buzzer1.play(n1, (units*myTempo));
          //If the frq of the second piezo is 0, we play the same note     as the first, else the note set for the second one
          if(n2 == 0)
          {
              secondFrq = n1;
          }else{
              secondFrq = n2;
          }

          buzzer2.play(secondFrq, (units*myTempo));  

        }

    //Then we wait for the note to end plus a little, between two notes
    delay((units*myTempo) + 10);

  }
} 


void setup() {
  Serial.begin(9600);
  buzzer1.begin(11);
  buzzer2.begin(12);
}

void loop()
{
   playSong();
}

我添加了一些行,以便在串行监视器中看到会发生什么。 它读取正确的长度...... 串行监视器的输出如下:

41                                                   (correct length)
Row 1: Frq1: 247 Frq2: 499 Units: 3        (row 0 - the first note is already missing)
Row 2: Frq1: 185 Frq2: 370 Units: 1
Row 3: Frq1: 247 Frq2: 499 Units: 2        (row 4 missing)
Row 5: Frq1: 247 Frq2: 499 Units: 6        (row 6-7 missing)
Row 8: Frq1: 294 Frq2: 587 Units: 2
Row 9: Frq1: 370 Frq2: 740 Units: 6
Row 10: Frq1: 294 Frq2: 587 Units: 6
Row 11: Frq1: 370 Frq2: 740 Units: 3
Row 12: Frq1: 294 Frq2: 587 Units: 1
Row 13: Frq1: 370 Frq2: 740 Units: 2
Row 14: Frq1: 440 Frq2: 880 Units: 6
Row 15: Frq1: 220 Frq2: 440 Units: 6    (row 16-17 missing)
Row 18: Frq1: 294 Frq2: 587 Units: 2
Row 19: Frq1: 370 Frq2: 740 Units: 6
Row 20: Frq1: 0 Frq2: 0 Units: 4
Row 21: Frq1: 220 Frq2: 440 Units: 2
Row 22: Frq1: 294 Frq2: 587 Units: 3
Row 23: Frq1: 220 Frq2: 440 Units: 1
Row 24: Frq1: 294 Frq2: 587 Units: 2
Row 25: Frq1: 370 Frq2: 740 Units: 6
Row 26: Frq1: 294 Frq2: 587 Units: 6
Row 27: Frq1: 370 Frq2: 740 Units: 3
Row 28: Frq1: 294 Frq2: 587 Units: 1
Row 29: Frq1: 370 Frq2: 740 Units: 2
Row 30: Frq1: 440 Frq2: 880 Units: 6
Row 31: Frq1: 370 Frq2: 740 Units: 6
Row 32: Frq1: 440 Frq2: 880 Units: 3
Row 33: Frq1: 370 Frq2: 740 Units: 1
Row 34: Frq1: 440 Frq2: 880 Units: 2
Row 35: Frq1: 554 Frq2: 1109 Units: 6
Row 36: Frq1: 277 Frq2: 554 Units: 6
Row 37: Frq1: 370 Frq2: 740 Units: 3
Row 38: Frq1: 277 Frq2: 554 Units: 1
Row 39: Frq1: 370 Frq2: 740 Units: 2
Row 40: Frq1: 466 Frq2: 932 Units: 6

有没有人有任何想法为什么会发生? 或者有没有人有更好,更有效的方法来解决这个问题? 非常感谢您提前寻求帮助。

1 个答案:

答案 0 :(得分:3)

在此行中,您检查数据,但尚未完成“pgm_read_word()&#39;实际上获取来自闪存的数据:

if(walkyrie[i].n1 > 0)

如果您意外获得非零值,那么您正确地从闪存中读取值,否则,您跳过该行。

进一步的证据:

Row 20: Frq1: 0 Frq2: 0 Units: 4

此处, n1 为零,但该测试应跳过该行。

此外,休息的逻辑是&#39;有点偏。现在,你不会在剩下的时间内阅读单位,所以它使用之前的值(来自播放的音符)。

我想我先得到所有三个值,然后检查它们。

我还将频率编码为一个字节,并使用查找表转换&#34;密钥号码&#34;进入一个频率(如MIDI键数)。你的结构数组会小一点。也许打开__packed__(无论)属性,以避免条目之间的填充 - 如果保存闪存空间很重要(那么你可以在那里获得更多的歌曲!)

听起来很有趣!祝你好运!