' $prog &HFF , &HE0 , &HDF , &HF9 'CKDIV8 = 1 , SUT = 10 , CKSEL = 0000 ' ' ' *********************************************** ' * * ' * 周波数カウンター・プログラム * ' * * ' * AVR is using ATmega88(P) * ' * Basic Compiler is BASCOM-AVR * ' * Copyright By O-Family 2010.10. 9 * ' *********************************************** ' ' Ver 1.01 初回公開バージョン。 ' Ver 1.21 LCD to LED ボード 対応バージョン。 ' ' Const Prgver = "01.21" 'プログラム・バージョン。 ' ' $regfile = "m88pdef.dat" '使用するAVRを設定。 $crystal = 12800000 'AVRクロックを設定。 ' $hwstack = 64 'ハードウェア・スタックの容量を設定。 $swstack = 8 'ソフトウェア・スタックの容量を設定。 $framesize = 24 'フレーム領域の容量を設定。 ' ' Sw_o1 Alias Portd.2 'スイッチ1のポートピン指定。 Sw_1 Alias Pind.2 Sw_o2 Alias Portd.1 'スイッチ2のポートピン指定。 Sw_2 Alias Pind.1 Sw_o3 Alias Portd.0 'スイッチ3のポートピン指定。 Sw_3 Alias Pind.0 ' Msel_a Alias Portb.1 '計測モード選択Aのポートピン指定。 Msel_b Alias Portd.7 '計測モード選択Bのポートピン指定。 ' Led_g Alias Portc.2 'ゲート・モード表示のLEDポートピン指定。 Led_r Alias Portc.3 'レシプロカル・モード表示のLEDポートピン指定。 Led_h Alias Portc.4 '[Hz]表示のLEDポートピン指定。 Led_s Alias Portc.5 '[Sec]表示のLEDポートピン指定。 ' ' 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 Measure As Byte '計測モード。(0 = ゲート・モード , 1 = レシプロカル・モード) Dim Prescale As Byte 'プリスケラ値。(0=1/1 , 1=1/10 , 2=1/100) Dim Average As Long 'レシプロカル・モード用の平均値。 Dim Avernum As Long 'レシプロカル・モード用の平均数。 Dim Dispsel As Byte '表示器の選択設定。(FF:LCD , 0:LCD to LED) Dim Dispft As Byte 'LCD to LEDモードの表示項目。(0:周波数 , 1:周期) Dim Swoff As Byte 'スイッチのOFFチェック用フラグ。 ' Dim Temp1 As Byte '汎用テンポラリ変数 Byte型 No.1 Dim Templ1 As Long '汎用テンポラリ変数 Long型 No.1 Dim Temps1 As Single '汎用テンポラリ変数 Single型 No.1 Dim Tempstr As String * 20 '汎用テンポラリ変数 String型 ' Dim Eep_dsel As Eram Byte At $10 'EEPROM 表示器の選択設定。(FF:LCD , 0:LCD to LED) ' ' ' ' * 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 = Portc.0 , Rs = Portc.1 Config Lcd = 16 * 2 'LCD表示を16文字2行に設定。 ' Cursor Off 'LCDのカーソルをオフ。 Cls 'LCD表示をすべて消去。 ' ' * ポートの初期設定 * ' Config Msel_a = Output 'モード選択Aポートを出力に設定。 Config Msel_b = Output 'モード選択Bポートを出力に設定。 ' Config Led_g = Output 'ゲート・モード表示のLEDポートを出力に設定。 Config Led_r = Output 'レシプロカル・モード表示のLEDポートを出力に設定。 Config Led_h = Output '[Hz]表示のLEDポートを出力に設定。 Config Led_s = Output '[Sec]表示のLEDポートを出力に設定。 ' Set Sw_o1 'スイッチ1 ポートをプルアップ。 Set Sw_o2 'スイッチ2 ポートをプルアップ。 Set Sw_o3 'スイッチ3 ポートをプルアップ。 Set Portb.7 '未使用ポートをプルアップ。 ' ' * タイマーの設定 * ' 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]端子から1Hzパルスを出力。 Ocr0a = 50 - 1 '100Hz / 50カウント = (2 / 2) = 1Hz ' Config Timer1 = Counter , Edge = Falling , Capture Edge = Falling '[T1]の立ち下がりエッジでカウント。 On Capture1 Tintcap Nosave 'キャプチャー割り込みルーチンのラベルを設定。 Enable Capture1 'キャプチャー割り込みを許可。 On Timer1 Tintovf Nosave 'オーバーフロー割り込みルーチンのラベルを設定。 Enable Timer1 'オーバーフロー割り込みを許可。 ' ' * 表示器の選択設定 * ' If Sw_2 = 0 Then 'If スイッチ2が押されているか? Then Eep_dsel = &HFF 'EEPROMに[LCD Mode]設定を書き込む。 Locate 1 , 1 '設定内容をを表示。 Lcd "Display select" Locate 2 , 4 Lcd "LCD Mode" Bitwait Sw_2 , Set 'スイッチ2が離されるまで待つ。 Waitms 30 'チャタリング・タイマー。 Cls End If ' If Sw_3 = 0 Then 'If スイッチ3が押されているか? Then Eep_dsel = &H00 'EEPROMに[LCD to LED Mode]設定を書き込む。 Locate 1 , 1 '設定内容をを表示。 Lcd "LCD-LED" Bitwait Sw_3 , Set 'スイッチ3が離されるまで待つ。 Waitms 30 'チャタリング・タイマー。 Cls End If Dispsel = Eep_dsel '表示器の選択設定を読み込む。 ' ' * プログラム・バージョンの表示 * ' If Sw_1 = 0 Then 'If スイッチ1が押されているか? Then Locate 1 , 1 'プログラム・バージョンを表示。 If Dispsel = &HFF Then 'If LCDモードか? Then Lcd "FrequencyCounter" Locate 2 , 4 Lcd "Ver. " ; Prgver Else 'LCD to LED モード。 Lcd "V. " ; Prgver End If Bitwait Sw_1 , Set 'スイッチ1が離されるまで待つ。 Waitms 30 'チャタリング・タイマー。 Cls End If ' ' * 変数と表示の初期設定 * ' Measure = 0 'モードの初期値。(0 = ゲート・モード) If Dispsel <> &HFF Then 'If LCD to LEDモードか? Then Dispft = 0 'LCD to LEDモードの初期表示項目。(0:周波数 , 1:周期) Reset Led_s '[Sec]表示のLEDを消灯。 Set Led_h '[Hz]表示のLEDを点灯。 End If Prescale = 0 'プリスケラの初期値。(0 = 1/1) Average = 0 'レシプロカル・モード用の平均値。 Avernum = 0 'レシプロカル・モード用の平均数。 Gosub Prescdss 'プリスケラ値の表示と設定。 Enable Interrupts 'すべての割り込みを許可。 ' ' ******************* ' * メイン ルーチン * ' ******************* ' Main: Gosub Switchin 'スイッチの入力処理。 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 Measure = 0 Then 'If 計測モードがゲート・モード? Then Measure = 1 'レシプロカル・モードに設定。 If Dispsel = &HFF Then 'If LCDモードか? Then Locate 1 , 1 Lcd "Rcp" Locate 2 , 1 Lcd Spc(4) Else 'LCD to LED モード。 Reset Led_g 'ゲート・モード表示のLEDを消灯。 Set Led_r 'レシプロカル・モード表示のLEDを点灯。 End If Set Msel_a 'モードセレクターを設定。 Set Msel_b Prescale = 0 Config Timer1 = Timer , Prescale = 1 , Capture Edge = Falling 'AVR動作クロックによりカウント。 Else Measure = 0 'ゲート・モードに設定。 Gosub Prescdss Config Timer1 = Counter , Edge = Falling , Capture Edge = Falling '[T1]の立ち下がりエッジでカウント。 End If ' Switchin9: Swoff = 1 'スイッチOFFチェックフラグを立てる。 Waitms 30 'チャタリング・タイマー。 Return ' ' Switchin2: 'スイッチ2 (プリスケラの選択) If Measure <> 0 Then Goto Switchin9 'If ゲート・モード? Else Prescale = Prescale + 1 Gosub Prescdss 'プリスケラ値の表示と設定。 Goto Switchin9 ' ' Switchin3: 'スイッチ3 (LCDtoLEDモードの周波数と周期の表示選択) If Dispsel = &HFF Then Goto Switchin9 'If LCDモードか? Then ' Toggle Dispft.0 'LCD to LEDモードの表示項目を切り換える。 If Dispft = 0 Then 'If 周波数表示か? Then Reset Led_s '[Sec]表示のLEDを消灯。 Set Led_h '[Hz]表示のLEDを点灯。 Else Reset Led_h '[Hz]表示のLEDを消灯。 Set Led_s '[Sec]表示のLEDを点灯。 End If 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 ' ' * プリスケラ値の表示と設定サブルーチン * ' Prescdss: Select Case Prescale Case 1 : 'プリスケラ 1/10。 Tempstr = "P10" Set Msel_a 'モードセレクターを設定。 Reset Msel_b Case 2 : 'プリスケラ 1/100。 Tempstr = "100" Reset Msel_a 'モードセレクターを設定。 Set Msel_b Case Else : 'プリスケラ 1/1。 Tempstr = "P1 " Reset Msel_a 'モードセレクターを設定。 Reset Msel_b Prescale = 0 End Select ' If Dispsel = &HFF Then 'If LCDモードか? Then Locate 1 , 1 Lcd "Gat" Locate 2 , 1 Lcd Tempstr Else 'LCD to LED モード。 Reset Led_r 'レシプロカル・モード表示のLEDを消灯。 Set Led_g 'ゲート・モード表示のLEDを点灯。 End If Return ' ' ************************************ ' * カウント値の計算処理サブルーチン * ' ************************************ ' Frqcal: If Capendf = 0 Then Return 'If キャプチャー計測が完了したか? Else ' Gosub Capsubt 'キャプチャー・バッファーの値を差分計算する。=> (Frqdat) If Dispsel <> &HFF Then Goto Leddisp 'If LCD to LEDモードか? Then ' If Measure = 1 Then Goto Frqcal2 'If レシプロカル・モードか? Then ' ' ****************** ' * ゲート・モード * ' ****************** ' Tempstr = Str(frqdat) '計測値を文字列に変換。 Templ1 = 1000000000 '周期測定用の被除数。(1/1 用) Select Case Prescale 'プリスケラにより、無効桁のマーク(x)を追加。 Case 1 : Tempstr = Tempstr + "x" '1/10 モード。 Templ1 = 100000000 '周期測定用の被除数。(1/10 用) Case 2 : Tempstr = Tempstr + "xx" '1/100 モード。 Templ1 = 10000000 '周期測定用の被除数。(1/100 用) End Select ' ' * LCDへ周波数を表示 * ' Temp1 = Len(tempstr) '計測値の桁数を調べる。 Locate 1 , 5 Select Case Temp1 '周波数により表示桁を整える。 Case 8 : Lcd Format(tempstr , " . ") ; "MHz"; '10MHz以上。 Case 7 : Lcd Format(tempstr , " . ") ; " MHz"; '1〜9MHz。 Case Is > 3: Lcd Spc(1) ; Format(tempstr , " . ") ; " KHz"; '1〜999KHz。 Case Else : Lcd Spc(5) ; Format(tempstr , " ") ; " Hz "; '1〜999Hz。 End Select ' ' * LCDへ周期を表示 * ' Templ1 = Templ1 / Frqdat '計測値を周期に変換。 Locate 2 , 5 Gosub Timdss '1ns〜2Secまでの周期を表示する。 ' Capendf = 0 'キャプチャー計測完了フラグをクリア。 Return ' ' ************************ ' * レシプロカル・モード * ' ************************ ' Frqcal2: Locate 1 , 5 If Frqdat < 64 Then Goto Frqcal21 'If 200KHzを超えたか? Then If Frqdat < 12800000 Then Goto Frqcal22 'If 1Hz以上か? Then ' ' * LCDへ周波数を表示 * ' Frqcal24: Temps1 = 12800000 / Frqdat '計測値を周波数に変換。 Frqcal25: Select Case Temps1 '周波数により表示桁を整える。 Case Is >= 100000 : Lcd Fusing(temps1 , "#.##") ; '100000〜999999Hz。 Case Is >= 10000 : Lcd Fusing(temps1 , "#.###") ; '10000〜99999Hz。 Case Is >= 1000 : Lcd Fusing(temps1 , "#.####") ; '1000〜9999Hz。 Case Is >= 100 : Lcd Fusing(temps1 , "#.#####") ; '100〜999Hz。 Case Is >= 10 : Lcd Fusing(temps1 , "#.######") ; '10〜99Hz。 Case Else : Lcd Fusing(temps1 , "#.#######") ; '0〜9Hz。 End Select Lcd " Hz" ' ' * LCDへ周期を表示 * ' Locate 2 , 5 If Frqdat < 25600000 Then 'If 周期が2秒未満か? Then (Long変数がオーバーフローするため) Temps1 = 78.125 * Frqdat '計測値を周期に変換。 Templ1 = Int(temps1) '整数化。 Gosub Timdss '1ns〜2Secまでの周期を表示する。 Else Temps1 = 0.78125 * Frqdat '計測値を周期に変換。 Templ1 = Int(temps1) '整数化。 Tempstr = Str(templ1) '周期値を文字列に変換。 If Templ1 < 100000000 Then Lcd Format(tempstr , " . ") ; " S "; '2S〜9S。 Else Tempstr = Left(tempstr , 8) Lcd Format(tempstr , " . ") ; " S "; '10S〜99S。 End If End If ' Frqcal26: Capendf = 0 'キャプチャー計測完了フラグをクリア。 Return ' ' Frqcal21: '200KHzを超えたオーバー表示。 Lcd "--- Over ---" Locate 2 , 5 Lcd Spc(12) Goto Frqcal26 ' Frqcal22: '1Hz以上の場合、0.5秒間隔で平均処理し表示を更新。 If Tifr0.ocf0a = 1 Then Goto Frqcal23 'If 0.5秒経過したか? Then Average = Average + Frqdat '平均値に加算。 Avernum = Avernum + 1 '平均数を加算。 Goto Frqcal26 ' Frqcal23: Set Tifr0.ocf0a 'タイマー0比較A割り込み要求フラグをリセット。 If Avernum = 0 Then Goto Frqcal24 'If 平均化処理が済んでいないか? Then Temps1 = Average / Avernum '平均値を算出。 Temps1 = 12800000 / Temps1 '計測値を周波数に変換。 Average = 0 Avernum = 0 Goto Frqcal25 ' ' ********************************************* ' * 1ns〜2Secまでの周期を表示するサブルーチン * ' ********************************************* ' Timdss: Tempstr = Str(templ1) '周期値を文字列に変換。 Temp1 = Len(tempstr) '周期値の桁数を調べる。 Select Case Temp1 '周期値により表示桁を整える。 Case 10 : Tempstr = Left(tempstr , 8) Lcd Format(tempstr , " . ") ; " S "; '1S以上。 Case 9 : Tempstr = Left(tempstr , 8) '100〜999mS。 Lcd Format(tempstr , " . ") ; " mS"; Case Is >= 7 : Lcd Format(tempstr , " . ") ; " mS"; '1〜99mS。 Case Is >= 4: Lcd Spc(2) ; Format(tempstr , " . ") ; " uS"; '1〜999uS。 Case Else : Lcd Spc(6) ; Format(tempstr , " ") ; " nS"; '1〜999nS。 End Select Return ' ' ************************* ' * LCD to LED の表示処理 * ' ************************* ' Leddisp: Locate 1 , 1 If Measure = 1 Then Goto Leddisp2 'If レシプロカル・モードか? Then ' ' * ゲート・モード * ' Tempstr = Str(frqdat) '計測値を文字列に変換。 Templ1 = 1000000000 '周期測定用の被除数。(1/1 用) Select Case Prescale 'プリスケラにより、無効桁のマーク(o)を追加。 Case 1 : Tempstr = Tempstr + "o" '1/10 モード。 Templ1 = 100000000 '周期測定用の被除数。(1/10 用) Case 2 : Tempstr = Tempstr + "oo" '1/100 モード。 Templ1 = 10000000 '周期測定用の被除数。(1/100 用) End Select ' If Dispft <> 0 Then Goto Leddisp1 'If 表示項目が周期か? Then ' ' * ゲート・モード 周波数表示 * ' Temp1 = Len(tempstr) '計測値の桁数を調べる。 Select Case Temp1 '周波数により表示桁を整える。 Case 8 : '10.000.000〜99.999.999 Lcd Left(tempstr , 2) ; "."; Lcd Mid(tempstr , 3 , 3) ; "." ; Right(tempstr , 3) Case 7 : '1.000.000〜9.999.999 Lcd " " ; Left(tempstr , 1) ; "."; Lcd Mid(tempstr , 2 , 3) ; "." ; Right(tempstr , 3) Case Is > 3: Lcd Spc(2) ; Format(tempstr , " . ") '1.000〜999.999 Case Else : Lcd Spc(5) ; Format(tempstr , " ") '1〜999 End Select ' Leddisp9: Capendf = 0 'キャプチャー計測完了フラグをクリア。 Return ' ' * ゲート・モード 周期表示 * ' Leddisp1: Templ1 = Templ1 / Frqdat '計測値を周期に変換。 Gosub Ledtimdss '1ns〜2Secまでの周期を表示する。 Goto Leddisp9 ' ' * レシプロカル・モード * ' Leddisp2: If Frqdat < 64 Then Goto Leddisp21 'If 200KHzを超えたか? Then If Frqdat < 12800000 Then Goto Leddisp22 'If 1Hz以上か? Then ' If Dispft <> 0 Then Goto Leddisp26 'If 表示項目が周期か? Then ' ' * レシプロカル・モード 周波数表示 * ' Leddisp24: Temps1 = 12800000 / Frqdat '計測値を周波数に変換。 Leddisp25: Select Case Temps1 '周波数により表示桁を整える。 Case Is >= 100000 : Lcd Fusing(temps1 , "#.##") ; '100000〜999999Hz。 Case Is >= 10000 : Lcd Fusing(temps1 , "#.###") ; '10000〜99999Hz。 Case Is >= 1000 : Lcd Fusing(temps1 , "#.####") ; '1000〜9999Hz。 Case Is >= 100 : Lcd Fusing(temps1 , "#.#####") ; '100〜999Hz。 Case Is >= 10 : Lcd Fusing(temps1 , "#.######") ; '10〜99Hz。 Case Else : Lcd Fusing(temps1 , "#.#######") ; '0〜9Hz。 End Select ' Leddisp29: Capendf = 0 'キャプチャー計測完了フラグをクリア。 Return ' ' * レシプロカル・モード 周期表示 * ' Leddisp26: If Frqdat < 25600000 Then 'If 周期が2秒未満か? Then (Long変数がオーバーフローするため) Temps1 = 78.125 * Frqdat '計測値を周期に変換。 Templ1 = Int(temps1) '整数化。 Gosub Ledtimdss '1ns〜2Secまでの周期を表示する。 Else Temps1 = 0.78125 * Frqdat '計測値を周期に変換。 Templ1 = Int(temps1) '整数化。 Tempstr = Str(templ1) '周期値を文字列に変換。 If Templ1 < 100000000 Then Lcd Format(tempstr , " . ") '2S〜9S。 Else Tempstr = Left(tempstr , 8) Lcd Format(tempstr , " . ") '10S〜99S。 End If End If Goto Leddisp29 ' ' Leddisp21: '200KHzを超えたオーバー表示。 Lcd "--Over--" Goto Leddisp29 ' Leddisp22: '1Hz以上の場合、0.5秒間隔で平均処理し表示を更新。 If Tifr0.ocf0a = 1 Then Goto Leddisp23 'If 0.5秒経過したか? Then Average = Average + Frqdat '平均値に加算。 Avernum = Avernum + 1 '平均数を加算。 Goto Leddisp29 ' Leddisp23: Set Tifr0.ocf0a 'タイマー0比較A割り込み要求フラグをリセット。 If Dispft <> 0 Then Goto Leddisp26 'If 表示項目が周期か? Then If Avernum = 0 Then Goto Leddisp24 'If 平均化処理が済んでいないか? Then Temps1 = Average / Avernum '平均値を算出。 Temps1 = 12800000 / Temps1 '計測値を周波数に変換。 Average = 0 Avernum = 0 Goto Leddisp25 ' ' ********************************************* ' * 1ns〜2Secまでの周期を表示するサブルーチン * ' * (LCD to LED 用) * ' ********************************************* ' Ledtimdss: Tempstr = Str(templ1) '周期値を文字列に変換。 Temp1 = Len(tempstr) '周期値の桁数を調べる。 Select Case Temp1 '周期値により表示桁を整える。 Case 10 : Tempstr = Left(tempstr , 8) Lcd Format(tempstr , " . ") '1S以上。 Case 9 : Tempstr = Left(tempstr , 7) '100〜999mS。 Lcd Format(tempstr , " . ") ; "m" Case 8 : Tempstr = Left(tempstr , 7) '10〜99mS。 Lcd Format(tempstr , " . ") ; "m" Case 7 : Tempstr = Left(tempstr , 7) '1〜9mS。 Lcd Format(tempstr , " . ") ; "m" Case Is >= 4: Lcd Spc(1) ; Format(tempstr , " . ") ; "u"; '1〜999uS。 Case Else : Lcd Spc(4) ; Format(tempstr , " ") ; "n" '1〜999nS。 End Select Return ' ' ********************************************************** ' * キャプチャー・バッファーの値を差分計算するサブルーチン * 差分カウント値 => 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