ysys_Baのアイコン画像

ジャンクLCDを使ってインジケーターを作成した

ysys_Ba 2021年02月28日に作成  (2021年02月28日に更新)
ジャンクLCDを使ってインジケーターを作成した

はじめに

突然ですが、皆さん秋葉原には行きますでしょうか?自分はよく秋葉原に行くのですが、秋葉原でよく見かけるものの1つにジャンク品があります。ジャンク品はその性質上、本来素人が手を出さないほうが良いものですが、いつも通り秋葉原を散策していたある日マルツ秋葉原本店でこのようなジャンク品を発見し、気が付いたら購入していました。

キャプションを入力できます

これは7セグLCD(液晶)で、特価コーナーで100円で売られていました(写真では3Dプリンタで作成したマウントがついてユニ基に刺さっていますが、店では単体で売られていました)。LCDは電子工作でよく利用されますが、店で売られているのは制御回路が組み込まれたものが多いのに対し、これは制御回路がない素の液晶モジュールです。電子工作超初心者だったのでLEDと同じ要領で動かせるだろうと思い買いましたが、実際は動かし方が違うので苦労しました。ちなみに先日(3月中旬)確認しましたが、まだ大量に売られてました。

セグメントLCDの動かし方

いきなりLCDの動かし方を説明するのは大変なので、まず簡単にLEDの動かし方から話します。

LED単体を光らせる場合、適切な抵抗を入れてアノードとカソードをそれぞれ電源の+,ーに接続します。複数のLEDを光らせる場合、一番簡単なのは単体の時と同様にLED1つ1つのアノードとカソードをそれぞれ+,ーに接続する方法です。アノードまたはカソードを共通化し、残ったほうの電圧を制御することで、LEDの数と同じピン数でLEDを制御できます。しかしながら、8×8マトリクスのようにLED数が増えていくと、LEDの数と同じピン数を用意するのは大変なのでLEDをマトリックス状に配線し、ダイナミック制御を用います(同時に、デコーダやシフトレジスタを利用しマイコンの使用ピン数を減らします)
ダイナミック制御の参考ページ

次にLCDを動かす場合を考えます。LCDは2枚の電極で液晶を挟み、電極間に一定以上の電位差を作ると液晶が電気的に動き向きが変わることで色が変わって見えるようになります。そのため、LEDと同じ回路を用いても動かないことはないのですが、その場合いくつか液晶特有の問題が起こります

  1. 電位差が変化しないと、1度動いた液晶が時間経過で元に戻る
    実際にやってみるとわかりますが、LEDのように電源につなぐと最初は黒くなりますが、数秒でゆっくりと元に戻ります
  2. 電極の正負が偏ると寿命が縮まる
    実際に壊したわけではないのでわかりませんが、調べてみるとそのような文献が見つかったので、LEDと同様につなぐと壊れやすくなると考えられます

以上の理由から、点灯のために片側のみをHIGH/LOWで切り替えるだけのLEDとは異なり、点灯のON/OFFと電極のどちらがHIGH/LOWかの両方を切り替える「交流印加」で動かす必要があります。
キャプションを入力できます
そして今回購入した7セグLCDは3×21のマトリックス状に配線されているため、これをLEDと同様にダイナミック制御する必要があります。Arduino nanoを利用して動かしたかったので、LCDの3+21ピンのうち3ピンの方はHIGH/MIDDLE/LOWの3段階、21ピンの方はHIGH/LOWの2段階の電圧を印加できるようにしました。また24ピンをそのままArduino nanoに接続するのは無理があるので、8bitシフトレジスタ(74HC595)を3つ利用しました。
実験してみたところ、このLCDは動作電位差が1.5~2V程度だったので、マイコンの5/0V出力から大量の10kΩ抵抗で抵抗分圧し、HIGH/MIDDLE/LOWそれぞれの電圧2.5/1.25/0Vを作りました。(PWMで電圧を決めるのも試しましたが、普通にやると液晶の反応速度が速いため5V印加の時と同じ動きになりました)

デバイスの説明

このデバイスを作った一番の理由はジャンクで買ったLCDを動かしたかったからですが、ただ動かすだけではあまり面白くないのでたまたま持っていたArduino nanoを組み込みインジケータモジュールとすることにしました。これにより、今まではArduino IDEのシリアルモニタで確認するだけだった数字データを簡単に出力できるようになりました。LCD以外にも入出力ができるようにとLED2つとスイッチ3つを追加し、インジケータとして使いやすくしました。また、残ったピンをピンソケットと接続することで、必要があればブレッドボードと同じようにジャンプワイヤーで簡単に接続できるようにしました。
キャプションを入力できます
回路むき出しでは雰囲気が出ないので、3Dプリンタで自作してケースに入れています。
サンプルコードではラップ機能付きのタイマーを実装していますが、元のコードをいじれば他の用途として使うのも簡単なので、新しく買ってきた部品を実験する際によく使っています。

構成

キャプションを入力できます

回路

