====== 複数のロータリエンコーダを繋ぐ ======
===== 複数個繋ぎたい時にはどうすれば良いのでしょう? =====
H8/3052のハードでサポートされているのは、1個のロータリエンコーダだけです。\\ 
秋月のロータリエンコーダは1回転で24パルス。監視すべきタイミングはA相とB層の立ち上がりと、\\ 
立下りなので24x4=96。1秒間に3回転したとしても96x3=288Hz=3.5ms間隔でチェックすれば良い。\\ 
ソフトで書いても全然余裕です。\\ 
\\ 
接続は以下のようにします。
^  ポート  ^  エンコーダ  ^  相  ^
|  PA-0  |ロータリエンコーダ 0|A 相|
|  PA-1  |ロータリエンコーダ 0|B 相|
|  PA-2  |ロータリエンコーダ 1|A 相|
|  PA-3  |ロータリエンコーダ 1|B 相|
|  PA-4  |ロータリエンコーダ 2|A 相|
|  PA-5  |ロータリエンコーダ 2|B 相|
|  PA-6  |ロータリエンコーダ 3|A 相|
|  PA-7  |ロータリエンコーダ 3|B 相|
===== 仕組みを考える =====
ロータリエンコーダはパルスの変化を見れば良いのだから、前回の値と今回の値を調べればよい。\\ 
表にまとめると以下のようになる。
^前回のA相^前回のB相^	今回のA相^	今回のB相^	回転変位^
|  0  |  0  |  0  |  0  |ありえない|
|  0  |  0  |  0  |  1  |  -  |
|  0  |  0  |  1  |  0  |  +  |
|  0  |  0  |  1  |  1  |ありえない|
|  0  |  1  |  0  |  0  |  +  |
|  0  |  1  |  0  |  1  |ありえない|
|  0  |  1  |  1  |  0  |ありえない|
|  0  |  1  |  1  |  1  |  -  |
|  1  |  0  |  0  |  0  |  -  |
|  1  |  0  |  0  |  1  |ありえない|
|  1  |  0  |  1  |  0  |ありえない|
|  1  |  0  |  1  |  1  |  +  |
|  1  |  1  |  0  |  0  |ありえない|
|  1  |  1  |  0  |  1  |  +  |
|  1  |  1  |  1  |  0  |  -  |
|  1  |  1  |  1  |  1  |ありえない|
===== プログラムの作成 =====
まずは、ポートが後で変わってもよいように、ポートの定義。
SOFT_ROT_PORT   EQU     PA                      ; ソフトウェアロータリエンコーダの接続ポート
SOFT_ROT_DR     EQU     PADR                    ; ソフトウェアロータリエンコーダの接続ポートの DR
SOFT_ROT_NUM    EQU     4                       ; ソフトウェアロータリエンコーダの接続数
次に上記した表のテーブルと、RAM にワークを作成。
;******************************************************************************
;       ROM 上のデータ
;******************************************************************************
                                                ; Ao Bo An Bn
ENC_CNT_TABLE:  DC.B     0                      ; 0  0  0  0
                DC.B    -1                      ; 0  0  0  1
                DC.B    +1                      ; 0  0  1  0
                DC.B     0                      ; 0  0  1  1
                DC.B    +1                      ; 0  1  0  0
                DC.B     0                      ; 0  1  0  1
                DC.B     0                      ; 0  1  1  0
                DC.B    -1                      ; 0  1  1  1
                DC.B    -1                      ; 1  0  0  0
                DC.B     0                      ; 1  0  0  1
                DC.B     0                      ; 1  0  1  0
                DC.B    +1                      ; 1  0  1  1
                DC.B     0                      ; 1  1  0  0
                DC.B    +1                      ; 1  1  0  1
                DC.B    -1                      ; 1  1  1  0
                DC.B     0                      ; 1  1  1  1
;******************************************************************************
;       RAM 上のデータ(初期化あり)
;******************************************************************************
                segment DATA
