top of page
Writer's picture賴紀廷

邊玩遊戲邊運動

Updated: Dec 7, 2020

邊玩遊戲邊運動

📷 📷

將Arduino變成USB鍵盤

Arduino Uno板上有一顆Atmega16U2,是一顆具有USB功能的微控制器

在出廠時它預先燒錄具有「USB轉序列埠」功能的韌體,於是可作為電腦USB埠與Arduino板微控制器序列埠之間的中介橋樑

我們可以讓Atmega16U2進入DFU(Device Firmware Update)模式,便可更新韌體,燒錄別的功能,譬如變成USB鍵盤,從Arduino板子傳送「按鍵」給電腦

📷

下載並安裝電腦端的DFU燒錄軟體JRE-FlipInstaller.exe並安裝讓Arduino Uno進入DFU模式,需重置16U2,作法是讓下圖的兩個腳位接觸一下(只需一下即可),其中一個是GND接地,另一個是RESET腳位,接觸一下即可重置📷重置後,Windows電腦端就會發現硬體選擇剛剛的Flip安裝目錄裡的usb子目錄,裡頭含有驅動程式📷完成後在裝置管理員裡便可看到ATmega16U2📷下載Arduino-keyboard.zip裡頭含有能讓Arduino板不斷送出「hello world」的草稿碼(helloworld/helloworld.pde),還有8U2/16U2的新韌體(Arduino-keyboard-0.3.hex),能讓Arduino Uno板變成USB鍵盤讓16U2的RESET腳位接觸GND接地,一下即可,便可進入DFU模式,然後開啟Flip,出現如下畫面📷點按左上角看起來像是晶片的圖示,或是選「Device-Select...」,選擇ATmega16U2,確定📷點按看起來像USB插頭的圖示,然後點按「USB」;或是選「Settings-Communication-USB」📷畫面便會從灰色變成彩色📷選「File-Load HEX File...」,選擇剛剛下載的Arduino-keyboard-0.3.hex韌體,點按左下「Run」進行燒錄,然後點按右下的「Start Application」重置此時Arduino板便會是USB鍵盤,不斷地送出「hello world」,請隨便開啟一個文字編輯器,便會看到類似下圖的樣子📷如果要改回原有的Arduino,請「File-Load HEX File...」時選擇Arduino-usbserial-uno.hex韌體,燒錄後重置即可

寫一個讓Mario跳的Arduino程式

int jumpButton = 0;
uint8_t keyNone[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };  //keyboard for RELEASE 
uint8_t keyJUMP[8] = { 0, 0, 29, 0, 0, 0, 0, 0 };    //keyboard for JUMP (ascii code 'z')

void setup() {
  Serial.begin (9600); 
}

void loop() {
  Serial.write(keyJUMP, 8);  // Send keystroke to PC
  Serial.write(keyNone, 8);  // Release key   
  delay(500);
}

寫好後燒錄到Arduino上之後讓Atmega16U2進入DFU模式,並燒錄Arduino-keyboard-0.3.hex韌體,然後拔掉重插Arduino此時Arduino變成是一個每0.5秒傳輸跳指令的鍵盤,請打開MARIO遊戲測試一下

用HC-SR04測距離的Arduino程式

📷

📷

int trigPin = 11;                  //Trig Pin
int echoPin = 12;                  //Echo Pin
long duration, cm;
long val = 0;

void setup() {
  Serial.begin (9600);             // Serial Port begin
  pinMode(trigPin, OUTPUT);        //Define inputs and outputs 
  pinMode(echoPin, INPUT);
}
 
void loop(){
  digitalWrite(trigPin, LOW);
  delayMicroseconds(5);
  digitalWrite(trigPin, HIGH);     // 給 Trig 高電位,持續 10微秒
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  pinMode(echoPin, INPUT);             // 讀取 echo 的電位
  duration = pulseIn(echoPin, HIGH);   // 收到高電位時的時間
  val = (duration/2) / 29.1;         // 將時間換算成距離 cm
  Serial.print("Distance : ");  
  Serial.print(val);
  Serial.print("cm");
  Serial.println();
  delay(200);
}

用MPU6050訊號轉換跳的keyboard指令

📷

#include "I2Cdev.h"
#include "MPU6050.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif
MPU6050 accelgyro;
//MPU6050 accelgyro(0x69); // -- use for AD0 high
int16_t ax, ay, az;
int16_t gx, gy, gz;
int jumpButton =0;
uint8_t keyNone[8]={0,0,0,0,0,0,0,0};
uint8_t keyJUMP[8]={0,0,44,0,0,0,0,0,}; //29=z, 44=spacebar
int oldAZ=18000;
int absDiff=0;

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif
    Serial.begin(9600);
    accelgyro.initialize();

}

void loop() {
    // read raw accel/gyro measurements from device
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
    // these methods (and a few others) are also available
    //accelgyro.getAcceleration(&ax, &ay, &az);
    //accelgyro.getRotation(&gx, &gy, &gz);
    #ifdef OUTPUT_READABLE_ACCELGYRO
        // display tab-separated accel/gyro x/y/z values
        //Serial.print("a/g:\t");
        //Serial.print(ax); Serial.print("\t");
        //Serial.print(ay); Serial.print("\t");
        //Serial.print(az); Serial.print("\t");
        //Serial.print(gx); Serial.print("\t");
        //Serial.print(gy); Serial.print("\t");
        //Serial.println(gz);
    #endif
    #ifdef OUTPUT_BINARY_ACCELGYRO
        //Serial.write((uint8_t)(ax >> 8)); Serial.write((uint8_t)(ax & 0xFF));
        //Serial.write((uint8_t)(ay >> 8)); Serial.write((uint8_t)(ay & 0xFF));
        //Serial.write((uint8_t)(az >> 8)); Serial.write((uint8_t)(az & 0xFF));
        //Serial.write((uint8_t)(gx >> 8)); Serial.write((uint8_t)(gx & 0xFF));
        //Serial.write((uint8_t)(gy >> 8)); Serial.write((uint8_t)(gy & 0xFF));
        //Serial.write((uint8_t)(gz >> 8)); Serial.write((uint8_t)(gz & 0xFF));
    #endif
   absDiff = az - oldAZ;
   if(absDiff>5000){
    Serial.write(keyJUMP,8);
    delay(3); 
    Serial.write(keyNone,8);
   }
   oldAZ = az;
   delay(100);
}

