I.MX6ull-I2C

一,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);}
}

(效果通過串口延時打印可以看出)

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/895559.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/895559.shtml
英文地址,請注明出處:http://en.pswp.cn/news/895559.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

書籍推薦:《書法課》林曦

記得樊登老師說過&#xff0c;如果你想了解一個事物&#xff0c;就去讀5本相關的書&#xff0c;你會比大部分人都更了解它。這是我讀的第4本和“書法”有關的書&#xff0c;作為一個零基礎的成年人&#xff0c;林曦這本《書法課》非常值得一讀。&#xff08;無論你是否寫字&…

【大疆無人機地圖測繪技術學習:高精度、高效率的全流程解決方案】

文章目錄 大疆無人機地圖測繪算法詳解一、數據采集&#xff08;一&#xff09;飛行平臺與傳感器&#xff08;二&#xff09;航線規劃&#xff08;三&#xff09;數據類型 二、數據處理與建模&#xff08;一&#xff09;數據導入與預處理&#xff08;二&#xff09;空三計算&…

【刪除tomcat默認管理控制臺】

停止Tomcat&#xff1a; ./catalina.sh stop 刪除管理控制臺應用&#xff1a; 進入Tomcat的webapps目錄&#xff1a; cd /path/to/tomcat/webapps List item 刪除manager和host-manager文件夾&#xff1a; rm -rf manager host-manager 啟動Tomcat&#xff1a; ./catali…

工具資料+H3C 交換機常見故障分析排查+高危操作

當我們從客戶那里接到一個故障時,我們根據現象讓客戶收集一堆信息,然后集成商、代理商、設備廠家一級一級的反復咨詢與確認,天天經歷這樣的場景。幾乎每個故障我們都要經過多個層級的人處理,信息的交流占據了每個人大部分的時間,反復的收集信息與確認問題現象也會讓客戶不厭其煩…

STM32:USB 虛擬串口以及使用usb->dfu進行iap

本文介紹stm32上usb的常用功能虛擬串口和DFU(Download Firmware Update) 文章目錄 前言一、usb二、虛擬串口1.cubemx配置1.我們選用高速usb&#xff0c;然后選擇內部低速的phy&#xff0c;這樣使用的usb&#xff0c;最高速度為12Mbit每秒。2.USB_DEVICE cdc類配置3.時鐘配置&am…

HCIA項目實踐--靜態路由的綜合實驗

八 靜態路由綜合實驗 &#xff08;1&#xff09;劃分網段 # 192.168.1.0 24#分析&#xff1a;每個路由器存在兩個環回接口&#xff0c;可以把兩個環回接口分配一個環回地址&#xff0c;所以是四個環回&#xff0c;一個骨干&#xff0c;這樣分配&#xff0c;不會出現路由黑洞#19…

C++基礎知識(三)之結構體、共同體、枚舉、引用、函數重載

九、結構體、共同體和枚舉 1、結構體的基本概念 結構體是用戶自定義的類型&#xff0c;可以將多種數據的表示合并到一起&#xff0c;描述一個完整的對象。 使用結構體有兩個步驟&#xff1a;1&#xff09;定義結構體描述&#xff08;類型&#xff09;&#xff1b;2&#xff…

通過內網穿透ssh實現遠程對家里的linux進行終端操作和編程

內網穿透就是將自己的地址當穿透到公網ip&#xff0c;這一就可以在外網訪問了(因為大部分人ip都是動態分配的)&#xff0c;以適用ssh遠程連接&#xff0c;我這里用的是極點云cpolar&#xff0c;反正也是黑框編程&#xff0c;免費就行了。我是ubuntu虛擬機&#xff0c;在虛擬機上…

Redis 數據類型 Zset 有序集合

有序集合相對于字符串、列表、哈希、集合來說會有?些陌?。它保留了集合不能有重復成員的特點&#xff0c;但與集合不同的是&#xff0c;有序集合中的每個元素都有?個唯?的浮點類型的分數&#xff08;score&#xff09;與之關 聯&#xff0c;著使得有序集合中的元素是可以維…

PHP 中的除以零錯誤

除以零錯誤&#xff08;Division by zero&#xff09;是指數字除以零的情況&#xff0c; 這在數學上是未定義的。在 PHP 中&#xff0c;處理這種錯誤的方式取決于 PHP 版本&#xff1a; PHP 7&#xff1a; 使用 / 運算符會產生一個警告 (E_WARNING) 并返回 false。 使用 intd…

