目次
前
次
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をどちらも全入力に設定するとき
各ビットの値を次のように設定。
- 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
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 ;
状態変数を用意して、配列に入れるパターンを
変える方式は、応用範囲が広いので、開発時間
を短縮する場合に採用されることが多いです。
目次
前
次