C言語によるPICプログラミング

 

1. はじめに

 PIC の開発用の言語としては、アセンブラ言語が良く用いられています。これはアセンブラ言語の開発環境が無料で手に入り、多くの参考書で取り扱っているためです。

 一方、C言語での開発環境も提供されています。しかし、複数のメーカから提供されており仕様が異なること、ANSI C に準拠していないこと、コンパイラの価格が高額であることなど、いくつかのデメリットも存在します。

 以下に手に入れることの出来るコンパイラについて示します。

 HI-TECH 社のコンパイラには、製品版とフリーの PICC Lite が提供されています。現在、手に入るフリーのCコンパイラであり、近年よく用いられているコンパイラです。PICC Lite は、ANSI 準拠なので、ふつうのC言語の文法と同じように、演算、配列、ポインタ、関数、構造体等を用いたプログラミングが可能です。
 まだ、日本言の解説ページなど資料が少ないのが辛いところですが、オーム社から出版されている「C言語ではじめるPICマイコン―フリーのCコンパイラではじめよう」が解説書として出版されています。PIC のメーカである Microchip Technology 社が提供している開発環境 MPLAB で使用することが出来ます。使用できる PIC の種類やプログラムサイズに制限がありますので、本格的な開発には向かないかもしれませんが、C言語でのプログラミングの最初の選択にはちょうどいいと思います。
 ここでは、HI-TECH PICC Lite を用いたC言語によるプログラミングについて説明します。

 CCS C Compiler は、書籍等で良く取り上げられており、一般的に良く用いられています。日本語の解説ページなどもたくさんあり、最も資料の多いコンパイラです。PIC のメーカである Microchip Technology 社が提供している開発環境 MPLAB で使用することが出来ます。価格が少し高いですが、きちんとしたプログラムを行うのであれば、 CCS 社のコンパイラを購入することを考えるといいでしょう。
 MPLAB C18 コンパイラは、Microchip Technology 社が提供しているCコンパイラであり、純正の開発言語になります。このコンパイラも高価ですが、きちんとしたプログラム開発を行うのであれば購入を考えると良いと思います。

 秋月で販売されている PicC C Compiler(Grich 社)は2000円と低価格であり、簡単なものですが日本語の解説書も付属しているので最初の選択としてはいいと思います。

 

2. HI-TECH PICC Lite のインストール

1) ダウンロード

 HI-TECH PICC Lite のインストールファイルは、HI-TECH 社の PICC のページよりダウンロードすることが出来ます。

PICC Lite のインストールページ1

 このページの一番下にある“Downloads page”をクリックして、ダウンロードページを開きます。

PICC Lite のインストールページ2

 このページの中央にある“Demos and Free Software”をクリックします。

PICC Lite のインストールページ3

 このページを一番下までスクロールします。

PICC Lite のインストールページ4

 このページ内の以下のリンクをクリックするとダウンロードが開始されます。

 次に User ID と Mail Address を要求されますので、登録していればそのまま入力して下さい。ダウンロードが開始されます。登録をしていない場合は、一番上にある“Your Details”をクリックして、必要事項を入力して下さい。

2) インストール

 インストールファイルを実行すれば、手順通りでインストールが完了します。Microchip 社の MPLAB がインストールされていない場合やインストールされている MPLAB のバージョンが 6.40 以前だとインストールが蹴られます。新しいバージョンの MPLAB をインストールしておいて下さい。

3) 設定

 MPLAB 側のコンパイラの設定(HI-TECH PICC Lite のコンパイラへのリンク)は、インストール時に自動的にやってくれているはずです。設定自体は、特に何もしなくても大丈夫です。

 ただし、プロジェクト・ウィザードを実行したときに、コンパイラとして PICC Lite を選択する必要があります。

PICC Lite の設定ページ1

 インストールと設定については、「全て無料のC言語開発環境(MPLAB7.21とHitech-C)使用!」で詳しく解説されていますので、そちらも参照して下さい。

 

3. 動作確認(LED点滅プログラムの作成)

 以下に動作確認に使用したサンプルプログラムと実行用の回路図を示します。

 1: #include "pic.h"
 2: #include "delay.h"
 3: int main(void) {
 4:     TRISB=0x00;
 5:     while(1) {
 6:         PORTB=0xFF;
 7:         DelayMs(250);
 8:         DelayMs(250);
 9:         PORTB=0x00;
10:         DelayMs(250);
11:         DelayMs(250);
12:     }
13: }

 

 このプログラムは、500 msec 毎に LED が点灯・消灯を繰り返すものである。以下にアセンブラで作成した同様のプログラムを示す。

 
 1:         LIST    P=PIC16F84
 2:         INCLUDE "P16F84.INC"

 3: CNT1    EQU     0CH
 4: CNT2    EQU     0DH
 5: CNT3    EQU     0EH

 6:         ORG     0
 7: MAIN
 8:         BSF     STATUS, RP0
 9:         CLRF    TRISB
