ここでは、PICに書き込んだプログラムを基板にセットし、実際にLEDを光らせてみます。
「LEDの点滅」プログラム |
---|
// ファイル名 led.c // LEDの点滅 #include <htc.h> __CONFIG(PWRTEN&HS&WDTDIS&UNPROTECT&MCLRDIS&BORDIS&IESODIS&FCMDIS); #define _XTAL_FREQ 20000000 main() { unsigned int i; PORTA = 0; // PORTAを0にする TRISA = 0; // PORTAを出力に設定する ANSEL = 0; // アナログ入力をOFF while(1) { PORTA = ~PORTA; // PORTAを反転 for(i=0; i<100; i++) __delay_ms(10); // 1秒ディレイ } } |
はじめに、// ファイル名 led.cとありますが、頭に//が付く行はコメント文になります。ここでは、先頭に何をするプログラムか分かるようにコメントしています。 コメント文は読み飛ばされるので、プログラムには影響しません。プログラムを作る際、特に長いプログラムではこまめにコメントを記入しておくと便利です。 また、/* ~コメント~ */のように/*と*/で囲むと複数行のコメントを記述することか可能です。
#includeは指定されたファイルの読み込みを行ないます。2行目ではhtc.hというファイルを 読み込むよう指定してます。C言語では使用する関数はすべてそのプログラムの中でで定義しなければなりませんが、その指定されたファイルにはよく使う関数などがあらかじめ定義されているので、これを読み込むことによりプログラム中に関数の定義をしなくても、使用することができるようになります。ここでは、Hitech-CでのPICの定義を読み込んでいます。
4行目にある__CONFIG はPICのハードウエア的な動作のモードを設定します。これは毎回プログラムと一緒に書き込む必要があります。
PWRTEN |
パワーアップタイマーを使用する。パワーアップタイマーとは、周辺回路を安定しさせてるためのウェイト機能。 |
HS |
外部クロック発振モードを一番高いゲインで設定。 |
WDTDIS |
ウォッチドッグタイマーをOFFに設定。 |
UNPROTECT |
書き込んだコードにプロテクトをかけない。 |
MCLRDIS |
リセットピン(RA3)はI/Oピンとして使用する。 |
BORDIS |
ブラウンアウトリセットを無効にする。これは電圧が下がり動かなくなる前にプログラムのリセットを行ない中断する機能。電圧が安定している時は無効にしておく。 |
IESODIS |
Internal Extarnal Switchoverモードを無効。クロックの2段階(内外部)スタートアップ機能を無効にする。 |
FCMDIS |
Fail-Safe Clock Monitorは外部のクロックが動作しないとき、内部クロックさせる機能だが、これを無効にする。 |
#defineでは定数を定義しています。またはマクロ定義するともいいます。
形式は次のようになります。
#define 定数名 数値
このように記述すると数値の値が定数名に置き換えられます。
上記のプログラムでは_XTAL_FREQは20000000に置き換えられ、プログラム上に_XTAL_FREQがある場合は20000000に置換されます。
この_XTAL_FREQはあとに出てくる__delay_ms(
)マクロを使用する為に必要で、PICの外部クロック20MHzの値を示しています。
次はmain関数の定義です。はじめのうちはこのmain関数の{ }中に処理するプログラムを記述していきます。
C言語のプログラムでは複数の関数を組み合わせて作っていきますが、このmain関数は必ず必要でここから処理が実行されていきます。
main() { 関数の中身(処理) } |
ここからはmain関数の中身をみていきます。unsigned int i ; はプログラム中で使用する変数の宣言をおこなっています。
変数宣言の形式は次のようになります。
変数の型 変数名 ;
基本データの型にはint型、float型、double型、char型、void型などがあります。各型の意味は以下の表で確認してください。
データ型 |
意味 |
大きさ |
扱える数値範囲 |
int |
符号付き整数型 | 4バイト | -2,147,483,648 ~ 2,147,483,647 |
float |
浮動小数点数 | 4バイト | 6桁分の精度 |
double |
倍精度浮動小数点数 | 8バイト | 10桁分の精度 |
char |
文字 | 1バイト | -128 ~ 127 |
void |
値なし |
int i ; と記述するとi
は符号付整数型の変数であるといえます。したがって、int型はそのまま使うと正数も負数も扱えますが、
今回のように「unsigned」という型修飾子といわれるものを頭に付けると負数を扱えないようにすることができます。
unsignedを使うことによって、符号を記憶しておく必要がなくなるため、より大きい正数が扱えるようになります。
データ型 |
大きさ |
扱える数値範囲 |
unsigned
int |
4バイト | 0~4,294,967,295 |
PORTAは6ビット(RA0~RA5)からなるI/O(入出力)ポートです。このポートの入出力設定はTRISAで行ないます。TRISAを'1'にするとPORTAは入力ポートになり、'0'にすると出力ポートになります。
次に繰り返し文について説明します。プログラムの中で同じ処理を何回も行なう場合は繰り返し文をつかいます。
この繰り返しのことをループともいいます。今回はwhile文とfor文を使っています。
while文の書式形式は次のようになります。
while(条件式) { 繰り返す処理 } |
C言語では条件式の値が0ならば偽(flase)、0以外ならば真(true)となります。while文ではこの条件式が真(true)の時、繰り返し処理が実行されます。通常は条件を満たしている間は繰り返し処理が行なわれ、繰り返し処理の中に「条件式」の条件を変化させていくよなプログラムを書きますが、今回は条件式が(1)となってます。これは条件が変化することな状態で、永久に終わらない無限ループの意味になります。
for文の書式形式は次のようになります。
for(変数の初期化式;条件式;変数の増減) { 繰り返す処理 } |
変数の初期値から条件式を満たすまで繰り返し処理が行なわれます。今回は変数i が0から100になるまで処理が繰り返されます。
変数の増減のi++はi=i+1の意味と同じです。処理が1回終わるごとにi
の値には+1され、0、1、2、3、・・・と変化し100になるまで繰り返されます。
「LEDの点滅」と同様に新規にプロジェクトを作成し、ソースプログラムは次の「赤LEDの点滅」をコピーして作成し、コンパイルをします。
PICに書き込み、赤LEDを点滅しているか確認してください。
以下のプログラムをコピーして、貼り付けて使用してください。
カラーLEDはPORTAに接続されていて、赤はbit0、青はbit1、緑はbit2に割り当てられています。
赤のPOTRAのbit0はRA0と記述します。同様に青はRA1、緑はRA2になります。
プログラム中のRA0 = ~RA0;の~は否定(ビット反転)を意味しています。
bit2 | bit1 | bit0 |
緑 | 青 | 赤 |
RA2 | RA1 | RA0 |
「赤LEDの点滅」プログラム |
---|
// ファイル名 LED1.c // 赤LEDの点滅 #include <htc.h> __CONFIG(PWRTEN&HS&WDTDIS&UNPROTECT&MCLRDIS&BORDIS&IESODIS&FCMDIS); #define _XTAL_FREQ 20000000 main() { unsigned int i, LED=0; PORTA = 0; // PORTAを0にする TRISA = 0; // PORTAを出力に設定する ANSEL = 0; // アナログ入力をOFF while(1) { RA0 = ~RA0; // カラーLED赤 for(i=0; i<100; i++) __delay_ms(10); // 1秒ディレイ } } |
PORTA = 0;
| PORTAを0にする |
TRISA = 0;
| PORTAを出力に設定する |
ANSEL = 0;
| アナログ入力をOFF |
以下のプログラムをコピーして、貼り付けて使用してください。
「カラーLEDの点滅」プログラム |
---|
// ファイル名 LED2.c // カラーLEDの点滅 #include <htc.h> __CONFIG(PWRTEN&HS&WDTDIS&UNPROTECT&MCLRDIS&BORDIS&IESODIS&FCMDIS); #define _XTAL_FREQ 20000000 main() { unsigned int i, LED=0; PORTA = 0; // PORTAを0にする TRISA = 0; // PORTAを出力に設定する ANSEL = 0; // アナログ入力をOFF while(1) { PORTA = LED++ % 7 + 1; // カラーLED for(i=0; i<100; i++) __delay_ms(10); // 1秒ディレイ } } |
こちらも同様に次のプログラムも動かしてみます。
前までのプログラムとは違い、main関数の他にLED関数、Delay50関数、Delay100関数が定義されています。
以下のプログラムをコピーして、貼り付けてください。
「指定した色で指定した回数光らせる」プログラム |
---|
// ファイル名 LED3.c // 指定した色で指定した回数光らせる関数を作る #include <htc.h> __CONFIG(PWRTEN&HS&WDTDIS&UNPROTECT&MCLRDIS&BORDIS&IESODIS&FCMDIS); #define _XTAL_FREQ 20000000 typedef unsigned char byte; void LED(byte n, byte times); void Delay50(); void Delay100(); main() { unsigned int i; PORTA = 0; // PORTAを0にする TRISA = 0; // PORTAを出力に設定する ANSEL = 0; // アナログ入力をOFF while(1) { LED(1, 5); // 赤LED for(i=0; i<100; i++) __delay_ms(10); // 1秒ディレイ } } void LED(byte n, byte times) { byte i; for(i=0; i<times; i++) { PORTA = n; Delay50(); // 50msディレイ PORTA = 0; Delay50(); // 50msディレイ } } void Delay50() // 50m秒ディレイ { int i; for(i=0; i<5; i++) __delay_ms(10); } void Delay100() // 100m秒ディレイ { int i; for(i=0; i<10; i++) __delay_ms(10); } |
関数にはあらかじめC言語で用意されたものもありますが、自分で関数を作ることもできます。main関数の中に長々と処理を書き込むより、まとまった処理を関数として定義するとプログラムもコンパクトになり、見やすくなります。また同じ処理を何度も行なう場合も、1度関数で定義しておけばその関数を呼び出すだけで処理できとても便利です。
関数の定義形式は次のようになります。
戻り値の型 関数名(引数型 仮引数名) { 処理内容 }
関数の定義についてLED関数を例に説明します。 void LED(byte n ,byte times) { byte i; for(i=0; i<times; i++) { PORTA = n; Delay50(); // 50msディレイ PORTA = 0; Delay50(); // 50msディレイ } } |
プログラムはmain()関数の上から順に実行されていきます。LED( )関数のところに来たらLED関数の処理へ飛びます。このとき、データとして1と5を渡します。これを実引数といいます。
LED()関数ではこの1と5をnとtimesにそれぞれ代入され処理を行ないます。このnとtimesは仮引数といいます。処理後、main( )関数に戻す値が今回はありません。
そのため、このLED関数の戻り値の型はvoid型(値なし)になっています。