CPLDとPICによるシグナルジェネレータ
CPLDのパルス発振ブロックとPICを組み合わせた
パルスジェネレータです。USBでパソコンとも接続し
リモコンが出来ます。
【概要】
CPLDのパルス発振ブロックとPICを組み合わせたパルスジェネレータで、
USBでパソコンとも接続しリモートコントロールが出来ます。
CPLDのパルス発振ブロックは、VHDLのページでで説明したものを
そのまま使っています。下記写真は本信号発生装置の完成した外観と前面パネルの詳細です。
前面パネルに手動設定用のディジスイッチが並んでいます。
【機能仕様】
(1) パルス出力仕様
パルス信号の出力は下表のような2段階の範囲で出力出来ます。
この段階は、外部クロックを1倍と1/10倍に切り替えて広いパルス幅の
出力範囲をカバーするようにしています。
モード 出力パルス幅 パルス幅刻み デューティ範囲 デューティ刻み リモート
モード
100nsec〜100msec
(10MHz〜20Hz)
100nsec 0〜100% 100nsec 100msec〜1sec
(20Hz〜1Hz)1μsec 0〜100% 1μsec 手動モード 100nsec〜100msec
(10MHz〜10Hz)100nsec 50%固定 なし 出力信号種類とインターフェース
信号出力: TTLレベル
監視用用出力: TTLレベル(2) 手動操作仕様
パルス幅設定はディジスイッチによる10進数6桁のマニュアル設定で、
設定を変更すると即出力に反映されます。
100nsecから99,999,900nsecつまり100msecまで設定が可能です。
リモートと手動との切替えは自動的に行うものとし後発優先とします。
(3)リモート操作仕様
パルス幅、デューティとも手動設定と同じようなディジスイッチによる
設定とし、パルス幅は10進数7桁、デューティは10進数3桁で%設定
とします。
リモート設定では100nsecから999,999,900nsecつまり1secまで設定が可能と
します。(4) スイープ機能
リモートでは自動スイープ機能を持ち、設定した開始パルス幅と終了パルス幅、
さらに刻みステップと時間間隔を指定すれば、一定時間間隔で順次パルス幅を
増加させながら出力します。
【ユニットの構成】
信号発生装置の全体構成は下図のようになっています。信号発生そのものは
CPLDで行い、それをPIC16F876で制御します。またパソコンとのUSBインター
フェースには、USBコントローラのUSBN9603を使いこれもやはりPIC16F876で
コントロールしています。
さらに手動設定用のディジスイッチが合計6桁分ありますが、これのダイナ
ミックスキャン制御もPIC16F876で実行しています。
【回路構成】
信号出力ユニットは基板となっていてその回路は下図のようになっています。
USBN9603とPICの間は定石通りSPI通信で接続しています。
またCPLDとPICの間はシリアル通信で接続していますが専用のインターフェース
となっています。CPLDのクロックには20MHzの水晶発信器を使っています。
電源は3端子レギュレータを使いますが、CPLDの消費電流が100mA近くと
やや多いので大きめの1Aクラスの7805を使い放熱器をつけています。
下記ファイルはWinDraft、WinBoard用の回路図とパターン図です。
ダウンロードし解凍してお使い下さい。
★ 回路図ファイル(WinDraft用)
★ パターン図ファイル(WinBoard用)
組みあがったユニット基板の外観は下記写真のようになります。USBコントローラ
はフラットパッケージタイプなので、基板のパターン面に直接はんだ付けして
います。
【デバイス側プログラム】
C言語版のUSB基本プログラムに、各エンドポイントのユーザー処理部を
追加して作成します。
エンドポイントの構成は下表のようにしています。IN/OUTの見方はホスト側から
見た入出力となっています。
USBN9603は最大でエンドポイントがコントロール+6個まで使えます。基本デバ
イスプログラムでは、全部が使えるようになっていますが、汎用I/Oとして使って
いるのは、下表のようにコントロール+4個です。
パイプNo エンドポイント IN/OUT 処理関数 用途 無し 0 IN/OUT コントロール転送
コンフィギュレーション用0 1 バルクIN do_tx1( ) 未使用 1 2 バルクOUT do_rx1( ) コマンド出力
2 3 バルクIN do_tx2( ) 未使用 3 4 バルクOUT do_rx2( ) 4 5 バルクIN do_tx3( ) 5 6 バルクOUT do_rx3( )
デバイスのプログラムはC言語ベースとなっています。C言語で作成したUSBの
基本プログラムにユーザー処理部分を追加しています。
プログラムの構成としては下記の4つとなっています。
sysgen2.c :本体プログラム
usbmain.h :USB処理基本デバイスプログラムモジュール
usbn960x.h :USBN9603のレジスタ類の定義ファイル
usbdef.h :USB関連の定数とデバイスディスクリプタを定義したファイル
以下からデバイス側の上記プログラムがダウンロード出来ますので
解凍して、CCSのCコンパイラでお使い下さい。 MPLABに統合してコンパイル
するのが便利です。
★ USB接続汎用I/Oデバイスプログラム (3/3 Verup)
メインプログラムでUSB処理メインリンクモジュールをインクルードすれば、
あとは、ユーザー処理部分だけをメインプログラムで作成すれば良いように
なっています。
メインプログラムでユーザー処理部として追加した部分は下記となっています。
(1) メイン処理の基本部分
メイン処理として基本となる部分で、ここでUSBのバッファのサイズ指定と
usbmain.hというUSB処理のメイン関数をリンクしています。
あとは自分のハードウェア関連の設定を追加し、最後にUSB初期化関数
のinit_usb( )をコールしたあと、メインループになります。
メインのアイドルループでは実行すべきことがあります。まずパルス幅
設定のディジスイッチの設定値をダイナミックスキャンで読みこみ
DIGIT[i]の配列変数に桁毎に格納します。
読み込みが完了したらそれをバイナリ数値に変換します。このとき最大値
が999,999になりlong型で間に合わなくなりますので、CCSコンパイラの
最新版(Version3)で追加された”int32”という32ビットの整数型を使い
ました。
そしてこの値が前回と同じかどうかをチェックし、同じであれば何も操作
されていないものとして何もせず、最初のディジスイッチ入力処理に
戻って繰り返します。
数値が前回と異なっていれば操作をされたということですので、その値を
CPLDに出力します。その出力する関数は受信処理の関数と同じ処理です
ので流用しています。出力が完了したら今回値を新たに前回値として置き
なおして次回に備えてから最初に戻って繰り返します。
出力するときデューティ値は固定で50%としています。
(2) パルス幅設定制御(パイプ1)
パイプ1の受信処理では受信したデータR1_DAT[n]にはパルス幅設定の
データが入っています。この1バイト目のデータR1_DAT[0]はクロックの
切替用のデータなので、この内容の0か0でないかによってHILO信号を
制御しています。その後のR1_DAT[1]からR1_DAT[2]までの3バイトは
パルス幅設定値なので、そのデータをそのままCPLDに出力します。
(3) デューティ制御(パイプ3)
パイプ3の受信処理では受信データR2_DAT[0]からR2_DAT[2]までに
デューティの設定値が入っていますのでこれもそのままCPLDに出力
します。
(4) 設定値折り返し送信(パイプ5)
パイプ5の受信処理は、ディジスイッチの設定値読み込みのコマンドです
から、現在読みこんだ数値を3バイトのデータに直してパイプ2で送信出力
して返送します。この送信は単にusb_send2()という関数を呼ぶだけです。
【シグナルジェネレータ制御プログラム】
このパルス信号発生装置をUSBでリモートコントロールするためのパソコン
側のプログラムを作りましょう。
USBのドライバは、柏野さん作の汎用USBドライバにベンダーIDを追加して
使いますので、USB周りで特に作らなければならないものはありません。
これもすべてVisual Basicで作成します。
まず機能ですが、下図のフォームをベースにして下記のような機能を実現します。
(1)パルス幅とデューティの制御
画面上のディジスイッチの各桁の上(▲)、下(▼)スイッチを押すことで
パルス幅とデューティ値を設定します。設定を変更すればその値がすぐ
装置に出力され反映されます。
(2)スイープ制御
開始パルス幅(From)、終了パルス幅(To)、パルス幅増分(Step)、インターバル
時間(Interval)を設定して「開始」ボタンを押せば、指定時間間隔で増分毎に
パルス幅が増えて出力され、順次パルス幅が広がります。
そして終了パルス幅になったら終了します。
途中で「停止」ボタンを押せばいつでも終了します。
(3)装置側ディジスイッチの読み出し
読み出しボタンを押すと、その時のディジスイッチの内容をUSB経由で入力
して10進数で表示します。
このフォームの各コンポーネントは図のようなオブジェクトで構成されて
います。ディジスイッチを構成するオブジェクトは桁ごとにインデックスが
付いていて配列の扱いになっています。
そしてディジスイッチの上向き矢印を押す度に表示数字が増え、下向き矢印
押す度に表示数字が小さくなります。さらにこの矢印を押したイベントで、
設定されているパルス幅とデューティ値が信号発生装置に設定出力されます。
本プロジェクトには2つのコードモジュールがあります。標準モジュールと
フォームモジュールです。下記からダウンロードできます。
★シグナルジェネレータプロジェクトファイル一式
標準モジュールの方は、お決まりのUSB関連の宣言だけですので他から
コピーして使うことが可能です。但し、USBのハンドル名は変更した方が
わかりやすくなるので、機能に合わせて変更します。
次はフォームモジュールの方のコードですが、それぞれのコンポーネントの
イベントに対して作成して行きます。
まずは、フォームのオープン、クローズ時の処理です。まずフォームをオープン
したときにはUSBの接続をオープンしてパイプを確保しハンドル値を得ます。
これが確保できないときはエラーとしてメッセージを表示してプログラムは
強制終了になります。
フォームをクローズするときには、オープンしたUSBをパイプも含めて
忘れないようにクローズして切離してからプログラムを終了します。
同じように「終了」ボタンを押したときにも全てをクローズしてから終了させ
ます。
次は、ディジスイッチの処理で上向き矢印ボタンを押したイベントの時の
処理です。まずどの桁の数値アップ(上向き矢印ボタン)を押しても配列定義に
なっているので同じイベントが発生します。区別はインデックス値でつけます。
従ってどの桁であっても全て共通の処理とすることができ、index値で区別されて
処理されます。
実際の処理は、まず対応する桁の数値を+1します。このとき既に9の時には
0に戻します。この後、全桁から設定値を10進数として求めますが、最上位桁が
0より大きいときには最下位桁を無視して上位6桁だけの扱いにしてクロック
設定を1/10にします。
これが求まったら、3バイトのバイナリ値に変換してからパイプ1で送信します。
続いてデューティ値の方も設定%値とパルス幅値から設定値を求め、やはり
3バイトのバイナリ値に変換してからパイプ3で出力しています。
ディジスイッチのダウンボタンを押したときの処理も数値を−1するだけで
後の送信処理は全く同一です。
次はスイープ機能のコード部で、「開始」と「停止」ボタンのイベント処理と
なります。まず「開始」ボタンが押された時には開始パルス幅(From)に入力され
ているデータをチェックしてOKならそれを最初のパルス幅としてパイプ1で出力
します。
続いてデューティは常に50%としますのでパルス幅の1/2の値をパイプ3
で出力します。その後でタイマーを入力されたインターバルの値でスタートします。
これ以降はタイマーのイベントで処理されることになります。
「停止」ボタンが押された時には、単純にタイマを停止させているだけです。
次はタイマのイベント処理部分です。ここでは現在のパルス幅増分(Step)に
入力されている値を加算し、終了パルス幅を超えていないか、1秒を超えて
いなければ、次のパルス幅として出力します。
デューティも同じ50%として出力します。超えた時にはスイープ機能の終了
としてメッセージを表示してタイマーを停止させます。
【外観】
基板をケースに実装しますがその実装方法を説明します。
ディジスイッチのBCD出力部は全桁をリード線でまとめて配線してしまいます。
そしてそのBCD4ビット分と各桁の6本をまとめてコネクタ接続で基板と
接続します。デューティ設定用にロータリーエンコーダが接続できるコネクタ
が用意されていて、ロータリエンコーダ本体もパネルに取り付けていますが
今回は使っていません。
電源はACアダプタ等から供給するものとして直接基板に入力しています。
このときダイオードを1個直列に挿入していますが、これはACアダプタなどの
極性間違いから保護する目的のためです。
USBの接続はコネクタになるのですが、基板に直接コネクタを実装しています
ので、背面からUSBケーブルが挿入できるように配置し、背面パネルに少し
大きめの四角い穴をあけています。これで背面から直接ケーブルを挿入できます。
下記が組み立て後の外観です。
電源を簡略化したのですっきりしている。
USBコネクタの先のパネルには大きめの四角い
穴をあけている。
ディジスイッチ周りの配線、桁のBCD出力はパラ接続
ロータリエンコーダは未使用