I2C实验

目录

一、I2C简介

二、硬件原理

1、看原理图,找到I2C

2、查看使用设备

3、查看使用的IO

 4、查数据手册看复用位

三、查看寄存器

1、I2C Address Register (I2Cx_IADR)

2、I2C Frequency Divider Register (I2Cx_IFDR)

3、I2C Control Register (I2Cx_I2CR)

4、I2C Status Register (I2Cx_I2SR)

5、I2C Data I/O Register (I2Cx_I2DR)

四、I2C协议

1、起始位start

 2、停止位stop

 3、数据传输

 4、应答信号ack

5、 I2C 写时序

6、 I2C 读时序

7、start信号产生

8、stop信号产生

五、AP3216C

1、查数据手册看设备地址

2、查看寄存器

六、代码编写

1、创建工作目录

2、编写bsp_i2c.h

3、编写bsp_i2c.c

4、编写ap3216c.h

5、ap3216c.c


一、I2C简介

I2C 是很常见的一种总线协议,  I2C 使用两条线在主控制器和从机之间进行数据通信。一条是 SCL(串行时钟线),另外一条是 SDA(串行数据线),这两条数据线需要接上拉电阻,总线空闲的时候 SCL 和 SDA 处于高电平。I.MX6U 的 I2C 支持两种模式:标准模式和快速模式,标准模式下 I2C 数据传输速率最高是 100Kbits/s,在快速模式下数据传输速率最高为 400Kbits/s。I2C总线支持多从机,通过从机地址来区分访问对应的从机。

I2C实验_第1张图片

二、硬件原理

1、看原理图,找到I2C

I2C实验_第2张图片

 这里使用I2C1,搜索它接到哪里

2、查看使用设备

I2C实验_第3张图片

 AP3216C,这是一个IIC接口的器件,这是一个环境光传感器,AP3216C连接到了I2C1上

3、查看使用的IO

I2C实验_第4张图片

       I2C1_SCL: 使用的是UART4_TXD这个IO

       I2C1_SDA: 使用的是UART4_RXD这个IO

 4、查数据手册看复用位

UART4_TXD 复用位ALT2

I2C实验_第5张图片

 UART4_RXD复用为ALT2

三、查看寄存器

I2C寄存器如下

I2C实验_第6张图片

 可以看到有五个,下面逐一看一下各个寄存器

1、I2C Address Register (I2Cx_IADR)

I2C实验_第7张图片

寄存器 I2Cx_IADR 只有 ADR(bit7:1)位有效,用来保存 I2C 从设备地址数据。当我们要访问某个 I2C 从设备的时候就需要将其设备地址写入到 ADR 里面

2、I2C Frequency Divider Register (I2Cx_IFDR)

I2C实验_第8张图片

 这个是 I2C 的分频寄存器,寄存器 I2Cx_IFDR 也只有 IC(bit5:0)这个位,用来设置 I2C 的波特率, I2C 的时钟源可以选择 IPG_CLK_ROOT=66MHz,通过设置 IC 位既可以得到想要的 I2C 波特率,IC 位可选的设置如下

I2C实验_第9张图片

 假如现在需要100kbit的速率,那么时钟源66000000/100000=660。经过查找上图IC位设置位0X38或0X15的时候,为640分频,66000000/640=103.125Kbit,较为接近

3、I2C Control Register (I2Cx_I2CR)

I2C实验_第10张图片I2C实验_第11张图片

 这个是 I2C 控制寄存器,寄存器 I2Cx_I2CR 的各位含义如下:
IEN(bit7): I2C 使能位,为 1 的时候使能 I2C,为 0 的时候关闭 I2C。
IIEN(bit6): I2C 中断使能位,为 1 的时候使能 I2C 中断,为 0 的时候关闭 I2C 中断。
MSTA(bit5):主从模式选择位,设置 IIC 工作在主模式还是从模式,为 1 的时候工作在主
模式,为 0 的时候工作在从模式。
MTX(bit4):传输方向选择位,用来设置是进行发送还是接收,为 0 的时候是接收,为 1 的
时候是发送。
TXAK(bit3):传输应答位使能,为 0 的话发送 ACK 信号,为 1 的话发送 NO ACK 信号。
RSTA(bit2):重复开始信号,为 1 的话产生一个重新开始信号。