ENC_OLD_DATA:   DC.B    0,0,0,0                 ; 各ロータリエンコーダの前回の値
ENC_CNT_DATA:   DC.W    0,0,0,0                 ; 各ロータリエンコーダのカウント値
まずは初期化ルーチン。ポートを入力に切り替えるだけです。
;******************************************************************************
;       ソフトウェアロータリエンコーダの初期化
;
;       _SoftRotEncInit
;         2004/12/21 : 初期バージョン完成
;
;       [書式]  void SoftRotEncInit(void) ;
;
;       [IN]    なし
;
;       [OUT]   なし
;
;       [DED]   
;******************************************************************************
                public  _SoftRotEncInit
_SoftRotEncInit:SUB.B   R0L,R0L                 ; ポートを入力に切り替え
                MOV.B   R0L,@SOFT_ROT_DR
                RTS
ステップ数取得ルーチンはカウンタの値を持ってくるだけです。結果はint型なのでR0に返す。\\ 
ステップ数取得とクリアも同じで、カウンタクリアが多いだけ。この行数なのでサブルーチン化はしない。
;******************************************************************************
;       ソフトウェアロータリエンコーダのステップ数取得
;
;       _SoftRotEncCheck
;         2004/12/21 : 初期バージョン完成
;
;       [書式]  int SoftRotEncCheck(int ch) ;
;
;       [IN]    なし
;
;       [OUT]   int     = ステップ数
;
;       [DED]   ER1
;******************************************************************************
                public  _SoftRotEncCheck
_SoftRotEncCheck:
                MOV.W   @(4,ER7),R1
                SHLL.W  R1
                EXTU.L  ER1
                MOV.W   @(ENC_CNT_DATA,ER1),R0
                RTS
;******************************************************************************
;       ソフトウェアロータリエンコーダのステップ数取得とクリア
;
;       _SoftRotEncRead
;         2004/12/21 : 初期バージョン完成
;
;       [書式]  int SoftRotEncRead(int ch) ;
;
;       [IN]    int     ch      = チャンネル
;
;       [OUT]   int     = ステップ数
;
;       [DED]   E0,ER1
;******************************************************************************
                public  _SoftRotEncRead
_SoftRotEncRead:MOV.W   @(4,ER7),R1
                SHLL.W  R1
                EXTU.L  ER1
                MOV.W   @(ENC_CNT_DATA,ER1),R0
                SUB.W   E0,E0
                MOV.W   E0,@(ENC_CNT_DATA,ER1)
                RTS
肝となるのは、このポート監視ルーチン。\\ 
アセンブラとCから呼べるようにしてあります。最終的にはタイマ割り込みから呼び出す。
;******************************************************************************
;       ソフトウェアロータリエンコーダの監視
;
;       _SoftRotEncUpdate
;         2004/12/21 : 初期バージョン完成
;
;       [書式]  void SoftRotEncUpdate(void) ;
;
;       [IN]    なし
;
;       [OUT]   なし
;
;       [DED]   ER0,ER1,ER2,ER3
;******************************************************************************
                public  _SoftRotEncUpdate
                public  SOFT_ROTENC_UPDATE
_SoftRotEncUpdate:
SOFT_ROTENC_UPDATE:
                MOV.L   #ENC_OLD_DATA,ER1       ; ER1 = 前回のパルス
                MOV.L   #ENC_CNT_DATA,ER2       ; ER2 = カウント値
                MOV.B   @SOFT_ROT_PORT,R0L      ; ポート値の取得
                NOT.B   R0L                     ; 論理を戻す
                MOV.B   #SOFT_ROT_NUM,R0H       ; ROH = 回数
SOFT_ENC_LOOP:  SUB.L   ER3,ER3                 ; ER3 = 0
                MOV.B   @ER1,R3L                ; ER3 = Ao Bo
                SHLR.B  R0L                     ; CF = An
                ROTXL.B R3L                     ; ER3 = Ao Bo An
                SHLR.B  R0L                     ; CF = Bn
                ROTXL.B R3L                     ; ER3 = Ao Bo An Bn
                AND.B   #00001111B,R3L          ; 不要な Bit を捨てる
                MOV.B   R3L,@ER1                ; パルス値を書き戻す
                INC.L   #1,ER1
                MOV.B   @(ENC_CNT_TABLE,ER3),R3L; テーブルで増分を取得
                EXTS.W  R3
                MOV.W   @ER2,E0                 ; カウンタに足す
                ADD.W   R3,E0
                MOV.W   E0,@ER2
                INC.L   #2,ER2
                DEC.B   R0H
                BNE     SOFT_ENC_LOOP:8
                RTS
