ソースリスト
#include <16f88.h>
#fuses HS,NOWDT,NOPROTECT
#use delay(CLOCK=20000000)
//LCD_Lib設定
#define mode 0
#define input_x input_B
#define output_x output_B
#define set_tris_x set_tris_B
#define stb PIN_B0
#define rs PIN_B1
#include <lcd_lib.c>
#bit T1_kaisi=0x10.0
#bit T0_IF=0x0b.2
Int End;
Int Sec;
long Count;
Int32 Freq;
#INT_ccp1
void isr(void){
Sec--;
if(Sec==0){
output_low(PIN_A4);
T1_kaisi=0;
End=1;
}
}
void main()
{
setup_timer_0(RTCC_EXT_L_TO_H | RTCC_DIV_8);
set_timer0(0);
setup_timer_1(T1_INTERNAL | T1_Div_BY_8);
T1_kaisi=0;
set_timer1(0);
setup_ccp1(CCP_COMPARE_RESET_TIMER);
CCP_1=62500;
enable_interrupts(INT_ccp1);
enable_interrupts(GLOBAL);
while(1)
{
setup_timer_0(RTCC_EXT_L_TO_H | RTCC_DIV_8);
End=0;
Count=0;
set_timer0(0);
T0_IF=0;
Sec=10;
Set_timer1(0);
T1_kaisi=1;
delay_cycles(66);
Input(PIN_A4);
while(!End){
if(T0_IF) {
Count++;
T0_IF=0;
}
}
Freq=(int32)Count*2048+(int32)get_timer0()*8;
lcd_init();
lcd_clear();
lcd_cmd(0xC0);
printf(lcd_data,"freq=%Lu",Freq);
delay_ms(100);
}
}
周波数は単位時間内における周期の数のことです。単位時間は1秒ですので、1秒間に何サイクルあるかを数えることになります。ここではPIC16F88を20MHzのクリスタルで動作させて使用しますが、最大周波数は次のように求められるということだそうです。
最小パルス幅=((クロックサイクル)+40nsec)/プリスケーラ―値
システムクロックは5MHzですので、クロックサイクルは200nsecになり上式に入れると最小パルス幅はプリスケ―ラー値を8で使用しますので30nsecになり周波数は33MHzということになります。オーディオからHFまで測定できるということになります。問題はこの単位時間をいかに作り出すかということになります。一番簡単な方法は
delay(1000ms) を使用すればよさそうですが、精度が全く期待できないと言われています。この関数を使用して試したところ5MHz位までは概略値としてカウントはできました。ここではタイマ1とコンパレータを使用しています。条件は以下のようになります。
タイマ1のクロック=20MHz/4/8=625KHz
コンペア値=62500
割込み周期=100msec(62500/625000)
割込み回数=10
信号カウント タイマ0を使用
ゲート停止 信号入力端子を出力モードにする。
ゲート開始 信号入力端子を入力モードにする。
SGが20000270HzのときPICでは19997624Hzで2646Hzの差で0.13%、132ppmと高精度です。下の写真はSGが30000270HzのときPICでは30000144で126Hzの差で0.004%、4.2ppmです。
SGは無変調で出力しています。周波数が高いほどSGの出力レベルを上げる必要がありましたが原因調査中です。