4、I2C Status Register (I2Cx_I2SR)

I2C实验_第12张图片

I2C实验_第13张图片

这个是 I2C 的状态寄存器,寄存器 I2Cx_I2SR 的各位含义如下:
ICF(bit7):数据传输状态位,为 0 的时候表示数据正在传输,为 1 的时候表示数据传输完成。
IAAS(bit6):当为 1 的时候表示 I2C 地址,也就是 I2Cx_IADR 寄存器中的地址是从设备地址。
IBB(bit5): I2C 总线忙标志位,当为 0 的时候表示 I2C 总线空闲,为 1 的时候表示 I2C 总线忙。
IAL(bit4):仲裁丢失位,为 1 的时候表示发生仲裁丢失。
SRW(bit2):从机读写状态位,当 I2C 作为从机的时候使用,此位用来表明主机发送给从机的是读还是写命令。为 0 的时候表示主机要向从机写数据,为 1 的时候表示主机要从从机读取数据。
IIF(bit1): I2C 中断挂起标志位,当为 1 的时候表示有中断挂起,此位需要软件清零。
RXAK(bit0): 应答信号标志位,为 0 的时候表示接收到 ACK 应答信号,为 1 的话表示检测到 NO ACK 信号。

5、I2C Data I/O Register (I2Cx_I2DR)

I2C实验_第14张图片

 这是 I2C 的数据寄存器,此寄存器只有低 8 位有效,当要发送数据的时候将要发送的数据写入到此寄存器,如果要接收数据的话直接读取此寄存器即可得到接收到的数据

四、I2C协议

I2C 总线工作是按照一定的协议来运行的

1、起始位start

I2C 通信起始标志,通过这个起始位就可以告诉 I2C 从机,“我”要开始进行 I2C 通信了。在 SCL 为高电平的时候, SDA 出现下降沿就表示为起始位

I2C实验_第15张图片

 2、停止位stop

停止位就是停止 I2C 通信的标志位,和起始位的功能相反,也就是I2C 通信。在 SCL 位高电平的时候, SDA出现上升沿就表示为停止位

I2C实验_第16张图片

 3、数据传输

I2C 总线在数据传输的时候要保证在 SCL 高电平期间, SDA 上的数据稳定,因此 SDA 上的数据变化只能在 SCL 低电平期间发生
 I2C实验_第17张图片

 4、应答信号ack

当 I2C 主机发送完 8 位数据以后会将 SDA 设置为输入状态,等待 I2C 从机应答,也就是等到 I2C 从机告诉主机它接收到数据了。应答信号是由从机发出的,主机需要提供应答信号所需的时钟,主机发送完 8 位数据以后紧跟着的一个时钟信号就是给应答信号使用的。从机通过将 SDA 拉低来表示发出应答信号,表示通信成功,否则表示通信失败

5、 I2C 写时序

主机通过 I2C 总线与从机之间进行通信不外乎两个操作:写和读, I2C 总线单字节写时序如下

I2C实验_第18张图片

 I2C 写时序的具体步骤:
1、开始信号start
2、发送 I2C 设备地址,每个 I2C 器件都有一个设备地址,通过发送具体的设备地址来决定访问哪个 I2C 器件。这是一个 8 位的数据,其中高 7 位(msb-lsb)是设备地址,最后 1 位是读写位
3、 I2C 器件地址后面跟着一个读写位,为 0 表示写操作,为 1 表示读操作
4、从机发送的 ACK 应答信号。
5、重新发送开始信号start
6、发送要写入数据的寄存器地址
7、从机发送的 ACK 应答信号
8、发送要写入寄存器的数据
9、从机发送的 ACK 应答信号。
10、停止信号stop

6、 I2C 读时序

