// 歌う扇風機 (KIMURA + MATHRAX LLC.) // スケッチ by MATHRAX LLC. // 2010.05.15 // サーボモーター制御ライブラリの準備 #include Servo myservo; // アナログマルチプレクサ関連の定義---------------------------------// // アナログ入力ピン #define MUX_1 1 #define MUX_2 0 #define MUX_3 2 // アナログマルチプレクサ切替用の出力ピン #define MUX_A 4 #define MUX_B 3 #define MUX_C 2 // DCモーター制御関連の定義---------------------------------// // DCモーター制御につかう出力ピン #define IN1_A 8 #define IN1_B 10 #define IN2_A 9 #define IN2_B 11 // その他の定義---------------------------------// // ツマミ用の入力ピン #define POT 4 // サーボ用の出力ピン #define SERVO 6 // 変数の準備---------------------------------// // アナログマルチプレクサ用の変数 int scanCount=7; int mux_num=2; int muxInput[8]={ 5,7,4,6,2,1,0,3}; // 24個のスイッチ入力用の変数(今回使っているのは22個分の変数です) int switchStatus_A[24]; int switchStatus_B[24]; int switchValue[24]; int lastSwitch; // DCモーターが音階を奏でるように割り振った変数 // (回転数ではなく「0~255」までのモーター回転の速度) // 24個のうち22個しか使ってないので最後の2つは「0」としています int Freq[24]={ 17,18,19,20,21,22,23,24,25,27,29,31, 34,36,40,43,47,59,73,93,136,245,0,0}; // DCモーター制御のための変数 int ccnt; int ppwm; int ncnt; // 初期設定 ---------------------------------// void setup(){ //アナログマルチプレクサの切替え用のピンを出力に pinMode(MUX_A , OUTPUT); pinMode(MUX_B , OUTPUT); pinMode(MUX_C , OUTPUT); //DCモーター制御のピンを出力に //「IN2_B」に割り振ったピンはPWMモードで使うため、ここでは設定していません。 pinMode(IN1_A, OUTPUT); pinMode(IN1_B, OUTPUT); pinMode(IN2_A, OUTPUT); //DCモーターを最初にストップさせる digitalWrite(IN1_A, LOW); digitalWrite(IN1_B,HIGH); digitalWrite(IN2_A, LOW); analogWrite(IN2_B, 255); //サーボモーター制御用のピンを割り振る myservo.attach(SERVO); //サーボモーターの角度を「0」にして原点に戻す myservo.write(0); } // ループ ---------------------------------// void loop(){ //アナログマルチプレクサをスキャン scanMUX(); //サーボモーターの角度を、ツマミのアナログ値で変える //ツマミの「0~1023」のアナログ値を、「0~60」まで変化するように変換しています myservo.write((analogRead(POT)/1023.0)*60.0); //24個分のスイッチの処理 for(int i=0; i<24; i++){ //スイッチ入力の数値が、800以上だったら //オンオフのみですが、アナログ入力として扱っています //「0~1023」までの変化のうち、「800以上」になったらオンとみなしています if(switchValue[i]>=800){ // 最初にDCモーターの回転速度を上げて、音階にアクセントをつける処理 // // 最後に押したスイッチが、現在のスイッチの番号より上か下かをチェックして // 音階が上がるのか、下がるのかを判断します。 // // もし、音階が上がったら、 if(lastSwitch<=i){ // 鍵盤スイッチの状態Aが「0」のとき(鍵盤スイッチが押されてない状態から鍵盤スイッチを押したとき) if(switchStatus_A[i]==0){ // DCモーターの回転速度を上げ、アクセントをつける時間カウント変数「ccnt」を50にする ccnt=50; // DCモーターの回転速度の変数に、「音階用の数値+20」を設定し、回転速度を一瞬だけ上げる(音階が上がるときにメリハリ) ppwm=Freq[i]+20; // DCモーターの回転速度は「0~255」なので、+20して255を超えた時は255にする if(ppwm>255) ppwm=255; // DCモーターの回転速度を反映させる rotateMotor(ppwm); // 鍵盤スイッチを押しっぱなしにしているときは、音階にアクセントをつけないようにするため // 鍵盤スイッチの状態を「1」としておく switchStatus_A[i]=1; } // 鍵盤スイッチの状態Aが「1」のとき(鍵盤スイッチが押されたままのとき) else if(switchStatus_A[i]==1){ // DCモーターの回転速度を上げておく時間をカウントダウン ccnt--; // カウントダウンして0になったら if(ccnt==0){ // カウントダウン変数ccntを20にして ccnt=20; // DCモーター回転速度を音階用の数値に設定 ppwm=Freq[i]; // DCモーターの回転速度を反映させる rotateMotor(ppwm); // 鍵盤スイッチを離したときに余韻を残すための時間カウント変数「ncnt」を200にする ncnt=200; } } } // もし、鍵盤スイッチを押したときに、前の鍵盤スイッチより音階が下がっていたら else{ // 鍵盤スイッチの状態Bが「0」のとき(鍵盤スイッチが押されてない状態からスイッチを押したとき) if(switchStatus_B[i]==0){ // DCモーターの回転速度にブレーキをかけて、回転速度を素早く落とす(音階が下がるときのメリハリ) brakeMotor(); // ブレーキの時間カウント「ccnt」を50にする ccnt=50; // 鍵盤スイッチを押し続けているときは、音階にアクセントをつけないようにするため // 鍵盤スイッチの状態Bを「1」としておく switchStatus_B[i]=1; } // もし、鍵盤スイッチの状態Bが「1」のとき(DCモーターにブレーキをかけ強制停止) else if(switchStatus_B[i]==1){ // DCモーターにブレーキをかけておく時間をカウントダウン ccnt--; // カウントダウンして0になったら if(ccnt==0){ // カウントダウン変数を200にして、DCモーターが空回りする時間を200にする ccnt=200; // DCモーターの回転速度を0に(速度がない状態) ppwm=0; // DCモーターの空回りさせストップ stopMotor(); // 鍵盤スイッチの状態Bを「2」にする switchStatus_B[i]=2; } } // もし、鍵盤スイッチの状態Bが「2」のとき(DCモーターを空回りさせる) else if(switchStatus_B[i]==2){ // DCモーターを空回りさせておく時間をカウントダウン ccnt--; // カウントダウンして0になったら if(ccnt==0){ // カウントダウン変数ccntを20にして ccnt=20; // DCモーター回転速度を音階用の数値に設定 ppwm=Freq[i]; // DCモーターの回転速度を反映させる rotateMotor(ppwm); // 鍵盤スイッチを離したときに余韻を残すための時間カウント変数「ncnt」を200にする ncnt=200; } } // 最後に押した鍵盤スイッチの番号を「lastSwitch」に記憶しておく lastSwitch=i; } } } // 鍵盤スイッチが押されていないとき // 1ミリ秒待つ(1/1000秒) delay(1); // 時間カウント変数をカウントダウン ccnt--; // カウントダウンして0になったら if(ccnt==0){ // 余韻の時間カウント変数をカウントダウン ncnt--; // 余韻をカウントダウンして0になったら if(ncnt==0){ // 最後に押した鍵盤スイッチをクリア lastSwitch=0; // DCモーターにブレーキをかけて強制停止 brakeMotor(); // 余韻の時間を「1」にする(次は−1されて必ず「ncnt==0」になるように) ncnt=1; } // 余韻が残っているとき else{ for(int i=0; i<24; i++) { // 鍵盤スイッチが押されていないなら if(switchValue[i]==0){ // 鍵盤スイッチの状態A、鍵盤スイッチの状態Bをクリア switchStatus_A[i]=0; switchStatus_B[i]=0; } } // DCモーターを空回りさせる stopMotor(); } // 時間カウント変数を「1」にする(次は−1されて必ず「ccnt==0」になるように) ccnt=1; } // 時間カウント変数「ccnt」が0でないとき else{ // DCモーターに回転速度を反映させ回転させる rotateMotor(ppwm); } } // アナログマルチプレクサのスキャン ---------------------------------// // 24個の鍵盤スイッチをチェックし、switchValue[]に格納 void scanMUX(){ // 全部で3つのアナログマルチプレクサを使っています // 1つのアナログマルチプレクサに8個の鍵盤スイッチがついているので // その8個の鍵盤スイッチを順番にチェック scanCount++; // 8個のチェックが終わったら if(scanCount>=8){ // スキャンカウントをクリア scanCount=0; // 次のアナログマルチプレクサに切り替える mux_num++; // アナログマルチプレクサは3つ使っているので、アナログマルチプレクサ切り替え変数「mux_num」は、0~1~2と切り替える // アナログマルチプレクサ切り替え変数が3以上になったら、0にする if(mux_num>=3) mux_num=0; } // アナログマルチプレクサから読み取る鍵盤スイッチの切り替え digitalWrite(MUX_A, (muxInput[scanCount]) & 1); digitalWrite(MUX_B, (muxInput[scanCount]>>1) & 1); digitalWrite(MUX_C, (muxInput[scanCount]>>2) & 1); switch(mux_num){ // もし、アナログマルチプレクサ切り替え変数「mux_num」が0のとき(1つ目のアナログマルチプレクサの場合) case 0: // MUX_1のピンからアナログ値を読み取って、switchValue[]の0~7番目に格納しておく switchValue[scanCount] = analogRead(MUX_1); break; case 1: // MUX_2のピンからアナログ値を読み取って、switchValue[]の8~15番目に格納しておく switchValue[scanCount+8] = analogRead(MUX_2); break; case 2: // MUX_3のピンからアナログ値を読み取って、switchValue[]の16~23番目に格納しておく switchValue[scanCount+16] = analogRead(MUX_3); break; } } // DCモーターの制御 ---------------------------------// // DCモーターの空回り(電気が流れないようにしたストップ) void stopMotor(){ digitalWrite(IN1_A, LOW); digitalWrite(IN1_B,LOW); digitalWrite(IN2_A, LOW); analogWrite(IN2_B, 0); } // DCモーターのブレーキ(電気を流してモーターの回転を強制停止) void brakeMotor(){ digitalWrite(IN1_A, LOW); digitalWrite(IN1_B,HIGH); digitalWrite(IN2_A, LOW); analogWrite(IN2_B, 255); } // DCモーターの回転(回転速度を設定して回転) void rotateMotor(int pwm){ digitalWrite(IN1_A, HIGH); analogWrite(IN1_B, 0); digitalWrite(IN2_A, 0); analogWrite(IN2_B, pwm); }