===== 全ソース =====
まとめるとこんな感じになります。コードは 130 Byte と思ったより小さめです。
;******************************************************************************
;       ソフトウェアロータリエンコーダ処理
;                                                       (C)YdlProg
;******************************************************************************
                INCLUDE (../lib3052/3052.inc)
SOFT_ROT_PORT   EQU     PA                      ; ソフトウェアロータリエンコーダの接続ポート
SOFT_ROT_DR     EQU     PADR                    ; ソフトウェアロータリエンコーダの接続ポートの DR
SOFT_ROT_NUM    EQU     4                       ; ソフトウェアロータリエンコーダの接続数
                segment TEXT
;******************************************************************************
;       ソフトウェアロータリエンコーダの初期化
;
;       _SoftRotEncInit
;         2004/12/21 : 初期バージョン完成
;
;       [書式]  void SoftRotEncInit(void) ;
;
;       [IN]    なし
;
;       [OUT]   なし
;
;       [DED]   
;******************************************************************************
                public  _SoftRotEncInit
_SoftRotEncInit:SUB.B   R0L,R0L                 ; ポートを入力に切り替え
                MOV.B   R0L,@SOFT_ROT_DR
                RTS
;******************************************************************************
;       ソフトウェアロータリエンコーダのステップ数取得
;
;       _SoftRotEncCheck
;         2004/12/21 : 初期バージョン完成
;
;       [書式]  int SoftRotEncCheck(int ch) ;
;
;       [IN]    なし
;
;       [OUT]   int     = ステップ数
;
;       [DED]   ER1
;******************************************************************************
                public  _SoftRotEncCheck
_SoftRotEncCheck:
                MOV.W   @(4,ER7),R1
                SHLL.W  R1
                EXTU.L  ER1
                MOV.W   @(ENC_CNT_DATA,ER1),R0
                RTS
;******************************************************************************
;       ソフトウェアロータリエンコーダのステップ数取得とクリア
;
;       _SoftRotEncRead
;         2004/12/21 : 初期バージョン完成
;
;       [書式]  int SoftRotEncRead(int ch) ;
;
;       [IN]    int     ch      = チャンネル
;
;       [OUT]   int     = ステップ数
;
;       [DED]   E0,ER1
;******************************************************************************
                public  _SoftRotEncRead
_SoftRotEncRead:MOV.W   @(4,ER7),R1
                SHLL.W  R1
                EXTU.L  ER1
                MOV.W   @(ENC_CNT_DATA,ER1),R0
                SUB.W   E0,E0
                MOV.W   E0,@(ENC_CNT_DATA,ER1)
                RTS
;******************************************************************************
;       ソフトウェアロータリエンコーダの監視
;
;       _SoftRotEncUpdate
;         2004/12/21 : 初期バージョン完成
;
;       [書式]  void SoftRotEncUpdate(void) ;
;
;       [IN]    なし
;
;       [OUT]   なし
;
;       [DED]   ER0,ER1,ER2,ER3
;******************************************************************************
                public  _SoftRotEncUpdate
                public  SOFT_ROTENC_UPDATE
_SoftRotEncUpdate:
SOFT_ROTENC_UPDATE:
                MOV.L   #ENC_OLD_DATA,ER1       ; ER1 = 前回のパルス
                MOV.L   #ENC_CNT_DATA,ER2       ; ER2 = カウント値
                MOV.B   @SOFT_ROT_PORT,R0L      ; ポート値の取得
                NOT.B   R0L                     ; 論理を戻す
                MOV.B   #SOFT_ROT_NUM,R0H       ; ROH = 回数
