2016-10-19 22:27 | カテゴリ:PIC応用回路

前回はご参考までにと、プログラムを単にUPさせていただいただけでしたので、多少皆様のお役に立てそうな処理の一部をご紹介させていただきます。

細かなネタですので、PICのプログラミングにご興味のある方はどうぞ。(笑)


ライフゲームでは、各ドットについて、その周りのドットの状況を調べて、自分自身の次の世代の生死が決まります。
したがって、二次元平面の自分の位置の上段の3か所、同じ段の左右、下段の3か所の合計8か所のドットのON/OFFを連続的に調べ、そのONの数をカウントしなければなりません。
内部では、(X,Y)座標で、ドットを指定できるようにしていますので、そのXとYをそれぞれ、プラス、マイナスして目的のドットを調べるのですが、その際のX,Yの指定を次のような方法で行いました。

まず、配列を定義して、そこに、必要なXとYのプラスマイナスの値を格納して、

int mtrx[8][2] = {
{-1, -1},
{-1, 0},
{-1, 1},
{0, -1},
{0, 1},
{1, -1},
{1, 0},
{1, 1}
};

それを以下の関数で呼び出して、自分のまわりのONのドット数を計測します。


//-------------------------------------------------
// X, Y, pnで指定されたポイントの周りののDOTのON数を返す
//-------------------------------------------------

int Dot_cnt(int x0, int y0, int pn) {
int xc, yc, i, ttl_no, x1, y1;

ttl_no = 0;
for (i = 0; i <= 7; i++) {
xc = mtrx[i][0];
yc = mtrx[i][1];
x1 = x0 + xc;
y1 = y0 + yc;
if (x1 < 0) x1 = 15;
if (x1 > 15) x1 = 0;
if (y1 < 0) y1 = 15;
if (y1 > 15) y1 = 0;

ttl_no = Dot_chk(x1, y1, pn) + ttl_no;
}
return ttl_no;
}

ここで、pnは、プレーン番号で、実は今回のライフゲームは4つのプレーン(X,Y)を持っていて、4世代を管理しています。
もし、ドットがONになると、そのプレーンのドットのみがONにされます。
次の世代でもONが維持されれば、そのプレーンでもONとなります。
こうすることで、4世代ONになれば、その点は、ダイナミック表示で毎回表示されますので、より明るく、また、一つのプレーンでしかONでないドットは、スキャンが1/4なので、くらいドットとして表示されます。

実際には、それほど明暗の差は付きませんが、なんとなくわかります。


また、指定されたドット(X,Y)をONにしたりOFFにしたりする関数はこれです。


//--------------------------------------------------
// Dot ON 指定ビットを0に
//--------------------------------------------------

void Dot_on(int xc, int yc, int pn) {
int temp;
temp = 1;
temp = temp << xc;
temp = ~temp;
Dot_data[yc][pn] = Dot_data[yc][pn] & temp;
}


//--------------------------------------------------
// Dot OFF 指定ビットを1に
//--------------------------------------------------

void Dot_off(int xc, int yc, int pn) {
int temp;
temp = 1;
temp = temp << xc;
Dot_data[yc][pn] = Dot_data[yc][pn] | temp;
}

マトリックスのプレーンは整数変数の配列(16ビットx16個)x4プレーンで構成されています。
したがって、ドット単位のON・OFFは、整数変数の内部のビットをON・OFFしなければなりません。
たぶん、構造変数を用いて、多重定義すればビット単位で扱えると思うのですが、よくわからなかったので、整数変数を左右にビットシフトして、ANDやORを取ることで、ビット操作しています。


16ビットX16行X4プレーンのドットデータをダイナミック表示するわけですが、HWの配線を簡単にするために、変則的なレジスターアサインになってしまい、結果、ものすごく面倒なダイナミック表示関数になっています。
書き込む整数データ16ビットを、各レジスターの対応するビットに分解して、それをレジスターに一ビットずつ書き込み、8ドットそろったら、対応する行のTRをONにし、残りの8ビットをそろえて、別のTRをONにして、という面倒な作業をしています。

お時間がありましたら、下記、ご参考まで。


//----------------------------------------------------------
// 配列のDOTデータ(4プレーン)をLEDにダイナミック表示する
// コールされるとLEDを消灯し、mで指定されたLEDを点灯して戻る
// TMR0を設定して100usec毎に実行
//----------------------------------------------------------

