I2C实验

硬件分析

  • mpu6050

    ../../_images/image-20210822161234587.png

  • AP3216C

    ../../_images/image-20210822161322502.png

  • 触摸ic

    ../../_images/image-20210822161414658.png

I2C简介

I.MX6U 提供了4 个I2C 外设,支持两种模式:标准模式和快速模式,标准模式下 I2C数据传输速率最高是 100Kbits/s,在快速模式下数据传输速率最高为 400Kbits/s。每个I2C控制器有5个16-bit 的寄存器。结构图如下所示:

../../_images/image-20210823084538161.png

I2C 寄存器

各个I2C单元的寄存器地址如下:

../../_images/image-20210823084714471.png

  • 地址寄存器 I2Cx_IADR

    I2Cx_IADR(x=1~4,下面也是如此,不在累赘)寄存器,这是I2C的地址寄存器,寄存器 I2Cx_IADR只有 ADR(bit7:1)位有效,用来保存 I2C从设备地址数据。当我们要访问某个 I2C从设备的时候就需要将其设备地址写入到 ADR里面。寄存器结构如图:

    ../../_images/image-20210823085145808.png

  • 分频寄存器I2Cx_IFDR

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

    ../../_images/image-20210823085404848.png

    I2C时钟树如下:

    ../../_images/image-20210823092852435.png

    根据bsp_clk.c里面的imx6u_clkinit函数得到PLL2_PFD2是396M,AHB_PODF是3,IPG_PODF是2,PERCLK_PODF是1,如下,参见代码【i2c_ap3216c】工程。

    ../../_images/image-20210823093557888.png

    ../../_images/image-20210823093803402.png

    所以,计算 PER_CLK_ROOT过程如下:
    PLL2 = 528 MHz
    PLL2_PFD2 = 528 * 18 / 24 = 396 MHz
    IPG_CLK_ROOT = (PLL2_PFD2 / AHB_PODF )/ IPG_PODF = (396 MHz/3)/2 = 66 MHz
    PER_CLK_ROOT = IPG_CLK_ROOT/PERCLK_PODF = 66  MHz/1 = 66 MHz
    我们要设置 I2C的波特率100KHz,那么 IC = 66000000/100000 =660,
    查询IC表可知,和660最接近的IC值为0x15
    

    ../../_images/image-20210823085451427.png

  • 控制寄存器I2Cx_I2CR

    ../../_images/image-20210823085641641.png

位域 读写 描述
[7] IEN R/W I2C使能,
0:I2C控制器被禁止,但是还可以访问它的寄存器;
1:I2C控制器使能,要想让本寄存器中其他位起效,此位必须先置1
[6] IIEN R/W I2C中断使能,
0:I2C中断禁止,但是中断状态位(I2C_I2SR[IIF])还是可以使用的;
1:I2C中断使能,发生中断时,中断状态位(I2C_I2SR[IIF])也会被设置
[5] MSTA R/W 主从模式选择,
0:从设备模式,MSTA从1变0时,会发出STOP信号,并变为从设备模式;
1:主机模式,MSTA从0变1时,会发即STAT信号,并变为主机模式。
注意1:I2C主设备失去总线时,硬件会清除此位,但是不会发出STOP信号
注意2:要修改此位时,要先提供I2C控制器时钟
注意3:软件清除此位时,会发出STOP信号;如果失去总线,硬件会清除此位
[4] MTX R/W 发送/接收模式,
0:接收模式,
1:发送模式。
作为主机时,应该根据数据传输的方向设置MTX位,当然,发送I2C设备地址时MTX总是1。
[3] TXAK R/W 发送响应使能,当I2C设备处于接收状态时,此位才有效,
0:在第9个时钟,发送响应信号,即把SDA拉低;
1:在第9个时钟,不发送响应信号
[2] RSTA R/W Repeat start,读该位时总得到0, 写:
0:不发送repeat start信号;
1:发送repeat start信号
  • 状态寄存器I2Cx_I2SR

    ../../_images/image-20210823090305125.png

    ../../_images/image-20210823090407321.png

  • 数据寄存器最后一个寄存器就是 I2Cx_I2DR

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

I2C代码分析

bsp_i2c.c 参见代码【i2c_ap3216c】工程。


#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的时钟源来源于 PERCLK_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;	
}

I2C丛机器件

ap3216c

简介

开发板上通过 I2C1连接了一个三合一环境传感器: AP3216C,AP3216C是由敦南 科技 推出的一款传感器,其支持环境光强度 (ALS)、接 近距离 (PS)和红外线强度 (IR)这三个环境参数检测。该芯片可以通过 IIC接口与主控制相连,并且支持中断。AP3216C常被用于手机、平板、导航设备等,其内置的接近传感器可以用于检测是否有物体接近,比如手机上用来检测耳朵是否接触听筒,如果检测到的话就表示正在打电话,手机就会关闭手机屏幕以省电。也可以使用环境光传感器检测光照强度,可以实现自动背光亮度调节。

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

../../_images/image-20210823095649110.png

寄存器介绍

../../_images/image-20210823095836727.png

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就不存在。

参见代码【i2c_ap3216c】工程。