10:         BCF     STATUS, RP0
11: MAINLP
12:         CLRF    PORTB
13:         CALL    SECTIM
14:         MOVLW   0FFH
15:         MOVWF   PORTB
16:         CALL    SECTIM
17:         GOTO    MAINLP

18: TIM10   MOVLW   0F9H
19:         MOVWF   CNT1
20: TIMLP1  NOP
21:         DECFSZ  CNT1, F
22:         GOTO    TIMLP1
23:         RETURN

24: TIM100  MOVLW   0F9H
25:         MOVWF   CNT2
26: TIMLP2  CALL    TIM10
27:         DECFSZ  CNT2, F
28:         GOTO    TIMLP2
29:         RETURN

30: SECTIM  MOVLW   5
31:         MOVWF   CNT3
32: TIMLP3  CALL    TIM100
33:         DECFSZ  CNT3, F
34:         GOTO    TIMLP3
35:         RETURN

36:         END

 

4. PIC C コンパイラ(HI-TECH社)の文法

1) 変数のデータ型と変数の宣言

 PICC Lite で使用できる変数の型を以下に示す。

データ型 ビット数 数の範囲
bit  2  0 〜 1
char  8  -128 〜 127
unsigned char  8  0 〜 255
short 16 -32768 〜 32767
unsigned short 16 0 〜 65535
int 16 -32768 〜 32767
unsigned int 16 0 〜 65535
long 32 -2147483648 〜 2147483647
unsigned long 32 0 〜 4294967295
float 24 -3.4×1038 〜 3.4×1038
double 24 -3.4×1038 〜 3.4×1038

 プログラムで変数を用いるためには、最初に変数の宣言を行う。

 
    int a;             // int 型の a という変数を宣言  

    int b, c, d;       // 続けて書くことが出来る

    int e=100, f=50;   // 初期値も書ける

    unsigned char g;   // unsigned char 型の g という変数を宣言

2) 数字の表記

 PICC Lite では、整数の表記として 10 進数、2 進数、8 進数、16 進数を用いることが出来る。

2進数 0b10011010
8進数 0144
10進数 100
16進数 0x64
実  数 100.0,  1.0e2
文  字 'a',  '\x61'
文 字 列 "abc"

3) 分岐と繰り返し

 分岐として、if 文と switch 文がある。if を使用する分岐には、if 文、if 〜 else 文、else if 文がある。

if 文 if 〜 else 文 else if 文
main(){
    int a, b, c;

    if (a<b) {
        c=1;
    }
}
main(){
    int a, b, c;

    if (a<b) {
        c=1;
    } else {
        c=2;
    }
}
main(){
    int a, b, c;

    if (a<b) {
        c=1;
    } else if (a>b) {
        c=2;
    } else {
        c=3;
    }
}

 多重分岐には、switch 〜 case 文を使用する。

main(){
    int a, b;

    switch (a) {
        case 1:    b=800;
                   break;

        case 2:    b=300;
                   break;

        case 3:    b=200;
                   break;

        default:   b=100;
    }
}

 繰り返しとして、for 文、while 文、do 〜 while 文がある。

for 文 while 文 do 〜 while 文
main(){
    int i, j;

    j=0;
    for (i=0;i<=10;i++) {
        j=j+i;
    }
}
main(){
    int i, j;

    i=0;
    j=0;
    while(i<=10) {
        j=j+i;
        i++;
    }
}
main(){
    int i, j;

    i=0;
    j=0;
    do {
        j=j+i;
        i++;
    } while(i<=10);
}

4) 関数

 ユーザ定義関数を ANSI C と同じように用いることが出来る。ただし、関数の入れ子は8回までしか出来ない。また、再起呼び出しを行うことが出来ない。

 PICC Lite には多くのライブラリ関数が用意されている。代表的な代表的なヘッダファイルを以下に示します。

ヘッダファイル 説明
1 pic.h   PIC マイコン制御関数のヘッダファイル  
2 stdlib.h   ユーティリティ関数のヘッダファイル  
3 math.h   数学関数のヘッダファイル  
4 string.h   文字列操作関数のヘッダファイル  

 以下に上記ヘッダファイルで定義されている関数の代表的なものについて示します。この他にも多くの関数がヘッダファイル内で定義されています。詳しくは、ヘッダファイルをご覧ください。

1) PIC マイコン制御関数:pic.h

戻り値 関数 内容
unsigned char eeprom_read( unsigned char addr ) データ EEPROM の読み出し
unsigned char eeprom_write( unsigned char addr ) データ EEPROM の読み出し
void ei( void ) 割り込みを発生できるようにする

2) ユーティリティ関数:stdlib.h

戻り値 関数 内容
int abs( int n ) 整数の絶対値を返す
int atoi( const char *str ) 文字列を整数に変換する
double atof( const char *str ) 文字列を実数に変換する
int rand( void ) 乱数を返す
void srand( unsigned int seed ) 乱数列の初期化

