7セグメントLEDドライバで7セグメントLEDを操作
エレキ素人が何か考える(その12):シフトレジスタで7セグメントLEDの続編。7セグメントLEDドライバを用いて、7セグメントLEDを制御する。マイコンの使用GPIO数を減らすことについては、シフトレジスタと同じである。
7セグメントLEDドライバ
7セグメント用LEDドライバーIC TM1630を利用。本ICは、カソードコモン専用となるため、カソードコモン用LEDであるC-551SRDを対象とした。いずれも、秋月電子で購入。
LEDのピン配置
TM1630のデータシート
データシートは中国語で書かれている。Googleで英訳したものを適宜PickUp。なお、次のサイトの説明が参考になる。
ピンアサイン、LEDとの接続
コマンドやデータの書き込みシーケンス
固定アドレスモード(後述)のコマンドシーケンスは下記となる。(小さな字でゴメンナサイ)
- Display Mode(5桁7セグメント or 4桁8セグメント)
- Data Setting(固定アドレスモード)
- Display Address(GRID1-4のいずれか選択)
- Data(AddressへのLED表示データのセット)
(3,4の繰り返し) - Display Control(ON or OFF)
となっており、上記の1-5までのそれぞれのコマンド実行前にSTBをLowに、実行後にSTBをHighにする。コマンド実行(データ転送)中に、8ビット分のクロックを発生させるため、shiftOut()を利用する。ソースコード的には下記となる。
- STB Low: digitalWrite(pin, LOW)
- コマンド: shiftOut(DIO, CLK, LSBFIRST, データ) (必要に応じて繰り返す)
- STB High: digitalWrite(pin, HIGH)
データシートにはこのシーケンスとなっているが、実はこのとおりでなくても動作する。詳細は後述するソースコードを参照してほしいが、最初に
1(Display Mode) -> 2(Data Setting) -> 5(Display Control)
を実施し、その後
3(Display Address) -> 4(Data)
を繰り返しても問題ないようだ。また、途中で
5(Display Control)
により、LED Off/Onを単独で行っても動作した。
Display Mode
5桁7セグメントまたは4桁8セグメントの設定。ここでは後者を選択(0b00xxxx01)。
Data Setting
データ書き込み、固定アドレスモードの選択(0b01xx0100)。
Display Address
自動翻訳後の内容が見えづらくなっているが、SEG2-8へのデータを書き込む場合、各Gridに対して次のデータをアドレスとして用いる。
- Grid1: 0b11xx0000 (00H)
- Grid2: 0b11xx0010 (02H)
- Grid3: 0b11xx0100 (04H)
- Grid4: 0b11xx0110 (06H)
Data
LEDの各セグメント(A-G)を用いて、数字の0-9を作る。ソースコードのほうがわかりやすい。
uint8_t digit[] = {0b01111110, 0b00001100, 0b10110110, 0b10011110, 0b11001100,
0b11011010, 0b11111010, 0b01001110, 0b11111110, 0b11011110};
shiftOut()にて、LSB1stでデータを送出するので、bit7がセグメントGに、bit1がセグメントAに相当するようだ。
Display Control
- Display ON: 0b10xx1110
- Display OFF: 0b10xx0000
ソースコード
1秒毎に0から9までを表示させる単純なもの。動作中でも、LEDのOFF/ON制御、テスト用のGRID選択をPCから行いたかったため、タスクを設けて制御(FreeRTOS利用)。
#include <Arduino_FreeRTOS.h>
// TM1630
#define DISP_MODE 0b00000001 // 5-digit 7-segments
#define FIX_MODE 0b01000100 // Increased Fixed Write Mode
#define DISP_ON 0b10001110 // Display ON & PWM-13/16
#define DISP_OFF 0b10000000 // Display OFF
#define GRID1 0b11000000 // 00H
#define GRID2 0b11000010 // 02H
#define GRID3 0b11000100 // 04H
#define GRID4 0b11000110 // 06H
// Arduino
#define DIO 5
#define CLK 6
#define STB 7
- データシートにそった各種コマンドなどの定義
- Arduino GPIO番号
boolean tgl;
uint8_t addr;
uint8_t grid[] = {GRID1, GRID2, GRID3, GRID4};
uint8_t digit[] = {0b01111110, 0b00001100, 0b10110110, 0b10011110, 0b11001100,
0b11011010, 0b11111010, 0b01001110, 0b11111110, 0b11011110};
TaskHandle_t xKbd, xDisp;
- Display On/OFF用変数:tgl
- GRID用変数:addr
- GRID定義
- 0-9までの数値の定義
- FreeRTOS用タスクハンドラ
void configure(uint8_t arg) {
digitalWrite(STB, LOW);
shiftOut(DIO, CLK, LSBFIRST, arg);
digitalWrite(STB, HIGH);
}
void disp_num(uint8_t num) {
digitalWrite(STB, LOW);
shiftOut(DIO, CLK, LSBFIRST, addr);
shiftOut(DIO, CLK, LSBFIRST, digit[num]);
digitalWrite(STB, HIGH);
}
- コマンド制御関数:configure()
- 数値データ関数:disp_num()
TaskHandle_t xKeyboard() {
for (;;) {
if (Serial.available() > 0) {
String data = Serial.readStringUntil('\n');
uint8_t val = data.toInt();
val = val%5; // Avoid exception
Serial.println(val);
if (val == 0) {
tgl = !tgl;
configure((tgl? DISP_ON: DISP_OFF));
} else {
addr = grid[val-1];
}
}
vTaskDelay(1);
}
}
- PCからのシリアル入力タスク
- 入力値0:Display ON/OFF切り替え
- 入力値1-4:GRID選択
(今回はLEDが1つだけだが、配線を変えてGRID1-4が機能することを確認するため、選択できるようにしている。)
TaskHandle_t xDisplay() {
for (;;) {
for (int i=0; i<10; i++) {
disp_num(i);
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
}
- LED表示タスク(1秒毎に0-9までの数値を表示)
void setup() {
Serial.begin(9600);
pinMode(DIO, OUTPUT);
pinMode(CLK, OUTPUT);
pinMode(STB, OUTPUT);
digitalWrite(DIO, LOW);
digitalWrite(CLK, LOW);
digitalWrite(STB, HIGH);
tgl = true;
addr = GRID1;
delay(1);
// Command Display
configure(DISP_MODE);
// Address Incremental
configure(FIX_MODE);
// Setting Display Control
configure((tgl? DISP_ON: DISP_OFF));
// Task
xTaskCreate(xKeyboard, "Keyboard", 128, NULL, 1, &xKbd);
xTaskCreate(xDisplay, "Display", 128, NULL, 1, &xDisp);
vTaskStartScheduler();
}
void loop() {
// nothing
}
- シリアル初期化
- GPIO初期値設定
- 各種変数初期化
- TM1630初期値設定
- タスク起動およびスケジューリング
検証
特に説明は不要かと。中央下にあるICが、TM1630である。
なお、ここでは、Arduino Uno互換ボードを利用した。
EOF