一,I2C總線介紹
?
I2C(Inter-Integrated Circuit 集成電路)總線是Philips公司在八十年代初推出的一種串行、半雙工的總 線,主要用于近距離、低速的芯片之間的通信;I2C總線有兩根雙向的信號線,一根數據線SDA用于收 發數據,一根時鐘線SCL用于通信雙方時鐘的同步;I2C總線硬件結構簡單,簡化了PCB布線,降低了系 統成本,提高了系統可靠性,因此在各個領域得到了廣泛應用。
I2C總線是一種多主機總線,連接在 I2C總線上的器件分為主機和從機。主機有權發起和結束一次通信,從機只能被動呼叫;當總線上有多個主機同時啟用總線時,I2C也具備沖突檢測和仲裁的功能來防 止錯誤產生;每個連接到I2C總線上的器件都有一個唯一的地址(7bit),傳輸數據的設備間是簡單的 主/從關系,每個器件都可以作為主機也可以作為從機(但同一時刻只能有一個機),總線上的器件增加和刪除不影響其他器件正常工作;I2C總線在通信時總線上發送數據的器件為發送器,接收數據的 器件為接收器。
I2C總線可以通過外部連線進行在線檢測,便于系統故障診斷和調試,故障可以立即被尋址,軟件也有 利于標準化和模塊化,縮短開發時間。 串行的8位雙向數據傳輸速率在標準模式下可達100Kbit/s,快速模式下可達400Kbit/s,高速模式下可達3.4Mbit/s。
二,通信過程
1. 主機發送起始信號啟用總線
2. 主機發送一個字節數據指明從機地址和后續字節的傳送方向
3. 被尋址的從機發送應答信號回應主機
4. 發送器發送一個字節數據
5. 接收器發送應答信號回應發送器
6. ........ (循環步驟4、5)
7. 通信完成后主機發送停止信號釋放總線
注意點:
第4步和第5步用的是發送器和接收器,不是主機和從機,這是由第一個字節的最后一位決定主給從發,還是從給主發。也就是說,第一個字節和最后的停止信號一定是主機發給從機,但中間就不一定了。
發送數據過程中不允許改變發送方向.
三、I2C總線的信號類型
I2C總線在傳送數據過程中共有3種類型信號:開始信號、結束信號和響應信號。
3.1 開始信號(S)和結束信號(P)
開始信號:SCL 為高電平時,SDA由高電平向低電平跳變,開始傳送數據
結束信號:SCL 為高電平時,SDA由低電平向高電平跳變,結束傳送數據

起始信號和停止信號都是由主機發出,起始信號產生后總線處于占用狀態,停止信號產生后總線被釋 放,處于空閑狀態。(空閑時,SCL與SDA都是高電平。)
IIC停止通信的情況有兩種:
1. 主機不想發了,就發送停止信號;
2. 從機不想接了,不應答,主機就發送停止信號結束此次通信。
3.2 響應信號(ACK)
????????接收器在接收到8位數據后,在第9個時鐘周期,拉低SDA電平
需要注意:SDA上傳輸的數據必須在SCL為高電平期間保持穩定,SDA上的數據只能在SCL為低電平期間變化
SCL和SDA發送數據的電平轉換圖
四、IIC總線的數據傳輸格式
?
I2C總線通信時每個字節為8位長度,數據傳送時,先傳送最高位(MSB),后傳送低位,發送器發送完一 個字節數據后接收器必須發送1位應答位來回應發送器,即一幀共有9位。

啟動一個傳輸時,主機先發送S信號,然后發出8位數據。這8位數據中前7位為從機的地址,第8位表示 傳輸的方向(0表示寫操作,1表示讀操作)。從機收到后會發出一個ACK信號.

