質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

4回答

710閲覧

3つある波形をプログラムで表したい。

DMR

総合スコア6

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2020/09/03 13:16

編集2020/09/10 16:03

イメージ説明イメージ説明イメージ説明

扇風機には三枚の羽根が付いています。羽根にはそれぞれ金属板が貼ってあり、1の羽根に識別のために異形形態にしています。
波形を見るセンサーは扇風機の真上0度の位置に取り付けています。回転スピードは一定していません。(リズムボタンがあり、早くなったり遅くなったりです)。LEDの点灯順番は1,3,2,1,3,2・・・・です。
例えは1の波形がオフになった瞬間2の羽根が280度の位置に来るのでこの場合点灯しません、2の羽根がオフになった瞬間3の羽根が280度の位置に来るのでLEDをON,300度の位置でOFFします。これをプログラムで書けないかと思っています。よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

thkana

2020/09/03 22:29

タグにはArduinoとありますが、Arduinoにも各種あります。何を想定しているかを明示してください。 > 2,3の波形も表せる どうなったら「波形を表せた」ことになるのでしょう? 図だけでなく、それぞれのパルスのバルス幅や間隙の最大値/最小値なども、暫定でもいいのでわかっていることは質問に記してください。 横軸に数字が入っていないのですが、0.001msの間に起こることなのか100msの間に起こることなのかによって、手抜き?で解決できるのかちゃんと考えなきゃいけないのかが変わってきます。
ozwk

2020/09/04 04:56

場合によってはもっと話が簡単になるかもしれないので そもそも何をしようとしているのか教えて下さい
DMR

2020/09/04 07:56

私が作っているのは、扇風機に3枚の羽根が付いています。羽根は120度間隔で取り付けられています。羽根にはパルスが取れるように金属板を取り付けています。1の羽根には識別のために異形の金属板にしています。扇風機の裏にセンサーを取り付けてこのパルスを読めるようにしているので、画像のような波形になっています。扇風機の回転スピードは可変で最大6500回転/分です。6500回転で回っているとすると1回転するのに9msで回ることになると思います。 私が考えているのは、例えば1の羽根が90度の位置に来た時にLEDを点灯させるという感じのプログラムを作りたいのです。先生このようなプログラムつくれますか?
DMR

2020/09/04 07:57

今持っているのはArduino レオナルドです。
nac_tnk

2020/09/04 08:49

あぁ、読み取りの方だったのね。 90°とは何を原点として90度なの?そして消灯のタイミングは? そして実際のパルス幅は?(大まかでいい) 金属版を点灯のタイミングの所に1つだけ取り付ければ簡単なんだけど。
DMR

2020/09/04 13:06

そうです読み取りの方です。原点は時計の12時の位置で、この位置にセンサーを取り付けています。角度は特に限定していません。任意に変更できるようにしたいのです。パルス幅はmillis関数でだめですかね?消灯のタイミングはパルス幅の真ん中に来た時です。1の羽根が分かったら、例えば3の羽根が270度の位置に来た時にLEDを点灯とかできると思うので。よろしくお願いいたします。
nac_tnk

2020/09/04 18:47

基本的には、4つのパルス幅を測ればそれがどの位置なのかは判断付きます。 それと周期を測定したら済む事だと思います。 millisでは正確性に欠けるでしょうね。使うならmicrosでしょう。 ここでメモリをケチってもしょうがない気がします。 バーサライタの予備テストでもしているのでしょうか?
thkana

2020/09/05 02:21

> 角度は特に限定していません。 何の角度ですか? 主語を略されるとわかりません。直前の文は「原点」あるいは「センサー」が主題でしたが、原点は原点で動きませんし、センサーは既に原点に取り付けられています。 > 任意に変更できるようにしたいのです。 同様に、変更する要素は何ですか? > 消灯のタイミングはパルス幅の真ん中に来た時です。 どのパルスですか? 一周に一回、Z相だけセンスして、その周期から角度を求めて制御すればよいものを3枚の羽根それぞれをセンサーに反応させるようにしたが故に話が面倒になっている気がします。 それぞれの羽根につけるにしても、切り欠きができるくらいなら、パルスの立ち下がりが羽根の真ん中の位置になるようにすることもできるはずですね? そうすれば、「羽根の真ん中」を調べる必要もなくパルスの立ち下がりで制御すればいいだけ。 あちこちで「わざわざ話を面倒にしている」気がして仕方ありません。機構上出来ない、というのなら仕方ありませんが、どうなんでしょう。
thkana

