Quantcast
Viewing latest article 9
Browse Latest Browse All 440

PIC16F1827 周波数カウンタ

 PIC16F1827を使って、周波数カウンタを作ってみました。

 これまで、PIC16F88,PIC16F628Aなどで製作した「電子交差etc」というサイトで紹介された「周波数カウンタV7」と基本的には同じアルゴリズムです。

 残念ながら「電子工作etc」というサイトは既に見えなくなっているようです。

 PIC 1個で、どのようにして周波数カウンタを作るかを簡単に説明します。

 周波数カウンタを作るには、周波数を測定するカウンタとカウント時間(普通は1秒)を発生するタイムベースが必要です。

 PICは、内部に複数のタイマー(カウンタ)を持っています。そのうち16bitタイマーであるTimer1(TMR1)を周波数を測定するカウンタに使い、8bitタイマーTimer2(TMR2)を使って1秒を発生させます。

 TMR2を利用したタイムベースからの1秒の合図で、TMR1へのゲートを開けたり閉めたりして、周波数をカウントします。

 詳細は、JH7UBCホームページのここを見てください。

回路図です。

Image may be NSFW.
Clik here to view.
イメージ 1

 入力信号は、2SC1815GRの簡単なアンプを通して、T1CKI(RB6)に加えます。

 クロックは、正確に測定するために20MHzのクリスタルオシレータを使い、外部クロック入力CLKIN(RA7)に入れます。

 周波数表示は、I2Cアダプタ付きのLCD1602を使いました。

 動作確認のために、TMR1のゲートが開いている間点灯するLEDをつけました。

 ブレッドボードです。自作SGからの1MHz(1000000Hz)の信号を測定しています。

Image may be NSFW.
Clik here to view.
イメージ 2

プログラムです。
------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
// CONFIG1
#pragma config FOSC = ECH   //外部クロック CLKIN (4-32MHz)
#pragma config WDTE = OFF
#pragma config PWRTE = ON
#pragma config MCLRE = OFF
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = ON
#pragma config CLKOUTEN = OFF
#pragma config IESO = OFF
#pragma config FCMEN = OFF
// CONFIG2
#pragma config WRT = OFF
#pragma config PLLEN = OFF
#pragma config STVREN = ON
#pragma config BORV = HI
#pragma config LVP = OFF

#define _XTAL_FREQ 20000000   //クロック20MHz
#define LED RA4

//LCD関係定義
#define LCD_EN 0b00000100   //Enable
#define LCD_BL 0b00001000   //Back Light
#define LCD_CMD 0x00
#define LCD_CHR 0x01
#define LCD_LINE1 0x80
#define LCD_LINE2 0xC0
#define LCD_addr 0x4E   //0x27<<1

/* I2C 初期化*/
void I2C_init(){
    SSP1CON1 = 0x28;        //SSPEN = 1,I2C Master Mode
    SSP1STATbits.SMP = 1;   //標準速度モード(100KHz)
    SSP1ADD = 0x31;         //Fosc/(4*Clock)-1  Clock=100kHz,Fosc=20MHz
}

/* スタートコンディション */
void I2C_start(){
    SSP1CON2bits.SEN = 1;
    while(SSP1CON2bits.SEN);
}

/* ストップコンディション */
void I2C_stop(){
    SSP1IF = 0;
    SSP1CON2bits.PEN = 1;
    while(SSP1CON2bits.PEN);
    SSP1IF = 0;
}

/* I2Cに1byte送信 */
void I2C_write(unsigned char dat){
    SSP1IF = 0;
    SSP1BUF = dat;
    while(!SSP1IF);
}

void Write_data(unsigned char data){
    I2C_start();
    I2C_write(LCD_addr);
    I2C_write(data | LCD_EN | LCD_BL);
    I2C_write(data | LCD_BL);
    I2C_stop();
    __delay_us(100);
}

void LCD_write(unsigned char bits,unsigned char mode){
    //send High 4bits
    Write_data((bits & 0xF0) | mode);
    //send Low 4bits
    Write_data(((bits << 4) & 0xF0) | mode);
}

void LCD_init(){
    LCD_write(0x33,LCD_CMD);
    LCD_write(0x32,LCD_CMD);
    LCD_write(0x06,LCD_CMD);
    LCD_write(0x0C,LCD_CMD);
    LCD_write(0x28,LCD_CMD);
    LCD_write(0x01,LCD_CMD);
    __delay_ms(1);
}

