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

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

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

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

Q&A

解決済

1回答

8196閲覧

Arduino DUEでエンコーダを用いてカウント

super987

総合スコア7

Arduino

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

0グッド

0クリップ

投稿2016/12/18 08:53

###前提・実現したいこと
ArduinoDUEで360P/Rのロータリーエンコーダ(E6A2-CWZ3E)を用いて+/-カウントを行っています。
エンコーダには直径46mmのタイヤをつけています。
将来的には、速度・距離を計測しようと思っています。
###発生している問題・エラーメッセージ

1mの距離をゆっくり回転させる分には安定したカウント(±5000カウント)を取っているのですが、 同じ距離で速く回転させると±1000カウントしか取れません。

###該当のソースコード

const int rot_pinA = 2;//PinA const int rot_pinB = 3;//PinB int rot_count = 0, sw=0, pt=0; void setup() { Serial.begin(9600); pinMode(rot_pinA,INPUT); pinMode(rot_pinB,INPUT); attachInterrupt(1, rotary_changedPin, CHANGE); //pinの信号変化に合わせて割り込み処理。 } void loop() { //シリアルコンソールに現在の値を出力。 Serial.println(rot_count); delayMicroseconds(1000); } //pinの割り込み処理 void rotary_changedPin() { if( (digitalRead(rot_pinA)==LOW) && (digitalRead(rot_pinB)==LOW) ) { if ( pt==2 ) { sw=1; // 正転 rot_count++; } else if ( pt==3 ) { sw=2; // 逆転 rot_count--; } pt=1; } if ( (digitalRead(rot_pinA)==LOW) && (digitalRead(rot_pinB)==HIGH) ) { if ( pt==4 ) { sw=1; // 正転 rot_count++; } else if ( pt==1 ) { sw=2; // 逆転 rot_count--; } pt=2; } if ( (digitalRead(rot_pinA)==HIGH) && (digitalRead(rot_pinB)==HIGH) ) { if ( pt==3 ) { sw=1; // 正転 rot_count++; } else if ( pt==2 ) { sw=2; // 逆転 rot_count--; } pt=4; } }

###試したこと
ネット等で関連記事を読み、TmTimer2を用いたプログラムを作成しましたが、同じ様な問題が出ました。

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

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

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

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

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

MasahikoHirata

2016/12/18 08:57

これ、タイマー割り込みではなくて、エンコーダーからの信号で割り込みすべきでは?
MasahikoHirata

2016/12/18 09:17

ソースを見ると1つのピンの割り込みですね。
MasahikoHirata

2016/12/18 10:21

arduinoにARMが有るのが再確認でき、参考に成りました。arduino互換でARMとなると秋月のhttp://akizukidenshi.com/catalog/g/gM-10175/ とかが安価でARMの環境が使えたので。
guest

回答1

0

ベストアンサー

arduino DUEは全てのデジタルピンで割り込みが可能なので、質問中の’タイマー割り込み’ではなく、エンコーダの信号のA相、B相がソース上のPIN A及びPIN Bと仮定して、回答致します。
また割り込みの定義ではCHANGEになっていますが、立ち上がり、立下り、変化が割り込みの起因になりますが、ソースの通りCHANGEとします。
その前に注意点ですが、OMRONのこの型番のエンコーダーは動作電圧が5V。しかしDUEでは3.3Vです。これもレベル変換回路が有るものと仮定します。
ソース上割り込みは起因が'1'ですのでpin1?と思いますが、割り込みは変化するA相、B相ですから、これらの割り込みを受け取り、またどのように変化したか?で判断します。
その為にはソースの中ではptで状態遷移を見ていると思いますが、確度を上げるには前の値とするべきでは?
よってA相のPin AとB相のPin Bの前回値(初期状態では読み込み値)を保持すべきでしょう。
それと一周を判断するZ相は参照の範囲ではないと仮定します。

これらの仮定から机上ですが、サンプルソースは以下のようになると考えます。

arduino

1#define rot_pinA 2 2#define rot pinB 3 3 4long rot_count = 0; // 一周を300countとして状態が4ステップなので1200ステップに拡張。 5int direction = 0; 6int parse; 7 8void setup() 9{ 10 int current_a; 11 int current_b; 12 13 Serial.begin(9600); 14 pinMode(pinA,INPUT); 15 pinMode(pinB,INPUT); 16 17 current_a = digitalRead(pinA); 18 current_b = digitalRead(pinB); 19 20 if(( current_a == 0 ) && ( current_b == 0 )) // A,Bとも0 21 { 22 parse = 0; 23 } 24 if(( current_a == 1 ) && ( current_b == 0 )) // A=1 B = 0 CCW 25 { 26 parse = 1; 27 } 28 if(( current_a == 1 ) && ( current_b == 1 )) // A,Bとも0 29 { 30 parse = 2; 31 } 32 if(( current_a == 0 ) && ( current_b == 1 )) // A,Bとも0 33 { 34 parse = 3; 35 } 36 37 attachInterrupt(pinA,rotary_changedPin,CHANGE); 38 attachInterrupt(pinB,rotary_changedPin,CHANGE); 39} 40 41void loop() 42{ 43 //シリアルコンソールに現在の値を出力。 44 Serial.println(rot_count); 45 delayMicroseconds(1000); 46} 47 48//pinの割り込み処理 49void rotary_changedPin() 50{ 51 int now_a; 52 int now_b; 53 now_a = digitalRead(pinA); 54 now_b = digitalRead(pinB); 55 56 if( parse == 0 ) 57 { 58 if(( now_a == 1 ) && (now_b == 0 )) // reverse=CCW 59 { 60 rot_count--; 61 direction = 0; //CCW 62 parse = 3; 63 return; 64 } else if (( now_a == 0 ) && ( now_b == 1)) //foward = CW 65 { 66 rot_count++; 67 direction = 1; //CW 68 parse = 1; 69 return; 70 } else { 71 // fatal error 72 } 73 } 74 if( parse == 1 ) 75 { 76 if(( now_a == 0 ) && (now_b == 0 )) // reverse = CCW 77 { 78 rot_count--; 79 direction= 0; //CCW 80 parse = 3; 81 return; 82 } else if (( now_a == 1 ) && ( now_b == 1)) //foward = CW 83 { 84 rot_count++; 85 direction = 1; // CW 86 parse = 2; 87 return; 88 } else { 89 // fatal error 90 } 91 } 92 if( parse == 2 ) 93 { 94 if(( now_a == 1 ) && (now_b == 0 )) // reverse = CCW 95 { 96 rot_count--; 97 direction= 0; //CCW 98 parse = 1; 99 return; 100 } else if (( now_a == 0 ) && ( now_b == 1)) //foward = CW 101 { 102 rot_count++; 103 direction = 1; // CW 104 parse = 3; 105 return; 106 } else { 107 // fatal error 108 } 109 } 110 if( parse == 3 ) 111 { 112 if(( now_a == 1 ) && (now_b == 1 )) // reverse = CCW 113 { 114 rot_count--; 115 direction= 0; //CCW 116 parse = 2; 117 return; 118 } else if (( now_a == 0 ) && ( now_b == 0)) //foward = CW 119 { 120 rot_count++; 121 direction = 1; // CW 122 parse = 0; 123 return; 124 } else { 125 // fatal error 126 } 127 } 128}

こんな感じですかね?

投稿2016/12/18 10:18

MasahikoHirata

総合スコア3747

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

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

super987

2016/12/19 11:02

回答ありがとうございます。 頂いたサンプルソースを少しだけいじると自分が求めている動作ができました。 色々と参考になりました。本当にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問