18_I.MX6ULL_I2C实验

目录

I2C简介

起始位

停止位

数据传输

应答信号

I2C写时序

I2C读时序

I2C多字节读写时序

相关寄存器

AP3216C简介

实验源码


I2C简介

I2C是最常用的通信接口,众多的传感器都会提供I2C接口来和主控相连,比如陀螺仪、加速度计、触摸屏等等。所以I2C是做嵌入式开发必须掌握的, I.MX6U有4个I2C接口,可以通过这4个I2C接口来连接一些I2C外设。

I2C是很常见的一种总线协议, I2C是NXP公司设计的, I2C使用两条线在主控制器和从机之间进行数据通信。一条是 SCL(串行时钟线),另外一条是SDA(串行数据线),这两条数据线需要接上拉电阻,总线空闲的时候SCL和SDA处于高电平。12C总线标准模式下速度可以达到 100Kb/s,快速模式下可以达到400Kb/S。I2C 总线工作是按照一定的协议来运行的,接下来就看一下 I2C 协议。

I2C是支持多从机的,也就是一个I2C控制器下可以挂多个I2C从设备,这些不同的I2C从设备有不同的器件地址,这样I2C主控制器就可以通过I2C设备的器件地址访问指定的I2C设备了,一个I2C总线连接多个I2C设备如图示:

 

图中SDA和SCL这两根线必须要接一个上拉电阻,一般是4.7K。其余的I2C从器件都挂接到SDA和SCL这两根线上,这样就可以通过SDA和SCL这两根线来访问多个12C设备。接下来看一下I2C协议有关的术语:

起始位

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

 

停止位

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

 

数据传输

I2C总线在数据传输的时候要保证在SCL高电平期间, SDA上的数据稳定,因此SDA上的数据变化只能在SCL低电平期间发生,如图所示:

 

应答信号

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

I2C写时序

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

 

图就是I2C写时序,我们来看一下写时序的具体步骤:

1.开始信号。

2.发送I2C设备地址,每个I2C器件都有一个设备地址,通过发送具体的设备地址来决定访问哪个I2C器件。这是一个8位的数据,其中高7位是设备地址,最后1位是读写位,为1的话表示这是一个读操作,为0的话表示这是一个写操作。

3.I2C器件地址后面跟着一个读写位,为0表示写操作,为1表示读操作。

4.从机发送的ACK应答信号。

5.重新发送开始信号。

6.发送要写写入数据的寄存器地址。

7.从机发送的ACK应答信号。

8.发送要写入寄存器的数据。

9.从机发送的ACK应答信号。

10.停止信号。

I2C读时序

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通信。

I2C多字节读写时序

有时候我们需要读写多个字节,多字节读写时序和单字节的基本一致,只是在读写数据的时候可以连续发送多个自己的数据,其他的控制时序都是和单字节一样的。

I.MX6U提供了4个I2C外设,通过这四个I2C外设即可完成与I2C从器件进行通信,I.MX6U的I2C外设特性如下:

1.与标准I2C总线兼容。

2.多主机运行

3.软件可编程的64中不同的串行时钟序列。

4.软件可选择的应答位。

5.开始/结束信号生成和检测。

6.重复开始信号生成。

7.确认位生成。

8.总线忙检测

I.MX6U的I2C支持两种模式:标准模式和快速模式,标准模式下I2C数据传输速率最高是 100Kbits/s,在快速模式下数据传输速率最高为400Kbits/s。

相关寄存器

首先看一下I2Cx_IADR(x=1~4)寄存器,这是I2C的地址寄存器,此寄存器结构如图所示:

寄存器I2Cx_IADR只有ADR(bit7:1)位有效,用来保存设I2C从设备地址数据。

当我们要访问某个I2C从设备的时候就需要将其设备地址写入到ADR里面。

寄存器I2Cx_IFDR,这个是12C的分频寄存器,寄存器结构如图所示:

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

 不像其他外设的分频设置一样可以随意设置,图中列出了IC的所有可选值。比如现在I2C的时钟源为66MHz,我们要设置I2C的波特率为100KHz,那么IC就可以设置为0X15,也就是640分频。66000000/640-103.125KHz~100KHz

