PICAXEで鉄道模型の在線検出と信号機の制御

## プログラムについて
・予め用意されている変数ではプログラムが見づらくなるので symbol を使用して名前を変えています。

・ポート名、固定値も、symbolで定義してみました。

・２つの信号機を別々に制御するため、ステートマシンを使いました。

・時間管理は、EtimeA = time のように最初のシステム時刻し、以降は calA = time - EtimeA　で現在のシステム時刻から、保存しておいたシステム時刻を減算し、if calA >= STPTIM then　でタイムアップしたかをチェックしています。

・システム時間は time で取得できますが、16bitの為、連続稼働で18日とちょっと過ぎた時にオーバーフローします。
事前にオーバーフローを検出して2つのステートマシーンが進行IDLE時にtimeを初期化するようにしてみました。

・if 内で演算できませんでしたので
```cpp
if time - EtimeA  >= STPTIM then
```
途中演算用の変数 calA を用意して回避しました。
```cpp
calA = time - EtimeA 
if calA >= STPTIM then 
```
・debug を 有効にするとプログラムがかなり遅くなるので、タイムアウト時間を短くして動作確認しました。

・複数の時間制御を行うときは、pause を使わない方法でプログラムを作るとよいです。

## 組み立て
実際は、Cdsセンサ、LEDは別基板にて接続しています。
![assy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111210/5669a069-4611-e70b-2f35-e74ebd3bdd17.png)

## 動画
https://twitter.com/masashi_214/status/1741809033361887263

## 写真
PICAXE-20Mとブレッドボード
![スクリーンショット 2024-01-01 23.10.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111210/29f0e8d5-bd42-72ad-699d-6f8529fdd178.png)

動作確認用全体写真
![スクリーンショット 2024-01-01 23.10.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111210/7c90e593-f6a1-65c2-1e9f-d73181fb2337.png)

## 関連投稿
https://qiita.com/masashi_214/items/5495503bf6bd82c1980b

https://qiita.com/masashi_214/items/d1acb1ecdc32de5a1698