void LCD_clear(){
    LCD_write(0x01,LCD_CMD);
    __delay_ms(1);
}

void LCD_home(){
    LCD_write(0x02,LCD_CMD);
    __delay_ms(1);
}

void LCD_cursor(unsigned char x,unsigned char y){
    if (y == 0){
        LCD_write(LCD_LINE1+x,LCD_CMD);
    }
    if (y == 1){
        LCD_write(LCD_LINE2+x,LCD_CMD);
    }
}
void putch(unsigned char ch){
    LCD_write(ch,LCD_CHR);
}

static unsigned int MeassuremmentCnt;

/*TMR2のオーバーフロー割り込み*/
void interrupt isr(){
    TMR2IF = 0;//TMR2割り込みフラッグクリア
    MeassuremmentCnt --;
    if (MeassuremmentCnt == 0){
        TMR1ON = 0;//ゲートを閉める。
        TMR2ON = 0;//TMR2を停止する。
    }
}

/*周波数測定*/
unsigned long FreqMeassurement(){
    static unsigned long freq;
    /*TIMERの初期化*/
    TMR1IF = 0; //TMR1割り込みフラッグクリア
    TMR1L = 0;  //TMR1クリア
    TMR1H = 0;
    /*TMR2の初期化*/
    TMR2IF = 0; //TMR2割り込みフラッグクリア
    MeassuremmentCnt = 1221;
    TMR2 = 0x4C;
    /*counter 初期化*/
    freq = 0;
    /*割り込み許可*/
    PEIE = 1;
    GIE = 1;
    //count start
    TMR2ON = 1;
    /*gate time調整 NOP 25*/
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    /*ゲートを開ける*/
    TMR1ON = 1;
    while(TMR2ON){
        if(TMR1IF == 1){
            TMR1IF = 0;
            freq ++;
        }
    }
    if(TMR1IF == 1){
        TMR1IF = 0;
        freq ++;
    }
    /*換算*/
    freq = freq * 65536;
    freq = freq + ((unsigned)TMR1H * 256) + (unsigned)TMR1L;
   
    return(freq);
}
   
void main() {
    ANSELA = 0b00000000 ;     // AN0-AN4は使用しない
    ANSELB = 0b00000000 ;     // AN5-AN11は使用しない
    TRISA  = 0b10000000 ;     // RA7は入力  他は出力(RA5は入力)
    TRISB  = 0b01010010 ;     // RB1(SDA),RB4(SDA),RB6は入力他は出力
    PORTA  = 0b00000000 ;     // PORTA初期化
    PORTB  = 0b00000000 ;     // PORTB初期化
   
    I2C_init();
    LCD_init();
    LCD_cursor(12,0);
    printf("Hz");
   
     /*TMR2の設定*/
    TMR2IE = 1;     //TMR2割り込み許可
    TMR2IF = 0;     //TMR2割り込みフラッグクリア
    T2OUTPS0 = 0;   //TMR2 output poststscaler 1:1
    T2OUTPS1 = 0;
    T2OUTPS2 = 0;
    T2OUTPS3 = 0;
    TMR2ON = 0;     //TMR2 off
    T2CKPS0 = 0;    //TMR2 prescaler 1:16
    T2CKPS1 = 1;
    TMR2 = 0;       //TMR2 clear
   
    /*TMR1の設定*/
    TMR1IE = 0;     //TMR1割り込み禁止
    TMR1IF = 0;     //TMR1割り込みフラッグクリア
    T1CKPS0 = 0;    //TMR1 prescaler 1:1
    T1CKPS1 = 0;
    T1OSCEN = 0;    //TMR1 Clock source = T1CKI
    TMR1CS1 = 1;
    TMR1CS0 = 0;
    nT1SYNC = 1;
    TMR1ON = 0;     //TMR1 stop
    TMR1L = 0;      //TMR1 clear
    TMR1H = 0;
   
    while(1){
    /*周波数の測定*/
    LED = 1;//RA4 LED ON
    unsigned long frequency = FreqMeassurement();
    LED = 0;//RA4 LED OFF
    LCD_cursor(2,0);
    printf("%9ld",frequency);
    __delay_ms(500);
    }
}


Viewing latest article 9
Browse Latest Browse All 440

Trending Articles