2020/09/10 12:55

3つ検出部がある理由はまぁわかりましたが。 > LEDの点灯順番は1,3,2,1,3,2・・・・です。 別に1の位置を識別しなくても、センサ1回おきにLEDを点灯すればいいだけなのではないですか? 1を知らなきゃいけない理由はなんでしょう? > 1の波形がオフになった瞬間2の羽根が280度の位置に来るのでこの場合点灯しません、 > 2の羽根がオフになった瞬間3の羽根が280度の位置に来るのでLEDをON 「ので」というのはLEDを点灯したりしなかったりする理由を表しているはずですよね? この2つの文で、LEDをONとOFFをわける条件が全く見えないのですが? 点灯/消灯の角度は任意ではなかったのでしたっけ? 変動させたいパラメータはわかるように図に書き込んでいただけませんか。
DMR

2020/09/10 15:59

1の位置を識別しているのはLEDの色を分けたいからです。1は赤、2は青、3は緑です。LEDを点灯する順番は、私がそうしたいからだけなんです。 LEDをoffするタイミングの式と変数T1を図に入れておいたので見てくれますか。
guest

回答4

0

第二次大戦ぐらいの戦闘機が、プロペラの回転の隙間を縫って機関銃を撃った、なんていう話を思い出したり。もちろん当時はマイコンなんかないから全部機械仕掛けでしょうけど。

センサはちゃんと出来ているのなら、パルスの立ち上がり立ち下がりでタイマをキャプチャして、その値をみて判断すればよいのでは。

最初は回転数とか知りませんから、立ち上がり-立ち下がりの間隔を4回測定します。
そのパルス幅を見れば1の羽根を判別できるでしょう。残りの羽根のパルス幅もわかります。次の周で、短いパルス幅を検出したらLEDを点灯して、先の測定で残りの羽根のパルス幅の半分でタイマとのコンペアかなにかで割り込ませてLEDを消灯すれば。もちろん、この間も「次の周」に備えて各パルス幅は測り続けます。

あるいはタイマ使わなくてフリーランのループでも測れるかなぁ? その切れ込みパルスは一周に対してどういう比率になるのでしょう?


(追記)質問と条件が変わってしまいますが、センサーは羽根1枚だけを、切込み無しで検出するという前提で簡易的(=タイマ使わなくてフリーランのループ)なプログラムを試してみました。それでこれだけ出来るのですが、これじゃダメなんですか?

おおよそ9ms毎に1msのパルスを作って、以下のプログラムに突っ込んでみました。Arduino UNOなので16MHzのAVR 328Pです。

Arduino

