| | ホーム | 私の電子工作作品集 |
| [ 初公開日:2017年3月5日 ] |
|
最近、"中日電工さんのホームページ" へ
よくお邪魔をしているのですが、そのホームページの中に "周波数カウンタ組立キット" という記事がありました。 中日電工さんはいろいろな組立キットを販売しているのですが、
記事中に回路図が公開されており簡単そうなので、その回路図を参考にさせていただいて私も "周波数カウンタ" を製作してみました。 ただし、回路図は公開されておりますが、プログラムについては公開されておりませんので、私独自の考えのもとで作成をした私のオリジナルです。 |
![]() |
|
| ( 2025/11/20 更新 ) *1 更新(差し替え)、*2 改造後パターン図、*3 追加 |
|
|
中日電工さんのオリジナル回路図では、カウンタ心臓部のPICに PIC16F883 が使用されていますが、その改良前の PIC16F873A が私の手持ちにたくさんありますので、
それを使用することにしました。 カウンタ前段の 74HC590 を使用したプリスケーラ部は、オリジナル回路図からそっくりいただくことにしました。 また、周波数表示部については、オリジナル回路図では7セグLEDを8個 並べて使用していますが、私は手持ちにLCDモジュールがたくさんありますので、それを使用することにしました。 |
|
プログラムの更新と、ICSP 端子(6P ピンヘッダ)の追加改造 ( 2025/11/20 更新 ) 本機を製作して以来、ずっと続いていた症状(LCD に表示される周波数の値に安定性がなく、下1桁 〜 3桁の表示が1秒おきにたえず変動する)を、無くすようにプログラムを修正しました。 それに先立って、プログラムの書き換えが簡単に行えるように、本機に ICSP 端子の追加改造(下の回路図を参照)も行いました。 プログラムの詳細については、プログラムの項の 再度、1秒ゲートの作成方法の変更、および 現在の最新プログラムバージョン を、 ICSP 端子の追加改造については、改造後の 回路図、プリント基板パターン図 (部品面)、同 (ハンダ面) をご覧になってください。 |
![]() |
| 回路図 (FreqCounterII.CE3) | ページトップ |
|
久々にハマってしまいました。 といっても、夢中になった、のめり込んだ、熱中した、というような良い意味ではありません。 最悪な状況に入り込んでしまった
という意味でです。 そのために2日間ほど無駄な時間を費やしてしまいました。 実は、上の回路図はもちろん修正後のものですが、当初、74HC590 とPICのポートAとの接続は、次図のように行っていました。 これは、上述したように、プリスケーラ部を オリジナル回路図からそっくりいただいたためで、ポートAの使用したポート番号も同じものを使用したのです。 (今思えば、この回路図を描いた時点で気が付くべきでした。) ![]() PICの RA3、RA4、RA5 はすべてアウトポートに指定して、それぞれで 74HC590 の RCK、/CCLR、/CCKEN の各入力端子をコントロールしています。 実際のPICの制御プログラムは 下記の通りで、下リストの中央に位置するゲート(1秒間開いている)の前後( (1) 〜 (6) の部分)で、それらの信号をコントロールしています。 : : main01 movlw 1 btfss PORTA,ZS_SW ;ゼロサプレススイッチ = OFF か? xorwf zsflg,F ;No. フラグをビット反転 clrf bin3 ;周波数入力カウンタの初期設定 clrf bin2 clrf bin1 clrf bin0 movlw high tm1_cycle ; movwf TMR1H ;TMR1H に設定 movlw low tm1_cycle ; movwf TMR1L ;TMR1L に設定 movlw 100 movwf sec1cnt ;1秒カウンタの初期設定 bsf PORTA,CCLR ;RA4(/CCLR)=1: カウンタ値維持 ..... (1) bsf INTCON,GIE ;bit7(GIE)=1: 全割り込み許可 bcf PORTA,CCKEN ;RA5(/CCKEN)=0: カウント許可: (カウント開始) ..... (2) movf sec1cnt,W ;10 mS * 100 = 1 S btfss STATUS,Z ;1秒経過したか? ;; ;;この間で HC590からオーバーフローした /RCO数を 割り込みでカウントする ;; goto $ - 2 ;No bsf PORTA,CCKEN ;RA5(/CCKEN)=1: カウント禁止: (カウント終了) ..... (3) bcf INTCON,GIE ;bit7(GIE)=0: 全割り込み禁止 bsf PORTA,RCK ;RA3(RCK)=1: カウンタのデータをレジスタにストア ..... (4) nop bcf PORTA,RCK ;RA3(RCK)=0: レジスタ状態は変化しない ..... (5) movf PORTC,W ;PORTC(HC590のレジスタ)の内容を movwf bin0 ;bin0に読み込む bcf PORTA,CCLR ;RA4(/CCLR)=0: カウンタクリア ..... (6) call bindec32 ;32ビット数値を10進数10桁の文字列に変換 call freq_display ;LCD への " xx,xxx,xxx Hz " 表示 goto main01 : :PICのプログラムはこの後(一連のポートAの操作後)、カウントした4バイト(32ビット)のバイナリ(2進)データ(パルス数 = 周波数)を 10進数の文字列に変換した後、ポートBからLCDに送出して表示をさせています。 そもそも測定をするパルス列(周波数)は、上図の 74HC590 の CCK(カウンタクロック)端子に接続をして入力しますが、本機を起動させた直後の入力に何も接続していない状態では 当然ながら 0 Hz を表示しています。 ところが、実際に CCK 端子にパルス列を入力しても表示は 0 Hz のままで何の変化も起こらないのです。 ・・・・・・ ンッ ?? 初め、一瞬目を疑いました。 このようなときって、実にいろいろなことを考えます。 どこか半田上げ不良で断線状態になっているのではないのか? とか、74HC590 の使用方法が 間違っているのでは? とか、それよりも 74HC590 自体が不良なのでは? とか、ハードウエアばかりでなくプログラム自体にもどこか問題があるのでは? とか、 ・・・・・・ 等々 CCK 端子周りの配線を入念にチェックをしました。 74HC590 も別の個体と取り換えてみました。 プログラムについても次に示す 74HC590 のデータシートの真理値表や、タイミング図などを 何度も見直して、オペレーションに間違いがないかを十分に確認をしました。 (以下の真理値表、ブロック図、タイミング図は、東芝 TC74HC590AP データシートより抜粋。)
しかし、特に悪いと思われるようなところは見当たらず結果も変わりません。 やはり 0 Hz を表示したままです。 ・・・・・・ わからない。 ・・・・・・ 一体、何が悪いのか? ・・・・・・ CCK 端子に入力しているパルス列は 256 Hz 以上にもかかわらず、オーバーフローの /RCO 信号が1つも出力されて来ない(らしい)のが一番の謎でした。 そして、 カウントしたパルス数の下位8ビットがPICのポートCに読み込めていない(らしい)のも謎でした。 そこで、まず次のことを試みてみました。 本機では 74HC590 にも ICソケットを使用しているため 74HC590 をソケットから外して、/RCO 信号の代わりにパルス列を直接 PICの RB0/INT 端子に接続してみたところ、256 倍された(たぶん)周波数がLCDに表示されました。 これで、PICの外部(RB0/INT)割り込みは正常に機能していることが 確認できました。 したがって、74HC590 からは /RCO 信号が出力されて来ないことが決定されたのです。 次に、なぜ /RCO 信号が出力されないのか ―― ですが、複数の 74HC590 と交換しても結果が変わらなかったことから、74HC590 の不良ということはまず考えられず、 やはり、オペレーションに問題があるのでしょう。 しかし、上記したプログラムリストを見た限りでは問題はなさそうです。 ・・・・・・ わからない。 また、上記したプログラムリストには挙げてはいませんが、この段階以前で 74HC590 の初期化を行っており、そのときのポートAからは h'20' を送っています。すなわち、 RA5(/CCKEN) = 1(カウント禁止)、RA4(/CCLR) = 0(カウンタクリア)、RA3(RCK) = 0(レジスタ状態は変化しない)の状態です。 そこで、ポートAからの各信号が実際にプログラム通りに出力されているかどうかを確認をするために、ポートAを操作した都度プログラムを止めて(直後に goto $ 命令を挿入)、 順にテスターで当たって確認をして行くことにしました。 まず、初期化直後では RA5(/CCKEN), RA4(/CCLR), RA3(RCK) = 1, 0, 0 となっておりOKでした。 次のポートA操作は、上記のプログラムリスト中の (1) で表した RA4(/CCLR) = 1(カウンタ値維持)ですが、テスターで当たってみるといきなりNGで RA4(/CCLR) = 0 のままです。 あっ、そうか ―― と思いましたがとりあえずここはパスをして先を進め、(2) から (6) までの信号がOKであることを確認しておきました。 結局、(1) の RA4(/CCLR) = 1 の動作のみNGであることが分かりました。 ―― そうなんです。 左下表(クリックすると拡大します)に示すように RA4 は他のポートと違って オープンドレイン出力になっているのです。 10KΩ程度の抵抗でプルアップをしてやらないと、(1) の命令( bsf PORTA,CCLR ;RA4(/CCLR) = 1: カウンタ値維持)を実行しても、 RA4(/CCLR) = 1 が出力されることがないのです。 (左右下の表は、マイクロチップ PIC16F873A および PIC16F883 データシートより抜粋)
したがって、プログラムでいくら RA4(/CCLR) に "1" をセットしてやっても、実際には "0" のままで "1" が出力されることはなく、すなわち初めから クリア状態のままで永遠にクリア状態が解除されることがなく、入力パルスをカウントすることができないでいたのです。 ちなみに、オリジナル回路で使用している PIC16F883 は、右上表に示すように RA4 はオープンドレイン出力にはなっておらず、他の一般のポートと同様に扱えますから プルアップ抵抗は不要です。 この違いに気が付かずにオリジナル回路をそのままコピーし、PICだけを PIC16F883 から PIC16F873A に変更をした私の不覚でありました。 修正後の 回路図 では、プルアップ抵抗が不要な他の空きポート番号に、3本の制御ポートとも変更をしました。
また、修正後の回路で追加をした RA3 の入力ポートに接続した ZERO SUP.(ゼロサプレス)スイッチは、LCDに表示する形態を変更するためのもので、 上写真に示すように、周波数を単純に8桁で表示する/先頭に連なる "0" をゼロサプレスする、の表示形態をスイッチを押すごとに切り替えるトグルスイッチとして機能します。 | |||||||||||||||||
| ページトップ |
|
| ページトップ |
|
本機(周波数カウンター)のような測定器を作製した場合に、私のような一般的なアマチュアがその精度をいかにして確保すれば良いのか、校正方法を含め
非常に難しい問題だと思います。 本機では、上記 回路図 のように 20MHz のクリスタルを使用しているため、PICの基準クロックは ( 1 / 20MHz ) * 4 = 0.2μS となります。 この 0.2μS を 50000 回カウントして、すなわち 0.2μS * 50000 = 0.01 S = 10 mS 周期でタイマー1オーバフロー割り込みを起こさせ、それをまた 100 回カウントすることによって 1秒(10 mS * 100 = 1000 mS = 1 S)という基準時間を作り出しています。 そして、その1秒間をゲート時間として測定をするパルス列(周波数)を通過させ、74HC590 と PICでその数をカウントしてLCDに表示をさせています。 このゲート時間がきっちりと正確な1秒間であることが理想的なんですが、現実的には、PICのオシレータ入力に繋がっている 20MHz のクリスタルが 正確な値で発振をしてくれないため、よって、その基準クロックも正確な 0.2μS とはならないために、ゲート時間(1秒)も理想からずれてしまうのです。 このクリスタルによる発振周波数を正確な 20MHz に合わせ込むためには、クリスタルの両端につながっている2つのコンデンサ(22pF)の容量を調整するために、 一般的にはトリマコンデンサや複数の容量のコンデンサを用意して、カットアンドトライで取っ替え引っ替えしながら調整する方法しかありません。 そのためには基準となる 正確な測定器も必要となるでしょう。 また、本機のようにユニバーサル基板を使用している場合には、数回のはんだの取り外しですぐにランドが剥がれてダメになってしまいます。 そこで、このようなハード的な方法ではなく、邪道かもしれませんが私がよく行っている方法をご紹介します。 まず、発振周波数を正確な 20MHz に合わせ込むことは、 上記の理由からきっぱりあきらめます。 そして、今回は正確な1秒のゲート時間を作り出すことが最終的な目的でもあることから、これをソフト的に補正をかけて 理想の1秒に近づけることにします。 それには、やはり基準となるもの(正確な発振器)が必要で、私の場合には、"京セラ" の "KTXO-18S" という超高精度クリスタルモジュールを使用しています。 10年ほど以前に "秋月電子通商" で複数個を購入したものの1つですが、現在ではもう既に販売はされていないようです。 ただし、私は購入したことはありませんが、現在では類似のものとして "VM39S5G" という超高精度クリスタルモジュールが販売さているようです。 (下左図は、 "秋月電子通商" で "KTXO-18S" を購入時に添付されていた資料より抜粋)
本機のプログラムリストの冒頭部分に定数の定義をしているところがありますが、そこで、タイマー1のカウントレジスタ(TMR1L, TMR1H)への設定値、 すなわち、タイマー1の割り込み周期を決める定数を次のように定義をしています。 xx equ 24 ;補正値 tm1_cycle equ 65536 - 50000 + xx ;割り込み周期: 4/20MHz * 50000 = 0.2μS * 50000 = 0.01 S = 10 mS ...... (1)そして、本機の入力端子に上右図に示す "KTXO-18S" による基準周波数を接続して、上記の補正値 xx の値を順に変更して行くと、次表のような結果を得ました。 表中で、LCD表示周波数の値には安定性がなく、実際には下1桁ないし2桁は数秒おきに値が変更されています。 したがって、表に記入した数値は変更を繰り返している 一瞬をとらえた代表的な1つの数値にほかなりませんので、これが絶対的な値ではないことを断っておきます。 また、この表では入力された基準周波数が完全なもの(0 ppm)と仮定していますので、表中の誤差(ppm)値は、実際には基準周波数の誤差も加味して考える必要があります。 とはいうものの、左上図に示すように "KTXO-18S" は ±1ppm ということですから、周波数に変換すると±12.8 Hz の範囲に誤差が収まっているという精度になります。
上表で補正値 xx が 0 のとき、すなわち何も補正をしなかったときには、約 + 8,000 Hz ほどの誤差がありますが、これはプラスの値であることから、 ゲート時間が実際の1秒よりも大きくてそのゲートを通過したパルス数が多くなってしまった、ということですので次式
1秒ゲートの作成方法と、ゼロサプレススイッチのON検出方法の見直し ( 2017/2/26 更新 ) 1秒ゲートの作成方法の見直しでは、前バージョンでは 10 mS のタイマー1の割り込み周期に値 xx の補正をかけ、その常に補正がかかった割り込み周期を 100 回カウントする方法であったのを改め、変更後は、1 〜 99 回目までは無補正の割り込み周期をカウントし、100 回目だけに値 yy の補正をかけるようにしました。 結果、 後者の方がきめ細かな時間単位で調節が可能となりました。 すなわち、前者では補正値を1だけ変更しても全体では 100 変更したことになってしまいますが、後者では 補正値は全体でも1ずつの変更が可能です。 具体的には、タイマー1の割り込み周期を決める定数を次のように定義を変更しました。 ;xx equ 24 ;補正値 ;削除 ;tm1_cycle equ 65536 - 50000 + xx ;4/20MHz * 50000 = 0.2μS * 50000 = 0.01 S = 10 mS ; tm1_cycle1 equ 65536 - 50000 ;4/20MHz * 50000 = 0.2μS * 50000 = 0.01 S = 10 mS ...... (2) yy equ 3135 ;補正値 tm1_cycle2 equ 65536 - 50000 + yy ;100回目の割り込み時のみ使用 ...... (3)そして、上述のように 1 〜 99 回目までは (2) を使用し、100 回目だけに (3) の補正をかけたものを使用しています。 その切り替えを実際に行っているところは、 次に示すリストのように割り込みルーチン内の一部で実現をさせています。 interrupt ; レジスタの保存 movwf w_save ;W レジスタの保存 swapf STATUS,W clrf STATUS movwf s_save ;STATUS レジスタの保存 movf PCLATH,W movwf p_save ;PCLATH レジスタの保存 clrf PCLATH btfsc INTCON,INTF ;外部割り込み(RB0/INT) か? goto int01 ;Yes btfsc PIR1,TMR1IF ;タイマー1オーバフロー か? goto t1int01 ;Yes goto int_end ;No : : ; タイマー1オーバフロー割り込み t1int01 bcf PIR1,TMR1IF ;タイマー1オーバフロー解除 ; movlw high tm1_cycle ; ; movlw high tm1_cycle1 ; ; (Ver. 1.01 にて変更) movwf TMR1H ;TMR1H に設定 ; movlw low tm1_cycle ; ; movlw low tm1_cycle1 ; ; (Ver. 1.01 にて変更) movwf TMR1L ;TMR1L に設定 decf sec1cnt,F ;1秒カウンタを -1 更新 decfsz sec1cnt,W ;1秒カウンタ = 0 か? ; goto int_end ;No ; ; movlw high tm1_cycle2 ; ; (Ver. 1.01 にて追加) movwf TMR1H ;TMR1H に設定 ; movlw low tm1_cycle2 ; ; movwf TMR1L ;TMR1L に設定 ; int_end : :前バージョンと同じように、補正値 yy の値を順に変更したときのLCD表示周波数との関係を、調べて次表のようにまとめてみました。 やはりLCD表示周波数の 値には安定性がなく、実際には下1桁ないし3桁が1秒おきに表示が変更しています。 とりあえず、補正値 yy に 3135 を採用しました。
今回は、LCD表示周波数を範囲で表示してはありますが、前バージョンと同様にこれらが絶対的な値ではないことを断っておきます。 しかしながら、 前バージョンでもそうでしたが、変動の範囲が大き過ぎるような気もしますが ・・・ 電源電圧の変動とか周囲温度の影響とかはある程度はあるとは思いますが、 それにしても大き過ぎるような ・・・ 何度も書いているように、本機ではPICの基準クロックをクリスタルを使用して(セラロックなどではなく)作り出しており、また、その基準クロックを使用して タイマー1の割り込み周期 10 mS、しいては1秒のゲート時間を作り出しているわけですから、そのゲートを通過するパルス数(周波数)の変動が大きい、 ということはどうも納得が行きません。 たとえ発振周波数が 20MHz からずれていたとしても、クリスタルを使用している以上ある程度の安定度は確保できるのでは ・・・ と思うのですが。 実は、私は過去に周波数カウンターをもう1台製作をしています。 その1作目はPICの基準クロックに単体のクリスタルではなく、本機の校正用に使用したものと同じ クリスタルモジュール "KTXO-18S" を使用しているのです。 その1作目の周波数カウンターで、今回 "KTXO-18S" を使用した(ややこしい?)基準周波数を測定すると、 かなり安定した表示をします。 プリスケーラの関係で下2桁が "08" または "16" のどちらかを必ず表示しています。 それに比べて本機では、上記した表の範囲内でたえずいろいろな値に変更を繰り返しながら表示をしています。 これはやはり、使用しているクリスタルの問題では なさそうな気がしますが、しかしどこかに問題があるはず ・・・ と思います。 最近、私のホームページの更新が滞りがちなのでこのページはとりあえず公開はしますが、 この問題については今後も検討を続けていきたいと思っています。 一方、ゼロサプレススイッチのON検出方法では、前バージョンでは1秒のゲート外で検出していた( ハードバグと回路検討 の項のリストを参照、次のリストでは上部でコメント行に変更した3行部分)のを、次のリストに示すようにゲート内で検出(ラベル main02 から main03 の部分) するように改めました。 : : main01 ; movlw 1 ; ; btfss PORTA,ZS_SW ;ゼロサプレススイッチ = OFF か?; (Ver. 1.01 にて削除) ; xorwf zsflg,F ;No. フラグをビット反転 ; clrf bin3 ;周波数入力カウンタの初期設定 clrf bin2 clrf bin1 clrf bin0 ; movlw high tm1_cycle ; ; movlw high tm1_cycle1 ; ; (Ver. 1.01 にて変更) movwf TMR1H ;TMR1H に設定 ; movlw low tm1_cycle ; ; movlw low tm1_cycle1 ; ; (Ver. 1.01 にて変更) movwf TMR1L ;TMR1L に設定 movlw 100 movwf sec1cnt ;1秒カウンタの初期設定 bcf zsflg,7 ;スイッチON入力受付済み解除 ; (Ver. 1.01 にて追加) bsf PORTA,CCLR ;RA1(/CCLR)=1: カウンタ値維持 bsf INTCON,GIE ;bit7(GIE)=1: 全割り込み許可 bcf PORTA,CCKEN ;RA2(/CCKEN)=0: カウント許可: (カウント開始) main02 btfsc zsflg,7 ;スイッチON入力受付済みか? ;;(Ver. 1.01 にて変更) goto main03 ;Yes ;; ;; btfsc PORTA,ZS_SW ;ゼロサプレススイッチ = ON か? ;; goto main03 ;No ;; ;; movlw 1 ;;この間で HC590からオーバーフローした xorwf zsflg,F ;No. フラグをビット反転 ;;/RCO数を 割り込みでカウントする bsf zsflg,7 ;スイッチON入力受付済み設定 ;; ;; main03 movf sec1cnt,W ;10 mS * 100 = 1 S ;; btfss STATUS,Z ;1秒経過したか? ;; goto main02 ;No ;; bsf PORTA,CCKEN ;RA2(/CCKEN)=1: カウント禁止: (カウント終了) bcf INTCON,GIE ;bit7(GIE)=0: 全割り込み禁止 bsf PORTA,RCK ;RA0(RCK)=1: カウンタのデータをレジスタにストア nop bcf PORTA,RCK ;RA0(RCK)=0: レジスタ状態は変化しない movf PORTC,W ;PORTC(HC590のレジスタ)の内容を movwf bin0 ;bin0に読み込む bcf PORTA,CCLR ;RA1(/CCLR)=0: カウンタクリア call bindec32 ;32ビット数値を10進数10桁の文字列に変換 call freq_display ;LCD への " xx,xxx,xxx Hz " 表示 goto main01 : :1秒のゲート内では文字通り1秒間の時間があるわけですが、それに対して、ゲート外ではほんの一瞬の時間しかありません。 その時間比でカウンター動作を 繰り返しているのですが、当然ながらスイッチのON検出をするためには、ゲート外ではスイッチのONを見逃すおそれが大きいため、ゲート内で検出する方が圧倒的に有利となります。 再度、1秒ゲートの作成方法の変更 ( 2025/11/20 更新 ) もしも、このページをご覧になって本機のクローン(Ver. 1.01)を製作された方がおられましたら、大変申し訳ありませんでした。 私が本機のプログラムを作成したのは9年近くも以前のことで、 PIC に関してもまだまだ未熟な頃で、思慮不足で大きな間違いを起こしていました。 本機では、1秒のゲートを作成するためにタイマー1割り込みを使用していますが、タイマー1は 16 ビットカウンタで、カウント値が 0xFFFF からオーバーフローをして 0x0000 になったときに、 割り込み が発生します。 カウント値の初期設定として 0x0000、または任意の値から始まり、0xFFFF の次に 1 回目のオーバーフローをして、次回からは 0x0000 からカウントをさせるような使い方をする場合には、 新たに初期値を再設定する必要がないためあまり問題はないのですが、上記 のように 0x0000 ではない初期値を再設定する場合に問題が起こります。 前バージョンでは、この割り込みが発生すると 割り込み処理 interrupt が実行され、タイマー1割り込み t1_int 内で初期値を再設定するまでに、 10 数ステップから約 20 ステップほどの命令が実行されます。 そして、その新しい設定値が設定されるまでの間にも、タイマーのカウントと周波数のカウントは続けられていて、これが 100 回も繰り返されて、 周波数のカウントには大きな誤差を生む(そのための補正は行ってはいますが)ことになります。 今回のプログラムでは、ここらあたりの誤差を極力無くすように大きく変更を行いました。 本機では、PIC の基準クロックが ( 1 / 20 MHz ) x 4 = 0.2 μS のため、タイマー1の 16 ビットカウンタでは 0xFFFF + 1(= 65536)、すなわち、1巡するまでに 0.2 μS x 65,536 = 13,107.2 μSを費やし、この 13,107.2 μS を 76 回繰り返すことで 13,107.2 μS x 76 = 996,147.2 μSとなりますが、1秒 ( 1,000,000 μS ) には 1,000,000 - 996,147.2 = 3,852.8 μS3,852.8 μS 足らないので、 3,852.8 / 0.2 = 19,264 65,536 - 19,264 = 46,272この値 46,272 を最後の 77 回目の初期値として、タイマー1割り込みを起こさせれば良いのですが、実際にはプログラムを簡単にするためもあって、逆に、この値を初期値とするのは 1 回目に行い、 2 〜 77 回目はオーバーフローした 0x0000 を初期値とするようにして、プログラムでの再設定は行っていません。 しかし、メイン・ルーチン内で ゲートをオープン してから、ゲートをクローズ するまでを1秒に近づけるために、クローズは割り込み処理内で 行っていますが、やはり、最後の 77 回目の割り込みの場合だけは、割り込み処理 内の赤字で示した1行目 bsf PORTA,CCKEN ;RA2(/CCKEN)=1: カウント禁止: (カウント終了)にたどり着くまでに実行される 10 数ステップほどの命令群(正確には 16 クロック分)が誤差となります。 ですから、実際には 1 回目の初期値としては、この誤差クロック分を差し引いて設定する 必要があります。 また、前バージョンでも述べたように、クリスタルによる発振周波数の誤差に対する補正値 xx も加味する必要があります。 xx equ 33 ;補正値 tm1_cycle equ 65536 - 19264 + 16 + xx ;1 回目の割り込み時のみ使用 また、タイマー1割り込みを制御するのに前バージョンでは、INTCON レジスタの GIE ビットを除いて、予め、タイマー1割り込みに必要な各レジスタの設定をすべてしておき、その後、INTCON レジスタの GIE ビットをオン/オフすることによって、1秒タイマーを作り出していました。 この点についても今回のプログラムでは、予め、T1CON レジスタの TMR1ON ビット以外の設定(GIE ビットをオンも含めて)をすべてしておき、その後に行うのは、この T1CON レジスタの TMR1ON ビットをオン/オフすることによって、1秒タイマーを作り出すように改めました。 ただし、最終的にゲートのオープン/クローズを決めるのは、上記のように PORTA レジスタの RA2 (/CCKEN) ビットで、この点については、前バージョンのプログラムでも今回のプログラムでも 変わることはありませんが、上記したようにクローズは割り込み処理内で行っています。 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
もう1つ、大きな間違いがありました。 次の図表は既に 上掲 したものに、私自身が分かりやすくなるように彩色をして再掲しました。
プリスケーラとして使用した 74HC590 の /RCO 出力について、その数をカウントするのに本機では、PIC の外部 (RB0/INT) 割り込みを使用していますが、前バージョンでは、立ち下がりエッジで 割り込みを掛けていました。 これは大きな間違いで、立ち上がりエッジで割り込みを掛けるようにしないと、最大で 255 の狂いを生じます。 左下のタイミング図で左端の赤色線を引いた部分に注目をしながら、なぜ /RCO の立ち上がりエッジ(O で囲んだ部分)でないといけないのか、CCK、RCK、/RCO の各信号の関係をよく理解しないと 間違いを起こします。
以上、前バージョンでのいくつかの不備等を改めて、新しく作り直したものが、次に示すプログラム(メイン・ルーチンと割り込み処理の部分を抜粋)です。 次のリスト(メイン・ルーチン)内の赤字ステートメントで示した、1行目(bsf T1CON,TMR1ON)でタイマー1を使用する 1秒タイマーのカウントが開始されるとともに、2行目(bcf PORTA,CCKEN) によってゲートがオープンされて、74HC590 の CCK(カウンタクロック)入力端子(回路図 を参照)に接続されている、測定をするパルス列(周波数)のカウントが始まります。 このパルス列(周波数)のカウントは、次の青字ステートメント群で示した、1行目(main02 btfsc PORTA,CCKEN)でゲートがクローズされたのを検出されるまで(厳密には、タイマー1割り込み内で ゲートがクローズ(bsf PORTA,CCKEN)されるまで)続けられます。 ;========================================================================== ; メイン・ルーチン ;========================================================================== main movlw b'00001100' ;表示ON call Lcd_Cmd ;LCD へコマンドを出力 clrf zsflg ;ゼロサプレスフラグの初期設定 movlw b'11010000' ;bit7(GIE)=1: 全割り込み許可, ;bit6(PEIE)=1: 周辺機器割り込み許可, ;bit4(INTE)=1: 外部割り込み(RB0/INT)許可 movwf INTCON bsf STATUS,RP0 ;バンク 1 bsf PIE1,TMR1IE ;タイマー1割り込みを許可 bcf STATUS,RP0 ;バンク 0 main01 clrf bin3 ;周波数入力カウンタの初期設定 clrf bin2 clrf bin1 clrf bin0 bsf PORTA,CCLR ;RA1(/CCLR)=1: カウンタ値維持 bcf zsflg,7 ;スイッチON入力受付済み解除 movlw 77 movwf sec1cnt ;1秒カウンタの初期設定 movlw high tm1_cycle ; movwf TMR1H ;TMR1H に設定 movlw low tm1_cycle ; movwf TMR1L ;TMR1L に設定 bsf T1CON,TMR1ON ;タイマー1を動作 bcf PORTA,CCKEN ;RA2(/CCKEN)=0: カウント許可: (カウント開始) main02 btfsc PORTA,CCKEN ;RA2(/CCKEN)=1: (カウント終了) か? goto main03 ;Yes btfsc zsflg,7 ;スイッチON入力受付済みか? goto main02 ;Yes btfsc PORTA,ZS_SW ;ゼロサプレススイッチ = ON か? goto main02 ;No movlw 1 xorwf zsflg,F ;サプレスフラグをビット反転 bsf zsflg,7 ;スイッチON入力受付済み設定 goto main02 main03 bsf PORTA,RCK ;RA0(RCK)=1: カウンタのデータをレジスタにストア nop bcf PORTA,RCK ;RA0(RCK)=0: レジスタ状態は変化しない movf PORTC,W ;PORTC(HC590のレジスタ)の内容を movwf bin0 ;bin0に読み込む bcf PORTA,CCLR ;RA1(/CCLR)=0: カウンタクリア call bindec32 ;32ビット数値を10進数10桁の文字列に変換 call freq_display ;LCD への " xx,xxx,xxx Hz " 表示 goto main01プリスケーラとして使用した 74HC590 は8ビットバイナリカウンタなので、内部カウンタでは 0x00 から 0xFF までしかカウントすることができません。 そこで、内部のカウント値が 0xFF になったときに /RCO から Low を出力します。 そして、次の入力パルスによって内部カウンタは 0x00 に戻るとともに、/RCO 出力を High に戻します。 すると、この /RCO 出力が High に戻ったとき(立ち上がりエッジ)を、本機では PIC の外部 (RB0/INT) 割り込みを使用してその数を、次のリスト(割り込み処理)内の青字ステートメント群で 示したように、4バイトカウンタの内の上位3バイト(bin1, bin2, bin3)でカウントしています。 これら一連のパルス列(周波数)のカウントは、次のリスト(割り込み処理)内の赤字ステートメントで示した、1行目(bsf PORTA,CCKEN)によってゲートがクローズされるまで続けられます。 上述したように タイマー1割り込みは、1 + 76 = 77 回(変数 sec1cnt の初期値)繰り返されて、その度ごとに変数 sec1cnt をデクリメントして、sec1cnt = 0 となった時点で繰り返しは終了で、 すなわち1秒が経過したわけなのでゲートをクローズするとともに、2行目(bcf T1CON,TMR1ON)でタイマー1の動作も停止させます。 その後、下リストの割り込み処理から上リストのメイン・ルーチンに戻ると、上述したように、青字ステートメント群で示した、1行目(main02 btfsc PORTA,CCKEN)でゲートがクローズされたのを 検出して、ラベル main03 にジャンプして(main03 bsf PORTA,RCK)ステートメントが実行されます。 これは何をしているのかというと、74HC590 の RCK に High を送りその立ち上がりエッジで、74HC590 の内部カウンタ8ビットの(現在残っている)値を、レジスタ、3-ステートバッファを通して、 74HC590 の出力端子 QA, QB, QC, QD, QE, QF, QG, QH に出力するように指示をしています。(上の再掲した ブロック図 を参照) そして、それら8ビットの出力は PIC のポートCに接続(回路図 を参照)されているため、上リストの下から6行目〜5行目で、プログラム内で使用している 変数(最下位カウンタ)bin0 に取り込んでいます。 これで4バイトカウンタのすべてに値が揃ったことになります。 その後は、これら4バイト(bin0 〜 bin3)のカウンタの値を 10 進数に変換後、LCD で表示をしていますが、これらは前バージョンと何ら変わるところはありません。 ;========================================================================== ; 割り込み処理 ;========================================================================== org h'0004' ;割り込みベクタ interrupt ; レジスタの保存 movwf w_save ;W レジスタの保存 swapf STATUS,W clrf STATUS movwf s_save ;STATUS レジスタの保存 movf PCLATH,W movwf p_save ;PCLATH レジスタの保存 clrf PCLATH btfsc INTCON,INTF ;外部割り込み(RB0/INT) か? goto rb0_int ;Yes btfsc PIR1,TMR1IF ;タイマー1オーバフロー か? goto t1_int ;Yes goto int_end ;No ; 外部(RB0/INT)割り込み rb0_int bcf INTCON,INTF ;外部割り込み(RB0/INT)フラグをクリア incf bin1,F btfss STATUS,Z goto int_end ;No incf bin2,F btfss STATUS,Z goto int_end ;No incf bin3,F goto int_end ; タイマー1割り込み t1_int bcf PIR1,TMR1IF ;タイマー1割り込みフラグをクリア decfsz sec1cnt,F ;1秒カウンタ = 0 か? goto int_end ;No bsf PORTA,CCKEN ;RA2(/CCKEN)=1: カウント禁止: (カウント終了) bcf T1CON,TMR1ON ;タイマー1を停止 ; 割り込み処理の終了 int_end movf p_save,W movwf PCLATH ;PCLATH レジスタの復帰 swapf s_save,W movwf STATUS ;STATUS レジスタの復帰 swapf w_save,F swapf w_save,W ;W レジスタの復帰 retfie ;割り込みからの復帰今回も、補正値 xx の値を順に変更したときの LCD 表示周波数との関係を調べて、次表のようにまとめてみました。 前バージョンまでは、LCD に表示される周波数の値には安定性がなく、 下1桁 〜 3桁が1秒おきにたえず変動しながら表示されていたのが、うそのようにピタッと止まりました。 ただし、下1桁だけは表のように、どの補正値に対しても 1 Hz だけの範囲で変動があります。 表中には2値の範囲で書いてありますが、左側の値がほぼ安定して表示される値で、 ときどき(数秒間に1度)右側の値でも表示されることがあります。(1つの補正値に対して数分間単位で測定していると、1 Hz ずつの3値程度の変動もありました。) 誤差の ppm 表示では、小数点以下2位まで求めてもあまり意味がないとは思いますが、変動の範囲がすべて 1 Hz なので、その2値の違いを表すために2位までとしました。 結果は次表に示すように、補正値を xx = 33 とした場合が最も理想的な測定値となり、最終的に本機のプログラム(Ver. 1.02)の "定数、変数の定義とレジスタ割付け" 内で、 xx equ 33 ;補正値 tm1_cycle equ 65536 - 19264 + 16 + xx ;1 回目の割り込み時のみ使用のように定義をしました。
校正をするために使用したクリスタルモジュールは、前バージョンと同様に、昔、 "秋月電子通商" で購入した、"京セラ" の "KTXO-18S" という超高精度クリスタルモジュールを 使用しました。(現在では入手するのが困難と思われますが、これに代わるものとして "VM39S5G" が販売(在庫限り)されているようです。) そして、上表はそのモジュールの出力 12.8 MHz が完全なもの(誤差 ± 0 ppm)と仮定をした表となっていますが、実際にはそんなことはあり得ないわけで、上述もしたように "KTXO-18S" は ±1ppm ということですから、周波数に変換すると ± 12.8 Hz の範囲の精度誤差があり、本当はそれを加味して考える必要があります。 本機のシステムクロックとして使用したクリスタルは、これも "秋月電子通商" で購入した 20 MHz のクリスタルで、そのデータシートによると ± 30 ppm の精度となっていますが、上表の補正値なし ( = 0 ) の欄を見てみると、私が使用したクリスタル 20 MHz では、12.8 MHz を測定したときに誤差値は + 10 ppm 以内に収まっています。 これには、周囲温度とか電源電圧の安定性などの影響も少しはあると思いますが、そのほとんどが使用したクリスタルの精度誤差だけに影響されたものと考えられ、かなり良い値ではないでしょうか。 そんな精度のクリスタルを使用した本機では、プログラムによって上表のように補正値 xx = 33 とした場合に、最も理想的な値を示す "周波数カウンター" になってくれました。 この項の 冒頭 でも申し上げましたように、本ページをご覧になって、本機のクローン(Ver. 1.01)を既に製作をされた方々には、大変ご迷惑をおかけしました。 その方たちにはぜひとも次に掲げてある、"現在の最新プログラムバージョン: Ver. 1.02" に更新をしていただけると、前作の "周波数カウンター" が見違えるほどに生まれ変わります。 しかしながら、この補正値 33 というのは、あくまでも私が使用したクリスタルの場合で、誤差はクリスタル個々によって異なるので、そのままクローンを製作されても同結果になるとは限りません。 したがって、できることなら、私が行ったように基準となるような周波数(例えば 12.8 MHz)をご用意されて、実際に使用する個々の 20 MHz クリスタルに対して校正されれば(補正を掛け直せば) 申し分ないと思います。 ところが ・・・・・ 一夜明けて次の日にもう一度電源を入れてみたところ、とんでもない表示をするようになりました。 条件は前日に設定をしたまま(上表の黄色の補正値 33 のまま)で、同様に "KTXO-18S" の 12.8 MHz を測定した結果、12,799,999 〜 12,800,255 Hz の2値が表示されます。 その次の日には、12,799,998 〜 12,799,997 Hz と表示されました。 これらの表示値の一貫性の無さは、現在、測定をしている時期が原因(日々寒くなって行く)、すなわち周囲温度に変化があるためと思われますが、問題はそこではなく、2日目の測定値 12,799,999 〜 12,800,255 Hz にあります。(12,799,999 〜 12,800,000 Hz の変動時に限って起こる現象) 自分では上に再掲した タイミング図 を理解したつもりだったのですが、また、その上でのプログラムなのですが、まだ考慮不足があるのかもしれません。 そして、その後1週間ほどジタバタと、プログラムを ああでもない、こうでもない、といろいろと試してみたのですが、相変わらず余分な 255 を取り除くことはできませんでした。 したがって、次に掲げる "現在の最新プログラムバージョン: Ver. 1.02" は、作者としても残念ですがとりあえずの暫定版ということにしておきます。
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ページトップ |
![]() |
![]() |
| プリント基板(1)パターン図 (部品面) (FreqCounterII_PC.CE3) | ページトップ |
| ここでは "改造" と言っていますが、単に ICSP 端子(6P ピンヘッダ)を追加しただけで、カウンタとしての機能には影響はありません。 |
![]() |
![]() |
![]() |
| プリント基板(1)パターン図 (部品面) (FreqCounterII2_PC.CE3) | 黒色文字を除いた図 (FreqCounterII2_PC2.CE3) | ページトップ |
![]() |
![]() |
| プリント基板(1)パターン図 (ハンダ面) (FreqCounterII_PC1.CE3)
| ページトップ |
![]() |
![]() |
| プリント基板(1)パターン図 (ハンダ面) (FreqCounterII2_PC1.CE3)
| ページトップ |
![]() |
![]() |
||
| コネクタ, ケーブルを 取り付け前の様子 , 取り付け後の様子 | |||
| プリント基板(2)パターン図 (部品面) (FreqCounterII_2PC.CE3) | ページトップ |
![]() |
![]() |
||
| コネクタ, ケーブルを 取り付け前の様子 , 取り付け後の様子 | |||
| プリント基板(2)パターン図 (ハンダ面) (FreqCounterII_2PC1.CE3) | ページトップ |
| LCDモジュールとプリント基板を繋ぐための、フラットケーブル、コネクタ(ピンソケット)の取り付け例を次に示します。 |
![]() |
![]() |
| ページトップ |
|
使用した液晶モジュール(S-10551D)を固定させるための、取り付け用穴の横幅間隔は 75 mm となっており、ケースに取り付けるときに下の
ケース加工図 に示すように、液晶モジュールの下には 72 mm 幅のプリント基板(1)が位置するため、このままではプリント基板(1)が邪魔となって
液晶モジュールを取り付けることができません。 そこで、液晶モジュールの取り付け用穴の横幅間隔を広げるために、次の写真に示すように、プリント基板の端材を使用した継ぎ手を左右に足し込んでやることによって、 左右それぞれ 5 mm ずつの横幅間隔の拡張を確保し、プリント基板(1)を十分に跨ぐことが可能なようにアダプタを取り付けました。 液晶モジュールにアダプタを取り付けるときの注意点としては、下写真中の上段右側の写真に示すように、アダプタとしてのプリント基板片は、必ず液晶モジュール基板の 下側に位置するように取り付けます。 といっても、液晶モジュールの構造上(黒枠部分の左右両端が邪魔をして)上側には取り付けはできない、はずです。
そして、アダプタを取り付けた液晶モジュールをケースに取り付けるためには、左下の写真に示すように M 2.6 のビスとスペーサーが必要ですが、 M 2.6 用のスペーサーは一般的ではなく入手が困難なため、自作をして使用しました。 その自作方法については "万年カレンダー" の "ケースへの液晶モジュールの取り付け" で既に紹介していますので、そちらの項を参照してください。 右下の写真は、自作をしたスペーサーを実際に使用してケースに取り付けた様子を、ケースの後側面から見たところです。 青色↓印の位置にそのスペーサーをはさんで、 ケースの底面側と液晶モジュール用アダプタの上面側から各 M 2.6 のビスで取り付けています。
また、プリント基板(2)のようなものの取り付けでは、通常私は、ケースの内側面に沿って取り付けを行っているのですが、今回の製作に限り次の写真のように、 ケースの外側面側に取り付けを行いました。 それは周波数の入力端子に使用しているターミナルブロック(青色のもの)の構造上、ケースの内側面側では、ケースの厚さが 2 mm ほどありますので接続する部分(根本付近にある)が断面に少しばかり隠れてしまって、使用時に支障をきたすからです。 したがって、写真のようにプリント基板を外側面側に取り付けたことによって、ターミナルブロックの左側にあるタクトスイッチも外側に飛び出した格好となり、 面体も非常に悪くなりましたが致し方がありません。
|
| ページトップ |
| 使用したケースは、100均(セリア)で購入した "クリアケース ミニ (L-8033) サナダ精工" という、ポリスチレンケースです。 |
![]() |
| ケース加工図 (FreqCounterIICS.CE3) |
![]() |
![]() |
![]() |
|||
| ケース左側面から見たところ | 蓋をあけて下箱の内部を真上から見たところ | ケース右側面から見たところ |
| ページトップ |
| (主要部品: IC, トランジスタ等) | (データシート) | ||
| PICマイコン | .................... | PIC16F873A | |
| HC-MOS | .................... | HD74HC590P | |
| LCDモジュール | .................... | S-10551D | |
| 部品表
| Excel ファイル (FreqCounterII_parts.xls)
| ページトップ |
|
ここ数年間、本機はお蔵入り状態? になっていたのですが、1年と数か月ほど前にあることがあって本機の電源を入れたところ、LCD 画面には左下写真の状態で表示がされるようになっていました。
使用した LCD モジュール S-10551D は、2009 年 4 月ごろに "秋月電子通商" で複数個を同時購入したものの1つで、他の作品でも使用をしています。 参考までに、同型番の LCD モジュールを使用した、"145. 長時間ストップウオッチ/タイマー" にも電源を入れて確認をしましたが、 こちらは特に異常は無さそうでした。
そして、再びお蔵入りになってしまっていた本機ですが、最近になって、プログラムの項の 再度、1秒ゲートの作成方法の変更 で述べたように、プログラム変更を行うためには、 まず、LCD 画面の表示を何とか(正常に戻すように)しなければなりません。 画面の表示にこのような症状が現れる場合には、恐らく LCD モジュール自体に劣化等の問題があるのでは? と想像しますが、本当のところは良く分かりません。 私に出来ることは、モジュール裏面にある LSI の HD44780A やフィルムケーブル辺りの配線に異常がないかを、目視チェックで調べる程度しかありません。 結局、新しいモジュール(と言っても、この不良モジュールと同時期に購入しておいた未使用のモジュール)と交換をした方が早いので、フラットケーブルの付け替えが面倒でしたが、新しいモジュールに 交換をしました。(この項は、こう言った事実があった、という記録を上3枚の写真とともに残しておくのが目的です。) |
| ページトップ |
| 周波数カウンタ組立キット(連載トップページ) | .......... | http://userweb.alles.or.jp/chunichidenko/fcounter1.html |
| 32ビット数値を10進数10桁の文字列に変換する | .......... | http://orange.zero.jp/electronics/pic/hxdec32c_mp.txt (現在リンク切れ) |