JavaScriptでわかる!組込みプログラミングの神髄

第2回 並列処理プログラムを見やすく書く方法

この記事を読むのに必要な時間:およそ 4 分

前回は,一続きの処理をタイマー割り込みを使って分割して行うサンプルを紹介しました。このような処理は,JavaScriptや組込みプログラミングなど,さまざまな場面で必要になります。

今回は,より複雑な処理を見やすく書く方法について説明します。

オートリピートをどう作るか

さっそくサンプルプログラムを見てみましょう。これはメトロノームで,数字は1分間の拍数(いわゆるBPM)です。

リスト1 metronom.html

<HTMLM><HEAD><TITLE>metronom</TITLE>
<SCRIPT type="text/javascript"><!--

var	tempo = 0;
var	accval = 0;
var	arm = 0;
var	t0_interval = 50;
var	repeat_delay = 0;
var	repeat_val = 0;

function	update_tempo(val)
{
	tempo += val;
	if (tempo < 10)
		tempo = 10;
	else if (tempo > 300)
		tempo = 300;
	document.getElementById("tempo").innerHTML = tempo + "";
}

function	int_t0()
{
	accval += tempo;
	if (accval >= 60000 / t0_interval) {
		accval -= 60000 / t0_interval;
		arm ^= 1;
		document.getElementById("box").style.marginLeft = (arm)? "0px" : "200px";
	}
	if (repeat_delay <= 0)
		;
	else if (repeat_delay < 10)
		repeat_delay++;
	else
		update_tempo(repeat_val);
}

function	press_plus()
{
	update_tempo(repeat_val = 1);
	repeat_delay = 1;
}

function	press_minus()
{
	update_tempo(repeat_val = -1);
	repeat_delay = 1;
}

function	release()
{
	repeat_delay = 0;
}

function	init()
{
	tempo = parseInt(document.getElementById("tempo").innerHTML);
	setInterval(int_t0, t0_interval);
	document.onmouseup = release;
}

// --></SCRIPT>
</HEAD><BODY onload="init()">
<H1>metronom</H1>

<DIV id="box" style="margin-left:0px; width:50px; height:50px; background:#f00;">
</DIV>

<P><BIG><BIG>
<SPAN onmousedown="press_minus()">[-1]</SPAN>
<SPAN id="tempo">120</SPAN>
<SPAN onmousedown="press_plus()">[+1]</SPAN>
</BIG></BIG></P>

</BODY></HTML>

[-1]や[+1]のボタンを押し続けると,連続して数字が変わるようになっています。いわゆるオートリピートです。ソースを見る前に,どうやって実現するかを考えてみてください。ヒントですが,ボタンが離されたときに発生する割り込みを利用しています。

リピート処理をしているあいだ,メトロノームの動作が止まってもいいのであれば,処理を並列的に行う必要はありません。しかし,リピートしているあいだもメトロノームの動作を続けたいのであれば,タイマー割り込みの中で2つの処理を行う必要があります。このような場面は,プログラムを書いていればいくらでもでてきますね。

まずメトロノームの処理ですが,50ミリ秒のタイマー割り込みをそのまま使うと,飛び飛びの間隔しか実現できません。たとえば毎分60拍の場合は,タイマー割り込み20回で1拍になります。その1つ上は,タイマー割り込み19回で1拍ですが,これは毎分に換算すると約63拍です。つまり,その中間の毎分61拍という指定はできないことになります。これではメトロノームとして困りますね。

そこで解決策として,拍数を変数に積算していき,変数がオーバーフローしたときに拍を刻むようにします。拍数が大きければ,頻繁にオーバーフローすることになります。たとえは毎分60拍のとき,50ミリ秒ごとに変数に60を加算すると,1秒で1200増えます。このときに拍を刻んで変数を1200減らせば,余った分がきちんと残るようになります。

毎分61拍の場合,先ほどのやり方では正確に刻むことはできませんでした。しかし積算方式であれば,まず20回目の割り込みで1220になります。ここで拍を刻んで1200を引くと,20残ります。次は,通算40回目の割り込みで1240になり,拍を刻んで40残ります。次は60回目で1260になり,60残ります。そして,79回目で1219になり,19残ります。このように,自動的に20回と19回が組み合わさって,平均すると毎分61拍が刻めることになります。

次に,これと平行して,オートリピートの処理を行います。オートリピートは,スイッチを押すとまず1回カウントされ,押し続けると連続でカウントされるものです。キーを押し続けると連続で文字が入力されますが,これをマウスでもおこなおうというものです。

マウスの場合,押したときに一度割り込みが発生しますが,そのあとは何も起きません。従って,押したときにグローバル変数をセットしておいて,タイマー割り込みでリピート処理をおこないます。タイマー割り込みをそのまま使うと,押した瞬間から毎秒20カウントのスピードで増えてしまいますので,最初の10カウントは無視するようにします。また,マウスを離したら,この処理を止めるようにします。

グローバル変数に保存するのは,マウスを押してからどれくらい経ったかと,押されたのがどのボタンかの2つです。前者は,最初の10カウントを無視するのに使います。後者は,リピートのときに数を増やすのか減らすのかを判断するのに使います。

こうして,2つのタイマー処理が並列に行えるようになりました。

著者プロフィール

木元峰之(きもとみねゆき)

独立系ソフトハウスに8年間勤務,パッケージソフトの開発や記事執筆などを行う。現在はフリーのコンサルタント。SWESTなどのワークショップで分科会のコーディネータを務める。デジタル回路設計歴30年,プログラミング歴27年。

きもと特急電子設計
URL:http://business.pa-i.org/

コメント

コメントの記入