Arduino + 乒乓球遊戲之8×8點陣應用


在本應用中,我們將使用的點矩陣是8×8矩陣,這意味著它具有8列8行,因此總共包含64個LED。

Arduino + 乒乓球遊戲之8×8點陣應用

MAX7219芯片僅需使用Arduino電路板的3個數字引腳,即可更輕鬆地控制點矩陣。我認為最好的選擇是購買以MAX7219芯片為模塊的點矩陣,這將簡化佈線。

Arduino + 乒乓球遊戲之8×8點陣應用

您一次可以控制多個矩陣。為此,您只需要將它們彼此連接即可,因為它們的兩側都有引腳以擴展點矩陣。

所需部件

對於本應用,您需要:

  • 1x 8×8點矩陣,帶有MAX7219
  • 跳線
  • Arduino UNO
  • 引腳接線

    您只需要將5個引腳從點矩陣連接到Arduino開發板即可。接線非常簡單:

    點矩陣針 接線到Arduino Uno

    地線 地線

    VCC 5伏

    DIN標準 數碼針

    CS 數碼針

    時鐘 數碼針

    如何使用Arduino控制點矩陣

    為了使控制點矩陣更加容易,您需要下載並在Arduino IDE中安裝LedControl庫。要安裝該庫,請按照下列步驟操作:

    1. 單擊此處下載LedControl庫。您的下載中應該有一個.zip文件夾

    2. 解壓縮.zip文件夾,您應該得到LedControl-master文件夾

    3. 重命名文件夾 到LedControl

    4. 將LedControl 文件夾移至Arduino IDE安裝 文件夾

    5. 最後,重新打開您的Arduino IDE

    使用LedControl庫函數

    在點矩陣上顯示內容的最簡單方法是使用setLed(),setRow()或setColumn()函數。這些功能使您可以一次控制一個LED,一行或一列。

    這是每個函數的參數:

    setLed(addr,row,col,state)

    · addr是矩陣的地址,例如,如果只有1個矩陣,則int addr將為零。

    · row是led所在的行

    · col是led所在的列

    · state

    · 如果您要打開LED,則為true或1

    · 如果為假,則為false或0

    setRow(addr,row,value)

    setCol(addr,column,value)

    指數

    如前所述,此矩陣有8列和8行。每個索引的索引範圍都是0到7。下面是一個更好理解的模型:

    Arduino + 乒乓球遊戲之8×8點陣應用

    如果要在矩陣中顯示某些內容,則只需要知道確定的行或列中的LED是打開還是關閉。

    例如,如果您想露出笑臉,這是您需要做的:

    Arduino + 乒乓球遊戲之8×8點陣應用

    源代碼

    這是一個簡單的草圖,其中顯示三種類型的面孔:悲傷的面孔,中性的面孔和幸福的面孔。將以下代碼上傳到您的開發板上:

    #include "LedControl.h"

    #include "binary.h"

    /*

    DIN connects to pin 12

    CLK connects to pin 11

    CS connects to pin 10

    */

    LedControl lc=LedControl(12,11,10,1);

    // delay time between faces

    unsigned long delaytime=1000;

    // happy face

    byte hf[8]= {B00111100,B01000010,B10100101,B10000001,B10100101,B10011001,B01000010,B00111100};

    // neutral face

    byte nf[8]={B00111100, B01000010,B10100101,B10000001,B10111101,B10000001,B01000010,B00111100};

    // sad face

    byte sf[8]= {B00111100,B01000010,B10100101,B10000001,B10011001,B10100101,B01000010,B00111100};

    void setup() {

    lc.shutdown(0,false);

    // Set brightness to a medium value

    lc.setIntensity(0,8);

    // Clear the display

    lc.clearDisplay(0);

    }

    void drawFaces(){

    // Display sad face

    lc.setRow(0,0,sf[0]);

    lc.setRow(0,1,sf[1]);

    lc.setRow(0,2,sf[2]);

    lc.setRow(0,3,sf[3]);

    lc.setRow(0,4,sf[4]);

    lc.setRow(0,5,sf[5]);

    lc.setRow(0,6,sf[6]);

    lc.setRow(0,7,sf[7]);

    delay(delaytime);

    // Display neutral face

    lc.setRow(0,0,nf[0]);

    lc.setRow(0,1,nf[1]);

    lc.setRow(0,2,nf[2]);

    lc.setRow(0,3,nf[3]);

    lc.setRow(0,4,nf[4]);

    lc.setRow(0,5,nf[5]);

    lc.setRow(0,6,nf[6]);

    lc.setRow(0,7,nf[7]);

    delay(delaytime);

    // Display happy face

    lc.setRow(0,0,hf[0]);

    lc.setRow(0,1,hf[1]);

    lc.setRow(0,2,hf[2]);

    lc.setRow(0,3,hf[3]);

    lc.setRow(0,4,hf[4]);

    lc.setRow(0,5,hf[5]);

    lc.setRow(0,6,hf[6]);

    lc.setRow(0,7,hf[7]);

    delay(delaytime);

    }

    void loop(){

    drawFaces();

    }


    乒乓球比賽

    對於乒乓遊戲,您只需要在前面的原理圖中添加一個1k歐姆的電位器即可。組裝新電路,如下所示:

    Arduino + 乒乓球遊戲之8×8點陣應用

    源代碼

    然後,將以下代碼上傳到您的Arduino開發板:

    #include "LedControl.h"

    #include "Timer.h"

    #define POTPIN A5 // Potentiometer

    #define PADSIZE 3

    #define BALL_DELAY 200

    #define GAME_DELAY 10

    #define BOUNCE_VERTICAL 1

    #define BOUNCE_HORIZONTAL -1

    #define NEW_GAME_ANIMATION_SPEED 50

    #define HIT_NONE 0

    #define HIT_CENTER 1

    #define HIT_LEFT 2

    #define HIT_RIGHT 3

    //#define DEBUG 1

    byte sad[] = {

    B00000000,

    B01000100,

    B00010000,

    B00010000,

    B00000000,

    B00111000,

    B01000100,

    B00000000

    };

    byte smile[] = {

    B00000000,

    B01000100,

    B00010000,

    B00010000,

    B00010000,

    B01000100,

    B00111000,

    B00000000

    };

    Timer timer;

    LedControl lc = LedControl(12,11,10,1);

    byte direction; // Wind rose, 0 is north

    int xball;

    int yball;

    int yball_prev;

    byte xpad;

    int ball_timer;

    void setSprite(byte *sprite){

    for(int r = 0; r < 8; r++){

    lc.setRow(0, r, sprite[r]);

    }

    }

    void newGame() {

    lc.clearDisplay(0);

    // initial position

    xball = random(1, 7);

    yball = 1;

    direction = random(3, 6); // Go south

    for(int r = 0; r < 8; r++){

    for(int c = 0; c < 8; c++){

    lc.setLed(0, r, c, HIGH);

    delay(NEW_GAME_ANIMATION_SPEED);

    }

    }

    setSprite(smile);

    delay(1500);

    lc.clearDisplay(0);

    }

    void setPad() {

    xpad = map(analogRead(POTPIN), 0, 1020, 8 - PADSIZE, 0);

    }

    void debug(const char* desc){

    #ifdef DEBUG

    Serial.print(desc);

    Serial.print(" XY: ");

    Serial.print(xball);

    Serial.print(", ");

    Serial.print(yball);

    Serial.print(" XPAD: ");

    Serial.print(xpad);

    Serial.print(" DIR: ");

    Serial.println(direction);

    #endif

    }

    int checkBounce() {

    if(!xball || !yball || xball == 7 || yball == 6){

    int bounce = (yball == 0 || yball == 6) ? BOUNCE_HORIZONTAL : BOUNCE_VERTICAL;

    #ifdef DEBUG

    debug(bounce == BOUNCE_HORIZONTAL ? "HORIZONTAL" : "VERTICAL");

    #endif

    return bounce;

    }

    return 0;

    }

    int getHit() {

    if(yball != 6 || xball < xpad || xball > xpad + PADSIZE){

    return HIT_NONE;

    }

    if(xball == xpad + PADSIZE / 2){

    return HIT_CENTER;

    }

    return xball < xpad + PADSIZE / 2 ? HIT_LEFT : HIT_RIGHT;

    }

    bool checkLoose() {

    return yball == 6 && getHit() == HIT_NONE;

    }

    void moveBall() {

    debug("MOVE");

    int bounce = checkBounce();

    if(bounce) {

    switch(direction){

    case 0:

    direction = 4;

    break;

    case 1:

    direction = (bounce == BOUNCE_VERTICAL) ? 7 : 3;

    break;

    case 2:

    direction = 6;

    break;

    case 6:

    direction = 2;

    break;

    case 7:

    direction = (bounce == BOUNCE_VERTICAL) ? 1 : 5;

    break;

    case 5:

    direction = (bounce == BOUNCE_VERTICAL) ? 3 : 7;

    break;

    case 3:

    direction = (bounce == BOUNCE_VERTICAL) ? 5 : 1;

    break;

    case 4:

    direction = 0;

    break;

    }

    debug("->");

    }

    // Check hit: modify direction is left or right

    switch(getHit()){

    case HIT_LEFT:

    if(direction == 0){

    direction = 7;

    } else if (direction == 1){

    direction = 0;

    }

    break;

    case HIT_RIGHT:

    if(direction == 0){

    direction = 1;

    } else if(direction == 7){

    direction = 0;

    }

    break;

    }

    // Check orthogonal directions and borders ...

    if((direction == 0 && xball == 0) || (direction == 4 && xball == 7)){

    direction++;

    }

    if(direction == 0 && xball == 7){

    direction = 7;

    }

    if(direction == 4 && xball == 0){

    direction = 3;

    }

    if(direction == 2 && yball == 0){

    direction = 3;

    }

    if(direction == 2 && yball == 6){

    direction = 1;

    }

    if(direction == 6 && yball == 0){

    direction = 5;

    }

    if(direction == 6 && yball == 6){

    direction = 7;

    }

    // "Corner" case

    if(xball == 0 && yball == 0){

    direction = 3;

    }

    if(xball == 0 && yball == 6){

    direction = 1;

    }

    if(xball == 7 && yball == 6){

    direction = 7;

    }

    if(xball == 7 && yball == 0){

    direction = 5;

    }

    yball_prev = yball;

    if(2 < direction && direction < 6) {

    yball++;

    } else if(direction != 6 && direction != 2) {

    yball--;

    }

    if(0 < direction && direction < 4) {

    xball++;

    } else if(direction != 0 && direction != 4) {

    xball--;

    }

    xball = max(0, min(7, xball));

    yball = max(0, min(6, yball));

    debug("AFTER MOVE");

    }

    void gameOver() {

    setSprite(sad);

    delay(1500);

    lc.clearDisplay(0);

    }

    void drawGame() {

    if(yball_prev != yball){

    lc.setRow(0, yball_prev, 0);

    }

    lc.setRow(0, yball, byte(1 << (xball)));

    byte padmap = byte(0xFF >> (8 - PADSIZE) << xpad) ;

    #ifdef DEBUG

    //Serial.println(padmap, BIN);

    #endif

    lc.setRow(0, 7, padmap);

    }

    void setup() {

    // The MAX72XX is in power-saving mode on startup,

    // we have to do a wakeup call

    pinMode(POTPIN, INPUT);

    lc.shutdown(0,false);

    // Set the brightness to a medium values

    lc.setIntensity(0, 8);

    // and clear the display

    lc.clearDisplay(0);

    randomSeed(analogRead(0));

    #ifdef DEBUG

    Serial.begin(9600);

    Serial.println("Pong");

    #endif

    newGame();

    ball_timer = timer.every(BALL_DELAY, moveBall);

    }

    void loop() {

    timer.update();

    // Move pad

    setPad();

    #ifdef DEBUG

    Serial.println(xpad);

    #endif

    // Update screen

    drawGame();

    if(checkLoose()) {

    debug("LOOSE");

    gameOver();

    newGame();

    }

    delay(GAME_DELAY);

    }

    最後

    您是否曾經在Arduino項目中使用過點矩陣?如果您喜歡這篇文章,可能您還會喜歡我的下一篇文章,敬請期待。謝謝閱讀,


    分享到:


    相關文章: