Arduino筆記(95):APDS9960 手勢感測器控制8x8 LED方向燈

繼前一篇使用 xantorohara.github.io 產生方向箭頭的 8x8 LED 矩陣程式碼後,接著繼續使用 APS9960 手勢感測器來當作方向控制,當往左方揮手時,方向燈箭頭往左移動;當手勢往右揮時,箭頭方向往右移動。
一開始撰寫程式,就因為讀取手勢值 readGesture()這個指令,它會讓程式停在這裡等候新的手勢變化,無法讓迴圈內的 LED燈產生動畫的效果。想改用硬體插斷的方式,結果不行。後來找了 Arduino_APDS9960 的函式庫,是否能偵測手勢的讀取,結果找到一個判斷是否有讀取值的函式 gestureAvailable(),才順利完成程式。以下就來看看如何完成手勢控制方向燈實作。


APDS-9960是一個極小的感測器,內置紫外線和紅外線阻隔濾鏡,四個單獨的二極體不同方向的敏感,以及一個I2C相容介面。其他規格如下:
  • 工作電壓:3.3V
  • 環境光及RGB色彩感應
  • 接近檢測
  • 手勢檢測
  • 測量範圍:4-8in (10-20CM)
  • I2C介面 (I2C位址:0x39)

[安裝APDS9960 Library]

Arduino_APDS9960 函式庫提供用於從 APDS-9960 手勢感測器,可以偵測環境光線讀取數據。本實作需要安裝以下程式庫: 您可以在 Arduino IDE的介面上的「管理程式庫」找到這個程式庫。有關程式庫(Library)安裝方法請參考另一篇文章:  Arduino筆記:安裝 Arduino IDE 程式庫(Library)

[材料]

  • Arduino Uno
  • APDS-9960 顏色、非接觸手勢檢測傳感器模組 x1
  • MAX7219 8x8 LED矩陣模組 x1
  • 連接線 x n

[接線圖]

Arduino UnoAPDS-99608x8 LED Matrix 模組
3.3VVCC-
GNDGNDGND
A5SCL-
A4SDA-
D2INT-
+5V-VCC
D10-CS
D11-CLK
D12-Data In(DIN)



[程式]

#include <Arduino_APDS9960.h>
#include <LedControl.h>

// Pin 12:Data in, Pin 11: Clock,  Pin 10: CS(Load)
LedControl display = LedControl(12,11,10,1);

const uint64_t R_IMAGES[] = {   //往右箭頭
  0x0000000100000000,
  0x0000010301000000,
  0x0001030703010000,
  0x0103070f07030100,
  0x02060f1f0f060200,
  0x040c1f3f1f0c0400,
  0x08183f7f3f180800,
  0x08183f7f3f180800,
  0x10307fff7f301000,
  0x2060fefefe602000,
  0x40c0fcfcfcc04000,
  0x8080f8f8f8808000,
  0x0000f0f0f0000000,
  0x0000e0e0e0000000,
  0x0000c0c0c0000000,
  0x0000808080000000,
  0x0000000000000000
};
const int R_IMAGES_LEN = sizeof(R_IMAGES)/8;

const uint64_t L_IMAGES[] = {   //往左箭頭
  0x0000008000000000,
  0x000080c080000000,
  0x0080c0e0c0800000,
  0x80c0e0f0e0c08000,
  0x4060f0f8f0604000,
  0x2030f8fcf8302000,
  0x1018fcfefc181000,
  0x080cfefffe0c0800,
  0x04067f7f7f060400,
  0x02033f3f3f030200,
  0x01011f1f1f010100,
  0x00000f0f0f000000,
  0x0000070707000000,
  0x0000030303000000,
  0x0000010101000000,
  0x0000000000000000
};
const int L_IMAGES_LEN = sizeof(L_IMAGES)/8;
int LastGesture = 0;   //紀錄最後一次的手勢
int i = 0;

void setup() {
  Serial.begin(115200);
  
  if(!APDS.begin()){
    Serial.println("failed to initialize device! Please check your wiring.");
  }
  else Serial.println("Detecting gestures ...");

  display.clearDisplay(0);    // 清除螢幕
  display.shutdown(0, false);  // 關閉省電模式
  display.setIntensity(0, 10); // 設定亮度為 8 (介於0~15之間)
}

void displayImage(uint64_t image) {
  for (int i = 0; i < 8; i++) {
    byte row = (image >> i * 8) & 0xFF;
    for (int j = 0; j < 8; j++) {
      display.setLed(0, i, j, bitRead(row, j));
    }
  }
}

void loop() {
  if (APDS.gestureAvailable()) {
    //讀取 APDS9960 的值
    uint8_t gesture = APDS.readGesture();
    if(gesture == GESTURE_DOWN) Serial.println("DOWN");
    if(gesture == GESTURE_UP) Serial.println("UP");
    
    if(gesture == GESTURE_LEFT) {
      Serial.println("LEFT");
      LastGesture = 1;
    }
    if(gesture == GESTURE_RIGHT) {
      Serial.println("RIGHT");
      LastGesture = 2;
    }
  }
  
  if (LastGesture == 1) {
    displayImage(L_IMAGES[i]);
    if (++i >= L_IMAGES_LEN ) {
      i = 0;
    }
    delay(10);      
  }
  if (LastGesture == 2) {
    displayImage(R_IMAGES[i]);
    if (++i >= R_IMAGES_LEN ) {
      i = 0;
    }
    delay(10);     
  }
}

[結果]


[參考資料]

Post a Comment

較新的 較舊