我正在使用带有两个压电元件的独立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
有没有人有任何想法为什么会发生? 或者有没有人有更好,更有效的方法来解决这个问题? 非常感谢您提前寻求帮助。
答案 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__(无论)属性,以避免条目之间的填充 - 如果保存闪存空间很重要(那么你可以在那里获得更多的歌曲!)
听起来很有趣!祝你好运!