あそ~ぶUSB サンプルソース解説・その2

LEDイルミネーションを作る

2010/11/11

Assembly Desk

1. 概要

ここでは、あそ~ぶUSB のサンプルプログラムを解説していきます。

ここではLED点滅を少し進めたLEDイルミネーションを作ります。

USBケーブルを挿し込むと、赤と青のLEDがじわじわと色を変えます。

2色しか無いので、少し寂しいですが、

ちなみに、このプログラムはあそ~ぶUSBにはじめに入ってる物になります。

この文章は、開発環境が既にインストールされている事を前提としてかかれています。

まだ、開発環境を整えて居ない方はこちらを参考にして、まずは開発環境を整えて下さい。

http://a-desk.jp/modules/forum_pic/index.php?cat_id=4

まだ、ファームウェアのビルドの仕方についてはこちらを参考にして下さい。

http://a-desk.jp/modules/forum_pic/index.php?cat_id=3

2. ソースコード解説

2.1 ファイルの構成

”LEDsample”は3つのファイルが登録されています。

“main.c”はmain関数が含まれているソースファイルです。今回のサンプルプログラムはこのファイルだけで記述されています。

“bootload.h”と”rm18f2550 - HID Bootload.lkr”にはブートローダでファームウェアをあそ~ぶUSBへ書き込み出来る様にする為のおまじないが書かれています。

興味があれば読んでみてください。意味が分からなくても全く問題ありません。

2.2 main(void)関数

“main.c”には3つの関数が含まれています。

“isr_high”は高位レベル割り込みの処理を、”isr_low”には低位レベル割り込みの処理を記述します。

ここでは、高位レベル割り込みのみを使用しています。後でその内容を追っていきます。

ちなみに、低位レベル割り込みの方には何も記述されていませんが、関数自体を消してはいけません。

プログラムは“main”から始まります。(厳密には違いますが・・・)

ここから内容を追っていきます。


void main(void)

{

        TRISB = 0;        //PORT Bは全て出力に設定

        LATB = 0;        //PORT Bを全てOFF

//        タイマ0の設定

        OpenTimer0(TIMER_INT_ON & T0_8BIT & T0_SOURCE_INT & T0_PS_1_8);

        WriteTimer0(WRITE_TIMER0_COUNT);

//        割り込み開始

        RCONbits.IPEN = 1;                //割り込み優先付あり

        INTCON2bits.TMR0IP = 1;                //タイマ0を高位レベル割り込みに設定

        INTCONbits.TMR0IE = 1;                //タイマ0割り込み許可

        INTCONbits.GIEH = 1;                //高位レベル割り込みの許可

        

        while(1)

        {

                switch(led_flash_state)

                {

                        case 0:                //赤LEDを0->MAXへ

                                led_duty_red++;

                                if(led_duty_red == LED_DUTY_MAX)

                                        led_flash_state = 1;

                                break;

                        case 1:                //青LEDを0->MAXへ

                                led_duty_blue++;

                                if(led_duty_blue == LED_DUTY_MAX)

                                        led_flash_state = 2;

                                break;

                        case 2:                //赤LEDをMAX->0へ

                                led_duty_red--;

                                if(led_duty_red == 0)

                                        led_flash_state = 3;

                                break;

                        case 3:                //赤LEDを0->MAXへ

                                led_duty_red++;

                                if(led_duty_red == LED_DUTY_MAX)

                                        led_flash_state = 4;

                                break;

                        case 4:                //青LEDをMAX->0へ

                                led_duty_blue--;

                                if(led_duty_blue == 0)

                                        led_flash_state = 1;

                                break;

                        default:

                                break;

                }        

                Delay10KTCYx(MAIN_ROUTINE_CYCLE_TIME);

        }

}


2.2.1 PORT Bの初期化

最初のTRISB=0;はPORT Bの0~7を全て出力として使いますよ。と言う意味になっています。

1は入力、0は出力でビット毎に設定します。

例えば、TRISB = 0x15;とすると、PORT Bの0/2/4だけ入力、後は出力として使いますよ、と言う意味になります。

LATB = 0;は、PORT Bは全て0Vを出力しますよ、と言う意味です。

LATBbits.LATB5=0;の様に、一つづつ指定する書き方も出来ます。

2.2.2 タイマ0

次に、タイマ0の初期化処理が入ります。

        OpenTimer0(TIMER_INT_ON & T0_8BIT & T0_SOURCE_INT & T0_PS_1_8);

