入力するピンが不足した場合に入力ピンを増やす方法

〔マイコン使用による電子部品の使い方に戻る〕


前回の記事で「出力するピンがが不足した場合に出力ピンを増やす方法」を74HC595で記載しました。
今回は入力側です、74HC165を使用します。
また、74HC153も入力ピンを増やす事が出来ますが、こちらは4ピン使用して8ピンに増やす事が出来ます。

概念図1   概念図2

74HC165が1個辺り8ピンの入力を増やす事が可能です、
しかも上左図の様に74HC165を何個増やそうとマイコンからの制御は3ピンのみです。
マイコンからのクロック信号(CK)に応じて、入力端子の情報(パラレル)をQHの端子からシリアルに変換されてマイコンへ送信されます。

74HC165の動きは
@通常S/L信号はHIGHにして置きます、そして、LOWからHIGH(19ns)に信号を変化させると、
 LOWのタイミングで74HC165は入力端子A〜Hの情報をレジスタA〜Hに格納します。
Aこの時点でQH端子には 入力端子H の情報が出力されています。
 (マイコンでQHの情報を読み取りましょう)
BCK信号をHIGHからLOWにワンパルス出力(19ns)します。
 HIGHのタイミングで74HC165はレジスタをシフト動作させます。
 A→B、B→C、----、G→Hに移動させ、QHには 入力端子G の情報が出力されます、
 Aレジスタには SI端子 から74HC165(2)の QH からの情報が移動します。
 もちろん74HC165が1個のみで SI が GND接続なら Aレジスタは 0 となります。
 (ここでまた、マイコンでQHの情報を読み取りましょう)
Cなのでぇ、Bを7回繰り返せば74HC165(1)の入力端子情報を読み取る事が出来ます。
 もちろん74HC165を使用している個数分繰り返す事になります。

以上の様な動作を行うので、入力端子の情報がマイコンに伝わるまでには時間がかかると言う事で、
I/O割込み等を利用する場合は直接マイコンに接続しましょう。
また、CK信号の立ち上がりで動作するのだから立上りのタイミング間隔を短くすればそれだけ早く動作させる事が可能です (VCC=4.5Vで24MHz位はいけそうです)。 今回速度の計測は行っていません。

Arduinoの標準関数でshiftIn()関数が有りますがこれを使用すると1ビットずれます、
また、SPI(SPI.transfer)で読み出しても1ビットずれます、
(先頭の入力端子Hの情報が左へシフトされた状態で消えている為です)
これはおそらく、上で説明のBのみ8回繰り返しているからです、
shiftIn()関数もSPIもAの操作をプログラミングしないとダメです。
なのでぇ、今回はオリジナルのShiftIn()関数を作成しました。
(74HC165のQH出力に74HC74(D-FF)を付ければ良いような気もしますが....)

TC74HC165APのデータシートはこちらからダウンロードして下さい。
74HC165はマルツパーツや、共立エレショップで購入できます。

《Arduino》

配線図1
    74HC165ピン配列
 74HC165ピン配列
 74HC165の入力端子A〜Hで使用しない入力
 ピンが有れば、電源かGNDに配線します。
 74HC165は1個なので、SIはGND接続です。
 "CK INH"はHIGHだとクロック禁止入力です、
 たぶん、シフト動作しなくなると思います、
 だからこの端子もGND接続にします。

 今回、入力部にはDIP-SWを接続しました、
 DIP-SWはプルアップ接続です。
 プルアップ接続の話はこちらを参照下さい。

 (Fritzing用のDIP-SW部品ダウンロードは
 こちらからお願いします。)


実験T

まずは、IDEに下記のスケッチプログラムをコピーペーストして貼り付けて下さい。
IDEツールバーの「Upload」ボタンをクリックしてコンパイルとarduinoボードに書込みを行います。
---------------------------------------------------------------------
#define MISO 12     // データの入力ピン(74HC165-QH)
#define SCK  13     // クロック出力ピン(74HC165-CK)
#define SL   10     // レジスタロードピン(74HC165-SL)

byte ShiftData ;

