2016-08-11 136 views
0

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

当我遍历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 

没有人有为什么会发生什么想法吗? 还是有没有人有更好,更有效的方法来解决这个问题? 非常感谢您的帮助。

+0

这听起来像你可能需要学习如何使用调试器来遍历代码。使用一个好的调试器,您可以逐行执行您的程序,并查看它与您期望的偏离的位置。如果你打算做任何编程,这是一个重要的工具。进一步阅读:** [如何调试小程序](http://ericlippert.com/2014/03/05/how-to-debug-small-programs/)** – NathanOliver

回答

3

在这一行,您可以检查数据,但你没有做过“pgm_read_word()”实际上得到从闪存中的数据:

if(walkyrie[i].n1 > 0) 

如果,偶然,您得到一个非零值,然后你从闪存正确读取值,否则,你跳过那一行。

进一步的证据:

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

这里,N1是零,但测试应该跳过行。

此外,“休息”的逻辑是有点关闭。现在,在剩下的时间内,您不会读单位,因此它使用之前的值(来自播放的音符)。

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

我也会将频率编码为一个字节,并使用查找表将“键号”转换为频率(如MIDI键号)。你的结构数组将会稍微小一些。可能还会打开__packed__(whatever)属性,以避免条目之间的填充 - 如果节省闪存空间问题(那么您可以在那里获得更多歌曲!)

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