基于springboot軌道交通安全評估系統(源碼+lw+部署文檔+講解),源碼可白嫖!

摘要 時代在飛速進步&#xff0c;每個行業都在努力發展現在先進技術&#xff0c;通過這些先進的技術來提高自己的水平和優勢&#xff0c;軌道交通安全評估管理當然不能排除在外。軌道交通安全評估系統是在實際應用和軟件工程的開發原理之上&#xff0c;運用Java語言以及Spring…

前端面試題目---頁面抖動的原因、如何避免、如何解決

前端頁面抖動是一個常見且影響用戶體驗的問題&#xff0c;下面將從抖動發生的場景、解決辦法以及預防措施三個方面進行詳細闡述。 頁面抖動發生的場景 1. 元素尺寸動態變化 圖片加載&#xff1a;當頁面中圖片的寬高沒有預先設定&#xff0c;在圖片加載完成后&#xff0c;其實…

vue知識點3

1.使用componenent的好處 符合高內聚&#xff0c;低耦合。一個組件出問題了&#xff0c;不會影響其他組件。 2.vue版本決定了一些使用框架的版本 vue2使用的路由版本只能到3 3.路由的配置介紹一下 a.安裝路由的插件 npm install vue-router3 b.整理文件路徑 將路徑整理…

如何測試和驗證CVE-2024-1430:Netgear R7000 路由器信息泄露漏洞分析

CVE-2024-1430 是一個影響 Netgear R7000 路由器的安全漏洞&#xff0c;漏洞來源于該路由器 Web 管理界面的信息泄露問題。攻擊者通過訪問 /currentsetting.htm 文件&#xff0c;可能泄露敏感信息&#xff0c;如 Wi-Fi 密碼等。 在測試和驗證 CVE-2024-1430 時&#xff0c;您需…

數據結構:哈夫曼樹

1.概念 哈夫曼樹&#xff08;Huffman Tree&#xff09;是一種用于數據壓縮的二叉樹&#xff0c;由大衛哈夫曼&#xff08;David A. Huffman&#xff09;于1952年提出。它通過構建最優二叉樹來實現數據的高效壓縮&#xff0c;廣泛應用于文件壓縮、圖像壓縮等領域。 哈夫曼樹的…

UE5.2后 Bake Out Materials失效

這個問題出現在5.3&#xff0c;5.4&#xff0c;5.5沒有測試 烘焙貼圖后會找不到貼圖位置&#xff0c; 這個是5.2的正常狀態 默認是生成在模型當前目錄里&#xff0c;包括新的材質 但是這個bug會讓材質和貼圖都消失&#xff0c;無法定位 暫時沒有辦法解決&#xff0c;等官方 …

ADC 的音頻實驗,無線收發模塊( nRF24L01)

nRF24L01 采用 QFN20 封裝&#xff0c;有 20 個引腳&#xff0c;以下是各引腳的詳細介紹&#xff1a; 1. 電源引腳 ? VDD&#xff1a;電源輸入端&#xff0c;一般接 3V 電源&#xff0c;為芯片提供工作電壓&#xff0c;供電電壓范圍為 1.9V&#xff5e;3.6V。 ? VSS&#xf…

基于HTML5 Canvas 和 JavaScript 實現的煙花動畫效果

以下是一個使用 HTML5 Canvas 和 JavaScript 實現的煙花動畫效果代碼盒子: <!DOCTYPE html> <html> <head><title>煙花效果

C++課程設計 運動會分數統計(含源碼)

C++課程設計 運動會分數統計 一、題目描述(一)問題描述(二)基本要求二、程序設計文檔1. 項目概述1.1 項目背景1.2 功能需求1.3 非功能需求2. 系統設計2.1 數據結構設計2.1.1 `School` 結構體2.1.2 `Project` 結構體2.2 功能模塊設計2.2.1 主菜單2.2.2 輸入/修改項目成績2.2…

【音視頻】RTSP拉流: RTP負載AAC詳解(三)

此文為系列文章&#xff0c;此系列主要講解RTSP客戶端的拉流及播放&#xff0c;文章持續更新&#xff0c;會從rtsp的基本協議講起&#xff0c;如何一步步實現音視頻的拉流過程&#xff0c;包括一系列涉及到的協議&#xff0c;rtsp&#xff0c;sdp&#xff0c; rtp&#xff08;本…