// 74HC165のデータを読込む(受信する)関数
// DataPin :データの入力ピン
// clockPin:クロック出力ピン
// loadPin :レジスタロードピン
byte ShiftIn(int dataPin,int clockPin,int loadPin)
{
     unsigned char x ;
     int  i ;

     x = 0 ;
     digitalWrite(loadPin,LOW) ;          // 入力端子(A-H)の情報をレジスタに読込めと指示する
     digitalWrite(loadPin,HIGH) ;
     x = x | (digitalRead(dataPin) << 7) ;// H端子の内容を受信する
     for (i=6 ; i>=0 ; i--) {             // G端子〜A端子まで繰り返す
          digitalWrite(clockPin,HIGH) ;         // 1ビットシフト指示を出す
          digitalWrite(clockPin,LOW) ;
          x = x | (digitalRead(dataPin) << i) ; // シフトされた内容を受信する
     }
     return x ;
}
// 電源起動時とリセットの時だけのみ処理する関数
void setup() {
     // シリアル通信の初期化
     Serial.begin(9600) ;
     // 74HC165のピン情報初期化
     pinMode(MISO, INPUT) ;
     pinMode(SCK,  OUTPUT) ;
     pinMode(SL,   OUTPUT) ;
     digitalWrite(SL,HIGH) ;
     digitalWrite(SCK,LOW) ;
     // 3秒後に開始
     delay(3000) ;
     // 74HC165入力端子のデータを読込み表示を行う
     ShiftData = ShiftIn(MISO,SCK,SL) ;
     Serial.println(ShiftData, BIN);
}
// 繰り返し実行されるメインの処理関数
void loop() {
     byte dt ;

     // 74HC165入力端子のデータを読込む
     dt = ShiftIn(MISO,SCK,SL) ;
     if ( dt != ShiftData ) {
          // データに変化が有れば表示する
          ShiftData = dt ;
          Serial.println(dt, BIN) ;
     }
}
---------------------------------------------------------------------
ArduinoIDEのシリアルモニター画面を起動させましょう。
画面にはDIP-SWのパターンが"11110101"等の様に表示されます、DIP-SWを切り替えて下さい、
そのパターンで表示更新がされると思います。
サンプルスケッチはDIP-SWのデータが変わるとその都度表示更新を行います、
だから、DIP-SWを変更している時にSWがチャタリングを起こせばその分データが表示されるでしょう。
また、DIP-SWはプルアップ接続なのでSWがOFF状態で"1"が入力され、SWがONなら"0"です。
尚、"HGFEDCBA"の順序でビットが表示されます。
さらに尚、"00110101"がDIP-SWのパターンとすると表示される内容は"110101"ですよ、念の為。

オリジナルのShiftIn()関数について

ans = ShiftIn(dataPin,clockPin,loadPin)
 74HC165のデータを読込む(受信する)処理を行います。
  dataPin :データの入力ピン、74HC165のQHに接続しているピンを指定します
  clockPin:クロック出力ピン、74HC165のCKに接続しているピンを指定します
  loadPin :レジスタロードピン、74HC165のS/Lに接続しているピンを指定します
  ans   :読込んだデータをbyte値("HGFEDCBA"の順)で返します

SPIについて

上記配線図の接続でSPIを利用可能ですが、 例えば下の様にスケッチを行ったとします。
---------------------------------------------------------------------
void loop() {
     byte dt ;

     digitalWrite(SS, LOW) ;   // 入力端子(A-H)の情報をレジスタに読込めと指示する
     digitalWrite(SS, HIGH) ;
     dt = SPI.transfer(0xff) ; // 端子の内容を受信する
     Serial.println(dt,BIN) ;
     while(1) ;                // 処理中断
}
---------------------------------------------------------------------
この時、DIP-SWのパターンが"11110101"とするとdtの受信内容は"11101010"と表示されます、
上の方で記述した様にずれるのです、なので、下記スケッチの如く
     digitalWrite(SS, LOW) ;
     digitalWrite(SS, HIGH) ;
     (ここでQH:MISOの内容をdt1に読込んでおく)
     dt = SPI.transfer(0xff) ; // 端子の内容を受信する
     (dt1を8ビット目として、dtの上位7ビットを取り出し、dt1とdtを合体させる)
     Serial.println(dt,BIN) ;
といった感じにプログラミングを行う必要が有ります。
SPI.transfer()で速度を稼いでも他の処理が有るので、なんだかぁな〜ぁ、って感じでぇ
SPIの実験やスケッチ載せるのをやめました。
あ、それとぉSPIで動作させた場合はArduinoのMOSI(11番ピン)は使用しないけど他のピンとしては
利用できなくなります。

《PIC 12F1822》

配線図2
ピン構成図
 PICのRA2ピンから別途自作のLCDモニター
 に表示させています。
 74HC165-QH → PIC-RA0(INPUT)
 74HC165-CK ← PIC-RA5(OUTPUT)
 74HC165-S/L ← PIC-RA4(OUTPUT)

SPIで通信する場合はこの配線ではだめです、ピンの接続先を変える必要が有ります。

実験U

このプログラムにはデバッグモニタープログラム「skMonitorLCD.c」「skMonitorLCD.h」が必要です。
デバッグモニターについてはこちらを参照して下さい。

尚、LCDモニターの出力はRA2から行っているので「skMonitorLCD.h」を下記の様に変更します。
#define MONITOR_PIN RA2        // モニタ出力するピンの番号を設定する

また、CPUクロックはここでは16MHzで行っているので次の様に変更します。 *1)
#define _XTAL_FREQ 16000000  // 使用するPIC等により動作周波数値を設定する
#define BAUDRATE 103      // 9600bps(8MHz=51)(4MHz=25)(16MHz=103)(20MHz=129)

@MPLAB X(v2.15)を起動させます。 *2)

A下記がプログラムソースです、
  MPLAB(R) XC8 C Compiler Version 1.32コンパイラを使用しています。 *2)
  プロジェクトを作成して新規ファイルにコピーペーストして貼り付けて下さい。

