Проблема при использовании PROGMEM для массива, содержащего заметки для говорящего на Arduino

У меня возникла немного странная проблема. Я пытаюсь настроить звук для своего проекта на Arduino и экспериментирую с примером из IDE. Проблема в том, что при попытке передать массив нот в PROGMEM выходная нота становится выше той, что я ввёл. Мне это не нужно. Если это важно, код у меня такой:

    #define tuneSize 2
    // ноты в мелодии:
    const int melody[tuneSize] PROGMEM /*This is what's screwing it up*/= {
      NOTE_AS3, 0
    };

    // длительности нот: 4 = четвертная нота, 8 = восьмая нота и т. д.:
    int noteDurations[tuneSize] = {
      6, 16
    };

    void setup() {
      // не нужно повторять мелодию.
      // перебираем ноты мелодии:
      for (int thisNote = 0; thisNote < tuneSize; thisNote++) {

        // чтобы рассчитать длительность ноты, возьмите одну секунду
        // делится на тип заметки.
        //например, четвертная нота = 1000 / 4, восьмая нота = 1000 / 8 и т. д.
        int noteDuration = 1000 / noteDurations[thisNote];
        tone(8, melody[thisNote], noteDuration);

        // чтобы различать ноты, установите минимальное время между ними.
        // длительность ноты + 30% кажется работает хорошо:
        int pauseBetweenNotes = noteDuration * 1.30;
        delay(pauseBetweenNotes);
        // остановить воспроизведение тона:
        noTone(8);
    }
}

(Pitch.h можно найти на вкладке примеров Arduino в разделе «Цифровые устройства»)

В моей схеме на выводе 8 есть резистор сопротивлением 8 Ом. Вот и всё.

Единственное, что приходит мне в голову, — это то, что из-за медленной работы PROGMEM данные не так быстро доходят до динамиков, что делает вывод странным. Кто-нибудь знает, как решить эту проблему? Кроме того, размещение только в SRAM не идеально, поскольку я работаю с дисплеем, а используемая им библиотека потребляет много SRAM.

, 👍2


1 ответ


Лучший ответ:

3

Нельзя напрямую разыменовать объект (получить доступ к массиву), находящийся во флэш-памяти. Для этого необходимо использовать функции pgm_read_xxx из <avr/pgmspace.h> .

В вашем случае, вероятно, следует написать что-то вроде этого:

tone(8, pgm_read_word(&melody[thisNote]), noteDuration);

Pgm_read_word считывает два байта. Вы также можете вызвать эту функцию внутри функции tone(), и функция примет указатель на флэш-память в качестве аргумента.

Я бы также рекомендовал использовать целочисленные типы из <stdint.h>, поскольку у них определён размер. Чистый int, скорее всего, 32-битный на вашем ПК, но 16-битный на AVR (я убедился в этом на собственном горьком опыте, когда мой алгоритм отлично работал на ПК, но выдавал совершенно бесполезный вывод на AVR).

,