/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_ap3216c.c
作者	   : 左忠凯
版本	   : V1.0
描述	   : AP3216C驱动文件。
其他	   : 无
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/3/26 左忠凯创建
***************************************************************/
#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); 	
}

main.c

	while(ap3216c_init())		/* 检测不到AP3216C */
	{
		printf("AP3216C Check Failed!\r\n");
		delay_ms(1000);
	}	

	while(1)			
	{	
	
		ap3216c_readdata(&ir, &ps, &als);		/* 读取数据		  	*/
		printf("ir=%d ps=%d als=%d \r\n",ir,ps,als);
		delay_ms(1000);
		LED_RGB_RED_TOG();
	
   }

mpu6050

参见代码【i2c_mpu6050】工程。

/***************************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2019. All rights reserved.
文件名	: 	 bsp_mpu.c
作者	   : 左忠凯
版本	   : V1.0
描述	   : MPU6050驱动文件。
其他	   : 无
论坛 	   : www.wtmembed.com
日志	   : 初版V1.0 2019/1/15 左忠凯创建
***************************************************************/
#include "bsp_mpu.h"
#include "bsp_i2c.h"
#include "bsp_delay.h"
#include "stdio.h"

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

	/* 1、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);

	/* 2、配置I2C IO属性	
	 *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 */
    mpu_write_byte(MPU6050_ADDR,MPU_PWR_MGMT1_REG,0X80);//复位MPU6050
    delay_ms(100);  //延时100ms
    mpu_write_byte(MPU6050_ADDR,MPU_PWR_MGMT1_REG,0X00);//唤醒MPU6050
    mpu_set_gyro_range(3);					        	//陀螺仪传感器,±2000dps
 	mpu_set_accel_range(0);					       	 	//加速度传感器,±2g
    mpu_set_rate(50);						       	 	//设置采样率50Hz
    mpu_write_byte(MPU6050_ADDR,MPU_INT_EN_REG,0X00);   //关闭所有中断
	mpu_write_byte(MPU6050_ADDR,MPU_USER_CTRL_REG,0X00);//I2C主模式关闭
	mpu_write_byte(MPU6050_ADDR,MPU_FIFO_EN_REG,0X00);	//关闭FIFO
	mpu_write_byte(MPU6050_ADDR,MPU_INTBP_CFG_REG,0X82);//INT引脚低电平有效,开启bypass模式,可以直接读取磁力计

	data = mpu_read_byte(MPU6050_ADDR,MPU_DEVICE_ID_REG);
	if(data == MPU6050_ID)
	{
		printf("MPU6050 ID=%#X\r\n", data);
		mpu_write_byte(MPU6050_ADDR, MPU_PWR_MGMT1_REG, 0X01);  /* 设置CLKSEL,PLL X轴为参考 */
        mpu_write_byte(MPU6050_ADDR, MPU_PWR_MGMT2_REG, 0X00);  /* 加速度与陀螺仪都工作 				*/
        mpu_set_rate(50);						       			/* 设置采样率为50Hz   */
	}
	else {
		return 1;
	
	}
	 
    // data = mpu_read_byte(AK8963_ADDR, MAG_WIA);    				/* 读取AK8963 ID    */  
	// if(data == AK8963_ID)
    // {
    //     printf("AK8963_ID=%#X\r\n", data);
    //     mpu_write_byte(AK8963_ADDR, MAG_CNTL1, 0X11);			/* 设置AK8963为单次测量模式 */
    // }else return 2;
	 

	return 0;
}

/*
 * @description	: 向MPU6050写入数据
 * @param - addr: 设备地址
 * @param - reg : 要写入的寄存器
 * @param - data: 要写入的数据
 * @return 		: 操作结果
 */
