PICでCの練習 2007.06.03(日)〜 LessonC_24。ロータリーエンコーダーのパルス数を4桁の7セグメントLEDで表示します。
著作者名: 中野 良知 作成開始: 2007.06.02(土) 更新 : 2007.06.03(日) 実行結果の追加。回路図作成。
目次 1. 目的 2. ゼネラルフローチャート 3. プログラムソースコード 4. キーワード 4.1. ロータリーエンコーダー 4.1.1. チャタリング処理 4.2. 2進数→10進数変換 5. 実行結果 6. 実験回路 1. 目的 ロータリーエンコーダーの1/N回転毎のパルスの変化から回転方向の検出と回転数を カウントします。 カウントは回転方向でインクリメント又はデクリメントし、4桁の7セグメントLEDに 10進数で表示します。 2. ゼネラルフローチャート (main) ↓ プルアップ許可 ↓ TMR0割り込み許可 ↓ ポートの初期化 ↓ ├←──────────┬←─────────┐ ↓ │ │ ロータリーエンコーダー │ │ の入力処理 │ │ ↓ no │ │ <A相立上り?>→──────┘ │ ↓yes 0 │ <B相入力?> →────────┐ │ ↓1 │ │ カウンタインクリメント カウンタデクリメント │ ↓ ↓ │ ├─────────────┘ │ ↓ │ 16ビットバイナリカウント値を │ 10進数の4桁に変換し │ 表示バッファーに格納 │ ↓ │ └──────────────────────┘ (TMR0割り込み) ↓ TMR0=1msec ↓ 割り込みフラグリセット ↓ 全桁消灯 ↓ 走査順の桁データを セグメントデータに変換 ↓ セグメントデータ出力 ↓ 走査順の桁を点灯 ↓ 走査順を更新 ↓ 1msecカウンタインクリメント ↓ (終了) 3. プログラムソースコード //***************************************************************************** // タイトル : LesssonC_24 // 作者 : ioio // 目的 : ロータリエンコーダーの回転数を4桁の7セグメントLEDで表示します。 // マイコン : PIC16F84A // クロック : 20MHz // Config : PROTECT=OFF, WDTE=OFF, XTAL // Compiler : PICC Lite(V9.6)。 HI-TEC software製。 // Compile : >picl -16f84a lesson.c // ASM List : >picl -16f84a --ASMLIST lesson.c //***************************************************************************** // 変更履歴 // 2007.06.02(土) 作成 //***************************************************************************** //----------------------------------------------------------------------------- // ヘッダーファイル #include "pic.h" // デバイス関連の定義を展開 //----------------------------------------------------------------------------- // コンフィグレーション定義 __CONFIG(0x3FFA); // PROTECT=OFF, WDTE=OFF, HS_OSILLATOR //----------------------------------------------------------------------------- // 関数定義 //----------------------------------------------------------------------------- // 定数の定義 #define ANODE_COMM 1 // 7segLEDがアノードコモンの場合に1 #define CATHORD_COMM 0 // 7segLEDがカソードコモンの場合に1 #if ANODE_COMM == 1 // セグメント変換(アノードコモン用) const unsigned char seg_data[16] = { 0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x58, 0x00, 0x18, 0x08, 0x03, 0x27, 0x21, 0x06, 0x0E }; // 桁走査ビット(アノードコモン用) const unsigned char scan[4] = {1,2,4,8}; #endif #if CATHORD_COMM == 1 // セグメント変換(カソードコモン用) const unsigned char seg_data[16] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x27, 0x7F, 0x67, 0x77, 0x7C, 0x58, 0x5E, 0x79, 0x71 }; // 桁走査ビット(カソードコモン用) const unsigned char scan[4] = {0xE,0xD,0xB,0x7}; #endif #define SET_TMR0 256-156 // TMR0設定=156*32*200ns=998.4us #define AIN 0x10 // A相入力マスクデータ #define BIN 0x80 // B相入力マスクデータ //----------------------------------------------------------------------------- // グローバル変数定義 unsigned char digit_no; // 表示走査桁指定 unsigned char dsp_buf[4]={0,0,0,0}; // 表示バッファー int t_cnt; // TMR0割込み回数 unsigned int dsp_cnt; // 表示用カウント //----------------------------------------------------------------------------- // ビットフィールド構造体定義 //----------------------------------------------------------------------------- // ポートマップ // NAME PIN NO I/O USE // -----+--------+------+----------------------------------------- // RA0 17 O 1st Digit。d0 // RA1 18 O 2nd Digit。d1 // RA2 1 O 3rd Digit。d2 // RA3 2 O 4th Digit。d3 // RA4 3 I ロータリーエンコーダーA相入力 // RB0 6 O a segment // RB1 7 O b segment // RB2 8 O c segment // RB3 9 O d segment // RB4 10 O e segment // RB5 11 O f segment // RB6 12 O g segment // RB7 13 I(PU) ロータリーエンコーダーB相入力 //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void main(void) { unsigned int temp1; // 10進数変換に使用 unsigned int temp2; // 10進数変換に使用 int i; // 10進数変換に使用 int n; // 10進数変換に使用 char rt_new = 0x00; // ロータリーエンコーダー最新値 char rt_old = 0x90; // ロータリーエンコーダー前回値 char rt_fix = 0x90; // ロータリーエンコーダー確定値 INTCON = 0b10100000; // 割り込み制御初期化設定 OPTION = 0b01000100; // プリスケール=1/32 TMR0 = SET_TMR0; // タイマー0設定 TRISA = 0x10; // PortA b3,b2,b1,b0=Out。b4=In TRISB = 0x80; // PortB b7=In、b6,b5,b4,b3,b2,b1,b0=Out PORTB = 0x80; // ポートB初期化。b7=プルアップ。 PORTA = 0x00; // ポートA初期化。 digit_no = 0; // 走査桁NoをLSDに初期化 t_cnt = 0; // TMR0割込み回数を初期化 dsp_cnt = 0; // 表示カウンタを初期化 while(1){ // ロータリーエンコーダーの入力処理 if(t_cnt == 5){ // 5msec毎にサンプリング t_cnt = 0; // TMR0割込み回数初期化 rt_new = PORTA & AIN; // A相入力以外をマスク rt_new |= PORTB & BIN; // B相入力以外をマスクして追加 if(rt_new ^ rt_old){ // 入力に変化あり rt_old = rt_new; // 新しい入力データを保存 }else{ // 前回入力と一致(チャタリングなし) if((rt_fix & AIN ) ^ (rt_new & AIN)){ // A相入力が変化していれば if(rt_new & AIN){ // A相入力の立上りエッジなら if(rt_new & BIN){ // B相入力が1なら dsp_cnt++; // カウンタをインクリメント }else{ // B相入力が0なら dsp_cnt--; // カウンタをデクリメント } } } rt_fix = rt_new; // 確定した入力を保存 } } // 表示値の制限。表示の最大値は9999 if(dsp_cnt == 10000){ // 9999をインクリメントすると dsp_cnt = 0; // 0 } if(dsp_cnt == 0xFFFF){ // 0000をデクリメントすると dsp_cnt = 9999; // 9999 } // dsp_cntを4桁の10進数に変換 temp1 = dsp_cnt; n = 1000; for(i = 3; i >= 0; i--){ temp2 = temp1 / n; // 千、百、十、一の個数を計算 dsp_buf[i] = (unsigned char)temp2; // 表示バッファーに代入 temp1 = temp1 % n; // 余りを求める n /= 10; } } } //----------------------------------------------------------------------------- // 機能 : TMR0割り込み関数 // 引数 : なし // 戻値 : なし // 作成 : 2007.05.30(水) //----------------------------------------------------------------------------- static void interrupt isr(void) { TMR0 = SET_TMR0; // タイマー0設定 T0IF = 0; // タイマー0オーバーフローフラグリセット PORTA = 0x10; // 走査ビットオフ。全桁消灯 // セグメントデータ出力。b7=プルアップ PORTB = seg_data[dsp_buf[digit_no]] + 0x80; PORTA = scan[digit_no]; // 走査ビット出力 if(++digit_no == 4){ // 一巡したら digit_no = 0; // 表示桁を1桁目に設定 } t_cnt++; // TMR0割込み回数インクリメント } //***************************************************************************** //***************************************************************************** 4. キーワード 4.1. ロータリーエンコーダー インクリメンタルタイプのロータリーエンコーダーを使用します クリック位置 1 2 3 | | | ┌──────┐ ┌──────┐ A相 ───┘ └───────┘ └───────── ┌──────┐ ┌──────┐ B相 ─────┘ └───────┘ └─────── →0 1← A相の立上りエッジに注目すると、 1) 右方向に進行すると時のB相は 0 です。 2) 左方向に進行すると時のB相は 1 です。 1)と2)のB相の違いによって、ロータリーエンコーダーの回転方向を検出します。 クリック位置が2にもある場合には、 A相の立下がりエッジに注目し、 1) 右方向に進行すると時のB相は 1 です。 2) 左方向に進行すると時のB相は 0 です。 クリック位置が、B相のエッジ部分に設定されているロータリーエンコーダーもあり ます。 今回作成したプログラムは、A相の立上りエッジを検出します。 4.1.1. チャタリング処理 A、B相の変化は、5msec毎のサンプリングで、2回連続して一致したときに信号が確定 したことにします。 ┌──────┐ ┌──────┐ A相 ───┘ └───────┘ └──────── ┌──────┐ ┌──────┐ B相 ─────┘ └───────┘ └────── SAMPLE ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ ││ ││ ││ ││ └┘ └┘ └┘ └┘ ↓ ↓ ↓ ↓ ┌──────┐ ┌──────┐ A相 ─────┘ └───────┘ └─────── ┌──────┐ ┌──────┐ B相 ───────┘ └───────┘ └───── 4.2. 2進数→10進数変換 ロータリーエンコーダーの回転数を16ビットの2進数でカウントしています。 回転数を10進数の4桁で表示するために、2進数を10進数に変換、結果を表示 バッファーへ桁ごとに代入します。 カウント÷1000┐ ├余り÷100┐ │ ├余り÷10 ┐ │ │ ├余り ──┐ ↓ ↓ ↓ ↓ ┌───┐ ┌───┐ ┌───┐ ┌───┐ 表示バッファー │千の位│ │百の位│ │十の位│ │一の位│ └───┘ └───┘ └───┘ └───┘ 5. 実行結果 上:A相入力信号 下:チャタリング処理後のカウンタインクリメントのタイミング PORTAビット0にインクリメントのタイミングでパルスを出力するようにプログラムを 変更して測定しました。 ロターリーエンコーダー信号に、LessonC_18のA相、B相の信号を使用しました。 6. 実験回路 PIC16F84A ┌────┐14 │ VDD├──────●──────●────●───← +5V │ │ │ │0.1u │ │ │ R10K ┴ /50V │┴│100u/16V │ │4 │ 0.1u/50V ┬ └┬┘ │ -MCLR├──────●─┤├───●────●──── 0V │ │ │ │ │16 ┌ ─ ─ ─ ┐ │ │ OSC1├───●─┤├──┐ │ │ │ │┴ ││ │ │ │ □ 20MHz │ │ │ │15 │┬ ││ │ │ OSC2├───●─┤├──● │ │ │ └ ─ ─ ─│┘ │ │ │5 ┌───────┘ │ │ Vss├─●───────────┘ │ │ │ │ +5V │ │ │ │ │ R10K │ │ │ │ RA4├──────●──────────────← A相信号 │ │ │ RB7├─────────────────────← B相信号 │ │ │ │17 │ RA0├─────────────────────┐ │ │18 │ │ RA1├────────────────┐ │ │ │1 │ │ │ RA2├───────────┐ │ │ │ │2 │ │ │ │ RA3├──────┐ │ │ │ │ │ │d3 │d2 │d1 │d0 │ │ ┌┴─┐ ┌┴─┐ ┌┴─┐ ┌┴─┐ │ │ │ 8 │ │ 8 │ │ 8 │ │ 8 │ │ │ └┰┰┘ └┰┰┘ └┰┰┘ └┰┰┘ │ │6 a ┃┃a〜g ┃┃a〜g ┃┃a〜g ┃┃a〜g │ RB0├──R820━━╋┻━━━┻┻━━━┻┻━━━┻┛ │ │7 b ┃ │ RB1├──R820━━┫ │ │8 c ┃ │ RB2├──R820━━┫ │ │9 d ┃ │ RB3├──R820━━┫ │ │10 e ┃ │ RB4├──R820━━┫ │ │11 f ┃ │ RB5├──R820━━┫ │ │12 g ┃ │ RB6├──R820━━┛ │ │ └────┘ 電源パスコン0.1u/50VのセラミックコンデンサーはVDDとVssの近くに接続します。 発振子のGNDはVssの直ぐ近くに接続します。
LessonCのTopへ
サイトのTopへ
法律条項 この資料により生じたいかなる障害や損害に対し、著者は全てを免責されるものとします。 この資料は、著作権法の下で保護され、入手先、著者、日付、法律条項を含んだ場合にのみ複製が可能です。
inserted by FC2 system