キャプションを入力できます
(同じ数字が書かれたところ同士を接続しています。6~8番はスイッチのピンで、Arduino nanoの適当なDigitalピンに接続されています。)
小型化のためにLCDの下に部品を入れたり空中配線を使ったりしていますが、メンテ性が皆無なのでお勧めしません

動作の様子

作者のツイート(動画があります)
(汎用デバイスとして利用している場合 その1 その2

コード

インジケータ

unsigned long time = 10000; const int DATA = 7; const int LATCH = 8; const int CLOCK = 9; const int V_SWITCH = 10; const int MODE_BOTTON = 11; const int MAIN_BOTTON = 12; int n1 = 0; int n2 = 0; int n3 = 0; int n4 = 0; int n5 = 0; int n6 = 0; int p1 = 0; int p2 = 1; int p3 = 0; int p4 = 1; int p5 = 0; int pu = 0; int pd = 0; int arrow = 0; int GREEN_LED = 0; int RED_LED = 0; int mat_LCD[3][11] = { {7,1,3,3,5,6,6,7,7,7,0}, {5,1,6,3,3,3,7,1,7,3,0}, {2,0,2,2,0,2,2,0,2,2,0}}; int t001 = 0; int t1 = 0; int t60 = 0; int time0_s = 0; int time1_s = 0; int time2_s = 0; int time0_m = 0; int time1_m = 0; int time2_m = 0; int timer = 0; void setup() { pinMode( V_SWITCH, INPUT_PULLUP ); pinMode( MODE_BOTTON, INPUT_PULLUP ); pinMode( MAIN_BOTTON, INPUT_PULLUP ); pinMode(DATA, OUTPUT); pinMode(CLOCK, OUTPUT); pinMode(LATCH, OUTPUT); digitalWrite(DATA, LOW); digitalWrite(CLOCK, LOW); digitalWrite(LATCH, LOW); Serial.begin( 9600 ); } void loop() { int value1; int value2; int value3; value1 = digitalRead( V_SWITCH ); value2 = digitalRead( MODE_BOTTON ); value3 = digitalRead( MAIN_BOTTON ); if(value2 == 0){ // sub botton pushed time1_s = 0; time1_m = 0; timer = 0; RED_LED = 1; GREEN_LED = 0; } if(value3 == 0){ // main botton pushed if(timer == 0){ time0_m = millis() / 1000; time0_s = millis() % 1000; RED_LED = 0; GREEN_LED = 1; timer = 1; arrow = 0; } if(timer == 2){ timer = 3; time2_m = millis() / 1000 - time0_m; time2_s = millis() % 1000 - time0_s; if(time2_s < 0){ time2_s = time2_s + 1000; time2_m = time2_m - 1; } } if(timer == 4){ timer = 3; RED_LED = 0; time2_m = millis() / 1000 - time0_m; time2_s = millis() % 1000 - time0_s; if(time2_s < 0){ time2_s = time2_s + 1000; time2_m = time2_m - 1; } } } if(value3 == 1){ if(timer == 0){ RED_LED = 1; GREEN_LED = 0; time1_m = 0; time1_s = 0; arrow = 1; pu = 0; pd = 0; } if(timer == 1){ timer = 2; } if(timer == 2){ time1_m = millis() / 1000 - time0_m; time1_s = millis() % 1000 - time0_s; if(time1_s < 0){ time1_s = time1_s + 1000; time1_m = time1_m - 1; } } if(timer == 3){ timer = 4; } if(timer == 4){ if(millis() % 2000 >= 1000){ time1_m = millis() / 1000 - time0_m; time1_s = millis() % 1000 - time0_s; if(time1_s < 0){ time1_s = time1_s + 1000; time1_m = time1_m - 1; } RED_LED = 0; } else{ time1_m = time2_m; time1_s = time2_s; RED_LED = 1; } } } Serial.println( time1_m ); if(arrow == 0){ if(millis() % 1000 <= 200){ pu = 1; pd = 1; } else{ pu = 0; pd = 0; } } t001 = time1_s / 10; t1 = time1_m % 60; t60 = time1_m / 60; n6 = t001 % 10; n5 = (t001 - t001 % 10) / 10; n4 = t1 % 10; n3 = (t1 - t1 % 10) / 10; n2 = t60 % 10; n1 = (t60 - t60 % 10) / 10; if(value1 == 0){ digitalWrite(LATCH, LOW); shiftOut(DATA, CLOCK, LSBFIRST, 228-(mat_LCD[0][n6]%4)*32+GREEN_LED*16+RED_LED*8); shiftOut(DATA, CLOCK, LSBFIRST, 255-(mat_LCD[0][n3]%2)*128-mat_LCD[0][n4]*16-mat_LCD[0][n5]*2-(mat_LCD[0][n6]-mat_LCD[0][n6]%4)/4); shiftOut(DATA, CLOCK, LSBFIRST, 255-mat_LCD[0][n1]*32-mat_LCD[0][n2]*4-(mat_LCD[0][n3]-mat_LCD[0][n3]%2)/2); digitalWrite(LATCH, HIGH); delay(1); digitalWrite(LATCH, LOW); shiftOut(DATA, CLOCK, LSBFIRST, 226-(mat_LCD[1][n6]%4)*32+GREEN_LED*16+RED_LED*8); shiftOut(DATA, CLOCK, LSBFIRST, 255-(mat_LCD[1][n3]%2)*128-mat_LCD[1][n4]*16-mat_LCD[1][n5]*2-(mat_LCD[1][n6]-mat_LCD[1][n6]%4)/4); shiftOut(DATA, CLOCK, LSBFIRST, 255-mat_LCD[1][n1]*32-mat_LCD[1][n2]*4-(mat_LCD[1][n3]-mat_LCD[1][n3]%2)/2); digitalWrite(LATCH, HIGH); delay(1); digitalWrite(LATCH, LOW); shiftOut(DATA, CLOCK, LSBFIRST, 225-(mat_LCD[2][n6]%4)*32+GREEN_LED*16+RED_LED*8-pu*32); shiftOut(DATA, CLOCK, LSBFIRST, 255-(mat_LCD[2][n3]%2)*128-mat_LCD[2][n4]*16-mat_LCD[2][n5]*2-(mat_LCD[2][n6]-mat_LCD[2][n6]%4)/4-p3*128-p4*16-p5*2-arrow*8-pd); shiftOut(DATA, CLOCK, LSBFIRST, 255-mat_LCD[2][n1]*32-mat_LCD[2][n2]*4-(mat_LCD[2][n3]-mat_LCD[2][n3]%2)/2-p1*32-p2*4); digitalWrite(LATCH, HIGH); delay(1); digitalWrite(LATCH, LOW); shiftOut(DATA, CLOCK, LSBFIRST, 3+(mat_LCD[0][n6]%4)*32+GREEN_LED*16+RED_LED*8); shiftOut(DATA, CLOCK, LSBFIRST, (mat_LCD[0][n3]%2)*128+mat_LCD[0][n4]*16+mat_LCD[0][n5]*2+(mat_LCD[0][n6]-mat_LCD[0][n6]%4)/4); shiftOut(DATA, CLOCK, LSBFIRST, mat_LCD[0][n1]*32+mat_LCD[0][n2]*4+(mat_LCD[0][n3]-mat_LCD[0][n3]%2)/2); digitalWrite(LATCH, HIGH); delay(1); digitalWrite(LATCH, LOW); shiftOut(DATA, CLOCK, LSBFIRST, 5+(mat_LCD[1][n6]%4)*32+GREEN_LED*16+RED_LED*8); shiftOut(DATA, CLOCK, LSBFIRST, (mat_LCD[1][n3]%2)*128+mat_LCD[1][n4]*16+mat_LCD[1][n5]*2+(mat_LCD[1][n6]-mat_LCD[1][n6]%4)/4); shiftOut(DATA, CLOCK, LSBFIRST, mat_LCD[1][n1]*32+mat_LCD[1][n2]*4+(mat_LCD[1][n3]-mat_LCD[1][n3]%2)/2); digitalWrite(LATCH, HIGH); delay(1); digitalWrite(LATCH, LOW); shiftOut(DATA, CLOCK, LSBFIRST, 6+(mat_LCD[2][n6]%4)*32+GREEN_LED*16+RED_LED*8+pu*32); shiftOut(DATA, CLOCK, LSBFIRST, (mat_LCD[2][n3]%2)*128+mat_LCD[2][n4]*16+mat_LCD[2][n5]*2+(mat_LCD[2][n6]-mat_LCD[2][n6]%4)/4+p3*128+p4*16+p5*2+arrow*8+pd); shiftOut(DATA, CLOCK, LSBFIRST, mat_LCD[2][n1]*32+mat_LCD[2][n2]*4+(mat_LCD[2][n3]-mat_LCD[2][n3]%2)/2+p1*32+p2*4); digitalWrite(LATCH, HIGH); delay(1); } if(value1 == 1){ digitalWrite(LATCH, LOW); shiftOut(DATA, CLOCK, LSBFIRST, 0); shiftOut(DATA, CLOCK, LSBFIRST, 0); shiftOut(DATA, CLOCK, LSBFIRST, 0); digitalWrite(LATCH, HIGH); delay(1); } }

n1~6が数字それぞれの桁の数字、p1~5,pu,pdが点、arrowが右側にある←です。これらをいじれば簡単に出力できます。

終わりに

このデバイスを作ったことで、素人でも調べて試行錯誤すれば意外といろいろなものが動かせる思えるようになりました。一方で、事前に調べて準備する重要さも実感しました。

2
ysys_Baのアイコン画像
東京の大学の学生です。3DCADと電子工作の勉強中です。
ysys_Ba さんが 2021/02/28 に 編集 をしました。 (メッセージ: 初版)
ysys_Ba さんが 2021/02/28 に 編集 をしました。
ysys_Ba さんが 2021/02/28 に 編集 をしました。
ログインしてコメントを投稿する