$programmer = 22 'ARDUINO (using stk500v1 protocol) ' ' ********************************************** ' * AD9850 DDSモジュール コントローラ * ' * [REFCLOCK:125MHz , OUT:0-62,499,000Hz] * ' * * ' * Copyright O-Family 2020. 3.11 * ' ********************************************** ' ' Ver 0.01 初回公開バージョン。 2020. 3.11 ' Const Reference_clock = 125000000 '基準クロック(REFCLOCK)の値。 Const Board_version = 10 'DFROBOT社のボード・バージョン。[1.0] = 10 or [1.1] = 11 $regfile = "m328pdef.dat" '使用するAVRを設定。 $crystal = 16000000 'AVRクロックを設定。 ' $hwstack = 64 'ハードウェア・スタックの容量を設定。 $swstack = 10 'ソフトウェア・スタックの容量を設定。 $framesize = 24 'フレーム領域の容量を設定。 ' ' * ポート名の定義 * ' Lcd_bkl Alias Portb.2 'LCDのバックライト制御の接続ポート。 ' Dds_wclk Alias Portd.2 'DDSモジュールの[W_CLK]接続ポート。 Dds_fqud Alias Portd.3 'DDSモジュールの[FQ_UD]接続ポート。 Dds_d7 Alias Portb.3 'DDSモジュールの[DATA(D7)]接続ポート。 Dds_reset Alias Portb.4 'DDSモジュールの[RESET]接続ポート。 ' ' * 変数の宣言 * ' Dim Keydata As Byte 'キー(スイッチ)の入力データ。(押された場合にコードが入る) Dim Keyadcode As Byte 'キー(スイッチ)をA/D変換したコード。(押されている状態のコードが入る) Dim Keystat As Byte , Keyw1 As Word 'キー(スイッチ)の検出状態フラグ。内部で使用する変数。 ' Dim Frequency As Long 'DDSに設定する周波数データ値。 Dim Ddscontrol As Byte 'DDSのコントロール・データ値。 Dim Channel As Byte '出力チャンネルの選択。 Dim Channeltemp As Byte '出力チャンネル選択の一時保管。 Dim Curx As Byte '設定カーソルの[X]位置。 Dim Resolution As Single '分解能の値。 ' Dim Temp1 As Byte '汎用テンポラリ変数 Byte型 No.1 Dim Temp2 As Byte '汎用テンポラリ変数 Byte型 No.2 Dim Temp3 As Byte '汎用テンポラリ変数 Byte型 No.3 ' Dim Tempw1 As Word '汎用テンポラリ変数 Word型 No.1 ' Dim Templ1 As Long '汎用テンポラリ変数 Long型 No.1 Dim Tempdw1 As Dword '汎用テンポラリ変数 Dword型 No.1 Dim Temps1 As Single '汎用テンポラリ変数 Single型 No.1 Dim Tempstr As String * 20 '汎用テンポラリ変数 String型 No.1 Dim Tempstr2 As String * 20 '汎用テンポラリ変数 String型 No.2 ' Dim Eepdummy As Eram Long 'EEPROM 4バイトのダミーエリア。 Dim Eepprgid As Eram Long 'EEPROM プログラムのID。 Dim Eepfrequency(100) As Eram Long 'EEPROM 周波数データ。 Dim Eepchannel As Eram Byte 'EEPROM 出力チャンネルの選択。 '-------------------------------------------------------------------------------------------------- ' ' * ポートの初期設定 * ' Config Lcd_bkl = Output 'LCDのバックライト制御の接続ポートを出力に設定する。 Set Lcd_bkl 'LCDのバックライトを点灯する。 ' Config Dds_reset = Output 'DDSの[RESET]接続ポートを出力に設定する。 Reset Dds_reset 'DDSの[RESET]を[L]にする。 Config Dds_fqud = Output 'DDSの[FQ_UD]接続ポートを出力に設定する。 Reset Dds_fqud 'DDSの[FQ_UD]を[L]にする。 Config Dds_wclk = Output 'DDSの[W_CLK]接続ポートを出力に設定する。 Reset Dds_wclk 'DDSの[W_CLK]を[L]にする。 Config Dds_d7 = Output 'DDSの[DATA(D7)]接続ポートを出力に設定する。 ' Set Portb.5 '未使用ポートをプルアップする。 ' Set Portd.0 '未使用ポートをプルアップする。 Set Portd.1 '未使用ポートをプルアップする。 ' ' * A/Dコンバータの初期設定 * ' Config Adc = Single , Prescaler = Auto , Reference = Avcc 'A/Dコンバータの設定。 Start Adc 'A/Dコンバータに電源を供給する。 Didr0 = &B0011_1111 'デジタル入力禁止レジスタの設定。(アナログ入力ピンをデジタル入力禁止にする) ' ' * LCDの初期設定 * ' Config Lcdmode = Port 'LCDを4ビットのポートモードに設定。 Config Lcdbus = 4 'LCDデータバスを4bitに設定。 Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 'LCDのポート割り当て。 Config Lcdpin = Pin , Db6 = Portd.6 , Db7 = Portd.7 Config Lcdpin = Pin , E = Portb.1 , Rs = Portb.0 Config Lcd = 16 * 2 'LCD表示を16文字2行に設定。 Cls 'LCD表示をすべて消去。 ' ' * カスタム文字をLCDに設定する * ' Deflcdchar 0 , &H04 , &H0A , &H11 , &H00 , &H00 , &H11 , &H0A , &H04 'カスタム文字[上下矢印]をLCDへ書き込む。 ' ' * 周波数データの初期化を確認する * ' Gosub Getkey 'キー(スイッチ)を検出する。 If Keydata = 1 Then 'If [SELECT]キーが押されているか? Then Locate 1 , 1 Lcd "*Initialize Freq" '初期化のメッセージを表示する。 Locate 2 , 2 Lcd "Memory? [UP]key" Keydata = 0 'キー(スイッチ)の入力をクリアする。 ' Do Gosub Getkey 'キー(スイッチ)を検出する。 Loop Until Keydata <> 0 'If キー入力がないか? Then If Keydata = 4 Then 'If [UP]キーが押されたか? Then Eepprgid = &HFFFFFFFF 'EEPROM プログラムのIDを消去する。 Locate 2 , 10 Lcd "-Done!-" End If Keydata = 0 'キー(スイッチ)の入力をクリアする。 End If ' Do Gosub Getkey 'キー(スイッチ)を検出する。 Loop Until Keyadcode = 0 'If キーが離されていないか? Then ' ' * EEPROMのデータを確認する * ' If Eepprgid <> &H30353839 Then 'If EEPROMが初期値か? Then Eepchannel = 1 'EEPROM 出力チャンネルの選択。 For Temp1 = 1 To 99 'EEPROMの周波数データをすべて初期化(0Hz)する。 Eepfrequency(temp1) = 0 'EEPROM 周波数データ。 Next Temp1 Eepprgid = &H30353839 'EEPROM プログラムのID。[9850] End If Channel = Eepchannel '出力チャンネルの選択。 Channeltemp = Channel '出力チャンネル選択の一時保管。 ' ' * [AD9850]の初期設定 * ' Ddscontrol = &B0000_0000 'DDSのコントロール・データ。(位相=0, パワー・アップ) Tempdw1 = &H00000000 'DDSの周波数データの初期値。(DDSのレジスターをクリアする) Gosub Ddsset40b0 'DDSをリセットしてから40bitのデータを送信する。 ' Tempdw1 = Reference_clock * 10 '分解能の計算。 Resolution = Tempdw1 / 4294967296 '[REFCLOCK * 10] / 2^32 ' ' * LCDの初期表示 * ' Cls 'LCD表示をすべて消去。 Locate 1 , 15 Lcd "Hz" Locate 2 , 4 Lcd Chr(0) ; ", , . cM" ' Gosub Chandisp 'LCDにチャンネル番号を表示する。 Frequency = Eepfrequency(channel) '出力周波数を読み出す。 Gosub Freqdisp 'LCDに設定周波数を表示する。 Gosub Freqset 'DDSに周波数データを送信する。 ' Curx = 4 '設定カーソルの初期位置。 Gosub Curdisp 'LCDに設定カーソルを表示する。 Cursor Off , Blink 'LCDのカーソルをオフ・点滅にする。 '================================================================================================== ' ' ******************* ' * メイン ルーチン * ' ******************* ' Main: Gosub Getkey 'キー(スイッチ)を検出する。 If Keydata = 0 Then Goto Main 'If キー入力がないか? Then ' ' * スイッチが押された処理 * ' Select Case Keydata Case 1 : '[SELECT]キーが押された場合。 If Channel = 1 Then 'If 現在の出力チャンネルが[Ch.1]か? Then Channel = Channeltemp '出力を[Ch.1]以外にする。 Else '[Ch.1]以外の場合。 Channel = 1 '出力を[Ch.1]にする。 End If Eepchannel = Channel 'EEPROMに出力チャンネル選択を記憶する。 Gosub Chandisp 'LCDにチャンネル番号を表示する。 Frequency = Eepfrequency(channel) '出力周波数を読み出す。 Gosub Freqdisp 'LCDに設定周波数を表示する。 Gosub Freqset 'DDSに周波数データを送信する。 ' Case 2 : '[LEFT]キーが押された場合。 If Curx < 15 Then 'If 設定カーソルが[c][M]以外か? Then If Curx > 2 Then 'If 設定カーソルが[チャンネル番号]以外か? Then Lcd " " '[上下矢印]を消す。 End If End If ' Curx = Curx - 1 '設定カーソルを左へ移動させる。 Select Case Curx 'カーソルの位置調整。 Case 13 : Curx = 12 Case 9 : Curx = 8 Case 5 : Curx = 4 Case 0 : Curx = 16 End Select ' Case 5 : '[RIGHT]キーが押された場合。 If Curx < 15 Then 'If 設定カーソルが[c][M]以外か? Then If Curx > 2 Then 'If 設定カーソルが[チャンネル番号]以外か? Then Lcd " " '[上下矢印]を消す。 End If End If ' Curx = Curx + 1 '設定カーソルを右へ移動させる。 Select Case Curx 'カーソルの位置調整。 Case 5 : Curx = 6 Case 9 : Curx = 10 Case 13 : Curx = 14 Case 17 : Curx = 1 End Select ' Case 4 : '[UP]キーが押された場合。 Select Case Curx 'カーソルの位置による処理。 Case Is < 3 : 'チャンネル番号の加算。 If Curx = 2 Then 'If チャンネル番号の1の桁か? Then Channel = Channel + 1 Else Channel = Channel + 10 'チャンネル番号の10の桁の場合。 End If ' If Channel > 99 Then 'If チャンネルの上限か? Then Channel = 1 End If ' Eepchannel = Channel 'EEPROMに出力チャンネル選択を記憶する。 Channeltemp = Channel '出力チャンネル選択の一時保管。 Gosub Chandisp 'LCDにチャンネル番号を表示する。 Frequency = Eepfrequency(channel) '出力周波数を読み出す。 Gosub Freqdisp 'LCDに設定周波数を表示する。 Gosub Freqset 'DDSに周波数データを送信する。 ' Case 3 : '周波数[X0,000,000.0]位置の加算。 Frequency = Frequency + 100000000 Gosub Freqchg '出力周波数を変更する。 ' Case 4 : '周波数[0X,000,000.0]位置の加算。 Frequency = Frequency + 10000000 Gosub Freqchg '出力周波数を変更する。 ' Case 6 : '周波数[00,X00,000.0]位置の加算。 Frequency = Frequency + 1000000 Gosub Freqchg '出力周波数を変更する。 ' Case 7 : '周波数[00,0X0,000.0]位置の加算。 Frequency = Frequency + 100000 Gosub Freqchg '出力周波数を変更する。 ' Case 8 : '周波数[00,00X,000.0]位置の加算。 Frequency = Frequency + 10000 Gosub Freqchg '出力周波数を変更する。 ' Case 10 : '周波数[00,000,X00.0]位置の加算。 Frequency = Frequency + 1000 Gosub Freqchg '出力周波数を変更する。 ' Case 11 : '周波数[00,000,0X0.0]位置の加算。 Frequency = Frequency + 100 Gosub Freqchg '出力周波数を変更する。 ' Case 12 : '周波数[00,000,00X.0]位置の加算。 Frequency = Frequency + 10 Gosub Freqchg '出力周波数を変更する。 ' Case 14 : '周波数[00,000,000.X]位置の加算。 Frequency = Frequency + 1 Gosub Freqchg ' Case 15 : '[C]周波数の全クリア処理。 Frequency = 0 Gosub Freqchg '出力周波数を変更する。 ' Case 16 : '設定周波数のメモリー操作。 Eepfrequency(channel) = Frequency '選択されているチャンネルの周波数をEEPROMに記憶する。 End Select ' Case 3 : '[DOWN]キーが押された場合。 Select Case Curx 'カーソルの位置による処理。 Case Is < 3 : 'チャンネル番号の減算。 If Curx = 2 Then 'If チャンネル番号の1の桁か? Then Channel = Channel - 1 Else Channel = Channel - 10 'チャンネル番号の10の桁の場合。 End If ' If Channel = 0 Or Channel > 99 Then 'If チャンネルの下限か? Then Channel = 99 End If ' Eepchannel = Channel 'EEPROMに出力チャンネル選択を記憶する。 Channeltemp = Channel '出力チャンネル選択の一時保管。 Gosub Chandisp 'LCDにチャンネル番号を表示する。 Frequency = Eepfrequency(channel) '出力周波数を読み出す。 Gosub Freqdisp 'LCDに設定周波数を表示する。 Gosub Freqset 'DDSに周波数データを送信する。 ' Case 3 : '周波数[X0,000,000.0]位置の減算。 Frequency = Frequency - 100000000 Gosub Freqchg '出力周波数を変更する。 ' Case 4 : '周波数[0X,000,000.0]位置の減算。 Frequency = Frequency - 10000000 Gosub Freqchg '出力周波数を変更する。 ' Case 6 : '周波数[00,X00,000.0]位置の減算。 Frequency = Frequency - 1000000 Gosub Freqchg '出力周波数を変更する。 ' Case 7 : '周波数[00,0X0,000.0]位置の減算。 Frequency = Frequency - 100000 Gosub Freqchg '出力周波数を変更する。 ' Case 8 : '周波数[00,00X,000.0]位置の減算。 Frequency = Frequency - 10000 Gosub Freqchg '出力周波数を変更する。 ' Case 10 : '周波数[00,000,X00.0]位置の減算。 Frequency = Frequency - 1000 Gosub Freqchg '出力周波数を変更する。 ' Case 11 : '周波数[00,000,0X0.0]位置の減算。 Frequency = Frequency - 100 Gosub Freqchg '出力周波数を変更する。 ' Case 12 : '周波数[00,000,00X.0]位置の減算。 Frequency = Frequency - 10 Gosub Freqchg '出力周波数を変更する。 ' Case 14 : '周波数[00,000,000.X]位置の減算。 Frequency = Frequency - 1 Gosub Freqchg ' Case 15 : '[C]周波数の下位3桁クリア処理。 Frequency = Frequency / 10000 Frequency = Frequency * 10000 Gosub Freqchg '出力周波数を変更する。 ' Case 16 : '設定周波数のメモリー操作。 Eepfrequency(1) = Frequency '現在の周波数をCh.1のEEPROMに記憶する。 End Select ' End Select Gosub Curdisp 'LCDに設定カーソルを表示する。 Keydata = 0 'キー(スイッチ)の入力をクリアする。 Goto Main '################################################################################################## ' ' ***************************************** ' * LCDに設定周波数を表示するサブルーチン * (Frequency = 周波数値) ' ***************************************** ' Freqdisp: Locate 1 , 3 Tempstr = Str(frequency) '周波数を文字列に変換する。 Temp1 = Len(tempstr) '文字列の桁数を調べる。 Select Case Temp1 Case 1 : '[小数点以下1桁の場合] Lcd Spc(9) ; "0." Lcd Tempstr '小数点以下1桁を表示する。 Case Is < 5 : '[3桁以下の場合] Lcd Spc(7); Lcd Format(tempstr , " . ") '下位3桁+小数点以下1桁を表示する。 Case Is < 8 : '[6桁以下の場合] Lcd Spc(3); Temp2 = Temp1 - 4 '上位3桁を表示する。 Tempstr2 = Left(tempstr , Temp2) Lcd Format(tempstr2 , " ") ; Tempstr2 = Right(tempstr , 4) '下位3桁+小数点以下1桁を表示する。 Lcd "," ; Format(tempstr2 , " . ") Case Else : '[7桁以上の場合] Temp2 = Temp1 - 7 '上位2桁を表示する。 Tempstr2 = Left(tempstr , Temp2) Lcd Format(tempstr2 , " ") ; Temp2 = Temp1 - 6 '中間の3桁を表示する。 Tempstr2 = Mid(tempstr , Temp2 , 3) Lcd "," ; Tempstr2 ; Tempstr2 = Right(tempstr , 4) '下位3桁+小数点以下1桁を表示する。 Lcd "," ; Format(tempstr2 , " . ") End Select Return ' ' ********************************************* ' * LCDにチャンネル番号を表示するサブルーチン * ' ********************************************* ' Chandisp: Locate 2 , 1 Tempstr = Str(channel) 'チャンネル番号を文字列に変換する。 Lcd Format(tempstr , " ") '2桁をゼロサプレスで表示する。 Return ' ' ******************************************* ' * LCDに設定カーソルを表示するサブルーチン * ' ******************************************* ' Curdisp: If Curx < 15 Then 'If 設定カーソルが[c][M]以外か? Then If Curx > 2 Then 'If 設定カーソルが[チャンネル番号]以外か? Then Locate 2 , Curx Lcd Chr(0) '[上下矢印]を表示する。 End If End If ' Locate 2 , Curx Return ' ' ************************************ ' * 出力周波数を変更するサブルーチン * ' ************************************ ' Freqchg: If Frequency > 624990000 Then 'If 動作周波数の上限か? Then Frequency = 624990000 '上限値に設定する。 End If ' If Frequency < 0 Then 'If 動作周波数の下限か? Then Frequency = 0 '下限値に設定する。 End If ' Gosub Freqdisp 'LCDに設定周波数を表示する。 Gosub Freqset 'DDSのレジスタに周波数データを送信する。 Return '================================================================================================== ' ' ***************************************************** ' * DDSのレジスタに周波数データを送信するサブルーチン * (Frequency = 周波数値) ' ***************************************************** ' Freqset: If Frequency = 0 Then 'If 周波数値が0Hzか? Then Tempdw1 = &H00000000 'FREQ REGを先に[0]にする。 Gosub Ddsset40b 'DDSに40bitのデータを送信する。 Gosub Ddsset40b0 'DDSをリセットしてから40bitのデータを送信する。 Else Temps1 = Frequency '周波数値をシングル変数に変換する。 Temps1 = Temps1 / Resolution 'FREQ REG = Fout / SYSCLK * 2^32 = Fout / 分解能(小数点以下x10) Tempdw1 = Temps1 'FREQ REG値をダブルワード変数に変換する。 Gosub Ddsset40b 'DDSに40bitのデータを送信する。 End If Return ' ' ******************************************** ' * DDSに40bitのデータを送信するサブルーチン * (Tempdw1 = 32bitの周波数データ) ' ******************************************** (Ddscontrol = 8bitのコントロール・データ) ' Ddsset40b0: 'DDSをリセットしてからの場合。 Set Dds_reset 'DDSの[RESET]を[H]にする。 Waitus 10 'リセット期間[tRS]の待ち時間。 Reset Dds_reset 'DDSの[RESET]を[L]にする。 Waitus 10 'リセットからの回復時間[tRR]。 ' Set Dds_wclk 'DDSの[W_CLK]を[H]にする。(シリアル・モードへの移行) Reset Dds_wclk 'DDSの[W_CLK]を[L]にする。 Set Dds_fqud 'DDSの[FQ_UD]を[H]にする。(シリアル・モードを有効にする) Reset Dds_fqud 'DDSの[FQ_UD]を[L]にする。 ' Ddsset40b: Shiftout Dds_d7 , Dds_wclk , Tempdw1 , 3 , 32 '32bitの周波数データを送信する。 Shiftout Dds_d7 , Dds_wclk , Ddscontrol , 3 , 8 '8bitのコントロール・データを送信する。 Set Dds_fqud 'DDSの[FQ_UD]を[H]にする。 Reset Dds_fqud 'DDSの[FQ_UD]を[L]にする。 Return '================================================================================================== ' ' *********************************************************** メイン・ルーチンで定期的に呼び続けること。 ' * キー(スイッチ)を検出するサブルーチン (抵抗値のA/D変換) * Keydata = キー(スイッチ)の入力データ。(押された場合にコードが入る) ' *********************************************************** Keyadcode = キー(スイッチ)をA/D変換したコード。(押されている状態のコードが入る) ' (0:押されていない, 1:[SELECT] , 2:[LEFT], 3:[DOWN], 4:[UP], 5:[RIGHT]キー) Getkey: Gosub Keyadconv 'キー(スイッチ)の分圧抵抗値をA/D変換する。 If Keyadcode <> 0 Then 'If いずれかのキーが押されているか? Then If Keystat = 0 Then 'If キー入力の検出中か? Then Waitms 30 'チャタリングを除去する待ち時間。 Gosub Keyadconv 'キー(スイッチ)の分圧抵抗値をA/D変換する。 If Keyadcode <> 0 Then 'If いずれかのキーが押されているか? Then Keydata = Keyadcode 'キーが押されたことを通知する。 Keystat = 1 'キーの解放待ちにする。 End If End If Else 'キーが押されていない場合。 If Keystat <> 0 Then 'If キーの解放待ちか? Then Waitms 30 'チャタリングを除去する待ち時間。 Gosub Keyadconv 'キー(スイッチ)の分圧抵抗値をA/D変換する。 If Keyadcode = 0 Then 'If キーが離されているか? Then Keystat = 0 'キー入力の検出中にする。 End If End If End If Return ' ' * キー(スイッチ)の分圧抵抗値をA/D変換するサブルーチン * ' Keyadconv: Keyw1 = Getadc(0) 'キー(スイッチ)の分圧抵抗値をA/D変換する。 #if Board_version = 10 'If DFROBOT社のボード・バージョンが1.0か? Then Select Case Keyw1 '分圧抵抗のA/D値から押されたキーを判別する。 Case Is > 950 : Keyadcode = 0 'キーが押されていない場合。 Case Is < 50 : Keyadcode = 5 '[RIGHT] キー。 Case Is < 195 : Keyadcode = 4 '[UP] キー。 Case Is < 380 : Keyadcode = 3 '[DOWN] キー。 Case Is < 555 : Keyadcode = 2 '[LEFT] キー。 Case Else : Keyadcode = 1 '[SELECT] キー。 End Select #else 'DFROBOT社のボード・バージョンが1.1の場合。 Select Case Keyw1 '分圧抵抗のA/D値から押されたキーを判別する。 Case Is > 950 : Keyadcode = 0 'キーが押されていない場合。 Case Is < 50 : Keyadcode = 5 '[RIGHT] キー。 Case Is < 250 : Keyadcode = 4 '[UP] キー。 Case Is < 450 : Keyadcode = 3 '[DOWN] キー。 Case Is < 650 : Keyadcode = 2 '[LEFT] キー。 Case Else : Keyadcode = 1 '[SELECT] キー。 End Select #endif Return ' ' End