BコンパイルPIC書き込みを実行して下さい。 *2)
---------------------------------------------------------------------
#include <xc.h>
#include "skMonitorLCD.h"     // LCDモニター用

#define _XTAL_FREQ 16000000   // delay用に必要(クロック16MHzを指定)
#define QH         RA0        // データの入力ピン(74HC165-QH)
#define CK         RA5        // クロック出力ピン(74HC165-CK)
#define SL         RA4        // レジスタロードピン(74HC165-SL)

char shiftData ;

// コンフィギュレーション1の設定
#pragma config FOSC     = INTOSC   // 内部クロック使用する(INTOSC)
#pragma config WDTE     = OFF      // ウオッチドッグタイマー無し(OFF)
#pragma config PWRTE    = ON       // 電源ONから64ms後にプログラムを開始する(ON)
#pragma config MCLRE    = OFF      // 外部リセット信号は使用せずにデジタル入力(RA3)ピンとする(OFF)
#pragma config CP       = OFF      // プログラムメモリーを保護しない(OFF)
#pragma config CPD      = OFF      // データメモリーを保護しない(OFF)
#pragma config BOREN    = ON       // 電源電圧降下常時監視機能ON(ON)
#pragma config CLKOUTEN = OFF      // CLKOUTピンをRA4ピンで使用する(OFF)
#pragma config IESO     = OFF      // 外部・内部クロックの切替えでの起動はなし(OFF)
#pragma config FCMEN    = OFF      // 外部クロック監視しない(OFF)

// コンフィギュレーション2の設定
#pragma config WRT    = OFF        // Flashメモリーを保護しない(OFF)
#pragma config PLLEN  = OFF        // 動作クロックを32MHzでは動作させない(OFF)
#pragma config STVREN = ON         // スタックがオーバフローやアンダーフローしたらリセットをする(ON)
#pragma config BORV   = HI         // 電源電圧降下常時監視電圧(2.5V)設定(HI)
#pragma config LVP    = OFF        // 低電圧プログラミング機能使用しない(OFF)

// 74HC165のデータを読込む(受信する)関数
char ShiftIn()
{
     unsigned char x ;
     int  i ;

     x = 0 ;
     SL = 0 ;                 // 入力端子(A-H)の情報をレジスタに読込めと指示する
     SL = 1 ;
     x = x | (QH << 7) ;      // H端子の内容を受信する
     for (i=6 ; i>=0 ; i--) { // G端子〜A端子まで繰り返す
          CK = 1 ;                 // 1ビットシフト指示を出す
          CK = 0 ;
          x = x | (QH << i) ;      // シフトされた内容を受信する
     }
     return x ;
}
// メインの処理
void main()
{
	char dt ;

     OSCCON = 0b01111010 ;    // 内部クロックは16MHzとする
     ANSELA = 0b00000000 ;    // アナログは使用しない(すべてデジタルI/Oに割当てる)
     TRISA  = 0b00000001 ;    // RA0ピン以外を全て出力に割当てる(RA3は入力専用)
     PORTA  = 0b00000000 ;    // 出力ピンの初期化(全てLOWにする)
     SL = 1 ;

     // LCDモニターを使用する為の初期化処理 *1)
     MonitorInit() ;

     __delay_ms(3000) ;       // 3秒後に開始する

     shiftData = ShiftIn() ;  // 74HC165入力端子のデータを読込む
     MonitorPutc(0x11) ;      // モニターの表示位置を決める
     MonitorPutb(shiftData) ; // 2進数で表示する
     while (1) {
          dt = ShiftIn() ;
          if (dt != shiftData) {
               // 入力端子のデータが変化したら表示する
               shiftData = dt ;
               MonitorPutc(0x11) ;
               MonitorPutb(dt) ;
          }
     }
}
---------------------------------------------------------------------

実験風景
 PICを起動させるとArduinoと同じような動作をします、
 LCDモニター画面の2行目に2進数でDIP-SWの
 パターンが表示されます、
 DIP-SWを切替えればその都度表示更新を行います。
 また、表示のビットパターンは"HGFEDCBA"の順序で
 ビットが表示されます。

 左の写真が実験風景ですが、
 上記載の配線図とは少し違う配線です。
 この位の配線になると小さいブレッドボードでは
 少し無理があるかもね。
 大きいブレッドボードを買うかなぁ....

 PS. *3)
 MCP23017と言うICが有ります、これは入出力を行って
 くれる専用のICです。
 16チャンネル有り其々のピンを入力/出力に割付ける
 事が可能です、又、16ピン全てで割り込み入力と
 プルアップも出来て通信はI2Cを利用します。
 ですので入力を増やすならこれがお手軽です、
 この記事についてはこちらを参照下さい。



追記(*3) 2016/01/20
MPLAB X用に記事変更(*2) 2015/10/30
記事見直し(*1) 2014/09/23


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2016 Shigehiro Kimura All Rights Reserved.