第十六章 I2C编程
I2C(Inter-Integrated Circuit BUS)是I2C BUS中文是目前应用最广泛的集成电路总线之一IMX6ULL有些相关的是,正好是总线NXP前身的PHILIPS设计。它仍然是应用最广泛的总线协议之一。
16.1 I2C协议
16.1.1 概述
I2C它是一条串行通信总线,采用多主从架构。最初,设计师开发它是为了让主板、嵌入式系统或手机连接低速周边设备。在小数据量场合使用,传输距离短,任何时候只能有一个主机。严格地说,I2C应该是软硬件结合体,所以我们将分物理层和协议层来介绍该总线。(总线结构如下图)
对于I2C在通信过程中,魏老师有一句生动的话:
为了传输数据,我们需要发送数据,从主设备到主设备,以及从设备到主设备的数据。
举个例子:
体育老师:你可以把球送给学生,也可以从学生那里拿球。
① 发球:
a. 老师说:注意(start)
b. 老师对A学生说,我想把球发给你(地址)。
c. 老师发球(传输)。
d. A收到球后,应该告诉老师(回应)。
e. 老师说下课(停)
② 接球:
a. 老师说注意了(start),
b. 老师说:B把球发给我(地址)
c. B把球发给老师(传)
d. 收到球后,老师对B说,说他收到了球(回应)。
e. 老师说下课(停)
让我们用这个简单的例子来解释IIC传输协议。
- 老师说注意了,说信号开始了(start)
- 老师告诉学生发送地址(address)
- 教师发球/接球,表示数据传输
- 老师/学生收到球,回应信号(ACK)
- 老师说下课,说IIC传输接受§
16.1.2 物理层
**特性1:**半双工(非全双工)
两条总线:
主芯片通过一个SDA线可以从设备或设备发送数据SDA读取数据,连接SDA线的引脚必须有两个引脚发送引脚/接受引脚)。详见下图device端I2Cn_SDA(output/input)。
**SCL(**串行时钟线):**同SDA引脚电路结构一致,引脚的输出驱动与输入缓冲连接在一起。输出为漏极开路的场效应管,输入缓冲为高输入阻抗的同相器。该结构具有以下特点:
a. 由于 SDA、SCL 借助外部上拉电阻,实现信号的线与逻辑;
b. 引脚在输出信号号的同时检测引脚上的电平,检测是否与刚才的输出一致。 为时钟同步和总线仲裁提供硬件基础。
SDA和CLK连接线上有两个上拉电阻。当总线有空时,两条线都是高电平。连接到总线上任何设备输出的低电平都会降低总线的信号。(物理连接如下图所示)
**特性2:**可配置地址和角色
每个连接到总线的设备都可以通过唯一的地址和其他设备通信,可以配置主机/从机角色和地址,主机可以用作主机发送器和主机接收器。
:多主机
IIC是真正的多主机总线,( IIC如果两个或两个以上的主机同时要求总线,则可以通过冲突检测和仲裁来防止总线数据损坏。
**特性4:**传输速率
在标准模式下,传输速率可达1000kb/s,在快速模式下4000kb/s。
**特性5:**负载和距离
节点的最大数量受地址空间和总线电容器的限制。此外,总电容器还限制了实际通信距离只有几米。
16.1.2 协议层
(1)
I2C在时钟的高电平周期内,保证协议数据的有效性,SDA在线数据必须保持稳定。数据线只能在时钟SCL平时换低电。
(2)
**起始条件:**当SCL高电平时,SDA从高到低的跳变被定义为起始条件。
**结束条件:**当SCL高电平时,SDA从低到高的在线跳转被定义为停止条件。请注意,起始和终止信号由主机发出并连接到I2C如果总线上有装置,I2C起始和终止信号很容易检测到总线的硬件接口。
起始条件后,总线视为忙碌状态,停止条件后视为空闲状态。
(3)
每当主机向从机发送一个字节数据时,主机总是需要等待从机发出响应信号,以确认从机是否成功接收数据。从机响应主机所需的时钟仍由主机提供。响应出现在每个主机完成8个数据位传输后的时钟周期中。低电平0表示响应,1表示非响应
(4)
SDA每个字节在线必须是8位长,每个字节传输几个字节transfer没有限制,每个字节后面必须有一个ACK。首先使用最高有效位数据(MSB)传输。
16.2 IMX6ULL的I2C控制器操作及寄存器介绍
IMX6ULL的I2C提供了标准I2C服务器和主服务器的功能,I2C设计与标准NXP I2C总线协议兼容,所以上面的通用知识完全可以应用在IMX6ULL I2C编程和控制。
掌握IMX6ULL I2C关键是要熟悉控制器的使用IMX6ULL I2C操作寄存器。
在关注寄存器之前,让我们先看看IMX6ULL的I2C控制器的框图,对IMX6ULL I2C初步了解结构和特点。
IMX6ULL的I2C控制器具有以下附加特性:
① 多主机运行。
② 可编程的软件有64种不同的串行时钟频率。
③ 应答位可选软件。
④ 中断驱动,逐字节数据传输。
⑤ 仲裁丢失中断与自动模式从主到从。
⑥ 生成/检测启动和停止信号。
⑦ 生成重复启动信号。
⑧ 生成和测试应答位。
⑨ 总线忙于检测。
另外的IMX6ULL 的I2C还支持标准模式和快速模式两种模式I2C最高数据传输率为100Kbits/s,数据传输速度最高为400Kbits/s。
通过以上介绍IMX6ULL的I2C控制器有一个整体的理解,以下组合I2C 框图对重点寄存器进行介绍。
16.2.1 I2C Memory Map
I2C包含5个16-bit 的寄存器
注:寄存器偏移0x0002/0x0006/0x000A/0x000E作为保留位。
可以看到I2C入口地址为21A_我们重点关注这一点,以后做实验,编程会用到。
16.2.2 Register
让我们先介绍一下这些寄存器的用途,然后结合位图在编程框架中进行解释。以下部分也可以先跳过,然后回头查看。
16.2.2.1 I2C Address Register (I2Cx_IADR)地址寄存器的偏移量为0h。
a. 为保留位即只读为0。
b. (ADR)位是I2C从机时的地址。从属模式是I2C默认模式,该地址作为相应的从机地址,不能被软件复位。
16.2.2.2 I2C Frequency Divider Register (I2Cx_IFDR)分频寄存器的偏移量为4h。
a. 保留位,即只读为0。
b. 位为I2C时钟频率
注:该值在传输过程中不应改变,但可在以前改变。
I2C_IFDR时钟配置用于比特率选择,寄存器不会被软件重置。
寄存器IC位设置计算方法如下:
I2C的时钟源来源于=66Mhz
= 528 MHz
= 528 MHz
= (PLL2_PFD2 / ahb_podf )/ ipg_podf = (528 MHz/4)/2 = 66Mhz
= IPG_CLK_ROOT/perclk_podf = 66 MHz/1 =
设置I2C的波特率为100K, 因此当分频值=66000000/100000=660.
参考Table 31-3. I2C_IFDR Register Field Values 中只有
即寄存器IFDR的IC位设置为0X15。
16.2.2.3 I2C Control Register (I2Cx_I2CR)控制寄存器,偏移量为8h
a. 为保留位,即只读为0。
b. 为I2C使能位。(0 disable,1 enable)
c. 为I2C中断使能位。(0 disable,1 enable)
d. 为主/从模式选择位(0 slave mode,1 master mode )
e. 为传输方向模式选择位 (0 receive mode,1 transmit mode)
f. 为应答使能位 (0 ACK , 1 NO ACK)
g. 重复开始信号(0 no repeat start,1 Generates repeat start)
h. 保留位
16.2.2.4 I2C Status Register (I2Cx_I2SR)状态寄存器,偏移量为Ch
a. 为保留位即只读为0。
b. 数据传输状态位(0 传输中,1 传输完成)
c. I2C地址是否为从标识(0 不表示,1 是从机地址)
d. I2C总线忙状态标识位(0 空闲,1 忙 )
e. 仲裁丢失位 (0 正常,1 仲裁丢失)
f. 保留位
g. 从机读写标识位 (0 slave接收,主向从写 , 1 slave发送 主向从读)
h. I2C中断(0无中断等待, 1有中断等待)
i. 应答信号标识位(0检测到ACK, 1检测到NO ACK)
6.2.2.5 I2C Data I/O Register (I2Cx_I2DR)数据寄存器,偏移量为10h
a. 为保留位即只读为0。
b. 数据字节
注意:在主接收模式下,读取数据寄存器允许发生读取并初始化下一个字节被接收。在从模式下,相同功能需要编址后生效。
低8位为有效数据位,发送数据时将数据写到这个寄存器中,如果要接收时直接读取该寄存器中的数据。
16.3 AP3216C操作方法
16.3.1 AP3216C简介
AP3216C 模块的核心就是这个芯片本身。这颗芯片集成了光强传感器(ALS: Ambient Light Sensor),接近传感器(PS: Proximity Sensor),还有一个红外LED(IR LED)。这个芯片设计的用途是给手机之类的使用,比如:返回当前环境光强以便调整屏幕亮度;用户接听电话时,将手机放置在耳边后,自动关闭屏幕避免用户误触碰。该芯片通过I2C接口作为slave与主控制器相连,支持中断。
16.3.2 AP3216C特性
① 接口:I2C
② 速率:FS mode 可达400kbit/s
③ 模式:ALS/PS+IR/ALS+PS+IR/PD/ALS once/SW Reset/PS+IR once/ALS+PS+IR once。
④ 内置温度补偿电路。
⑤ 工作温度:-30℃ to +80℃
⑥ ALS
a. (0-65536)16位有效的线性输出
b. 4量程动态范围可选择
c. 防闪烁(50/60 HZ)
d. 高敏感性@黑玻璃
e. 窗口损失补偿
⑦ PS
a. (0-1023)10位有效线性输出
b. 4增益
c. 高环境光抑制
d. 串扰补偿
⑧ 封装大小:4.1mm x 2.4mm x 1.35mm
16.3.3 AP3216C结构图
下面是AP3216C的结构图以及典型电路应用图
从图上看AP3216C结构简单,应用方便。本来模块我们其实也不用太深究原理,所以重点我们放在对典型I2C从设备的应用上。
16.3.4 AP3216C寄存器及使用
a. I2C从设备地址
从设备地址有7bit ,一个读/写位应该由主设备附加到从设备地址以正确地与设备通信。
AP3216的地址是0X1E。
b. 系统寄存器表
同其他所有从设备一样,AP3216C有它的内部寄存器让我们来设置和操作。表格如下所示。可以知道。次级地址0x00为系统配置寄存器,并且提供了后面7bit组合的工作模式供选择。
后面会参考这张表格对AP3216C进行编程并读取数据。
16.4 I2C控制器编程_框架
之前的所有铺垫都是为了实现I2C通讯,所以怎么用代码实现也是尤为关键的一个问题。本节源码目录在
首先,需要定义I2C寄存器的入口地址,各个寄存器绝对地址,我们代码仅使用I2C1,故仅先定义I2C1相关寄存器。
/* *The I2C contains five 16-bit registers. */
/* 绝对地址 寄存器名 位宽(bit)权限 复位值 章节/页 * 21A_0000 (I2C1_IADR) 16 R/W 0000h 31.7.1/1463 * 21A_0004 (I2C1_IFDR) 16 R/W 0000h 31.7.2/1463 * 21A_0008 (I2C1_I2CR) 16 R/W 0000h 31.7.3/1465 * 21A_000C (I2C1_I2SR) 16 R/W 0081h 31.7.4/1466 * 21A_0010 (I2C1_I2DR) 16 R/W 0000h 31.7.5/1468 */
#define I2C1_BASE_ADDR (0x21A0000u)
/* I2C1 Base address */
#define I2C1 ((I2C_REGISTERS *)I2C1_BASE_ADDR)
有了上面的地址,定义如下寄存器结构体,这样在使用时,我们仅需要把入口地址定义成如下结构,那么就可以通用I2C1-IC25,在使用时传入相应的入口地址即可。
/* 寄存器地址的宏结构体定义,此种方式仅定义入口地址即可 */
/* all registers address is Base address + xh offset*/
typedef struct tagRegisters{
volatile uint16_t IADR; /*I2C Address Register, offset: 0x0 */
uint8_t ReservedIADR[2];
volatile uint16_t IFDR; /*I2C Frequency Divider Register, offset: 0x4 */
uint8_t ReservedIFDR[2];
volatile uint16_t I2CR; /*I2C Control Register, offset: 0x8 */
uint8_t ReservedI2CR[2];
volatile uint16_t I2SR; /*I2C Status Register, offset: 0xC */
uint8_t ReservedI2SR[2];
volatile uint16_t I2DR; /*I2C Data I/O Register, offset: 0x10 */
} I2C_REGISTERS;
有了基本的信息,我们也要有相应的操作,主要有读和写两个操作码。
typedef enum enI2C_OPCODE
{
I2C_WRITE = 0, /* 主机向从机写数据 */
I2C_READ = 1, /* 主机从从机读数据 */
I2C_DONOTHING_BULL
} I2C_OPCODE;
然后需要有个分配和传输承载信息角色的载体,我们仅以做master为例,如果做通用的结构体,还可以加上角色等信息。而master的主传输结构体包括目标以下信息:
typedef struct tagI2cTransfer
{
uint8_t ucSlaveAddress; /* 7位从机地址 */
uint32_t ulOpcode ; /* 操作码*/
uint32_t ulSubAddress; /* 目标寄存器地址 */
uint8_t ulSubAddressLen; /* 寄存器地址长度 */
volatile uint32_t ulLenth; /* 数据长度 */
uint8_t *volatile pbuf; /* 数据*/
} I2C_TRANSFER;
有了这些寄存器的基本信息、操作方式、传输结构,下面来实现具体的函数和功能。
16.4.1 i2c_init
void i2c_init(I2C_REGISTERS *I2C_BASE);81 void i2c_init(I2C_REGISTERS *I2C_BASE);
通过传入I2C1的入口地址,完成初始化。
因为不使用中断服务函数模式,初始化代码非常简单,我们仅需要将I2CR(bit7)(位图如下)
置0后写入IFDR为0x15(位图如下),设置波特率为100k。(具体计算方法参考16.2 IMX6ULL的I2C控制器操作与寄存器介绍中关于分频寄存器),然后再使能I2C,将I2CR(bit7)置1 。
代码如下:
I2C_BASE->I2CR &= ~(1 << 7);
I2C_BASE->IFDR = 0x15;
I2C_BASE->I2CR |= (1<<7);
16.4.2 i2c_transfer
函数原型如下:
uint8_t i2c_transfer(I2C_REGISTERS *I2C_BASE, I2C_TRANSFER *transfer);
参数是I2C控制器入口地址以及传输结构体,作为通用公共传输函数,负责公共流程
下面是函数流程图。
清除标识位是bit-4 IAL 仲裁位,bit-1 IIF 中断标志位都置位,位图如图所示:
代码如下:
I2C_BASE->I2SR &= ~((1 << 1) | (1 << 4));
等待传输完成需要判断上面的ICF位:
while(!((I2C_BASE->I2SR >> 7) & 0X1)){
};
16.4.3 i2c_start
start需要先判断I2C是否忙,然后设置发送模式,最后将slave地址通过数据寄存器发出去,函数声明如下:
uint8_t i2c_start(I2C_REGISTERS *I2C_BASE, uint8_t ucSlaveAddr, uint32_t ulOpcode);
首先,判断忙是上面的IBB位
if(I2C_BASE->I2SR & (1 << 5))
设置发送模式MSTA设置为1即master,MTX设置为1即发送模式,位图如下:
I2C_BASE->I2CR |= (1 << 5) | (1 << 4);
接下来将slave地址放到数据寄存器中发送,最后一位是操作码,位图如下:
63 I2C_BASE->I2DR = ((uint32_t)ucSlaveAddr << 1) | ((I2C_READ == ulOpcode)? 1 : 0);
16.4.4 i2c_check
check中传入的是I2SR寄存器中的值,代码如下:
uint8_t i2c_check(I2C_REGISTERS *I2C_BASE, uint32_t status);
判断仲裁位即SR寄存器bit4,如果置位,需要清除仲裁位,并重启I2C。如果没有收到从机的应答信号即SR寄存器bit0是否为1,如果没有返回状态码NAK。代码如下:
uint8_t i2c_check(I2C_REGISTERS *I2C_BASE, uint32_t status);
/* 检查是否发生仲裁丢失错误 */
if(status & (1<<4))
{
I2C_BASE->I2SR &= ~(1<<4); /* 清除仲裁丢失错误位 */
I2C_BASE->I2CR &= ~(1 << 7); /* 先关闭I2C */
I2C_BASE->I2CR |= (1 << 7); /* 重新打开I2C */
return I2C_ARBITRATIONLOST;
}
else if(status & (1 << 0)) /* 没有接收到从机的应答信号 */
{
return I2C_NAK; /* 返回NAK(No acknowledge) */
}
return I2C_OK;
16.4.5 i2c_write
写函数完成清除标志位,设置模式为发送,把buf中的数据写入I2DR数据寄存器中,等待传输完成(判断的是I2SR bit1 IIF),然后清除该位。然后检查ACK,最后再清除标识位。代码如下:
void i2c_write(I2C_REGISTERS *I2C_BASE, const uint8_t *pbuf, uint32_t len)
{
/* 等待传输完成 */
while(!(I2C_BASE->I2SR & (1 << 7)));
I2C_BASE->I2SR &= ~(1 << 1); /* 清除标志位 */
I2C_BASE->I2CR |= 1 << 4; /* 发送数据 */
while(len--)
{
I2C_BASE->I2DR = *pbuf++; /* 将buf中的数据写入到I2DR寄存器 */
while(!(I2C_BASE->I2SR & (1 << 1))); /* 等待传输完成 */
I2C_BASE->I2SR &= ~(1 << 1); /* 清除标志位 */
/* 检查ACK */
if(i2c_check(I2C_BASE, I2C_BASE->I2SR))
break;
}
I2C_BASE->I2SR &= ~(1 << 1);
i2c_stop(I2C_BASE); /* 发送停止信号 */
}
16.4.6 i2c_read
读函数具体流程如下,值得注意两个点,一个是假读是为了启动用的,有兴趣的小伙伴可以移步https://community.nxp.com/thread/378405 查看官方解释。另外如果仅需要读一个字节的话,需要发送一个NACK信号。即将I2CR bit3 TXAK置1。其他寄存器和操作我们在上面已经都讲解过。代码如下:
void i2c_read(I2C_REGISTERS *I2C_BASE, uint8_t *pbuf, uint32_t len)
{
volatile uint8_t dummy = 0;
dummy++; /* 防止编译报错 */
/* 等待传输完成 */
while(!(I2C_BASE->I2SR & (1 << 7)));
I2C_BASE->I2SR &= ~(1 << 1); /* 清除中断挂起位 */
I2C_BASE->I2CR &= ~((1 << 4) | (1 << 3)); /* 接收数据 */
/* 如果只接收一个字节数据的话发送NACK信号 */
if(len == 1)
I2C_BASE->I2CR |= (1 << 3);
dummy = I2C_BASE->I2DR; /* 假读 */
while(len--)
{
while(!(I2C_BASE->I2SR & (1 << 1))); /* 等待传输完成 */
I2C_BASE->I2SR &= ~(1 << 1); /* 清除标志位 */
if(len == 0)
{
i2c_stop(I2C_BASE); /* 发送停止信号 */
}
if(len == 1)
{
I2C_BASE->I2CR |= (1 << 3);
}
*pbuf++ = I2C_BASE->I2DR;
}
}
16.4.7 I2C读写标准流程
下面是是I2C的读写标准流程,可能实际使用时根据需求略有异同。
写寄存器的标准流程如下图:
① 1.Master发起START
② 2.Master发送I2C addr(7bit)和w操作0(1bit),等待ACK
③ 3.Slave发送ACK
④ 4.Master发送reg addr(8bit),等待ACK
⑤ Slave发送ACK
⑥ Master发送data(8bit),即要写入寄存器中的数据,等待ACK
⑦ Slave发送ACK
⑧ 第6步和第7步可以重复多次,即顺序写多个寄存器
⑨ Master发起STOP
读寄存器的标准流程如下图:
① Master发送I2C addr(7bit)和w操作1(1bit),等待ACK
② Slave发送ACK
③ Master发送reg addr(8bit),等待ACK
④ Slave发送ACK
⑤ Master发起RESTART
⑥ Master发送I2C addr(7bit)和r操作1(1bit),等待ACK
⑦ Slave发送ACK
⑧ Slave发送data(8bit),即寄存器里的值
⑨ Master发送ACK
⑩ 第8步和第9步可以重复多次,即顺序读多个寄存器
⑪ Master发送NO ACK表示读取完成,从机也不用发送ACK
⑫ Master发送STOP
1.5 I2C控制器编程_中断
I2C控制器中和中断有关的寄存器如下:
**IIEN:**I2C_I2CR(bit6)(0 disable I2C interrupt ,1 enable I2C interrupt)
**IIF:**I2C_I2SR (bit1) (0 No I2C interrupt pending ,1 An interrupt is pending)
上面分别是中断使能位,中断状态位。
编码中在传送完1byte后可以通过判断IIF状态来确认ACK和传输完成。当然作为从机时,收到自己的地址后也可以进入中断。
16.6 AP3216C编程
AP3216C的编程基于I2C初始化后,write/read功能之上。
代码路径在
16.6.1 AP3216C初始化IO
参考100ASK_IMX6ULL原理图如下:
AP3216C接口简单,仅将PIN2和PIN8分别连接到I2C1_SCL和I2C1_SDA。而另外的一端从下图可知,I2C1_SCL使用的UART4_RXD,I2C1_SDA使用的UART4_TXD这两个IO。
16.6.2 初始化AP3216C
通过《1.3-1.3.4 AP3216C寄存器及使用》 的系统寄存器表格可知,0X00这个寄存器是模式控制寄存器,用来设置AP3216C的工作模式。
初始化流程如下:
① 复位(设置0X00寄存器为0X04)
② 设置工作模式(如0X03,开启ALS+PS+IR,其他模式请参考16.3中系统寄存器表格)
③ 设置中断(可选)
代码如下:
ret = i2c_write_one_byte(AP3216C_ADDR, AP3216C_SYSTEMCONG, 0X4);
mdelay(10); /* AP33216C复位至少10ms */
ret = i2c_write_one_byte(AP3216C_ADDR, AP3216C_SYSTEMCONG, 0X3);
判断是否初始化成功,就读一下刚写入的data是否为0X3,代码如下:
data = i2c_read_one_byte(AP3216C_ADDR, AP3216C_SYSTEMCONG);
i2c_write_one_byte和i2c_read_one_byte就是刚才 i2c_transfer函数入参的填写过程,这里不多介绍。详细可以参考i2c.c中具体实现。
16.6.3 AP3216C数据读取
重点介绍一下下面的读数据操作,函数原型如下:
void ap3216c_read_data(uint16_t *ir, uint16_t *ps, uint16_t *als)
入参和出参很简单,分别是这三个寄存器的值。
寄存器AP3216C_IRDATALOW到AP3216C_PSDATAHIGH一共6个寄存器,将这个6个寄存器的值顺序读取,分别放到ir,ps,als变量中。
void ap3216c_read_data(uint16_t *ir, uint16_t *ps, uint16_t *als)
{
uint8_t buf[6];
uint8_t i;
for(i = 0; i < 6; i++) /* 循环读取所有传感器数据 */
{
buf[i] = i2c_read_one_byte(AP3216C_ADDR, AP3216C_IRDATALOW + i);
}
if(buf[0] & 0X80) /* IR_OF位为1,则数据无效 */
{
*ir = 0;
}
else /* 读取IR传感器的数据 */
{
*ir = ((uint16_t)buf[1] << 2) | (buf[0] & 0X03);
}
/* 读取ALS传感器的数据 */
*als = ((uint16_t)buf[3] << 8) | buf[2];
if(buf[4] & 0x40) /* IR_OF位为1,则数据无效*/
{
*ps = 0;
}
else /* 读取PS传感器的数据 */
{
*ps = ((uint16_t)(buf[5] & 0X3F) << 4) | (buf[4] & 0X0F);
}
return;
}
从0X0A~0X0F这6个寄存器就是数据寄存器,保存着ALS、PS和IR这三个传感器获取到的数据值。如果同时打开ALS、PS和IR的读取间隔最少要112.5ms,其他情况时间间隔,如下图所示:
16.7 AP3216C上机实验
通过下面的两个例程总结本章对于AP3216C通过I2C总线将数据发送给IMX6ULL并使用不同输出方法显示。实验程序结构如下:
① 实验中的显示或输出设备
② 通信方式
③ 设备
④ 应用
16.7.1 AP3216C实验一
代码在
通过上述实验程序结构图中1-3步骤后,应用通过如下方式获取数据,并显示结果。
while(!ret)
{
/*环境光强度(ALS)、接近距离(PS)和红外线强度(IR)*/
ap3216c_read_data(&ir,&ps,&als);
/*调整光强和接近距离可以控制LED亮灭*/
if (als>100 || ps >1000)
{
led_ctl(1);
}
else
{
led_ctl(0);
}
}
16.7.2 参考章节《4-1.4编译程序》编译程序
进入
16.7.3 参考章节《3-1.4映像文件烧写、运行》烧写、运行程序
初始化成功后会绿灯闪烁一下后关闭,LED用来判断ALS或者PS寄存器值的是否超过阈值,如果超过绿灯亮起,否则常暗。
下图常暗:
下图调整板子入光或者接近传感器后绿灯亮起:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8bHFu5S5-1642060404761)(https://cdn.jsdelivr.net/gh/DongshanPI/HomeSite-Photos@main/IMX6ULL-BareMetal/I2C_Program_image0026.png)]
16.7.4 AP3216C实验二
代码在
通过上述实验程序结构图中1-3步骤后,应用通过如下方式获取数据,并显示结果。
while(1)
{
delay(100000);
/*环境光强度(ALS)、接近距离(PS)和红外线强度(IR)*/
ap3216c_read_data(&ir,&ps,&als);
printf("ir=%d ps=%d als=%d\n\r",ir,ps,als);
}
16.7.5 参考章节《4-1.4编译程序》编译程序
进入 **裸机Git仓库 NoosProgramProject/(16_I2C编程\002_example_i2c_ap3216c_printf_show)**源码目录进行编译。
16.7.6 参考章节《3-1.4映像文件烧写、运行》烧写、运行程序
实验结果如图所示: