PICAXEでPWMを使用した調光機能を使って蛍を作る

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

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

・PICAXEは、PICAXE-20M2を使用しました。
　PWM portは、C.2 , C.3 , C.5 , B.1 の 4chを使用しました。
　PICAXE-14M2　も、4chありますので、symbol　hotalA　あたりの定義を変更すれば使えそうです。
　　![スクリーンショット 2024-01-28 13.01.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111210/972dbd3b-5111-8243-0af4-052a962b463e.png)

・4匹の蛍をバラバラに動かすための工夫
１、pwmのch数だけ蛍を作りました。（4匹）
２、PICAXEのマルチタスクの機能は使わずにステートマシーンを4つ組み込みました。
３、同時に光ると残念な感じになってしまうので、ptnA、ptnB、ptnC、ptnDで異なるパターンを4つ用意
４、4匹の点灯タイミングを微妙にずらすために以下のプログラムでずらしています。
システムタイマーの下位1bitを見て1だったら点灯シーケンスを開始させます。
他のステートマシーンは0x0001のマスク部分の数値を変えています。
```cpp
Ptime = time & 0x0001
if Ptime <> 0 then
    stateA = ST_step1
endif
```
５、結構処理が重いので4匹が限界かも。
６、>>ビットシフトが使えなかったのでcntA = cntA * 2という2のベギ乗コードを使用してます。



## ソースファイル
```cpp
;--------------------------------------------------------------------------------
; レイアウト用蛍点灯用プログラムです ver3が良い感じ
; [hotaru.ino]
; Copyright (c) 2020 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 stateA = b0	;w0 ステートマシン変数
symbol stateB = b1	;w0
symbol stateC = b2	;w1
symbol stateD = b3	;w1

symbol flgA = b4		;w2 点灯順序格納用変数
symbol flgB = b5		;w2
symbol flgC = b6		;w3
symbol flgD = b7		;w3

symbol Ptime = w4		;点灯タイミング変更用時間一時変数

symbol brightA = w5	;明るさ格納用変数
symbol brightB = w6
symbol brightC = w7
symbol brightD = w8

symbol cntA = w9		;ビットシフトが使えないので、マスク変数として
symbol cntB = w10
symbol cntC = w11
symbol cntD = w12

symbol hotalA = C.2	;pwmが使用できるポート
symbol hotalB = C.3
symbol hotalC = C.5
symbol hotalD = B.1

symbol ptnA = %11101101	;点灯パターン
symbol ptnB = %10101110
symbol ptnC = %00111011
symbol ptnD = %10101100
symbol MaxBright = 800	;1kHz自の最大値 1000 800にしてちょっと明るさを落としている
symbol BrightStep = 10	;明るさ変化量 10

symbol ST_init = 0	;ステート状態の割り当て
symbol ST_step1 = 1
symbol ST_step2 = 2
symbol ST_next = 3

pwmout pwmdiv4, hotalD, 249, 0	;pwm 周波数は1kHz
pwmout pwmdiv4, hotalA, 249, 0
pwmout pwmdiv4, hotalB, 249, 0
pwmout pwmdiv4, hotalC, 249, 0

setfreq m16			; m16でtimeが秒になる

cntA = 0x01
cntB = 0x01
cntC = 0x01
cntD = 0x01

stateA = ST_init		; 4匹のステートマシーンのステートをST_initに設定
stateB = ST_init
stateC = ST_init
stateD = ST_init

main:
;--------------------------------------------------------------------------------
    select case stateA		; グループA
    	case ST_init		;　初期化ステート
    		brightA = 0
    		flgA = ptnA & cntA
    		Ptime = time & 0x0001
    		if Ptime <> 0 then
    			stateA = ST_step1
    		endif
        case ST_step1		;　点灯ステート
    		brightA = brightA + BrightStep	;明るさを増加
    		if brightA >= MaxBright then		;Max値まで達したらステート変更
    			brightA = MaxBright
    			stateA = ST_step2
    		endif
    		if flgA<>0 then 	;flgAが0以外だったら点灯、0だと消灯
    			pwmduty hotalA,brightA
    		else
    			pwmduty hotalA,0
    		endif
    	case ST_step2		;　消灯ステート
    		brightA = brightA - BrightStep	;明るさを減少
    		if brightA <= 0 then			;0値まで達したらステート変更
    			brightA = 0				
    			stateA = ST_next
    		endif
    		if flgA<>0 then 	;flgAが0以外だったら点灯、0だと消灯
    			pwmduty hotalA,brightA
    		else
    			pwmduty hotalA,0
    		endif
    	case ST_next
    		cntA = cntA * 2		; >> ビットシフトが使えないので代用処理
    		if cntA = 256 then
    			cntA = 0x01
    		endif
    		flgA = ptnA & cntA
    		stateA = ST_step1
	endselect
;--------------------------------------------------------------------------------
    select case stateB		; グループB
    	case ST_init		;　初期化ステート
    		cntB = 0x01
    		brightB = 0
    		flgB = ptnB & cntB
    		Ptime = time & 0x0002
    		if Ptime <> 0 then
    			stateB = ST_step1
    		endif
    	case ST_step1		;　点灯ステート
    		brightB = brightB + BrightStep
    		if brightB >= MaxBright then
    			brightB = MaxBright
    			stateB = ST_step2
    		endif
    		if flgB<>0 then 
    			pwmduty hotalB,brightB
    		else
    			pwmduty hotalB,0
    		endif
    	case ST_step2		;　消灯ステート
    		brightB = brightB - BrightStep
    		if brightB <= 0 then
    			brightB = 0
    			stateB = ST_next
    		endif
    		if flgB<>0 then 
    			pwmduty hotalB,brightB
    		else
    			pwmduty hotalB,0
    		endif
    	case ST_next
    		cntB = cntB * 2		; >> ビットシフトが使えないので代用処理
    		if cntB = 256 then
    			cntB = 0x01
    		endif
    		flgB = ptnB & cntB
    		stateB = ST_step1
	endselect
;--------------------------------------------------------------------------------
    select case stateC		; グループC
    	case ST_init		;　初期化ステート
    		cntC = 0x01
    		brightC = 0
    		flgC = ptnC & cntB
    		Ptime = time & 0x0004
    		if Ptime <> 0 then
    			stateC = ST_step1
    		endif
    	case ST_step1		;　点灯ステート
    		brightC = brightC + BrightStep
    		if brightC >= MaxBright then
    			brightC = MaxBright
    			stateC = ST_step2
    		endif
    		if flgC<>0 then 
    			pwmduty hotalC,brightC
    		else
    			pwmduty hotalC,0
    		endif	
    	case ST_step2		;　消灯ステート
    		brightC = brightC - BrightStep
    		if brightC <= 0 then
    			brightC = 0
    			stateC = ST_next
    		endif
    		if flgC<>0 then 
    			pwmduty hotalC,brightC
    		else
    			pwmduty hotalC,0
    		endif	
    	case ST_next
    		cntC = cntC * 2		; >> ビットシフトが使えないので代用処理
    		if cntC = 256 then
    			cntC = 0x01
    		endif
    		flgC = ptnC & cntC
    		stateC = ST_step1
	endselect
;--------------------------------------------------------------------------------
    select case stateD		; グループD
    	case ST_init		;　初期化ステート
    		cntD = 0x01
    		brightD = 0
    		flgD = ptnD & cntD
    		Ptime = time & 0x0008
    		if Ptime <> 0 then
    			stateD = ST_step1
    		endif
	case ST_step1		;　点灯ステート
    		brightD = brightD + BrightStep
    		if brightD >= MaxBright then
    			brightD = MaxBright
    			stateD = ST_step2
    		endif
    		if flgD<>0 then 
    			pwmduty hotalD,brightD
    		else
    			pwmduty hotalD,0
    		endif	
	case ST_step2		;　消灯ステート
    		brightD = brightD - BrightStep
    		if brightD <= 0 then
    			brightD = 0
    			stateD = ST_next
    		endif
    		if flgD<>0 then 
    			pwmduty hotalD,brightD
    		else
    			pwmduty hotalD,0
    		endif	
	case ST_next
    		cntD = cntD * 2		; >> ビットシフトが使えないので代用処理
    		if cntD = 256 then
    			cntD = 0x01
    		endif
    		flgD = ptnD & cntD
        	stateD = ST_step1
	endselect

goto main
```

## 写真
https://twitter.com/masashi_214/status/1751434365429850259

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

## 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