//ソフトテニスマシン用プログラム(2021.10.8) //MsTimer2の割り込み使用 //Aボタン:5秒毎に連続射出 //Bボタン:10秒毎に連続射出 //Cボタン:1回だけ射出 //Dボタン:停止 //連続射出で動作中ABCどのボタンでももう一度押せば停止 //連続射出で動作中は、Cボタンは無効 //用語定義 //射出:エスケープが1回動作+モータが1回転の動作をまとめたもの //動作:ボタンが押されて一定時間毎に射出している状態 //待機:ただ電源が入っているだけの状態(ボタンの押下待ち) //回転:動作時中でモータが回転している状態 //停止:動作時中でモータが停止している状態 #include #include Servo servo1; const int SW_A = 5; //リモコンスイッチA const int SW_B = 4; //リモコンスイッチB const int SW_C = 3; //リモコンスイッチC const int SW_D = 2; //リモコンスイッチD const int MOTOR = 6; //モータ制御ピン const int MOTOR_ZERO = 8; //モータの原点信号 原点にいる時にLOW const int ESCAPEMENT = 7; //エスケープメント サーボモータ const int LED = 13; //動作中を示す高輝度LED const int BALL_STOP = 85; //ボールを停める 85 const int BALL_THRU = 60; //ボールを通す 60 volatile int TIMER_FLAG = 0; //指定した時間が経過したことを示すフラグ //経過したら1になる。 //割り込み処理で使用するのでvolatile型 int sw_old = 0; //スイッチの長押し回避用変数 void setup() { servo1.attach(ESCAPEMENT); pinMode(MOTOR,OUTPUT); pinMode(SW_A,INPUT_PULLUP); pinMode(SW_B,INPUT_PULLUP); pinMode(SW_C,INPUT_PULLUP); pinMode(SW_D,INPUT_PULLUP); pinMode(MOTOR_ZERO,INPUT_PULLUP); pinMode(LED,OUTPUT); servo1.write(BALL_STOP); //エスケープメント初期位置 } //■割り込み処理 //指定時間毎にタイマーフラグを立てるだけ。 //LOOP内ではこれを監視してモータを回転させる。 //フラグのクリアはフラグを確認したところで行う。 void interrupt(){ TIMER_FLAG = 1; } void loop() { static int flag = 0; //動作状態を示すフラグ 動作状態=1、待機状態=0 int sw_data; sw_data = 0; //明示目的 if( digitalRead(SW_D) == LOW ){ sw_data = 4 ; } //各スイッチ読み込み if( digitalRead(SW_C) == LOW ){ sw_data = 3 ; } if( digitalRead(SW_B) == LOW ){ sw_data = 2 ; } if( digitalRead(SW_A) == LOW ){ sw_data = 1 ; } //SW_Aが優先順位が高い delay(50);//チャタリング回避 if( sw_data != sw_old ){ //スイッチの押し続けを回避する。 sw_old = sw_data; }else{ sw_data = 0; //sw_data=0なら何の処理もしない。 } switch( sw_data ){ case 1: //▼SW_Aが押された時の処理 if( flag == 0){ //待機状態ならば動作開始 flag = 1; //状態フラグを立て動作状態とする digitalWrite(LED,HIGH); //LED点灯 MsTimer2::set(5000, interrupt); //5秒毎に割り込み MsTimer2::start(); //割り込み開始 esc(); //1回目のボール切り出し digitalWrite(MOTOR,HIGH); //モータ回転 delay(300); //これが無いとすぐに停止状態を //検出してしまう }else{ flag = 0; //動作状態なら停止処理 digitalWrite(LED,LOW); //LED消灯 MsTimer2::stop(); //割り込み停止 TIMER_FLAG = 0; //タイマーフラグクリア } break; case 2: //▼SW_Bが押された時の処理 if( flag == 0){ //待ち時間が違う以外はcase1と同じ flag = 1; digitalWrite(LED,HIGH); MsTimer2::set(10000, interrupt); //10秒毎に割り込み MsTimer2::start(); esc(); digitalWrite(MOTOR,HIGH); delay(300); }else{ flag = 0; digitalWrite(LED,LOW); MsTimer2::stop(); TIMER_FLAG = 0; } break; case 3: //▼SW_Cが押された時の処理 //単純に1ショット //もちろん割り込みもなし //時間の確認していないので連射に注意 if( flag == 0 ){ //動作は待機状態のときだけ digitalWrite(LED,HIGH); esc(); digitalWrite(MOTOR,HIGH); delay(300); if(digitalRead(MOTOR_ZERO) == LOW){ digitalWrite(MOTOR,LOW); } digitalWrite(LED,LOW); } break; case 4: //▼SW_D押された時の処理 停止 flag = 0; MsTimer2::stop(); TIMER_FLAG = 0; digitalWrite(LED,LOW); } if((flag == 1)&&(TIMER_FLAG == 1)){ //2回目以降の打ち出し処理 //動作状態で且つタイマーフラグが //立った(一定時間経過)状態で回転 TIMER_FLAG = 0; esc(); digitalWrite(MOTOR,HIGH); delay(300); //モータが原点で止まっているので、起動後すぐに次の処理(停止確認)に移ると //原点領域を抜け出す前に停止処理に入ってしまうので原点領域を抜け出すのを //待つためのdelay } //■モータ停止 //待機時は常に MOTOR_ZERO = LOWなので、 //毎回モータ停止信号を出すことになるが問題はない。 if(digitalRead(MOTOR_ZERO) == LOW){ //モータが原点位置に来たらモータ停止 digitalWrite(MOTOR,LOW); } } //■エスケープメント動作 void esc(){ servo1.write(BALL_THRU);//ボールを通す delay(500); servo1.write(BALL_STOP);//次のボールを停める } //おしまい