I2C 单字节读时序比写时序要复杂一点,读时序分为 4 大步,第一步是发送设备地址,第二步是发送要读取的寄存器地址,第三步重新发送设备地址,最后一步就是 I2C 从器件输出要读取的寄存器值,具体如下
1、主机发送起始信号。
2、主机发送要读取的 I2C 从设备地址。
3、读写控制位,因为是向 I2C 从机设备发送数据,因此是写信号。
4、从机发送的 ACK 应答信号。
5、重新发送 START 信号。
6、主机发送要读取的寄存器地址。
7、从机发送的 ACK 应答信号。
8、重新发送 START 信号。
9、重新发送要读取的 I2C 从机设备地址。
10、读写控制位,这里是读信号,表示接下来是从 I2C 从机设备里面读取数据。
11、从机发送的 ACK 应答信号。
12、从 I2C 器件里面读取到的数据。
13、主机发出 NO ACK 信号,表示读取完成,不需要从机再发送 ACK 信号了。
14、主机发出 STOP 信号,停止 I2C 通信。

7、start信号产生

I2C实验_第19张图片

 初始化过程完成后,串行数据可以通过选择主传输模式。在多主站总线系统上,繁忙总线(I2C_I2SR[IBB]) 必须进行判断确定串行总线是否可用。如果总线是free(IBB = 0)空闲,可以发送开始信号和第一个字节(从地址),不需要控制某个寄存器,数据写入数据寄存器包括所需从机的地址和LSB指示传输方向,start信号就会同步产生

8、stop信号产生

I2C实验_第20张图片

 当主设备发出停止信号时,数据传输结束,这可能在发送所有数据后发生。要使主接收器终止数据传输,它必须通过以下方式通知从发送器不确认最后一个数据字节。这是通过设置传输确认来完成的位 (I2C_I2CR[TXAK]),然后再读取倒数第二个字节(也就是传输的第五个数据)。在读取最后一个字节之前,必须生成停止信号。

五、AP3216C

 I2C1 连接了一个三合一环境传感器: AP3216C, AP3216C是由敦南科技推出的一款传感器,其支持环境光强度(ALS)、接近距离(PS)和红外线强度(IR)这三个环境参数检测。该芯片可以通过 IIC 接口与主控制相连,并且支持中断。

1、查数据手册看设备地址

打开 AP3216C数据手册

I2C实验_第21张图片

 可以看到AP3216C的从机地址位0X1E

2、查看寄存器

AP3216C 内部也有一些寄存器,通过这些寄存器可以配置 AP3216C 的工作模式,并且读取相应的数据,部分寄存器如下

I2C实验_第22张图片

 这里简单看几个,比如0X00是系统配置寄存器,bit2:0设置AP3216C使用那些传感器,这里需要设置位011,也就是0x3,表示开始ALS+PS+IR;

0X0A是IR Ddata low(IR 低位数据)。Bit7为0的时候表示IR和PS数据有效,为1的时候IR和PS数据无效。Bit1:0是IR的低2位数据;

0X0B是IR Data high(IR 高位数据),big7:0是高字节。与0X0A一起组成10bit的数据"IR byte of ADC output";

 0X0C和0X0D分别为ALS的低8位和高8位“ALSbyte of ADC output”;

0X0E的bit3:0是低4位数据,0X0F的bit5:0是高6位数据。加起来就是10位PS byte of ADC output

到此基本了解完I2C及AP3216C,下面开始编程

六、代码编写

1、创建工作目录

分别是i2c和ap3216c

I2C实验_第23张图片

2、编写bsp_i2c.h

#ifndef __BSP_I2C_H
#define __BSP_I2C_H

#include "imx6ul.h"

/* 相关宏定义 */
#define I2C_STATUS_OK				(0)
#define I2C_STATUS_BUSY				(1)
#define I2C_STATUS_IDLE				(2)
#define I2C_STATUS_NAK				(3)
#define I2C_STATUS_ARBITRATIONLOST	(4) /*仲裁丢失*/
#define I2C_STATUS_TIMEOUT			(5)
#define I2C_STATUS_ADDRNAK			(6)

/*传输方向*/
enum i2c_direction
{
    kI2C_Write = 0x0, /* 主机向从机写数据 */
    kI2C_Read = 0x1, /* 主机从从机读数据 */
};