用藍芽對接兩台Arduino

📷

藍牙模組有「主控端 MASTER」和「從端 SLAVE」兩種模式,在配對時,一定是由「主控端」主導,探索其他「從端」並與之配對連線;從端無法彼此互連。

每個藍牙模組都有一個唯一的位址,主控端模組可透過AT+BIND命令來配對要控制的從端位址

設定好之後,它就能在通電(開機)時,自動探索並和指定位址的從端相連,不需要Arduino介入

設定前需要先連好裝置如下:

📷📷

Slave端設定

AT+RMAAD (刪除之前的所有配對設備)AT+ROLE=0 (設定這顆藍芽模組為Slave)AT+ADDR (取得這顆HC-05的地址,請將它記錄下來貼在模組上)AT+UART=38400,0,0 (設定baud rate為38400)

Master端設定

AT+RMAAD (刪除之前的所有配對設備)AT+ROLE=1 (設定這顆藍芽模組為master)AT+CMODE=0 (AT+CMODE=0 #代表只與已配對的從端相連, AT+CMODE=1 #代表能與任何從端相連)AT+BIND=xxxx,xx,xxxxxx (配對從端的模組地址,請注意是用逗號','分隔,而不是用冒號':'分隔)AT+UART=38400,0,0 (設定baud rate為38400)

用nRF24L01無線模組對接兩片綠板

下載完整專案檔:Keyboard.rarGsensor.rar

nRF24L01是挪威Nordic半導體公司設計的無線收發器晶片,工作在世界通用、免許可證的ISM 2.4GHz頻段具備價格低廉、省電、程式設計簡單且通訊可靠等優點,廣泛用於無線鍵盤、滑鼠、門禁系統…等無線通訊和控制產品

📷

nRF24L01溝通架構

該模組可使用125個頻道每個頻道可以有6個地址互相溝通

📷

Receiver接收端設定

接收端ARM板需要在收到指令後,執行一個按空白鍵的動作,讓恐龍跳起來,所以必須將ARM板加入USB HID Keyboard的功能首先我們參考Nuvoton的範例程式在WengNANO\NUVOTON\Nano100B_Series_BSP_CMSIS_V3.02.000\Nano100B Series BSP_CMSIS_V3.02.000\SampleCode\StdDriver\USBD_HID_Keyboard 或者到 Nuvoton的Github儲存庫查看範例程式所需要的函式庫,另外新建一個專案叫MyHIDKeyboard,將所需的函式庫加入其中(Core,Startup,CLK,FMC,SYS,USB)複製範例程式資料夾中的4個C程式檔(descriptors.chid_kb.chid_kb.hmain.c)貼在我們新建的專案資料夾中,並在Keil加入這4個檔案新增一個RFinput.c檔,將何老師範例程式中的nRF24l01p的程式內容複製到該檔案中,並且在專案的Manage Runtime Environment函式庫加入SPI(因為RF24L01是用SPI做通訊)上述步驟完成後專案的畫面應該如下:📷 加上SysTick程式碼:把何老師範例程式中的Systick加入main.cRF無線模組的設定:打開main.c,在SysTick的init()function中加入NRF的初始化設定📷 我們想用SW2(Switch按鈕)來測試用HID USB傳輸到PC是否成功:所以去參考電路圖查看到SW2的接腳是PB2📷 因為恐龍的跳是用鍵盤上的空白鍵,因此我們去參考HIDUsageTables.pdf的第54頁,找到空白鍵相對應的UsageID(空白鍵Spacebar = 0x2C)📷 然後將HID USB傳送到PC的function寫成一個HID_Send()函式,並且在SW2被按下時呼叫這個函式,傳一個空白鍵📷 最後修改main()函式,在while迴圈中加入以下📷 編譯後燒錄到主板上,用一條USB線將主板上的USB孔接到PC,就可以用SW2按鈕來測試是否有傳空白鍵了

Sender傳送端設定

傳輸端ARM板需要在偵測到G-Sensor的跳動後,透過RF24L01模組傳輸一個空白鍵給接收端首先開一個新的專案叫MyGSensor,加入函式庫(Core,Startup,CLK,UART,SPI,SYS)新增一個RFoutput.c檔,將何老師範例程式中的nRF24l01p的程式內容複製到該檔案中拷貝RFoutput.c上面的開放函式拷貝到main.c的最上方📷 新增一個myi2c.c檔,將何老師範例程式中的i2c的程式內容複製到該檔案中為了驅動Gsensor(MPU6050),將何老師範例程式中的MPU6050程式內容複製到i2c.c的最下面📷 新增一個main.c,加入何老師範例程式中的main()、UART0()程式RF無線模組的設定:打開main.c,在SysTick的init()function中加入NRF的初始化設定📷 最後修改main()函式,加入Gsensor初始化及判斷,並透過nRF傳送資料的程式📷 編譯後燒錄到主板上,就可以用GSensor來測試隔空讓恐龍跳障礙物了

157 views0 comments

Comments


bottom of page