はじめに
16Seg LEDで遊んでみたくなりAliでモジュールを購入し、作成してみた。基本的には武蔵野電波のプロトタイパーズのそのままなのだが、Aliのモジュールは素直な作りではないので、その辺りを中心に説明したいと思います。

必要なもの
16Seg Module - KYX-5441AS

Aliで購入できる16SegLEDです。実際には14Segですが便宜上16Segと書きます。
シフトレジスタ 74HC164 x 2

シリアルパラレル変換ロジックICです。Arduinoの出力信号だけでは足りませんので、シフトレジスタを使用して信号線を増やします。
トランジスタアレイ TD62083AP x 2

トランジスタアレイです。配線が簡単になるのでお勧めです。
型番によって仕様が違います。5Vで使用するのでTD62083APを選択します。
| 品種 | 入力抵抗 | 推奨使用回路、条件 |
|---|---|---|
| TD62081AP | 無 | 汎用(外付け抵抗使用) |
| TD62082AP | 10.5kΩ+7Vツエナー | 14-25V PMOS |
| TD62083AP | 2.7kΩ | TTL, 5V CMOS |
| TD62084AP | 10.5kΩ | 6-15V PMOS, CMOS |
Arduino Uno
PCとお手軽に通信できるUnoを使用します。
その他
330Ω x 12
コネクタ、配線材
基板
回路図
全体の回路図
16Segモジュールの内部配線です。

