Простые мелодии для Arduino

deckard
Offline
Зарегистрирован: 23.07.2019
Я хотел бы предложить Вашему вниманию программы
исполнения "биперной" музыки, которые я написал
в разное время. Это конечно не музыкальный шедевр
и даже не то, что было на Спектрумовском AY,
а просто интересные для начального обучения примеры
Архивы включают множество коротких мелодий.
 
 
BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

С отключённым фильтром рекламы - сплошная реклама куда не ткни. Кликбейт како то. 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Для того, чтобы примеры были «интересны для обучения», они должны быть хотя бы минимально грамотными. Давай посмотрим. Вот у тебя в комментарии написана важная вещь.

"deckard" пишет:
Если Вы хотите применить низкоомный динамик, надо подключить его через резистор 100 Ом (см рисунок), чтобы избежать токовой перегрузки процессора

Ну, давай посмотрим, как мы её избежим. Активное сопротивление «обычного» динамика – 8Ω, плюс резистор 100Ω, таким образом имеем ток 5В/108Ω = 46,3мА. В то время как абсолютный максимум для пина ATmega328P – 40мА, т.е. мы превысили абсолютный максимум почти на 16%. Хорошо избежали!

Но это аппаратная часть. Посмотрим на программную.

Основа там, как я понимаю, вот эта функция:

// собственно аппаратный вывод звука
// tone - полупериод импульса (микросекунды), а не частота звука
// duration - длительность звука (миллисекунды)
 void playTone(int tone,int duration) {
	digitalWrite(LED,HIGH)
	for (unsigned long i=0;i < duration*1000L;i+=(tone*2)) {
		digitalWrite(SPEAKER,HIGH);
		delayMicroseconds(tone);
		digitalWrite(SPEAKER,LOW);
		delayMicroseconds(tone);
	}
	digitalWrite(LED,LOW)
}

Для чего ты смешиваешь в сравнении знаковые и беззнаковые величины (и плюёшь на соответствующее предупреждение компилятора) я не знаю, но Бог с ним, есть вещи поинтереснее.

Нигде в комментариях не сказано об ограничениях, потому, как я понимаю, я могу попытаться сыграть любую разумную ноту. Так? Хорошо, беру «ля» субконтроктавы (частота 27,5Гц, полупериод – 18182 микросекунды). Запускаю «playTone(18182, 2000);» – какая боль! Нихрена не играет и время 2 сек не выдерживает!

Может быть нельзя играть такие низкие звуки? Тогда нужно написать о существующем ограничении (не менее 30,53 Герц) в документации (комментариях). Но лучше всё же аккуратнее программировать и не допускать детских ошибок в своих программах, тогда и таких глупых ограничений не будет.

В общем, ты сначала пройди обучение сам, а потом уж будешь публиковать «примеры для обучения».

deckard
Offline
Зарегистрирован: 23.07.2019
Нынче куда ни глянешь, везде наткнешься на троллей.
Весьма неприятное обстоятельство. "А народ-то не знает" -
действительно могут чёрт знает что подумать о моих
программах после такой проповеди.
 
>> Не играет ноту с частотой 27 герц.
 
А кто в наше тяжелое время играет такую ноту ?
Считается, что человек воспринимает звуки с частотой
20 - 20000 Hz. Но ещё есть такая вещь как частотная
характеристика, которая разная у hi-fi колонок, наушников,
всяких разных динамиков и уж совсем плохая у биперов.
 
Вот простая программа, которая сначала выдаёт звук
с помощью стандартной для Arduino функции tone(),
а затем с помощью функции playTone(). Запустите программу
и откройте окно терминала, 9600 Бод, чтобы увидеть результат
(Разумеется, бипер должен быть подключен к плате и значение
SPEAKER должно быть правильно установлено)
 
>> Программа
#define LED 13
#define SPEAKER 8

int f[]={16000,8000,4000,2000,1000,500,100,50,27};

