6-3. まずは、LEDの点滅から試してみたい
#procfreq 2097 // System Clock = 2.097MHz
#procfreqは、kHzの単位で使用しているクリスタルの発振周波数を指定する。
#include <delays.h> #include <datalib.h> #include <P16F873.H> #include <Strings.h> # define BIT1 0x2
#includeでは、ヘッダーファイルなどをインクルードしている。この例では、全部は必要ないのだが、あっても毒にはならないので、いつもオマジナイとして全てを書いている。#defineの行では、BIT1に16進数で2という意味を持たせている。BIT1は変数ではなく、定数となる。プログラム中では書き換えられない。
I/Oポートの初期化では、最低限設定必要な部分を書いてある。ポートの設定は、PICを動かす上で基礎中の基礎である。これを間違えると、絶対動かない。文献3および詳細は文献4を見ながら、気をつけて設定する必要がある。後閑さんのPIC活用ガイドブックは読みやすく、ポイントが上手に押さえてあるので、一冊手元におくことをお勧めする。ただし、PICの機能を使いこなすには、やはりメーカー発行の仕様書(文献4)のお世話になることとなる。本GMカウンターのプログラムについても、最終的には文献4まで目を通さないと完成できないこととなった。幸い、文献4に関しては日本語版もあるので、こちらを入手した方が効率があがると思われる。日本語の説明書は、IPI社からFED-Cを購入すると、CD-ROMに入っているハズである。
プログラムソ−スの転用・転記不可。および個人の趣味を超えた使用を禁止する。性能は一切保証しない。
// Test Program 1.0 //
#procfreq 2097 // System Clock = 2.097MHz
#include <delays.h>
#include <datalib.h>
#include <P16F873.H>
#include <Strings.h>
# define BIT1 0x2
//
//----------------------------------------------------------------//
//
void init_port() // Init I/O Ports
{
TRISA = 0x17 ; // Port A xxOI OIII
TRISB = 0x01 ; // Port B OOOO OOOI
TRISC = 0x89 ; // Port C IOOO IOOI
OPTION_REG = 0xc7 ; // Pullup = off, T0 = OSC, PS -> TMR0
INTCON = 0x00 ; // All IRQ OFF
}
//
// ------------------------------------------------------------------
//
void main()
{
unsigned int i ;
init_port() ;
while(1)
{
PORTC |= BIT1 ; // LED ON
Wait (1000) ; // wait 1sec
PORTC &= ~BIT1 ; // LED OFF
Wait (1000) ; // wait 1sec
} // End of while loop
} // End of main program |
//----------------------------------------------------------------//
void main()
{
unsigned int i ;
init_port() ;
while(1)
{
PC.B1 = 1 ; // LED ON
Wait (1000) ;
PC.B1 = 0 ; // LED OFF
Wait (1000) ;
} // End of while loop
} // End of main program |
<6-3-2> LEDの明るさをコントロール
さて、LEDの単純な点滅は実現できた。しかし、単なる「点滅」であった。次は、LEDの明るさを変えてみたい。デジタルなのだから、本来信号は1か0である。LEDなら点灯しているか消灯しているかのどちらかのはずだ。しかし、PIC16F873に内蔵されているPWM(puls width modulation)機能を使うと、擬似的に明るさのコントロールが可能となる。詳細なメカニズムについては文献3のp213「パルス幅変調の原理」を参考にするとよい。少し詳しい設定方法はココ。なお、このプログラムはまだ最適化ができるが、「なにをやっているか?」を追うには、最適化したものよりはわかりやすいと思う。
void set_duty(unsigned int duty, char ch)
これは、PWM用のサブルーチンである。dutyには、0〜1023の値がセットできる。これが、デューティ比を決める値となる。chは2つあるPWMモジュールのどちらを使うかを指定するものである。値としては1か2である。この例では、0の時はLEDは完全に消えている。1になると時間比にして1/1023だけ点灯する。511を指定すると、約半分の時間点灯することになる。ただし、目には見えない速さでの点滅なので、あたかも「明るさが変わった」ように見えます。これがPWMで明るさをかえるカラクリです。ちなみに1023を指定すると、つきっぱなしになるので、最も明るい状態となりますね。
CCP2CON = 0x0c ; // CCP2 is PWM mode set_duty(0,2) ; // Duty2 = 0 PR2 = 0xff ; // T2CON = 0x7d ; // PoS = 1:16, PreS = 1:4, ON
これはPWMを使うにあたり必要な初期設定です。CCP2CONを使って、「PWMを使うよー」ということをPICに知らせます。ちなみに、CCP1CONにも同じ値を設定すると、もう1つのPWMも使用可能になります。PWM時の周波数自体はタイマー2関連のレジスター設定で決定されますので、タイマー2周辺の初期化もしておきます。これを忘れますと、PWM機能は使えません。・・・ここでハタと・・・・そうです。PWMを使うと、タイマー2は他の用途に使えなくなります。回路の設計時にはここのところを注意しなければなりません。このあたりの設定値の考え方は、文献3の214ページから詳しく書いてあります。
プログラムソ−スの転用・転記不可。および個人の趣味を超えた使用を禁止する。性能は一切保証しない。
// Test Program 6-3-2 //
#procfreq 2097 // System Clock = 2.097MHz
#include <delays.h>
#include <datalib.h>
#include <P16F873.H>
#include <Strings.h>
//
# define BIT1 0x2
void init_port(); // Init I/O Ports
void set_duty(unsigned int duty, char ch);
//
//------ init I/O-------------------------------------------------//
//
void init_port() // Init I/O Ports
{
TRISA = 0x17 ; // Port A xxOI OIII
TRISB = 0x01 ; // Port B OOOO OOOI
TRISC = 0x89 ; // Port C IOOO IOOI
OPTION_REG = 0xc7 ; // Pullup = off, T0 = OSC, PS -> TMR0
INTCON = 0x00 ; // All IRQ OFF
CCP2CON = 0x0c ; // CCP2 is PWM mode
set_duty(0,2) ; // Duty2 = 0
PR2 = 0xff ; //
T2CON = 0x7d ; // PoS = 1:16, PreS = 1:4, ON
}
//
//--- PWM subroutine --------------------------------------------//
//
void set_duty(unsigned int duty, char ch)
{
unsigned int temp1 ;
unsigned char temp2 ;
temp1 = duty ;
temp1 >>= 2 ;
temp2 = temp1 & 0xff;
if (ch == 1)
CCPR1L = temp2 ;
else
CCPR2L = temp2 ;
temp1 = duty ;
temp1 <<= 4 ;
temp2 = temp1 | 0x0c ;
if (ch == 1)
CCP1CON = temp2 ;
else
CCP2CON = temp2 ;
}
//
//--- END of PWM subroutine---------------------------------------//
//
// ------------------------------------------------------------------
//
void main()
{
unsigned int i ;
init_port() ;
while(1)
{
for (i=0; i<1024; i++) {
set_duty(i, 2) ; // Set Duty for Unit 2
Wait (1) ;
}
} // End of while loop
} // End of main program |