邊玩遊戲邊運動
- 賴紀廷
- Feb 5, 2020
- 5 min read
Updated: Dec 7, 2020
邊玩遊戲邊運動
將Arduino變成USB鍵盤寫一個跳的Arduino程式用HC-SR04測距離的Arduino程式用MPU6050訊號轉換跳的keyboard指令用藍芽對接兩台Arduino用nRF24L01無線模組對接兩片綠板
將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.rar, Gsensor.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.c, hid_kb.c, hid_kb.h, main.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來測試隔空讓恐龍跳障礙物了
Comments