3) 数学関数:math.h

戻り値 関数 内容
double sin( double x ) sin(x) の結果を返す 
double cos( double x ) cos(x) の結果を返す
double tan( double x ) tan(x) の結果を返す
double asin( double x ) sin-1(x) の結果を返す 
double acos( double x ) cos-1(x) の結果を返す
double atan( double x ) tan-1(x) の結果を返す
double fabs( double x ) x の絶対値を返す
double pow( double x, doubel y ) xy の結果を返す
double sqrt( double x ) √x の結果を返す
double  log( double x ) loge(x) の結果を返す 
double  log10( double x ) log10(x) の結果を返す

4) 文字列操作関数:string.h

戻り値 関数 内容
char * strcpy( char *str1, const char *str2 ) str1の領域に文字列str2をコピーする
char * strcat( char *str1, const char *str2 ) 文字列str1に文字列str2を連結する
size_t strlen( const char *str ) 文字列の長さを返す
char * strchr( const char *str, int ch )

文字列中に文字があった場合にその最初の文字位置へのポインタを返す

char * strstr( const char *str1, const char str2 )

文字列str1の中で文字列str2と一致する最初の位置へポインタを返す

5) 入出力ポートの制御

 PICC Lite で PIC の制御プログラムを作成する場合、アセンブラと同じように SFR(Special Function Register:特殊機能レジスタ)を用いることによって、入出力ポートの制御を行う。

 PIC マイコンとして PIC16F84A を使用する場合は、入出力ポート PORTA と PORTB があり、このレジスタの値によって入出力の状態が決まる。また、PORTA と PORTB の設定を決めるレジスタとして TRISA と TRISB がある。このレジスタの値を設定する場合、アセンブラではバンクの切り替えを行わなければならないが、PICC Lite では自動的に行われるのでバンクの切り替えは必要ない。

#include "pic.h"
#include "delay.h"

int main(void) {
  TRISB=0x00;            // PORTB を出力に設定

  while(1) {
    PORTB=0xFF;       // PORTB を HIGH に設定
    DelayMs(250);   // 250msec のディレイ
    DelayMs(250);
    PORTB=0x00;       // PORTB を LOW に設定 
    DelayMs(250);
    DelayMs(250);
  }
}

 このプログラムでは、 TRISB や PORTB への値の代入が 16 進数で行われているが、2 進数や 10 進数で行っても構わない。このプログラムで使用している遅延関数 DelayMs() は、PICC Lite のサンプルファイルにある delay.h と delay.c によって定義されている。

 ポート毎のレジスタだけでなく、ピン毎のビット変数が PICC Lite で用意されている。このビット変数を使用することによって、多くの分岐を簡単に行うことが出来る。PORTA のピン(RA0〜RA4)PORTBのピン(RB0〜RB7)に対応するビット変数は、それぞれ RA0〜RA4 と RB0〜RB7 で与えられる。

#include "pic.h"
#include "delay.h"

int main(void) {
	TRISB3=0;            // RB3 を出力に設定
	while(1) {
		RB3=1;        // RB3 を HIGH に設定
		DelayMs(250);
		DelayMs(250);
		RB3=0;        // RB3 を LOW に設定
		DelayMs(250);
		DelayMs(250);
	}
}

 

5. プログラム実行例

1) LED の順次点灯プログラム

 RB0 〜 RB4 に LED が接続され、LOW 状態で点灯、HIGH 状態で消灯となる回路で、順次点灯するプログラム。

#include "pic.h"
#include "delay.h"

int main(void) {
    TRISB=0b00000000;          // PORTB IO を出力に設定
    while(1) {
        PORTB=0b11111110;      // RB0 を LOW 状態に設定
        DelayMs(100);
        PORTB=0b11111101;      // RB1 を LOW 状態に設定
        DelayMs(100);
        PORTB=0b11111011;      // RB2 を LOW 状態に設定
        DelayMs(100);
        PORTB=0b11110111;      // RB3 を LOW 状態に設定
        DelayMs(100);
    }
}

 

2) スイッチ入力制御の LED 点灯プログラム

 以上の回路において、スイッチが ON の時に LED が点灯、OFF の時に消灯するプログラム。

#include "pic.h"

int main(void) {
  TRISA=0b11111111;          // PORTA IO を入力に設定
  TRISB=0b00000000;          // PORTB IO を出力に設定
  while(1) {
    if (RA3) {             // RA3 が HIGH の時、PORTB を HIGH
      PORTB=0b11111111;
    } else {               // RA3 が LOW の時、PORTB を LOW
      PORTB=0b00000000;
    }
  }
}

 ここで、TRISA と TRISB の設定を 2 進数で制御している。 2 進数で 0b00000000 と 0b11111111 示される値は、 16 進数ならばそれぞれ 0x00 と 0xFF と表される。

 

6. リンク