周波数カウンタ(LCD版)
R8C/27を用いたLCD表示の周波数カウンタです。
ニキシー管表示にしたいところですが、手始めにLCD版を作りました。
とりあえず、できた周波数カウンタの外観を披露しておきます。
最初に秋月電子通商のR8C/27マイコン開発セットで試作し、続いて基板を作成しました。下の写真は作成した基板を組み立てたものです。

周波数カウンタ外見(上面より)


周波数カウンタ外見(裏面より)




[目標仕様]
上限の周波数は6MHz強といったところです。入力アンプや波形整形回路は設けていません。マイコンのタイマ入力回路の特性にお任せです。
今さら普通の周波数カウンタを作っても‥というところがありますが、今回はジッタの多い信号の周波数を平均化して測定したいというニーズがあって、それに対応するようなものにしました。

[設計]
計数やLCDモジュールの制御にはルネサスのワンチップマイコンの1つであるR8C/27を使用しました。

−マイコン開発環境−
まずは秋月電子通商のR8C/27マイコン開発セットを購入しました。なお、電源には5V/1A出力のスイッチング電源を使用しています。基板はコネクタ類を半田付けすれば、とりあえずOKです。
次にCD-Rに入っていた開発環境をMicrosoft WindowsXP にインストールしました。(CD-Rに入っていた開発環境はVistaには(少なくとも簡単には)インストールできないようでした。ルネサスのホームページからはVistaの開発環境も無償ダウンロードできますが、インストールしただけではコンパイルやリンクのオプションが設定されないようでした。インストール手順をどこかで間違えたのかもしれませんが、環境構築などはとっとと済ませてしまいたかったので追求していません。)
→ 2010.03.15 再度新しいプロジェクトを作成してみたところ、デフォールトでチャンと全体ビルドができました。今回のプロジェクト作成時に、以前の作成時とどこの設定がどう違うのか、そのうち調べたいと思います。(今回は「標準I/Oライブラリを使用する」のチェックは入れませんでしたが、これが決定的な差異かどうかはまだわかりません。)

CD-Rには3つほどのサンプルプログラムが添付されています。これらを動作すれば、ハード、ソフトが正しくセットされ、正しく操作できたことの大まかな確認になります。
秋月のCD-Rに沿って素直に環境構築していくと、R8Cコンパイル編.pdf にしたがってサンプルプログラムのビルドを行うことになります。ここではあまり先のことを考えずにしたがうのが吉です。つまり、新規ワークスペースの作成としてCD-Rに入っているサンプルプログラムと同名のプロジェクト名を入力することになっていますが、pdfの通りに同名のプロジェクト名で新規にプロジェクトを作成します。そうすればうまく行くことでしょう。サンプルプログラムの中にはLCDに表示するものもありますから、プログラム作成時の参考になります。
注意: 当方の場合、最初ビルド・フラッシュ書き込みが成功しても正常動作しませんでした。
 原因:サンプルプログラム中の外部水晶発振の安定待ち時間の不足でした。
 対策: cプログラムの中に asm("NOP"); が4行ありますが、その直後に for(i=50;i>0;i--); の時間待ちを追加しました。i は、たまたま元プログラムで unsigned int として定義されていたので改めて宣言する必要がありません。自分の場合には50でOKでしたが、マイコンの資料では評価して決めるようにとのアドバイスですので、場合によってはもっと大きくする必要があるかもしれません。127もあればおそらく十分と思いますが‥。高温や低温環境で使用するのであれば、そのような条件でも確認したうえ、余裕を見た値にするべきでしょう。おそらくサンプルプログラムの開発者のところではNOP 4行で十分だったのでしょう。開発時の基板が、商品の基板と異なっていたのかもしれません。

