C -герц в секунды и как получить нужное время для задержки?

Я играю с PIC 24, и в настоящее время у меня есть небольшая проблема с преобразованием герц в секунды и последующим использованием его в качестве задержки для отправки сигнала на пьезоэлемент (зуммер, зуммер, динамик и т. Д.), И я хотел бы чтобы он играл определенные ноты.

Я хочу знать, делаю ли я свое преобразование из герц в секунды (мсек в предоставленном коде) и правильно ли я выполняю свою обработку сигналов.

Вот код, с которым я обеспокоен:

Мой герц в int преобразование:

int16 note(int i)
{
   float time = (1.0/i);

   int fin = ((time/2) * 1000);

   return fin;
}

и вот как я посылаю сигнал на рис24, который я использую:

void main()
{
InitMCU();

 output_high(PIN_D1);
 delay_ms(note(E));
 output_low(PIN_D1);
 delay_ms(200); 
 output_high(PIN_D1);
 delay_ms(note(E));
 output_low(PIN_D1);
 delay_ms(200);
}

Вот как я определил примечания:

#define C 255 //do
#define D 227 //re
#define E 204 //mi
#define F 191
#define G 170
#define A 153
#define B 136
#define C2 127

3 ответа

Решение

Во-первых, вы пытаетесь использовать прямоугольные волны для создания синусоидальных волн. Так что это всегда будет звучать немного неправильно, если вы будете стремиться к целевой частоте с помощью таймера. сделать прямоугольную волну 440 Гц, она не "звучит", как синусоида 440 Гц. Может быть, физика закруглит это, но я держу пари, что не так много, как вы хотите.

Вы можете, если у вас есть скорость. Сделайте однобитную вещь ЦАП из 90-х или когда бы то ни было. Если вы можете заставить свои прямоугольные волны идти быстрее, чем динамик может физически двигаться, вы можете сказать, что на некоторое время посыпьте больше единиц, чем нулей, скажем, выталкивая динамик немного с контролируемой скоростью, чем больше нулей, чем на некоторое время, дразня динамик. Динамик становится физическим фильтром низких частот. Вы, вероятно, можете использовать ШИМ в микроконтроллере, чтобы помочь с этим. Но вам нужно динамически изменить его, и это PIC, так что вы, скорее всего, исчерпаете ресурсы, прежде чем сможете кодировать множество таблиц для чистого звука.

Чтобы сделать прямоугольную волну, вам нужно изменить выходной контакт на половину частоты. Не выполняйте вычисления во время выполнения, затем делайте это на своем калькуляторе или позволяйте инструментальной цепочке делать это. Скажем, вы используете свой процессор / таймер на частоте 1 МГц, и вы хотите 440 Гц на выводе. Вам нужен период, чтобы быть 1/440. Гц - это количество циклов в секунду, поэтому оно инвертируется, что составляет секунды за цикл. 0,00227272 (повторяющихся) секунд за цикл или период, поэтому вам нужно его высокое значение для половины и низкое значение для половины (или наоборот, не имеет значения), что означает 0,00113636... между изменениями состояния выхода. Если ваш таймер был 1 МГц, то это 1/1 миллион секунд на цикл. Или одна микросекунда. сколько микросекунд в 0,00113636... 1136. Таким образом, каждый тикер 1136 тикает, что вы меняете состояние, вы читаете документы по таймеру и просчитываете его в обратном или обратном направлении, или что-то еще 1136 (обычно это нулевые числа, поэтому 1135, а затем подсчитывает ноль, а затем прерывание или флаг состояния или что-то еще). Вы также можете, вероятно, опрашивать счетчик, который считает / из всех единиц в / из всех нулей и переворачивает, затем вычитает с этого момента и маскирует его количеством подсчитываемых битов, а разница - это время. с 16-битным счетчиком (начало-сейчас)&0xFFFF - это разница, если желаемое время достаточно меньше 0xFFFF. 1136 наверняка будет. подождите, пока стартовый минус сейчас (если это счетчик вниз или теперь старты минут, если счетчик вверх).

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

В зависимости от динамика и вашей частоты он должен работать. Если вы хотите попробовать одну вещь

https://en.wikipedia.org/wiki/1-bit_DAC

Вы могли бы начать с треугольной волны, скажем, с рабочим циклом 66% для 1/4 из 1136 микросекунд, с коэффициентом заполнения 33% для 1/2 из 1136 микросекунд, а затем с 66% для последней 1/4. Или один раз выполните 1/4, затем 1/2 в одном рабочем цикле, затем 1/2 в другом. Вы должны быть в состоянии найти или написать фильтр нижних частот, не то чтобы вы знали, каковы свойства динамика, но вы можете почувствовать, как генерировать более медленную волну в верхнем. После треугольника вы можете попробовать трапецию. нарастить с некоторой скоростью, сделать 50% на некоторое время, затем нарастить, повторить для другой половины периода.

