周波数カウンタとは、入力されたパルスの周波数を数える電子機器です。
今回は、周波数カウンタをPIC16F688を使って製作してみました。
周波数測定部
周波数を測定するには、PICの「タイマー0」の機能を使います。タイマー0にはT0CK1ピンから入ってきたパルスを数えることができます。

(PIC16F688のデータシートより)
測定されるパルスは、上図の赤線の経路をたどってTMR0レジスタに蓄積されます。
このようにして、タイマー0をT0CK1ピンを使って使用する場合、次のような設定が必要です。
| 設定 | 理由 |
|---|---|
| T0SEビット=1 | パルスが立ち上がった(「0」から「1」になった)時にTMR0レジスタをインクリメントするため |
| PSAビット=1 | プリスケーラを使わない設定にする。測定したい周波数地によってプリスケーラを設定するべき |
| T0CSビットを1 | タイマー0の入力クロックはT0CK1ピンから入力するため |
以上の3つの設定を行うことで、タイマー0のパルスの回数を測定することができます。このようにして、一秒間TMR0でパルスをカウントし、その値を測定した周波数とします。
しかし、それでは0~254Hz(2の8乗)までしか計測できません。TMR0レジスタは8ビットのレジスタで、255個目のパルスが入力されえるとレジスタがオーバーフローするからです。
そこで、OVERFLGという変数を新しく作り、TMR0レジストがオーバーフローしたら、その時は、変数のOVERFLGをインクリメントします。TMR0レジスタがオーバーフローしたかどうかはT0IFビットが1か同課で判断します。

こうすることで、0Hz~65535Hz(2の16乗)の周波数を計測することができます。詳細なプログラムは下に載せています。
データ送信部
上の要領で測定した周波数のデータは、独自にプログラムしたシリアル通信アルゴリズムによって送信するアルゴリズムです。
まず、シリアル通信とは、データ(今回の場合は周波数)を1ビット(バイト)ずつ送信する方法のことです。PICにはEUSARTというシリアル通信の機能がついているが、これを使っても一度に9ビット(0~512)までの数字しか送れないので、シリアル通信のプログラムも自作した。
データを送信するピンはTX_PIN(プログラム参照)で行います。
送信順番は、
- スタートビット(ON)を1ms
- 変数OVERFLGを送信
- TMR0レジスタを送信
の3ステップです。

送信された信号をハンディーオシロ(無料のオシロスコープアプリ)を使って可視化してみました。

ちなみに、ハンディーオシロの使い方は、こちら↓
shizenkarasuzon.hatenablog.com
ハードウェアについて
下のプログラムを動かすための回路について簡単に説明します。
下のプログラムは、T0CK1ピンからの入力パルスの周波数を測定するものなので、測定したい周波数はT0CK1ピンに入力してください。
また、データのシリアル送信はTX_PIN(プログラム参照)で行われます。デフォルトはPORTCの5ピンです。
MCLRリセットを使用しているので、MCLRピンはプルアップしてください。
サンプルプログラム
周波数カウンタの測定部プログラムです。マイコンはPIC16F688を使用します。
周波数カウンタというだけに、時間にシビアな動作が要求されるため、プログラムはアセンブリです。
;/******************************************
; Frequency Counter (PIC16F688)
;*******************************************
LIST P=PIC16F688
INCLUDE "P16F688.INC"
__CONFIG _FCMEN_ON & _IESO_OFF & _BOR_ON & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO
;/******************************************
; 変数
;******************************************/
GATEDATA EQU 20H ;周波数を格納する最下位バイト
OVERFLG EQU 21H ;周波数を格納する最上位バイト
CNT1 EQU 23H
CNT2 EQU 24H
CNT3 EQU 25H
CNT4 EQU 28H
TX_CNT EQU 26H
TEMP EQU 27H ;TX_BITEで送信するデータを入れるバイト
#DEFINE TX_PIN PORTC,5 ;データ送信ピン
ORG 0
MAIN CALL IOPORT
CLRF OVERFLG
CLRF GATEDATA
MAINLOOP GOTO GET_DATA_L
IOPORT CLRF PORTA
CLRF PORTC
MOVLW 07H
MOVWF CMCON0
BSF STATUS,5
MOVLW 75H
MOVWF OSCCON
CLRF ANSEL
MOVLW 0CH
MOVWF TRISA
CLRF TRISC
BCF STATUS,RP0
CLRF TMR0
BCF INTCON,T0IF
RETURN
;-----------------------------------------
;GET_DATA_L関数…周波数測定
GET_DATA_L CLRF TMR0
CLRF OVERFLG
BSF PORTC,RC2
BCF INTCON,T0IF
CLRF TMR0 ;GATE open
MOVLW 020H
CALL WAIT
MOVLW 05H
CALL TIMER2
NOP
MOVF TMR0,0 ;Gate Close
MOVWF GATEDATA
BCF PORTC ,RC2
GOTO SEND_DATA
DUMYNOP DECFSZ CNT4,1
GOTO DUMYNOP
RETURN
WAIT MOVWF CNT1
LPCNT1 MOVLW 1AH
MOVWF CNT2
LPCNT0 MOVLW 0C7H
MOVWF CNT3
LPCNT4 NOP
NOP
CHECK BTFSS INTCON,T0IF ;TIMER0
GOTO LPCNT2
INCF OVERFLG,1
BCF INTCON,T0IF
GOTO LPCNT3
LPCNT2 NOP
NOP
NOP
LPCNT3 NOP
DECFSZ CNT3,1
GOTO LPCNT4
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
DECFSZ CNT2,1
GOTO LPCNT0
MOVLW 03H
CALL TIMER2
DECFSZ CNT1,1
GOTO LPCNT1
RETURN
TIMER2 MOVWF CNT4
LPCNT01 NOP
DECFSZ CNT4,1
GOTO LPCNT01
RETURN
;-------------------------------------------
;SEND_DATA関数…データ転送
SEND_DATA BSF TX_PIN
MOVLW 0F8H
CALL TIMER
NOP ;1ms
NOP
BCF TX_PIN
MOVF OVERFLG,W
CALL TX_BITE
MOVF GATEDATA,W
CALL TX_BITE
BCF TX_PIN
GOTO MAINLOOP
;------------------------------
;TX_BITE関数…1バイト送信
TX_BITE MOVWF TEMP
MOVLW 8H
MOVWF TX_CNT
TXLPSTART RLF TEMP,F
BTFSS STATUS,C
GOTO TX0
GOTO TX1
TX0 BCF TX_PIN ;0を送信
GOTO TXLPEND
TX1 BSF TX_PIN ;1を送信
NOP
TXLPEND MOVLW 0F8H
CALL TIMER
NOP
DECFSZ TX_CNT,F
GOTO TXLPSTART
RETURN
TIMER MOVWF CNT3
LPCNT6 NOP
NOP
NOP
NOP
NOP
DECFSZ CNT3,1
GOTO LPCNT6
RETURN
END上のプログラムの動作は保証できません。

