目錄
- STC8H開發(一): 在Keil5中配置和使用FwLib_STC8封裝庫(圖文詳解)
- STC8H開發(二): 在Linux VSCode中配置和使用FwLib_STC8封裝庫(圖文詳解)
- STC8H開發(三): 基於FwLib_STC8的模數轉換ADC介紹和演示用例說明
- STC8H開發(四): FwLib_STC8 封裝庫的介紹和使用注意事項
- STC8H開發(五): SPI驅動nRF24L01無線模塊
- STC8H開發(六): SPI驅動ADXL345三軸加速度檢測模塊
- STC8H開發(七): I2C驅動MPU6050三軸加速度+三軸角速度檢測模塊
- STC8H開發(八): NRF24L01無線傳輸音頻(對講機原型)
- STC8H開發(九): STC8H8K64U模擬USB HID外設
- STC8H開發(十): SPI驅動Nokia5110 LCD(PCD8544)
- STC8H開發(十一): GPIO單線驅動多個DS18B20數字溫度計
- STC8H開發(十二): I2C驅動AT24C08,AT24C32系列EEPROM存儲
- STC8H開發(十三): I2C驅動DS3231高精度實時時鍾芯片
- STC8H開發(十四): I2C驅動RX8025T高精度實時時鍾芯片
MPU-6050
MPU-6050是InvenSense生產的六軸運動跟蹤芯片, 芯片尺寸4×4×0.9mm, QFN封裝. 整合了三軸陀螺儀, 三軸加速度計, 片內溫度傳感器和數字運動處理器(DMP), 可以使用I2C接口外接三軸電子羅盤的輸入,提供完整的九軸運動融合輸出.
MPU-6050包含6個16位ADC, 3個用於陀螺儀輸出, 3個用於加速度計輸出. 用戶可以設置的陀螺儀滿量程范圍為±250,±500,±1000,±2000°/秒(dps), 可設置的加速度計滿量程范圍為±2g, ±4g, ±8g和±16g. 通信使用 400kHz的 I2C接口或 1MHz的 SPI接口(SPI僅MPU-6000可用).
關於I2C通信
在 FwLib_STC8 中, I2C 通信部分的頭文件代碼如下
typedef enum
{
I2C_MasterCmd_Wait = 0x00, // Wait, idle
I2C_MasterCmd_Start = 0x01, // START
I2C_MasterCmd_Send = 0x02, /* Send data. This command will generate 8 clocks on SCL, and
send I2CTXD to SDA bit by bit from MSB */
I2C_MasterCmd_RxAck = 0x03, /* Recive Ack. This command will generate 1 clock on SCL, and
save the received bit to MSACKI(I2CMSST.1) */
I2C_MasterCmd_Recv = 0x04, // Recive data
I2C_MasterCmd_TxAck = 0x05, /* Send Ack. This command will generate 1 clock on SCL, and
write the value of MSACKO(I2CMSST.0) to SDA */
I2C_MasterCmd_Stop = 0x06, // STOP. This command will send STOP signal, and reset MSBUSY flag
I2C_MasterCmd_StartSendRxAck = 0x09, // START + Send data + RxAck
I2C_MasterCmd_SendRxAck = 0x0A, // Send data + RxAck
I2C_MasterCmd_RecvTxAck0 = 0x0B, // Receive data + TxAck(0)
I2C_MasterCmd_RecvNAck = 0x0C, // Receive data + NAck
} I2C_MasterCmd_t;
#define I2C_SendMasterCmd(__CMD__) { \
(I2CMSCR) = (I2CMSCR) & ~(0x0F) | ((__CMD__) & 0x0F); \
while (!(I2CMSST & 0x40)); \
I2CMSST &= ~0x40; \
}
#define I2C_MasterStart() I2C_SendMasterCmd(I2C_MasterCmd_Start)
#define I2C_MasterSendData(__DATA__) do{I2CTXD = (__DATA__); I2C_SendMasterCmd(I2C_MasterCmd_Send);}while(0)
#define I2C_MasterRxAck() I2C_SendMasterCmd(I2C_MasterCmd_RxAck)
#define I2C_MasterAck() do{I2CMSST &= ~(0x01); I2C_SendMasterCmd(I2C_MasterCmd_TxAck);}while(0)
#define I2C_MasterNAck() do{I2CMSST |= 0x01; I2C_SendMasterCmd(I2C_MasterCmd_TxAck);}while(0)
#define I2C_MasterStop() I2C_SendMasterCmd(I2C_MasterCmd_Stop)
對這部分的說明如下:
STC8H 對 I2C 通信涉及的功能做了硬件封裝, 通過在 I2CMSCR 中寫入命令完成I2C操作. 命令執行的結束, 通過 I2CMSST 的 B6 判斷, 命令完成時這一位會置1, 需要軟件清零, 這就是這兩行代碼的作用
while (!(I2CMSST & 0x40)); \
I2CMSST &= ~0x40;
所有的命令執行完都要使用這兩行進行處理.
主設備往從設備的寫操作實現如下, 可以看到在每一個數據發送后, 都要用RxAck產生一個時鍾, 讀取從設備在SDA上產生的電平, 可以用於判斷是ACK還是NAK
uint8_t I2C_Write(uint8_t devAddr, uint8_t memAddr, uint8_t *dat, uint16_t size)
{
SFRX_ON();
I2C_MasterStart();
I2C_MasterSendData(devAddr & 0xFE);
I2C_MasterRxAck();
I2C_MasterSendData(memAddr);
I2C_MasterRxAck();
while(size--)
{
I2C_MasterSendData(*dat++);
I2C_MasterRxAck();
}
I2C_MasterStop();
SFRX_OFF();
return HAL_OK;
}
主設備對從設備的讀操作實現如下, 可以看到在寫地址部分和寫操作是一樣的, 在讀操作部分, 每次讀取完之后, 主設備會回寫ACK或NAK響應, 告訴從設備是否要繼續給主設備發送數據.
uint8_t I2C_Read(uint8_t devAddr, uint8_t memAddr, uint8_t *buf, uint16_t size)
{
SFRX_ON();
I2C_MasterStart();
I2C_MasterSendData(devAddr & 0xFE);
I2C_MasterRxAck();
I2C_MasterSendData(memAddr);
I2C_MasterRxAck();
I2C_MasterStart();
I2C_MasterSendData(devAddr | 0x01);
I2C_MasterRxAck();
while(size--)
{
I2C_SendMasterCmd(I2C_MasterCmd_Recv);
*buf++ = I2CRXD;
if (size == 0)
{
I2C_MasterNAck();
}
else
{
I2C_MasterAck();
}
}
I2C_MasterStop();
SFRX_OFF();
return HAL_OK;
}
I2C的響應問題
對於每一個從設備(slaver), 當它被尋址后, 都要求在接收到每一個字節后產生一個響應. 因此主設備必須產生一個額外的時鍾脈沖用於讀取從設備的響應.
在這個脈沖期間, 主設備釋放對SDA的控制, 從設備必須將SDA拉低並在時鍾的高電平期間保持住, 這代表返回了一個ACK; 如果不拉低SDA, 就代表返回了NACK.
在從設備發送完最后一個字節后, 主設備(讀取方)必須產生一個不響應位, 用以通知從設備不要再發送信息, 這樣從機就知道該將SDA釋放了, 而后主設備發出停止信號.
模塊與STC8H的接線
市面上的模塊, 一般是8個pin腳, 如果只是獲取6軸采樣和溫度, 與STC8H只需要連接4根線
P32 -> SCL
P33 -> SDA
GND -> GND
3.3V -> VCC
未連接的其它4個pin分別是
- XDA和XCL: I2C主設備接口, 用於外接I2C從設備,
- AD0: I2C從設備地址LSB
- INT: 中斷輸出
模塊與STC8H的通信
I2C頻率最高為400KHz, STC8H的設置如下, 其中I2C功能復用選擇的是P32/P33, 如果換到其它復用腳需要相應調整
void I2C_Init(void)
{
// 主節點模式
I2C_SetWorkMode(I2C_WorkMode_Master);
/**
* I2C 時鍾 = SYSCLK / 2 / (__prescaler__ * 2 + 4)
* MPU6050 works with i2c clock up to 400KHz
*
* 44.2368 / 2 / (26 * 2 + 4) = 0.39 MHz
*/
I2C_SetClockPrescaler(0x1A);
// 復用口選擇
I2C_SetPort(I2C_AlterPort_P32_P33);
// 啟動 I2C
I2C_SetEnabled(HAL_State_ON);
}
與MPU6050的通信可以直接使用SDK中的I2C讀寫方法, 需要注意的幾點
- 一次性讀出的雙字節結果, 如果直接轉uint16_t, 其高字節和低字節位置是相反的, 需要調換后再轉換
- 可以一次性讀出6軸+溫度數據
uint16_t swap(uint16_t num)
{
return (num >> 8) | (num << 8);
}
void MPU6050_Write(uint8_t addr, uint8_t dat)
{
I2C_Write(MPU6050_ADDR, addr, &dat, 1);
}
uint8_t MPU6050_Read(uint8_t addr)
{
uint8_t ret;
I2C_Read(MPU6050_ADDR, addr, &ret, 1);
return ret;
}
// 讀取16位數據
uint16_t MPU6050_ReadInt(uint8_t addr)
{
uint16_t ret;
I2C_Read(MPU6050_ADDR, addr, (uint8_t *)&ret, 2);
return swap(ret); // swap high/low bits for correct order
}
// 一次性讀取7個16位數據
void MPU6050_ReadAll(uint16_t *buf)
{
uint8_t i;
I2C_Read(MPU6050_ADDR, MPU6050_REG_ACCEL_XOUT_H, (uint8_t *)buf, 14);
for (i = 0; i < 7; i++)
{
*(buf + i) = swap(*(buf + i));
}
}
主要的寄存器設置
幾個可能會用到的寄存器說明
電源管理寄存器 0x6B 和 0x6C
這兩個寄存器控制了MPU6050的工作模式: 睡眠模式(Sleep), 節電模式(Cycle)和正常工作模式
- 睡眠模式: 0x6B 的第六位置1開啟, 睡眠模式下可以通信, 但是所有的檢測轉換都是停止的, 結果讀取的值都是0
- 節電模式: 是一種睡眠和正常交替的模式, MPU6050每隔一段時間做一次檢測轉換, 其余時間都處在睡眠狀態
- 進入節電模式, 需要將sleep位置0, cycle位置1, 禁止溫度采樣位置1, STBY_XG, STBY_YG, STBY_ZG置1
- 節點模式下的采樣頻率可以設置為 1.25Hz, 5Hz, 20Hz, 40Hz
- 正常模式: 正常模式按設置進行正常的檢測和轉換
在 0x6C 中, 還可以指定六個檢測軸中的哪些軸暫停檢測
采樣速率寄存器 0x19
這個寄存器用於設置陀螺儀輸出速率分頻系數, 采樣速率通過陀螺儀輸出速率除以此寄存器的值產生:
采樣速率 = 陀螺儀輸出速率 / (1 + SMPLRT_DIV)
其中, 禁用DLPF(低通過濾)時陀螺儀輸出速率為8KHz(DLPF_CFG = 0 or 7), 當啟用DLPF時為1KHz.
配置寄存器 0x1A
這個寄存器用於設置外部幀同步(FSYNC)引腳采樣和數字陀螺儀和加速度計的低通濾波器(DLPF). 連接到FSYNC引腳的外部信號可以通過配置EXT_SYNC_SET來采樣, FSYNC引腳的信號變化被鎖存, 以便捕捉信號, FSYNC信號將以寄存器0x19中定義的采樣速率進行采樣。采樣后鎖存器將復位到當前的FSYNC信號狀態.
- 位3,4,5: 設置FSYNC位的位置
- 位0,1,2: 取值0 - 6, 設置DLPF, 數字越大延遲越大.
角速度檢測(陀螺儀)配置寄存器 0x1B
這個寄存器用於設置角速度三軸的自檢和滿刻度范圍
加速度檢測配置寄存器 0x1C
這個寄存器用於設置加速度三軸的自檢和滿刻度范圍
模塊的中斷類型及設置
中斷功能通過中斷配置寄存器進行配置。 可配置的項目包括INT引腳配置,中斷鎖存和清除方法以及中斷觸發器。 可觸發中斷的項目有:
- 時鍾發生器鎖定到新的參考振盪器(用於切換時鍾源)
- 可以讀取新數據(來自FIFO和數據寄存器)
- 加速度計事件中斷
- MPU-6050 沒有收到輔助傳感器的確認I2C總線
中斷狀態可以從中斷狀態寄存器讀取。
檢測數據
MPU6050在檢測過程中, 根據采樣速率不斷輸出六軸加溫度的檢測值, 如果設置的滿刻度范圍較大, 則測量輸出的數字較小, 靈敏度較低, 要增加靈敏度可以調小滿刻度范圍. 相比較 ADXL345, MPU6050更適合運動中的物體檢測, 能檢測到更准確的運動中物體姿態變化, 同樣的, 如果沒有接入電子羅盤(磁強計), 只能得到俯仰角和橫滾角數據, 不能得到航向角數據.
演示代碼
演示代碼以100ms的時間間隔, 不斷讀取7個檢測數據並通過UART1串口輸出, 接線正確的話, 可以通過串口軟件觀察到模塊運動帶來的檢測值變化