/*主机传输结构体*/
struct i2c_transfer
{
    unsigned char slaveAddress;      	/* 7位从机地址*/
    enum i2c_direction direction; 		/* 传输方向*/
    unsigned int subaddress;       		/* 寄存器地址*/
    unsigned char subaddressSize;    	/* 寄存器地址长度*/
    unsigned char *volatile data;    	/* 数据缓冲区*/
    volatile unsigned int dataSize;  	/* 数据缓冲区长度*/
};
/*函数声明*/
void i2c_init(I2C_Type *base);

unsigned char i2c_master_start(I2C_Type *base,
                                unsigned char address,
                                enum i2c_direction direction);

unsigned char i2c_master_stop(I2C_Type *base);

unsigned char i2c_master_repeated_start(I2C_Type *base,
                                        unsigned char address,
                                        enum i2c_direction direction);

unsigned char i2c_check_and_clear_error(I2C_Type *base , unsigned int status);

void i2c_master_write(I2C_Type *base , 
                       const unsigned char *buf,
                       unsigned int size);

void i2c_master_read(I2C_Type *base , 
                     unsigned char *buf,
                     unsigned int size);

unsigned char i2c_master_transfer(I2C_Type *base, struct i2c_transfer *xfer);

#endif

3、编写bsp_i2c.c

#include "bsp_i2c.h"

/*初始化I2C
 * @description : 初始化 I2C,波特率 100KHZ
 * @param – base : 要初始化的 IIC 设置
 * @return : 无
 */
void i2c_init(I2C_Type *base)
{/* 要访问I2C的寄存器,首先需要先关闭I2C */
    base->I2CR &= ~(1 << 7); 
    /* 设置波特率为100K
     * I2C的时钟源来源于IPG_CLK_ROOT=66Mhz
 	 * IC2 时钟 = PERCLK_ROOT/dividison(IFDR寄存器)
	 * 设置I2C的波特率为100K, 因此当分频值=66000000/100000=660.
	 * 在IFDR寄存器给出的表里面查找,没有660这个值,但是有640,因此就用640,
	 * 即寄存器IFDR的IC位设置为0X15
	 */
    base->IFDR = 0X15;
    /* 使能I2C */
    base->I2CR |= (1 << 7); 
}

/*start信号产生和从机地址发送*/
unsigned char i2c_master_start(I2C_Type *base,
                                unsigned char address,
                                enum i2c_direction direction)
{
    if(base->I2SR & (1 << 5)) /*判断I2C忙*/
        return 1;/*0代表正常,其他值均为不正常*/
    
    /*设置主机发送模式
     * 设置寄存器 I2CR
     * bit[5]: 1 主模式
     * bit[4]: 1 发送
     */
    base->I2CR |= (1 << 5) | (1 << 4); 

    /*产生start信号
     *寄存器 I2DR, bit[7:0]因为高七位为地址,最后一位为读写位,所以要左移1
     *判断1或0,1为读,0为写
    */
    base->I2DR = ((unsigned int)address << 1) | ((direction == kI2C_Read) ? 1 : 0);
    return 0;
}   

/*stop信号
* @description : 停止信号
* @param - base : 要使用的 IIC
* @param : 无
* @return : 状态结果
*/
unsigned char i2c_master_stop(I2C_Type *base)
{
    unsigned short timeout = 0xffff;
    /*清除I2CR的bit5:3*/
    base->I2CR &= ~((1 << 5) | (1 <<4) | (1 << 3));
    /*等待I2C忙结束*/
    while((base->I2SR & (1<<5))){
        timeout --;
        if(timeout ==0)/*超时跳出*/
            return I2C_STATUS_TIMEOUT;
    }
    return I2C_STATUS_OK;
}
/*repeaned start信号
 * @description : 发送重新开始信号
 * @param - base : 要使用的 IIC
 * @param - addrss : 设备地址
 * @param - direction : 方向
 * @return : I2C_STATUS_OK 正常 其他值 出错
 */