void setup()
{
  Serial.begin(9600);
  pinMode(LED,OUTPUT);pinMode(SPEAKER,OUTPUT); 
}

void loop()
{char i;int ton;
  for (i=0;i<9;i++)
    {ton=(int)(500000L/f[i]);
      Serial.print("tone()     function  f=");Serial.println(f[i]);
      tone(SPEAKER,f[i],500);delay(1000); //500+500
      Serial.print("playTone() function  f=");Serial.println(f[i]);
      playTone(ton,500);delay(500);
    }
    delay(2000);
}

//hardware play tone itself. tone is a delay in microseconds (not frequancy),
//duration is a sound length in milliseconds
void playTone(int tone,int duration)
{digitalWrite(LED,HIGH);
  for (unsigned long i=0;i<duration*1000L;i+=(tone*2))
  {digitalWrite(SPEAKER,HIGH);
   delayMicroseconds(tone);
   digitalWrite(SPEAKER,LOW);
   delayMicroseconds(tone);
  }
digitalWrite(LED,LOW);
}
 

 

 
 
>>Конец программы
 
Какой скандал ! И 16000 Hz не звучит! И 50 Hz не звучит!
50 Hz - это частота, с которой гудят трансформаторы.
Вы же требуете, чтобы (чисто ?) звучала нота на октаву
ниже, чем гудение трансформатора. И говорите "не звучит".
Проблема не в том, что программа, микроконтроллер или компьютер
не могут выдать сигнал очень высокой или низкой частоты, а в том,
что ни маленький динамик, ни бипер не могут звучать на таких частотах.
Но всё-таки ради интереса: а кому нужна музыка с такими нотами?
 
>> Зачем задекларирован счетчик как unsigned long i в функции playTone() ?
>> Ведь компилятор выдает предупреждение ...
 
Нет, не выдает. Специально проверял, у меня Arduino IDE 1.8.5, не самый новый,
но всё же. В любом случае проблема может проявиться (?), если значение счётчика
превысит 2^31 микросекунд, то есть если кто-то захочет проиграть ноту длительностью
свыше 35 минут. В любом случее "документированная ошибка - это особенность".
И опять-таки возникает вопрос: кому нужно тянуть ноту 35 минут ?
 
Друзья мои ! Не сомневайтесь, у меня самая правильная музыка для Arduino во всей
Сети (при условии, что она биперная, одноголосная, затёртая и всем надоевшая) !
 

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ворота пишет:

Активное сопротивление «обычного» динамика – 8Ω, плюс резистор 100Ω, таким образом имеем ток 5В/108Ω = 46,3мА. В то время как абсолютный максимум для пина ATmega328P – 40мА, т.е. мы превысили абсолютный максимум почти на 16%. Хорошо избежали!

Но это аппаратная часть.

Это еще не вся аппаратная часть. Даже из той весьма небольшой мощности, которую способен выдать вывод МК, на динамик мы пускаем менее 7.5%, остальные 92.5% попусту рассевивая на резисторе.

Цитата:

Посмотрим на программную.

// tone - полупериод импульса (микросекунды), а не частота звука

// duration - длительность звука (миллисекунды)

Мало того, что полупериод зачем-то назван "tone", так еще и в вызове одной функции вперемешку следуют величины, выраженные то в миллисекундах, то в микросекундах.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015
>>>> Не играет ноту с частотой 27 герц.
 
>>А кто в наше тяжелое время играет такую ноту ?
 
Обычное домашнее пианино, не говоря даже о концертном рояле или синтезаторе.
 
>>Считается, что человек воспринимает звуки с частотой
>>20 - 20000 Hz.
 
Ну да, в детских популярных книжках примерно так и написано, но если мы говорим о НОТАХ, то их частоты лежат в пределах от 16.35 Гц до 4.185 кГц.
 
