XC8用ロータリーエンコーダー処理関数
XC8用ロータリーエンコーダ処理関数
以前にアッセンブラ用にプログラムを作ってますが、今回はXC8用にアッセンブラ版を移植してみる事にしました。
基本的にそのままの移植なのですが、使用方法を少々単純化してみました。
使用したロータリーエンコーダーは秋月電子で安価に購入した、アルプス電気のインクリメンタル方式エンコーダー(クリック無し)です。
クリック有タイプも販売されていますが、1クリックで数パルスを発生し、使い勝手が悪いです。
型番:EC12E2420803
以前にアッセンブラ用にプログラムを作ってますが、今回はXC8用にアッセンブラ版を移植してみる事にしました。
基本的にそのままの移植なのですが、使用方法を少々単純化してみました。
使用したロータリーエンコーダーは秋月電子で安価に購入した、アルプス電気のインクリメンタル方式エンコーダー(クリック無し)です。
クリック有タイプも販売されていますが、1クリックで数パルスを発生し、使い勝手が悪いです。
型番:EC12E2420803
インクリメンタルタイプ・ロータリーエンコーダー(RE)の動作
REは左記回路図の様につまみを左あるいは右に回すと、RE内部にある2つのスイッチがON/OFFします。
そのため、スイッチをプルアップしREを回転する事によりパルスを発生します。
ここでは、スイッチ1を「REA」、スイッチ2を「REB」とします。
軸を回転すると、REAとREBの出力パルスが時間差(位相差)をもって検出されます。
それぞれのパルス長は、ほぼ同じですが、共に軸回転スピードに左右されます。
その位相差はどちらかのパルス長の約半分の時間(1/4周期)の様です。
右回転した場合、REBパルスはREAパルスより位相が遅れます。
左回転した場合、逆にREAパルスがREBパルスより位相が遅れます。
PICはこの位相差を検出して、右回転あるいは左回転を判定します。
回転パルスの1/4周期ごとのビットデータを、2回分取得する必要があります。
すなわち、REAパルスとREBパルスの’H’部分が重なっていない部分と重なっている部分の2回分のデータが判別式に使用されます。
(’H’は’L’と置き換えても同じ)
オシロのDC入力モードでREA/REBポート電圧を観察してみた結果
REのスイッチと回転軸の関係実験
どんな構造になっているのか不明ですが、メカニカルなスイッチと思われます。
RE軸の位置によっては、
①REA/REBが共にONだったり、
②共にOFFだったり、
③④どちらかがONでもう一方がOFFだったり、
と、4種類の状態の存在をそのままRE軸を超ゆっくり回転および反回転させる事で確認しています。
と言う事は、機器立ち上がり時にREのポートデータは、その4種類の内のいずれかと言う事になり、不確定要素となります。
そのREの位置を把握するには、まずは1回制御関数を呼び出せば、確定されます。
REの軸回転させた場合の取得パルス幅の実験
パルスの周期はオシロで見ながら、
a)REを自力で思いっきり回すと、約20ms位
b)ゆっくり回すと数百ms、(目測ですが・・・)
でした。
ONの時間(OFFの時間)パルス幅は、その半分の約10ms~数百msの、PIC動作レベルとしては、かなりのんびりとした世界と思われます。
一人ではオシロで画像採取できないのが残念ですが・・・
そのデータ処理方法アルゴリズムについてはソースファイルを参照して下さい。
( 超投げやり・・・ <m(_ _)m> )
REは左記回路図の様につまみを左あるいは右に回すと、RE内部にある2つのスイッチがON/OFFします。
そのため、スイッチをプルアップしREを回転する事によりパルスを発生します。
ここでは、スイッチ1を「REA」、スイッチ2を「REB」とします。
軸を回転すると、REAとREBの出力パルスが時間差(位相差)をもって検出されます。
それぞれのパルス長は、ほぼ同じですが、共に軸回転スピードに左右されます。
その位相差はどちらかのパルス長の約半分の時間(1/4周期)の様です。
右回転した場合、REBパルスはREAパルスより位相が遅れます。
左回転した場合、逆にREAパルスがREBパルスより位相が遅れます。
PICはこの位相差を検出して、右回転あるいは左回転を判定します。
回転パルスの1/4周期ごとのビットデータを、2回分取得する必要があります。
すなわち、REAパルスとREBパルスの’H’部分が重なっていない部分と重なっている部分の2回分のデータが判別式に使用されます。
(’H’は’L’と置き換えても同じ)
オシロのDC入力モードでREA/REBポート電圧を観察してみた結果
REのスイッチと回転軸の関係実験
どんな構造になっているのか不明ですが、メカニカルなスイッチと思われます。
RE軸の位置によっては、
①REA/REBが共にONだったり、
②共にOFFだったり、
③④どちらかがONでもう一方がOFFだったり、
と、4種類の状態の存在をそのままRE軸を超ゆっくり回転および反回転させる事で確認しています。
と言う事は、機器立ち上がり時にREのポートデータは、その4種類の内のいずれかと言う事になり、不確定要素となります。
そのREの位置を把握するには、まずは1回制御関数を呼び出せば、確定されます。
REの軸回転させた場合の取得パルス幅の実験
パルスの周期はオシロで見ながら、
a)REを自力で思いっきり回すと、約20ms位
b)ゆっくり回すと数百ms、(目測ですが・・・)
でした。
ONの時間(OFFの時間)パルス幅は、その半分の約10ms~数百msの、PIC動作レベルとしては、かなりのんびりとした世界と思われます。
一人ではオシロで画像採取できないのが残念ですが・・・
そのデータ処理方法アルゴリズムについてはソースファイルを参照して下さい。
( 超投げやり・・・ <m(_ _)m> )
ヘッダーファイルの置き場所
MPLAB X IDE Ver5.5
「Projects」ウインドウの、
「Header Files」を右クリック、
「Add Existing Item・・・」
ここで「R_ENCODERv1.h」を登録
同様に、
「Source Files」に
「R_ENCODERv1.c」を登録
この場所にはメインプログラムも登録
MPLAB X IDE Ver5.5
「Projects」ウインドウの、
「Header Files」を右クリック、
「Add Existing Item・・・」
ここで「R_ENCODERv1.h」を登録
同様に、
「Source Files」に
「R_ENCODERv1.c」を登録
この場所にはメインプログラムも登録
ロータリーエンコーダー(RE)処理関数の呼び出し方法
ロータリーエンコーダ出力パルス変化に対して、PICの動作は桁違いに早いので、PICはREのパルス変化が起きるまで待っている訳にはいきません。
また、REのスイッチ部分のチャタリング等のため数msのウエイトを入れますので、
割り込みルーチン内でRE処理をするのも気が進みません。
ただ、1ms位で常に割り込みが掛かってるなら、割り込み専用RE処理関数を埋め込んでも良いかもしれません。(今の所、作成予定はありませんが)
なので、やっぱりメイン関数内のループの中にRE処理関数を呼び出すのが現実的な気がします。
よって、メイン関数内で「頃合い」を見て呼び出す事を想定する事にします。
「頃合い」のさじ加減は、アッセンブラなら2~3ms程度間隔以下でしょうか・・・
XCではどんなコードを吐き出しているのか分からないので、ましてや当局を含めたアマチュア各局は無料コンパイラを使用されてると思いますし、それでは最適化もされないので、REパルスの取りこぼし具合を実験しながら、適所にRE関数を埋め込むのが良さげです。
つまり、メイン関数の処理進行時間によって、一か所あるいは複数個所にRE関数を埋め込む、と言った使用方法を想定します。
ちょっと曖昧なな言い方で申し訳ないのですが・・・ <m(__)m>
ユーザーが使うRE処理関数は1つのみで、動作は以下となります。
メインカウンタ値(引数1)と加減算数値(引数2)を添えて呼び出すと、
戻し値はREの回転方向により、(引数1+引数2)あるいは(引数1-引数2)を返してくると言った処理をするだけです。
REが回転してなかった場合は引数1をそのまま返してきます。
引数はすべて32bit符号無し整数です。
下限値は0H、上限値はFFFFFFFFHです。
オーバーフローやボロー等のフラグは無く、上・下限値に張り付くだけです。
下限値はともかく、上限値に行く事はまず無いと思いますが。
実際の所、上限値の処理確認は面倒で行って居ないです・・・ <m(__)m>
ロータリーエンコーダ出力パルス変化に対して、PICの動作は桁違いに早いので、PICはREのパルス変化が起きるまで待っている訳にはいきません。
また、REのスイッチ部分のチャタリング等のため数msのウエイトを入れますので、
割り込みルーチン内でRE処理をするのも気が進みません。
ただ、1ms位で常に割り込みが掛かってるなら、割り込み専用RE処理関数を埋め込んでも良いかもしれません。(今の所、作成予定はありませんが)
なので、やっぱりメイン関数内のループの中にRE処理関数を呼び出すのが現実的な気がします。
よって、メイン関数内で「頃合い」を見て呼び出す事を想定する事にします。
「頃合い」のさじ加減は、アッセンブラなら2~3ms程度間隔以下でしょうか・・・
XCではどんなコードを吐き出しているのか分からないので、ましてや当局を含めたアマチュア各局は無料コンパイラを使用されてると思いますし、それでは最適化もされないので、REパルスの取りこぼし具合を実験しながら、適所にRE関数を埋め込むのが良さげです。
つまり、メイン関数の処理進行時間によって、一か所あるいは複数個所にRE関数を埋め込む、と言った使用方法を想定します。
ちょっと曖昧なな言い方で申し訳ないのですが・・・ <m(__)m>
ユーザーが使うRE処理関数は1つのみで、動作は以下となります。
メインカウンタ値(引数1)と加減算数値(引数2)を添えて呼び出すと、
戻し値はREの回転方向により、(引数1+引数2)あるいは(引数1-引数2)を返してくると言った処理をするだけです。
REが回転してなかった場合は引数1をそのまま返してきます。
引数はすべて32bit符号無し整数です。
下限値は0H、上限値はFFFFFFFFHです。
オーバーフローやボロー等のフラグは無く、上・下限値に張り付くだけです。
下限値はともかく、上限値に行く事はまず無いと思いますが。
実際の所、上限値の処理確認は面倒で行って居ないです・・・ <m(__)m>
ロータリーエンコーダ処理関数 Ver1
呼び出して使うのは下記の1)の関数1つのみです・・・ (;´・ω・)
ヘッダーファイルでREと接続する入力ポート設定が必要です。
1)unsigned long int RE_DATA(
unsigned long int 引数1、unsiged long int 引数2)
REを右回転した場合、引数1に引数2を加算します
加算によるキャリー発生時は最大値のままです。
REを左回転した場合、引数1から引数2を減算します
減算によるボロー発生時は’0’のままです。
RE取得データ(2bit)は過去3回、全部で4回分まで専用広域変数に保存
その専用変数の数値はユーザーが意識する必要はありません。
引数1:元となるカウンタ数値で32bit符号無し整数
引数2:加減算する1ステップ数値で32bit符号無し整数
戻値:加減算された32bit符号無し整数
REが回転してなかった場合、元の数値をそのまま返します。
2)unsigned char GET_REPORT(void)
ロータリーエンコーダの生数値2bitを取得します
事前に使用読み込みポートを指定します。
REAポート REの下位ビット
REBポート REの上位ビット
1)の関数から呼び出され、ユーザーは使用しません。
引数:無し
戻値:REのポートデータ、下位2bitが有効
3)unsigned char DIREC(
unsigned char 引数1、unsigned char 引数2)
ロータリーエンコーダの回転方向を判別
1)の関数から呼び出され、ユーザーは使用しません。
引数1:現在(最新)のRE生数値で8bit符号無し整数
引数2:一つ過去のRE生数値で8bit符号無し整数
戻値:’0’ならば右回転(CW)を意味します
’1’ならば左回転(CCW)を意味します
広域変数およびポート定義
4)REA、REB
デジタル入力ポートを定義します。
ヘッダーファイルに定義場所があります。
デフォルトでRC3,RC4となっています。
使用システムに合わせ、定義ポートを変更します。
5)RE_BIT
charタイプの広域変数の定義でヘッダーファイルに記述されてます。
REA,REBの2ビットデータ4回分を保存
REA=bit0、REB=bit1(現在値(t0)
そのまま左シフトで過去データとする
REA=bit2、REB=bit3(過去値(t-1)
REA=bit4、REB=bit5(過去値(t-2)
REA=bit6、REB=bit7(過去値(t-3)
呼び出して使うのは下記の1)の関数1つのみです・・・ (;´・ω・)
ヘッダーファイルでREと接続する入力ポート設定が必要です。
1)unsigned long int RE_DATA(
unsigned long int 引数1、unsiged long int 引数2)
REを右回転した場合、引数1に引数2を加算します
加算によるキャリー発生時は最大値のままです。
REを左回転した場合、引数1から引数2を減算します
減算によるボロー発生時は’0’のままです。
RE取得データ(2bit)は過去3回、全部で4回分まで専用広域変数に保存
その専用変数の数値はユーザーが意識する必要はありません。
引数1:元となるカウンタ数値で32bit符号無し整数
引数2:加減算する1ステップ数値で32bit符号無し整数
戻値:加減算された32bit符号無し整数
REが回転してなかった場合、元の数値をそのまま返します。
2)unsigned char GET_REPORT(void)
ロータリーエンコーダの生数値2bitを取得します
事前に使用読み込みポートを指定します。
REAポート REの下位ビット
REBポート REの上位ビット
1)の関数から呼び出され、ユーザーは使用しません。
引数:無し
戻値:REのポートデータ、下位2bitが有効
3)unsigned char DIREC(
unsigned char 引数1、unsigned char 引数2)
ロータリーエンコーダの回転方向を判別
1)の関数から呼び出され、ユーザーは使用しません。
引数1:現在(最新)のRE生数値で8bit符号無し整数
引数2:一つ過去のRE生数値で8bit符号無し整数
戻値:’0’ならば右回転(CW)を意味します
’1’ならば左回転(CCW)を意味します
広域変数およびポート定義
4)REA、REB
デジタル入力ポートを定義します。
ヘッダーファイルに定義場所があります。
デフォルトでRC3,RC4となっています。
使用システムに合わせ、定義ポートを変更します。
5)RE_BIT
charタイプの広域変数の定義でヘッダーファイルに記述されてます。
REA,REBの2ビットデータ4回分を保存
REA=bit0、REB=bit1(現在値(t0)
そのまま左シフトで過去データとする
REA=bit2、REB=bit3(過去値(t-1)
REA=bit4、REB=bit5(過去値(t-2)
REA=bit6、REB=bit7(過去値(t-3)
↑ デモ・プログラム1回路図
14ピンPIC16F1705使用
↑ デモ・プログラム1実験全体
↑ CPU基板
↑ RE部分
クリップはオシロに接続
AQM1602LCDに回転数値を表示
AQM1602制御関数および、
MSSP制御関数が必要です。
デモ・プログラム1XC8ソースファイル
XC8_16F1705_AQM162_RE01.c
インクルードするファイル
MSSP02b.h
MSSP02b.c
AQM1602v1.h
AQM1602v1.c
↑ デモ・プログラム2回路図
↑デモ・プログラム2実験全体
↑ CPU基板
DFR0090 8桁7セグLED使用
回転データを表示
DEF0090制御関数が必要です
デモ・プログラム2ソースファイル
XC8_16F1705_DEF90_RE01.c
インクルードするファイル
DFR0090v2a.h
DFR0090v2a.c
デモ・プログラム実行結果
デモ・プログラムは2種類用意してみました。
どちらもほぼ同じ、超簡単なプログラムで恐縮ですが・・・
このデモ・プログラムでは、表示以外何も仕事をしていませんので、REの回転と数値表示はスムーズに行われました。
メイン関数に実数演算や長いウエイト等が入り、RE制御関数への呼び出し間隔が長くなると、REを思いっきり高速回転した時に追従しなくなります。
その場合は、ゆっくりとREを回すか、メイン関数を工夫して、関数呼び出し間隔を短くします。
他のREデバイスで動作実験はしていませんので悪しからず。
バグや追加事項などありましたら、ここに追記します。
デモ・プログラムは2種類用意してみました。
どちらもほぼ同じ、超簡単なプログラムで恐縮ですが・・・
このデモ・プログラムでは、表示以外何も仕事をしていませんので、REの回転と数値表示はスムーズに行われました。
メイン関数に実数演算や長いウエイト等が入り、RE制御関数への呼び出し間隔が長くなると、REを思いっきり高速回転した時に追従しなくなります。
その場合は、ゆっくりとREを回すか、メイン関数を工夫して、関数呼び出し間隔を短くします。
他のREデバイスで動作実験はしていませんので悪しからず。
バグや追加事項などありましたら、ここに追記します。