--- tags: BW16, RTL8720, Ameba, Arduino, I2C, MPU6050, HMC5883L, 陀螺儀, 伴伴學 --- # BW16伴伴板 + I2C (MPU6050, HMC5883L) # BW16伴伴板 * 伴伴學社群開發板,主核心採用瑞昱的BW16 * 外拉GPIO腳位完全依照BW16排列,無額外NC腳 * 板載電源LED與一顆可控LED於PA12,上拉3.3V時發光 * UART接頭與常見6PIN FT232相對應,方便直連不需額外拉線 # I2C * IIC I2C TWI都是指一樣的東西,CLOCK與DATA兩條線 * 頻率由主機決定,每個設備端有一個不衝突的地址 * 每次傳輸固定8bit的資料為一個單位 * 主從式架構,只能由主機發送訊號啟始,設備端不可自行傳輸 起始訊號只有主機傳送資料或主機要求設備回傳資料兩種選擇 * 地址為7bit,但傳輸時會左移一個bit,最後一個bit為讀寫的設定 例如HMC5883L的地址為0x1E,僅發送資料時為0x3C,要求回傳資料時為0x3D * BW16接腳位置: SCL = PA25,SDA = PA26,正好是最底部兩個GPIO # MPU6050 * 6軸: 三軸加速度計與三軸陀螺儀 * 已停產,後續改用MPU9250(9軸)? * 搭配指南針可啟用DMP自動計算俯仰,細節未公開在文件中 I2CDEV函式庫有解讀成功,但每次開機須矯正 # HML5883L * 三軸指南針 # 程式資料 特別注意操作Bitwise控制時,最好的做法是先讀取原有數值,更改要變更的位置後再寫入 此次很剛好不需要保留原數值 ## I2C * 內建函式庫: Wire.h * 初始化: Wire.begin(); Wire.setClock(400000L); (預設為100KHz) * 傳送: Wire.beginTransmission(SLAVE_ADDR); Wire.write(REG_ADDR); Wire.write(DATA); Wire.endTransmission(true); * 讀取: Wire.beginTransmission(SLAVE_ADDR); Wire.write(REG_ADDR); (移動暫存器位置) Wire.endTransmission(false); Wire.requestFrom(SLAVE_ADDR, N, true); Wire.read(); (N times) ## MPU6050 僅加速度儀 * I2C地址: 0x68 (7bit) * 驗證正確讀取: 暫存器0x75 內容為0x68 暫存器位置: 10~12, 數值: 0x48,0x34, 0x33 * 運作頻率: 內部晶振8mHz, 關閉陀螺儀與溫度計,加速度計每秒採樣20次 暫存器位置: 0x6B, 數值: 0x28 暫存器位置: 0x6C, 數值: 0x87 * 低通過濾: 94Hz 暫存器位置: 0x1A, 數值: 0x02 * 加速度: +-2g 暫存器位置: 0x1C, 數值: 0x00 * 加速度資料: 暫存器位置: 0x3B~0x40, 數值: signed 16bit x3 * 標準化加速度數值: +-2G時: 16384 LSB/G :::spoiler 伴伴板讀取MPU6050加速度計 ```c= #include<Wire.h> const int MPU_ADDR = 0x68; #define MPU_ACC_CONST 16384 // for +-2G void mpu6050_init(){ // Set gyroscope range to +-1000 deg/s Serial1.println("Set to internal 8mHz clock."); Serial1.println("Turn off GYRO and TEMP and set sampling at 20Hz"); Wire.beginTransmission(MPU_ADDR); Wire.write(0x6B); // PWR_MGMT_1 and PWR_MGMT_2 Wire.write(0x28); Wire.write(0x87); Wire.endTransmission(true); delay(100); Serial1.println("Set Low-pass filiter to 94Hz"); Wire.beginTransmission(MPU_ADDR); Wire.write(0x1A); // CONFIG Wire.write(0x02); Wire.endTransmission(true); // Set accelerometer range to +-2g Serial1.println("Set accel to 2G"); Wire.beginTransmission(MPU_ADDR); Wire.write(0x1C); // ACCEL_CONFIG Wire.write(0x00); Wire.endTransmission(true); delay(100); } void mpu_read_acc(int16_t *x, int16_t *y, int16_t *z){ Wire.beginTransmission(MPU_ADDR); Wire.write(0x3B); Wire.endTransmission(false); Wire.requestFrom(MPU_ADDR, 6, true); *x = (Wire.read()<<8 | Wire.read()); *y = (Wire.read()<<8 | Wire.read()); *z = (Wire.read()<<8 | Wire.read()); } void setup() { Wire.begin(); Wire.setClock(400000L); Serial1.begin(115200); delay(100); mpu6050_init(); } void loop() { int16_t acc_x = 0; int16_t acc_y = 0; int16_t acc_z = 0; mpu_read_acc(&acc_x, &acc_y, &acc_z); //Serial1.print("ACC: "); Serial1.print((float)acc_x/MPU_ACC_CONST); Serial1.print(", "); Serial1.print((float)acc_y/MPU_ACC_CONST); Serial1.print(", "); Serial1.print((float)acc_z/MPU_ACC_CONST); Serial1.println(", "); delay(500); } ``` ::: ## HMC5883L * I2C地址: 0x1E (7bit) * 驗證正確讀取: 暫存器10~12 內容為"H43" 暫存器位置: 10~12, 數值: 0x48,0x34, 0x33 * 運作頻率: 8次平均,15Hz連續輸出 暫存器位置: 0, 數值: 0x70 暫存器位置: 2, 數值: 0x00 * 磁場資料: 暫存器位置: 3~8, 數值: signed 16bit x3 正常輸出為-2048~2047之間,若輸出為-4096則表示超過可偵測數值,調整Gain * 標準化磁場數值: +-1.3高斯時: 1090 LSB/Gauss :::spoiler 伴伴板讀取HMC5883L磁力表 ```c= #include<Wire.h> const int MAG_ADDR = 0x1E; #define MAG_SCALE_CONST 1090 // for +-1.3Ga void hmc5883l_init(){ // Disable sleep mode Serial1.println("Init HMC5883L"); Wire.beginTransmission(MAG_ADDR); Wire.write(0); // CONFIG REG A Wire.write(0x70); Wire.endTransmission(true); Wire.beginTransmission(MAG_ADDR); Wire.write(2); // MODE Wire.write(0x00); Wire.endTransmission(true); delay(100); } void hmc5883l_read_value(int16_t *x, int16_t *y, int16_t *z){ Wire.beginTransmission(MAG_ADDR); Wire.write(3); // 3~8 Wire.endTransmission(false); Wire.requestFrom(MAG_ADDR, 6, true); *x = (Wire.read()<<8 | Wire.read()); *y = (Wire.read()<<8 | Wire.read()); *z = (Wire.read()<<8 | Wire.read()); } void setup() { Wire.begin(); Wire.setClock(400000L); Serial1.begin(115200); delay(100); hmc5883l_init(); } void loop() { int16_t mag_x = 0; int16_t mag_y = 0; int16_t mag_z = 0; hmc5883l_read_value(&mag_x, &mag_y, &mag_z); //Serial1.print("MAG: "); Serial1.print((float)mag_x/MAG_SCALE_CONST); Serial1.print(", "); Serial1.print((float)mag_y/MAG_SCALE_CONST); Serial1.print(", "); Serial1.print((float)mag_z/MAG_SCALE_CONST); Serial1.println(", "); delay(500); } ``` ::: # 參考資料 ## 瑞昱 BW16 * 官方網站: https://www.amebaiot.com/zh/ameba-arduino-summary/ * 官方github: https://github.com/ambiot/ambd_arduino/ * BW16模塊接腳圖: ![模塊接腳圖](https://github.com/mikey60/BW16-RTL8720DN-Module-Arduino/raw/main/Info/RTL8720DN_Pinout_Small.png) ## 伴伴學與伴伴板 * 伴伴學共筆: https://hackmd.io/@accomdemy/SJsr63mkt * 伴伴板開發共筆: https://hackmd.io/y3AZWm9URGGaHvRV8FjrMg ## I2C模塊相關資料 * Arduino I2CDev非官方函式庫: https://github.com/jrowberg/i2cdevlib * I2C介紹: https://magicjackting.pixnet.net/blog/post/173061691 * I2C範例: https://forum.arduino.cc/t/i2c-protocol-tutorial-using-an-mpu6050/387512 * MPU6050資料: https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf * MPU6050暫存器表: https://invensense.tdk.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf * HMC5883L資料: https://cdn-shop.adafruit.com/datasheets/HMC5883L_3-Axis_Digital_Compass_IC.pdf