PIC18F14K50の基本動作から応用プログラムまでを学びます。

ホーム
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
    
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
周波数カウンタ

18F14K50のTimer1とTimer2を使用し、周波数カウンタを作成しました。
測定精度を高めるために測定の基本となるクロックは4MHzのクリスタルを使用しています。測定範囲は、1.2MHzまでしか実測していませんが、PIC内蔵Timerの動作上限である48MHzぐらいはOKと思われます。
無線実験などで使用するには、パルス入力にFET等による入力バッファーが必要でしょう。 私は、ロジック回路の実験が主なので、1KΩ程度の抵抗を直列に入れPICの入力端子にパルスを加える方法であまり不便は感じていません。

5v用LCD表示器を3.3vで使用する

下の写真では、3.3vの電源で動作するように作成しています。ですから液晶のバイアス端子(Vo)にマイナスの電位を加えるため、電源IC、LTC1144、を使い負電圧を発生させる回路も映っています。この周波数カウンタ回路自体は、5vでも動作します、その場合には、回路図のように電源回路を取り外し、5vを直接VRに接続します。
LTC1144によるチャージポンプ方式の負電圧発生回路はここを見てください。

写真の回路には、 3.3vでLCDが動作するよう液晶バイアス端子(Vo)に負電圧を加える回路も組んであります。

周波数カウンタ プログラム

Timer1:
パルス計数に使用し、低優先割込み設定
Timer2:
基準時間発生に使用し、高優先割込み設定

Timer2で10mSec毎に割込みを発生させ、その回数を100回数え、基本となある1秒間の計測時間を作っています。

Timer1のON/OFF機能を使用し、Timer2で発生させた1秒間だけ入力パルスを カウントすします。 16bitのTimer1がオーバーフローした場合は、割込みを発生させ、その回数をソフトウエアでカウントし、48MHzまで使用できるよう処理しています。

プロジェクトファイル H11_FreqCounter.zip

文字を画面に表示するLCDライブラリを利用しています。プロジェクトファイルには、同梱してありますが、このページに記載するのは省略します。

<プログラム>
main.c

//*********************************************************
//  PIC18F14K50
//  File name: FreqCounter      Kazuo Iwamoto
//
//  Timer2でクロック(4MHz)をプリスケラで1/4にして、PR2の値(249)で
//  リセットを繰り返すと1KHzになる、ポストスケラでさらに1/10で、
//  100Hzになる。割込み100回で1秒になる。
//  Timer1で外部パルスを計測する。16bitからあふれた分はソフトで
//  T1Carryとして処理積算する。
//    LED       : PORTB RB4
//    パルス入力: PORTC RC6
//
//    Notes   : 4MHzXtalクロック
//    Language: MPLAB C18
//    Target  : PIC18F14K50
// ----------------------------------------------------------------
// Timer1を、パルスのカウントに使用する。低優先割込みに設定
// Timer2を、時間計測に使用する。高優先割込みに設定
// ----------------------------------------------------------------
#include <p18cxxx.h>
#include <timers.h>
#include "L_LCD.h"

#define LED LATBbits.LATB4

#pragma config FOSC = HS        //  Ttal 4MHzクロック
#pragma config USBDIV = OFF, CPUDIV = NOCLKDIV
#pragma config IESO  = OFF, FCMEN = OFF, PLLEN  = OFF
#pragma config BORV  = 30,  BOREN = OFF, PWRTEN = OFF
#pragma config WDTPS = 32768, WDTEN = OFF
#pragma config MCLRE = OFF, HFOFST = OFF, XINST  = OFF
#pragma config BBSIZ = OFF, LVP    = OFF, STVREN = ON
#pragma config CP1  = OFF, CP0  = OFF, CPD  = OFF, CPB  = OFF
#pragma config WRT1 = OFF, WRT0 = OFF, WRTB = OFF, WRTC = OFF
#pragma config EBTR1 = OFF, EBTR0 = OFF, EBTRB  = OFF

//------- プロトタイプ ----------------
void ito_st(unsigned long, char *,char);
void isr_high(void);
void isr_low(void);

//------- 各インタラプトベクトル --------
#pragma interrupt isr_high
#pragma interruptlow isr_low save = WREG,BSR,STATUS

#pragma code h_int_vect = 0x0008
void _h_isr (void){ _asm goto isr_high _endasm}

