田舎の組み込みプログラマーがわざわざ趣味でも色々開発してみようとあがく様を綴るブログです。
DMM.makeのクリエイターズマーケットに出品しています。
シェミュレータ炸裂 ― 2018年05月06日
またもや随分と放置してしまいました。
例によって思いっきりサボってみたり、水面下で色々あがいたりしていたんですが、その結果絞り出したのがこれです。
ご覧の通り、マイコンを載せた変換基板をエミュレータに繋げた物ですが、この状態でデバッガーを走らせることができます。
つまり、シミュレータ的に使えるエミュレータということで、「シェミュレータ」というわけですね。
エミュレータからの給電だけで動きますし、シミュレータと違ってタイマーなどの周辺機能も普通に使えますので、ちょっとしたコードを確認したいときに便利です。
そんなわけで
ちょっとしたコードを書いてみました。
.list OFF
.include CORE_BASE.inc
.include sfr_r832m.inc
.include R8C_3M.inc
.list ON
PART$_DEFINE LED_CONTROL
$CPU
PORT_BIT$_PULL P42 ; Vref不使用、プルアップ
XIN$_USE ; XIN使用
CLOCK$_EXT CLOCK_F1 ; CPU クロック 外部クロック入力、分周なし
; システム周期(タイマRA)
TRA$_TIMER_MODE C_f8 ; タイマモード f8 - 0.4usec
TRA$_PRE 250 ; プリスケーラ 0.1msec
TRA$_REG 10 ; TRAレジスタ 1.0msec
TRA$_START ; 初期化時にスタートする
$END
RAM$
FLAG$_ system_flags
FLAG$_ADD SYSTEM_CYCLE
FLAG$_ADD LED_PORT_BIT
_$
DIVIDING$_ALLOC regular_10 ; 分周処理定義
stop_timer: .blkw 1
_END
$SETUP ; arduino風
PROC$_CALL LED_CONTROL$_UNIQUE ; いきなり点滅
[ stop_timer ] = 230
$END
$LOOP ; arduino風
btstc SYSTEM_CYCLE ; 1msec毎にONされる(フラグ→C、クリア)
if C ; 1msec周期
DIVIDING$_ regular_10, 10 ; 10分周
PROC$_CALL$_W LED_CONTROL$_TIMER, 10 ; 10msec を通知
_ ; 処理分割
if [ stop_timer ]
[ stop_timer ] = -- [ stop_timer ]
if Z
PROC$_CALL LED_CONTROL$_OFF ; 点滅をやめる
endif
endif
_$
endif
$END
TRA$ 1
_ITP ; 割り込み処理
btsts SYSTEM_CYCLE ; フラグをCにコピーした後セット
if C ; フラグがクリアされていない
; 処理遅れ
endif
_END
;==========================================================
PART$ LED_CONTROL
;----------------------------------------------------------
blink_timer: .blkw 1
blink_limit: .blkw 1
;==========================================================
; コンディション定義
CONDITION$_DEFINE C_LED_OFF ;[消灯中]
CONDITION$_DEFINE C_LED_ON ;[点灯中]
CONDITION$_DEFINE C_LED_BLINK ;[点滅中]
; ステータス定義
STATE$_DEFINE LED_STATIC_OFF ; 消灯<[消灯中]
STATE$_DEFINE LED_OFF_DELAY ; 消灯遅延<[消灯中]
STATE$_DEFINE LED_STATIC_ON ; 点灯<[点灯中]
STATE$_DEFINE LED_BLINK_OFF ; 点滅(OFF)<[点滅中]
STATE$_DEFINE LED_BLINK_ON ; 点滅(ON)<[点滅中]
;=======================================
;[消灯中]
;=======================================
CONDITION$ C_LED_OFF
_ON
TRANS LED_STATIC_ON ; → 点灯<[点灯中]
_UNIQUE
TRANS LED_BLINK_ON ; → 点滅(ON)<[点滅中]
_END
;-----------------------------------
; 消灯<[消灯中]
;-----------------------------------
STATE$ LED_STATIC_OFF, C_LED_OFF
[ LED_PORT_BIT ] = OFF
_END
;-----------------------------------
; 消灯遅延<[消灯中]
;-----------------------------------
STATE$ LED_OFF_DELAY, C_LED_OFF
_TIMER
; ジャンクション●的な動作
if [ blink_timer ].w > [ PARAMETER ].w
; タイマー更新
[ blink_timer ].w = [ blink_timer ].w - [ PARAMETER ].w
else
; タイムアップ
TRANS LED_STATIC_OFF ; → 消灯<[消灯中]
endif
_END
;=======================================
;[点灯中]
;=======================================
CONDITION$ C_LED_ON
_OFF
TRANS LED_STATIC_OFF ; → 消灯<[消灯中]
_UNIQUE
TRANS LED_BLINK_OFF ; → 点滅(OFF)<[点滅中]
_END
;-----------------------------------
; 点灯<[点灯中]
;-----------------------------------
STATE$ LED_STATIC_ON, C_LED_ON
[ LED_PORT_BIT ] = ON
_END
;=======================================
;[点滅中]
;=======================================
CONDITION$ C_LED_BLINK
_OFF
NOP
TRANS LED_OFF_DELAY ; → 消灯遅延<[消灯中]
_ON
TRANS LED_STATIC_ON ; → 点灯<[点灯中]
_END
;-----------------------------------
; 点滅(OFF)<[点滅中]
;-----------------------------------
STATE$ LED_BLINK_OFF, C_LED_BLINK
[ LED_PORT_BIT ] = OFF
[ blink_timer ].w = [ blink_limit ].w
_TIMER
if [ blink_timer ].w > [ PARAMETER ].w
[ blink_timer ].w = [ blink_timer ].w - [ PARAMETER ].w
else
TRANS LED_BLINK_ON ; → 点滅(ON)<[点滅中]
endif
_END
;-----------------------------------
; 点滅(ON)<[点滅中]
;-----------------------------------
STATE$ LED_BLINK_ON, C_LED_BLINK
[ LED_PORT_BIT ] = ON
[ blink_timer ].w = [ blink_limit ].w
_TIMER
if [ blink_timer ].w > [ PARAMETER ].w
[ blink_timer ].w = [ blink_timer ].w - [ PARAMETER ].w
else
TRANS LED_BLINK_OFF ; → 点滅(OFF)<[点滅中]
endif
_END
;==========================================================
_INIT
[ blink_limit ].w = 1000
_SET
[ blink_limit ].w = [ PARAMETER ].w
;----------------------------------------------------------
_END
;==========================================================
$END$
.end
前回の最終形態の状態遷移図からコーディングしたもので、なんと、これがソースファイルの全体像なのです。
つまり、このまま動いてしまうわけで、スタートアップ処理とかその他もろもろの面倒なことはマクロの中でやってしまっているわけです。
ちなみに、このコードのプログラムセクションは988バイトです。
ほぼ定型的な処理をあちこちで展開しているせいで大きくなってしまっていますが、アセンブラの癖を悪用している都合上、色々難しいところではあります。
一応、コードを far 領域にも置けるように設計していますが、ピン数の少ない品種ではそこまでの領域がないのがつらいですね。
ぼやいていてもしかたないので
状態遷移図を再掲します。
外部からの指令によってLEDを点灯/消灯/点滅させるわけですが、[点滅]から[消灯]に移行するときにLEDが唐突に消えないよう、遅延タイマーを入れているのが特徴です。
今回のコードだと、点滅は2秒周期、つまり1秒点いて1秒消えるの繰り返しになっていて、点滅を終えるときも1秒点いてから消えるようにしています。
テストコードでは、スタート直後に点滅指令を出し、2.3秒後に消灯指令を出しています。
遅延処理がなければ2回目は0.3秒で消灯してしまいますが、遅延処理のおかげでちゃんと1秒後に消灯します。
実を言えば
前回の更新から一年近く経ってしまったのは、状態遷移処理の実装方法を煮詰めるだけでなく、分周処理の仕様で悩んでいたことが大きかったりします。
以前は別オブジェクト的な実装でしたが、最終的に今回のインライン的な扱いに決めました。
以下のような感じで"_"で分割して処理を書くことで、1回通る毎に1つだけ処理を実行し、次回には次の処理を実行します。
DIVIDING$_ regular_10, 10 ; 10分周('_'で分割された処理を切替実行)
処理1
_
処理2
_
処理3
・
・
・
_$
ここでは分割数を10にしているので10個までの処理を書けますが、10個に満たない分は何もせずに通過します。
つまり、1msec毎に通過する部分にこの処理を書いておけば10msecのタイマーを10個得たことになるわけですね。
メインループの負荷分散のための優れた方法だと自画自賛しておきます。
そんなわけで
今度こそちゃんとした物を完成させようと何度目になるか分からない誓いを立てたりしていますが、どうなることやら。
コメント
トラックバック
このエントリのトラックバックURL: http://trident.asablo.jp/blog/2018/05/06/8845925/tb
コメントをどうぞ
※メールアドレスとURLの入力は必須ではありません。 入力されたメールアドレスは記事に反映されず、ブログの管理者のみが参照できます。
※投稿には管理者が設定した質問に答える必要があります。