3.4 とりあえず使ってみる(音を出してみる)
音の出力をします。ここでは音の出力は3種類考えます。
1.DigitalOutによるもの
2.PWMによるもの
3.DACによるもの
必要な知識
音の周波数は等比数列で表すことができます。1オクターブあげるのには倍の周波数が必要です。
1オクターブあげるには2倍、2オクターブあげるには4倍です
| 周波数 | |
| ド | 261.626 |
| レ | 293.665 |
| ミ | 329.628 |
| ファ | 349.228 |
| ソ | 391.995 |
| ラ | 440.000 |
| シ | 493.883 |
このホームページを参考にしましたhttp://flawtips.ami.amigasa.jp/blog/060315.html
1.DigitalOutによる単純矩形波によるもの
これは圧電スピーカを使用するには最適です。
圧電スピーカに力が加わると高電圧が発生してマイコンを壊すので抵抗を入れます。

完成したコード/users/yueee_yt/programs/sound_1/lth75y
#define mC 261.626
#define mD 293.665
#define mE 329.628
#define mF 349.228
#define mG 391.995
#define mA 440.000
#define mB 493.883
#include "mbed.h"
DigitalOut sp1(p5);
Ticker timer;
int oto=0;
void tick(void)
{
sp1.write(oto);
oto=!oto;
}
int main() {
float mm[]={mC,mD,mE,mF,mG,mA,mB,mC*2};
int i;
for (i=0;i<sizeof(mm);i++) {
timer.attach(&tick,1.0/mm[i]/2.0);
wait(0.5f);
}
timer.detach();
while(1);
}
コードに間違いがあり修正しました。
なんかこれでは上手く出ません。リセットするたびに音程が変わっているような。。もしかしたらTimerとTickerって一緒に使えないのかなあ。LED例ではつかっているけど。
Quote:
float mm[]={mC*2,mD*2,mE*2,mF*2,mG*2,mA*2,mB*2,mC*4};
にして2オクターブからならまだ聞けるかも
2.PWMを使用した単純矩形波による音だし
PWMを使用してみましょう。
PWMは周波数を指定すれば良いので、プログラムがとても簡単になります。が、使えるポートは限られます。
以下のように接続
完成したコード/users/yueee_yt/programs/sound_2/ltbtei
#define mC 261.626
#define mD 293.665
#define mE 329.628
#define mF 349.228
#define mG 391.995
#define mA 440.000
#define mB 493.883
#include "mbed.h"
PwmOut sp1(p25);
int main() {
float mm[]={mC,mD,mE,mF,mG,mA,mB,mC*2};
int i;
for (i=0;i<sizeof(mm);i++) {
sp1.period(1.0/mm[i]);
sp1.write(0.5f);
wait(0.5f);
sp1.write(0.0f);
}
while (1);
}
Quote:
PwmOutにバグ?
int main() {
float mm[]={mC,mD,mE,mF,mG,mA,mB,mC*2};
int i;
sp1.write(0.5f);
for (i=0;i<sizeof(mm);i++) {
sp1.period(1.0/mm[i]);
wait(0.5f);
}
sp1.write(0.0f);
while (1);
}
とする音が止まらない!
要はPwmOutは、
1.periodの設定
2. write
の手順でないとwriteができなくなるのか!
3.PWMで疑似Sin波音源を作る
PWMなのでこれも一応矩形波です、
今後でDACからADCへ出力するために10kHz(100μs)で
ここからはアンプとスピーカもしくはヘッドフォンが必要です。音量は小さくなります。圧電スピーカは使用できません。圧電スピーカを使用する場合は、アンプが必要です。
スピーカを使用する回路は圧電スピーカの部分を置き換えるだけ、抵抗はなくてもよいです。
プログラムはここ/users/yueee_yt/programs/sound_3/ltbkx4 float ms[179];はfloat ms[180];の間違い
#define mC 261.626
#define mD 293.665
#define mE 329.628
#define mF 349.228
#define mG 391.995
#define mA 440.000
#define mB 493.883
#include "mbed.h"
Ticker timer;
PwmOut sp1(p25);
float ms[180];
float m1;
void sound_out(void) {
static float j=0; //jはStaticで保存できるようにします
j=j+m1; //jに100μSで動く角度/2を足します。
if(j>180)j=j-180; //1周期を超えたら360/2を引く
sp1.write(ms[(int)j]);
}
int main() {
float mm[]={mC,mD,mE,mF,mG,mA,mB,mC*2};
int i;
//Sin波のテーブルを作成します(2度づつ)
for (i=0;i<180;i++) {
ms[i]=sin(2*3.1415*(float)i/180.0)/2.0+0.5;
}
sp1.period_us(10); //100kHz PWMは100kHzとしました。これは10kHzより早ければ問題なし
for (i=0;i<sizeof(mm);i++) {
m1=mm[i]*180/10000; //100μs(10kHz)で動く角度/2の時間を計算
timer.attach_us(&sound_out,100); //10kHz
wait(0.5f);
}
sp1.write(0.0f);
while (1);
}
LPFを通せばいい音になるかも。
4.DACを使用して音を出す
DACで音を作ってみましょう
回路図
プログラムはここ/users/yueee_yt/programs/sound_4/ltbx0k float ms[179];はfloat ms[180];の間違い
PWM版とあまり変更はありません。
#define mC 261.626
#define mD 293.665
#define mE 329.628
#define mF 349.228
#define mG 391.995
#define mA 440.000
#define mB 493.883
#include "mbed.h"
Ticker timer;
AnalogOut sp1(p18);
float ms[180];
float m1;
void sound_out(void) {
static float j=0;
j=j+m1;
if(j>180)j=j-180;
sp1.write(ms[(int)j]);
}
int main() {
float mm[]={mC,mD,mE,mF,mG,mA,mB,mC*2};
int i;
//setting sincurv
for (i=0;i<180;i++) {
ms[i]=sin(2*3.1415*(float)i/180.0)/2.0+0.5;
}
for (i=0;i<sizeof(mm);i++) {
m1=mm[i]*180/10000;
timer.attach_us(&sound_out,100); //10kHz
wait(0.5f);
}
sp1.write(0.0f);
while (1);
}
たぶん10kHzのノイズがのっていると思われる。LPFで取り除けばそこそこきれいな音になるでしょう。
応用 和音
プログラムはここhttp://mbed.org/users/yueee_yt/programs/sound_5/ltgk7z float ms[179];はfloat ms[180];の間違い
#define mC 261.626
#define mD 293.665
#define mE 329.628
#define mF 349.228
#define mG 391.995
#define mA 440.000
#define mB 493.883
#include "mbed.h"
Ticker timer;
AnalogOut sp1(p18);
float ms[180];
float m1,m2,m3;
void sound_out(void) {
static float j1=0;
static float j2=0;
static float j3=0;
j1=j1+m1;
j2=j2+m2;
j3=j3+m3;
if (j1>180)j1=j1-180;
if (j2>180)j2=j2-180;
if (j3>180)j3=j3-180;
sp1.write((ms[(int)j1]+ms[(int)j2]+ms[(int)j3])/3.0);
}
int main() {
int i;
//setting sincurv
for (i=0;i<180;i++) {
ms[i]=sin(2*3.1415*(float)i/180.0)/2.0+0.5;
}
timer.attach_us(&sound_out,100); //10kHz
//ceg
m1=mC*2*180/10000;
m2=mE*2*180/10000;
m3=mG*2*180/10000;
wait(1.0f);
//cfa
m1=mC*2*180/10000;
m2=mF*2*180/10000;
m3=mA*2*180/10000;
wait(1.0f);
//ceg
m1=mC*2*180/10000;
m2=mE*2*180/10000;
m3=mG*2*180/10000;
wait(1.0f);
//bdg
m1=mB*180/10000;
m2=mD*2*180/10000;
m3=mG*2*180/10000;
wait(1.0f);
//ceg
m1=mC*2*180/10000;
m2=mE*2*180/10000;
m3=mG*2*180/10000;
wait(1.0f);
timer.detach();
sp1.write(0.0f);
while (1);
}
プログラムを少し修正しました。
PWM版はここ/users/yueee_yt/programs/sound_6/ltb35h float ms[179];はfloat ms[180];の間違い
6 comments on 3.4 とりあえず使ってみる(音を出してみる):
Please log in to post comments.

いろんな方法で音が出せるのって面白いですね.
ちなみに各音の周波数をあらかじめmbedに計算させておくことも可能です.
"mbed.h"をインクルードしてあれば標準C数学関数が使えるので,プログラムの最初のほうで
#define tone_A 440.0 float tone_freq[ 11 ]; for ( int i = 0; i < 12; i++ ) tone_freq[ i ] = pow( 2, (float)i / 12.0 ) * tone_A; }のようにしてしまうのも手です.
(tone_freq配列には添字0〜11の範囲でA(ラ)〜G#(ソ#)までの周波数が入ります [12平均律で])
こうしておけばピッチをA=440Hzからシフトさせるときにも便利です(笑)