−周波数カウンタとしてのペリフェラルの割り当て−
周波数カウンタとしては、1秒ごとに計測値を更新することにします。
つまり、入力信号のパルス数を1秒ごとに集計します。また、仕様で述べたようにジッタの多い信号の周波数を平均化して測定したいという事情があります。ですから、計測を開始してからパルス数をずっと積算していき、計測開始後の秒数で割ることで平均周波数を求めて表示することにします。
このようなことを実現するにはタイマRCのインプットキャプチャ機能を用いるのが適当と思われます。
あと1秒ごとに取り込み信号をタイマRCに与える必要がありますが、このためにタイマRAとタイマRBを使用することにします。
 ところで、マイコン開発セットではLCDを駆動するためにLCDのDB7〜4の4本とP3_5、P1_2、P1_1、P1_0が、またLCDのRS端子とP3_3が、LCDのE端子とP3_4が接続されています。また、フラッシュ書き換え用にP3_7とP4_5が使用されます。さらにP4_6、P4_7は外部発振子を接続するのに使用します。
 周波数カウンタ実現のためにタイマを使用するにあたって、タイマRBからの1秒パルスをP3_1/TRB0端子から出力します。
また、タイマRC用にカウントソースとしてP3_3/TRCCLK端子、インプットキャプチャ用としてP5_3/TRCIOC端子を使用することにします。
 LCDのRS端子と接続していたP3_3がタイマに取られるのでRS端子はP3_6と接続することにします。ついでにLCDのDB7の接続をP3_5からP1_3に変更します。この方がLCD駆動のプログラムもわずかですが楽になります。
これらを表にまとめると次のようになります。

表 MCUピン番号と周辺機能割り当て
ピン番号 端子名 機能割り当て コメント
2
P3_7 TXD1 (MODE="L"時) 開発セットから変更なし
3
RESET# RESET# 開発セットから変更なし
4
P4_7 XOUT 開発セットから変更なし
5
VSS VSS 開発セットから変更なし
6
P4_6 XIN 開発セットから変更なし
8
MODE MODE 開発セットから変更なし
9
P4_5 RXD1 (MODE="L"時) 開発セットから変更なし
11
P3_6 LCD RSを駆動 開発セットから変更あり
12
P3_1 TRBO 新規機能割り当て
14
P5_3 TRCIOC 新規機能割り当て
18
P1_3 LCD DB7を駆動 開発セットから変更あり
19
P1_2 LCD DB6を駆動 開発セットから変更なし
21
P1_1 LCD DB5を駆動 開発セットから変更なし
22
P1_0 LCD DB4を駆動 開発セットから変更なし
23
P3_3 TRCCLK 開発セットから変更あり
24
P3_4 LCD Eを駆動 開発セットから変更なし

あと、P1_3がA/Dコンバータの実験用に接続されていましたが、LCD DB7以外に最悪330Ωをプルアップ/プルダウンするのも好ましくないので、R3(330Ω)の接続先をP0_7/AN0に移動しておきます。

−開発セットを用いた周波数カウンタのハードウェア−
このように改造した基板が以下の写真になります。

開発セットベース基板表面写真(子基板であるCPUボードは取り外してあります)


開発セットベース基板裏面写真


開発セットベース基板表面改造部拡大写真


パターンカットは上の開発セットベース基板表面改造部拡大写真で分かる通り、パターンのカットが"I"や"X"で示すように4ヶ所あります。配線材の半田箇所を小さめの赤丸で示しています。また基板に小さな穴を2ヶ所あけて線を通しています。茶色の破線は基板裏面の接続先を示します。(なお、CN1A-15pin、CN3−13pinの○印はパターンカット前の行き先です。CN1-6pinもパターンカットされて、現在は元と異なる信号であるLCDのDB7とLEDのL4が接続されています。) さらに、CN3Aコネクタの6pinは12pinと接続されています。また、同コネクタの13pinは振幅制限用の抵抗を通じてカウントソースに、16pinはカウントソースのグランドに接続されます。開発セットのプリント基板のパターンは変更される/変更された可能性があります。もし追試される場合は、ご自分が今どのような結線変更をしようとしているか確認しながら作業するようにしてください。
ベース基板の変更した回路図を示します。

開発セットベース基板変更部分回路図


