gpt4 book ai didi

c - pgm_read_ 和 PROGMEM - 意外行为

转载 作者:行者123 更新时间:2023-11-30 16:39:31 26 4
gpt4 key购买 nike

我制作了一个播放数组中保存的歌曲(使用蜂鸣器)的程序:

(...)
//function which plays a single note
void playNote(int8 wavelength, int duration) {
if (wavelength != 1) {
OCR0A = wavelength; /* set pitch */
SPEAKER_DDR |= (1 << SPEAKER); /* enable output on speaker */
}
while (duration) { /* Variable delay */
_delay_ms(1);
duration--;
}
SPEAKER_DDR &= ~(1 << SPEAKER); /* turn speaker off */

//function which plays song from array
void playSong( int8 *song,int tempo){
int length_16_note = tempo;
for( int8 i = 0;song[i]) ; i += 2){
playNote(song[i],song[i+1]*length_16_note);
_delay_ms(15);
}
}
int main(void){
//array of macros and lenghts of notes
int8 song1[] = {
C,4, E1,4, F1,3, E1,3, F1,2,
F1,2, F1, 2, B1,2, A1,2, G1,1, F1,2, G1,5,
G1,4, B1,4, C1,3, F1,3, E1,2,
B1,2, B1,2, G1,2, B1,2,
B1,3, C1,13, 0};
//initialize a timer
initTimer();
//play song
playSong(song1, 150)
}

我省略了其中的一些部分,但这段代码工作得很好。现在我想将我的歌曲保存到程序内存中,所以我更改:

#include <avr/pgmspace.h>
(...)
int8 song1[] PROGMEM = {...}

void playSong( int8 *song, int tempo){
int length_16_note = tempo;
for( int8 i = 0; pgm_read_byte(&(song[i])) ; i += 2){
playNote(pgm_read_byte(&(song[i])), pgm_read_byte(&(song[i+1]))*length_16_note);
_delay_ms(15);
}
}

当我在 Arduino 上运行该代码时,我会收到随机持续时间(比预期长得多)的随机蜂鸣声。看起来 pgm_read_byte(&(song[i])) 返回随机值。

我尝试将函数 playSong 中的代码提取到 main 中,以便不将数组作为参数传递给函数,但没有任何变化。那么这段代码有什么问题呢?

最佳答案

我不确定这就是原因,但我的第一个猜测是您的持续时间比预期更长,因为您的 for 循环如下所示:

for( int8 i = 0; pgm_read_byte(&(song[i])) ; i += 2)

这意味着每次执行for循环时,程序都会检查程序空间中的数据,因为这是循环条件。

avr-libc 用户手册中有一条关于在循环和函数中使用程序内存读取的警告,请参见下文。

The macros and functions used to retrieve data from the Program Space have to generate some extra code in order to actually load the data from the Program Space. This incurs some extra overhead in terms of code space (extra opcodes) and execution time. (...) But you should be aware of this so you can minimize the number of calls within a single function that gets the same piece of data from Program Space.

此外,您还可以在 for 循环内对程序闪存进行两次额外的调用。所有这些意味着,要更改音符,程序需要等待从程序存储器读取 3 个字节,并需要额外的 15 ms 延迟。结果,笔记比预期长得多。

我建议程序首先将整首歌曲读入 RAM 中的某种缓冲区,然后直接从 RAM 中播放。

关于c - pgm_read_ 和 PROGMEM - 意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47007018/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com