unsigned char i2c_master_repeated_start(I2C_Type *base,
                                        unsigned char address,
                                        enum i2c_direction direction)
{
    /* I2C忙并且工作在从模式,跳出
     * base->I2CR为0在从模式
     */
    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] : 要发送的数据,这里写入从设备地址
	 */ 
    base->I2DR = ((unsigned int)address << 1) | ((direction == kI2C_Read) ? 1 : 0);
    return I2C_STATUS_OK;
}

/*错误检查和清除函数
* @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 - 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-- )
    {
        /* 将buf中的数据写入到I2DR寄存器 */
        base->I2DR = *buf++;
        /* 等待传输完成 */	
        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);/*nack*/
    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;	
}

I2C 的操作函数已经准备好了,接下来就是使用前面编写 I2C 操作函数来配置 AP3216C 了

4、编写ap3216c.h

#ifndef __BSP_AP3216C_H
#define __BSP_AP3216C_H

#include "bsp_i2c.h"
#include "stdio.h"
#include "bsp_delay.h"

#define AP3216C_ADDR    	0X1E	/* AP3216C器件地址 */

/* AP3316C寄存器 */
#define AP3216C_SYSTEMCONG	0x00	/* 配置寄存器*/
#define AP3216C_INTSTATUS	0X01	/* 中断状态寄存器*/
#define AP3216C_INTCLEAR	0X02	/* 中断清除寄存器*/
#define AP3216C_IRDATALOW	0x0A	/* IR数据低字节*/
#define AP3216C_IRDATAHIGH	0x0B	/* IR数据高字节*/
#define AP3216C_ALSDATALOW	0x0C	/* ALS数据低字节*/
#define AP3216C_ALSDATAHIGH	0X0D	/* ALS数据高字节*/
#define AP3216C_PSDATALOW	0X0E	/* PS数据低字节*/
#define AP3216C_PSDATAHIGH	0X0F	/* PS数据高字节 */
/* 函数声明 */
unsigned char ap3216c_init(void);
unsigned char ap3216c_readonebyte(unsigned char addr,
                                    unsigned char reg);
unsigned char ap3216c_writeonebyte(unsigned char addr,
                                    unsigned char reg,
                                    unsigned char data);
void ap3216c_readdata(unsigned short *ir ,
                        unsigned short *ps,
                        unsigned short *als);
#endif

5、ap3216c.c

#include "bsp_ap3216c.h"

/*
 * @description	: 初始化AP3216C
 * @param		: 无
 * @return 		: 0 成功,其他值 错误代码
 */
unsigned char ap3216c_init(void)
{
	unsigned char data = 0;

	/* 1、IO初始化,配置I2C IO属性	
     * I2C1_SCL -> UART4_TXD
     * I2C1_SDA -> UART4_RXD
     */
	IOMUXC_SetPinMux(IOMUXC_UART4_TX_DATA_I2C1_SCL, 1);
	IOMUXC_SetPinMux(IOMUXC_UART4_RX_DATA_I2C1_SDA, 1);

	/* 
	 *bit 16:0 HYS关闭
	 *bit [15:14]: 1 默认47K上拉
	 *bit [13]: 1 pull功能
	 *bit [12]: 1 pull/keeper使能 
	 *bit [11]: 0 关闭开路输出
	 *bit [7:6]: 10 速度100Mhz
	 *bit [5:3]: 110 驱动能力为R0/6
	 *bit [0]: 1 高转换率
	 */
	IOMUXC_SetPinConfig(IOMUXC_UART4_TX_DATA_I2C1_SCL, 0x70B0);
	IOMUXC_SetPinConfig(IOMUXC_UART4_RX_DATA_I2C1_SDA, 0X70B0);

	i2c_init(I2C1);		/* 初始化I2C1 */

	/* 2、初始化AP3216C */
	ap3216c_writeonebyte(AP3216C_ADDR, AP3216C_SYSTEMCONG, 0X04);	/* 复位AP3216C 			*/
	delayms(50);													/* AP33216C复位至少10ms */
	ap3216c_writeonebyte(AP3216C_ADDR, AP3216C_SYSTEMCONG, 0X03);	/* 开启ALS、PS+IR 		   	*/
	data = ap3216c_readonebyte(AP3216C_ADDR, AP3216C_SYSTEMCONG);	/* 读取刚刚写进去的0X03 */
	if(data == 0X03)
		return 0;	/* AP3216C正常 	*/
	else 
		return 1;	/* AP3216C失败 	*/
}

