Проблема при использовании 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.
@Jo-Bob Bubba, 👍2
1 ответ
Лучший ответ:
Нельзя напрямую разыменовать объект (получить доступ к массиву), находящийся во флэш-памяти. Для этого необходимо использовать функции 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).
- Преимущества глобальных переменных перед статическими членами класса?
- Arduino IDE: как получить длину PROGMEM const?
- Как использовать PROGMEM в файле .h/.cpp вместо файла .ino?
- Печать элементов массива символов из PROGMEM
- Как объявить массив переменного размера (глобально)
- Программирование Arduino с использованием Python, а не C/C ++
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
- Как справиться с rollover millis()?