某ファブ施設スタッフの落書き

某ファブ施設で働くスタッフの気まぐれな日記のようなものです。

なんちゃっテトリス

8x8のマトリクスLEDを使って、テトリスを作ってみた。
基本動作は、左移動、右移動のみ。だから、"なんちゃっテトリス"。
手元にある部品だけで作ったので、頭悪い設計。picは、余っていた16f1939。マトリクスの部分はシフトレジスタを使えば、もっとピン数の少ないpicでOK。

仕様
・スタートボタンでゲームスタート。
・操作は、左移動と右移動。
・ブロックを一列消すごとにブロックの落下スピードがup。LEDのレベルメータが点灯する。

回路図
f:id:hogerian1306:20160316152630p:plain

プログラム

#include<stdio.h>
#include <xc.h>
#include <stdlib.h>

#define _XTAL_FREQ 32000000 //32MHz
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = HS        // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = OFF       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config VCAPEN = OFF     // Voltage Regulator Capacitor Enable (All VCAP pin functionality is disabled)
#pragma config PLLEN = OFF       // PLL Enable (4x PLL enabled)
#pragma config STVREN = OFF      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

#define BLOCK1 0
#define BLOCK2 1
#define BLOCK3 2
#define BLOCK4 3

#define LSW RC0
#define RSW RC1
#define START_SW RC2

int matrix[8][10];//Block情報
int delete_sum;//消したBlockの総数
int active_block[3];//操作中のBlockの種類と始点 [0]:種類 [1]:x軸 [2]:y軸
unsigned int count;//Block落下用カウンタ
int flg;//Block接触確認フラグ
int mode;//GameMode
/******************************************************************************
 * COL → RB0?RB7 ROW → RA0?RA7                                              *
 *****************************************************************************/

void init(void);
void matrix_plot(int x,int y,int color);
void matrix_vline(int x,int color);
void matrix_hline(int y,int color);
void matrix_all(int color);
void matrix_reset(void);
void matrix_show(void);
void matrix_set(int number);
void create(void);
void delete(int y);
void move(int direction);
void gamestart(void);
void gameover(void);
void difficulty(int number);
void shift_register(int number);
void interrupt timer(void);

void main(void) {

    init();

    int i,j;

    for(i=0;i<=10;i++){
      shift_register(i);
      __delay_ms(300);
    }

    mode = 3;
    while(1){
        if(mode == 0){//GameStartMode
            gamestart();
            mode = 1;
        }else if(mode == 1){//GameMode
            matrix_show();
            difficulty(delete_sum);
        }else if(mode == 2){//GameOverMode
            gameover();
            mode = 3;
        }else if(mode == 3){//StayMode
            matrix_all(1);
            count = 0;
            delete_sum = 0;
        }
    }
}

/*レジスタ初期化関数*/
//入出力
//割り込み
void init(void)
{
  /*レジスタ設定*/
  OSCCON = 0x70;
  TRISA = 0x00;
  TRISB = 0x00;
  TRISC = 0x0f;
  TRISD = 0x00;
  ANSELA = 0x00;
  ANSELB = 0x00;
  ANSELD = 0x00;
  PORTA = 0x00;
  PORTB = 0x00;
  PORTC = 0x00;
  PORTD = 0x00;

  /*割り込み関連のレジスタ設定*/
  T2CON = 0x7f;
  PR2 = 0x7c;
  TMR2IE = 1;
  PEIE = 1;
  GIE = 1;

}

/*タイマー2割り込み関数*/
//Blockの落下スピード
//移動用スイッチの監視
void interrupt timer(void)
{
    if(TMR2IF == 1){
        TMR2IF = 0;//フラグクリア

        if(mode == 1){//GameMode
            if(flg == 1){
                create();
                flg = 0;
            }else{
                count++;
            }
            if(count == (25-delete_sum)){//Block落下スピード設定
                move(2);
                count = 0;
            }
            if(LSW == 0){//左移動スイッチ
                while(LSW == 0);
                move(0);
            }else if(RSW == 0){//右移動スイッチ
                while(RSW == 0);
                move(1);
            }
        }
        if(START_SW == 0){//スタートスイッチ
            while(START_SW == 0);
            mode = 0;
        }
    }
}