寄存器12Cx_12CR,这个是I2C控制寄存器,此寄存器结构如图所示:

IEN(bit7): I2C使能位,为1的时候使能I2C,为0的时候关闭I2C。

IIEN(bit6): I2C中断使能位,为1的时候使能I2C中断,为0的时候关闭I2C中断。

MSTA(bit5):主从模式选择位,设置I2C工作在主模式还是从模式,为1的时候工作在主模式,为0的时候工作在从模式。

MTX(bit4):传输方向选择位,用来设置是进行发送还是接收,为0的时候是接收,为1的时候是发送。

TXAK(bit3):传输应答位使能,为0的话发送ACK信号,为1的话发送NOACK信号。

RSTA(bit2):重复开始信号,为1的话产生一个重新开始信号。

寄存器I2Cx_12SR,这个是I2C的状态寄存器,寄存器结构如图所示:

 

ICF(bit7):数据传输状态位,为0的时候表示数据正在传输,为1的时候表示数据传输完成。

IAAS(bit6):当为1的时候表示I2C地址,也就是I2Cx_IADR寄存器中的地址是从设备地址。线忙。

IBB(bit5): I2C总线忙标志位,当为0的时候表示I2C总线空闲,为1的时候表示12C总线忙。

IAL(bit4):仲裁丢失位,为1的时候表示发生仲裁丢失。

SRW(bit2):从机读写状态位,当I2C作为从机的时候使用,此位用来表明主机发送给从机的是读还是写命令。为0 的时候表示主机要向从机写数据,为1 的时候表示主机要从从机读取数据。

IIF(bit1): I2C中断挂起标志位,当为1的时候表示有中断挂起,此位需要软件清零。

RXAK(bit0):应答信号标志位,为0的时候表示接收到ACK应答信号,为1的话表示检测到NO ACK信号。

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

AP3216C简介

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

1.I2C 接口,快速模式下波特率可以到400Kbit/S

2.多种工作模式选择: ALS、PS+IR、ALS+PS+IR、PD等等。

3.内建温度补偿电路。

4.宽工作温度范围(-30°C~+80°C)。

5.超小封装, 4.1mm x 2.4mm x 1.35mm

6.环境光传感器具有16位分辨率。

7.接近传感器和红外传感器具有10位分辨率。

AP3216C常被用于手机、平板、导航设备等,其内置的接近传感器可以用于检测是否有物体接近,比如手机上用来检测耳朵是否接触听筒,如果检测到的话就表示正在打电话,手机就会关闭手机屏幕以省电。也可以使用环境光传感器检测光照强度,可以实现自动背光亮度调节。AP3216C结构如图所示:

 AP3216的设备地址为0X1E,同几乎所有的I2C从器件一样,AP3216C内部也有一些寄存器,通过这些寄存器我们可以配置AP3216C的工作模式,并且读取相应的数据。AP3216C用的寄存器如表所示:

 在表中,0x00这个寄存器是模式控制寄存器,用来设置AP3216C 的工作模式一般开始先将其设置为0X04,也就是先软件复位一次AP3216C。接下来根据实际使用情况选择合适的工作模式,比如设置为0X03,也就是开启ALS+PS+IR。从0x0A-0x0F这6个寄存器就是数据寄存器,保存着ALS、PS和IR这三个传感器获取到的数据值。如果同时打开ALS、PS和IR则读取间隔最少要112.5ms,因为AP3216C完成一次转换需要112.5ms。关于AP3216C的介绍就到这里,如果要想详细的研究此芯片的话,请大家自行查阅其数据手册。

实验源码

#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)


/*
 * I2C方向枚举类型
 */
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_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);
unsigned char i2c_master_stop(I2C_Type *base);
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
#include "bsp_i2c.h"
#include "bsp_delay.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寄存器)
	 * 设置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] : 要发送的数据,这里写入从设备地址
     *            
	 */ 
	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] : 要发送的数据,这里写入从设备地址
     *            
	 */ 
	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;	
}

#ifndef _BSP_AP3216C_H
#define _BSP_AP3216C_H

