' $prog &HFF , &HE0 , &HDF , &HF9 'CKDIV8 = 1 , SUT = 10 , CKSEL = 0000 ' ' ' *************************************************** ' * * ' * 精度アップ * ' * レシプロカル式 周波数カウンター 3 プログラム * ' * * ' * AVR is using ATmega88P * ' * Basic Compiler is BASCOM-AVR * ' * Copyright By O-Family 2011. 3.30 * ' *************************************************** ' ' Ver 3.01 初回公開バージョン。2011. 1.12 ' Ver 3.02 [Serial to LED]用の出力形式を変更。2011. 1.28 ' Ver 3.03 100MHz以上の周波数で表示が乱れるのを修正。[10E6]指数処理のエラーを修正。2011. 3.30 ' ' Const Prgver = "03.03" 'プログラム・バージョン。 ' ' $regfile = "m88Pdef.dat" '使用するAVRを設定。 $crystal = 12800000 'AVRクロックを設定。 ' $hwstack = 64 'ハードウェア・スタックの容量を設定。 $swstack = 32 'ソフトウェア・スタックの容量を設定。 $framesize = 64 'フレーム領域の容量を設定。 ' $baud = 9600 'ハードウェアUARTの通信速度(ボーレート)を設定。 ' ' Sw_o1 Alias Portc.3 'スイッチ1のポートピン指定。 Sw_1 Alias Pinc.3 Sw_o2 Alias Portc.4 'スイッチ2のポートピン指定。 Sw_2 Alias Pinc.4 Sw_o3 Alias Portc.5 'スイッチ3のポートピン指定。 Sw_3 Alias Pinc.5 ' Msel_a Alias Portb.7 '[SL1]プリスケーラ選択[A]のポート。 Msel_b Alias Portc.2 '[SL2]プリスケーラ選択[B]のポート。 Pfrq_b0 Alias Pind.2 '[PFb0]プリスケーラの選択入力ビット[0]ポート。 Pfrq_b1 Alias Pind.5 '[PFb1]プリスケーラの選択入力ビット[1]ポート。 ' ' Dim Capmode As Byte 'キャプチャー割り込みの動作モード。 Dim Capendf As Byte 'キャプチャー計測完了フラグ。 Dim Capdat1 As Word 'キャプチャー・レジスター値 バッファー1。 Dim Capovf1 As Word 'オーバーフロー・カウント値 バッファー1。 Dim Capdat2 As Word 'キャプチャー・レジスター値 バッファー2。 Dim Capovf2 As Word 'オーバーフロー・カウント値 バッファー2。 Dim Capovfc As Word 'オーバーフロー・カウンター。 ' Dim Frqdat As Long 'キャプチャー・データを差分計算したカウント値。 Dim Frqcun As Long 'SUB AVRから受信したカウント値。 Dim Frqcun0 As Byte At Frqcun + 0 Overlay 'バイト型に名前を重複させる。 Dim Frqcun1 As Byte At Frqcun + 1 Overlay Dim Frqcun2 As Byte At Frqcun + 2 Overlay Dim Frqcun3 As Byte At Frqcun + 3 Overlay ' Dim Meatime As Byte '測定周期の選択設定。(0:1.24S , 1:5S) Dim Prescmode As Byte 'プリスケーラの動作モード。(0:自動 , 1:1/1 , 2:1/10 , 3:1/100) Dim Prescale As Byte 'プリスケーラ値。(0:1/1 , 1:1/10 , 2:1/100) Dim Dispsel As Byte '表示モードの選択設定。(0:全桁表示 , 1:小数点以下3桁表示) Dim Noinpf As Byte '入力無しのカウントフラグ。 Dim Swoff As Byte 'スイッチのOFFチェック用フラグ。 Dim Meatchr As String * 1 'シリアル出力用の測定周期文字。 Dim Prscchr As String * 1 'シリアル出力用のプリスケーラ文字。 ' Dim Temp1 As Byte '汎用テンポラリ変数 Byte型 No.1 Dim Temp2 As Byte '汎用テンポラリ変数 Byte型 No.2 Dim Temp3 As Byte '汎用テンポラリ変数 Byte型 No.3 Dim Temp4 As Byte '汎用テンポラリ変数 Byte型 No.4 Dim Tempi1 As Integer '汎用テンポラリ変数 Integer型 No.1 Dim Templ1 As Long '汎用テンポラリ変数 Long型 No.1 Dim Tempd1 As Double '汎用テンポラリ変数 Double型 No.1 Dim Tempd2 As Double '汎用テンポラリ変数 Double型 No.2 Dim Tempstr As String * 30 '汎用テンポラリ変数 String型 Dim Tempstr2 As String * 20 '汎用テンポラリ変数 String型 No.2 Dim Tempstr3 As String * 20 '汎用テンポラリ変数 String型 No.3 Dim Tempstr4 As String * 20 '汎用テンポラリ変数 String型 No.4 ' Dim Eep_meatime As Eram Byte At $10 'EEPROM 測定周期の選択設定。(0:1.24S , 1:5S) Dim Eep_prescmode As Eram Byte At $11 'EEPROM プリスケーラ値。(0:自動 , 1:1/1 , 2:1/10 , 3:1/100) Dim Eep_dispsel As Eram Byte At $12 'EEPROM 表示モードの選択設定。(0:全桁表示 , 1:小数点以下3桁表示) ' ' ' ' * LCDの初期設定 * ' Config Lcdmode = Port 'LCDを4ビットのポートモードに設定。 Config Lcdbus = 4 'LCDデータバスを4bitに設定。 Config Lcdpin = Pin , Db4 = Portb.5 , Db5 = Portb.4 'LCDのポート割り当て。 Config Lcdpin = Pin , Db6 = Portb.3 , Db7 = Portb.2 Config Lcdpin = Pin , E = Portb.1 , Rs = Portc.0 Config Lcd = 16 * 2 'LCD表示を16文字2行に設定。 ' Cursor Off 'LCDのカーソルをオフ。 Deflcdchar 0 , &H04 , &H0C , &H04 , &H04 , &H04 , &H0E , &H11 , &H1F 'カスタム文字[T1]をLCDへ書き込む。 Deflcdchar 1 , &H0E , &H08 , &H0C , &H02 , &H02 , &H0C , &H11 , &H1F 'カスタム文字[T5]をLCDへ書き込む。 Cls 'LCD表示をすべて消去。 ' ' * ポートの初期設定 * ' Config Msel_a = Output 'モード選択Aポートを出力に設定。 Config Msel_b = Output 'モード選択Bポートを出力に設定。 Set Sw_o1 'スイッチ1 ポートをプルアップ。 Set Sw_o2 'スイッチ2 ポートをプルアップ。 Set Sw_o3 'スイッチ3 ポートをプルアップ。 Set Portd.7 '未使用ポートをプルアップ。 Open "comC.1:9600,8,N,1" For Output As #1 'シリアル出力用のポートを設定する。 ' Waitms 100 Print #1 , Chr(&H12) ; "1" '[Serial to LED]ユニットにモード変更を指示する。 Waitms 100 Print #1 , Chr(&H12) ; "1" '[Serial to LED]ユニットにモード変更を指示する。 ' ' * EEPROMの確認 * ' If Eep_meatime > 1 Then 'EEPROMが初期状態か? Then Eep_meatime = 0 'EEPROMに初期設定を書き込む。 Eep_prescmode = 0 Eep_dispsel = 0 End If Meatime = Eep_meatime Prescmode = Eep_prescmode Dispsel = Eep_dispsel ' ' * プログラム・バージョンの表示 * ' If Sw_1 = 0 Then 'If スイッチ1が押されているか? Then Locate 1 , 1 'プログラム・バージョンを表示。 Lcd "Freq-Counter 3" Locate 2 , 4 Lcd "Ver. " ; Prgver Bitwait Sw_1 , Set 'スイッチ1が離されるまで待つ。 Waitms 30 'チャタリング・タイマー。 Cls End If ' ' * タイマーの設定 * ' Config Timer2 = Timer , Prescale = 256 , Clear Timer = 1 , Compare B = Toggle '12,800,000Hz / 256 = 50,000Hz Ocr2a = 250 - 1 '50,000Hz / 250カウント = (200 / 2) = 100Hz Ocr2b = 250 - 1 Config Timer0 = Counter , Edge = Rising , Clear Timer = 1 , Compare A = Toggle '[OC0A]端子から測定周期パルスを出力する。 Gosub Meatmset '測定周期を設定する。 ' Config Timer1 = Timer , Prescale = 1 , Capture Edge = Rising 'AVR動作クロックによりカウント。 On Capture1 Tintcap Nosave 'キャプチャー割り込みルーチンのラベルを設定。 Enable Capture1 'キャプチャー割り込みを許可。 On Timer1 Tintovf Nosave 'オーバーフロー割り込みルーチンのラベルを設定。 Enable Timer1 'オーバーフロー割り込みを許可。 ' ' * 変数と表示の初期設定 * ' Gosub Prescdss 'プリスケーラ値の表示と設定。 Gosub Disp0hz '[OHz]を表示する。 Enable Interrupts 'すべての割り込みを許可。 ' ' ******************* ' * メイン ルーチン * ' ******************* ' Main: Gosub Switchin 'スイッチの入力処理。 Gosub Autopresc 'プリスケーラの自動切換処理。 Gosub Frqcal 'カウント値の計算処理。 Goto Main ' ' ********************************** ' * スイッチの入力処理サブルーチン * ' ********************************** ' Switchin: If Swoff <> 0 Then Goto Switchin4 'If スイッチのOFF検出中か? Then If Sw_1 = 0 Then Goto Switchin1 'If スイッチ1が押されたか? Then If Sw_2 = 0 Then Goto Switchin2 'If スイッチ2が押されたか? Then If Sw_3 = 0 Then Goto Switchin3 'If スイッチ3が押されたか? Then Return ' ' Switchin1: 'スイッチ1 (測定周期の選択) If Meatime = 0 Then Meatime = 1 Else Meatime = 0 End If Eep_meatime = Meatime 'EEPROMへ書き込む。 Gosub Meatmset '測定周期を設定する。 ' Switchin9: Swoff = 1 'スイッチOFFチェックフラグを立てる。 Waitms 30 'チャタリング・タイマー。 Return ' ' Switchin2: 'スイッチ2 (プリスケーラの選択) Prescmode = Prescmode + 1 Gosub Prescdss 'プリスケーラ値の表示と設定。 Eep_prescmode = Prescmode 'EEPROMへ書き込む。 Goto Switchin9 ' ' Switchin3: 'スイッチ3 (表示モードの選択設定 [全桁表示,小数点以下3桁表示]) If Dispsel = 0 Then Dispsel = 1 Else Dispsel = 0 End If Eep_dispsel = Dispsel 'EEPROMへ書き込む。 Goto Switchin9 ' ' Switchin4: 'スイッチが離されるのを待つ。 Temp1 = Sw_1 And Sw_2 Temp1 = Temp1 And Sw_3 If Temp1 = 0 Then Return 'If どれかのスイッチが押されているか? Then Swoff = 0 Waitms 30 'チャタリング・タイマー。 Return ' ' * 測定周期を設定するサブルーチン * ' Meatmset: Locate 2 , 1 If Meatime = 0 Then 'If 測定周期が[1.24S]か? Then Lcd Chr(&H00) Ocr0a = 62 - 1 '100Hz / 62カウント = (1.6129 / 2) = 0.8064Hz (1.24S) Meatchr = "1" Else Lcd Chr(&H01) Ocr0a = 250 - 1 '100Hz / 250カウント = (0.4 / 2) = 0.2Hz (5S) Meatchr = "5" End If Return ' ' * プリスケーラ値の表示と設定サブルーチン * ' Prescdss: Locate 2 , 2 Select Case Prescmode Case 1 : 'プリスケーラ 1/1。 Tempstr = "5M " Reset Msel_a 'モードセレクターを設定。 Reset Msel_b Prescale = 0 Prscchr = "P" Case 2 : 'プリスケーラ 1/10。 Tempstr = "50M" Set Msel_a 'モードセレクターを設定。 Reset Msel_b Prescale = 1 Prscchr = "Q" Case 3 : 'プリスケーラ 1/100。 Tempstr = "99M" Reset Msel_a 'モードセレクターを設定。 Set Msel_b Prescale = 2 Prscchr = "R" Case Else : 'プリスケーラ 自動。 Tempstr = "AT " Prescmode = 0 Prscchr = "A" End Select ' Locate 2 , 2 Lcd Tempstr Return ' ' ****************************** ' * プリスケーラの自動切換処理 * ' ****************************** ' Autopresc: If Prescmode <> 0 Then Return 'If プリスケーラが自動か? Else If Pfrq_b1 = 1 Then 'If プリスケーラの選択入力[1]が[H]か? Then Prescale = 2 '1/100。 Reset Msel_a 'セレクターを設定。 Set Msel_b Else If Pfrq_b0 = 0 Then 'If プリスケーラの選択入力[0]が[L]か? Then Prescale = 0 '1/1。 Reset Msel_a 'セレクターを設定。 Reset Msel_b Else Prescale = 1 '1/10。 Set Msel_a 'セレクターを設定。 Reset Msel_b End If End If Return ' ' ************************************ ' * カウント値の計算処理サブルーチン * ' ************************************ ' Frqcal: If Capendf = 0 Then Goto Frqcal3 'If キャプチャー計測が完了していないか? Then ' Gosub Capsubt 'キャプチャー・バッファーの値を差分計算する。=> (Frqdat) Capendf = 0 Noinpf = 0 Temp2 = Inkey() 'ダミーの受信。(UARTを空にする) ' Temp1 = 0 Frqcal1: Temp2 = &H02 Printbin Temp2 '[STX]を送信する。 Frqcal2: If Capendf <> 0 Then Goto Frqcal9 'If タイムアウトが発生したか? Then Temp2 = Ischarwaiting() If Temp2 = 0 Then Goto Frqcal2 'If データを受信したか? else ' Inputbin Temp2 'UARTよりデータを取り出す。 Select Case Temp1 '受信データを格納する。 Case 0 : Frqcun0 = Temp2 Case 1 : Frqcun1 = Temp2 Case 2 : Frqcun2 = Temp2 Case 3 : Frqcun3 = Temp2 End Select ' Temp1 = Temp1 + 1 If Temp1 < 4 Then Goto Frqcal1 'If データの受信が終了か? Else ' Tempd1 = Frqdat '周波数を求める。 Tempd2 = Frqcun Tempd1 = Tempd1 / Tempd2 Tempd2 = 12800000 / Tempd1 ' Select Case Prescale 'プリスケーラによって計測値を補正する。 Case 1 : '[1/10] Tempd2 = Tempd2 * 10 Tempd1 = Tempd1 / 10 Case 2 : '[1/100] Tempd2 = Tempd2 * 100 Tempd1 = Tempd1 / 100 End Select Gosub Frqstrc '計測値をLCDとシリアル出力に表示する。 Return ' ' Frqcal9: Temp2 = &H03 Printbin Temp2 '[ETX]を送信する。 Return ' ' Frqcal3: '無信号のチェック。 Temp1 = Ischarwaiting() If Temp1 = 0 Then Return 'If データを受信したか? else ' Inputbin Temp1 'UARTよりデータを取り出す。 If Temp1 = &H30 Then 'If "0"か? Then Gosub Disp0hz '[OHz]を表示する。 End If Return ' ' * 計測値をLCDとシリアル出力に表示する * ' Frqstrc: ' ' * 周波数の表示 * ' Gosub Strconv '指数表示を単純な文字列に変換する。 On Temp1 Goto Digit0 , Digit0 , Digit2 , Digit3 , Digit4 , Digit5 , Digit6 , Digit7 , Digit8 , Digit9 '桁数により表示項目を選択する。 ' ' Digit0: '0.00000000000〜9.99999999999 Hz Tempstr2 = Left(tempstr , 5) Tempstr3 = Mid(tempstr , 6 , 8) Temp2 = 8 Goto Digitend ' Digit2: '10.0000000000〜99.9999999999 Hz Tempstr2 = Left(tempstr , 6) Tempstr3 = Mid(tempstr , 7 , 7) Temp2 = 7 Goto Digitend ' Digit3: '100.000000000〜999.999999999 Hz Tempstr2 = Left(tempstr , 7) Tempstr3 = Mid(tempstr , 8 , 6) Temp2 = 6 Goto Digitend ' Digit4: '1,000.0000000〜9,999.9999999 Hz Tempstr2 = Left(tempstr , 1) + "," Tempstr2 = Tempstr2 + Mid(tempstr , 2 , 3) + "." Tempstr2 = Tempstr2 + Mid(tempstr , 5 , 3) Tempstr3 = Mid(tempstr , 8 , 4) Temp2 = 4 Goto Digitend ' Digit5: '10,000.000000〜99,999.999999 Hz Tempstr2 = Left(tempstr , 2) + "," Tempstr2 = Tempstr2 + Mid(tempstr , 3 , 3) + "." Tempstr2 = Tempstr2 + Mid(tempstr , 6 , 3) Tempstr3 = Mid(tempstr , 9 , 3) Temp2 = 3 Goto Digitend ' Digit6: '100,000.00000〜999,999.99999 Hz Tempstr2 = Left(tempstr , 3) + "," Tempstr2 = Tempstr2 + Mid(tempstr , 4 , 3) + "." Tempstr2 = Tempstr2 + Mid(tempstr , 7 , 3) Tempstr3 = Mid(tempstr , 10 , 2) Temp2 = 2 Goto Digitend ' Digit7: '1,000,000.000〜9,999,999.999 Hz Tempstr2 = Left(tempstr , 1) + "," Tempstr2 = Tempstr2 + Mid(tempstr , 2 , 3) + "," Tempstr2 = Tempstr2 + Mid(tempstr , 5 , 3) + "." Tempstr2 = Tempstr2 + Mid(tempstr , 8 , 3) Tempstr3 = "" Temp2 = 0 Goto Digitend ' Digit8: '10,000,000.00〜99,999,999.99 Hz Tempstr2 = Left(tempstr , 2) + "," Tempstr2 = Tempstr2 + Mid(tempstr , 3 , 3) + "," Tempstr2 = Tempstr2 + Mid(tempstr , 6 , 3) + "." Tempstr2 = Tempstr2 + Mid(tempstr , 9 , 2) Tempstr3 = "" Temp2 = 0 Goto Digitend ' Digit9: '100,000,000.0〜999,999,999.9 Hz Tempstr2 = Left(tempstr , 3) + "," Tempstr2 = Tempstr2 + Mid(tempstr , 4 , 3) + "," Tempstr2 = Tempstr2 + Mid(tempstr , 7 , 3) + "." Tempstr2 = Tempstr2 + Mid(tempstr , 10 , 1) Tempstr3 = "" Temp2 = 0 ' ' Digitend: If Dispsel = 0 Then 'If 全桁表示か? Then Tempstr = Tempstr2 + Tempstr3 Else '小数点以下3桁表示。 Tempstr = "" While Temp2 <> 0 '先頭にスペースを入れる。 Tempstr = Tempstr + " " Temp2 = Temp2 - 1 Wend Tempstr = Tempstr + Tempstr2 End If ' Tempstr = Tempstr + " Hz" Locate 1 , 1 'LCDに周波数を表示する。 Lcd Tempstr Print #1 , Tempstr ; 'UART用に周波数を出力する。 ' ' * 周期の表示 * ' Tempd2 = Tempd1 * 78.125 '周期を計算する。 ' Gosub Strconv '指数表示を単純な文字列に変換する。 Tempstr2 = Left(tempstr , Temp1) Temp1 = Len(tempstr2) '周期値の桁数を調べる。 Select Case Temp1 '周期値により表示桁を整える。 Case 10 : Tempstr3 = Left(tempstr2 , 8) Tempstr = Format(tempstr3 , " . ") + " S " '1S以上。 Case 9 : Tempstr3 = Left(tempstr2 , 8) '100〜999mS。 Tempstr = Format(tempstr3 , " . ") + " mS" Case Is >= 7 : Tempstr = Format(tempstr2 , " . ") + " mS" '1〜99mS。 Case Is >= 4: Tempstr = " " + Format(tempstr2 , " . ") + " uS" '1〜999uS。 Case Else : Tempstr = " " + Format(tempstr2 , " ") + " nS" '1〜999nS。 End Select ' Locate 2 , 5 'LCDに周期を表示する。 Lcd Tempstr Frqstrc9: Print #1 , " " ; Meatchr ; Prscchr ; " " ; Tempstr 'UART用に周期を出力する。 Return ' ' ************************************************ (指数入力 = Tempd2) ' * 指数表示を単純な文字列に変換するサブルーチン * (Tempstr = 文字列) ' ************************************************ (Temp1 = 整数部の桁数) ' Strconv: Tempstr = Str(tempd2) '周波数を文字列に変換する。 Temp1 = Len(tempstr) '文字数を調べる。 Temp2 = Charpos(tempstr , "E") '"E"指数表記を調べる。 If Temp2 = 0 Then Goto Strconv1 'If "E"無しの表記か? Then Temp2 = Temp2 + 1 Tempstr2 = Mid(tempstr , Temp2 , 1) '"E"の次の文字を取得する。 If Tempstr2 = "-" Then Goto Strconv2 'If [E-] 0以下か? Then ' Temp2 = Val(tempstr2) '指数部を数値に変換する。 Temp3 = Charpos(tempstr , ".") '小数点の位置を調べる。 If Temp3 = 0 Then 'If 小数点が無いか? Then Temp1 = Temp1 - 2 '"Ex" 指数部の文字数の文字数を減算する。 Tempstr2 = Left(tempstr , Temp1) '整数部を取り出す。 Tempstr3 = "" Temp3 = Temp1 Else '小数点が有る場合。 Temp1 = Temp1 - 3 '"Ex" 指数部の文字数と小数点の文字数を減算する。 Temp3 = Temp3 - 1 '整数部の桁数。 Tempstr2 = Left(tempstr , Temp3) '整数部(小数点の左側)を取り出す。 Temp1 = Temp1 - Temp3 '小数部(小数点の右側)の桁数を算出する。 Temp4 = Temp3 + 2 '小数部の先頭位置。 Tempstr3 = Mid(tempstr , Temp4 , Temp1) '小数部(小数点の右側)を取り出す。 End If Tempstr = Tempstr2 + Tempstr3 '数値を合体する。 Temp1 = Temp2 + Temp3 '整数部の桁数を計算する。 Strconv9: Tempstr = Tempstr + "000000000000" '下位を[0]で満たす。 Return ' ' Strconv1: '"E"無しの表記の場合。 Temp3 = Charpos(tempstr , ".") '小数点の位置を調べる。 If Temp3 = 0 Then 'If 小数点が無いか? Then Tempstr = Tempstr + "." Else '小数点が有る場合。 Temp1 = Temp3 - 1 End If Goto Strconv9 ' ' Strconv2: '0以下の場合。 Temp3 = Charpos(tempstr , ".") '小数点の位置を調べる。 If Temp3 = 0 Then 'If 小数点が無いか? Then Temp1 = Temp1 - 3 '"Ex" 指数部の文字数の文字数を減算する。 Tempstr2 = Left(tempstr , Temp1) '整数部を取り出す。 Tempstr3 = "" Else Temp1 = Temp1 - 4 '"Ex" 指数部の文字数と小数点の文字数を減算する。 Temp3 = Charpos(tempstr , ".") '小数点の位置を調べる。 Temp3 = Temp3 - 1 Tempstr2 = Left(tempstr , Temp3) '整数部(小数点の左側)を取り出す。 Temp1 = Temp1 - Temp3 '小数部(小数点の右側)の桁数を算出する。 Temp4 = Temp3 + 2 '小数部の先頭位置。 Tempstr3 = Mid(tempstr , Temp4 , Temp1) '小数部(小数点の右側)を取り出す。 End If Tempstr = "0." + Tempstr2 '小数点表記を付ける。 Tempstr2 = Tempstr + Tempstr3 '数値を合体する。 Tempstr = Tempstr2 + "000000000000" '下位を[0]で満たす。 Temp1 = 0 Return ' ' * [0Hz]を表示するサブルーチン * ' Disp0hz: Locate 1 , 1 Lcd Spc(12) ; "0 Hz" Locate 2 , 5 Lcd Spc(12) ' Print #1 , " 0 Hz"; Tempstr = " " Goto Frqstrc9 ' ' ********************************************************** ' * キャプチャー・バッファーの値を差分計算するサブルーチン * 差分カウント値 => Frqdat(ロング型) ' ********************************************************** ' Capsubt: $asm LDS R24,{Capendf} 'キャプチャー・バッファーの使用状況を調べる。 SBRC R24,0 'バッファー1が測定終了データか? Then RJMP Capsubt1 ; LDS R16,{capdat1} '32bit引き算(バッファー2)−(バッファー1)。 LDS R17,{capdat1+1} LDS R18,{capovf1} LDS R19,{capovf1+1} LDS R20,{capdat2} LDS R21,{capdat2+1} LDS R22,{capovf2} LDS R23,{capovf2+1} RJMP Capsubt2 ; Capsubt1: LDS R16,{capdat2} '32bit引き算(バッファー1)−(バッファー2)。 LDS R17,{capdat2+1} LDS R18,{capovf2} LDS R19,{capovf2+1} LDS R20,{capdat1} LDS R21,{capdat1+1} LDS R22,{capovf1} LDS R23,{capovf1+1} ; Capsubt2: Sub R20 , R16 '32bit引き算。 SBC R21,R17 SBC R22,R18 SBC R23,R19 STS {Frqdat},R20 '計算結果をロング型変数に格納。 STS {Frqdat+1},R21 STS {Frqdat+2},R22 STS {Frqdat+3},R23 $end Asm Return ' ' ******************************************** ' * Timer1 キャプチャー 割り込み処理ルーチン * ' ******************************************** ' Tintcap: $asm PUSH R1 IN R1,SREG 'ステータス・レジスタを待避。 PUSH R22 PUSH R23 'R23は、拡張I/Oレジスタへのアクセスに使用する。 PUSH R24 PUSH R25 ; LDS R22,{Capendf} 'メインルーチンの処理状態をチェック。 CPI R22,0 BREQ Tintcap1 'If メインルーチンでキャプチャー・データの処理が終了しているか? Else JMP Tintcap8 ; Tintcap1: IN R24,ICR1L 'キャプチャー・レジスターの下位バイトを取得。 IN R23,ICR1H 'キャプチャー・レジスターの上位バイトを取得。 ; LDS R22,{Capmode} 'キャプチャー割り込みのモードを調べる。 SBRC R22,0 'If データ・バッファー2 へ書き込み? Then RJMP Tintcap2 ; ; '---<データ・バッファー1 書き込み処理>--- STS {Capdat1},R24 'データ・バッファー1へ保存。 STS {Capdat1+1},R23 ; LDS R24,{Capovfc} 'オーバーフロー・カウント値を取得。 LDS R25,{Capovfc+1} CPI R23,0 BRNE Tintcap3 'If キャプチャー・データの上位バイトが00? Else ; IN R23,TIFR1 SBRS R23,TOV1 'オーバーフローが発生しているか? Else RJMP Tintcap3 ; ADIW R24,1 'オーバーフロー・カウント値を+1 ; Tintcap3: STS {Capovf1},R24 'データ・バッファー1へ保存。 STS {Capovf1+1},R25 ORI R22,&H01 'モードをデータ・バッファー2 書き込みに変更。 RJMP Tintcap5 ; ; Tintcap2: '---<データ・バッファー2 書き込み処理>--- STS {Capdat2},R24 'データ・バッファー2へ保存。 STS {Capdat2+1},R23 ; LDS R24,{Capovfc} 'オーバーフロー・カウント値を取得。 LDS R25,{Capovfc+1} CPI R23,0 BRNE Tintcap4 'If キャプチャー・データの上位バイトが00? Else ; IN R23,TIFR1 SBRS R23,TOV1 'オーバーフローが発生しているか? Else RJMP Tintcap4 ; ADIW R24,1 'オーバーフロー・カウント値を+1 ; Tintcap4: STS {Capovf2},R24 'データ・バッファー2へ保存。 STS {Capovf2+1},R25 ANDI R22,&HF0 'モードをデータ・バッファー1 書き込みに変更。 ; ; Tintcap5: CPI R22,&H10 BRCC Tintcap6 'If 1と2の両バッファーにデータの準備が完了か? Then ORI R22,&H10 'キャプチャー・モードを2つめのデータ待ちにセット。 RJMP Tintcap7 ; Tintcap6: STS {Capendf},R22 'キャプチャー計測完了フラグをセット。 Tintcap7: STS {Capmode},R22 'キャプチャー・モードを更新。 ; POP R25 POP R24 POP R23 POP R22 Out Sreg , R1 'ステータス・レジスタを復帰 POP R1 $end Asm Return ' ' $asm Tintcap8: 'メインルーチンでキャプチャー・データの処理が終わっていない。 LDI R22,0 'キャプチャー・モードを初期化する。 RJMP Tintcap7 $end Asm ' ' ********************************************** ' * Timer1 オーバーフロー 割り込み処理ルーチン * ' ********************************************** ' Tintovf: $asm PUSH R1 IN R1,SREG 'ステータス・レジスタを待避。 PUSH R24 PUSH R25 ; LDS R24,{Capovfc} 'オーバーフロー・カウント値を+1。 LDS R25,{Capovfc+1} ADIW R24,1 STS {Capovfc},R24 STS {Capovfc+1},R25 ; POP R25 POP R24 Out Sreg , R1 'ステータス・レジスタを復帰 POP R1 $end Asm Return ' ' End