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

(...)
//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用户手册中有一条警告,内容涉及在循环和函数中使用程序存储器读取,请参见下文。


  为了从程序空间实际加载数据,用于从程序空间检索数据的宏和函数必须生成一些额外的代码。就代码空间(额外的操作码)和执行时间而言,这会产生一些额外的开销。 (...)但是您应该意识到这一点,因此可以最大程度地减少从“程序空间”获取相同数据的单个函数中的调用次数。


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

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

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

10-11 16:38