一,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);}
}
(效果通过串口延时打印可以看出)