## ソースファイル
```cpp
;---------------------------------------------------------------------------
; 閉塞信号機 2回路
; [閉塞信号機2.bas]
; Copyright (c) 2024 Ayanosuke(Maison de DCC)
;
; http://maison-dcc.sblo.jp/ http://dcc.client.jp/ http://ayabu.blog.shinobi.jp/
; https://twitter.com/masashi_214
;
; DCC電子工作連合のメンバーです
; https://desktopstation.net/tmi/ https://desktopstation.net/bb/index.php
;
; This software is released under the MIT License.
; http://opensource.org/licenses/mit-license.php
;---------------------------------------------------------------------------

symbol STATE_A = b0 	;w0
symbol STATE_B = b1 	;w0
symbol CH1ADCVAL = b2 	;w1
symbol CH2ADCVAL = b3 	;w1
symbol EtimeA = w2
symbol EtimeB = w3
symbol calA = w4
symbol calB = w5

symbol CH1ADCPORT = c.1
symbol CH2ADCPORT = c.2

symbol ADCHth = 200		;Hth未使用
symbol ADCLth = 60		;60=曇りで照明を付けていないリビング
symbol STPTIM = 10		;停止 10秒
symbol CAUTIM = 5		;注意 5秒
symbol DECTIM = 5		;減速 5秒
;symbol STPTIM = 2		;停止 10秒 debugモード用
;symbol CAUTIM = 1		;注意  5秒 debugモード用
;symbol DECTIM = 1		;減速  5秒 debugモード用

symbol ST_INIT = 0
symbol ST_ADVANCE = 1
symbol ST_ADVIDLE = 2
symbol ST_CAUTION = 3
symbol ST_CAUIDLE = 4
symbol ST_STOP = 5
symbol ST_STPIDLE = 6
symbol ST_DECELE = 7
symbol ST_DECIDLE = 8

adcconfig %000		; b2 = 0 VRef- is 0V , b1-0 = 00 VRef+ is V+ (power supply)
setfreq m16			; m16でtimeが秒になる

let STATE_A = ST_INIT	; STATE変数に、初期値ST_INITを代入

main: 
;---------- CHA ----------
    select case STATE_A				; ステートマシーン
    	case ST_INIT				; STATE:初期
			STATE_A = ST_ADVANCE
    	case ST_ADVANCE				; STATE:進行状態
			gosub advanceA
			STATE_A = ST_ADVIDLE
    	case ST_ADVIDLE				;進行状態で在線検出を確認
			gosub detection_chk
			if CH1ADCVAL =< ADCLth then	;在線検知したら ST_STOPへ
				STATE_A = ST_STOP
			endif
		case ST_STOP				;STATE:停止状態
			gosub stopA
			EtimeA = time
			STATE_A = ST_STPIDLE
		case ST_STPIDLE				;停止状態で在線検出
			gosub detection_chk
			if CH1ADCVAL =< ADCLth then 	;在線検知したら ST_STOPへ
				STATE_A = ST_STOP
			endif
			calA = time - EtimeA 
			if calA >= STPTIM then	;タイムアップしたら ST_CAUTIONへ 
				STATE_A = ST_CAUTION 
			endif
		case ST_CAUTION				;STATE:注意状態
			gosub cautionA
			EtimeA = time			;タイマーリセット
			STATE_A = ST_CAUIDLE
		case ST_CAUIDLE				;注意状態で在線検出を確認
			gosub detection_chk
			if CH1ADCVAL =< ADCLth then  	;在線検知したら ST_STOPへ
				STATE_A = ST_STOP
			endif
			calA = time - EtimeA 
			if calA >= CAUTIM then	;タイムアップしたらST_ADVNCEへ
				STATE_A = ST_ADVANCE
			endif
	endselect

;---------- CHB ----------
	select case STATE_B				; ステートマシーン
		case ST_INIT				; STATE:初期
			STATE_B = ST_ADVANCE
		case ST_ADVANCE				; STATE:進行状態
			gosub advanceB
			STATE_B = ST_ADVIDLE
		case ST_ADVIDLE				;進行状態で在線検出を確認
			gosub detection_chk
			if CH2ADCVAL < ADCLth then	;在線検知したら ST_STOPへ
				STATE_B = ST_STOP
			endif
		case ST_STOP				;STATE:停止状態
			gosub stopB
			EtimeB = time			;現在値のタイマー読み込み
			STATE_B = ST_STPIDLE
		case ST_STPIDLE				;停止状態で在線検出
			gosub detection_chk
			if CH2ADCVAL =< ADCLth then 	;在線検知したら ST_STOPへ
				STATE_B = ST_STOP
			endif
			calB = time - EtimeB
			if calB >= STPTIM then		;タイムアップしたら ST_CAUTIONへ 
				STATE_B = ST_CAUTION 
			endif
		case ST_CAUTION				;STATE:注意状態
			gosub cautionB
			EtimeB = time			;タイマーセット
			STATE_B = ST_CAUIDLE
		case ST_CAUIDLE				;注意状態で在線検出を確認
			gosub detection_chk
			if CH2ADCVAL =< ADCLth then  	;在線検知したら ST_STOPへ
				STATE_B = ST_STOP
			endif
			calB = time - EtimeB
			if calB >= DECTIM then		;タイムアップしたらST_DECELEへ
				STATE_B = ST_DECELE
			endif
		case ST_DECELE				;STATE:減速
			gosub decelerationB
			EtimeB = time			;タイマーセット
			STATE_B = ST_DECIDLE
		case ST_DECIDLE				;減速状態で在線検出を確認
			gosub detection_chk
			if CH2ADCVAL =< ADCLth then  	;在線検知したら ST_STOPへ
				STATE_B = ST_STOP
			endif
			calB = time　-　EtimeB
			if calB >= CAUTIM then		;タイムアップしたらST_ADVNCEへ
				STATE_B = ST_ADVANCE
			endif	
	
	endselect

	gosub timechk					;timeのオーバーフローチェック
;	debug		;有効にするとかなり遅くなる
goto main

;------------------------------------------------------------
;3現示信号機
;------------------------------
;消灯
;------------------------------
ledoffA:
	low b.0
	low b.1
	low b.2
	low b.3
return
;------------------------------
;進行
;------------------------------
advanceA:
    low b.0
	high b.1
	low b.2
	low b.3
return
;------------------------------
;注意
;------------------------------
cautionA:
	high b.0
	low b.1
	low b.2
	high b.3
return
;------------------------------
;停止
;------------------------------
stopA:
	high b.0
	high b.1
	high b.2
	low b.3
return
;------------------------------------------------------------
;4現示信号機
;------------------------------
;消灯
;------------------------------
ledoffB:
	low b.4
	low b.5
	low b.6
	low b.7
return
;------------------------------
;進行
;------------------------------
advanceB:
    low b.4
	high b.5
	low b.6
	low b.7
return
;------------------------------
;注意
;------------------------------
cautionB:
	high b.4
	high b.5
	low b.6
	high b.7
return
;------------------------------
;減速
;------------------------------
decelerationB:
	low b.4
	high b.5
	low b.6
	high b.7
return
;------------------------------
;停止
;------------------------------
stopB:
	high b.4
	high b.5
	high b.6
	low b.7
return
;------------------------------
;ADC取り込み
;------------------------------	
detection_chk:
	readadc CH1ADCPORT,CH1ADCVAL
	readadc CH2ADCPORT,CH2ADCVAL
return
;------------------------------
;time のオーバーフローを確認
;------------------------------	
timechk:
	if time >= 64800 then	; 18日以上 60 x 60 x 18 = 64800
		if STATE_A = ST_ADVIDLE and STATE_B = ST_ADVIDLE then
			time = 0
		endif
	endif
return
```
## PICAXE関連の投稿
PICAXE（ピカクス）でLチカ
https://qiita.com/masashi_214/items/5495503bf6bd82c1980b
PICAXE 最初に調べた事
https://qiita.com/masashi_214/items/d1acb1ecdc32de5a1698
PICAXEで鉄道模型の在線検出と信号機の制御
https://qiita.com/masashi_214/items/c728814df4f7a2453112
PICAXE（ピカクス）のポート設定
https://qiita.com/masashi_214/items/e5d5e1b9817aed754f52
PICAXE（ピカクス） リンク集
https://qiita.com/masashi_214/items/8b630b2c60ddb466b1ac
PICAXE（ピカクス）のpwm設定
https://qiita.com/masashi_214/items/f92e52837a9fa902879f
PICAXEでPWMを使用した調光機能を使って蛍を作る
https://qiita.com/masashi_214/items/0231a75ae0c77c2be206