void interrupt Dot_disp(void) {
GIE = 0;

//---- LED Off -------
PORTA = 0b11111111; // SW1 = RA4
PORTB = 0b11111111; //
PORTC = 0b11111111; //
PORTD = 0b11111111; //
PORTE = 0b11111111; //


if (flg == 0) {
if (n == future) goto last;
// 上段下位バイト
Dot_work1 = Dot_data[m][n];
RC4 = Dot_work1 & 1; // dotデータをポートに移す 0->0, 1->1
Dot_work1 = Dot_work1 >> 1;
RD1 = Dot_work1 & 1; // dotデータをポートに移す 0->0, 1->1
Dot_work1 = Dot_work1 >> 1;
RC5 = Dot_work1 & 1; // dotデータをポートに移す 0->0, 1->1
Dot_work1 = Dot_work1 >> 1;
RC6 = Dot_work1 & 1; // dotデータをポートに移す 0->0, 1->1
Dot_work1 = Dot_work1 >> 1;
RD0 = Dot_work1 & 1; // dotデータをポートに移す 0->0, 1->1
Dot_work1 = Dot_work1 >> 1;
RD2 = Dot_work1 & 1; // dotデータをポートに移す 0->0, 1->1
Dot_work1 = Dot_work1 >> 1;
RC7 = Dot_work1 & 1; // dotデータをポートに移す 0->0, 1->1
Dot_work1 = Dot_work1 >> 1;
RD3 = Dot_work1 & 1; // dotデータをポートに移す 0->0, 1->1

// 下段下位バイト
Dot_work2 = Dot_data[m + 8][n];
RB3 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RD4 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RB2 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RB1 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RD5 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RD6 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RB0 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RD7 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
last:

//-- TR on ----------
TR_drive_onL(m); // mによってドライブTRをon
cnt = cnt + 1;


} else {
if (n == future) goto last2;

// 上段上位バイト
Dot_work1 = Dot_data[m][n];
Dot_work1 = Dot_work1 >> 8;
RC4 = Dot_work1 & 1;
Dot_work1 = Dot_work1 >> 1;
RD1 = Dot_work1 & 1;
Dot_work1 = Dot_work1 >> 1;
RC5 = Dot_work1 & 1;
Dot_work1 = Dot_work1 >> 1;
RC6 = Dot_work1 & 1;
Dot_work1 = Dot_work1 >> 1;
RD0 = Dot_work1 & 1;
Dot_work1 = Dot_work1 >> 1;
RD2 = Dot_work1 & 1;
Dot_work1 = Dot_work1 >> 1;
RC7 = Dot_work1 & 1;
Dot_work1 = Dot_work1 >> 1;
RD3 = Dot_work1 & 1;
Dot_work1 = Dot_work1 >> 1;

// 下段上位バイト
Dot_work2 = Dot_data[m + 8][n];
Dot_work2 = Dot_work2 >> 8; //上位バイト
RB3 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RD4 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RB2 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RB1 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RD5 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RD6 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RB0 = Dot_work2 & 1;
Dot_work2 = Dot_work2 >> 1;
RD7 = Dot_work2 & 1;

last2:
//-- TR on ----------
TR_drive_onH(m); // mによってドライブTRをon
cnt = cnt + 1;

}

TR_no = m; // TR_noにmを保存

m = m + 1; //表示するLEDの行を+1する

if (m >= 8) {
m = 0;
if (cnt >= 16) {
cnt = 0;
n = n + 1;
}
if (n >= 4) n = 0;
flg ^= 1; //flgを反転
}
T0IF = 0;
GIE = 1;
}




//---------------------------
// TRドライブ(on)
//---------------------------

void TR_drive_onL(int drv) {

switch (drv) {
case 0: RC3 = on;
break;
case 1: RC2 = on;
break;
case 2: RC1 = on;
break;
case 3: RC0 = on;
break;
case 4: RA3 = on;
break;
case 5: RA2 = on;
break;
case 6: RA1 = on;
break;
case 7: RA0 = on;
break;

break;
}
}


//---------------------------
// TRドライブ H (on)
//---------------------------

void TR_drive_onH(int drv) {

switch (drv) {
case 0: RE2 = on;
break;
case 1: RE1 = on;
break;
case 2: RE0 = on;
break;
case 3: RA5 = on;
break;
case 4: RB7 = on;
break;
case 5: RB6 = on;
break;
case 6: RB5 = on;
break;
case 7: RB4 = on;
break;

break;
}
}







【ジャンル】:趣味・実用 【テーマ】:電子工作
コメント(2)

管理者のみに表示する