1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-300792-1-1.html 3)对正点原子Linux感兴趣的同学可以加群讨论:935446741 4)关注正点原子公众号,获取最新资料更新
第二十六章 I2C实验
I2C是最常用的通信接口,众多的传感器都会提供I2C接口来和主控相连,比如陀螺仪、加速度计、触摸屏等等。所以I2C是做嵌入式开发必须掌握的,I.MX6U有4个I2C接口,可以通过这4个I2C接口来连接一些I2C外设。I.MX6U-ALPHA使用I2C1接口连接了一个距离传感器AP3216C,本章我们就来学习如何使用I.MX6U的I2C接口来驱动AP3216C,读取AP3216C的传感器数据。
26.1 I2C & AP3216C简介 26.1.1 I2C简介 I2C是很常见的一种总线协议,I2C是NXP公司设计的,I2C使用两条线在主控制器和从机之间进行数据通信。一条是SCL(串行时钟线),另外一条是SDA(串行数据线),这两条数据线需要接上拉电阻,总线空闲的时候SCL和SDA处于高电平。I2C总线标准模式下速度可以达到100Kb/S,快速模式下可以达到400Kb/S。I2C总线工作是按照一定的协议来运行的,接下来就看一下I2C协议。 I2C是支持多从机的,也就是一个I2C控制器下可以挂多个I2C从设备,这些不同的I2C从设备有不同的器件地址,这样I2C主控制器就可以通过I2C设备的器件地址访问指定的I2C设备了,一个I2C总线连接多个I2C设备如图26.1.1.1所示:
图26.1.1.1 I2C多个设备连接结构图 图26.1.1.1中SDA和SCL这两根线必须要接一个上拉电阻,一般是4.7K。其余的I2C从器件都挂接到SDA和SCL这两根线上,这样就可以通过SDA和SCL这两根线来访问多个I2C设备。 接下来看一下I2C协议有关的术语: 1、起始位 顾名思义,也就是I2C通信起始标志,通过这个起始位就可以告诉I2C从机,“我”要开始进行I2C通信了。在SCL为高电平的时候,SDA出现下降沿就表示为起始位,如图26.1.1.2所示:
图26.1.1.2 I2C通信起始位 2、停止位 停止位就是停止I2C通信的标志位,和起始位的功能相反。在SCL位高电平的时候,SDA出现上升沿就表示为停止位,如图26.1.1.3所示:
图26.1.1.3 I2C通信停止位 3、数据传输 I2C总线在数据传输的时候要保证在SCL高电平期间,SDA上的数据稳定,因此SDA上的数据变化只能在SCL低电平期间发生,如图26.1.1.4所示:
图26.1.1.4 I2C数据传输 4、应答信号 当I2C主机发送完8位数据以后会将SDA设置为输入状态,等待I2C从机应答,也就是等到I2C从机告诉主机它接收到数据了。应答信号是由从机发出的,主机需要提供应答信号所需的时钟,主机发送完8位数据以后紧跟着的一个时钟信号就是给应答信号使用的。从机通过将SDA拉低来表示发出应答信号,表示通信成功,否则表示通信失败。 5、I2C写时序 主机通过I2C总线与从机之间进行通信不外乎两个操作:写和读,I2C总线单字节写时序如图26.1.1.5所示:
图26.1.1.5 I2C写时序 图26.1.1.5就是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)、停止信号。 6、I2C读时序 I2C总线单字节读时序如图26.1.1.6所示:
图26.1.1.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、I2C多字节读写时序 有时候我们需要读写多个字节,多字节读写时序和单字节的基本一致,只是在读写数据的时候可以连续发送多个自己的数据,其他的控制时序都是和单字节一样的。 26.1.2 I.MX6U I2C简介 I.MX6U提供了4个I2C外设,通过这四个I2C外设即可完成与I2C从器件进行通信,I.MX6U的I2C外设特性如下: ①、与标准I2C总线兼容。 ②、多主机运行 ③、软件可编程的64中不同的串行时钟序列。 ④、软件可选择的应答位。 ⑤、开始/结束信号生成和检测。 ⑥、重复开始信号生成。 ⑦、确认位生成。 ⑧、总线忙检测 I.MX6U的I2C支持两种模式:标准模式和快速模式,标准模式下I2C数据传输速率最高是100Kbits/s,在快速模式下数据传输速率最高为400Kbits/s。 我们接下来看一下I2C的几个重要的寄存器,首先看一下I2Cx_IADR(x=1~4)寄存器,这是I2C的地址寄存器,此寄存器结构如图26.1.2.1所示:
图26.1.2.1 寄存器I2Cx_IADR结构 寄存器I2Cx_IADR只有ADR(bit7:1)位有效,用来保存I2C从设备地址数据。当我们要访问某个I2C从设备的时候就需要将其设备地址写入到ADR里面。接下来看一下寄存器I2Cx_IFDR,这个是I2C的分频寄存器,寄存器结构如图26.1.2.2所示:
图26.1.2.2 寄存器I2Cx_IFDR结构 寄存器I2Cx_IFDR也只有IC(bit5:0)这个位,用来设置I2C的波特率,I2C的时钟源可以选择IPG_CLK_ROOT=66MHz,通过设置IC位既可以得到想要的I2C波特率。IC位可选的设置如图26.1.2.3所示:
图26.1.2.3 IC设置 不像其他外设的分频设置一样可以随意设置,图26.1.2.3中列出了IC的所有可选值。比如现在I2C的时钟源为66MHz,我们要设置I2C的波特率为100KHz,那么IC就可以设置为0X15,也就是640分频。66000000/640=103.125KHz≈100KHz。 接下来看一下寄存器I2Cx_I2CR,这个是I2C控制寄存器,此寄存器结构如图26.1.2.4所示:
图26.1.2.4 寄存器I2Cx_I2CR结构 寄存器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的话产生一个重新开始信号。 接下来看一下寄存器I2Cx_I2SR,这个是I2C的状态寄存器,寄存器结构如图26.1.2.5所示:
图26.1.2.5 寄存器I2Cx_I2SR结构 寄存器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信号。 最后一个寄存器就是I2Cx_I2DR,这是I2C的数据寄存器,此寄存器只有低8位有效,当要发送数据的时候将要发送的数据写入到此寄存器,如果要接收数据的话直接读取此寄存器即可得到接收到的数据。 关于I2C的寄存器就介绍到这里,关于这些寄存器详细的描述,请参考《I.MX6ULL参考手册》第1462页的31.7小节。 26.1.3 AP3216C简介 I.MX6U-ALPHA开发板上通过I2C1连接了一个三合一环境传感器:AP3216C,AP3216C是由敦南科技推出的一款传感器,其支持环境光强度(ALS)、接近距离(PS)和红外线强度(IR)这三个环境参数检测。该芯片可以通过IIC接口与主控制相连,并且支持中断,AP3216C的特点如下: ①、I2C接口,快速模式下波特率可以到400Kbit/S ②、多种工作模式选择:ALS、PS+IR、ALS+PS+IR、PD等等。 ③、内建温度补偿电路。 ④、宽工作温度范围(-30°C ~ +80°C)。 ⑤、超小封装,4.1mm x 2.4mm x 1.35mm ⑥、环境光传感器具有16位分辨率。 ⑦、接近传感器和红外传感器具有10位分辨率。 AP3216C常被用于手机、平板、导航设备等,其内置的接近传感器可以用于检测是否有物体接近,比如手机上用来检测耳朵是否接触听筒,如果检测到的话就表示正在打电话,手机就会关闭手机屏幕以省电。也可以使用环境光传感器检测光照强度,可以实现自动背光亮度调节。 AP3216C结构如图26.1.3.1所示:
图26.1.3.1 AP3216C结构图 AP3216的设备地址为0X1E,同几乎所有的I2C从器件一样,AP3216C内部也有一些寄存器,通过这些寄存器我们可以配置AP3216C的工作模式,并且读取相应的数据。AP3216C我们用的寄存器如表26.1.3.1所示: 寄存器地址 位 寄存器功能 描述 0X00 2:0 系统模式 000:掉电模式(默认)。 001:使能ALS。 010:使能PS+IR。 011:使能ALS+PS+IR。 100:软复位。 101:ALS单次模式。 110:PS+IR单次模式。 111:ALS+PS+IR单次模式。 0X0A 7 IR低位数据 0:IR&PS数据有效,1:无效 1:0 IR最低2位数据。 0X0B 7:0 IR高位数据 IR高8位数据。 0X0C 7:0 ALS低位数据 ALS低8位数据。 0X0D 7:0 ALS高位数据 ALS高8位数据。 0X0E 7 PS低位数据 0,物体在远离;1,物体在接近。 6 0,IR&PS数据有效;1,IR&PS数据无效 3:0 PS最低4位数据。 0X0F 7 PS高位数据 0,物体在远离;1,物体在接近。 6 0,IR&PS数据有效;1,IR&PS数据无效 5:0 PS最低6位数据。 表26.1.3.1 本章使用的AP3216C寄存器表 在表26.1.3.1中,0X00这个寄存器是模式控制寄存器,用来设置AP3216C的工作模式,一般开始先将其设置为0X04,也就是先软件复位一次AP3216C。接下来根据实际使用情况选择合适的工作模式,比如设置为0X03,也就是开启ALS+PS+IR。从0X0A~0X0F这6个寄存器就是数据寄存器,保存着ALS、PS和IR这三个传感器获取到的数据值。如果同时打开ALS、PS和IR则读取间隔最少要112.5ms,因为AP3216C完成一次转换需要112.5ms。关于AP3216C的介绍就到这里,如果要想详细的研究此芯片的话,请大家自行查阅其数据手册。 本章实验中我们通过I.MX6U的I2C1来读取AP3216C内部的ALS、PS和IR这三个传感器的值,并且在LCD上显示。开机会先检测AP3216C是否存在,一般的芯片是有个ID寄存器,通过读取ID寄存器判断ID是否正确就可以检测芯片是否存在。但是AP3216C没有ID寄存器,所以我们就通过向寄存器0X00写入一个值,然后再读取0X00寄存器,判断读出得到值和写入的是否相等,如果相等就表示AP3216C存在,否则的话AP3216C就不存在。本章的配置步骤如下: 1、初始化相应的IO 初始化I2C1相应的IO,设置其复用功能,如果要使用AP3216C中断功能的话,还需要设置AP3216C的中断IO。 2、初始化I2C1 初始化I2C1接口,设置波特率。 3、初始化AP3216C 初始化AP3216C,读取AP3216C的数据。 26.2 硬件原理分析 本试验用到的资源如下: ①、指示灯LED0。 ②、 RGB LCD屏幕。 ③、AP3216C ④、串口 AP3216C是在I.MX6U-ALPHA开发板底板上,原理图如图26.2.1所示:
图26.2.1 AP3216C原理图 从图26.2.1可以看出AP3216C使用的是I2C1,其中I2C1_SCL使用的UART4_TXD这个IO、I2C1_SDA使用的是UART4_R XD这个IO。 26.3 实验程序编写 本实验对应的例程路径为:开发板光盘-> 1、裸机例程-> 17_i2c。 本章实验在上一章例程的基础上完成,更改工程名字为“ap3216c”,然后在bsp文件夹下创建名为“i2c”和“ap3216c”的文件夹。在bsp/i2c中新建bsp_i2c.c和bsp_i2c.h这两个文件,在bsp/ap3216c中新建bsp_ap3216c.c和bsp_ap3216c.h这两个文件。bsp_i2c.c和bsp_i2c.h是I.MX6U的I2C文件,bsp_ap3216c.c和bsp_ap3216c.h是AP3216C的驱动文件。在bsp_i2c.h中输入如下内容:
示例代码26.3.1 bsp_i2c.h文件代码
1 #ifndef _BSP_I2C_H
2 #define _BSP_I2C_H
3 /***************************************************************
4 Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
5 文件名 : bsp_i2c.h
6 作者 : 左忠凯
7 版本 : V1.0
8 描述 : IIC驱动文件。
9 其他 : 无
10 论坛 : www.openedv.com
11 日志 : 初版V1.0 2019/1/15 左忠凯创建
12 ***************************************************************/
13 #include "imx6ul.h"
14
15 /* 相关宏定义 */
16 #define I2C_STATUS_OK (0)
17 #define I2C_STATUS_BUSY (1)
18 #define I2C_STATUS_IDLE (2)
19 #define I2C_STATUS_NAK (3)
20 #define I2C_STATUS_ARBITRATIONLOST (4)
21 #define I2C_STATUS_TIMEOUT (5)
22 #define I2C_STATUS_ADDRNAK (6)
23
24 /*
25 * I2C方向枚举类型
26 */
27 enum i2c_direction
28 {
29 kI2C_Write = 0x0, /* 主机向从机写数据 */
30 kI2C_Read = 0x1, /* 主机从从机读数据 */
31 };
32
33 /*
34 * 主机传输结构体
35 */
36 struct i2c_transfer
37 {
38 unsigned char slaveAddress; /* 7位从机地址 */
39 enum i2c_direction direction; /* 传输方向 */
40 unsigned int subaddress; /* 寄存器地址 */
41 unsigned char subaddressSize; /* 寄存器地址长度 */
42 unsigned char *volatile data; /* 数据缓冲区 */
43 volatile unsigned int dataSize; /* 数据缓冲区长度 */
44 };
45
46 /*
47 *函数声明
48 */
49 void i2c_init(I2C_Type *base);
50 unsigned char i2c_master_start(I2C_Type *base,
unsigned char address,
enum i2c_direction direction);
51 unsigned char i2c_master_repeated_start(I2C_Type *base,
unsigned char address,
enum i2c_direction direction);
52 unsigned char i2c_check_and_clear_error(I2C_Type *base,
unsigned int status);
53 unsigned char i2c_master_stop(I2C_Type *base);
54 void i2c_master_write(I2C_Type *base, const unsigned char *buf,
unsigned int size);
55 void i2c_master_read(I2C_Type *base, unsigned char *buf,
unsigned int size);
56 unsigned char i2c_master_transfer(I2C_Type *base,
struct i2c_transfer *xfer);
57
58 #endif
第16到22行定义了一些I2C状态相关的宏。第27到31行定义了一个枚举类型i2c_direction,此枚举类型用来表示I2C主机对从机的操作,也就是读数据还是写数据。第36到44行定义了一个结构体i2c_transfer,此结构体用于I2C的数据传输。剩下的就是一些函数声明了,总体来说bsp_i2c.h文件里面的内容还是很简单的。接下来在文件bsp_i2c.c里面输入如下内容:
示例代码26.3.2 bsp_i2c.c文件代码
/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名 : bsp_i2c.c
作者 : 左忠凯
版本 : V1.0
描述 : IIC驱动文件。
其他 : 无
论坛 : www.openedv.com
日志 : 初版V1.0 2019/1/15 左忠凯创建
***************************************************************/
1 #include "bsp_i2c.h"
2 #include "bsp_delay.h"
3 #include "stdio.h"
4
5 /*
6 * @description : 初始化I2C,波特率100KHZ
7 * @param – base : 要初始化的IIC设置
8 * @return : 无
9 */
10 void i2c_init(I2C_Type *base)
11 {
12 /* 1、配置I2C */
13 base->I2CR &= ~(1
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?