>>Какой скандал ! И 16000 Hz не звучит!
 
Нет такой ноты.
 
>>Проблема не в том, что программа, микроконтроллер или компьютер
>>не могут выдать сигнал очень высокой или низкой частоты, а в том,
>>что ни маленький динамик, ни бипер не могут звучать на таких частотах.
 
А от него и не требуется.
Ведь Вы даже не пытаетесь генерить синус, а в меандре достаточно обертонов, чтобы их могла воспроизвести простейшая пищалка. А остальное человеческий слух восстановит. Благо, он это умеет делать.
 
>>Но всё-таки ради интереса: а кому нужна музыка с такими нотами?
 
Правильно, объявим ненужным нотам люстрацию!
 
PS. Достало уже воинствующее невежество.
 
qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

Даже простые мелодии под Ардуино должен писать не программист, а музыкант. Но если человек не музыкант, то даже скачка продвинутого ПО не поможет.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Я вчера подготовил исправления, чтобы таки заработало, и уже почти выложил их, но передумал, решил дождаться реакции ТС и не зря. ТС оказался «всегда и во всём правым».

Знаешь, нормальные люди, когда допустят ошибку в программе, просто спокойно признают это и исправляют. И от этого их репутация ничуть не страдает. А тех же, кто упирается рогом «нет никакой ошибки – вы все тролли» просто макают в эти ошибки носом и над ними начинают смеяться. Ты решил пойти по этому пути. Отлично - это втой выбор свободного человека!

Итак, поехали:

deckard пишет:
Проблема не в том, что программа, микроконтроллер или компьютер не могут выдать сигнал очень высокой или низкой частоты, а в том, что ни маленький динамик, ни бипер не могут звучать на таких частотах.

Да, нет, проблема как раз в том, что именно программа не может выдать такую частоту из-за элементарной ошибки программиста. Давай оставим проблемы динамиков динамикам, а сами просто посмотрим на твою программу. Я утверждаю, что низкие ноты не играет именно она из-за детской ошибки, до динамиков даже дело не доходит - им не дают шанса. С твоего позволения я написал вот такой тест для упомянутй мною ноты «ля» субконтроктавы (частота 27,5Гц, полупериод – 18182 микросекунды). Проверь, надеюсь я аккуратно скопипастил и корректо внес дополнения для теста.

#define	SPEAKER 13

// собственно аппаратный вывод звука
// tone - полупериод импульса (микросекунды), а не частота звука
// duration - длительность звука (миллисекунды)
 void playTone(int tone,int duration) {
//	digitalWrite(LED,HIGH);
	uint32_t playCounter = 0;
	for (unsigned long i=0;i < duration*1000L;i+=(tone*2)) {
		playCounter++;
		digitalWrite(SPEAKER,HIGH);
		delayMicroseconds(tone);
		digitalWrite(SPEAKER,LOW);
		delayMicroseconds(tone);
	}
//	digitalWrite(LED,LOW);
	Serial.print("playCounter: ");
	Serial.println(playCounter);
}

void setup(void) {
	Serial.begin(115200);
	pinMode(SPEAKER,OUTPUT);
	playTone(18182, 32000);
}

Программа должна напечатать количество прохождений цикла. И что же она печатает?

playCounter: 1

Т.е. эту ноту программа даже не попыталась сыграть! И динамик тут, ну совсем не приделах.

Кстати, если бы бы ты прислушался к предупреждения компилятора, то ошибку нашёл бы сразу, но он у тебя ...

deckard пишет:
Нет, не выдает. Специально проверял, у меня Arduino IDE 1.8.5

Родной ты наш, открой диалог «Настройки» в IDE и найди там опцию «Сообщения компилятора». Если ты уберёшь «страусиное» умолчание «нет» и поставишь что-то более адекватное, то немедленно увидишь сообщение

In function 'void playTone(int, int)':
warning: comparison between signed and unsigned integer expressions [-Wsign-compare]