注意:
主機接收器在接收到最后一個字節后,也不會發出ACK信號。于是,從機發送器釋放SDA線,以許主 機發出P信號結束傳輸。
五,i.MX6ull I2C控制器介紹
?
Inter IC (I2C)提供標準I2C從機和主機的功能。I2C被設計為兼容標準 NXP I2C總線協議。
I2C是一種雙線雙向串行總線,它提供了一種簡單有效的數據交換方法, 最大限度地減少了設備之間的互連。這種總線適用于需要在許多設備之間 偶爾進行短距離通信的應用。靈活的I2C標準允許將其他設備連接到總線 上,以進行擴展和系統開發。
5.1 II2C控制器設計

5.2 Clocks
?
I2C有兩個輸入時鐘。
I2C的時鐘源說明如下表所示。請參閱時鐘控制器模塊(CCM)時鐘設置,
配置和門控信息。

Peripheral clock: This clock is used for peripheral bus register read/writes.
(外圍時鐘:這個時鐘用于外圍總線寄存器讀/寫)
Module clock: This is the functional clock of the I2C. The serial bit clock frequency is derived from the module clock. The module clock and peripheral clocks are synchronous with each other. The
minimum frequency of the module clock should be 12.8 MHz for Fast mode to achieve 400-kbps
operation.
(模塊時鐘:這是I2C的功能時鐘。串行位時鐘頻率來源于模塊時鐘。模塊時鐘與外設時鐘是同步的。在Fast模式下,模塊時鐘的最小頻率應為12.8 MHz,以實現400kbps的工作。)
5.3 Arbitration procedure(仲裁程序)
1,如果多個設備同時請求總線,總線時鐘由一個同步過程確定,其中低周期 等于設備中最長的時鐘低周期,高周期等于最短的時鐘低周期。數據仲裁 程序決定了競爭設備的相對優先級。
2,如果一個設備發送高邏輯而另一個發送低邏輯,則失去仲裁;立即切換到Slave Receive模式,停止驅動I2Cn_SDA。在這種情況下,從主模式到從模式的轉換不會生成Stop條件。同時,硬件在I2C狀態寄存器(I2C_I2SR[IAL]表示仲裁丟失)中設置仲裁丟失位。
5.4 Initialization sequence(初始化順序)
?
1,初始化程序完成后,可以通過選擇主傳輸模式來發送串行數據。在多主總 線系統中,需要測試忙碌的總線(I2C_I2SR[IBB])以確定串行總線是否 空閑。如果總線是空閑的(IBB = 0),則可以發送起始信號和第一個字 節(從機地址)。寫入數據寄存器的數據包括所需從機的地址,并且最低有效位指示傳輸方向
2,停止和下一個開始條件之間的空閑時間內置在生成開始周期的硬件中。根據系統時鐘和SCL周期的相對頻率,在將調用地址寫入數據寄存器(I2C_I2DR)后,可能需要等到I2C不忙,然后再將數據加載到數據寄存器(I2C_I2DR)中
5.6 Generation of Stop(停止的產生)
?
數據傳輸結束時,主站發出停止信號,這可能發生在所有數據發送后。對 于主接收器終止數據傳輸,它必須通過不確認最后一個數據字節來通知從 站發送器。這是通過在讀取倒數第二個字節之前設置傳輸確認位 (I2C_I2CR[TXAK])來完成的。在讀取最后一個字節之前,必須生成停
止信號。
5.7 Generation of Repeated Start(重復啟動的產生)
在數據傳輸之后,如果主站仍然需要總線,它可以發出另一個啟動信號, 后面跟著另一個從站地址,而不用發出停止信號
5.8 Post-transfer software response(傳輸后軟件響應)
?
發送或接收一個字節設置數據傳輸位(I2C_I2SR[ICF]),表示一個字節的 通信完成。完成后,中斷狀態(I2C_I2SR[IIF])也被設置。如果設置了中 斷使能(I2C_I2CR[IIEN]),則會產生外部中斷。軟件必須首先清除中斷 例程中的中斷狀態(I2C_I2SR[IIF])。
數據傳輸位(I2C_I2SR[ICF])通過在接收模式下從I2C_I2DR讀取或在 傳輸模式下寫入該寄存器來清除。
六,代碼實現
IIC的驅動程序相比較pwm,adc,gpt復雜了許多,存在軟件IIC和硬件IIC.使用哪一種取決于電路中是否含有硬件IIC的電路.硬件IIC要比軟件IIC簡單,不需要對特定的操作進行延時(此次案例于光環境傳感器,AP3216進行通信)
?
1,軟件IIC
IIC代碼
#include "i2c.h"void i2c_gpio_init(){//tx初始化 alt5 gpio工作模式IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO28 &=~(0xf<<0);IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO28 |=(0x5<<0);//rx初始化 工作模式同上IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO29 &=~(0xf<<0);IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO29 |=(0x5<<0);//延時delay_ms(5);return ;
}void i2c_start_signal(){SCL_OUT_MODE();SDA_OUT_MODE();SCL_OUTPUT_LEVEL(HIGH);SDA_OUTPUT_LEVEL(HIGH);delay_ms(5);SDA_OUTPUT_LEVEL(LOW);delay_ms(5);
}void i2c_stop_signal(){SCL_OUT_MODE();SDA_OUT_MODE();SCL_OUTPUT_LEVEL(LOW);SDA_OUTPUT_LEVEL(LOW);delay_ms(5);SCL_OUTPUT_LEVEL(HIGH);delay_ms(5);SDA_OUTPUT_LEVEL(HIGH);delay_ms(5);
}
//delay_ms(10);
void i2c_write_data(uint_fast8_t data){SDA_OUT_MODE();SCL_OUTPUT_LEVEL(LOW);int i;uint_fast8_t level;for(i=0;i<8;i++){//由高到低去寫level = data>>7 & 1;SDA_OUTPUT_LEVEL(level);delay_ms(5);SCL_OUTPUT_LEVEL(HIGH);delay_ms(5);SCL_OUTPUT_LEVEL(LOW);data = data << 1;}
}
//delay_ms(1);
uint_fast8_t i2c_read_data(){uint_fast8_t data = 0;//設置SDA的模式為輸入SDA_IN_MODE();//設置SCL的電平狀態SCL_OUTPUT_LEVEL(LOW);delay_ms(5);//MSB先寫int i;for(i=0;i<8;i++){SCL_OUTPUT_LEVEL(HIGH);delay_ms(1);int level = SDA_INPUT_LEVEL();data <<=1;data|=level;SCL_OUTPUT_LEVEL(LOW);delay_ms(1);}return data;
}//接收端向發送端發送ACK
void i2c_receive_to_transmit_ack(){//設置SDA的方向為輸出SDA_OUT_MODE();//將SCL和SDA拉低SCL_OUTPUT_LEVEL(LOW);SDA_OUTPUT_LEVEL(LOW);delay_ms(5);//SDA保持低電平,SCL切換到高電平SCL_OUTPUT_LEVEL(HIGH);delay_ms(5);
}//接收端向發送端發送NACK
void i2c_receive_to_transmit_nack(){//設置SDA的方向為輸出SDA_OUT_MODE();//將SCL和SDA拉低SCL_OUTPUT_LEVEL(LOW);SDA_OUTPUT_LEVEL(HIGH);delay_ms(5);//SDA保持高電平,SCL切換到高電平SDA_OUTPUT_LEVEL(HIGH);delay_ms(5);
}//等待接收端向發送端發送應答信號
int i2c_wait_receive_to_transmit_signal(){//SDA為輸入SDA_IN_MODE();SCL_OUTPUT_LEVEL(LOW);delay_ms(5);SCL_OUTPUT_LEVEL(HIGH);delay_ms(5);int timeout = 0;int level=0;do{level = SDA_INPUT_LEVEL();//uart_printf("%d\r\n",level);delay_us(20);//兩次讀或寫操作之間需要延時timeout++;if(timeout>50){uart_printf("data transmit stop!\r\n");i2c_stop_signal();return -1;}}while(level);return 0;}
傳感器及測試代碼
//AP3216C_SENSOR_H
#include "ap3216c_sensor.h"void ap3216c_write_data_to_sensor(uint_fast8_t registerAddr,uint_fast8_t val){//1.主機向從機發送開始信號i2c_start_signal();//2.發送從機地址i2c_write_data(AP3216_WRITE_ADDRESS);//3.主機等待從機應答信號int ret = i2c_wait_receive_to_transmit_signal();if(ret ==-1){return;}//4.發送寄存器地址i2c_write_data(registerAddr);ret = i2c_wait_receive_to_transmit_signal();if(ret == -1){return;}//5.向相應的寄存器寫數據i2c_write_data(val);ret = i2c_wait_receive_to_transmit_signal();if(ret == -1){return;}//6.發送停止信號i2c_stop_signal();
}uint_fast8_t ap3216c_read_data_to_sensor(uint_fast8_t registerAddr){//1.主機向從機發送開始信號uint_fast8_t data;i2c_start_signal();//2.發送從機地址i2c_write_data(AP3216_WRITE_ADDRESS);//3.主機等待從機應答信號int ret = i2c_wait_receive_to_transmit_signal();if(ret ==-1){return;}//4.發送寄存器地址i2c_write_data(registerAddr);//5.主機等待從機應答信號ret = i2c_wait_receive_to_transmit_signal();if(ret == -1){return;}//6.主機向從機發送開始信號i2c_start_signal();//7.發送從機地址i2c_write_data(AP3216_READ_ADDRESS);//8.讀取數據ret = i2c_wait_receive_to_transmit_signal();if(ret == -1){return;}data = i2c_read_data();//9.發送NASK信號i2c_receive_to_transmit_nack();//10..發送停止信號i2c_stop_signal();return data;
}//配置ap3216傳感器
void ap3216c_sensor_config(){//uart_printf("no");//1.復位ap3216c [sw reset 100]//ap3216c_write_data_to_sensor(AP3216_SYSTEM_CONFIGRATION_ADDRESS,0x04);delay_ms(10);//2.激活 ALS + PS+IRap3216c_write_data_to_sensor(AP3216_SYSTEM_CONFIGRATION_ADDRESS,0x03);//delay_ms(10);//3.讀取uint_fast8_t ret = ap3216c_read_data_to_sensor(AP3216_SYSTEM_CONFIGRATION_ADDRESS);if(ret == 0x03){uart_printf("ap3216 communication success!\r\n");}
}//讀取ALS的數據
uint_fast16_t ap3216c_sensor_read_als(){//1.初始化GPIO管腳i2c_gpio_init();//2.配置ap3216的傳感器ap3216c_sensor_config();//3.讀取數據uint_fast16_t data=0;uint_fast8_t data_low = ap3216c_read_data_to_sensor(AP3216_ALS_DATA_LOW_ADDRESS);uint_fast8_t data_high = ap3216c_read_data_to_sensor(AP3216_ALS_DATA_HIGH_ADDRESS);data = data_high << 8| data_low;return data;
}uint_fast16_t ap3216c_sensor_read_ps(){//1.初始化GPIO管腳i2c_gpio_init();//2.配置ap3216的傳感器ap3216c_sensor_config();//3.讀取數據uint_fast16_t data=0;uint_fast8_t data_low = ap3216c_read_data_to_sensor(AP3216_PS_DATA_LOW_ADDRESS);uint_fast8_t data_high = ap3216c_read_data_to_sensor(AP3216_PS_DATA_HIGH_ADDRESS);// if(data_high & 0x40){// uart_printf("Invalid IR\r\n");//}data = data_high & (0x3f);data <<=4;data |= ((data_low)& 0xf);return data;
}void ap3216_sensor_als_test(){while(1){uint_fast16_t data_als = ap3216c_sensor_read_als();uart_printf("als:%d\r\n",data_als);}}void ap3216_sensor_ps_test(){while(1){uint_fast16_t data_ps = ap3216c_sensor_read_ps();uart_printf("ps:%d\r\n",data_ps);}}
2,硬件IIC
IIC代碼
#include "bsp_i2c.h"
#include "stdio.h"/** @description : 初始化I2C,波特率100KHZ* @param - base : 要初始化的IIC設置* @return : 無*/
void i2c_init(I2C_Type *base) {/* 1、配置I2C */base->I2CR &= ~(1 << 7); /* 要訪問I2C的寄存器,首先需要先關閉I2C *//* 設置波特率為100K* I2C的時鐘源來源于IPG_CLK_ROOT=66Mhz* IC2 時鐘 = PERCLK_ROOT/dividison(IFDR寄存器)* 設置寄存器IFDR,IFDR寄存器參考IMX6UL參考手冊P1260頁,表29-3,* 根據表29-3里面的值,挑選出一個還是的分頻數,比如本例程我們* 設置I2C的波特率為100K, 因此當分頻值=66000000/100000=660.* 在表29-3里面查找,沒有660這個值,但是有640,因此就用640,* 即寄存器IFDR的IC位設置為0X15*/base->IFDR = 0X15 << 0;/** 設置寄存器I2CR,開啟I2C* bit[7] : 1 使能I2C,I2CR寄存器其他位其作用之前,此位必須最先置1*/base->I2CR |= (1 << 7);
}/** @description : 發送重新開始信號* @param - base : 要使用的IIC* @param - addrss : 設備地址* @param - direction : 方向* @return : 0 正常 其他值 出錯*/
unsigned char i2c_master_repeated_start(I2C_Type *base, unsigned char address,enum i2c_direction direction) {/* I2C忙并且工作在從模式,跳出 */if (base->I2SR & (1 << 5) && (((base->I2CR) & (1 << 5)) == 0))return 1;/** 設置寄存器I2CR* bit[4]: 1 發送* bit[2]: 1 產生重新開始信號*/base->I2CR |= (1 << 4) | (1 << 2);/** 設置寄存器I2DR* bit[7:0] : 要發送的數據,這里寫入從設備地址* 參考資料:IMX6UL參考手冊P1249*/base->I2DR =((unsigned int)address << 1) | ((direction == kI2C_Read) ? 1 : 0);return 0;
}/** @description : 發送開始信號* @param - base : 要使用的IIC* @param - addrss : 設備地址* @param - direction : 方向* @return : 0 正常 其他值 出錯*/
unsigned char i2c_master_start(I2C_Type *base, unsigned char address,enum i2c_direction direction) {if (base->I2SR & (1 << 5)) /* I2C忙 */return 1;/** 設置寄存器I2CR* bit[5]: 1 主模式* bit[4]: 1 發送*/base->I2CR |= (1 << 5) | (1 << 4);/** 設置寄存器I2DR* bit[7:0] : 要發送的數據,這里寫入從設備地址* 參考資料:IMX6UL參考手冊P1249*/base->I2DR =((unsigned int)address << 1) | ((direction == kI2C_Read) ? 1 : 0);return 0;
}/** @description : 檢查并清除錯誤* @param - base : 要使用的IIC* @param - status : 狀態* @return : 狀態結果*/
unsigned char i2c_check_and_clear_error(I2C_Type *base, unsigned int status) {/* 檢查是否發生仲裁丟失錯誤 */if (status & (1 << 4)) {base->I2SR &= ~(1 << 4); /* 清除仲裁丟失錯誤位 */base->I2CR &= ~(1 << 7); /* 先關閉I2C */base->I2CR |= (1 << 7); /* 重新打開I2C */return I2C_STATUS_ARBITRATIONLOST;} else if (status & (1 << 0)) /* 沒有接收到從機的應答信號 */{return I2C_STATUS_NAK; /* 返回NAK(No acknowledge) */}return I2C_STATUS_OK;
}/** @description : 停止信號* @param - base : 要使用的IIC* @param : 無* @return : 狀態結果*/
unsigned char i2c_master_stop(I2C_Type *base) {unsigned short timeout = 0xffff;/** 清除I2CR的bit[5:3]這三位*/base->I2CR &= ~((1 << 5) | (1 << 4) | (1 << 3));/* 等待忙結束 */while ((base->I2SR & (1 << 5))) {timeout--;if (timeout == 0) /* 超時跳出 */return I2C_STATUS_TIMEOUT;}return I2C_STATUS_OK;
}/** @description : 發送數據* @param - base : 要使用的IIC* @param - buf : 要發送的數據* @param - size : 要發送的數據大小* @param - flags : 標志* @return : 無*/
void i2c_master_write(I2C_Type *base, const unsigned char *buf,unsigned int size) {/* 等待傳輸完成 */while (!(base->I2SR & (1 << 7)));base->I2SR &= ~(1 << 1); /* 清除標志位 */base->I2CR |= 1 << 4; /* 發送數據 */while (size--) {base->I2DR = *buf++; /* 將buf中的數據寫入到I2DR寄存器 */while (!(base->I2SR & (1 << 1))); /* 等待傳輸完成 */base->I2SR &= ~(1 << 1); /* 清除標志位 *//* 檢查ACK */if (i2c_check_and_clear_error(base, base->I2SR))break;}base->I2SR &= ~(1 << 1);i2c_master_stop(base); /* 發送停止信號 */
}/** @description : 讀取數據* @param - base : 要使用的IIC* @param - buf : 讀取到數據* @param - size : 要讀取的數據大小* @return : 無*/
void i2c_master_read(I2C_Type *base, unsigned char *buf, unsigned int size) {volatile uint8_t dummy = 0;dummy++; /* 防止編譯報錯 *//* 等待傳輸完成 */while (!(base->I2SR & (1 << 7)));base->I2SR &= ~(1 << 1); /* 清除中斷掛起位 */base->I2CR &= ~((1 << 4) | (1 << 3)); /* 接收數據 *//* 如果只接收一個字節數據的話發送NACK信號 */if (size == 1)base->I2CR |= (1 << 3);dummy = base->I2DR; /* 假讀 */while (size--) {while (!(base->I2SR & (1 << 1))); /* 等待傳輸完成 */base->I2SR &= ~(1 << 1); /* 清除標志位 */if (size == 0) {i2c_master_stop(base); /* 發送停止信號 */}if (size == 1) {base->I2CR |= (1 << 3);}*buf++ = base->I2DR;}
}/** @description : I2C數據傳輸,包括讀和寫* @param - base: 要使用的IIC* @param - xfer: 傳輸結構體* @return : 傳輸結果,0 成功,其他值 失敗;*/
unsigned char i2c_master_transfer(I2C_Type *base, struct i2c_transfer *xfer) {unsigned char ret = 0;enum i2c_direction direction = xfer->direction;base->I2SR &= ~((1 << 1) | (1 << 4)); /* 清除標志位 *//* 等待傳輸完成 */while (!((base->I2SR >> 7) & 0X1)) {};/* 如果是讀的話,要先發送寄存器地址,所以要先將方向改為寫 */if ((xfer->subaddressSize > 0) && (xfer->direction == kI2C_Read)) {direction = kI2C_Write;}ret =i2c_master_start(base, xfer->slaveAddress, direction); /* 發送開始信號 */if (ret) {return ret;}while (!(base->I2SR & (1 << 1))) {}; /* 等待傳輸完成 */ret = i2c_check_and_clear_error(base, base->I2SR); /* 檢查是否出現傳輸錯誤 */if (ret) {i2c_master_stop(base); /* 發送出錯,發送停止信號 */return ret;}/* 發送寄存器地址 */if (xfer->subaddressSize) {do {base->I2SR &= ~(1 << 1); /* 清除標志位 */xfer->subaddressSize--; /* 地址長度減一 */base->I2DR = ((xfer->subaddress) >>(8 * xfer->subaddressSize)); // 向I2DR寄存器寫入子地址while (!(base->I2SR & (1 << 1))); /* 等待傳輸完成 *//* 檢查是否有錯誤發生 */ret = i2c_check_and_clear_error(base, base->I2SR);if (ret) {i2c_master_stop(base); /* 發送停止信號 */return ret;}} while ((xfer->subaddressSize > 0) && (ret == I2C_STATUS_OK));if (xfer->direction == kI2C_Read) /* 讀取數據 */{base->I2SR &= ~(1 << 1); /* 清除中斷掛起位 */i2c_master_repeated_start(base, xfer->slaveAddress,kI2C_Read); /* 發送重復開始信號和從機地址 */while (!(base->I2SR & (1 << 1))) {}; /* 等待傳輸完成 *//* 檢查是否有錯誤發生 */ret = i2c_check_and_clear_error(base, base->I2SR);if (ret) {ret = I2C_STATUS_ADDRNAK;i2c_master_stop(base); /* 發送停止信號 */return ret;}}}/* 發送數據 */if ((xfer->direction == kI2C_Write) && (xfer->dataSize > 0)) {i2c_master_write(base, xfer->data, xfer->dataSize);}/* 讀取數據 */if ((xfer->direction == kI2C_Read) && (xfer->dataSize > 0)) {i2c_master_read(base, xfer->data, xfer->dataSize);}return 0;
}
傳感器及測試代碼
#include "ap3216c.h"
#include "string.h"
#include <stdint.h>
#include <stdio.h>struct i2c_transfer ap3216;
uint8_t res;void AP3216_W_Data(uint8_t registerAddr, uint8_t val)
{ap3216.data = &val;ap3216.dataSize = 1;ap3216.subaddressSize = 1;ap3216.subaddress = registerAddr;ap3216.direction = kI2C_Write;ap3216.slaveAddress = AP3216_ADDRESS;res = i2c_master_transfer(I2C1, &ap3216);if (res){uart_printf("Write 失敗 \r\n");}
}uint8_t AP3216_R_Data(uint8_t registerAddr)
{uint8_t data;ap3216.data = &data;ap3216.dataSize = 1;ap3216.subaddressSize = 1;ap3216.subaddress = registerAddr;ap3216.direction = kI2C_Read;ap3216.slaveAddress = AP3216_ADDRESS;res = i2c_master_transfer(I2C1, &ap3216);if (res){uart_printf("Read 失敗 \r\n");}return data;
}// 配置ap3216傳感器
void AP3216_Init()
{IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO28 &= ~(0xf << 0);IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO28 |= (0x2 << 0);// rx初始化 工作模式同上IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO29 &= ~(0xf << 0);IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO29 |= (0x2 << 0);// 打開時鐘CCM->CCGR2 |= (0x3 << 6);// 復位i2c_init(I2C1);AP3216_W_Data(AP3216_SYSTEM_CONFIGRATION_ADDRESS, 0x04);// 2.激活 ALS + PS+IRAP3216_W_Data(AP3216_SYSTEM_CONFIGRATION_ADDRESS, 0x03);// IIC_DELAY_MS(10);// 3.讀取uint8_t ret = AP3216_R_Data(AP3216_SYSTEM_CONFIGRATION_ADDRESS);if (ret == 0x03){uart_printf(" ap3216 communication success!\r\n");}
}// 讀取ALS的數據 光
uint16_t AP3216_R_ALS()
{// 3.讀取數據uint16_t data = 0;uint8_t data_low = AP3216_R_Data(AP3216_ALS_DATA_LOW_ADDRESS);uint8_t data_high = AP3216_R_Data(AP3216_ALS_DATA_HIGH_ADDRESS);data = data_high << 8 | data_low;return data;
}// 讀取PS的數據 距離
uint16_t AP3216_R_PS()
{// 3.讀取數據uint16_t data = 0;uint8_t data_low = AP3216_R_Data(AP3216_PS_DATA_LOW_ADDRESS);uint8_t data_high = AP3216_R_Data(AP3216_PS_DATA_HIGH_ADDRESS);data = data_high & (0x3f);data <<= 4;data |= ((data_low) & 0xf);return data;
}
void ap3216test()
{AP3216_Init();uint16_t res = 0;while (1){/* code */res = AP3216_R_ALS();uart_printf("ALS = %d \r\n", res);delay_ms(500);res = AP3216_R_PS();uart_printf("PS = %d \r\n", res);delay_ms(500);}
}
(效果通過串口延時打印可以看出)
?