7セグメントの制御
7セグメントLEDとは,7セグメントディスプレイとも呼ばれ,図1のように7本のバー(セグメント)で構成されている.それぞれのセグメントにはLEDが内蔵されており,どのセグメントを点灯させるかで,数値を表示させることができるものである.
図1はイメージであり,各セグメント内のLEDがどのような向きで配置されているかは不明である.
図1:7セグメントの構成イメージ
各セグメントには,a 〜 g までの名前が付けられている.例えば,数字の「1」を表示させたいときは,a ,b のセグメントを点灯させることになる.
7セグメントLEDには,7つのLEDが搭載されいる.LED単体では,アノードからカソードに電流を流すことで点灯する.7つのLEDが独立して存在していては配線などの問題があるため,一般的には図2のような2種類の7セグメントLEDが存在している.
図2:アノードコモンとカソードコモン
図2の左がLEDのアノードがひとつに束ねられたアノードコモンタイプの7セグメントLEDである.右がカソードがひとつに束ねられたカソードコモンタイプの7セグメントLEDである.
今回のMEMEsに搭載されている7セグメントLEDは,カソードコモンタイプが3つ搭載されている.
図3に示すように,7セグメントLEDのアノードは,マイコンと直接接続されておらず,2進数を10進数に変換するBCD(Binary Coded Decimal)ICを介して接続されている.そのため,マイコンからは,0 〜 9 の数値を出力すれば,IC が自動的に数値に対応したセグメントを選択する仕組みとなっている.そして,カソード部分をGNDに接続することで,LEDのアノードとカソード間に電位差が生まれて当該のセグメントが点灯する仕組みとなっている.
図3:7セグメントLEDとマイコンとの接続概要
図4は,点灯の手順を示している.まず,マイコンとICに接続されている端子を出力ポートにして,表示させたい数値を出力する.ICは,それを解読して点灯させるセグメントを選択して電圧を加える.その後,マイコンからスイッチをオンしてGNDに対して電流を流すことで当該のセグメントが点灯することになる.
図4:7セグメントLEDの点灯手順
図5に実際の回路構成図を示す.ICからの情報を3つの7セグメントLEDに同時に送られるが,どの7セグメントLEDを選択するかを Q1 〜 Q3 で選択する.例えば,1 を出力して,Q2 をオン(Q1,Q3はオフ)する.次に,2を出力して,Q1 をオン(Q2,Q3はオフ)する.最後に3を出力してQ3をオン(Q1,Q2はオフ)する.これを繰り返すことで,この3つの7セグメントLEDには,「123」と表示されているように見える.
実は,人間の目には認識できない程の速度で表示を切り替えているのである.これを「ダイナミック点灯」と呼ぶ.通常,十数ミリ程度の感覚で表示を切り替えれば人間の目には残像が残り表示を切り替えているようには見えない.
テレビのアニメと同じ原理である.テレビの場合,1秒間に約30コマの画像をぱらぱら漫画のように表示させて,動画のように見せているのである.
図5:実際の接続回路構成図
プログラムリスト1は,単に,任意の数値を一番右の7セグメントLED(U18)に表示させるだけのプログラムである.
実行結果は,図6である.プログラム中の 0x06 の値を変えることで表示が変化する.9 より大きな値の場合にはどうなるのか試してみるとよい.
#include "iodefine.h" #define DIG1 (PE.DR.BIT.B3) void init_peior(void); void init_paior(void); void main(void) { init_peior(); init_paior(); PA.DR.BYTE.HL &= 0xF0; PA.DR.BYTE.HL |= 0x06; DIG1 = 1; while(1); } void init_peior(void) { PFC.PEIORL.BIT.B3 = 1; } void init_paior(void) { PFC.PAIORH.BYTE.L |= 0x0F; }
プログラムリスト1:任意の値を表示
図6:実行結果
プログラムリスト2は,スイッチと連動させて,インクリメントする例である.スイッチは押して離したときに値をインクリメントするようになっている.
ここで,上述したダイナミック点灯を使い,一番左の7セグメントLED(U16)と一番右の7セグメントLED(U18)を使用している.スイッチは,SW6とSW4を使用している.
動作については,動画1を参照してもらいたい.プログラムリスト2をビルドして実行すると動画1のように動作するはずである.
#include "iodefine.h" #include "typedefine.h" #define DIG1 (PE.DR.BIT.B3) #define DIG3 (PE.DR.BIT.B1) #define SW4 (PD.DR.BIT.B16) #define SW6 (PD.DR.BIT.B18) #define WAIT_TM (10000) void init_peior(void); void init_paior(void); void init_pdior(void); void digit_disp(_UINT, _UBYTE, _UBYTE); void main(void) { _UBYTE cnt1, cnt3; cnt1 = 0; cnt3 = 0; init_peior(); init_paior(); init_pdior(); PA.DR.BYTE.HL &= 0xF0; PA.DR.BYTE.HL |= 0x00; while(1) { if(SW4) { while(SW4) { digit_disp(WAIT_TM, cnt1, cnt3); } cnt1 ++; if(cnt1 == 10) { cnt1 = 0; } } if(SW6) { while(SW6) { digit_disp(WAIT_TM, cnt1, cnt3); } cnt3 ++; if(cnt3 == 10) { cnt3 = 0; } } digit_disp(WAIT_TM, cnt1, cnt3); } } void digit_disp(_UINT tm, _UBYTE data1, _UBYTE data3) { _UINT i; PA.DR.BYTE.HL &= 0xF0; PA.DR.BYTE.HL |= data1; DIG1 = 1; DIG3 = 0; for(i = 0; i < tm; i ++); PA.DR.BYTE.HL &= 0xF0; PA.DR.BYTE.HL |= data3; DIG3 = 1; DIG1 = 0; for(i = 0; i < tm; i ++); } void init_peior(void) { PFC.PEIORL.BIT.B1 = 1; PFC.PEIORL.BIT.B3 = 1; } void init_paior(void) { PFC.PAIORH.BYTE.L |= 0x0F; } void init_pdior(void) { PFC.PDIORH.BIT.B16 = 0; PFC.PDIORH.BIT.B18 = 0; }
プログラムリスト2:SWと連動して7セグメントを制御
動画1:プログラムリスト2の動作
プログラムリスト3は,単純にカウントアップするプログラムである.3つの7セグメントLEDの真ん中(U17)と一番右(U18)の7セグメントLEDを数字の十の位と一の位に見立てて,インクリメントする.99の次は,00に戻りインクリメントを繰り返す.
実行の様子は,動画2を参照すること.
#include "iodefine.h" #include "typedefine.h" #define DIG1 (PE.DR.BIT.B3) #define DIG2 (PE.DR.BIT.B2) #define WAIT_TM (10000) #define CNT_TM (30) void init_peior(void); void init_paior(void); void digit_disp(_UINT, _UBYTE, _UBYTE); void main(void) { _UBYTE cnt, cnt1, cnt2; _UINT i; cnt = 0; cnt1 = 0; cnt2 = 0; init_peior(); init_paior(); PA.DR.BYTE.HL &= 0xF0; PA.DR.BYTE.HL |= 0x00; while(1) { cnt ++; if(cnt == 100) { cnt = 0; } cnt2 = cnt / 10; cnt1 = cnt % 10; for(i = 0; i < CNT_TM; i++) { digit_disp(WAIT_TM, cnt1, cnt2); } } } void digit_disp(_UINT tm, _UBYTE data1, _UBYTE data2) { _UINT i; PA.DR.BYTE.HL &= 0xF0; PA.DR.BYTE.HL |= data1; DIG1 = 1; DIG2 = 0; for(i = 0; i < tm; i ++); PA.DR.BYTE.HL &= 0xF0; PA.DR.BYTE.HL |= data2; DIG2 = 1; DIG1 = 0; for(i = 0; i < tm; i ++); } void init_peior(void) { PFC.PEIORL.BIT.B1 = 1; PFC.PEIORL.BIT.B2 = 1; } void init_paior(void) { PFC.PAIORH.BYTE.L |= 0x0F; }
プログラムリスト3:カウントアッププログラム
動画2:プログラムリスト3の実行結果
上記3つのプログラムリストを含んだワークスペースを下記よりダウンロードして,ビルドして,実行させて動画を確認せよ.
演習問題
- プログラムリスト1を参考にしてscanf 関数を使いhterm から 0 ~ 9 までの数値を入力し,動画3のようにその値を U18 の7 セグメントLEDに表示するプログラムを作成せよ.
- プログラムリスト1と2を参考にして,初期値を 0 とし,SW6 を押して離したら値をインクリメントし,SW5を押して離したら値をデクリメントする動画4のようなプログラムを作成せよ.ただし,インクリメントの際,9 の次は,0 とし,デクリメントの際, 0 の次は 9 とする.
- 上記のプログラムに動画5のようにSW4 を押して離すと 0 に戻す機能を付け加えよ.
- プログラムリスト2に動画6のようにSW5 を押して離すとU17がインクリメントする機能を付け加えよ.
- プログラムリスト3を参考にして,動画7のように999 までカウントしたら,0 に戻り,再びカウントアップするプログラムを作成せよ.
- 上記のプログラムに,動画8のようにSW6を押している間値をデクリメントする機能を付け加えよ.もちろん,SW6を離したら再びインクリメントするようにしておくこと.
難問に挑戦
【問題】3つの7セグメントLEDを左から,百の位,十の位,一の位と考える.そして,SW6を百の位の7セグメントLEDがに対応させ,SW5を十の位の7セグメントLEDに対応させ,SW4を一の位の7セグメントLEDに対応させる.そして,SW6〜SW4を押して離すと対応した位の7セグメントLEDがカウントアップする.このとき,9 の次は 0 とする.
適当な値を7セグメントLEDに与えたら,SW6〜SW4の3つのタクトスイッチを押して離す.このとき,同時でなくても構わない.3つのタクトスイッチを押して離すと3つの7セグメントLEDに表示されている値を3桁の数値とみなして,カウントダウンを開始する.カウントダウンして,0になると,右上のLEDが点滅する.
動作の詳細は,動画9を参照すること
タクトスイッチを2つ押して離した場合など,例外については特に考えなくて良い.
動画9:値を設定して,タクトスイッチでカウントダウンスタート