この回路変更に伴い、LCD制御用の関数はRS信号の制御がP3_3からP3_6に移りますので、方向レジスタも対応して変更します。また、DB7〜DB4への書き込みがP1_3〜P1_0への連続する4bitになったので、これも変更になります。FINにつながっている抵抗Rは本基板ではいい加減な値ですが、3.3kΩにしています。大きな振幅の信号が入ってきたとき、これがあるとマイコンチップが壊れる確率が低くなります。(実はプログラムデバッグ中、FIN入力にうっかり12Vを直接印加してマイコンチップを壊してしまい、基板からマイコンチップをはがして良品と載せ換えることになったので追加しました。)

−周波数カウンタのソフトウェア−
周波数カウンタのソフトウェアとして今回作成したソースファイルは次の2つです。他のソースファイルはAE_R8C27_LCDのコピーです。
このLCD16x2_27.c回路変更に合わせて変更したLCDのハンドリングプログラムです。変更点は簡単なので、説明は省略します。
このFcount1.cメインプログラムを含むカウンタ全体のプログラムです。

HEWで新しいプロジェクト"Fcount1"を作成したとき、Fcount1.cの骨組みプログラムはプロジェクトの1要素として自動的に生成されますが、LCD16x2_27.cはプロジェクトに追加する必要があります。これは、LCD16x2_27.cをプロジェクトのソースファイルのディレクトリにコピーしたのち、HEWのプロジェクト(P)→ファイルの追加(A)で、そのファイルを選択すると、プロジェクトの要素に登録されるようです。
なお、新しいバージョンの開発環境の場合は秋月のCD-Rの場合と異なって、sfr_r827.h はコピーしなくても、プロジェクト作成時に自動的に作成され、日付を削除するような編集も不要です。

Fcount1.cについて簡単に説明を加えます。
Fcount1.cプログラムは割り込み処理プログラム trcint と main、 timer_ra_init、 timer_rb_init、 timer_rc_init からなります。timer_ra_init 以降はタイマの初期化プログラムです。
 タイマ初期化プログラムについて
タイマRAとタイマRBを使用して1sパルスをP3_1/TRBO端子から出力します。タイマRCはインプットキャプチャモードに設定し、P5_3/TRCIOC端子入力の立ち上がりエッジごと(TRBO端子出力が接続されているので1sごと)にP3_3/TRCCLK端子入力の立ち上がり入力をカウントしていたTRCレジスタの値をTRCGRCレジスタに転送する(キャプチャする)ように設定しておきます。さらにタイマRCの割り込みをイネーブルに設定します。(実際にCPUで割り込みを受け付けるようになるのは、メインプログラム中で割り込み許可に設定した後になります。)
 trcint 関数について
これは割り込み処理プログラムになります。割り込み処理の取り扱いは、とりわけCのようなコンパイラを使用する高級言語ではコンパイラ、あるいはサポートライブラリのバージョンに依存して大きく変わる部分が出てくることがあるようです。(当方はソフトの事情に疎く、メーカWebを漁って古いバージョンの情報に振り回されてしまいました。メーカWebで見つけた rjj05b0951_r8cap.pdf の割り込み処理の説明では、sect30.incを編集することになっているのに対し、sect30.incのベクターアドレスはif 0 で事実上のコメントアウトになっているし、と戸惑ったりしましたが古いバージョンの処理系に関する情報のようでした。秋月開発セット付属のCD-Rやそれ以後のバージョンなどではベクターアドレス部分を編集する必要がありません。) 今回、適切な情報は開発環境をインストールしたときのCコンパイラユーザーズマニュアルにありました。幸せの青い鳥は一番身近なところにいたのです。本プログラムはCコンパイラパッケージV.5.44に対応したものです。(V.5.45でもOKでした。)
trcint 関数より手前で #pragma INTERRUPT/B 7 trcint を記述します。これによって割り込みベクタ 7 を trcint 関数で処理すること、関数呼び出し時にレジスタをスタックに退避する代わりに裏レジスタへ切り替えることを宣言しています。割り込みはTRCレジスタのオーバーフローによる要因とキャプチャによる要因が同一割り込みベクタですので思案のしどころです。オーバーフローならばTRCSRレジスタのbit 7、キャプチャならばbit 2が"1"になります。まずTRCSRレジスタの必要bitとキャプチャレジスタTRCGRCの値をそれぞれ変数stateとtrcbufに保存し、TRCSRレジスタをクリアしておきます。その後stateの値によって次の処理を決めます。
bit 2だけが"1"になっていたのであれば1秒経過した処理として、キャプチャレジスタのコピーであるtrcbufの値を変数lowerに保存し、1秒経過したしるしとして、flag=1という合図をセットして割り込み処理から抜けます。
もしbit 7だけが"1"になっていたのであればカウンタのオーバーフローが生じたということなので変数upperの値を65536だけ増やしlowerを0にします。1秒経過したわけではないのでflagの値は変更せずに割り込み処理から抜けます。
bit 2だけ"1"になっていたのでもbit 7だけ"1"になっていたのでもなければ、両方のbitが"1"になったことになります。この時、オーバーフローが先に発生したのか、1秒経過が先に発生したのかでカウント値が大きく異なりますから判断する必要があります。いずれにしても発生したタイミングは僅差のはずです。オーバーフロー後に1秒経過のキャプチャが発生したのならばtrcbufの値は小さいはずですし、1秒経過のキャプチャ後にオーバーフローが発生したのならばtrcbufの値はオーバーフローしそうな大きい値のはずです。この違いから、いずれであったかを判定します。前者の場合は変数upperの値を65536だけ増やし、trcbufの値も変数lowerに保存し、1秒経過したしるしとしてflag=1という合図をセットして割り込み処理から抜けます。後者の場合はtrcbufの値を変数lowerに保存し、1秒経過した直後にオーバーフローが生じたしるしとしてflag=3という合図をセットして割り込み処理から抜けます。
 メインプログラムについて