/*マトリクスに点を打つ*/
//x軸、y軸、色を指定
//(0,0)は、左下
void matrix_plot(int x,int y,int color)
{
    if(x == 0)PORTD = 0x01;
    if(x == 1)PORTD = 0x02;
    if(x == 2)PORTD = 0x04;
    if(x == 3)PORTD = 0x08;
    if(x == 4)PORTD = 0x10;
    if(x == 5)PORTD = 0x20;
    if(x == 6)PORTD = 0x40;
    if(x == 7)PORTD = 0x80;
    if(y == 0)PORTB = 0x7f;
    if(y == 1)PORTB = 0xbf;
    if(y == 2)PORTB = 0xdf;
    if(y == 3)PORTB = 0xef;
    if(y == 4)PORTB = 0xf7;
    if(y == 5)PORTB = 0xfb;
    if(y == 6)PORTB = 0xfd;
    if(y == 7)PORTB = 0xfe;
}

/*マトリクスに縦表示*/
//x軸、色を指定
void matrix_vline(int x,int color)
{
    PORTD = 0xff;
    if(color == 0){
        if(x == 7)RB0 = 1;
        if(x == 6)RB1 = 1;
        if(x == 5)RB2 = 1;
        if(x == 4)RB3 = 1;
        if(x == 3)RB4 = 1;
        if(x == 2)RB5 = 1;
        if(x == 1)RB6 = 1;
        if(x == 0)RB7 = 1;
    }else if(color == 1){
        if(x == 7)PORTB = 0xfe;
        if(x == 6)PORTB = 0xfd;
        if(x == 5)PORTB = 0xfb;
        if(x == 4)PORTB = 0xf7;
        if(x == 3)PORTB = 0xef;
        if(x == 2)PORTB = 0xdf;
        if(x == 1)PORTB = 0xbf;
        if(x == 0)PORTB = 0x7f;
    }
    __delay_ms(1);
}

/*マトリクスに横表示*/
//y軸、色を指定
void matrix_hline(int y,int color)
{
    PORTB = 0x00;
    if(color == 0){
        if(y == 0)RD0 = 0;
        if(y == 1)RD1 = 0;
        if(y == 2)RD2 = 0;
        if(y == 3)RD3 = 0;
        if(y == 4)RD4 = 0;
        if(y == 5)RD5 = 0;
        if(y == 6)RD6 = 0;
        if(y == 7)RD7 = 0;
    }else if(color == 1){
        if(y == 0)PORTD = 0x01;
        if(y == 1)PORTD = 0x02;
        if(y == 2)PORTD = 0x04;
        if(y == 3)PORTD = 0x08;
        if(y == 4)PORTD = 0x10;
        if(y == 5)PORTD = 0x20;
        if(y == 6)PORTD = 0x40;
        if(y == 7)PORTD = 0x80;
    }
    __delay_ms(1);
}

/*マトリクス全体に表示*/
//色を指定
void matrix_all(int color)
{
    if(color == 0){
        PORTD = 0x00;
        PORTB = 0x00;
    }else if(color == 1){
        PORTD = 0xff;
        PORTB = 0x00;
    }
}

/*フィールドデータの初期化*/
void matrix_reset(void)
{
    int i,j;

    for(i=0;i<8;i++){
        for(j=0;j<10;j++){
            matrix[i][j] = 0;
        }
    }
}

/*フィールドをマトリクスに表示*/
void matrix_show(void)
{
    int i;

    for(i=0;i<8;i++){//マトリクス8行分の表示
        RB0 = ~matrix[0][i];
        RB1 = ~matrix[1][i];
        RB2 = ~matrix[2][i];
        RB3 = ~matrix[3][i];
        RB4 = ~matrix[4][i];
        RB5 = ~matrix[5][i];
        RB6 = ~matrix[6][i];
        RB7 = ~matrix[7][i];
        if(i == 0){
            RD0 = 1;
            __delay_ms(1);
            RD0 = 0;
        }else if(i == 1){
            RD1 = 1;
            __delay_ms(1);
            RD1 = 0;
        }else if(i == 2){
            RD2 = 1;
            __delay_ms(1);
            RD2 = 0;
        }else if(i == 3){
            RD3 = 1;
            __delay_ms(1);
            RD3 = 0;
        }else if(i == 4){
            RD4 = 1;
            __delay_ms(1);
            RD4 = 0;
        }else if(i == 5){
            RD5 = 1;
            __delay_ms(1);
            RD5 = 0;
        }else if(i == 6){
            RD6 = 1;
            __delay_ms(1);
            RD6 = 0;
        }else if(i == 7){
            RD7 = 1;
            __delay_ms(1);
            RD7 = 0;
        }
    }
}

