1. 程式人生 > >【linux】i2c使用分析&原始碼實戰

【linux】i2c使用分析&原始碼實戰

[toc] --- ## 前言 * **目前不涉及驅動原始碼** * [原文](https://www.cnblogs.com/lizhuming/p/14063151.html) ## 1. 裝置檢查命令 ### 1.1 檢視I2C驅動 * 命令:**`ls /sys/bus/i2c/devices`** 用於檢視系統上存在的 I2C 匯流排 ### 1.2 i2c-tools * i2c-tools,安裝 i2c-tools 方便除錯 i2c裝置 #### 1.2.1 I2C-detect安裝 * 使用命令:**`sudo apt install i2c-tools -y`** 安裝 i2c-tools * 安裝後可以使用命令:**i2cdetect、i2cdump、i2cset** 和 **i2cget** #### 1.2.2 i2cdetect 命令 * i2cdetect * 用於掃描 I2C 總線上的裝置 * 語法 * **`i2cdetect [-y] [-a] [-q|-r] i2cbus [first last]`** * 引數 * **y**:關閉互動模式,使用該引數時,不會提示警告資訊。 * **a**:掃描總線上的所有裝置 * **q**:使用SMBus的“quick write”命令進行檢測,不建議使用該引數 * **r**:使用SMBus的“receive byte”命令進行檢測,不建議使用該引數 * **i2cbus**:指定i2c匯流排的編號 * **first、last**:掃描的地址範圍 * 返回值 * '-':表示該地址被檢測,但是沒有晶片應答 * 'UU':表示該地址當前由核心驅動程式使用 * '\*\*':\*\* 表示以16進製表示的裝置地址編號,如“68” * 例子: * **`i2cdetect -a 0`** * **i2cdetect**:i2cdetect命令 * **-a**:總線上所有裝置 * **0**:標號為 **0** 的 I2C,即是 I2C 1。 * ![](https://img2020.cnblogs.com/blog/2085252/202011/2085252-20201130193933743-85279157.png) * 上圖中掃描出存在裝置地址為 **0x1e** 和 **0x68** 的裝置。 * **`i2cdetect -F i2cbus`**:查詢 i2c 匯流排的功能,引數 i2cbus 表示 i2c 匯流排(*看上*) * **`i2cdetect -V`**:列印軟體的版本號 * **`i2cdetect -l`**:檢測當前系統有幾組 i2c 匯流排 #### 1.2.3 i2cget 命令 * i2cget * 用於讀取 I2C 裝置的某個暫存器的值 * 語法 * **`i2cget [-f] [-y] i2cbus chip-address [data-address [mode]]`** * 引數 * **f**:強制訪問 * **y**:關閉互動模式,使用該引數時,不會提示警告資訊 * **i2cbus**:指定 I2C 匯流排的編號 * **chip-address**:I2C 裝置地址 * **data-address**:I2C 暫存器地址 * **mode**:指定讀取的大小, 可以是b, w, s或i,分別對應了位元組,字,SMBus塊, I2C塊 #### 1.2.4 i2cset 命令 * i2cset * 寫入指定 I2C 裝置的某個暫存器的值 * 語法 * **`i2cset [-f] [-y] [-m mask] [-r] i2cbus chip-address data-address [value] … [mode]`** * 引數 * **f**:強制訪問 * **y**:關閉互動模式,使用該引數時,不會提示警告資訊 * **m**: * **r**:寫入後立即回讀暫存器值,並將結果與寫入的值進行比較 * **i2cbus**:指定 I2C 匯流排的編號 * **chip-address**:I2C 裝置地址 * **data-address**:I2C 暫存器地址 * **value**:要寫入的值 * **mode**:指定讀取的大小, 可以是b, w, s或i,分別對應了位元組,字,SMBus塊, I2C塊 #### 1.2.5 i2cdump 命令 * i2cdump * 讀取指定裝置的全部暫存器的值 * 語法 * **`i2cdump [-f] [-r first-last] [-y] i2cbus address [mode [bank [bankreg]]]`** * 引數 * **r**:指定暫存器範圍,只能掃描從 **first** 到 **last** 區域 * **f**:強制訪問裝置 * **y**:關閉人機互動模式 * **i2cbus**:指定 I2C 匯流排的編號 * **address**:指定裝置地址 * **mode**:指定讀取的大小, 可以是b, w, s或i,分別對應了位元組,字,SMBus塊, I2C塊 * 例子 * **`i2cdump -V`**:列印軟體的版本號 ## 2. 原始碼實戰 * 採用MPU6050裝置進行實驗 * 步驟: * 先編寫基礎的 I2C 基礎函式 * 編寫 MPU6050 初始化函式和關閉裝置檔案函式 * 編寫獲取 MPU6050 資料函式 * 編寫業務函式 ### 2.1 編寫 bsp_mpu6050.h 檔案 * 編寫好 MPU6050 需要的巨集 * extern 外部函式 ```c /** @file         bsp_mpu6050.h  *  @brief        簡要說明  *  @details      詳細說明  *  @author       lzm  *  @date         2020-11-28 19:22:20  *  @version      v1.0  *  @copyright    Copyright By lizhuming, All Rights Reserved  *  **********************************************************  *  @LOG 修改日誌:  ********************************************************** */ #ifndef _BSP_MPU6050_H_  #define _BSP_MPU6050_H_ /* 巨集 */ #define SMPLRT_DIV                                  0x19 #define CONFIG                                      0x1A #define GYRO_CONFIG                                 0x1B #define ACCEL_CONFIG                                0x1C #define ACCEL_XOUT_H                                0x3B #define ACCEL_XOUT_L                                0x3C #define ACCEL_YOUT_H                                0x3D #define ACCEL_YOUT_L                                0x3f #define ACCEL_ZOUT_H                                0x3F #define ACCEL_ZOUT_L                                0x40 #define TEMP_OUT_H                                  0x41 #define TEMP_OUT_L                                  0x42 #define GYRO_XOUT_H                                 0x43 #define GYRO_XOUT_L                                 0x44 #define GYRO_YOUT_H                                 0x45 #define GYRO_YOUT_L                                 0x46 #define GYRO_ZOUT_H                                 0x47 #define GYRO_ZOUT_L                                 0x48 #define PWR_MGMT_1                                  0x6B #define WHO_AM_I                                    0x75 #define SlaveAddress                                0xD0 #define Address                                     0x68                  //MPU6050地址 #define I2C_RETRIES                                 0x0701 #define I2C_TIMEOUT                                 0x0702 #define I2C_SLAVE                                   0x0703       //IIC從器件的地址設定 #define I2C_BUS_MODE                                0x0780 /* 型別轉換 */ typedef unsigned char uint8_t; /* 函式 */ uint8_t mpu6050_init(char * i2cDev); void    mpu6050_close(void); short   getData(unsigned char regAddr); #endif /* #define _BSP_MPU6050_H_ */ ``` ### 2.2 編寫 bsp_mpu6050.c 檔案 * bsp_mpu6050.c * 編寫 I2C 讀寫函式 * 編寫 MPU6050 裝置初始化函式及關閉檔案函式 * 編寫獲取 MPU6050 裝置暫存器資料函式 ```c /** @file         bsp_mpu6050.c  *  @brief        簡要說明  *  @details      詳細說明  *  @author       lzm  *  @date         2020-11-28 19:20:20  *  @version      v1.0  *  @copyright    Copyright By lizhuming, All Rights Reserved  *  **********************************************************  *  @LOG 修改日誌:  ********************************************************** */ /* 標頭檔案 */ #include #include #include #include #include #include #include #include #include #include "bsp_mpu6050.h" /* 裝置控制代碼 */ int i2cFd; // i2c裝置控制代碼 /**   * @brief  i2c 寫   * @param  fd:i2c裝置控制代碼   * @param  regAddr:暫存器地址   * @param  val:需要寫入的值   * @retval 0:寫入成功   * @retval -1:寫入失敗   * @author lzm   */ static uint8_t i2c_write(int fd, uint8_t regAddr, uint8_t val) {     int cnt; // 寫入失敗後,重複寫入的次數     uint8_t data[2]; // data[0]為暫存器地址,data[1]為需要寫入的值     data[0] = regAddr;     data[1] = val;     for(cnt=5; cnt>
0; cnt--)     {         if(write(fd, data, 2) == 2)             return 0; // 寫入成功     }     return -1; // 寫入失敗 } /**   * @brief  i2c 讀   * @param  fd:i2c裝置控制代碼   * @param  regAddr:暫存器地址   * @param  val:讀取到資料儲存的地方   * @retval 0:讀取成功   * @retval -1:讀取失敗   * @author lzm   */ static uint8_t i2c_read(int fd, uint8_t regAddr, uint8_t * val) {     int cnt; // 讀取失敗後,重新讀取的次數     for(cnt=5; cnt>
0; cnt--)     {         if(write(fd, ®Addr, 1) == 1)         {             if(read(fd, val, 1) == 1)                 return 0;         }     }     return -1; } /**   * @brief  mpu6050初始化   * @param  i2cDev   * @retval 1:初始化成功   * @retval 0:初始化失敗   * @author lzm   */ uint8_t mpu6050_init(char * i2cDev) {     i2cFd = open(i2cDev, O_RDWR); // 開啟i2c裝置檔案     if(i2cFd < 0)     {         printf("Can't open %s!\n", i2cDev);         exit(1);     }     printf("Open %s success!", i2cDev);     if(ioctl(i2cFd, I2C_SLAVE, Address) < 0)     {         printf("fail to set i2c device slave address!");         close(i2cFd); // 關閉i2c裝置檔案         return -1;     }     printf("set slave address to 0x%x success!", Address);     i2c_write(i2cFd, PWR_MGMT_1, 0X00);     i2c_write(i2cFd, SMPLRT_DIV, 0X07);     i2c_write(i2cFd, CONFIG, 0X06);     i2c_write(i2cFd, ACCEL_CONFIG, 0X01);     return 1; } /**   * @brief  關閉裝置檔案   * @param     * @retval    * @author lzm   */ void mpu6050_close(void) {     close(i2cFd); } /**   * @brief  獲取資料   * @param  regAddr:暫存器地址   * @retval 獲取到的資料   * @author lzm   */ short getData(unsigned char regAddr) {     char chH; // 高位元組     char chL; // 低位元組     i2c_read(i2cFd, regAddr, &chH);     usleep(1000);     i2c_read(i2cFd, regAddr, &chL);     return ((chH << 8) + chL); } ``` ### 2.3 編寫 main.c 檔案 * 編寫業務函式 ```c /** @file         main.c  *  @brief        簡要說明  *  @details      詳細說明  *  @author       lzm  *  @date         2020-11-28 19:18:20  *  @version      v1.0  *  @copyright    Copyright By lizhuming, All Rights Reserved  *  **********************************************************  *  @LOG 修改日誌:  ********************************************************** */ #include #include #include #include
#include #include #include #include #include #include "mpu6050/bsp_mpu6050.h" int main(int argc, char * argv[]) {     /* 程式開始標語 */     printf("This is a mpu6050 test!\n");     /* 初始化 MCPU6050 */     mpu6050_init("/dev/i2c-0");     sleep(1);     /* mpu6050 應用測試 */     while(1)     {         printf("get mpu6050 data!\n");         usleep(1000 * 100);         printf("ACCE_X:%6d\n ", getData(ACCEL_XOUT_H));         usleep(1000 * 100);         printf("ACCE_Y:%6d\n ", getData(ACCEL_YOUT_H));         usleep(1000 * 100);         printf("ACCE_Z:%6d\n ", getData(ACCEL_ZOUT_H));         usleep(1000 * 100);         printf("GYRO_X:%6d\n ", getData(GYRO_XOUT_H));         usleep(1000 * 100);         printf("GYRO_Y:%6d\n ", getData(GYRO_YOUT_H));         usleep(1000 * 100);         printf("GYRO_Z:%6d\n\n ", getData(GYRO_ZOUT_H));         sleep(1);     }     /* 退出 mpu6050 */     mpu6050_close(); } ``` ## 相關連結 * [原始碼](https://gitee.com/lidreaming/demo_code_for_mystudy/tree/master/linux/i