/*
 * @description	: 向AP3216C写入数据
 * @param - addr: 设备地址
 * @param - reg : 要写入的寄存器
 * @param - data: 要写入的数据
 * @return 		: 操作结果
 */
unsigned char ap3216c_writeonebyte(unsigned char addr,unsigned char reg, unsigned char data)
{
    unsigned char status=0;
    unsigned char writedata=data;
    struct i2c_transfer masterXfer;
	
    /* 配置I2C xfer结构体 */
   	masterXfer.slaveAddress = addr; 			/* 设备地址 				*/
    masterXfer.direction = kI2C_Write;			/* 写入数据 				*/
    masterXfer.subaddress = reg;				/* 要写入的寄存器地址 			*/
    masterXfer.subaddressSize = 1;				/* 地址长度一个字节 			*/
    masterXfer.data = &writedata;				/* 要写入的数据 				*/
    masterXfer.dataSize = 1;  					/* 写入数据长度1个字节			*/

    if(i2c_master_transfer(I2C1, &masterXfer))
        status=1;
        
    return status;
}

/*
 * @description	: 从AP3216C读取一个字节的数据
 * @param - addr: 设备地址
 * @param - reg : 要读取的寄存器
 * @return 		: 读取到的数据。
 */
unsigned char ap3216c_readonebyte(unsigned char addr,unsigned char reg)
{
	unsigned char val=0;
	
	struct i2c_transfer masterXfer;	
	masterXfer.slaveAddress = addr;				/* 设备地址 				*/
    masterXfer.direction = kI2C_Read;			/* 读取数据 				*/
    masterXfer.subaddress = reg;				/* 要读取的寄存器地址 			*/
    masterXfer.subaddressSize = 1;				/* 地址长度一个字节 			*/
    masterXfer.data = &val;						/* 接收数据缓冲区 				*/
    masterXfer.dataSize = 1;					/* 读取数据长度1个字节			*/
	i2c_master_transfer(I2C1, &masterXfer);

	return val;
}

/*
 * @description	: 读取AP3216C的数据,读取原始数据,包括ALS,PS和IR, 注意!
 *				: 如果同时打开ALS,IR+PS的话两次数据读取的时间间隔要大于112.5ms
 * @param - ir	: ir数据
 * @param - ps 	: ps数据
 * @param - ps 	: als数据 
 * @return 		: 无。
 */
void ap3216c_readdata(unsigned short *ir, unsigned short *ps, unsigned short *als)
{
    unsigned char buf[6];
    unsigned char i;

	/* 循环读取所有传感器数据 */
    for(i = 0; i < 6; i++)	
    {
        buf[i] = ap3216c_readonebyte(AP3216C_ADDR, AP3216C_IRDATALOW + i);	
    }
	
    if(buf[0] & 0X80) 	/* IR_OF位为1,则数据无效 */
		*ir = 0;					
	else 				/* 读取IR传感器的数据   		*/
		*ir = ((unsigned short)buf[1] << 2) | (buf[0] & 0X03); 			
	
	*als = ((unsigned short)buf[3] << 8) | buf[2];	/* 读取ALS传感器的数据 			 */  
	
    if(buf[4] & 0x40)	/* IR_OF位为1,则数据无效 			*/
		*ps = 0;    													
	else 				/* 读取PS传感器的数据    */
		*ps = ((unsigned short)(buf[5] & 0X3F) << 4) | (buf[4] & 0X0F); 	
}

编译烧到sd卡上,sd卡和屏幕装上开发板就能看到屏幕上有关ap3216c的数据

你可能感兴趣的:(IMX6ULL裸机开发,arm,单片机,arm开发,ubuntu,linux)