В экспериментальных целях, найдите или предварительно вычислите последовательность, охватывающую весь период, у вас может быть код, который генерирует несколько сотен или тысяч строк кода, с изображением, которое вы можете быть справедливым, если не совсем детерминированное X число микросекунд может быть достигнуто выполнение точно Y количество инструкций или правильное сочетание Y инструкций, таких как

on
on
off
on
off
on
on
off

затем последняя инструкция перепрыгивает наверх, снова экспериментально, но вы можете обнаружить, что если вы все сделаете правильно, вы получите более чистый звук, возможно, намного чище, чем прямоугольная волна.

Вы можете добавить простой R/C-фильтр, буквально два компонента, чтобы преобразовать ваш битовый поток в аналоговый сигнал, который вы затем подаете на динамик или усиливаете, а затем подаете на динамик, особенность здесь в том, что вы можете посмотреть на него в области видимости.

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

Или просто используйте настоящий ЦАП. основываясь на том, как быстро вы можете подать на ЦАП предварительное вычисление количества значений, которые вам нужно отправить за один период, и составить таблицу и просто отправить их в цикле, пока вы не закончите с этой частотой.

так со всем этим обратно в ваш код. Вы пытаетесь использовать какую-то миллисекундную библиотечную функцию? так скажем, это то, что вы хотите сделать.

440 Гц, как мы видели, составляет 0,00113636 секунд в течение половины периода, так что это будет 1 миллисекунда, а затем одна миллисекунда выключена, ваш код должен сделать это

for(i=0;i<nperiods;i++)
{
on
delay_ms(1)
off
delay_ms(1)
}

любые другие задержки там просто делают это неправильно... для прямоугольной волны. для других тогда я сомневаюсь, что у вас будут запрограммированные задержки.

Таким образом, существует ряд проблем, связанных с вышеизложенным. Во-первых, задержка в миллисекунду - это способ замедлить то, что вы пытаетесь, вам нужна микросекундная задержка, и вам нужно понять, сколько времени занимает служебная нагрузка в цикле, наша математика показала 1136 микросекунды для 440 Гц, с некоторым усечением точности. но код, который выполняет задержку, особенно на медленном mcu, как этот, занимает много тактов, если это код C, а не asm, то много-много других, плюс код для включения и выключения вывода gpio, вы должны вычесть / отключи их. Область поможет, если вы начинаете с 1136, и область показывает период 3000us вместо 2272.7, тогда вам нужно вычесть это и попробовать еще раз. так что задержка 772 вместо 1136. такого рода вещи.

Средняя C составляет 261,6 Гц, по словам Google, правильно или неправильно, давайте работать с ним. это 3823 микросекунды. кормление вашей функции заметки 255, которая, как я полагаю, является тем, для чего определяются определения, дает 1.9 Я предполагаю, миллисекунды. что верно, насколько миллисекунд идет. который усекается до 1 миллисекунды или 2000 микросекунд, что составляет 500 Гц, что, конечно, далеко. это определение должно было быть 261 или 262, а не 255 в любом случае, верно?

хммм, так вы пытаетесь сделать высокий импульс, а затем фиксированный длительный низкий импульс 200 мс? так что если вы подали это примечание E и предположили, что запуск кода не занял много времени. оно будет высоким в течение 2 мс, а затем низким в течение 200, и при условии, что вы повторили, что это рабочий цикл 1% на частоте 1/201 мс или 4,97... Гц, частоты пианино

https://en.wikipedia.org/wiki/Piano_key_frequencies

Не показывать записку на 5 Гц. Я уверен, что он близок к некоторой гармонике, но довольно низок.

А будет иметь высоту 3 мс и 200 мс или частоту 1/203 мс или 4,9 Гц

Помимо математики, выполнение плавающей запятой во время выполнения на изображении (или в любом месте, где нет fpu) чрезвычайно дорого, одна математика, вероятно, займет больше времени, чем весь ваш цикл. Абсолютно нет причин вычислять это время выполнения. Вы могли бы легко сделать определения с помощью математики или использовать свой калькулятор и сделать определения с помощью жестко запрограммированных чисел, вычисленных вручную. Он по-прежнему не работал бы с фиксированным низким периодом, особенно таким большим, по сравнению с нужными вам числами. с задержкой в ​​миллисекунду, предполагая, что код запускается мгновенно. с задержкой 1 мс с задержкой 1 мс - 500 Гц. вкл, задержка 2, задержка выключения 2, 250 Гц, задержка 3 равна 166, задержка 4 равна 125 и так далее. Вы не собираетесь получать много реальных заметок, предполагая, что код запускается мгновенно, а не с использованием миллисекундной задержки.