/*フィールドにBlockデータをセットする*/
//セットするBlockの番号を指定
void matrix_set(int number)
{
    int x,y;

    x = 3;
    y = 7;
    active_block[0] = number;
    active_block[1] = x;
    active_block[2] = y;

    if(matrix[0][7] == 1 || matrix[1][7] == 1 || matrix[2][7] == 1 || matrix[3][7] == 1 || matrix[4][7] == 1 || matrix[5][7] == 1 || matrix[6][7] == 1 || matrix[7][7] == 1){
        mode = 2;
    }else if(number == BLOCK1){
        matrix[x][y] = 1;
        matrix[x+1][y] = 1;
        matrix[x][y-1] = 1;
        matrix[x+1][y-1] = 1;
    }else if(number == BLOCK2){
        matrix[x][y] = 1;
        matrix[x][y-1] = 1;
    }else if(number == BLOCK3){
        matrix[x][y] = 1;
        matrix[x][y-1] = 1;
        matrix[x+1][y-1] = 1;
    }else if(number == BLOCK4){
        matrix[x][y] = 1;
        matrix[x+1][y] = 1;
        matrix[x+1][y-1] = 1;
    }
}

/*ランダムでBlockを発生させる*/
//単純にrand()を使っているため、初期起動時は重複あり
void create(void)
{
    int number;

    number = rand()%4;
    matrix_set(number);
}

/*フィールドを巡回し、対象を削除*/
//削除できそうなy軸を指定
void delete(int y)
{
    int i,j,k;
    int cnt=0;

    for(i=y;i>=0;i--){
        for(j=0;j<8;j++){
            cnt += matrix[j][i];
        }
        if(cnt == 8){
            for(k=i;k<8;k++){
                for(j=0;j<8;j++){
                    if(k == 7){
                        matrix[j][k] = 0;
                    }else{
                        matrix[j][k] = matrix[j][k+1];
                    }
                }
            }
            delete_sum++;
        }
        cnt = 0;
    }
}

