先日からいくつか記事にしているCH552E.しかし,いかんせんGPIOが少ない!!.確かに,GPIOの多いモデルもありますが,キーボードなどを作ろうとすると,8×8の16ピン使用しても64個しかつけられません.16ピン稼ぐのは他のマイコンでもそこそこ大変です.そこで,今回は74HC595と74HC165を使用して,お手軽にGPIOを増やそうと思います.
はじめに
そもそも,74HC595と74HC165とは何なのかというと,どちらも只の8bitのシフトレジスターです.どちらもシリアルパラレル変換に主に使用されます.
それぞれ,秋月のリンクを張っておきます.
秋月価格で595は40円,165は80円(少し高い)です.
74HC595
シリアル入力-パラレル出力をしてくれるICです.OUTPUTピンを増やしたいときに使えます.以下のサイトがわかりやすく書いていてくれています.
データシートからピン配置とロジック回路図を見てみます.
中身を見ると,D-FFをつなげただけなのが分かります.
主要なピンを軽く説明すると以下のようになります.
- SRCLR…ピンのクリアに使われる.負論理なので普段はHIGHにしておきます.
- SRCLK…データをシフトするのに使われる.このクロックの立ち上がったタイミングでD-FFのDへの入力がQの出力になる.
- SER…出力したいシリアルのデータを入力するピン.SER->CLK->SER->CLK…の様にデータ入力とクロックを繰り返してデータをセットしていく.
- RCLK…これをLOW->HIGHにしたタイミングで,下の出力保存用のD-FFの出力Qが確定する.なので,全データがセットし終わって,出力を始めるときにHIGHにする.
- OE…出力有効無効のピン.負論理なので常にLOWにしておく.
よって,最低限制御しないといけないのはSRCLK,SER,RCLKの3本です.また,QH’を使用すればどんどん595を増やしていけます.
74HC165
パラレル入力-シリアル出力をしてくれるICです.INPUTピンを増やしたいときに使えます.以下のサイトがわかりやすく書いていてくれています.こちらも,先程のサイトが参考になります.
こちらもデータシートからピン配置とロジック回路図を見てみます.
中身を見るとこちらも,D-FFをつなげただけなのが分かります.
主要なピンを軽く説明すると以下のようになります.
- SH/LD…ピンの入力を確定します.A-Hの入力を読み込みたいタイミングでLOWにし,読み込み終わったらHIGHにします.負論理なので注意.
- CLK…データをシフトするのに使われる.このクロックの立ち上がったタイミングのDの入力がQになる.
- QH…最後のD-FFの出力Qが出てくる.QH->CLK->QH->CLK…の様にデータ出力とクロックを繰り返してデータを読み取る.
- CLK INH…クロックの入力を受け付けるか選ぶ.HIGHだとFFに入るパルスが立ち上がったままになるので常にLOWにしておく.
- OE…出力有効無効のピン.負論理なので常にLOWにしておく.
よって,最低限制御しないといけSH/LD,CLK,QHになります.こちらもSERとQHを使えば,どんどんつなげることができます.
回路図
今回の回路は以下のようになります.
小さくて申し訳ないです.
CH552Eのピンが少ないのでCLKと{RCLK,SH/LD}を共有することで4ピンで両方のICを制御します.他のマイコンでも,ピン節約したいときはこれらを共有することで節約できます.試してはいませんが,入力と出力を切り替えれば,SERとQHも1ピンに節約できそうです.
165への入力にはプルアップをしています.
やってはいませんが,LEDを一気に全点灯すると電流的にやばいかも.
コード
以下の動作をするコードです.
- ボタンの入力(負論理)を読み取ってシリアルモニターに出力する
- 100[ms]おきに,順番にLEDを点灯していきます.
#include <Serial.h>
#define CLK 14
#define LATCH 15
#define SERIAL_OUTPUT 16
#define SERIAL_INPUT 17
uint8_t readData() {
uint8_t result = 0;
digitalWrite(CLK, LOW);
digitalWrite(LATCH, LOW);
digitalWrite(LATCH, HIGH);
for (int i = 0; i < 8; i++) {
result |= ((digitalRead(SERIAL_INPUT) & 0x01) << i);
digitalWrite(CLK, HIGH);
digitalWrite(CLK, LOW);
}
return result;
}
void sendData(uint8_t send_data) {
digitalWrite(CLK, LOW);
uint8_t mask = 0x01;
digitalWrite(LATCH, LOW);
for (int i = 0; i < 8; i++) {
digitalWrite(SERIAL_OUTPUT, send_data & mask);
digitalWrite(CLK, HIGH);
digitalWrite(CLK, LOW);
mask = mask << 1;
}
digitalWrite(LATCH, HIGH);
}
void setup() {
pinMode(CLK, OUTPUT);
pinMode(LATCH, OUTPUT);
pinMode(SERIAL_OUTPUT, OUTPUT);
pinMode(SERIAL_INPUT, INPUT);
digitalWrite(LATCH, LOW);
digitalWrite(CLK, LOW);
}
void loop() {
uint8_t result = readData();
USBSerial_println_ib(result, BIN);
for (int i = 0; i < 8; i++) {
sendData(1 << i);
delay(100);
}
}
Serial Printの部分がArduinoとは少し違うので注意です.書き込み時は,USB SettingsをDefaul CDCにしておきます.書き込みに関しては以下で説明しています.
参考までにArduino nanoでのコードは以下になります.
#define CLK A1
#define LATCH A2
#define SERIAL_OUTPUT A3
#define SERIAL_INPUT A4
void setup() {
pinMode(CLK, OUTPUT);
pinMode(LATCH, OUTPUT);
pinMode(SERIAL_OUTPUT, OUTPUT);
pinMode(SERIAL_INPUT, INPUT);
digitalWrite(LATCH, LOW);
digitalWrite(CLK, LOW);
Serial.begin(9600);
}
void loop() {
uint8_t result = readData();
Serial.println(result, BIN);
for (int i = 0; i < 8; i++) {
sendData(1 << i);
delay(100);
}
}
uint8_t readData() {
uint8_t result = 0;
digitalWrite(CLK, LOW);
digitalWrite(LATCH, LOW);
digitalWrite(LATCH, HIGH);
for (int i = 0; i < 8; i++) {
result |= ((digitalRead(SERIAL_INPUT) & 0x01) << i);
digitalWrite(CLK, HIGH);
digitalWrite(CLK, LOW);
}
return result;
}
void sendData(uint8_t send_data) {
uint8_t mask = 0x01;
digitalWrite(CLK, LOW);
digitalWrite(LATCH, LOW);
for (int i = 0; i < 8; i++) {
digitalWrite(SERIAL_OUTPUT, send_data & mask);
digitalWrite(CLK, HIGH);
digitalWrite(CLK, LOW);
mask = mask << 1;
}
digitalWrite(LATCH, HIGH);
}
動作結果
以下の動画のように動きます.
終わりに
今回はCH552Eで74HC595及び74HC165を使用してGPIOを増やしてみました.マイコンのピンをお手軽に増やしたい場合は結構使えます.
よかったら参考にしてみてください.
コメント