目次

LEDを点滅

 「Learning By Doing」の第4章は、LED点滅をテーマにしています。

 書籍内容に沿って、日本人の学生が利用できるように説明します。

 ワンチップマイコンを利用するためには、ピンアサインが
 どうなっているのかを調べて、入出力方向を決めなければ
 なりません。

 利用するチップのピンアサインは、以下。



 ピンアサインから、ポートA、Bがあることがわかります。

 ポートAは8ビットあるように見えますが、発振子接続や
 リセットに利用すると、5ビットしか使えません。


 マイコン内蔵モジュール(デジタル回路)を利用するには
 対応するレジスタに値を書込むか、レジスタ値を読込みか
 のどちらかで、対応します。

 ポートA、Bの入出力を指定するレジスタは、TRISA、TRISB。
 ポートA、Bの状態は、レジスタPORTA、PORTBの入出力で把握
 できます。



 これらは、データシートを読むと得られる情報。

 レジスタTRISA、TRISBの各ビットは、1か0を設定。
 1が入力設定、0が出力設定になってます。

 1はInputのIから、0はOutputの0から連想すればOK。

 ポートA、Bをどちらも全入力に設定するとき
 各ビットの値を次のように設定。

 mikroCでは、C言語の仕様を拡張し、ビットごとの入出力設定が
 できるようになっています。この仕様を使うと、1ビット毎に
 入出力を設定できます。

    TRISA.B4 = 1 ;
    TRISA.B3 = 1 ;
    TRISA.B2 = 1 ;
    TRISA.B1 = 1 ;
    TRISA.B0 = 1 ;
    TRISB.B7 = 1 ;
    TRISB.B6 = 1 ;
    TRISB.B5 = 1 ;
    TRISB.B4 = 1 ;
    TRISB.B3 = 1 ;
    TRISB.B2 = 1 ;
    TRISB.B1 = 1 ;
    TRISB.B0 = 1 ;

 上記の記述では、行数が増えるので2進、10進、16進で
 設定できるようになっています。

    TRISA = 0b00011111 ;
    TRISB = 0b11111111 ;

    TRISA = 0x1f ;
    TRISB = 0xff ;

 レジスタPORTA、PORTBは、ポートの値を反映するので
 入力と出力では、次のように記述。

    tmp = PORTA ;
    PORTB = tmp ;

 ポートA、Bをすべて出力にし、ポートBの0ビット目に
 1を出力するプログラムを作ってみると、以下。

    TRISA = 0b00000000 ;
    TRISB = 0b00000000 ;
    PORTB = 0b00000001 ;

    TRISA = 0x00 ;
    TRISB = 0x00 ;
    PORTB = 0x01 ;

 例題には、ポートBの7ビット目にLEDを接続して
 おいて、点滅させる処理がありました。



 回路図の中にある抵抗値は、E24系列の抵抗を使うと
 470Ωあるいは510Ωになります。

 LEDに電流を流すなら、1mAから10mAが相場。
 また順方向電圧降下は、赤、緑、黄で2V。
 (白色や青色は、3.2Vから3.6V程度です。)

 これらの情報から電流制限抵抗の値を計算します。

 R = (5V - 2V)/1mA  = 3000mV / 1mA  = 3kΩ
 R = (5V - 2V)/10mA = 3000mV / 10mA = 300Ω
 R = (3V - 2V)/1mA  = 1000mV / 1mA  = 1kΩ
 R = (3V - 2V)/10mA = 1000mV / 10mA = 100Ω

 マイコンの出力ピンから流せる電流は少なく、そして
 出力電圧は低いと考えると、1kΩがよいことに。
 ただし、LEDが点灯していることを確認できるよう
 1kΩの半分の500Ωとします。

 ブレッドボードを利用し、LEDを点滅させるには
 電源、水晶振動子を接続します。

 そのための回路は、以下。



 ポートBのビット7に接続したLEDの点滅用
 動作フローは、次のようにします。



 コンピュータは言葉で記述された動作を繰り返すので
 人間が言葉で事細かく指示する必要があります。

 動作フローに、対応するステートメントを追加。



 プログラムに変換。

void main(void)
{
  /* initialize PORT */
  TRISB = 0x00 ;
  /* endless loop */
  while (1) {
    PORTB = 0x80 ;
    Delay_ms(500);
    PORTB = 0x80 ;
    Delay_ms(500);
  }
}

 無限ループの構成に、whileを利用。

 mikroCのプロジェクトを作成し、コンパイル、リンク後
 winpicでチップに書込み、動作確認します。

 テスト基板にLEDを接続して確認。



 同じ内容を、次のプログラムでも実現できます。

#define OFF 0
#define ON  OFF+1

#define FIVE 500

typedef unsigned char UBYTE ;

UBYTE state ;

/* prototype */
void usr_init(void);

void main(void)
{
  /* initialize PORT */
  usr_init();
  /* endless loop */
  while (ON) {
    /* impress */
    PORTB = state & ON ;
    /* delay */
    Delay_ms(FIVE);
    /* update state */
    state++ ;
  }
}

