質問: ![![イメージ説明](https://teratail-v2.storage.googleapis.com/uploads/contributed_images/ee1b8cdd4b0ed42d780fb4c9b96a56e7.jpeg)](87314f8c4bbb0c88d452a85d826a93c0.jpeg)![イメージ説明](https://teratail-v2.storage.googleapis.com/uploads/contributed_images/7cf9ddf2325e5fb14b664ce84becfb11.jpeg)![イメージ説明](https://teratail-v2.storage.googleapis.com/uploads/contributed_images/89d9a49b9e18a3219018dce9309aaa2b.jpeg) 扇風機には三枚の羽根が付いています。羽根にはそれぞれ金属板が貼ってあり、1の羽根に識別のために異形形態にしています。 波形を見るセンサーは扇風機の真上0度の位置に取り付けています。回転スピードは一定していません。(リズムボタンがあり、早くなったり遅くなったりです)。LEDの点灯順番は1,3,2,1,3,2・・・・です。 例えは1の波形がオフになった瞬間2の羽根が280度の位置に来るのでこの場合点灯しません、2の羽根がオフになった瞬間3の羽根が280度の位置に来るのでLEDをON,300度の位置でOFFします。これをプログラムで書けないかと思っています。よろしくお願いします。
回答: <入力の問題だったようなので、全面的に書き換えます。> 基本的に、「簡単」とは言わないけど、1つずつ必要な処理を書いていけば出来る事だと思います。 ただし、目的がLED1個を角度○~△の間だけ点灯なら、何も考えずに書いていけばいい事ですけど、 目的によってはそうはいきません。バーサライタなんかだとほぼ裏方です。 つまり、loop関数は表示(LED操作)の為に残して、外部割り込みやタイマーを使って、現在の角度を取得できるように構成させる必要?というか、そうした方がやり易かったりします。 単にint degree_get()のような関数を作って、現在の角度を取得するように構成させます。 ※thkanaさんのスケッチへのレスを見る限り、そのスケッチに付け足して何かを作るのはまだ無理のように感じました。 出来るだけ簡単に角度を取得できる工夫も必要です。角度の取得に時間がかかっていれば表示はその影響を受けます。 この程度の事は数us程度の誤差(遅れ/作業時間)で済ませたい所です。 簡単に言えば、まずやりたい事全体で考える事です。そして、どのようにするのが良いシステムになるのか (どのように無駄のないものにするか)、を考えてください。 羽根(パルス)の数も、4(3)つあれば、それだけ識別に手間取りますし、間違いも起こります。 これは1つにすべきです。 ↓は、やはり羽根1つでのサンプルです。degree_get()をすればその時の角度(degree)*100で取得します。 後はセンサーの設置位置に合わせて適当にオフセットを付ければ良いです。 ループ関数は何もしていない(↓はテスト用の表示が入っている)ので、自由に使えます。 ``` volatile word period; void pulse_read() { period=TCNT1; TCNT1=0; } ISR (TIMER1_OVF_vect) {//低速、停止時に0にする為 period=0; } word degree_get() {//角度*100を返す if(period==0)return 0; return 36000UL*TCNT1/period; } void setup() { Serial.begin(9600) ; TCCR1A=0; TCCR1B=2; //1/8=0.5us/countでタイマー1を回す TIMSK1=1;//無回転等の判別用。まぁ無くてもOK attachInterrupt(0, pulse_read, RISING);//センサーD2ピン tone(4,125);//8ms ※テスト信号。これをD2に入れる } void loop() { Serial.print(period); Serial.print(" "); Serial.println(degree_get()); delay(300); } ``` プログラム的には超簡単です。(レジスタ操作は別として) 解説すれば、外部割り込みで、パルスの上昇で割り込み(pulse_read関数)をかけています。(原点) また、タイマー1(TCNT1)をストップウォッチのように使っています。 割り込み時にタイマ値を読み取りリセットします。そのタイマー値は回転周期(period)です。 degree_get関数は回転周期と現在のタイマ値から割合を出し、36000をかけて戻しています。 ※実際にはtoneやSerialは消してください。