マトリクスLEDの表示方法の原理

DD_matrix.png

※データシート→http://akizukidenshi.com/download/ds/optosupply/OSL641501-XX.pdf (-BRAのほう)

マトリクスLEDは、↑のようにたくさんのLEDが、格子状に縦横につながっています。
すべてのLEDを一斉に点灯/消灯をすることはできませんので、1列ずつ、表示させます(ダイナミック駆動)。
これは、以下のような手順で、1列ずつ、各8個のLEDを点灯/消灯する、ことを素早く順に行うことで、残像効果よって「すべての列が点灯しているように見える」というものです。

  1. COL1のみ"L"、COL2〜8を"H"とする。このとき、一番左の列の縦並び8個のLEDのうち、点灯させたいLEDがつながっている横の線(ROW)を"H"、消灯したいLEDがつながっているものを"L"とする。これにより、一番左の列の8個のLEDを、点灯/消灯でき、それより右の列のLEDはすべて消灯する。(※LEDは順方向に電圧をくわえたときのみ点灯するため)
  2. 少し時間がたってから、COL2のみ"L"、COL1,3〜8を"H"とする。このとき、左から2番目の列の縦並び8個のLEDのうち、点灯させたいLEDがつながっている横の線(ROW)を"H"、消灯したいLEDがつながっているものを"L"とする。これにより、左から2番目の列の8個のLEDを、点灯/消灯でき、それ以外の列のLEDはすべて消灯する。
  3. 同様に、COL3〜COL8まで繰り返し、その後、COL1から繰り返す。
    これを、例えば1列あたり3msごとに行えば、すべての列の表示が終わるまでに3ms×8=24msですので、1秒間に40回ほど表示を更新することができることになります。(いわゆるフレームレートが毎秒40フレームということ)

タイマ割り込み

このような動作は、メインプログラムの動作とは独立に行った方が、メインプログラムの記述が楽ですので、タイマ割り込みという手法を使って、メインプログラムとは独立に行うことにします。
これは、一定時間ごとに、指定した関数が自動的に呼び出される、というもので、一時的にメインプログラムの動作は中断されますが、事実上、メインプログラムは、このようなLED表示動作を気にすることなく、記述・動作することができます。
このタイマ割り込みは、Timer8ユーザモジュールを用います。

DD_timer8.png

↑のようにTimer8_1モジュールのパラメータを設定しておきます。
この中の「InterruptType」が、このTimer8_1が割り込みを起こす条件で、この場合は"Terminal Count"、つまりタイマのカウントが終了したとき、ということになります。タイマのカウントは、VC3をクロック(計算すると76.8kHz)として、Period(周期)が255まで、とありますので、タイマのカウントが終了するまでの時間は、1/(76.8kHz÷255)=3.3ms、となりますので、約3msごとに、タイマ割り込みが発生します。
タイマ割り込みが発生したときには、対応する関数(割り込み処理関数: Interrupt Service Routine; ISR)が呼ばれますが、PSoC1では、「モジュール名_ISR()」という関数名、と決まっています。少しおまじないを加えて、以下のように呼ばれる関数を記述すれば、この関数が約3msごとに、自動的に呼ばれることになります。

#pragma interrupt_handler Timer8_1_ISR
void Timer8_1_ISR()
{
  ....
}

ダイナミック駆動のLED制御の準備

ダイナミック駆動では、行方向(ROW1〜8)と列方向(COL1〜8)を、それぞれ"H"/"L"とする必要があります。
そこでPSoC1のモジュールとして、それぞれに対応するLEDを配置しておきましょう。ちょっと数が多い(合計16個)ですが、がんばって。

DD_led1.png

↑行方向は、こんな感じでLED_R1〜LED_R8を置きます。それぞれのPortとPinは、実際にマトリクスLEDがつながっているポート番号を設定します。
行方向は、点灯したい行を"H"にしますので、ActiveHigh、つまりLED_R1_On()で対応する出力ピンが"H"となるようにしておきます。

DD_led2.png

↑列方向も、同様にLED_C1〜LED_C8を置き、PortとPinを、実際にマトリクスLEDがつながっているポート番号を設定します。
列は、点灯したい列を"L"にしますので、ActiveLow、つまりLED_C1_On()で対応する出力ピンが"L"となるようにしておきます。

ダイナミック駆動の全体

以上の準備をふまえて、ダイナミック駆動の全体プログラムは、例えば以下のような感じになります。
pat[]に、各列で表示したいON/OFFのパターンを設定しておきます。例えばpat[0]=0x01(二進数で00000001)ならば、1列目では、ROW1に対応するLEDが点灯することになります。
変数colは、各タイマ割り込みで表示するべき列番号で、タイマ割り込みが呼ばれるごとに、その値に応じた列の表示パターンであるpat[col]に応じて、点灯するべきLEDの行のみOn("H")としています。その後、colを1ずつ増やし、8列の次に1列に戻しています。
main()では、表示するべきパターンの設定をしてタイマ割り込みが起こるように設定したあとは、何もしなくても、自動的にタイマ割り込みでマトリクスLEDのダイナミックが行われるので、main()の処理は、とても楽になります。

BYTE pat[8];
BYTE col;

#pragma interrupt_handler Timer8_1_ISR
void Timer8_1_ISR()
{
  LED_C1_Off(); LED_C2_Off(); LED_C3_Off(); LED_C4_Off();
  LED_C5_Off(); LED_C6_Off(); LED_C7_Off(); LED_C8_Off();
  if (pat[col] & 0x01) LED_R1_On(); else LED_R1_Off();
  if (pat[col] & 0x02) LED_R2_On(); else LED_R2_Off();
  if (pat[col] & 0x04) LED_R3_On(); else LED_R3_Off();
  if (pat[col] & 0x08) LED_R4_On(); else LED_R4_Off();
  if (pat[col] & 0x10) LED_R5_On(); else LED_R5_Off();
  if (pat[col] & 0x20) LED_R6_On(); else LED_R6_Off();
  if (pat[col] & 0x40) LED_R7_On(); else LED_R7_Off();
  if (pat[col] & 0x80) LED_R8_On(); else LED_R8_Off();
  switch (col){
    case 0 : LED_C1_On(); break;
    case 1 : LED_C2_On(); break;
    case 2 : LED_C3_On(); break;
    case 3 : LED_C4_On(); break;
    case 4 : LED_C5_On(); break;
    case 5 : LED_C6_On(); break;
    case 6 : LED_C7_On(); break;
    case 7 : LED_C8_On(); break;
  }
  col = col + 1; if (col == 8) col = 0;
}


void main(void)
{
  pat[0] = 0x01; // 00000001
  pat[1] = 0x02; // 00000010
  pat[2] = 0x04; // 00000100
  pat[3] = 0x08; // 00001000
  pat[4] = 0x10; // 00010000
  pat[5] = 0x20; // 00100000
  pat[6] = 0x40; // 01000000
  pat[7] = 0x80; // 10000000

  col = 0;

  M8C_EnableGInt ; // Uncomment this line to enable Global Interrupts
  Timer8_1_EnableInt();
  Timer8_1_Start();

  while (1){
  }
}

添付ファイル: fileDD_timer8.png 624件 [詳細] fileDD_led2.png 546件 [詳細] fileDD_matrix.png 739件 [詳細] fileDD_led1.png 581件 [詳細]

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2022-10-02 (日) 11:12:58