ブログ 「QRPな自作の日記」で紹介した、ディップメータ内蔵用の3桁LEDのダイナミ
ック点灯方式の周波数カウンタのプログラムを解説します。
このプログラムは、ディップメータのみならず、汎用の3桁周波数カウンタとして使
用することができます。
ハードウェアの仕様で制限されますが、入力する信号レベルが高ければ150MHz位までは
表示可能と思われます。
ディップメータを含めた、回路図、出来上がりは、下記のURLを参照ください。
http://blog.toshnet.com/article/3512822.html
http://blog.toshnet.com/article/3634215.html
http://blog.toshnet.com/article/3694989.html
プログラムとしての基本構成は、次の3つになります。
(1) 周波数カウント部
(2) 3桁LEDダイナミックスキャン表示部
(3) カウントした周波数を3桁で表示するための演算部
まず、(1) 周波数カウント部です。
この部分は以前に解説した周波数カウンタと基本は同じです。
違うところは、周波数表示が3桁であるために1Hz単位までのカウントが必要ない点です。
今回は、12.8MHzの基準クロックを使用し、これをプリスケーラで1/256することに
よって、5.12mS毎のタイマー割り込みを発生させ、この時間に周波数カウントするこ
ととしました。
従って、マイコンとしての周波数最小分解能は、1/5.12mS=195.3125Hzと
いうことになります。
実際には、マイコンだけだとカウントできる周波数の最大値は、基準クロックの
1/2=6.4MHz程度までであり、100MHz程度まで測定できるディップメータの周波数
表示としては使用することができないために、マイコンの前段にロジックICを使用し
た1/32のプリスケーラ(分周器)を接続して使用しています。
これによって、ロジック的には最大32×6.4MHz=204.8MHzまでカウントできる事に
なります。実際には、カウントする発信器の出力レベルをロジックレベルまで増幅
するアンプの周波数特性が影響を与えます。
今回製作したディップメータでは、96MHzくらいが限界でした。
周波数表示は、組み込むディップメータが1.8MHz〜100MHz程度の範囲のため、3桁の
表示では、
(1)1.80MHz〜9.99MHz
(2)10.0MHz〜99.9MHz
(3)100MHz〜
となります。従って、表示周波数の精度を考えても、表示桁の一つ下の桁の精度さえ
満足できれば十分であり、195.3125Hz×32=6.25KHzはその条件を満たしています。
下記のプログラムが、周波数カウント部分です。
カウントした周波数は、”Freq"という変数に格納されます。
1カウントは、上記の説明のように195.3125Hzとなりますのでマイコンに入力される
真の周波数は、
Freq×195.3125Hzと言う事になります。
最大6.4MHzのカウント場合、5.12ms間のカウント数は32768で、周波数を数える
Timer1カウンタ16bit(65536)を越える事はありませんので、Timer1カウンタの
オーバーフロー処理は何もせず、リターン命令だけ、擬似的に入れてあります。
このプログラムでは、入力された信号の周波数カウントは出来ますが、表示機能は
ありません。周波数カウンタの基本の部分だけです。
'***************************************************
'* TIMER INT INIT & START
'***************************************************
Config Timer0 = Timer , Prescale = 256 '5.12mS at 12.8MHz
On Ovf0 Tim0_int
Enable Ovf0
Config Timer1 = Counter , Edge = Falling , Noise Cancel = 1
On Ovf1 Cnt1_ovf
Enable Ovf1
Enable Interrupts
Timer1 = 0
Start Timer1
Main:
Goto Main
'************************************************
'* TIMER INT COUTER SUBROUTINE
'************************************************
Tim0_int:
Gosub Timerintsub
Return
Timerintsub:
Stop Timer1
Freq = Timer1
Timer1 = 0
Start Timer1
Return
Cnt1_ovf:
Return
次に、(2) 3桁LEDダイナミックスキャン表示部 を説明します。
ダイナミックスキャンのいいところは、使用するポート数が少なくて済むところ
ですが、表示桁ごとにデータを入れ替える作業をしなければなりません。
ここでは、5.12mS毎のタイマー割り込みルーチンで、3桁を順番に切り替えて表示
するようにプログラムしています。
どの桁を表示するかを”Dispcnt"と言う変数を定義して一回割り込み毎に1を足して
数え、表示桁を切り替えています。
表示する7セグメントのデータは、LEDに接続されたPin番号に合わせたテーブル
データ(7segd)を表示する桁(Seg0〜2)での値(7segd:0〜9)に対応して読み
込みます。
そして、その値をLEDの接続されたポートに出力します。
これを、桁ごとに、5.12mS周期で繰り返します。
3桁を
表示するのに、5.12mS×3=15.36mSとなり、電源周波数60Hzよりも少しだけ大きい
値です。何とかフリッカーのない表示が出来ていると思っています。
これを倍の10.24mS毎にスキャンしますと明らかにちらつきとなって見えます。
下記のプログラムは、3桁LEDダイナミックスキャン表示部の基本の部分を表示しています。
Timerintsub:
Stop Timer1
Freq = Timer1
Timer1 = 0
Start Timer1
If Dispcnt = 0 Then
Data7segd = Lookup(seg0 , 7segd)
Portd = &B0001100
Elseif Dispcnt = 1 Then
Data7segd = Lookup(seg1 , 7segd)
Portd = &B0010100
Elseif Dispcnt = 2 Then
Data7segd = Lookup(seg2 , 7segd)
Portd = &B0011000
End If
Dispcnt = Dispcnt + 1
If Dispcnt = 3 Then Dispcnt = 0
Portb = Data7segd
Return
Cnt1_ovf:
Return
'************************************************
'* 7seg LED DISPLAY DATA
'************************************************
7segd:
Data &B11101011 , &B00101000 , &B10110011 , &B10111010 , &B01111000 , &B11011010 ,
&B11011011 , &B11101000 , &B11111011 , &B11111010 , &B11010011 , &B00010001
次は、カウントした周波数を3桁で表示するための演算部です。
上記3桁LEDダイナミックスキャン表示部の表示データは各桁 Seg0〜2の値が得られて
いる事を前提としていますが、次は、その値を演算する部分を説明します。
他にいい方法があるのでしょうが、当局はこれしか思いつきませんでした。
製作したディップメータの測定範囲は1.8MHz〜100MHz程度であるため、3桁での
周波数表示は100MHz以上、10MHz〜99.9MHZ、1MHz〜9.99MHzの3つのレンジに分類され
ます。
つまり、100MHz以上では、MHz台までの3桁表示、10MHz〜99.9MHzでは、**.*MHz
の小数点第一までの3桁表示、1.8MHz〜9.99MHzでは、*.**MHzの小数点第二までの
3桁表示になるようにしました。
従って、
100MHz以上の時は、測定した周波数を1000000で割って上位3桁のみの数値とします。
10MHz〜99.9MHzの時は同様に100000で割って3桁の数値とします。
1.8MHz〜9.99MHzの時は同様に10000で割って3桁の数値とします。
この値を変数Freqdとします。
次に、最上位の桁(ここではSeg0)を求めるために3桁の数値Freqdを100で割ります。
これがSeg0の値です。
その次に、2桁目の値を求めます。
3桁の数値Freqdから、Seg0の値に100を掛けた値を引きます。:Segtmp1=Freqd-Seg0*100
これにより、下位2桁の値segtmp1が求まります。
2桁目の値を求めるために、下位2桁の値Segtmp1を10で割ります。
この値がSeg1の値となります。
その次に、最下位の桁Seg2を求めます。
下位2桁の値Segtmp1から、Seg1の値に10を掛けた値を引きます。:Seg2=Segtmp1-Seg1*10
この値がSeg2の値となります。
使用している言語であるBASCOM−AVRでは、同時に2つの演算ができないので一つずつ
計算して値を求めます。
こうして、3桁のそれぞれの値、Seg0、Seg1、Seg2が求まりました。
If Freqd >= 1000000000 Then '100MHz>FREQ
Freqd = Freqd / 1000000
Goto Leddisp
End If
If Freqd >= 10000000 Then '99.9-10.0MHZ:FREQ
Freqd = Freqd / 100000
Goto Leddisp
End If
If Freqd >= 1000000 Then '1.00-9.99MHzMHz
Freqd = Freqd / 10000
Seg1 = Seg1 And &B11111011
Goto Leddisp
Leddisp:
Seg0 = Freqd / 100
Segtmp1 = Seg0 * 100
Segtmp1 = Freqd - Segtmp1
Seg1 = Segtmp1 / 10
Segtmp2 = Seg1 * 10
Seg2 = Segtmp1 - Segtmp2
Goto Main
実際には、この3つの周波数レンジをうまく表示するためには、小数点を表示する
必要があります。
小数点は、各桁の7SegLEDに含まれますので、それぞれの桁表示の値
(ここではSeg0とSeg1)に表示される周波数のレンジに対応して小数点を表示するか
どうかを設定する必要があります。
ここでは、周波数レンジと同じようにして小数点の必要な桁を分類して、表示する
7segデータに論理積で強制的に小数点を消去、表示は論理和で小数点表示を行っています。
このプログラムは、賢明な方法とは思っていませんが、とりあえず動作はしているのでこのまま使用しています。
自分なりに解析してみてください。下記の部分です。
If Dispcnt = 0 Then
Data7segd = Lookup(seg0 , 7segd)
If Freq >= 1600 Then Data7segd = Data7segd And &B11111011
If Freq < 1600 Then Data7segd = Data7segd Or &B00000100
Portd = &B0001100
Elseif Dispcnt = 1 Then
Data7segd = Lookup(seg1 , 7segd)
If Freq >= 1600 Then Data7segd = Data7segd Or &B00000100
If Freq >= 16000 Then Data7segd = Data7segd And &B11111011
If Freq < 1600 Then Data7segd = Data7segd And &B11111011
Portd = &B0010100
Elseif Dispcnt = 2 Then
Data7segd = Lookup(seg2 , 7segd)
Portd = &B0011000
End If
Dispcnt = Dispcnt + 1
If Dispcnt = 3 Then Dispcnt = 0
Portb = Data7segd