これで、タイマ0を次の様に使用する、と言う意味になります。

TIMER_INT_ON

タイマオーバーフロー時に割り込みを発生

T0_8BIT

タイマを8ビットとして使用

T0_SOURCE_INT

内部クロックをカウントする

T0_PS_1_8

8回に1回、カウントする

        WriteTimer0(WRITE_TIMER0_COUNT);

これの命令で、タイマ0の初期をWRITE_TIMER0_COUNTとしています。

WRITE_TIMER0_COUNTはmain.cの先頭あたりに#defineされており、

#define WRITE_TIMER0_COUNT        0x6A        //Timer0の時間

となっています。

タイマ0が0x6Aから数えて、0xFFの次、0x00になった瞬間に割り込みが入ります。

0x6Aから0x00になるまでの時間は

0x100 - 0x6A = 0x96 = 150

1回のカウントが1/12000000秒に1回で、8回に1回カウントされるので、

1/12000000 × 8 × 150 = 1/10000秒

よって、0.0001秒に一回割り込みが入ります。

2.2.3 割り込み開始

IPEN/TMR0IP/TMR0IE/GIEHを設定する事で、割り込みがタイマ0の割り込みが有効になります。

これ以降、0.0001秒毎に割り込みが発生し、isr_high()が呼び出されます。

2.2.4 LED点灯状態変化

while(1)は無限ループです。この中の処理をグルグル繰り返しますよ、と言う意味です。

これを入れておかないと、プログラムが直ぐに終わってしまいます。

このwhile文の中で、LEDの点灯状態を徐々に変化させて行きます。

LEDの明るさはled_duty_red及びled_duty_blueの二つの変数で設定します。

それぞれ、0~100の値を設定出来、0で消灯、100で最高の明るさになります。

50だとその真中位の明るさになる訳です。

また、led_flash_stateはLEDの光り方の移り変わり状態です。

次の様になっています。

led_flash_state

動作

次のled_flash_state

0

赤LEDを0→100

1

1

青LEDを0→100

2

2

赤LEDを100→0

3

3

赤LEDを0→100

4

4

青LEDを100→0

1

最後にDelay10KTCYx(MAIN_ROUTINE_CYCLE_TIME);

で指定時間のウェイトを行います。

MAIN_ROUTINE_CYCLE_TIMEは12になっています。

これは、10msに当たります。

10msに一回、このwhileの中が繰り返される事になります。

Delay10KTCYx(120);はmicrochipが用意しているディレイ関数です。

この命令は引数×10000サイクルだけ待つ、と言う意味です。つまり、ここでは、1200000サイクル分待つ、と言う事になります。

これが具体的にどのくらいの時間になるかと言うと、100msです。

あそ~ぶUSBは内部クロック48MHzで動いています。PIC18Fシリーズは4クロックで1命令なので、一秒間に12000000の命令を実行しています。

ということは、1200000サイクル分の時間と言うのは、0.1秒になるわけです。

ここでは、この命令を5回繰り返していますので、0.5秒待っています。

Delay10KTCYxの引数は0~255なので、このように書いてある訳です。

LATBbits.LATB4 = !LATBbits.LATB4;とLATBbits.LATB5.LATB5 = !LATBbits.LATB5;はそれぞれ0を1に、1を0に反転させています。

LEDが付いていたら消し、消えていたら付けるわけです。

これで、LEDが0.5秒毎に付いたり消えたりするソフトが出来ました。

2.3 isr_high()関数

この関数は高位レベル割り込みが発生した時に呼び出される関数です。

このソースでは、割り込みはタイマ0だけなので、0.0001秒に一回、この関数が呼ばれる事になります。

ここでは、実際のLEDの明るさの調整を行っています。

この関数の中では、led_duty_countと言うカウンタを0から99まで回しています。

この値と先ほどのled_duty_red/led_duty_blueの値を比較して、led_dutyの方が小さければ、LEDをOFFしています。

例えば、while文の中でled_duty_redが30に指定されていたとすると、led_duty_countが0~29の間はLEDはON、30~99の間はLEDがOFFされます。

つまり、0.0030秒LEDがONし、続く0.007秒LEDはOFFします。これで、大体30%の明るさになる事になります。

(人間の目ではこのような高速な点滅は見ることが出来ません)

これで、mainルーチンのwhile文の中でled_duty_red/led_duty_blueを変更すればLEDの明るさを変更する事が出来るようになります。