' $prog &HFF , &HFF , &HDF , &HFF 'CKDIV8 = 1 , SUT = 11 , CKSEL = 1111 ' ' ********************************************** ' * * ' * AMラジオ トランスミッター プログラム * ' * * ' * AVR is using ATtiny2313 * ' * Basic Compiler is BASCOM-AVR * ' * Copyright By O-Family 2010. 8. 7 * ' ********************************************** ' ' Ver 1.01 初回公開バージョン。 2010. 8. 7 ' Const Prgver = "01.01 " 'プログラム・バージョン。 ' $regfile = "ATtiny2313.DAT" '使用するAVRを設定。 $crystal = 8000000 'AVRクロックを設定。 ' $hwstack = 48 'ハードウェア・スタックの容量を設定。 $swstack = 8 'ソフトウェア・スタックの容量を設定。 $framesize = 24 'フレーム領域の容量を設定。 ' ' Da_sck Alias Portb.7 '[MCP4922]の[SCK]接続ポート。 Da_sdi Alias Portb.5 '[MCP4922]の[SDI]接続ポート。 Da_cs Alias Portb.4 '[MCP4922]の[/CS]接続ポート。 ' Led_r Alias Portd.6 '[赤]LED接続ポート。 Led_b Alias Portb.0 '[青]LED接続ポート。 ' Dipsw_1 Alias Pind 'DIPスイッチ[1-4,8]接続ポート。 Dipsw_7 Alias Pinb.3 'DIPスイッチ[7]接続ポート。 ' ' Dim T100mscun As Byte '0.1秒(4mS X 25)カウンター。 Dim Frqmode As Byte '周波数カウント割り込みの動作モード。 Dim Frqendf As Byte '周波数計測完了フラグ。 Dim Frqdat1 As Word '周波数カウント・レジスター値 バッファー1。 Dim Frqovf1 As Word 'オーバーフロー・カウント値 バッファー1。 Dim Frqdat2 As Word '周波数カウント・レジスター値 バッファー2。 Dim Frqovf2 As Word 'オーバーフロー・カウント値 バッファー2。 Dim Frqovfc As Word 'オーバーフロー・カウンター。 Dim Frqdat As Long '周波数カウント・データを差分計算したカウント値。 Dim Setfrq As Long '設定チャンネルの周波数。 ' 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 Tempw2 As Word '汎用テンポラリ変数 Word型 No.2 Dim Tempi1 As Integer '汎用テンポラリ変数 Integer型 No.1 Dim Templ1 As Long '汎用テンポラリ変数 Long型 No.1 Dim Templ2 As Long '汎用テンポラリ変数 Long型 No.2 ' ' * ポートの初期設定 * ' Config Da_cs = Output '[MCP4922]の[/CS]接続ポートを出力に設定。 Config Led_r = Output '[赤]LED接続ポートを出力に設定。 Config Led_b = Output '[青]LED接続ポートを出力に設定。 Config Portb.2 = Output '[OC0A]ポートを出力に設定。 Portd = &B0001_1111 'DIPスイッチ[1-4,8]接続ポートをプルアップ。 Set Portb.3 'DIPスイッチ[7]接続ポートをプルアップ。 Set Portb.6 '未使用ポートをプルアップ。 Set Da_cs '[MCP4922]の[/CS]を[H]にセット。 Reset Led_r '[赤]LEDを消灯する。 Set Led_b '[青]LEDを点灯する。 ' ' * タイマーの設定 * ' Config Timer0 = Timer , Prescale = 256 , Clear Timer = 1 '8,000,000Hz / 256 = 31,250Hz Ocr0a = 125 - 1 '31,250Hz / 125カウント = 250Hz (4mS) On Oc0a Tint4ms Nosave 'TIMER0比較一致A割り込みルーチンのラベルを設定する。 Enable Oc0a 'TIMER0比較一致A割り込みを許可する。 ' Config Timer1 = Counter , Edge = Falling '[T1]の立ち下がりエッジでカウント。 On Timer1 Tintovf Nosave 'オーバーフロー割り込みルーチンのラベルを設定する。 Enable Timer1 'オーバーフロー割り込みを許可する。 ' ' * アナログ比較器の設定 * ' Config Aci = On 'アナログ比較器の電源を入れる。 Set Acsr.acbg 'アナログ比較器の基準電圧を内部1.1Vに設定する。 Set Acsr.aci 'アナログ比較器割り込みフラグをリセットする。 Set $01.ain1d '[AIN1]デジタル入力禁止レジスタの設定。 ' ' * キャリブレーション・モードの確認 * ' Waitms 100 'プルアップのレベル確定待ち時間。 If Dipsw_1.4 = 0 Then Goto Syscal 'If DIPスイッチ[8]がONか? Then ' ' * 変数の初期設定 * ' Enable Interrupts 'すべての割り込みを許可する。 Temp2 = &HFF 'DIPスイッチ[1-4]の記憶を不確定にする。 Tempw1 = 0 'D/Aコンバータに初期値をセットする。 Gosub Daout 'D/Aコンバータ[MCP4922]へ送信する。 Temp3 = 0 ' ' * メイン ルーチン * ' Main: ' ' * DIPスイッチの変化を検出し、周波数を設定する * ' Gosub Chswin 'チャンネルDIPスイッチの読み込み+変換。 If Temp2 <> Temp1 Then 'DIPスイッチ[1-4]が変えられたか? Then Temp2 = Temp1 Templ1 = 9000 * Temp1 'チャンネルの周波数を計算する。 Setfrq = 540000 + Templ1 End If ' ' * 周波数を計測して自動追従する * ' If Frqendf <> 0 Then 'If 周波数計測が完了したか? Then Gosub Frqcount '周波数計測ルーチン。 Reset Led_r '[赤]LEDを消灯する。 ' If Temp3 < 1 Then 'If 周波数計測が2回目か? Temp3 = Temp3 + 1 '1回目。 Else Temp3 = 0 '2回目。 Set Led_b '[青]LEDを点灯する。 ' Frqdat = Frqdat * 10 '計測周波数を10倍する。 Templ1 = Frqdat - Setfrq '計測周波数 - 設定周波数。 Templ2 = Templ1 / 42 'D/Aの分解能で差分を計算する。 Tempi1 = Templ2 'Integer変数に変換。 Tempw1 = Tempw1 + Tempi1 '現在のD/A値に差分を増減する。 ' If Tempw1 > 4095 Then 'If D/A設定値がオーバーしたか? Then Tempw1 = 4095 End If ' If Tempi1 <> 0 Then 'If 変更がない(差分が0)か? Else Gosub Daout 'D/Aコンバータ[MCP4922]へ送信する。 ' If Dipsw_7 = 0 Then 'If DIPスイッチ[7]がONか? Then Reset Led_b '[青]LEDを消灯する。 End If End If End If End If ' ' * ピークレベルを検出して[赤]LEDを100mS点灯させる * ' If Acsr.aci = 1 Then 'If ピークレベルを検出したか? Then Set Acsr.aci 'アナログ比較器割り込みフラグをリセットする。 Set Led_r '[赤]LEDを点灯する。 End If Goto Main ' ' ************************* ' * D/A 出力 サブルーチン * (Twmpw1 = D/A値) ' ************************* ' Daout: Tempw2 = &HB000 + Tempw1 'DAC-B , BUF-Off , GA-1x , SHDN-Off Reset Da_cs Shiftout Da_sdi , Da_sck , Tempw2 , 1 , 16 'D/Aコンバータ[MCP4922]へ送信する。 Set Da_cs Return ' ' ******************************************* ' * 周波数カウント値の差分計算 サブルーチン * (Frqdat = 測定周波数) ' ******************************************* ' Frqcount: Templ1 = Frqovf1 'バッファー1のカウント値をロング型に変換する。 Shift Templ1 , Left , 16 Templ1 = Templ1 + Frqdat1 Templ2 = Frqovf2 'バッファー2のカウント値をロング型に変換する。 Shift Templ2 , Left , 16 Templ2 = Templ2 + Frqdat2 ' If Frqendf.0 = 1 Then 'If バッファー1が測定終了データか? Then Frqdat = Templ1 - Templ2 Else Frqdat = Templ2 - Templ1 End If Frqendf = 0 '周波数計測完了フラグをクリア。 Return ' ' ***************************************************** ' * チャンネル DIPスイッチ 読み込み+変換 サブルーチン * (DIPスイッチコード = Temp1) ' ***************************************************** ' Chswin: $asm IN R16,Dipsw_1 CLR R17 BST R16,1 'DIPスイッチ[1-4]を16進コードに並び替える。 BLD R17,0 BST R16,2 BLD R17,1 BST R16,0 BLD R17,2 BST R16,3 BLD R17,3 STS {Temp1},R17 $end Asm Return ' ' **************************** ' * キャリブレーション 処理 * ' **************************** ' Syscal: Config Timer0 = Timer , Prescale = 1 , Clear Timer = 1 , Compare A = Toggle '8MHz水晶発振の較正。 Ocr0a = 0 '8,000,000Hz / 2 = 4,000,000Hz ' Tempw1 = 4095 Gosub Daout 'D/Aコンバータ[MCP4922]へ送信する。 Syscal1: Waitms 100 If Temp1 < 4 Then 'If 0.5秒経過したか? Temp1 = Temp1 + 1 Else Temp1 = 0 Toggle Led_b '[青]LEDを点滅させる。 ' If Temp2 < 9 Then 'If 5秒経過したか? Temp2 = Temp2 + 1 Else '発振周波数を最低と最高で切り換える。 Temp2 = 0 If Temp3 = 0 Then Set Led_r '最高周波数。 Temp3 = 1 Tempw1 = 0 Else Reset Led_r '最低周波数。 Temp3 = 0 Tempw1 = 4095 End If Gosub Daout 'D/Aコンバータ[MCP4922]へ送信する。 End If End If Goto Syscal1 ' ' ' * [Timer0] 4mS間隔 割り込み処理ルーチン * ' (4mSを25回数えて、0.1秒間隔でTimer1のカウント値を読み取る) ' Tint4ms: $asm PUSH R1 IN R1,SREG 'ステータス・レジスタを待避。 PUSH R16 ; LDS R16,{t100mscun} '0.1秒カウンターを+1する。 INC R16 STS {t100mscun},R16 CPI R16,25 BRCS Tint4ms1 'If 0.1秒(4mS X 25)経過していないか? Then ; ; CLR R16 STS {t100mscun},R16 ; PUSH R23 'R23は、拡張I/Oレジスタへのアクセスに使用する。 PUSH R24 PUSH R25 ; IN R24,TCNT1L 'Timer1の下位バイトを取得。 IN R23,TCNT1H 'Timer1の上位バイトを取得。 ; LDS R16,{Frqmode} '周波数カウントのモードを調べる。 SBRC R16,0 'If データ・バッファー2 へ書き込み? Then RJMP Tint4ms2 ; ; '---<データ・バッファー1 書き込み処理>--- STS {Frqdat1},R24 'データ・バッファー1へ保存。 STS {Frqdat1+1},R23 ; LDS R24,{Frqovfc} 'オーバーフロー・カウント値を取得。 LDS R25,{Frqovfc+1} CPI R23,0 BRNE Tint4ms3 'If 周波数カウント・データの上位バイトが00? Else ; IN R23,TIFR SBRS R23,TOV1 'オーバーフローが発生しているか? Else RJMP Tint4ms3 ; ADIW R24,1 'オーバーフロー・カウント値を+1 ; Tint4ms3: STS {Frqovf1},R24 'データ・バッファー1へ保存。 STS {Frqovf1+1},R25 ORI R16,&H01 'モードをデータ・バッファー2 書き込みに変更。 RJMP Tint4ms5 ; ; Tint4ms2: '---<データ・バッファー2 書き込み処理>--- STS {Frqdat2},R24 'データ・バッファー2へ保存。 STS {Frqdat2+1},R23 ; LDS R24,{Frqovfc} 'オーバーフロー・カウント値を取得。 LDS R25,{Frqovfc+1} CPI R23,0 BRNE Tint4ms4 'If 周波数カウント・データの上位バイトが00? Else ; IN R23,TIFR SBRS R23,TOV1 'オーバーフローが発生しているか? Else RJMP Tint4ms4 ; ADIW R24,1 'オーバーフロー・カウント値を+1 ; Tint4ms4: STS {Frqovf2},R24 'データ・バッファー2へ保存。 STS {Frqovf2+1},R25 ANDI R16,&HF0 'モードをデータ・バッファー1 書き込みに変更。 ; ; Tint4ms5: CPI R16,&H10 BRCC Tint4ms6 'If 1と2の両バッファーにデータの準備が完了か? Then ORI R16,&H10 '周波数カウント・モードを2つめのデータ待ちにセット。 RJMP Tint4ms7 ; Tint4ms6: STS {Frqendf},R16 '周波数計測完了フラグをセット。 Tint4ms7: STS {Frqmode},R16 '周波数カウント・モードを更新。 ; POP R25 POP R24 POP R23 ; ; Tint4ms1: POP R16 Out Sreg , R1 'ステータス・レジスタを復帰 POP R1 $end Asm Return ' ' ' * Timer1 オーバーフロー 割り込み処理ルーチン * ' (周波数カウント値を32bitにするため、[Timer1]が溢れた場合に上位16bit値を加算する) ' Tintovf: $asm PUSH R1 IN R1,SREG 'ステータス・レジスタを待避。 PUSH R24 PUSH R25 ; LDS R24,{Frqovfc} 'オーバーフロー・カウント値を+1する。 LDS R25,{Frqovfc+1} ADIW R24,1 STS {Frqovfc},R24 STS {Frqovfc+1},R25 ; POP R25 POP R24 Out Sreg , R1 'ステータス・レジスタを復帰 POP R1 $end Asm Return ' ' End