#pragma code l_int_vect = 0x0018
void _l_isr (void){ _asm goto isr_low _endasm}

#pragma code
// -------------- 共通変数 ----------------------
unsigned int T1Carry = 0;        //
char T2Carry = 0;                //

//----------------------高優先インタラプト------------------------
void isr_high(){
    if(PIR1bits.TMR2IF){            //Timer2からのインタラプトを確認
        PIR1bits.TMR2IF = 0;        // インタラプトフラッグをクリア
        switch(T2Carry){
            case 0:
                T1CONbits.TMR1ON = 1;    // Timer1計測開始
                T2Carry++;
                LED = 1;
                break;
            case 10:
                LED = 0;
                T2Carry++;
                break;
            case 100:
                Nop();
                Nop();
                Nop();
                Nop();
                T1CONbits.TMR1ON = 0;    // Timer1計測終了
                T2Carry++;
                break;
            case 101:
                break;
            default:
                T2Carry++;
                break;
        }
    }
}

//-----------------低優先インタラプトの処理------------------------
void isr_low(){
    if(PIR1bits.TMR1IF){            //Timer1からのインタラプトを確認
        PIR1bits.TMR1IF = 0;        // インタラプトフラッグをクリア
            T1Carry++;              // Timer1のカウントアップを積算
    }
}

//----------------------メインプログラム-------------------------
void main(void){
    unsigned long T1Count;
    char MsgUpper[]= "12,456,890 Hz";
    LATC = 0;
    TRISC = 0b11000000;
    TRISB = 0;
    ANSEL = 0;
    ANSELH = 0;
//----------------------
    OpenTimer1(                // Timer 1 設定
        TIMER_INT_ON &
        T1_16BIT_RW &
        T1_SOURCE_EXT &
        T1_PS_1_1 &
        T1_OSC1EN_OFF &
        T1_SYNC_EXT_OFF    );
    IPR1bits.TMR1IP = 0;    // Timer 1 からのインタラプトを低優先に設定
    PIR1bits.TMR1IF = 0;    // Timer 1 からのインタラプトフラッグをクリア

    OpenTimer2(             // Timer 2 設定
        TIMER_INT_ON &      // 10mSで割込みが発生
        T2_PS_1_4 &
        T2_POST_1_10 );
    PR2 = 249;              // Timer2 のカウントが249でリセット
    IPR1bits.TMR2IP = 1;    // Timer2 からのインタラプトを高優先に設定
    PIR1bits.TMR2IF = 0;    // Timer2 からのインタラプトフラッグをクリア

//----------------------
    T2Carry = 0;
    WriteTimer1(0);
    LCD_int();
    RCONbits.IPEN=1;        // 2段階のインタラプトに設定
    INTCONbits.GIEH=1;      // 高優先インタラプトを許可
    INTCONbits.GIEL=1;      // 低優先インタラプトを許可

    while(1){
        if(T2Carry == 101){
            T1Count = T1Carry * 0x10000 + ReadTimer1();
            WriteTimer1(0);
            T1Carry = 0;
            T2Carry = 0;
            ito_st(T1Count, MsgUpper, 10);
            LCD_posyx(0,0);
            LCD_str(MsgUpper);
        }
	}
}
//****** 正整数を文字列に変換する関数 ************************
//  num     変換する整数                  (ゼロサプレスあり)
//  strAdd  変換結果の格納される文字列    (コンマ      あり)
//  digit   変換される文字数
//************************************************************
void ito_st(unsigned long num, char *strAdd, char digit){
    char i;
    char flag=1;                        //ゼロサプレス Flag
    char coma=0;                        //コンマ Flag
    strAdd += digit;                    // 文字列の最後
    for(i=digit; i>0; i--) {            // 下位桁から処理
        strAdd--;                       // 1桁上に
        if (flag == 1){
            if (coma++ == 3){           //コンマ の位置か
                *strAdd = ',';          //コンマ を格納
                coma=0;
            }else{                      // 1桁の数値を文字で格納
                *strAdd = (num % 10) + 0x30;
                num = num / 10;         // 次桁の準備
                if (num == 0) flag=0;   // ゼロなら以降は抑制
            }
        }else{                          // 上位の0は抑制する
            *strAdd = 0x20;             // 0の代わりにスペース格納
        }
    }
}
// --- Copyright (C) 2011-2012 Kazuo Iwamoto All Rights Reserved. ---