Kepassa пишет:
Друзья мои ! Не сомневайтесь, у меня самая правильная музыка для Arduino во всей Сети

Это «да», не только в Сети, но и в её окрестностях. Правда, с беграмотными аппаратными советами, направленными на угробление аппаратуры, и детскими ошибками в программе, а в остальном очень хорошая! 

Был тут один Великий, у того тоже всегда было всё самое лучшее в сети :)

И да, кстати, о том «кому и зачем нужны такие ноты». А кому и зачем вообще нужна музыка? Ноты бывают от субконтроктавы до пятой октавы (и даже до седьмой в некоторых случаях). И это и есть музыка. Что же касается субконтроктавы непосредственно, так Тим Стромс её просто поёт. Но мы здесь говорим вовсе не о нужности или ненужности нот. Мы говорим о детских ошибках программирования в «учебных материалах» и об упирании рогом вместо того, чтобы просто сказать  «ой, блин, лажанулся» и исправить.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ворота пишет:

Ноты бывают от субконтроктавы до пятой октавы (и даже до седьмой в некоторых случаях).

А седьмая - это, часом, не в американской нотации? 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

andriano пишет:
А седьмая - это, часом, не в американской нотации?
Бог её знает, но частоты у шестой и седьмой - выше пятой (по общему правилу считаются).

Я никогда про "дальше пятой" не слышал, а тут полез частоту подсмотреть для этого примера, а там словами описаны до пятой, а в таблице частот - до седьмой. Причём написано, что некая Джорджия Браун может петь аж до соль седьмой октавы.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Ворота пишет:

 Причём написано, что некая Джорджия Браун может петь аж до соль седьмой октавы.

у ней, наерна, карикатурное сапрано. 

deckard
Offline
Зарегистрирован: 23.07.2019
Ну вот и ошибки нашлись
 
1) i+=(tone*2) в операторе for 
Поскольку tone определен как int
при умножении на 2, если tone>16383, возникает переполнение (отрицательный результат),
что после преобразования в unsigned long и сложения приводит к ошибке.
В этом случае цикл выполняется только 1 раз.
 
2) Менее очевидная ошибка.
Из руководства Arduino файл DelayMicroseconds.html
 
>>delayMicroseconds()
>>Description
 
>> Pauses the program for the amount of time (in microseconds) specified as parameter.
>> There are a thousand microseconds in a millisecond, and a million microseconds in a second.
 
!> Currently, the largest value that will produce an accurate delay is 16383.
!> This could change in future Arduino releases. 
>> For delays longer than a few thousand microseconds, you should use delay() instead. 
 
Видимо при создании стандартной библиотеки тоже не всё сложилось удачно.
Тоже наверное "дети писали". Вот это и есть наглый троллинг, когда вместо того
чтобы сказать "ты случайно ошибся в типе переменной, давай исправим" разводится спор ни о чём
на десятки килобайт.
 
Есть у меня другая функция
 
toneWithDelay(uint8_t _pin, unsigned int frequency, unsigned long duration) 
 
которая удобнее при использовании и не испытывает проблем с низкими частотами.
 
Поэтому я и сам отказался от playtone() как от неудобной.
И кстати функция playtone() не моя, я её взял из книги "Улли Соммер.
Программирование микроконтроллерных плат Arduino/Freeduino".
 
С учетом этого написана функция plytone2(), которая также имеет ограничение на
частоту, но 16 Hz (ton <= 32766)
 
>>Программа
 
#define SPEAKER 8

// Это другая версия вывода звука, которая не испытывает трудностей с низкими частотами

void toneWithDelay (uint8_t _pin, unsigned int frequency, unsigned long duration)
{
  unsigned long TimeMs, TimeUs;
  unsigned int Micros;
  char PinValue;
  
  PinValue = 0;
  TimeMs = millis();
  Micros = 500000L / frequency;
  while (!((millis() - TimeMs) >= duration)) {
    TimeUs = micros();
    while (!((micros() - TimeUs) >= Micros));
    PinValue = ~PinValue;
    if (frequency) digitalWrite(_pin, PinValue);
  }
  digitalWrite(_pin, 0);
} 