#include "imx6ul.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


#include "bsp_ap3216c.h"
#include "bsp_i2c.h"
#include "bsp_delay.h"
#include "cc.h"
#include "stdio.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 			*/
	delay_ms(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); 	
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/9430.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【高项】项目人力资源管理,沟通管理与干系人管理(十大管理)

【高项】项目人力资源管理&#xff0c;沟通管理与干系人管理&#xff08;十大管理&#xff09; 文章目录1、人力资源管理1.1 什么是人力资源管理&#xff1f;1.2 如何进行人力资源管理&#xff1f;&#xff08;过程&#xff09;1.3 人力资源管理工具1.4 人力资源管理文件2、沟通…

语雀笔记备份导出

参考: https://www.cnblogs.com/ssslinppp/p/17020303.htmlhttps://github.com/yuque/yuque-exporterhttps://zhuanlan.zhihu.com/p/582287220https://www.yuque.com/duzh929/blog/ocffqghttps://www.yuque.com/hijiaobu/datalife/onf6sy#BKajf 现在需要超级管理员,若是没有超级…

【华为机试真题详解JAVA实现】—整数与IP地址间的转换

目录 一、题目描述 二、解题代码 一、题目描述 原理:ip地址的每段可以看成是一个0-255的整数,把每段拆分成一个二进制形式组合起来,然后把这个二进制数转变成 一个长整数。 举例:一个ip地址为10.0.3.193 每段数字 相对应的二进制数 10 000…

GDPU C语言 天码行空6

1. 数组顺序查找 ⭐ 语法题 #include<stdio.h>int main() {int n,x,i;int a[102];scanf("%d", &n);for (i 0; i < n; i){scanf("%d", &a[i]);}scanf("%d", &x);int idx -1;//记录x的最大下标int max 0;// 记录大于x的数…

如何写一个优质高效的网络项目实施方案?这篇文章值得收藏!

随着互联网技术的不断发展&#xff0c;网络项目的实施成为了许多企业和组织的重要任务。网络项目实施方案是指在进行网络项目实施时&#xff0c;为了保障项目的顺利进行&#xff0c;达到项目目标和交付要求&#xff0c;所制定的详细计划和操作指南。一个好的网络项目实施方案对…

Unity Game FrameWork—模块使用—对象池分析

官方说明&#xff1a;提供对象缓存池的功能&#xff0c;避免频繁地创建和销毁各种游戏对象&#xff0c;提高游戏性能。除了 Game Framework 自身使用了对象池&#xff0c;用户还可以很方便地创建和管理自己的对象池。 下图是Demo中用到的对象池&#xff0c;所有的实体以及UI都使…

C++11多线程:原子操作std::automic-用于多个线程之间共享的变量。

系列文章目录 文章目录系列文章目录前言一、std::automic二、使用步骤1.代码案例总结前言 原子操作std::automic的基本概念和用法。 一、std::automic std::atomic来代表原子操作&#xff0c;std::automic是个类模板。其实std::atomic这个东西是用来封装某个类型的值的。 1.1…

echarts tooltip文字太长换行

tooltip文字太长换行&#xff0c;设置了宽度也没有换行&#xff0c;加上一句&#xff1a; extraCssText: ‘max-width:300px; white-space:pre-wrap’, 没加之前是这样&#xff1a; 加上之后 extraCssText: ‘max-width:300px; white-space:pre-wrap’, tooltip: {trigger: &…

Mybatis(六)缓存

缓存是Mybatis中非常重要的特性&#xff0c;Mybatis的一级缓存基于SqlSession实现&#xff0c;二级缓存基于Mapper实现。 一、缓存的使用 一级缓存默认开启&#xff0c;Mybatis提供了一个配置参数localCacheScope来控制一级缓存的级别&#xff0c;该参数的取值可以是session、…

主动配电网故障恢复的重构与孤岛划分统一模型研究【升级版本】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

CesiumForUnreal实现多边形裁剪3dTileset效果

