PIC16F1827を使った周波数カウンタは2019年に試作し、JH7UBCホームページの
ここに掲載しています。周波数カウンタの仕組みも解説していますので、ご一読ください。
この時は、LCD1602を周波数の表示器として使いました。今回は、MAX7219使用の8桁7セグメントLEDを表示器として使用した周波数カウンタを試作してみます。プログラムは、LCD版周波数カウンタのプログラムの表示部分を8×7セグメントLEDに差し替えました。
回路図です。入力を増幅するため簡単なアンプをつけました。
カウンタのゲートが開いている時LEDが点灯します。
プログラムです。
----------------------------------------------------------
/*
* PIC16F1827 Frequency Counter
* Author: JH7UBC
* Keiji Hata
* 2023/05/29
*/
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
// CONFIG1
#pragma config FOSC = ECH //外部クロック
#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 LATAbits.LATA4
// MAX7219 Register Address
#define MAX7219_DECODE_MODE 0x09
#define MAX7219_INTENSITY 0x0a
#define MAX7219_SCAN_LIMIT 0x0b
#define MAX7219_SHUTDOWN 0x0C
#define MAX7219_DISPLAY_TEST 0x0f
#define CS LATBbits.LATB3
void SPI_init(){
SSP1CON1 = 0b00100000; //SSP1EN=1:SSP1 Enable,CKP=0:Idle Low,Clock=FOSC/4
SSP1STAT = 0b01000000; //SMP=0:middle,CKE=1:Active to Idle
}
void maxTransfer(uint8_t address,uint8_t data){
CS = 0;
uint8_t dammy;
//send address
dammy = SSP1BUF;
SSP1BUF = address;
while(!SSP1STATbits.BF);
//send data
dammy = SSP1BUF;
SSP1BUF = data;
while(!SSP1STATbits.BF);
CS =1;
}
void MAX7219_init(){
maxTransfer(MAX7219_DECODE_MODE, 0xff);// Code B decode for digits 7-0
maxTransfer(MAX7219_INTENSITY, 0x03); // Intensity
maxTransfer(MAX7219_SCAN_LIMIT, 0x07);// Display digits 01234567
maxTransfer(MAX7219_SHUTDOWN, 0x01);// Normal Operation
maxTransfer(MAX7219_DISPLAY_TEST, 0x00);// Normal Operation
}
void Clear_Display(){
for(uint8_t i=1;i<=8;i++){
maxTransfer(i,0x0f);
}
}
//数値を表示する
void Num_Display(uint32_t n){
uint32_t josu = 10000000;
uint8_t sho;
uint32_t joyo;
uint8_t i=8;
uint8_t zflag = 1;
while(i){
sho = n / josu;
joyo = n % josu;
if(zflag==1 && sho==0 && i!=1){
sho = 0x0f; //空白
}
else{
zflag = 0;
}
maxTransfer(i,sho);
n = joyo;
josu = josu / 10;
i--;
}
}
static uint16_t MeassuremmentCnt;
/*TMR2のオーバーフロー割り込み*/
void __interrupt(high_priority) isr(){
TMR2IF = 0;//TMR2割り込みフラッグクリア
MeassuremmentCnt--;
if (MeassuremmentCnt == 0){
TMR1ON = 0;//ゲートを閉める。
TMR2ON = 0;//TMR2を停止する。
}
}
/*周波数測定*/
uint32_t FreqMeassurement(){
static uint32_t 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);
}
int main() {
ANSELA = 0b00000000 ; // AN0-AN4は使用しない
ANSELB = 0b00000000 ; // AN5-AN11は使用しない
TRISA = 0b10000000 ; // RA7は入力 他は出力(RA5は入力)
TRISB = 0b01000000 ; // RB6は入力他は出力
PORTA = 0b00000000 ; // PORTA初期化
PORTB = 0b00000000 ; // PORTB初期化
CS = 1; //CS初期値
SPI_init(); //SPI初期化
MAX7219_init(); //MAX7219初期化
Clear_Display(); //ディスプレイクリア
LED = 0;
/*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
uint32_t frequency = FreqMeassurement();
LED = 0;//RA4 LED OFF
Num_Display(frequency);
__delay_ms(500);
}
}
----------------------------------------------------------
MPLAB X IDEは、v6.00をXC8はv2.40を使っています。
ゲートタイム(1秒)は、プログラム中のNOP();の数で調整します。
今のところ、NOP 25個でちょうど良いようです。
MAX7219使用8X7セグメントLEDテストのままの表示プログラムですと、入力がない時に何も表示されませんので、ちょっと不安になります。そこでカウントが0の時は、0が表示されるように変更しました。
1MHzを入力した時の表示の様子です。
10MHzの時です。
周波数の測定範囲は10Hz~約50MHzです。
誤差は、数ppm程度だと思います。
自作SGからの信号ですから、どちらがずれているかの判断は難しいです。
この後、簡単な筐体に入れて、周波数カウンタとして仕上げてみたいと思います。