unsigned char mpu_write_byte(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	: 从MPU6050读取一个字节的数据
 * @param - addr: 设备地址
 * @param - reg : 要读取的寄存器
 * @return 		: 读取到的数据。
 */
unsigned char mpu_read_byte(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	: 从MPU6050读取多个字节的数据
 * @param - addr: 设备地址
 * @param - reg : 要读取的开始寄存器地址
 * @param - len : 要读取的数据长度.
 * @param - buf : 读取到的数据缓冲区
 * @return 		: 无
 */
void mpu_read_len(unsigned char addr,unsigned char reg,unsigned char len,unsigned char *buf)
{	
	struct i2c_transfer masterXfer;	
	
	masterXfer.slaveAddress = addr;				/* 设备地址 				*/
    masterXfer.direction = kI2C_Read;			/* 读取数据 				*/
    masterXfer.subaddress = reg;				/* 要读取的寄存器地址 			*/
    masterXfer.subaddressSize = 1;				/* 地址长度一个字节 			*/
    masterXfer.data = buf;						/* 接收数据缓冲区 				*/
    masterXfer.dataSize = len;					/* 读取数据长度1个字节			*/
	i2c_master_transfer(I2C1, &masterXfer);
} 

/*
 * @description		: 设置MPU6050陀螺仪量程
 * @param - range	: 量程范围,0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
 * @return 			: 操作结果 0,设置成功  其他,设置失败 
 */
unsigned char mpu_set_gyro_range(unsigned char range)
{
	return mpu_write_byte(MPU6050_ADDR, MPU_GYRO_CFG_REG, range << 3);//设置陀螺仪满量程范围  
}

/*
 * @description		: 设置MPU6050加速度量程
 * @param - range	: 量程范围,0,±2g;1,±4g;2,±8g;3,±16g
 * @return 			: 操作结果 0,设置成功  其他,设置失败 
 */
unsigned char mpu_set_accel_range(unsigned char range)
{
	return mpu_write_byte(MPU6050_ADDR, MPU_ACCEL_CFG_REG,range << 3);//设置加速度传感器满量程范围  
}

/*
 * @description		: 设置MPU6050的数字低通滤波器
 * @param - range	: 数字低通滤波频率(Hz)
 * @return 			: 操作结果 0,设置成功  其他,设置失败 
 */
unsigned char mpu_set_lpf(unsigned short fre)
{
	unsigned char data = 0;
	
	if(fre >= 188) data=1;
	else if(fre >= 98) data=2;
	else if(fre >= 42) data=3;
	else if(fre >= 20) data=4;
	else if(fre >= 10) data=5;
	else data = 6; 
	return mpu_write_byte(MPU6050_ADDR,MPU_CFG_REG,data);
}

/*
 * @description	: 设置MPU6050采样率(假定Fs=1KHz)
 * @param - rate: 4~1000(Hz)
 * @return 		: 操作结果 0,设置成功  其他,设置失败 
 */
unsigned char mpu_set_rate(unsigned short rate)
{
	unsigned char data;
	if(rate > 1000) rate = 1000;
	if(rate < 4) rate = 4;
	data = 1000 / rate - 1;
	data = mpu_write_byte(MPU6050_ADDR,MPU_SAMPLE_RATE_REG,data);	/* 设置数字低通滤波器 */
 	return mpu_set_lpf(rate / 2);	/* 自动设置LPF为采样率的一半 */
}

/*
 * @description	: 得到陀螺仪值(原始值)
 * @param - gx  : 陀螺仪X轴原始数据
 * @param - gy	: 陀螺仪Y轴原始数据
 * @param - gz 	:陀螺仪Z轴原始数据
 * @return 		:  0,设置成功  其他,设置失败 
 */
void mpu_get_gyroscope(short *gx,short *gy,short *gz)
{
    unsigned char buf[6]; 
	
	mpu_read_len(MPU6050_ADDR, MPU_GYRO_XOUTH_REG, 6, buf);
	*gx=((short)buf[0] << 8) | buf[1];  
	*gy=((short)buf[2] << 8) | buf[3];  
	*gz=((short)buf[4] << 8) | buf[5];
}

/*
 * @description	: 得到加速度原始值
 * @param - ax  : 加速度X轴原始数据
 * @param - ay	: 加速度Y轴原始数据
 * @param - az 	:加速度Z轴原始数据
 * @return 		:  0,设置成功  其他,设置失败 
 */
void mpu_get_accelerometer(short *ax,short *ay,short *az)
{
    unsigned char buf[6]; 
	
	mpu_read_len(MPU6050_ADDR, MPU_ACCEL_XOUTH_REG, 6, buf);
	*ax=((short)buf[0] << 8) | buf[1];  
	*ay=((short)buf[2] << 8) | buf[3];  
	*az=((short)buf[4] << 8) | buf[5];	
}

/*
 * @description	: 得到原始磁力计值
 * @param - mx  : 磁力计X轴原始数据
 * @param - my	: 磁力计Y轴原始数据
 * @param - mz 	:磁力计Z轴原始数据
 * @return 		:  0,设置成功  其他,设置失败 
 */
void mpu_get_magnetometer(short *mx, short *my, short *mz)
{
   	unsigned char buf[6];  
	
	mpu_read_len(AK8963_ADDR, MAG_XOUT_L , 6, buf);
	*mx = ((short)buf[1] << 8) | buf[0];  
	*my = ((short)buf[3] << 8) | buf[2];  
	*mz = ((short)buf[5] << 8) | buf[4];
	
    mpu_write_byte(AK8963_ADDR, MAG_CNTL1, 0X11); /* AK8963每次读完以后都需要重新设置为单次测量模式 */
}

main.c

    printf("i2c   demo  c=%d\r\n",c);


	while(ret =mpu_init())		/* 检测不到  */
	{
		printf("mpu6050 Check Failed =%d\r\n" ,ret);
		delay_ms(1000);
	}	
	
	printf("gyro.x		gyro.y		gyro.z		acc.x		acc.y		acc.z\r\n");
  
	while(1)			
	{	
	
		mpu_get_gyroscope(&gyro.x,&gyro.y,&gyro.z);		/* 读取数据		  	*/
		mpu_get_accelerometer(&acc.x,&acc.y,&acc.z);	/* 读取数据		  	*/
 
		printf( "%d		%d		%d		%d		%d		%d\r\n",gyro.x,gyro.y,gyro.z,acc.x,acc.y,acc.z);

		delay_ms(500);
		LED_RGB_RED_TOG();
	
   }

触摸IC

待写