文章目录 1.实现目标2.实现过程3.原理浅析4.参考资料1.实现目标 基于CesiumForUnreal插件的Cartographic Polygon Actor在Runtime运行时环境下实现对地形3DTileset的多边形裁剪效果,GIF动图如下: 2.实现过程 在Editor中的具体操作过程可以参考CesiumForUnreal官方裁剪地形的…

小巧型温湿度传感器

小巧型温湿度传感器是一种小巧的温湿度传感器&#xff0c;其作用是测量周围环境的温度和湿度&#xff0c;以及确定这些数据是否处于合适的范围内。这种传感器已经被广泛应用于医疗、工业、家居、冷链运输等领域&#xff0c;成为现代工业中不可或缺的一部分。小巧型温湿度传感器…

前置知识——Linux网络虚拟化

Linux网络虚拟化 信息是如何通过网络传输被另一个程序接收到的&#xff1f; 我们讨论的虚拟化网络是狭义的&#xff0c;它指容器间网络。 好了&#xff0c;下面我们就从 Linux 下网络通信的协议栈模型&#xff0c;以及程序如何干涉在协议栈中流动的信息来开始了解吧。 Linux…

全能PDF:Pdfium.Net SDK 2023-03-18 Crack

Pdfium.Net SDK 是领先的 .Net 库&#xff0c;用于生成、操作和查看可移植文档格式的文件。我们提供高级 c# / VB.Net API&#xff0c;用于在 WEB 服务器或任何其他服务器系统上动态创建 pdf&#xff0c;并在现有桌面或 WEB 应用程序中实现“另存为 PDF”功能。 入门&#xff1…

汽车网络管理的意义和分类

网络管理的意义&#xff1a; 1. 工作状态协同&#xff1a; 在任意多ECU节点网络工作时&#xff0c;对同一网络ECU的通信状态做统一的管理&#xff0c;保证各个ECU节点可以在条件满足的时候进入低功耗模式 2. 信息交互协同&#xff1a; 可以根据NM报文状态判定特定ECU的运行状态…

ESP32设备驱动-MPL3115A2压力传感器驱动

MPL3115A2压力传感器驱动 文章目录 MPL3115A2压力传感器驱动1、MPL3115A2介绍2、硬件准备3、软件准备4、驱动实现1、MPL3115A2介绍 MPL3115A2 是一款紧凑型压阻式绝对压力传感器,具有 I2C 数字接口。 MPL3115A2 具有 20 kPa 至 110 kPa 的宽工作范围,该范围涵盖了地球上的所…

CarSim仿真快速入门(二十四)-CarSimSimulink联合仿真中的输入和输出IO接口

导入和导出数组用于Simulink以外的外部仿真工具。同样的设置也用于LabVIEW、ASCET、FMI/FMU以及可能用MATLAB、Python和其他语言编写的自定义程序。 在所有这些情况下,I/O通道。导入和I/O通道。输出屏幕用于配置VS数学模型以满足外部仿真工具的通信要求。 I/O 通道:输出 输…

[攻城狮计划(三)] —— 看门狗定时器

&#x1f64c;秋名山码民的主页 &#x1f602;一个打过一年半的oier&#xff0c;写过一年多的Java&#xff0c;现在致力于学习iot应用的普通本科生 &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f64f;作者水平有限&#xff0c;如发现…

双非二本如何入职腾讯?只需要做好这些准备就能进大厂?

每年的招聘旺季在“金三银四”和“金九银十”这2段时间&#xff0c;许多在春招中没有找到心仪大厂offer的测试小伙伴最近有私信我&#xff0c;想要了解如何在秋招中一举获得心仪大厂的青睐&#xff0c;那今天我就来和大家扒一扒那些大厂自动化测试面试题以及注意事项哦&#xf…

Python解题 - CSDN周赛第43期

感觉周赛越来越无趣了&#xff0c;基本都是考过的题目。上期周赛也是&#xff0c;4道题都曾考过&#xff0c;问哥也都写过题解&#xff0c;奖品也不吸引人&#xff0c;实在没什么好写了。 回想前段时间用力过猛&#xff0c;刷了C站大部分OJ题&#xff0c;以致于现在看到题目就直…
最新文章