' ' ***************************************************** ' * * ' * N-Gauge Train Operation Program (PS Controller) * ' * * ' * AVR Used is ATmega164P * ' * Basic Compiler is BASCOM-AVR * ' * Copyright By O-Family 2008. 3.26 * ' ***************************************************** ' ' Ver 01.01 初回公開バージョン ' ' $regfile = "m164Pdef.dat" $crystal = 8000000 ' Psdo Alias Portd.0 'PSコントローラ [PSDO] 接続ポート Pscs Alias Portd.1 'PSコントローラ [PSCS] 接続ポート Psclk Alias Portd.2 'PSコントローラ [PSCLK] 接続ポート Psack Alias Pind.3 'PSコントローラ [PSACK] 接続ポート Psacks Alias Portd.3 Psdi Alias Pind.4 'PSコントローラ [PSDI] 接続ポート Psdis Alias Portd.4 ' Ifrintf Alias Eifr.intf1 '[PSACK] 外部割り込みフラグ名 [GIFR or EIFR] ' ' Dim Psrxdt1 As Byte 'PSコントローラーからの受信データ 1Byte目 Dim Psrxdt2 As Byte 'PSコントローラーからの受信データ 2Byte目 Dim Psackf As Byte 'PSコントローラーからのACKフラグ Dim Psercu As Byte 'PSコントローラーとの通信エラーカウンター Dim Psconf As Byte 'PSコントローラーの接続状態フラグ ' Dim Ad0spd As Byte '速度ボリュームのA/D変換値 Dim Ad1lit As Byte '照明ボリュームのA/D変換値 Dim Ad2acl As Byte '加速係数ボリュームのA/D変換値 Dim Daomot As Byte 'D/Aコンバータ用 モーターパルス 出力データ Dim Daolit As Byte 'D/Aコンバータ用 照明パルス 出力データ Dim Daompl As Byte 'D/Aコンバータ用 モーター+照明パルス 出力データ Dim Motpff As Byte 'モーター・パルス出力 10mS F/F Dim T20msf As Byte '20mS 経過フラグ Dim Cntmodf As Byte 'コントロール・モード (0=VR Mode : 1=PS Mode) Dim Psmascn As Byte 'PSコントローラ マスコン値 Dim Psbrake As Byte 'PSコントローラ ブレーキ値 Dim Motspd As Byte 'モーターのスピード値 Dim Motacl As Byte 'モーター加速カウンタ Dim Motslo As Byte 'モーター減速カウンタ Dim Motmof As Byte 'モーター慣性走行カウンタ Dim Lcddsc As Byte 'LCD 時分割表示 カウンタ ' 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 Tempw1 As Word '汎用テンポラリ変数 Word型 No.1 Dim Tempstr As String * 5 '汎用テンポラリ変数 String型 Dim Strlcd As String * 16 'LCD 2行目用 文字バッファ ' Config Psdo = Output 'PSコントローラ接続ポートのデータ方向を設定 Config Pscs = Output Config Psclk = Output Config Psack = Input Config Psdi = Input Set Psacks 'PSコントローラ [PSACK] 接続ポートをプルアップ Set Psdis 'PSコントローラ [PSDI] 接続ポートをプルアップ Config Portd.5 = Output '外部制御ポートを出力に設定 Config Portd.6 = Output Config Portd.7 = Output Set Portd.5 '外部制御端子を[H]にセット Set Portd.6 Set Portd.7 ' Config Porta = &B00011111 'A/Dポートを入力に、外部制御ポートを出力に設定 Porta = &B00011111 '外部制御端子を[H]にセット Config Portc = Output 'D/Aポートを出力に設定 Set Portb.0 'PORTB Bit0 をプルアップ Set Portb.1 'PORTB Bit1 をプルアップ ' Config Lcdmode = Port Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 'LCDのポート割り当て Config Lcdpin = Pin , Db6 = Portb.6 , Db7 = Portb.7 Config Lcdpin = Pin , E = Portb.3 , Rs = Portb.2 Config Lcd = 16 * 2 'LCD表示を16文字2行に設定 ' Deflcdchar 0 , 32 , 32 , 32 , 32 , 32 , 32 , 32 , 31 'レベル表示用 カスタム文字をLCDへ書き込み Deflcdchar 1 , 32 , 32 , 32 , 32 , 32 , 32 , 31 , 31 Deflcdchar 2 , 32 , 32 , 32 , 32 , 32 , 31 , 31 , 31 Deflcdchar 3 , 32 , 32 , 32 , 32 , 31 , 31 , 31 , 31 Deflcdchar 4 , 32 , 32 , 32 , 31 , 31 , 31 , 31 , 31 Deflcdchar 5 , 32 , 32 , 31 , 31 , 31 , 31 , 31 , 31 Deflcdchar 6 , 32 , 31 , 31 , 31 , 31 , 31 , 31 , 31 Deflcdchar 7 , 31 , 31 , 31 , 31 , 31 , 31 , 31 , 31 Cls 'LCD表示をすべて消去 Cursor Off 'LCDのカーソルを設定 ' Config Adc = Single , Prescaler = Auto 'A/Dコンバータの設定。 Start Adc 'A/Dコンバータに電源を供給。 ' Config Timer2 = Timer , Prescale = 1024 , Clear Timer = 1 'Timer2を設定(モーターパルス発生 タイマー 10mS) Tccr2a = &H02 '***** BASCOM-AVR Bug! ***** Tccr2b = &H07 '***** BASCOM-AVR Bug! ***** Ocr2a = 77 ' Config Timer1 = Timer , Prescale = 1 , Clear Timer = 1 'Timer1を設定 Compare1a = 399 'D/A用 タイマー 20KHz,50uS On Compare1a Tm1aint Nosave 'Timer1A の割り込みルーチンを設定 Enable Compare1a 'TIMER1A 比較一致割り込みを許可。 ' Compare1b = 329 '照明のパルス幅を 8.75uS に設定 On Compare1b Tm1bint Nosave 'Timer1B の割り込みルーチンを設定 Enable Compare1b 'TIMER1B 比較一致割り込みを許可。 ' Config Int1 = Rising '外部割り込みピン INT1を立ち上りエッジにセット ' Set Pscs 'PSコントローラ [PSCS] = H Set Psclk 'PSコントローラ [PSCLK] = H ' ' ******************************** ' * 電源ONで急発進を防止する処理 * ' ******************************** ' Initial: Gosub Vradcnv1 '速度ボリューム値をA/D変換 If Ad0spd < 4 Then Goto Initial1 'If ボリューム位置=0? Then Locate 1 , 1 '速度ボリュームを0にするメッセージ Lcd "ソクド ボリューム ヲ" Locate 2 , 2 Lcd "0 ニ シテクダサイ" Goto Initial ' Initial1: Gosub Psdatrd 'PSコントローラ データ受信 If Psackf = 0 Then Goto Initial2 'If PSコントローラ未接続? Then Temp1 = Psrxdt2 And &H0F If Temp1 = &H0F Then Goto Initial2 'If 非常ブレーキ位置? Then Locate 1 , 1 '非常ブレーキにするメッセージ Lcd "ブレーキ ヲ" ; Spc(9) Locate 2 , 2 Lcd "ヒジョウ ニ シテクダサイ " Goto Initial1 ' ' Initial2: Cls Locate 1 , 1 'LCD表示の初期設定 Lcd "Lt Ac Spd:" ' Enable Interrupts 'すべての割り込みを許可 ' ' ******************* ' * メイン ルーチン * ' ******************* ' Main: Gosub Vradcnv 'ボリューム A/D変換 Gosub Modcnt 'モード別 制御 Gosub Pros20ms '20mS毎の処理 Goto Main ' End ' ' **************** ' * 20mS毎の処理 * ' **************** ' Pros20ms: If T20msf = 0 Then Goto Pros20m1 'If 20mS経過? Else T20msf = 0 '20mS経過フラグをリセット ' Gosub Psdatrd 'PSコントローラ データ受信 ' Motacl = Motacl + 1 'モーター加速カウンタ+1 Motslo = Motslo + 1 'モーター減速カウンタ+1 Motmof = Motmof + 1 'モーター慣性運転カウンタ+1 ' ' Lcddsc = Lcddsc + 1 'LCDを時分割表示 If Lcddsc < 5 Then Goto Pros20m2 'If スピード表示時間? Else Lcddsc = 0 ' Tempstr = Str(motspd) 'スピード値をLCDに表示 Locate 1 , 14 Lcd Format(tempstr , " ") ' Temp1 = Ad1lit Shift Temp1 , Right , 4 '照明ボリュームを1/16する (0-7) Locate 1 , 3 Lcd Chr(temp1) '照明ボリューム値をバーグラフ表示 ' Temp1 = Ad2acl Shift Temp1 , Right , 5 '加速係数ボリューム値を1/32する (0-7) Locate 1 , 7 Lcd Chr(temp1) '加速係数ボリューム値をバーグラフ表示 Goto Pros20m1 ' Pros20m2: 'LCD 2行目の文字を4文字ずつ時分割表示 Temp1 = Lcddsc * 4 Temp1 = Temp1 - 3 Tempstr = Mid(strlcd , Temp1 , 4) Locate 2 , Temp1 Lcd Tempstr ' Pros20m1: Return ' ' ****************************** ' * ボリューム A/D変換ルーチン * ' ****************************** ' Vradcnv: Tempw1 = Getadc(6 , &H20) '照明ボリューム値をA/D変換 Temp1 = High(tempw1) Shift Temp1 , Right , 1 '変換値を1/2する (0-127) Ad1lit = Temp1 ' Tempw1 = Getadc(7 , &H20) '加速係数ボリューム値をA/D変換 Temp1 = High(tempw1) Ad2acl = Temp1 ' Vradcnv1: Tempw1 = Getadc(5 , &H20) '速度ボリューム値をA/D変換 Temp1 = High(tempw1) Shift Temp1 , Right , 1 '変換値を1/2する (0-127) Ad0spd = Temp1 Return ' ' ************************************* ' * PSコントローラ データ受信ルーチン * ' ************************************* ' Psdatrd: Reset Pscs 'PSコントローラ [PSCS] = L Temp1 = &H01 Gosub Psdatout 'PSコントローラへコマンドを送受信 Gosub Psackchk 'PSコントローラからのACKを確認 If Psackf = 0 Then Goto Psdatrd1 'If ACKが帰らない? Then ' Temp1 = &H42 Gosub Psdatout 'PSコントローラへコマンドを送受信 Gosub Psackchk 'PSコントローラからのACKを確認 If Psackf = 0 Then Goto Psdatrd1 'If ACKが帰らない? Then ' Temp1 = &H00 Gosub Psdatout 'PSコントローラへコマンドを送受信 Gosub Psackchk 'PSコントローラからのACKを確認 If Psackf = 0 Then Goto Psdatrd1 'If ACKが帰らない? Then ' Temp1 = &H00 Gosub Psdatout 'PSコントローラへコマンドを送受信 Temp4 = Temp2 '1Byte目のデータを保存 Gosub Psackchk 'PSコントローラからのACKを確認 If Psackf = 0 Then Goto Psdatrd1 'If ACKが帰らない? Then ' Temp1 = &H00 Gosub Psdatout 'PSコントローラへコマンドを送受信 Psrxdt2 = Temp2 '2Byte目のデータを保存 Psrxdt1 = Temp4 '1Byte目のデータを保存 Psercu = 0 '通信エラーカウンターをクリア Psconf = 1 'PSコントローラーの接続状態フラグをセット ' Psdatrd2: Set Pscs 'PSコントローラ [PSCS] = H Return ' ' Psdatrd1: 'ACKが帰らない場合の処理 If Psconf = 0 Then Goto Psdatrd2 'If PSコントローラ未接続? Then Psercu = Psercu + 1 If Psercu = 5 Then Psconf = 0 'If エラーが5回続いた? Then Goto Psdatrd2 ' ' ********************************************** ' * PSコントローラ コマンド送受信 サブルーチン * (Temp1 = 送信データ) ' ********************************************** (Temp2 = 受信データ) ' Psdatout: Waitus 40 Set Ifrintf '外部割り込み要求フラグをリセット Temp2 = 0 For Temp3 = 1 To 8 '8Bitのデータを送受信 If Temp1.0 = 0 Then 'データを送信 Reset Psdo 'PSコントローラ [PSDO] = L Else Set Psdo 'PSコントローラ [PSDO] = H End If Reset Psclk 'PSコントローラ [PSCLK] = L Waitus 10 Set Psclk 'PSコントローラ [PSCLK] = H Shift Temp1 , Right , 1 Shift Temp2 , Right , 1 If Psdi = 0 Then Set Temp2.7 'データを受信 Next Return ' ' *************************************** ' * PSコントローラ ACK受信 サブルーチン * (Psackf = 0:ACK無し 1:ACK有り) ' *************************************** ' Psackchk: Temp3 = 0 Psackchk1: If Ifrintf = 1 Then Goto Psackchk2 'If ACKが帰ってきたか? Then Waitus 10 Temp3 = Temp3 + 1 If Temp3 <> 10 Then Goto Psackchk1 'If 100uS タイムアウト? Else Psackf = 0 Return ' Psackchk2: Psackf = 1 Return ' ' ************************* ' * モード別 制御ルーチン * ' ************************* ' Modcnt: If Psconf = 0 Then Goto Modcnt01 'If PSコントローラ未接続? Then ' Temp1 = Psrxdt2 And &H0F 'ブレーキ・ハンドルの状態をTemp1へ入れておく If Cntmodf = 0 Then Goto Modcnt02 'If ボリューム モード? Then ' 'PSモード If Temp1 = &H0F Then Goto Modcnt03 'If 非常ブレーキ位置? Then If Ad0spd > 3 Then Goto Modcnt04 'If PSモード中に速度ボリュームを上げた? Then Goto Psmode ' ' Modcnt01: 'PSコントローラ未接続 Cntmodf = 0 'モードフラグをボリューム・モードに設定 Goto Vrmode ' Modcnt02: 'ボリューム モード If Ad0spd > 3 Then Goto Modcnt05 'If 速度ボリュームが上がっている? Then If Temp1 = &H0F Then Goto Modcnt01 'If 非常ブレーキ位置? Then Cntmodf = 1 'モードフラグをPSモードに設定 Goto Psmode ' Modcnt05: If Temp1 = &H0F Then Goto Modcnt01 'If ボリューム・モード中に非常ブレーキを解除していない? Then Strlcd = "ブレーキ ヲ ヒジョウ ニ!" '非常ブレーキ位置にするメッセージを表示 Return ' Modcnt03: If Ad0spd > 3 Then Goto Modcnt01 'If 速度ボリュームが上がっている? Then Goto Psmode ' Modcnt04: Strlcd = "ソクドボリューム ヲ 0ニ!" '速度ボリュームを0にするメッセージを表示 Return ' ' ' * PSコントローラ モード * ' ' Psmode: If Temp1 = &H04 Then Goto Psmode02 'If ブレーキ解除? Then ' Select Case Temp1 'ブレーキを掛けている Case &H01 : Psbrake = 1 'PSの受信コードをブレーキ値に変換 Case &H05 : Psbrake = 2 Case &H08 : Psbrake = 3 Case &H0C : Psbrake = 4 Case &H09 : Psbrake = 5 Case &H0D : Psbrake = 6 Case &H02 : Psbrake = 7 Case &H06 : Psbrake = 8 Case &H0F : Psbrake = 9 End Select Psmascn = 0 'PSのマスコン値を0にセット Goto Psmode01 ' Psmode02: 'ブレーキを解除している Psbrake = 0 'PSのブレーキ値を0にセット Temp2 = Psrxdt1 And &HF0 'PSのマスコンコードを1Byteに変換 Temp3 = Psrxdt2 And &H10 Shift Temp3 , Right , 4 Temp2 = Temp2 Or Temp3 ' Select Case Temp2 'PSの受信コードをマスコン値に変換 Case &H01 : Psmascn = 0 Case &H80 : Psmascn = 1 Case &H81 : Psmascn = 2 Case &H20 : Psmascn = 3 Case &H21 : Psmascn = 4 Case &HA0 : Psmascn = 5 End Select ' ' * LCDの2行目に、マスコンとブレーキの状態を表示 * ' Psmode01: If Psmascn = 0 Then 'マスコンの状態をLCDへ表示 Temp1 = &H20 Else Temp1 = Psmascn + 7 'キャラクター・コード[00]は、文字列終了コードになる End If Strlcd = " Mas:" + Chr(temp1) Strlcd = Strlcd + Str(psmascn) Strlcd = Strlcd + " " ' Select Case Psbrake 'ブレーキの状態をLCDへ表示 Case 0 : Temp1 = &H20 'ブレーキ解除 Temp2 = Asc( "R") Case 9 : Temp1 = &H0F '非常ブレーキ Temp2 = Asc( "E") Case Else: Temp1 = Psbrake + 7 Temp2 = &H30 + Psbrake End Select Strlcd = Strlcd + "Brk:" Strlcd = Strlcd + Chr(temp1) Strlcd = Strlcd + Chr(temp2) Strlcd = Strlcd + " " ' ' * 押しボタンの状態を、外部制御端子へ出力する * ' Temp1 = Psrxdt2 And &HE0 Rotate Temp1 , Left , 3 Temp2 = Psrxdt1 And &H08 Temp1 = Temp1 Or Temp2 Temp2 = Psrxdt1 And &H01 Shift Temp2 , Left , 4 Temp1 = Temp1 Or Temp2 Porta = Temp1 ' ' ' * 制動状態により、モーターの速度を決定する * ' ' If Psbrake = 0 Then Goto Psmode03 'If ブレーキ解除中? Then ' ' * 減速制御 * ' If Psbrake = 9 Then Goto Psmode04 'If 非常ブレーキ? Then ' Motacl = 0 'モーター加速カウンタをリセット Motmof = 0 'モーター慣性走行カウンタをリセット If Motspd = 0 Then Goto Vrmode01 'If モーター速度=0? Then ' Temp1 = 9 - Psbrake '減速間隔の時間を計算 Temp1 = Temp1 * 2 'ブレーキ・レバーに対する減速値を設定 Temp2 = Not Ad2acl '加速係数ボリューム値を反転 Temp2 = Temp2 / 40 '加速係数ボリュームに対する減速値を設定 (割数大->減速大) Temp1 = Temp1 + Temp2 If Motslo < Temp1 Then Goto Vrmode01 'If 減速時間に達したか? Else Motslo = 0 Motspd = Motspd - 1 'モーター速度を減速 Goto Vrmode01 ' Psmode04: '非常ブレーキを掛けた Motspd = 0 'モーター速度を0に設定 Goto Vrmode01 ' ' * 加速制御 * ' Psmode03: If Psmascn = 0 Then Goto Psmode06 'If マスコン切(慣性走行)? Then ' Motslo = 0 'モーター減速カウンタをリセット Motmof = 0 'モーター慣性走行カウンタをリセット Select Case Psmascn 'マスコン値から設定速度を決定 Case 1 : Temp1 = 25 'マスコン1 Case 2 : Temp1 = 50 'マスコン2 Case 3 : Temp1 = 75 'マスコン3 Case 4 : Temp1 = 100 'マスコン4 Case 5 : Temp1 = 125 'マスコン5 End Select If Motspd = Temp1 Then Goto Vrmode01 'If モーター速度と設定値が等しい? Then If Motspd > Temp1 Then Goto Psmode05 'If モーター速度が設定値より早い? Then ' ' * 設定速度まで加速 * ' Temp1 = Not Ad2acl '加速間隔の時間を計算 Temp1 = Temp1 / 16 '加速係数ボリュームに対する加速値を設定 (割数大->加速大) Temp1 = Temp1 + 2 If Motacl < Temp1 Then Goto Vrmode01 'If 再加速時間に達したか? Else Motacl = 0 Motspd = Motspd + 1 'モーター速度を加速 Goto Vrmode01 ' ' * 設定速度まで減速 * ' Psmode05: Temp1 = Not Ad2acl '減速間隔の時間を計算 Temp1 = Temp1 / 4 '加速係数ボリュームに対する減速値を設定 (割数大->減速大) Temp1 = Temp1 + 20 If Motacl < Temp1 Then Goto Vrmode01 'If 減速時間に達したか? Else Motacl = 0 Motspd = Motspd - 1 'モーター速度を減速 Goto Vrmode01 ' ' * 慣性走行 * ' Psmode06: If Motspd = 0 Then Goto Vrmode01 'If モーター速度=0? Then Motslo = 0 'モーター減速カウンタをリセット Motacl = 0 'モーター加速カウンタをリセット Temp1 = Not Ad2acl '再減速間隔の時間を計算 Temp1 = Temp1 / 4 '加速係数ボリュームに対する減速値を設定 (割数大->減速大) Temp1 = Temp1 + 20 If Motmof < Temp1 Then Goto Vrmode01 'If 慣性走行の減速時間に達したか? Else Motmof = 0 Motspd = Motspd - 1 'モーター速度を減速 Goto Vrmode01 ' ' ' * ボリューム モード * ' ' Vrmode: Motspd = Ad0spd 'スピード・ボリューム値をモータ速度に設定 Strlcd = " " 'LCDのメッセージ・エリアをクリア ' Vrmode01: 'D/A用 データを準備 If Motspd = 0 Then Daomot = 0 Else Tempw1 = Motspd * 14 Shift Tempw1 , Right , 4 Temp1 = Low(tempw1) Daomot = Temp1 + 16 'D/Aコンバータ用 モーターパルス 出力データ End If ' Daolit = Ad1lit 'D/Aコンバータ用 照明パルス 出力データ If Ad1lit > Daomot Then Goto Vrmode02 Daompl = Daomot 'D/Aコンバータ用 モーター+照明パルス 出力データ Return ' Vrmode02: Daompl = Ad1lit Return ' ' ********************************************* ' * Timer1B 割り込み処理 D/A用 照明パルス生成 * ' ********************************************* ' Tm1bint: $asm PUSH R22 PUSH R23 IN R22,SREG 'ステータス・レジスタを待避 ; LDS R23,{Motpff} 'モーターのパルス極性を判定 CPI R23,0 BRNE Tm1bint2 'If モーター・パルス H エリア? Then ; LDS R23,{Daolit} '照明・パルスのみエリア RJMP Tm1bint1 ; Tm1bint2: ' モーター・パルスと照明・パルス H エリア LDS R23,{Daompl} ; Tm1bint1: Out Portc , R23 'D/Aコンバータへデータを出力 ; Out Sreg , R22 'ステータス・レジスタを復帰 POP R23 POP R22 $end Asm Return ' ' ************************************************** ' * Timer1A 割り込み処理 D/A用 モーターパルス 生成 * ' ************************************************** ' Tm1aint: $asm PUSH R22 PUSH R23 IN R22,SREG 'ステータス・レジスタを待避 ; LDS R23,TIFR2 '*** 注意![SBIC]命令はR0を使用する *** SBRC R23,OCF2A 'If Timer2が10mSカウント終了? Then RJMP Tm1aint2 ; Tm1aint5: LDS R23,{Motpff} 'モーターのパルス極性を判定 CPI R23,0 BRNE Tm1aint3 'If モーター・パルス H エリア? Then ; LDI R23,0 'モーター・パルス L エリア ; Tm1aint1: Out Portc , R23 'D/Aコンバータへデータを出力 ; Out Sreg , R22 'ステータス・レジスタを復帰 POP R23 POP R22 $end Asm Return ' ' $asm Tm1aint3: LDS R23,{Daomot} ' モーター・パルスのみ H エリア RJMP Tm1aint1 ; ; Tm1aint2: SBI TIFR2,OCF2A 'Timer2 比較一致フラグをリセット ; LDS R23,{Motpff} CPI R23,0 BREQ Tm1aint4 'If モーターパルス F/F=0? Then LDI R23,0 Tm1aint6: STS {Motpff},R23 RJMP Tm1aint5 ; Tm1aint4: LDI R23,1 STS {T20msf},R23 RJMP Tm1aint6 $end Asm