void usr_init(void)
{
  /* initial value */
  PORTB = OFF ;
  /* direction */
  TRISB = 0x00 ;
  /* clear state counter */
  state = 0 ;
}

 8本のLEDを利用し、方向指示器を実現する
 ファームウエアを作成します。
 回路図は、以下。



 回路図から、ポートBを出力で利用とわかります。

 方向指示器を実現するには、点灯しているLEDが一方向に
 ずれていけばよいと考えて、シフト処理を使います。

 シフト処理は、演算子の「<<」を使用。

 1を点灯、0を消灯とみなすと、以下のように
 点灯しているLEDが、順送りで変わっていけばよい
 と考えます。

 0 0 0 0 0 0 0 1
        ↓
 0 0 0 0 0 0 1 0
        ↓
 0 0 0 0 0 1 0 0
        ↓
 0 0 0 0 1 0 0 0
        ↓
 0 0 0 1 0 0 0 0
        ↓
 0 0 1 0 0 0 0 0
        ↓
 0 1 0 0 0 0 0 0
        ↓
 1 0 0 0 0 0 0 0
        ↓
      はじめにもどる

 シフト演算利用には、変数に1を入れておき
 シフトしていけば、目的の処理を実現可能。

 シフトの回数は、8回だとし、次のコードで実現。

  /* initial value */
  j = 1 ;
  /* loop */
  for ( i = 1 ; i <= 8 ; i++ ) {
    /* impress */
    PORTB = j ;
    /* shift */
    j <<= i ;
    /* delay */
    Delay_ms(50);
  }

 指定回数の反復となるので、for文を利用。

 全体のフローは、以下。



 プログラム全体は、次のようになります。

#define OFF 0
#define ON  OFF+1

#define FIVE 50

typedef unsigned char UBYTE ;

UBYTE state ;

/* prototype */
void usr_init(void);

void main(void)
{
  UBYTE i ;
  UBYTE j ;
  /* initialize PORT */
  usr_init();
  /* endless loop */
  while (ON) {
    /* initial value */
    j = 1 ;
    /* loop */
    for ( i = 1 ; i <= 8 ; i++ ) {
      /* impress */
      PORTB = j ;
      /* shift */
      j <<= i ;
      /* delay */
      Delay_ms(50);
    }
  }
}

void usr_init(void)
{
  /* initial value */
  PORTB = OFF ;
  /* direction */
  TRISB = 0x00 ;
}

 方向指示を、関数で定義することもできます。

#define OFF 0
#define ON  OFF+1

#define FIVE 50

typedef unsigned char UBYTE ;

/* prototype */
void usr_init(void);
void led_dir(void);

void main(void)
{
  /* initialize PORT */
  usr_init();
  /* endless loop */
  while (ON) {
    led_dir() ;
  }
}

void usr_init(void)
{
  /* initial value */
  PORTB = OFF ;
  /* direction */
  TRISB = 0x00 ;
}

void led_dir(void)
{
  UBYTE i ;
  UBYTE j ;
  /* initial value */
  j = 1 ;
  /* loop */
  for ( i = 1 ; i <= 8 ; i++ ) {
    /* impress */
    PORTB = j ;
    /* shift */
    j <<= i ;
    /* delay */
    Delay_ms(FIVE);
  }
}

 関数led_dirの中で、変数i、jの使い方を
 変えると、どんな方向指示器になるのかを
 実際にやってみればよいでしょう。

  for ( i = 1 ; i <= 3 ; i++ ) {
    /* impress */
    PORTB = j ;
    /* shift */
    j <<= 2 ;
    /* delay */
    Delay_ms(FIVE);
  }

 シフト演算子を使わずに、配列に入れたパターンを
 引き出して出力することも可能。

#define OFF 0
#define ON  OFF+1

#define FIVE 50

typedef unsigned char UBYTE ;

UBYTE state ;
UBYTE pat[8] ;

/* prototype */
void usr_init(void);
void led_dir(void);

void main(void)
{
  /* initialize PORT */
  usr_init();
  /* endless loop */
  while (ON) {
    led_dir() ;
  }
}

void usr_init(void)
{
  /* initial value */
  PORTB = OFF ;
  /* direction */
  TRISB = 0x00 ;
  /* store bit pattern */
  *(pat+0) = 0x01 ; *(pat+1) = 0x02 ;
  *(pat+2) = 0x04 ; *(pat+3) = 0x08 ;
  *(pat+4) = 0x10 ; *(pat+5) = 0x20 ;
  *(pat+6) = 0x40 ; *(pat+7) = 0x80 ;
}

void led_dir(void)
{
  /* loop */
  for ( state = 0 ; state < 8 ; state++ ) {
    /* impress */
    PORTB = *(pat+state) ;
    /* delay */
    Delay_ms(FIVE);
  }
}

 配列を利用すると、方向指示器の点灯パターンを
 次のように変更した場合、パターンをあわせると
 なります。

 0 0 0 0 0 0 0 1
        ↓
 0 0 0 0 0 0 1 1
        ↓
 0 0 0 0 0 1 1 1
        ↓
 0 0 0 0 1 1 1 1
        ↓
 0 0 0 1 1 1 1 1
        ↓
 0 0 1 1 1 1 1 1
        ↓
 0 1 1 1 1 1 1 1
        ↓
 1 1 1 1 1 1 1 1
        ↓
      はじめにもどる

 点灯パターンを上のように変えた場合
 配列の内容初期化は、以下。

  *(pat+0) = 0x01 ; *(pat+1) = 0x03 ;
  *(pat+2) = 0x07 ; *(pat+3) = 0x0f ;
  *(pat+4) = 0x1f ; *(pat+5) = 0x3f ;
  *(pat+6) = 0x7f ; *(pat+7) = 0xff ;

 状態変数を用意して、配列に入れるパターンを
 変える方式は、応用範囲が広いので、開発時間
 を短縮する場合に採用されることが多いです。


目次

inserted by FC2 system