чтобы создать волну давления, вы хотите, чтобы динамик выталкивался из своего состояния покоя на половину цикла и всасывался из состояния покоя на половину цикла, в идеале в синусоидальной форме, чтобы он медленно выходил и потом возвращался тянет и уходит. переход от состояния сброса к выходу только будет работать наверняка, но вам все еще нужно иметь право рабочего цикла, чтобы приблизиться к прямоугольной волне. так что поймите таймеры, которые у вас есть, с помощью картинки вы можете легко кодировать некоторые циклы, которые записывают такты, поскольку они детерминированы из того, что я помню. начать с частоты вашего процессора, что это? сколько процессорных циклов за один период вашей заметки? так же, как математика 440 Гц до 1 МГц выше. 0.0011363636 умножить на 1 миллион (секунд на половину периода, тиков в секунду, секунды отменяются, и вы получаете тики на половину периода, математика работает на единицах, как числа), если ваш mcu работает с 2 миллионами тактов в секунду, то это 2 миллиона раз, 0,001136363636..,

Затем выясните, как включить его, дождитесь, когда количество процессорных часов выключится, и дождитесь этого количества процессорных часов. кормите это в свой пьезо или другой и посмотрите, как это звучит.

Если бы у вас были 16-битные регистры, которые, я уверен, вы не предполагаете, что при тактовой частоте 1 МГц вы бы

load reg with some number
top
subtract reg,1
compare with zero
branch to top

в сборке конечно. Предполагая один такт для вычитания и сравнивая каждый затем два для ветви, допустим, что это четыре на цикл, поэтому 1136/4 = 284. Загрузите регистр с предварительно вычисленным значением 284.

ручной код какой-то сборки

top:
gpio on
load reg,284
one:
sub reg,1
cmp reg,0
bne one
gpio off
load reg,284
two:
sub reg,1
cmp reg,0
bne two
jmp top

сырой, но это поможет вам начать путь.

если у вас нет 16-битных регистров, а 8-битных, 1 МГц 1136/0x100 = 4 остатка 112, что было бы неплохо, если бы этот процессор занимал 4 такта на цикл, как я фантазировал выше. каждая задержка будет

mov reg,0xFF
A:
sub reg,1
cmp reg,0
bne A
mov reg,28
B:
sub reg,1
cmp reg,0
bne B

Здесь, без сомнения, есть бесчисленные ресурсы и другие места, описывающие петли задержки для членов семейства PIC.

Вы могли бы просто включить его и увидеть, как меняются звуки

#define DELX 300
volatile unsigned int x;
while(1)
{
    output_high(PIN_D1);
    for(x=0;x<DELX;x++) continue; 
    output_low(PIN_D1);
    for(x=0;x<DELX;x++) continue; 
}

и играть с разными номерами для определения. тон должен измениться, качество может быть не таким большим или, может быть, намного лучше, чем у вас сейчас, но оно должно измениться, если его вообще слышно. есть вероятность, что вы столкнетесь с обрывами, я предполагаю, что это 8-битный процессор, поэтому отсчет до 200, скорее, отличается от подсчета до 300, это не будет частота, которая в полтора раза ниже. Возможно, он не будет линейным, может зависеть от компилятора, но это могут быть линейные сегменты с изломами здесь и там. От 100 до 200 могут быть линейными, а от 300 до 400, но от 200 до 300 - нет.

Это, вероятно, линейно, хотя

volatile unsigned int x;
unsigned int y,z;
for(z=0;z<1000;z++)
for(y=0;y<100;y++)
{
    output_high(PIN_D1);
    for(x=0;x<z;x++) continue; 
    output_low(PIN_D1);
    for(x=0;x<z;x++) continue; 
}

Вам нужна петля!

repeat for note length:
   on
   delay
   off
   delay

Также рассмотрите возможность вычисления требуемого периода для каждой ноты в автономном режиме и введите ее как целое число, а не в Гц - процессор не будет тратить время на вычисления с плавающей запятой

Средняя нота А обычно составляет 440 Гц. Если вы включаете и выключаете пьезодинамик 440 раз в секунду, задержка между последовательными переключениями составляет 1/880 секунды, что составляет 1,13636363636 мс. Это показывает две вещи:

  • ваши расчеты далеко; а также
  • Разрешение таймера в одну миллисекунду слишком грубое для этого приложения.

Конечно, вам нужен цикл для воспроизведения тона с некоторой продолжительностью.

Другие вопросы по тегам