前回の記事で圧電素子の使い方について紹介したので、今回はその応用編として電子マリンバを作ってみました。
以前ネットで電子マリンバなるものを見つけたとき、めちゃくちゃ欲しいと思ったんですが、ウン十万という値段を見て絶望しました。そこで自分で作ってしまえばいいのでは?という発想に至りこの記事が出来上がりました。
前回の記事はこちら
イメージが湧きやすいように初めに完成品の写真と動画を掲載しておきます。
動画だと打音がうるさいですが、実際にはそれほどではありません。
音源については暫定版でまだ開発中です。
今回は2オクターブ製作しましたが、構造的には同じものを連結する形で更に大きくすることが可能です。
主な材料(1オクターブ当たり)
1オクターブ当たりの材料になります。購入の最小単位がそれよりも大きい場合もあるのでご注意ください。
品目 | 個数 | 値段 | 購入場所 |
MDF 300x400x6 | 1 | \110 | ダイソー |
スポンジシート 300x300x5 | 0.5 | \220 | ホームセンター |
ウレタンフォーム 300x300x10 | 0.5 | \200 | ホームセンター |
タッピングネジM3、スペーサー | 4 | \60 | ホームセンター |
圧電素子 | 12 | \75 | AliExpress |
抵抗 1MΩ | 12 | \12 | 秋月電子 |
PIC16F1579+ICソケット | 1 | \150 | 秋月電子 |
両面ユニバーサル基板D | 1 | \40 | 秋月電子 |
XHコネクタ、ハウジング | 2 | \30 | 秋月電子 |
超小型USBシリアル変換モジュール(1オクターブ目のみ) | 1 | \600 | 秋月電子 |
合計 | \900 + 600 (概算) | (\600は1オクターブ目のみ) |
音源部について
今回はシリアル通信で外部に情報を送信してそちらで音を鳴らしますが、矩形波ぐらいだったらPIC自身でならせるので、USBシリアル変換モジュールの代わりにスピーカー等を使っても良いと思います。
矩形波の場合のテスト動画
設計図
手書きの超ゆるい設計図を掲載します。イメージだけつかんでください。
①基本構造
鍵盤はMDFをベースにして、打音を抑えるためにスポンジを貼り、振動が隣の鍵盤に伝わらないようにウレタンを挟んで土台に設置します。
鍵盤と基板の配線は土台の裏で行うことにしました。(裏側の見栄えは気にしてはいけない)
②大きさ
鍵盤と土台のサイズは図のようにしました。(単位:mm)
この大きさにした理由は、保管しやすいように手元にあった靴箱に合わせて設計したためです。
③通信
1つのキーボードにつきPICが1つあり、複数のキーボードを使用する時には各キーボードとPCを直接繋げるのは非効率です。
そこで、下図のように各キーボードを数珠繋ぎにします。各キーボードは鍵盤が叩かれたことを検知すると、その情報を1つ前のキーボードに送信します。後ろのキーボードから受信した情報はそのまま前に流します。
例えるならば、任意の場所から開始できるバケツリレーのような感じですね。このような接続方法はデイジーチェーンと呼ばれるみたいです。
また、電源はPCのUSBから供給し、この線と一緒に配線してしまいます。
キーボードの製作
まずはノコギリを使用してMDFから前述の設計図の大きさに合わせて土台と鍵盤を切り出します。鍵盤は12個です。
続いて、カッターを使用してスポンジシートとウレタンフォームからも鍵盤を切り出します。
続いて、ウレタンフォームと土台に配線を通すための穴をあけます。ウレタンフォームはポンチを使用し、土台はドリルを使用しました。
次に鍵盤を作ります。写真を撮り忘れたのでイラストで説明します。
基本は両面テープで接着しますが、ウレタンフォームには上手くくっつかないので、接着剤を使用しました。最適かどうかは知りませんが、ゴム用のもので上手くくっつきました。
図では省略してますが、圧電素子の配線は先ほど開けた穴に通しておいてください。
これでとりあえずキーボードの部分は完成しました。裏側はこんな感じです。
回路の製作
キーボードが出来たので、次は回路を作っていきます。
といっても回路は非常に簡単です。
回路は簡単なんですけど回路図はごちゃごちゃですね…。
やってることは12個のアナログピンをプルダウンして圧電素子に繋げるのと、シリアル通信用のTX/RXを繋いでいるだけです。
完成した基板がこちらです。特に裏面なんかは恥ずかしいので見ないでください//
ちなみにRXとTXは写真じゃ見えにくいかもしれませんがUEWで配線しています。
配線作業
キーボードと基板が出来たので、最後に配線をします。
まずは共通のGNDを配線してしまいます。スズメッキ線を幹にしてそこに各鍵盤のGNDを接続しました。(雑配線)
次に基板と圧電素子を繋ぐ線を用意します。基板からの位置によって長さを調節しています。作業のために線は長めに用意しておいた方が良いです。
色の違いに意味はありません。また、写真のように各線に印をつけて判別できるようにしておくと作業が捗ります。
この線を先程の写真のように基板の裏に接続してから土台の穴に通します。(カオス)
それぞれ対応する線を接続したら熱収縮チューブやテープで保護します。(やっぱりカオス)
配線を覆う板でも付けようかとも思いましたが、メンテナンス性を考えてスポンジテープで足を付けるだけにしました。
基板をねじで止めます。8mmのタッピングねじを使えば土台を貫通することなく固定できました。(ちなみにスペーサーは3Dプリンター製です)
上の写真は2オクターブ目ですが、1オクターブ目はこのようにUSBシリアル変換モジュールを挿せるようにピンソケットにしてあります。
また、キーボード間を繋ぐ線は百均のUSBケーブルを流用しました。
これでハードウェアは完成です!1オクターブ作るのに1日かかりました…。
プログラム
最後にプログラムを紹介します。やってることはとても簡単で、ADCの各チャンネルをポーリングして測定値が閾値を超えてその後下がったら鍵盤が叩かれたと判定して信号を送信するだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
#pragma config FOSC = INTOSC // Oscillator Selection Bits (INTOSC oscillator; I/O function on CLKIN pin) #pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled) #pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled) #pragma config MCLRE = OFF // MCLR Pin Function Select (MCLR/VPP pin function is digital input) #pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled) #pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled) #pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin) #pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off) #pragma config PPS1WAY = ON // PPSLOCK bit One-Way Set Enable bit (PPSLOCKED Bit Can Be Cleared & Set Once) #pragma config PLLEN = ON // PLL Enable (4x PLL enabled) #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset) #pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.) #pragma config LPBOREN = OFF // Low Power Brown-out Reset enable bit (LPBOR is disabled) #pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming) #include <xc.h> #include <stdio.h> #include "usart1579.h" #define _XTAL_FREQ 32000000 #define ID 1 //キーボード番号 #define THRE 50 //入力閾値 void Init(); char GoADCConversion(char ch); void PlaySound(char t); void main(void) { Init(); EUSART_Init(); char res = 0; char channel = 0; char isBeating[12] = {0,0,0,0,0,0,0,0,0,0,0,0}; while(1){ res = GoADCConversion(channel); switch(isBeating[channel]){ case 0: if(res > THRE){ isBeating[channel] = 1; } break; if(res < 4){ isBeating[channel] = 0; PlaySound(channel); } break; } channel++; if(channel == 12) channel = 0; } } void __interrupt isr(){ GIE = 0; if(RCIF){ //シリアル通信 受け流し EUSART_Send(RCREG); } GIE = 1; } void Init(){ OSCCONbits.IRCF = 0b1110; //32MHz TRISA = 0b00010111; ANSELA = 0b00010111; TRISB = 0b10110000; ANSELB = 0b00110000; TRISC = 0b11001111; ANSELC = 0b11001111; ADCON0 = 0b00000001; // AN0/ ADC ON ADCON1 = 0b10100000; // Right Justified/ clock : Fosc/32(1us) / Ref+ : VDD ADCON2 = 0; // No Auto Conversion OPTION_REG = 0b11000111; // WPU Disabled/ TMR0 Clock : Fosc/4 / TMR0 Prescaler : 256 // TMR0 period : 8ms PEIE = 1; GIE = 1; } char GoADCConversion(char ch){ ADCON0bits.CHS = ch; __delay_us(5); ADCON0bits.ADGO = 1; while(ADCON0bits.ADGO); //in process if(ADRESH != 0) //ADRES(max 1024) > 255 return 255; else return ADRESL; } void PlaySound(char t){ char c = (ID << 4) + t; EUSART_Send(c); } |
シリアル通信ライブラリ
1 2 3 |
void EUSART_Init(); void EUSART_Send(char c); char EUSART_Receive(); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#include<xc.h> #define _XTAL_FREQ 32000000 #define BAUDRATE 9600 void EUSART_Init(){ TXSTA = 0x24; //8bit/Async/HighSpeed RCSTA = 0x90; //8bit BAUDCON = 0x08; //16bitBRG SPBRGL = 0x00FF & (_XTAL_FREQ/BAUDRATE/4 - 1); SPBRGH = (0xFF00 & (_XTAL_FREQ/BAUDRATE/4 - 1)) >> 8; PIE1bits.RCIE = 1; PIR1bits.RCIF = 0; RXPPS = 0b00001111; //RX on RB7 RB6PPS = 0b00001001; //TX on RB6 } void EUSART_Send(char c){ while(TXSTAbits.TRMT == 0); TXREG = c; } char EUSART_Receive(){ if(PIR1bits.RCIF == 1){ if((RCSTAbits.OERR)||(RCSTAbits.FERR)){ RCSTA = 0; RCSTA = 0x90; return 0xff; //ERROR } else return RCREG; //NORMAL } else return 0; //NO DATA } |
PC側のソフトについては気が向いたら紹介します。
最後までご覧いただきありがとうございました。この記事を見て電子マリンバあるいは他の電子楽器を作る参考になれば幸いです。