サンプルプログラムであるAE_R8C27_LCD.cを元に変更しました。クロック源の設定、LCDの初期化後、タイマや各変数の初期設定を行い、割り込みを許可します。その後、1秒ごとに周波数カウンタの表示を更新し、999秒経過するかカウント値の累計が32bit無符号整数に入りきれなくなるとメインプログラムを終了します。メインプルグラムを終了すると作りつけのコードによって自動的に無限ループに入ります。
クロック源の設定ではシステムクロックをリセット中から外付け回路を使用しないオンチップオシレータだったのを、外付けの水晶振動子の分周なしクロックに切り替えます。元のプログラムのままでは前述したように水晶振動子の発振安定待ち時間が不足だったので for(i=255;i>0;i--); の1行を加えています。
P4_5はオシロを使用したデバッグ時に出力ポートとして使用したものですが、フラッシュ書き換え時のシリアルポートでありRS232CのI/F ICと干渉するので開発セットの基板では好ましくない選択だったと反省しています。
おもな変数としてはlastcountが前回のキャプチャ値の保存用で、新しい値が来た時に前回の値より新しい値が小さければ32bit符号なし整数がオーバーフローしたと判定します。countnewは今回のキャプチャ値の保存用32bit符号なし整数、countsubは最初のキャプチャ値の保存用です。secは実質的に周波数を計測し始めてからの秒数です。
while(1){ 以下が測定終了まで回り続けるループになっています。このループの中では割り込み処理プログラムによる変数flagの状態をチェックしており、結果として1秒ごとに表示の更新を行います。最初の1秒は初期化後真の1秒かどうか信用できないような気がしているのでこの時のカウント値をcountsubとして保存しておきます。32bit数がオーバーフローしていないことが確認できたら最新のキャプチャ値であるcountnewの値をlastcountにコピーしてしまいます。こうして得られた最新のキャプチャ値であるlastcountの値からcountsubの値を差し引いたものを最初の1秒を除いた経過秒数で割ったものを周波数とし、変数count1に代入します。メインプログラムの残りは周波数と秒数を10進数として、はじめの余分な"0"を消して表示させるものです。

−周波数カウンタ基板の作成−
開発セットの回路から周波数カウンタに必要な回路部分のみを取り出したような周波数カウンタの基板を作成しました。
マイコンの周辺回路の割り当てなどを変更すると、プログラムをそれに合わせて修正しなくてはなりませんからここで改良しようなどとは考えないことにします。(その気になれば周波数カウンタの基板でもプログラムの書き換えは可能なのですが、不要な手間が増えるので普通は割に合わないと思います。)
キーパーツはR8C/27 (R5F21276SNFP)、20MHz水晶振動子、液晶モジュール SC1602BS*BまたはSC1602BSLB、RS232CのI/F IC、9ピンコネクタ、といったところでしょう。5V電源やリセットボタンなどは言わずもがなです。なお、マイコンはR8C/26でも問題ないと思います。また小さいプログラムですので、ROM/RAMともそれほど必要ありません。プログラムの項で記すべきでしたが、プロジェクトを作成する際、ROMサイズは8Kでも全く問題ありません。ROMサイズの指定は小さい方が、フラッシュへの書き込み時間が短くて快適です。
抵抗、コンデンサにチップ部品を多く用いたのは、基板の穴あけを減らすためです。ただ、手で半田付けを行っていますが、多分チップ部品でない方が楽です。RS232CのI/Fは周波数カウンタ基板に作りつけとしましたが、別に作っておいた方が、いくつもRS232C I/F回路を作成せずに済んで経済的なように思います。(手持ちストックのRS232CのI/F ICが底をついてしまいました。次に何か作るときは、古い基板から外すか新しく購入する羽目になります。あるいはディスクリートで0-5Vスイングの怪しい回路で誤魔化すか‥)

周波数カウンタ基板回路図


開発セットのうち必要部分を抜き出して作成したのでシンプルな回路です。入力もCMOS5Vの方形波を想定したものになったままです。サージ保護を考慮して、周波数入力端子FINとGND間に100kΩを入れました。また、多少大きめの振幅の信号でも3.9kΩのおかげで(本当は感心しませんが)入力することが可能です。
マイコンとRS232CのI/F ICとの接続部はジャンパピンにしてみました。普通は接続したままで全く問題ありません。
なお、リセットICは多少古いものですが、たまたま手持ちが何個もあったので使ってみました。確かめていませんが、代案のような回路で問題なく動作すると思います。もし問題があれば10uFの値を33uF等に変更してみるなどすれば良いかと思います。
Flash書き換え時はMODE端子とGND端子間をみの虫クリップ等で短絡し、通常使用時は無接続とします。VCC端子は何か、簡易的な実験/確認時にあれば便利と思ってつけています。
水晶発振回路の18pFは開発セットの値をそのまま採用したものですが、思ったより20MHzからずれています。開発セットと水晶型番が異なっていることが要因として大きいのではないかと思います。P3_1の周期を測定したところ、手元の測定器では999.949msでした。理想の1sより短いので、XOUT−VSS間の18pFと並列に8pFを追加したところ999.976msとなりました。あと一息なので、XIN-VSS間の18pFにも並列に5pFを追加したところ、1.000,00sとなったのでこれで良いことにしました。

周期測定/調整時の周波数カウンタ基板


次に、作成したプリント基板の説明をするべきなのですが、基板の設計をやっつけ仕事で行ったため、ポカミスあり、好ましくない引き回しが目立ち、と反面教師のような基板になっています。それでも次の改善項目の覚書として載せておくことにします。

今回の周波数カウンタ基板プリントパターンの問題点


まずい点 (図中、オレンジの線を参照)
× 電源ジャックのレイアウトパターンを勘違いして上下裏返しにしてしまった。
(1) LCDバックライト用抵抗忘れ(バックライトなしなので問題なかったが、バックライトありの場合は壊れていたかも。現在は×の部分でパターンカットし、47Ωも付けた。バックライト付きLCDパネルと差し替えて問題なく点灯することを確認済み。
(2) シリアルコネクタの配線入れ違い。×の部分でパターンカットし(2ヶ所)、信号を入れ替えて接続。
(3) シリアルコネクタ5pinのGND接続漏れ。
(4) GNDパターン設計ミス。実害はないが、GNDの配線距離が不要に長くなっている。(半田付け付近は小さなスリットがあった方が半田付けしやすい)
(5) GNDパターン設計ミス。実害はないが、GNDの配線距離が不要に長くなっている。(半田付け付近は小さなスリットがあった方が半田付けしやすい)
(6) 周波数カウント入力信号のGND側引き回し長さが信号側引き回し長さと違い過ぎ。今回はFmaxが低いため問題は少ないと思われるが、ノイズトラブルの原因になりやすい。シリアル信号をジャンパでマイコンと接続すれば、周波数カウント信号のGND側引き回しが改善できる。
(7) 周波数カウント入力信号のGND側がLCDパネル裏のベゼル取り付け部とニアミス状態。右に1マス分(2.54mm)でも避けるべきだった。
(8) コネクタ位置が基板端から引っ込み過ぎ。プラグの縁が基板と干渉して刺さらないため、基板端をL字型に切り落とす必要が生じた。

良かった点
・ エッチング面積が少なくなるよう、配線不使用部分も銅箔パターンを設けたこと。
・ 同じ目的でユニバーサル式のパターンに四角のランドを使用したこと。これによりランドが丸の場合よりエッチング面積が少なくなった。
・ プリント板の最外周をGNDのパターンとしたこと。ケースに入れた場合も裸でも静電サージに対して防護する効果ある。

ポジ感光基板のパターン描きにはいつもフリーソフトのPCBEを利用しています。事前の仕込みが要らないのでとっつきやすかったです。余談ですが、今回の基板は室内で保管していた、使用期限から4年余り過ぎたものを使用しましたが何とか使えるものですね。片面ガラスエポキシ基板を用いましたが、コンポジット基板の方が穴あけ等の加工が容易だと思います。
100mm×150mmの基板に2個取れる周波数カウンタのパターンを圧縮したPCBE設計データがFcountPCB.zipです。
「AS IS」状態で上記のまずい点も修正していませんが、もし万一ほしい方はどうぞご自由に。ご使用は自己責任で。
自分で基板をエッチングするときシルク印刷などは行わないので、シルクのレイヤーは裏表など考えずにパーツの位置や値などが分かるように適当に描きました。 なおパターンは×1倍で透明フィルムにプリントし、印刷面がポジ感光基板の銅箔側の面と接触するようにして感光させます。(裏表注意ということです。)

−普通の周波数カウンタプログラム−
普通の周波数カウンタのプログラムFcountN.cを作成してみました。LCD表示の関数は先のプログラムと同一の LCD16x2_27.c を使用します。

ジッタ対応型にしても普通のタイプにしても、作成した周波数カウンタのソフト、タイマのオーバーフロー周りのプログラムがOKかどうかどうも良く分かりません。きわどい周波数の入力で確認したいと思います。そういえば、当方アマ無線の免許もリグもあります。忘れかけていましたが、リグの出力周波数範囲を調べてみると、3MHz−3.5MHz、6.5MHz−7MHzは出力可能でした。これなら最低でも10Hz刻みで出力周波数を設定できますから、アンテナにつないではいけませんが、低出力でダミーロードと接続して周波数カウンタにも信号を供給できます。これで確認していきたいと思います。
 周波数カウンタの読み取り値が6.5536MHz台の最低となる周波数をCWで出力し、そこから10Hz下げた周波数に出力を変更してしばらく周波数カウンタの読み取り値を観測しましたが、途中でオーバーフロー処理ミスで生じそうな65536Hzの整数倍程度ずれた値になることは観測できませんでした。
それでも割り込みの tricint 関数の
} else if ( trcbuf < 128 ) {/* overflow + 1_second procedure */
の部分は128でなく、もっと大きい数の方が安全かもしれません。

液晶画面では、記録が残らないため、「おやっ?」と思っても良く分かりません。シリアルポートからも出力させるプログラムを作成して観測したところ、時おり65536Hzほどずれた結果を出していることがわかりました。実際のところ、無線機は1Hz刻みで出力が変更できたので、その機能を使用しました。無線機は周波数変更ごとにPLLの設定を切り替えるのではなくDDSを使用した構成になっているため、周波数変更時にも周波数は暴れることなくきれいに変化しますので、このような評価には好都合です。結果はココ
先のtrcbuf < 128 の数字を増やしても効果はないようでした。まじめに解析してデバッグするか、このまま放置するか、65536Hz程度ずれていた場合は一度やり過ごすという姑息な方法で乗り切るかですが、とりあえず放置しています。
(周波数カウンタの項、とりあえずここまでで投げ出す)

戻る
戻る