SOFT_ENC_LOOP:  SUB.L   ER3,ER3                 ; ER3 = 0
                MOV.B   @ER1,R3L                ; ER3 = Ao Bo
                SHLR.B  R0L                     ; CF = An
                ROTXL.B R3L                     ; ER3 = Ao Bo An
                SHLR.B  R0L                     ; CF = Bn
                ROTXL.B R3L                     ; ER3 = Ao Bo An Bn
                AND.B   #00001111B,R3L          ; 不要な Bit を捨てる
                MOV.B   R3L,@ER1                ; パルス値を書き戻す
                INC.L   #1,ER1
                MOV.B   @(ENC_CNT_TABLE,ER3),R3L; テーブルで増分を取得
                EXTS.W  R3
                MOV.W   @ER2,E0                 ; カウンタに足す
                ADD.W   R3,E0
                MOV.W   E0,@ER2
                INC.L   #2,ER2
                DEC.B   R0H
                BNE     SOFT_ENC_LOOP:8
                RTS
;******************************************************************************
;       ROM 上のデータ
;******************************************************************************
                                                ; Ao Bo An Bn
ENC_CNT_TABLE:  DC.B     0                      ; 0  0  0  0
                DC.B    -1                      ; 0  0  0  1
                DC.B    +1                      ; 0  0  1  0
                DC.B     0                      ; 0  0  1  1
                DC.B    +1                      ; 0  1  0  0
                DC.B     0                      ; 0  1  0  1
                DC.B     0                      ; 0  1  1  0
                DC.B    -1                      ; 0  1  1  1
                DC.B    -1                      ; 1  0  0  0
                DC.B     0                      ; 1  0  0  1
                DC.B     0                      ; 1  0  1  0
                DC.B    +1                      ; 1  0  1  1
                DC.B     0                      ; 1  1  0  0
                DC.B    +1                      ; 1  1  0  1
                DC.B    -1                      ; 1  1  1  0
                DC.B     0                      ; 1  1  1  1
;******************************************************************************
;       RAM 上のデータ(初期化あり)
;******************************************************************************
                segment DATA
ENC_OLD_DATA:   DC.B    0,0,0,0                 ; 各ロータリエンコーダの前回の値
ENC_CNT_DATA:   DC.W    0,0,0,0                 ; 各ロータリエンコーダのカウント値
                END
===== 呼び出し方 =====
Cからの呼び出しは以下のように行います。SoftRotEncUpdateは割り込みで呼んでいないため、\\ 
他の処理が重いと読み取りに失敗します。実験時以外はタイマ割り込みからの呼び出しにします。
#include 
extern  void    SoftRotEncInit(void) ;          // ロータリエンコーダの初期化
extern  int     SoftRotEncCheck(int ch) ;       // ロータリエンコーダのステップ数取得
extern  int     SoftRotEncRead(int ch) ;        // ロータリエンコーダのステップ数取得とクリア
extern  void    SoftRotEncUpdate(void) ;        // ロータリエンコーダの監視
void main(void) {
    SoftRotEncInit() ;                          // ロータリエンコーダ 0~3 の初期化
    while(1) {
        SoftRotEncUpdate() ;                    // ロータリエンコーダ 0~3 の監視
        if(abs(SoftRotEncCheck(0)) >= 4) {      // ロータリエンコーダ 0 のステップ数取得
            num = SoftRotEncRead(0) ;           // ロータリエンコーダ 0 のステップ数取得とクリア
            // ロータリエンコーダ 0 の処理
        }
        if(abs(SoftRotEncCheck(1)) >= 4) {      // ロータリエンコーダ 1 のステップ数取得
            num = SoftRotEncRead(1) ;           // ロータリエンコーダ 1 のステップ数取得とクリア
            // ロータリエンコーダ 1 の処理
        }
        if(abs(SoftRotEncCheck(2)) >= 4) {      // ロータリエンコーダ 2 のステップ数取得
            num = SoftRotEncRead(2) ;           // ロータリエンコーダ 2 のステップ数取得とクリア
            // ロータリエンコーダ 2 の処理
        }
        if(abs(SoftRotEncCheck(3)) >= 4) {      // ロータリエンコーダ 3 のステップ数取得
            num = SoftRotEncRead(3) ;           // ロータリエンコーダ 3 のステップ数取得とクリア
            // ロータリエンコーダ 3 の処理
        }
    }
}
速度が遅いものは外部ハードウェアが無くても何とかなります。\\ 
コストを下げるためには、ソフトでできることはソフトでやりましょう。