4桁なのに5本分あるのはなんでよ?と思ってチェックしたら、各桁の右上右下のセグメントがDIG5で制御するようになっています。これはAliに掲載されている図ですが、LとNが反対になっていることに注意。
基板
プログラム
// 14セグメントLEDコントローラ
// by 武蔵野電波
// https://pc.watch.impress.co.jp/docs/column/musashino_proto/300483.html
//
// MDF for KYX-5441AS 2019/08/10
# include <MsTimer2.h> // ライブラリのインストールが必要
# define NUMDIGIT (4*2) // lenght of str
# define NUMOUTPUT (4*2+2) // lenght of str
# define SPACE ' '
# define CLK 3
# define SD 2
# define KANSUJI // 漢数字フォントにする場合に有効。アラビア数字にする場合はコメントアウト
// ** 0b0123456789ABCDEF
# define K1 0b0000000000100000
# define K2 0b0000000010000000
# define K3 0b0000000001000000
# define K4 0b0000100000000000
# define N1 0b0000000000010000
# define N2 0b1000000000000000
# define N3 0b0000010000000000
# define N4 0b0000001000000000
// 14セグ・フォントデータ
const unsigned int font[] = {
// FJLMDGGHBCAE NK
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0b0000000000000000, // space 0x20
0b0101000000000000, // !
0b1100000000000000, // "
0b1000111000010000, // #
0b1101111001100000, // $
// FJLMDGGHBCAE NK
0b1111011001000010, // %
0b1010110000110110, // &
0b0000000100000000, // '
0b0000000000000110, // (
0b0010000100000000, // )
0b0111011100000110, // *
0b0101011000000000, // +
0b0000000000000010, // ,
0b0000011000000000, // -
0b0000000000000100, // .
0b0010000000000010, // /
# ifdef KANSUJI
// FJLMDGGHBCAE NK
0b0000111001010000, // 〇
0b0000011000000000, // 一
0b0000111000000000, // 二
0b0000111000100000, // 三
0b0010111001010100, // 四
0b0101111001100000, // 五
0b0110011000000100, // 六
0b0010111000000010, // 七
0b0000000000010100, // 八
0b0101011001000000, // 九
# else
0b1010100011110010, // 0
0b0101000000000000, // 1
0b0000111010110000, // 2
0b0000101011100000,
0b1101011000000000,
0b1000111001100000,
0b1000111001110000,
0b0001000000100010, // 7 16segtype
0b1000111011110000,
0b1000111011100000, // 9
# endif
0b0101000000000000, // :
0b0101000000000000, // ;
0b0000000000000110, // <
0b0000111000000000, // =
0b0010000100000000, // >
0b1001010010100000, // ?
0b0000110010110100, // @ 0x40
0b1000011011110000, // A
0b0101101011100000, // B
0b1000100000110000, // C
// FJLMDGGHBCAE NK
0b0101100011100000, // D
0b1000111000110000, // E
0b1000011000110000, // F
0b1000101001110000, // G
0b1000011011010000, // H
0b0101100000100000, // I
// FJLMDGGHBCAE NK
0b0000100011010000, // J
0b1000010000010110, // K
0b1000100000010000, // L
0b1000000111010010, // M
// FJLMDGGHBCAE NK
0b1000000111010100, // N
0b1000100011110000, // O
0b1000011010110000, // P
0b1000100011110100, // Q
0b1000011010110100, // R
0b1000111101100100, // S
// FJLMDGGHBCAE NK
0b0101000000100000, // T
0b1000100011010000, // U
0b1010000000010010, // V
0b1010000011010100, // W
// FJLMDGGHBCAE NK
0b0010000100000110, // X
0b1010011010000000, // Y
0b0010100000100010, // Z
// FJLMDGGHBCAE NK
0b0101000000000110, // [
0b0000000100000100, // '\'
0b0111000100000000, // ]
0b0000000000100000, // ^
0b0000100000000000, // _
0b0000000100000000, // ` 0x60
0b0000110000010100, // a
0b1000111001010000, // b
0b0000111000010000, // c
// FJLMDGGHBCAE NK
0b0000111011010000, // d
0b0010111000010000, // e
0b1000010000110000, // f
0b0000101111100000, // g
0b1000011001010000, // h
0b0001000000000000, // i
// FJLMDGGHBCAE NK
0b0010100011000000, // j
0b1000011000010100, // k
0b0101000000000000, // l
0b0001011001010000, // m
// FJLMDGGHBCAE NK
0b0000011001010000, // n
0b0000111001010000, // o
0b1000010000110010, // p
0b0000001111100000, // q
0b0000011000010000, // r
0b0000101000000100, // s
// FJLMDGGHBCAE NK
0b1000110000010000, // t
0b0000100001010000, // u
0b0000000001000100, // v
0b0010000001010100, // w
// FJLMDGGHBCAE NK
0b0010000100000110, // x
0b1010000000000010, // y
0b0010110000000000, // z
0b0101010000000000, // {
0b0101000000000000, // |
0b0101001000000000, // }
0b0000000000100000, // ~
0b1010000000000010, // " "
};
// 14セグ・フォントデータ(カナ)
const unsigned int font_kana[] = {
// FJLMDGGHBCAE NK
0b0000000000000000, // space 0xA0
0b0000000000000000, // 。
0b1000000000110000, // 「
0b0000100011000000, // 」
0b0000000000000000, // 、
0b0000000000000000, // ・
// FJLMDGGHBCAE NK
0b0000000000000000, // ヲ
0b0000000000000000, // ア
0b0000000000000000, // イ
0b0000000000000000, // ウ
0b0000000000000000, // エ
0b0000000000000000, // オ
0b0000000000000000, // ヤ
// FJLMDGGHBCAE NK
0b0000000000000000, // ユ
0b0000000000000000, // ヨ
0b0000000000000000, // ツ
0b0000000000000000, // ー 0xB0
0b0000000000000000, // ア
0b0000000000000000, // イ
0b0000000000000000, // ウ
// FJLMDGGHBCAE NK
0b0000000000000000, // エ
0b0000000000000000, // オ
0b0000000000000000, // カ
0b0000000000000000, // キ
0b0000000000000000, // ク
0b0000000000000000, // ケ
0b0000000000000000, // コ
// FJLMDGGHBCAE NK
0b0000000000000000, // サ
0b0000000000000000, // シ
0b0000000000000000, // ス
0b0000000000000000, // セ
0b0000000000000000, // ソ
0b0000000000000000, // タ 0xC0
0b0000000000000000, // チ
// FJLMDGGHBCAE NK
0b0000000000000000, // ツ
0b0000000000000000, // テ
0b0000000000000000, // ト
0b0000000000000000, // ナ
0b0000000000000000, // ニ
0b0000000000000000, // ヌ
0b0000000000000000, // ネ
0b0000000000000000, // ノ
// FJLMDGGHBCAE NK
0b0000000000000000, // ハ
0b0000000000000000, // ヒ
0b0000000000000000, // フ
0b0000000000000000, // ヘ
0b0000000000000000, // ホ
0b0000000000000000, // マ
0b0000000000000000, // ミ 0xD0
0b0000000000000000, // ム
0b0000000000000000, // メ
// FJLMDGGHBCAE NK
0b0000000000000000, // モ
0b0000000000000000, // ヤ
0b0000000000000000, // ユ
0b0000000000000000, // ヨ
0b0000000000000000, // ラ
0b0000000000000000, // リ
0b0000000000000000, // ル
0b0000000000000000, // レ
0b0000000000000000, // ロ
// FJLMDGGHBCAE NK
0b0000000000000000, // ワ
0b0000000000000000, // ン
0b0000000000000000, // "
0b0000000000000000, // °
};
char driverPin[NUMOUTPUT] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; // カソードにつながるピン
char t[NUMDIGIT] = "ABCD0123"; // 最初にABCD0123と表示
char currentDigit = 0;
byte buf = 0;
void setup() {
for (char i = 0; i < NUMOUTPUT; i++) pinMode(driverPin[i], OUTPUT);
pinMode(CLK, OUTPUT);
pinMode(SD, OUTPUT);
// pinMode(13, OUTPUT);
MsTimer2::set(2, refresh); // リフレッシュレート
MsTimer2::start();
Serial.begin(9600);
// digitalWrite(13, HIGH);
}
void Send_Data(unsigned int out_data)
{
shiftOut(SD, CLK, LSBFIRST, lowByte(out_data));
shiftOut(SD, CLK, LSBFIRST, highByte(out_data));
}
void refresh() {
int offset = 0;
digitalWrite(driverPin[currentDigit], LOW);
currentDigit ++;
if ( currentDigit == NUMOUTPUT)
currentDigit = 0;
if ( currentDigit == 4 || currentDigit == 9 ) // for K & N segment
{
unsigned int dp = 0;
offset = ( currentDigit == 4 )? 0:0;
offset += ( currentDigit == 9 )?-1:0;
dp |= ( 0x02 & font[t[currentDigit - 4 + offset]] ) ? K1 : 0 ;
dp |= ( 0x04 & font[t[currentDigit - 4 + offset]] ) ? N1 : 0 ;
dp |= ( 0x02 & font[t[currentDigit - 3 + offset]] ) ? K2 : 0 ;
dp |= ( 0x04 & font[t[currentDigit - 3 + offset]] ) ? N2 : 0 ;
dp |= ( 0x02 & font[t[currentDigit - 2 + offset]] ) ? K3 : 0 ;
dp |= ( 0x04 & font[t[currentDigit - 2 + offset]] ) ? N3 : 0 ;
dp |= ( 0x02 & font[t[currentDigit - 1 + offset]] ) ? K4 : 0 ;
dp |= ( 0x04 & font[t[currentDigit - 1 + offset]] ) ? N4 : 0 ;
Send_Data(dp);
}
else
{
offset = ( currentDigit > 4 )?-1:0;
Send_Data( font[t[currentDigit + offset]]);
}
digitalWrite(driverPin[currentDigit], HIGH);
}
void loop() {
static char c = 0;
if (Serial.available() > 0)
{
buf = Serial.read();
Serial.println(buf);
if (c == 0)
{
for (char i = 0; i < NUMDIGIT; i++)
{
t[i] = SPACE;
}
}
// 受け取った文字の処理
if (buf == ';') // ;を受け取ったら行末と判断
{
c = 0;
}
else if ( isgraph( buf ) || buf == ' ' ) // Alphabet, number, mark & ' '
{
t[c++] = buf;
}
if (c >= NUMDIGIT) c = NUMDIGIT - 1;
}
}
MsTimer2::set(2, refresh);にて refresh()を2msec毎呼出して、LED表示しています。8桁表示に対して10桁分を制御しているので、少々見にくくなっています。
Arduino IDEのシリアルモニターから文字を送信すれば表示されます。数値、アルファベット大文字、小文字、記号に対応しています。また、デフォルトでは漢数字にしています。カタカナはまだ対応していません。
完成
おわりに
14Seg表示というのはなかなか楽しいです。フォントデータを作るのも、いろいろ考えながら作るのが楽しかったですね。
次はこれで時計を作るつもりです。
I2Cでの入出力に改造
シリアル入力からの文字入力をI2Cからの入力に変更してみました。
用意するもの
Arduino Unoもう一つ
配線
A4, A5同士を接続します。電源が違うならGNDも接続
マスター側のプログラム
マスター側のプログラムです。Serialより文字を読みこみ、I2Cへ出力します。
////////////////////////////////////////////////////////////////////
//
// Wireでマスタースレーブ制御する
// 2019/08/12
//
// https://qiita.com/UT-HACKs/items/540e9dddcd1d2d8b2be2
//
//
# include <Wire.h>
# define I2C_DEVICE_NO (0x10) // I2C device address
void setup() {
Serial.begin(9600);
Wire.begin();
pinMode(13,OUTPUT);
}
void loop() {
byte incomingByte = 0;
if( Serial.available() > 0 ) // read data有り
{
incomingByte = Serial.read();
digitalWrite(13,HIGH);
Wire.beginTransmission(I2C_DEVICE_NO) ; // 通信の開始処理、スレーブのアドレスは8とする
Wire.write( incomingByte ); // 通信データ送信
Wire.endTransmission();
digitalWrite(13,LOW);
}
}
スレーブ側(LEDを付けた方)
上にincludeと#defineを追加
# include <Wire.h>
# define I2C_DEVICE_NO (0x10) // I2C device address
setup()に下記追加
Wire.begin(I2C_DEVICE_NO) ; // Set address
Wire.onReceive(CharReadFromI2C); // Function for Int.
I2C受信時にコールされる関数追加
void CharReadFromI2C(int a)
{
static char c = 0;
if (Wire.available() > 0)
{
buf = (char)Wire.read();
Serial.println(buf);
if (c == 0)
{
for (char i = 0; i < NUMDIGIT; i++)
{
t[i] = SPACE;
}
}
// 受け取った文字の処理
if (buf == ';') // ;を受け取ったら行末と判断
{
c = 0;
}
else if ( isgraph( buf ) || buf == ' ' ) // Alphabet, number, mark & ' '
{
t[c++] = buf;
}
if (c >= NUMDIGIT) c = NUMDIGIT - 1;
}
}
loop()内は全消去
void loop() {
// deleted
}
完成
I2C通信は初めて使用しましたがすごく簡単ですね。ライブラリに感謝です。