/*Blockの移動*/
//移動する方向を指定
//0:left 1:right 2:under
//一回の呼び出しで1ドット移動
void move(int direction)
{
    int x,y;

    x = active_block[1];
    y = active_block[2];
    if(direction == 0){//左移動
        if(active_block[0] == BLOCK1 && x >= 1 && matrix[x-1][y] == 0 && matrix[x-1][y-1] == 0){
            matrix[x][y] = 1;
            matrix[x][y-1] = 1;
            matrix[x-1][y] = 1;
            matrix[x-1][y-1] = 1;
            matrix[x+1][y] = 0;
            matrix[x+1][y-1] = 0;
            active_block[1] = x-1;
        }else if(active_block[0] == BLOCK2 && x >= 1 && matrix[x-1][y] == 0 && matrix[x-1][y-1] == 0){
            matrix[x-1][y] = 1;
            matrix[x-1][y-1] = 1;
            matrix[x][y] = 0;
            matrix[x][y-1] = 0;
            active_block[1] = x-1;
        }else if(active_block[0] == BLOCK3 && x >= 1 && matrix[x-1][y] == 0 && matrix[x-1][y-1] == 0){
            matrix[x][y-1] = 1;
            matrix[x-1][y] = 1;
            matrix[x-1][y-1] = 1;
            matrix[x][y] = 0;
            matrix[x+1][y-1] = 0;
            active_block[1] = x-1;
        }else if(active_block[0] == BLOCK4 && x >= 1 && matrix[x-1][y] == 0 && matrix[x][y-1] == 0){
            matrix[x-1][y] = 1;
            matrix[x][y] = 1;
            matrix[x][y-1] = 1;
            matrix[x+1][y] = 0;
            matrix[x+1][y-1] = 0;
            active_block[1] = x-1;
        }
    }else if(direction == 1){//右移動
        if(active_block[0] == BLOCK1 && x <= 5 && matrix[x+2][y] == 0 && matrix[x+2][y-1] == 0){
            matrix[x+1][y] = 1;
            matrix[x+1][y-1] = 1;
            matrix[x+2][y] = 1;
            matrix[x+2][y-1] = 1;
            matrix[x][y] = 0;
            matrix[x][y-1] = 0;
            active_block[1] = x+1;
        }else if(active_block[0] == BLOCK2 && x <= 6 && matrix[x+1][y] == 0 && matrix[x+1][y-1] == 0){
            matrix[x+1][y] = 1;
            matrix[x+1][y-1] = 1;
            matrix[x][y] = 0;
            matrix[x][y-1] = 0;
            active_block[1] = x+1;
        }else if(active_block[0] == BLOCK3 && x <= 5 && matrix[x+2][y-1] == 0 && matrix[x+1][y] == 0){
            matrix[x+1][y] = 1;
            matrix[x+1][y-1] = 1;
            matrix[x+2][y-1] = 1;
            matrix[x][y] = 0;
            matrix[x][y-1] = 0;
            active_block[1] = x+1;
        }else if(active_block[0] == BLOCK4 && x <= 5 && matrix[x+2][y] == 0 && matrix[x+2][y-1] == 0){
            matrix[x+2][y] = 1;
            matrix[x+2][y-1] = 1;
            matrix[x+1][y] = 1;
            matrix[x][y] = 0;
            matrix[x+1][y-1] = 0;
            active_block[1] = x+1;
        }
    }else{//下移動
        if(active_block[0] == BLOCK1 && y >= 2 && matrix[x][y-2] == 0 && matrix[x+1][y-2] == 0){
            matrix[x][y-2] = 1;
            matrix[x+1][y-2] = 1;
            matrix[x][y] = 0;
            matrix[x+1][y] = 0;
            active_block[2] = y-1;
        }else if(active_block[0] == BLOCK2 && y >= 2 && matrix[x][y-2] == 0 ){
            matrix[x][y-2] = 1;
            matrix[x][y] = 0;
            active_block[2] = y-1;
        }else if(active_block[0] == BLOCK3 && y >= 2 && matrix[x][y-2] == 0 && matrix[x+1][y-2] == 0){
            matrix[x][y-2] = 1;
            matrix[x+1][y-2] = 1;
            matrix[x][y] = 0;
            matrix[x+1][y-1] = 0;
            active_block[2] = y-1;
        }else if(active_block[0] == BLOCK4 && y >= 2 && matrix[x][y-1] == 0 && matrix[x+1][y-2] == 0){
            matrix[x][y-1] = 1;
            matrix[x+1][y-1] = 1;
            matrix[x+1][y-2] = 1;
            matrix[x][y] = 0;
            matrix[x+1][y] = 0;
            active_block[2] = y-1;
        }else{
            delete(y);
            flg = 1;
        }
    }
}

/*ゲーム開始時のアニメーション*/
void gamestart(void)
{
    int i;

    matrix_all(1);
    __delay_ms(150);
    matrix_all(1);
    matrix_vline(3,0);
    matrix_vline(4,0);
    __delay_ms(150);
    matrix_all(1);
    matrix_vline(2,0);
    matrix_vline(3,0);
    matrix_vline(4,0);
    matrix_vline(5,0);
    __delay_ms(150);
    for(i=0;i<75;i++){
        matrix_vline(0,1);
        matrix_vline(7,1);
    }
    matrix_all(0);
    __delay_ms(300);

    matrix_reset();
    create();
}

/*ゲーム終了時のアニメーション*/
void gameover(void)
{
    int i;

    matrix_all(0);
    __delay_ms(150);
    for(i=0;i<75;i++){
        matrix_vline(0,1);
        matrix_vline(7,1);
    }
    matrix_all(1);
    matrix_vline(2,0);
    matrix_vline(3,0);
    matrix_vline(4,0);
    matrix_vline(5,0);
    __delay_ms(150);
    matrix_all(1);
    matrix_vline(3,0);
    matrix_vline(4,0);
    __delay_ms(150);
    matrix_all(1);
    __delay_ms(300);

    matrix_reset();
}

/*バーLEDの表示、レベルメータ*/
//表示する本数を指定
void difficulty(int number)
{
    shift_register(number);
}

void shift_register(int number)
{
    int i;

    RC7 = 0;//クリア
    RC7 = 1;
  for(i=0;i<number;i++){
    RC4 = 0;//データセット
    RC4 = 1;
    RC6 = 0;//シフト
    RC6 = 1;
  }
  RC5 = 0;//ラッチ
  RC5 = 1;
}