// Доработанная программа для низких частот до 16 Hz
// собственно аппаратный вывод звука
// ton - полупериод импульса (микросекунды), а не частота звука
// duration - длительность звука (миллисекунды)
// ton <= 32766 (0x7FFE), что соответствует частоте 500000L/32766 около 16 Hz
void playTone2(unsigned int ton,unsigned int duration)
{unsigned int tondiv2=ton/2;
  for (unsigned long i=0;i<duration*1000L;i+=ton,i+=ton)
  {digitalWrite(SPEAKER,HIGH);
   //Аргумент delayMicroseconds не может быть больше 16383 (0x3FFF)
   // См DelayMicroseconds.html
   delayMicroseconds(tondiv2);delayMicroseconds(tondiv2);
   digitalWrite(SPEAKER,LOW);
   delayMicroseconds(tondiv2);delayMicroseconds(tondiv2);
  }

}

void setup(void) {

    Serial.begin(9600);

    pinMode(SPEAKER,OUTPUT);
// Здесь первый аргумент - задержка полупериода мкс
  playTone2(18000, 2000);delay(1000);
  playTone2(25000, 2000);delay(1000);
  playTone2(32000, 2000);delay(1000);
// Здесь первый аргумент - частота Hz  
  toneWithDelay(SPEAKER,2000,2000);delay(1000);
  toneWithDelay(SPEAKER,20,2000);delay(1000);
  toneWithDelay(SPEAKER,18,2000);delay(1000);
  toneWithDelay(SPEAKER,8,2000);

 
}

void loop()
{}

 

 
>>Конец программы
 
Что ж, это вполне жизненная ситуация при программировании.
Извиняюсь, если кого случайно обидел.
 
 
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

deckard пишет:

Извиняюсь, если кого случайно обидел.

Боюсь, что не случайно. Ваш пост #3 написан глумливо-издевательски. Не думаю, что у Ворот или ещё у кого-нибудь после такой отповеди возникнет желание снова смотреть Ваш код и пытаться помочь, если там есть проблемы (а они там, увы, есть, и не одна). А ведь Вам по сути привели конкретные условия при которых программа не работает. Что мешало посмотреть в чём дело, зачем было глумиться? Чрезмерная уверенность в собственной непогрешимости в "лучшести в сети"? Сами себе злобный буратино.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

DetSimen пишет:

у ней, наерна, карикатурное сапрано. 

Уж и не знаю, но 25 с копейками киголерц - ультразвук же голимый! Она не летучая мышь случаем? Может, просто зверька так зовут?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Ворота пишет:

Я никогда про "дальше пятой" не слышал, а тут полез частоту подсмотреть для этого примера, а там словами описаны до пятой, а в таблице частот - до седьмой.

Мельком глянул - в статье и без этого достаточно ляпов.

 

PS. Хочешь, я прямо здесь опубликую таблицу с частотами "нот" до 12-й октавы включительно? 

nik182
Offline
Зарегистрирован: 04.05.2015

Зачем таблицу? Формула ж простая как грабли.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

nik182 пишет:

Зачем таблицу? Формула ж простая как грабли.

А я и не предлагал составлять таблицу на слух)))))))))))))))))

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

andriano пишет:
Хочешь, я прямо здесь опубликую таблицу с частотами "нот" до 12-й октавы включительно?
Не хочу. 

А чего до 12-ой, а не до 100500-ой? Компютеру не всё равно сколько считать?

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

100500 - это круто (как никак - частота от номера ноты зависит экспоненциально), боюсь, что текст такого объема перегрузит сервер, на котором крутится этот форум.