1void setup() { 2 pinMode(2, INPUT); 3 pinMode(13, OUTPUT); 4 Serial.begin(115200); 5} 6const unsigned int LED_ON_PHASE = 0; 7const unsigned int LED_OFF_PHASE = 180; 8unsigned int count; 9unsigned int totalCount; 10unsigned int dummy1, dummy2; 11 12int lastStat; 13 14void loop() { 15 int stat = digitalRead(2); 16 if (!stat) { 17 if (lastStat) { 18 totalCount = count; 19 count = 0; 20 // Serial.println(totalCount); 21 } else { 22 dummy1 = count;//プログラムの経路によって実行時間が変わるのを緩和するためのダミー 23 dummy2 = 0; 24 } 25 } else { 26 if (lastStat) { 27 dummy1 = count; 28 dummy2 = 0; 29 } else { 30 dummy1 = count; 31 dummy2 = 0; 32 } 33 } 34 int led = ((unsigned long)totalCount * LED_ON_PHASE / 360 < count) && 35 (count < (unsigned long)totalCount * LED_OFF_PHASE / 360); 36 digitalWrite(13, led); 37 count++; 38 lastStat = stat; 39}

これで、コメントしてあるSerial.printlnを活かすと183とか4とかの値になったので、タイマーを使わなくても2度分くらいのばらつきで動くことはできるようです。
(追記) 波形をみたところ、目視で100μs以下ぐらいのジッタはあるようです。要求される精度はどのくらいですか?

タイマーを使うにしても原理としては同じようにできるでしょう。精度や分解能は随分よくなる期待が持てるかと思います。

羽根3枚を検出しないといけない状況があるのでしょうか? それこそ羽根の隙間を狙わなきゃいけない、とかだと真面目に羽根を検出したほうがいいかも知れませんが。


質問情報の追記をうけての追記

例えば1の羽根が90度の位置に来た時にLEDを点灯させるという感じ

消灯のタイミングはパルス幅の真ん中に来た時です

とか、「どこにいっちゃったんだぁ?」と思いますけれど。

回転スピードは一定していません。

とかのびっくりネタはもう隠していませんか?
10倍のダイナミックレンジってのは結構インパクトありますよ。最初に「どのくらいの時間をみているのか」と聞きましたよね? なぜかというと、それが設計の基本的なところで押さえるべきパラメータだからです。そこを、最初に言った9msから平気で120msまでしかも可変で引っ張る、なんていうのは、「バカにしている」と怒られても文句は言えないレベルです(怒らないけど思ってます)。

完成寸前まで作っちゃったんで載せときます。nac_tnkさんのタイマー版をベースにしてます。1度単位での制御はソフトループだと苦しいので。
制約として、①の前半と後半の立ち上がり間隔が、①の後半の立ち上がりと②の立ち上がりの間隔より短い必要があります(パルス全体の幅と切れ込みの入れ方によってはその関係は崩れます)。「一番短い立ち上がり間隔」を①の検出の要件としましたので。図が現物通りなら特に問題ないでしょう。
あまり明確にかかれていませんが、LEDの点灯開始は各パルスの立ち上がりと勝手に解釈しました。

LED制御ぐらいは自分でやって下さい。そもそもの質問の「①を知る」ことはこれでできているはずなので。

Arduino

1#include <limits.h> 2const int LEDPORT[] = {11, 12, 13}; 3const int TM_STOP = 0; 4const int TM_RUN = 0b11; 5 6volatile bool roundComp; 7 8void pulse_read() { 9 //立ち上がり位置の記録。 10 unsigned int edge = TCNT1;//即座にタイマー値を取得することでばらつきを防ぐ 11 12 static unsigned int lastEdge;//前回の立ち上がり位置 13 static unsigned int width[4];//各パルスの幅を保存 14 static int cnt = 0;//パルスのインデックス 15 16 if (cnt == 3 ) { 17 //タイマー操作を優先するため同条件のif文が分かれている 18 TCCR1B = TM_STOP; //数μs狂うかも知れないけど、安全なタイマーカウンタ操作のため止める 19 if (OCR1A > TCNT1) { //未実行のコンペアがあったら移行する 20 OCR1A -= TCNT1; 21 } 22 TCNT1 = 0; //タイマーカウンタをリセット 23 TCCR1B = TM_RUN; 24 } 25 26 //バルス立ち上がりの間隔を求める 27 width[(cnt + 3) % 4] = edge - lastEdge; 28 if ( cnt == 3 ) { 29 roundComp = true;//一周データ取り終わったことを記録 30 edge = 0; 31 } 32 lastEdge = edge; 33 34 // いちばん幅が狭いところつまり1のパルスの検出。 35 unsigned int wMin = width[0]; 36 int firstEdge = 0; 37 for (int i = 1; i < 4; i++) { 38 if (width[i] < wMin) { 39 wMin = width[i]; 40 firstEdge = i; 41 } 42 } 43 44 //一周分のデータが揃っているならLED処理 45 if (roundComp ) { 46 // 直前での120度分の回転時間 47 int w_3 = width[(cnt + 3) % 4]; 48 //1のパルスが割れている分の補正 49 if (cnt == (firstEdge + 2) % 4) { 50 w_3 += width[firstEdge]; 51 } 52 53 if (cnt == firstEdge) {//1のセンサが発報 54 OCR1A = edge + w_3 * 40l / 120; //例として40度回る時間後タイマーで消灯 55 //計算途中でのオーバーフローを防ぐため一部をlong型にしている 56 digitalWrite(LEDPORT[0], HIGH);//センサが発報したら点灯 57 } 58 if (cnt == (firstEdge + 2) % 4 ) { //2のセンサが発報 59 OCR1A = edge + w_3 * 20l / 120; //20度 60 digitalWrite(LEDPORT[1], HIGH);//センサが発報したら点灯 61 } 62 if (cnt == (firstEdge + 3) % 4 ) { //3のセンサが発報 63 OCR1A = edge + w_3 * 60l / 120; //60度 64 digitalWrite(LEDPORT[2], HIGH);//センサが発報したら点灯 65 } 66 } 67 68 cnt=(cnt+1)%4;//立ち上がり取得カウンタを進めておく 69} 70 71ISR (TIMER1_OVF_vect) {//低速、停止時に0にする為 72 roundComp = 0; 73} 74 75ISR (TIMER1_COMPA_vect) {//OCRA一致割り込みでLED OFF 76 //面倒なので全部OFF 77 for ( auto l : LEDPORT) { 78 digitalWrite(l, 0); 79 } 80} 81 82void setup() { 83 Serial.begin(115200) ; 84 for ( auto l : LEDPORT) { 85 pinMode(l, OUTPUT); 86 } 87 TCCR1A = 0; 88 TCCR1B = TM_RUN; //1/64=4us/countでタイマー1を回す 89 OCR1A = 0; 90 OCR1B = 0; 91 TIMSK1 = 0b11; //必要な割り込みON 92 attachInterrupt(0, pulse_read, RISING);//センサーD2ピン 93} 94 95void loop() { 96}

実行結果

投稿2020/09/04 13:57

編集2020/09/12 22:56
thkana

総合スコア7703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DMR

2020/09/05 06:32

すごいですね!もうできたんですね。なんとなく分かるんですが、void loop辺りからチンプンカンプンです。頑張ってるつもりなんですが女子には無理なんですかね。 出来ましたらプラグラムを詳しく説明していただければ助かります。
thkana

2020/09/05 23:20

重要事項を書いてなかったですね。これは、センサーは羽根1枚だけを、切込み無しで検出するという前提です。それでこれだけ出来るのですが、これじゃダメなんですか? という話。 statとlaststatの関係からセンサー出力のエッジを検出しています。 立ち下がりエッジ(今回センサOFF、前回ONだった)を起点としています。一周分のループ回数totalCount(=時間)を測っているので、角度とループ回数の対応づけが出来ます。指定の角度の範囲内であれば、LEDを点灯します。 わからないところがあるならそれを聞いてください。 それと。ジェンダーどうこういうのも面倒ですが、女子関係ありません。
DMR

2020/09/07 06:42

分かりました。有難うございます。頑張ります。 ここの意味が分からないのですが、初心者がわかるようにお願いします。 if (!stat) { if (lastStat) { totalCount = count; count = 0; // Serial.println(totalCount); } else { dummy1 = count;//プログラムの経路によって実行時間が変わるのを緩和するためのダミー dummy2 = 0; } } else { if (lastStat) { dummy1 = count; dummy2 = 0; } else { dummy1 = count; dummy2 = 0; } }
thkana

2020/09/07 12:19

if (!stat) { if (lastStat) { statは今回のD2を読み取った値、lastStatは前回。つまり前回Hで今回Lだったのだから立ち下がりエッジだったとき。 totalCount = count; count = 0; 前回の立ち下がりエッジから一周回ったということだから、そのときのカウント値を覚えて、カウンタはクリアしましょう。 あとは、コメントの通り、ダミーです。必要かというと無くてもいいけど、条件によって1回分の実行時間があまり変わらないように、ということ。 で、これじゃダメなんですか?、というところはどうなんでしょう。ダメだというなら3(4)パルスを真正直に処理することになりますが。 (手元ではそれなりに出来てるけど、追記修正依頼のところの条件とかはっきりしてくれないから詰められない)
DMR

2020/09/07 15:34

やっぱりここの解説もお願いします。わからなくなってきました。 int led = ((unsigned long)totalCount * LED_ON_PHASE / 360 < count) && (count < (unsigned long)totalCount * LED_OFF_PHASE / 360); digitalWrite(13, led); count++; lastStat = stat;
thkana

2020/09/07 22:40 編集

totalCount * LED_ON_PHASE / 360 は、ONする角度に対するカウント値を求めていて(OFFも同様) ただし計算中にint/unsigned intの範囲を超えて結果がぐちゃぐちゃになるのを避けるため大きな型にキャストしています。 countは現在のカウント値だから、 ONするカウント値< 現在のカウント値 < OFFするカウント値、つまり今回ONすべきかOFFすべきかを調べています。 C/C++(そしてC++をベースとするArduino言語)では、<,>,==とかの比較の演算子、また&&や||の論理演算子は真なら1、偽なら0の整数値を返す演算子ですから、条件が成り立っていれば1、成り立っていなければ0が変数ledに設定されることになります。その値でLEDを点灯あるいは消灯し count++でループ実行回数を数え、 lastStat = stat; 現在のD2入力値を次回でのエッジ判定用に保存します。 (こちらの疑問には応えるつもりはない、ということかしら?)
DMR

2020/09/10 05:08

すみません。thkaneさんの疑問に応えよう思いながらプログラムを見ていたらそっちに頭がいっぱいになり、応えられない状態になってました。 最初から整理したので一番最初の追記、修正のところ見てもらえますか。
DMR

2020/09/12 13:36

thkanaさん怒らないでくださいよ。7月ごろからArduinoを始めたんですがプログラムの意味が全然わからなくで頭の中がへんになってるんです。他の言語も知らないので余計です。このプラグラムを理解できるように頑張ってみます。また分からないところがたくさんあると思うのでその時はよろしくお願いします。
thkana

2020/09/13 01:18

> プログラムの意味が全然わからなくで プログラムは、コンピュータになにかをやらせるための指示です。 コンピュータは、プログラムに書いてある通りに動くだけの機械に過ぎません。 今回問題になったのは、プログラム以前の話。「なにをやらせるのか」が明確になっていなかったこと、それを明確にしようと問いかけたら、無視したりコロコロと言う事が変わったり、大事なことが最後の最後で出てきたりしたこと。 なにをやらせるかわからないのに指示(プログラム)なんて出来るわけありませんし、やることが変わってしまったらプログラムは違ったものになり、程度によっては今まで考えたことは全く無駄になるかも知れません。 プログラムを考えるためには、「なにをやらせるのか」が決まっている必要があります。もちろん、ある程度作ってみて実験的に決めなければならない要素もあるでしょう。それでも、わかっている部分からプログラムの多くが決定され、未定なものが未定であることは明示できて、あり得る変化の範囲を想定して対応することも出来るでしょう。 もう一つ、これはプログラムとは全く関係ないことですが...(つまりプログラミングの初心者であることは関係ない) 回答者は、あなたの知っている/当然であると思っていることを、あなたがここに書かない限り知らない、ということを意識してください。 学校で勉強を教わっていてわからない問題があったのなら、先生もクラスメートも同じ問題を共有していますから「昨日の授業でやった例題3-2」で全て話は通じるでしょう。塾に行っても、生徒の学年や勉強範囲を知っているわけでその前提のもとで教えてくれるでしょう。 しかし、ここでの回答者は、あなたのことを「何も」知りません。あなたのスキルも、やろうとしていることも。 あなたが扇風機のそれぞれの羽根の位置でLEDを点灯しようとしている、などということは知らないわけで、そこに「3つのパルスの一つを識別したい」というだけの質問を持ち込んだら「最初からパルスを一つにしとけばいい」なんていう(あなたにとっては)的はずれな回答になるのもやむなしでは。 そういう意味で、ここでの質問は学校で先生や友人に聞くのとは異なります。わからないところ「だけ」書いても理解されません。背景や必要な要素、求めるものはちゃんと質問に書いてください。回答側が記述が足りないと思えば追記・修正依頼に書くでしょうから、それに対応してください。
guest

0

<入力の問題だったようなので、全面的に書き換えます。>

基本的に、「簡単」とは言わないけど、1つずつ必要な処理を書いていけば出来る事だと思います。
ただし、目的がLED1個を角度○~△の間だけ点灯なら、何も考えずに書いていけばいい事ですけど、
目的によってはそうはいきません。バーサライタなんかだとほぼ裏方です。
つまり、loop関数は表示(LED操作)の為に残して、外部割り込みやタイマーを使って、現在の角度を取得できるように構成させる必要?というか、そうした方がやり易かったりします。
単にint degree_get()のような関数を作って、現在の角度を取得するように構成させます。

※thkanaさんのスケッチへのレスを見る限り、そのスケッチに付け足して何かを作るのはまだ無理のように感じました。

出来るだけ簡単に角度を取得できる工夫も必要です。角度の取得に時間がかかっていれば表示はその影響を受けます。
この程度の事は数us程度の誤差(遅れ/作業時間)で済ませたい所です。

簡単に言えば、まずやりたい事全体で考える事です。そして、どのようにするのが良いシステムになるのか
(どのように無駄のないものにするか)、を考えてください。

羽根(パルス)の数も、4(3)つあれば、それだけ識別に手間取りますし、間違いも起こります。
これは1つにすべきです。

↓は、やはり羽根1つでのサンプルです。degree_get()をすればその時の角度(degree)*100で取得します。
後はセンサーの設置位置に合わせて適当にオフセットを付ければ良いです。
ループ関数は何もしていない(↓はテスト用の表示が入っている)ので、自由に使えます。

Arduino

1volatile word period; 2 3void pulse_read() { 4 period=TCNT1; 5 TCNT1=0; 6} 7 8ISR (TIMER1_OVF_vect) {//低速、停止時に0にする為 9 period=0; 10} 11 12word degree_get() {//角度*100を返す 13 if(period==0)return 0; 14 return 36000UL*TCNT1/period; 15} 16 17void setup() { 18 Serial.begin(9600) ; 19 TCCR1A=0; 20 TCCR1B=2; //1/8=0.5us/countでタイマー1を回す 21 TIMSK1=1;//無回転等の判別用。まぁ無くてもOK 22 attachInterrupt(0, pulse_read, RISING);//センサーD2ピン 23 tone(4,125);//8ms ※テスト信号。これをD2に入れる 24} 25 26void loop() { 27 Serial.print(period); 28 Serial.print(" "); 29 Serial.println(degree_get()); 30 31 delay(300); 32}

プログラム的には超簡単です。(レジスタ操作は別として)
解説すれば、外部割り込みで、パルスの上昇で割り込み(pulse_read関数)をかけています。(原点)
また、タイマー1(TCNT1)をストップウォッチのように使っています。
割り込み時にタイマ値を読み取りリセットします。そのタイマー値は回転周期(period)です。
degree_get関数は回転周期と現在のタイマ値から割合を出し、36000をかけて戻しています。

※実際にはtoneやSerialは消してください。

投稿2020/09/04 04:50

編集2020/09/06 02:02
nac_tnk

総合スコア494

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

DMR

2020/09/06 16:34

すいません。もう少しこのあたり詳しい解説が欲しいです。 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; } よろしくお願いいたします。
nac_tnk

2020/09/06 17:52

> volatile word period; 周期です。割り込みで使う外部変数はvolatileを付けます。単位は0.5usです。 > void pulse_read() { > period=TCNT1; > TCNT1=0; > } これは、ピンがLOW→HIGHになった瞬間に実行される(外部割り込み)関数です。 羽根が1枚なら、ストップウォッチで毎回計測すれば周期が判ります。 なので、新たな周期を記録して、リセット0しています。 > ISR (TIMER1_OVF_vect) {//低速、停止時に0にする為 > period=0; > } タイマー1溢れ割り込みです。16bitタイマーなので、計測できるのは0.5*65536=32768usまでです。 回転速度で言えば1830RPS以下の速度で回すなら分周を変える必要があります。 で、この割り込みに来たという事は低速すぎて35536カウントした事になりますから、本来は分周を上げる 方が適切かもしれません。今回は「低速エラー」として、periodを0にしています。 ※停止した場合は周期の取得は出来ません。中途半端な値で止まります。それが嫌なので識別させときます。 > word degree_get() {//角度*100を返す > if(period==0)return 0; > return 36000UL*TCNT1/period; > } 利用しやすい形で関数を作ります。エラーをして、0を返していますけど、適切では無かったです。 ※0度の時も0を返すので区別がつかない。0xFFFFあたりの方が良いですね。 で、勿論360UL*TCNT1/periodとして、0~359(或いは360や361等も返す可能性はあります)でも良いですけど、 扇風機という事なら面積も広いのでそれに100を掛けました。 原点調整の為にここで return 36000UL*TCNT1/period+offset; としても良いです。
thkana

2020/09/12 09:59

タイマー周り、お借りしました。
guest

0

私ならセンサーを2つつけて羽1だけ両方のセンサーが反応するように金属板を取り付けます。

投稿2020/09/04 08:03

編集2020/09/04 08:03
ozwk

総合スコア13553

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

タイマ割り込みでタイマカウンタを操作していけば図のような波形も生成可能です
一番幅が狭いところで、Arduino程度のCPUでは、数百μs程度が限界ですが

投稿2020/09/03 13:19

y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問