lv11 嵌入式开发 IIC(下) 20

目录

1 Exynos4412下IIC控制器介绍

1.1 总览

1.2 特征

1.3 工作框图

1.4 其他内容介绍

1.5 四种工作模式寄存器流程

2 IIC寄存器详解

2.1 概述

2.2 控制寄存器

2.3 状态寄存器

2.4 地址寄存器

2.5 数据寄存器

2.6 其他寄存器

3 MPU06050

3.1 简介

3.2 MPU6050主要参数

3.3 MPU6050通信接口

3.4 6050芯片手册

3.4.1 概览(8位寄存器)

3.4.2 实验需要用到的寄存器

4 MPU6050寄存器读写时序

4.1 向MPU6050的一个寄存器写一个字节的数据

4.2 从MPU6050的一个寄存器读一个字节的数据

1 Exynos4412下IIC控制器介绍

1.1 总览

Exynos 4412 SCP是一款支持四个多主I2C总线串行接口的精简指令集计算机(RISC)微处理器。为了在总线主和外围设备之间传输信息,使用了专用的串行数据线(SDA)和串行时钟(SCL)。SDA和SCL线都是双向的。

在多主I2C总线模式下,多个Exynos 4412 SCP RISC微处理器接收或发送串行数据到或从从设备。主Exynos 4412 SCP启动和终止I2C总线上的数据传输。 Exynos 4412 SCP的I2C总线使用标准的I2C总线仲裁过程实现多主和多从传输。

要控制多主I2C总线操作,必须向以下寄存器写入值:

• 多主I2C总线控制寄存器-I2CCON

• 多主I2C总线控制/状态寄存器-I2CSTAT

• 多主I2C总线Tx / Rx数据移位寄存器-I2CDS

• 多主I2C总线地址寄存器-I2CADD

如果I2C总线处于空闲状态,则SDA和SCL线都应处于高电平。 SDA的高至低转换会引发起始条件。 SDA的低至高转换会引发停止条件,而SCL保持稳定在高电平。

主设备始终生成起始和停止条件。在启动条件被初始化后,数据字节中的前7位地址值通过SDA线传输。该地址值确定了总线主设备选择的从设备。第8位确定传输的方向(读或写)。

放置在SDA线上的每个数据字节应为8位。在总线传输操作期间,发送或接收字节的数量没有限制。 I2C主设备和从设备始终从最高有效位(MSB)开始发送数据,然后立即跟随每个ACK位。

1.2 特征

I2C总线接口的特点包括:

• 9个通道的多主、从I2C总线接口(其中8个通道用于通用目的,1个通道专用于高清晰度多媒体接口(HDMI))。

• 7位寻址模式 • 串行、8位导向和双向数据传输

• 在标准模式下支持最高100 kbit/s的速率

• 在快速模式下支持最高400 kbit/s的速率

• 支持主设备发送、主设备接收、从设备发送和从设备接收操作

• 支持中断或轮询事件

当IIC发送完或者接收到一个字节数据,会以中断方式告知。

1.3 工作框图

1.4 其他内容介绍

四种工作模式及操作细节

 起始结束信号

 一个字节数据传输

应答信号

 读写

多主机仲裁机制

仲裁发生在SDA线上,以防止两个主设备之间的总线冲突。如果一个具有SDA高电平的主设备检测到另一个具有SDA低电平的主设备,则不会启动数据传输。这是因为总线上的电平不符合发起数据传输的条件。仲裁过程将一直进行,直到SDA线变为高电平。 当两个或多个主设备同时将SDA线置为低电平时,每个主设备都会评估自己是否具有主设备的资格。为了进行评估,每个主设备都会检测地址位。当每个主设备生成从设备地址时,它会检测SDA线上的地址位。这是因为SDA线变为低电平而不是高电平。 假设一个主设备生成低电平作为第一个地址位,而另一个主设备维持高电平。在这种情况下,两个主设备都会检测到总线上的低电平。这是因为低电平在电源中优于高电平。当发生这种情况时,生成低电平作为第一个地址位的主设备获得主设备的资格,而生成高电平作为第一个地址位的主设备则放弃主设备的资格。 当两个主设备都将第一个地址位生成为低电平时,再次进行第二个地址位的仲裁。这个仲裁过程会一直持续到最后一个地址位。 

1.5 四种工作模式寄存器流程

2 IIC寄存器详解

2.1 概述

2.2 控制寄存器

[7]位:应答信号,设置为接收模式时有用,收到字节会应答,发送模式时没有意义
[6]位:时钟源选择
[5]位:收到数据、发送数据后可以产生中断信号
[4]位:显示中断状态,建立在第5位的基础上,写0清除置位
[3:0]位:发送时钟的值

2.3 状态寄存器

[7:6]位:模式选择
[5]位:对于主机来说 1产生起始信号、0产生停止信号
           对于从机来说 置1 繁忙,0 空闲
[4]位:收发开关
[3:0]位:状态

2.4 地址寄存器

作为从机才有用

2.5 数据寄存器

2.6 其他寄存器

不常用

此滤波器可防止两个PCLK时钟之间的毛刺引起的错误。

3 MPU06050

3.1 简介

MPU6050是一个运动处理传感器,其内部集成了3轴加速度传感器     和3轴陀螺仪(角速度传感器),以及一个可扩展数字运动处理器

3.2 MPU6050主要参数

可测量X、Y、Z轴三个方向的角速度    

可编程设置角速度测量范围为±250、±500、±1000、±2000°/sec    

可测量X、Y、Z轴三个方向的加速度    

可编程设置加速度测量范围为±2g、±4g、±8g、±16g    

可编程设置低功耗模式    

可编程设置采样频率

3.3 MPU6050通信接口

MPU6050可以使用IIC总线和其他器件进行数据交互,我们可以使用IIC总线向MPU6050中的控制寄存器写入数据来设置MPU6050的工作参数 也可以使用IIC总线从MPU6050中的数据寄存器读取数据来获取加速度、角速度等信息

3.4 6050芯片手册

datasheet重点关注这个时序

寄存器

3.4.1 概览(8位寄存器)

3.4.2 实验需要用到的寄存器


/****************MPU6050内部常用寄存器地址****************/

#define	SMPLRT_DIV		0x19	//陀螺仪采样率,典型值:0x07(125Hz)
#define	CONFIG			0x1A	//低通滤波频率,典型值:0x06(5Hz)
#define	GYRO_CONFIG		0x1B	//陀螺仪自检及测量范围,典型值:0x18(不自检,2000°/s)
#define	ACCEL_CONFIG	0x1C	//加速计自检及测量范围及高通滤波频率,典型值:0x0(不自检,2G,5Hz)
#define	ACCEL_XOUT_H	0x3B
#define	ACCEL_XOUT_L	0x3C
#define	ACCEL_YOUT_H	0x3D
#define	ACCEL_YOUT_L	0x3E
#define	ACCEL_ZOUT_H	0x3F
#define	ACCEL_ZOUT_L	0x40
#define	TEMP_OUT_H		0x41
#define	TEMP_OUT_L		0x42
#define	GYRO_XOUT_H		0x43
#define	GYRO_XOUT_L		0x44
#define	GYRO_YOUT_H		0x45
#define	GYRO_YOUT_L		0x46
#define	GYRO_ZOUT_H		0x47
#define	GYRO_ZOUT_L		0x48
#define	PWR_MGMT_1		0x6B	//电源管理,典型值:0x00(正常启用)
#define	SlaveAddress	0x68	//MPU6050-I2C地址

上面设定了典型值,详细介绍参考手册

加速度和角速度都有正负,数据存放在2个寄存器,需要分别读取合并成16位。

 

加速度正负参考

从机地址(注意要地址需要根据ADO引脚确定,我们开发板即0x68,怕地址冲突)

4 MPU6050寄存器读写时序

4.1 向MPU6050的一个寄存器写一个字节的数据

1.主机(Exynos4412)发送起始信号

2.主机发送从机地址(MPU6050的地址)及读写方向(写)

3.从机(MPU6050)发送应答信号

4.主机发送一个字节数据(要写的寄存器的地址)

5.从机发送应答信号

6.主机发送一个字节数据(要写到寄存器的数据)

7.从机发送应答信号

8.主机发送停止信号

4.2 从MPU6050的一个寄存器读一个字节的数据

1.主机(Exynos4412)发送起始信号

2.主机发送从机地址(MPU6050的地址)及读写方向(写)

3.从机(MPU6050)发送应答信号

4.主机发送一个字节数据(要写的寄存器的地址)

5.从机发送应答信号

6.主机(Exynos4412)发送起始信号

7.主机发送从机地址(MPU6050的地址)及读写方向(读)

8.从机(MPU6050)发送应答信号

9.从机发送一个字节数据(要读的寄存器中的数据)

10.主机发送非应答信号(不再接收更多的数据)

11.主机发送停止信号

5 练习

简述通过主机从MPU6050中的一个寄存器中读一个字节的数据的过程

6 MPU6050基础代码


#include "exynos_4412.h"

/****************MPU6050内部寄存器地址****************/

#define	SMPLRT_DIV		0x19	//陀螺仪采样率,典型值:0x07(125Hz)
#define	CONFIG			0x1A	//低通滤波频率,典型值:0x06(5Hz)
#define	GYRO_CONFIG		0x1B	//陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define	ACCEL_CONFIG	0x1C	//加速计自检、测量范围及高通滤波频率,典型值:0x18(不自检,2G,5Hz)
#define	ACCEL_XOUT_H	0x3B
#define	ACCEL_XOUT_L	0x3C
#define	ACCEL_YOUT_H	0x3D
#define	ACCEL_YOUT_L	0x3E
#define	ACCEL_ZOUT_H	0x3F
#define	ACCEL_ZOUT_L	0x40
#define	TEMP_OUT_H		0x41
#define	TEMP_OUT_L		0x42
#define	GYRO_XOUT_H		0x43
#define	GYRO_XOUT_L		0x44
#define	GYRO_YOUT_H		0x45
#define	GYRO_YOUT_L		0x46
#define	GYRO_ZOUT_H		0x47
#define	GYRO_ZOUT_L		0x48
#define	PWR_MGMT_1		0x6B	//电源管理,典型值:0x00(正常启用)
#define	WHO_AM_I		0x75	//IIC地址寄存器(默认数值0x68,只读)
#define	SlaveAddress	0x68	//MPU6050-I2C地址

/************************延时函数************************/

void mydelay_ms(int time)
{
	int i,j;
	while(time--)
	{
		for(i=0;i<5;i++)
			for(j=0;j<514;j++);
	}
}

/**********************************************************************
 * 函数功能:I2C向特定地址写一个字节
 * 输入参数:
 * 		slave_addr: I2C从机地址
 * 			  addr: 芯片内部特定地址
 * 			  data:写入的数据
**********************************************************************/

void iic_write (unsigned char slave_addr, unsigned char addr, unsigned char data)
{
	/*对时钟源进行512倍预分频  打开IIC中断(每次完成一个字节的收发后中断标志位会自动置位)*/
	I2C5.I2CCON = I2C5.I2CCON | (1<<6) | (1<<5);

	/*设置IIC模式为主机发送模式  使能IIC发送和接收*/
	I2C5.I2CSTAT = 0xd0;
	/*将第一个字节的数据写入发送寄存器  即从机地址和读写位(MPU6050-I2C地址+写位0)*/
	I2C5.I2CDS = slave_addr<<1;
	/*设置IIC模式为主机发送模式  发送起始信号启用总线  使能IIC发送和接收*/
	I2C5.I2CSTAT = 0xf0;

	/*等待从机接受完一个字节后产生应答信号(应答后中断挂起位自动置位)*/
	while(!(I2C5.I2CCON & (1<<4)));

	/*将要发送的第二个字节数据(即MPU6050内部寄存器的地址)写入发送寄存器*/
	I2C5.I2CDS = addr;
	/*清除中断挂起标志位  开始下一个字节的发送*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));
	/*等待从机接受完一个字节后产生应答信号(应答后中断挂起位自动置位)*/
	while(!(I2C5.I2CCON & (1<<4)));

	/*将要发送的第三个字节数据(即要写入到MPU6050内部指定的寄存器中的数据)写入发送寄存器*/
	I2C5.I2CDS = data;
	/*清除中断挂起标志位  开始下一个字节的发送*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));
	/*等待从机接受完一个字节后产生应答信号(应答后中断挂起位自动置位)*/
	while(!(I2C5.I2CCON & (1<<4)));

	/*发送停止信号  结束本次通信*/
	I2C5.I2CSTAT = 0xD0;
	/*清除中断挂起标志位*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));
	/*延时*/
	mydelay_ms(10);
}

/**********************************************************************
 * 函数功能:I2C从特定地址读取1个字节的数据
 * 输入参数:         slave_addr: I2C从机地址
 * 			       addr: 芯片内部特定地址
 * 返回参数: unsigned char: 读取的数值
**********************************************************************/

unsigned char iic_read(unsigned char slave_addr, unsigned char addr)
{

	unsigned char data = 0;

	/*对时钟源进行512倍预分频  打开IIC中断(每次完成一个字节的收发后中断标志位会自动置位)*/
	I2C5.I2CCON = I2C5.I2CCON | (1<<6) | (1<<5);

	/*设置IIC模式为主机发送模式  使能IIC发送和接收*/
	I2C5.I2CSTAT = 0xd0;
	/*将第一个字节的数据写入发送寄存器  即从机地址和读写位(MPU6050-I2C地址+写位0)*/
	I2C5.I2CDS = slave_addr<<1;
	/*设置IIC模式为主机发送模式  发送起始信号启用总线  使能IIC发送和接收*/
	I2C5.I2CSTAT = 0xf0;
	/*等待从机接受完一个字节后产生应答信号(应答后中断挂起位自动置位)*/
	while(!(I2C5.I2CCON & (1<<4)));

	/*将要发送的第二个字节数据(即要读取的MPU6050内部寄存器的地址)写入发送寄存器*/
	I2C5.I2CDS = addr;
	/*清除中断挂起标志位  开始下一个字节的发送*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));
	/*等待从机接受完一个字节后产生应答信号(应答后中断挂起位自动置位)*/
	while(!(I2C5.I2CCON & (1<<4)));

	/*清除中断挂起标志位  重新开始一次通信  改变数据传送方向*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));

	/*将第一个字节的数据写入发送寄存器  即从机地址和读写位(MPU6050-I2C地址+读位1)*/
	I2C5.I2CDS = slave_addr << 1 | 0x01;
	/*设置IIC为主机接收模式  发送起始信号  使能IIC收发*/
	I2C5.I2CSTAT = 0xb0;
	/*等待从机接收到数据后应答*/
	while(!(I2C5.I2CCON & (1<<4)));


	/*禁止主机应答信号(即开启非应答  因为只接收一个字节)  清除中断标志位*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<7))&(~(1<<4));
	/*等待接收从机发来的数据*/
	while(!(I2C5.I2CCON & (1<<4)));
	/*将从机发来的数据读取*/
	data = I2C5.I2CDS;

	/*直接发起停止信号结束本次通信*/
	I2C5.I2CSTAT = 0x90;
	/*清除中断挂起标志位*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));
	/*延时等待停止信号稳定*/
	mydelay_ms(10);

	return data;

}


/**********************************************************************
 * 函数功能:MPU6050初始化
**********************************************************************/

void MPU6050_Init ()
{
	iic_write(SlaveAddress, PWR_MGMT_1, 0x00); 		//设置使用内部时钟8M
	iic_write(SlaveAddress, SMPLRT_DIV, 0x07);		//设置陀螺仪采样率
	iic_write(SlaveAddress, CONFIG, 0x06);			//设置数字低通滤波器
	iic_write(SlaveAddress, GYRO_CONFIG, 0x18);		//设置陀螺仪量程+-2000度/s
	iic_write(SlaveAddress, ACCEL_CONFIG, 0x0);		//设置加速度量程+-2g
}



/**********************************************************************
 * 函数功能:主函数
 **********************************************************************/

int main(void)
{

	unsigned char zvalue_h,zvalue_l;						//存储读取结果
	short int zvalue;

	/*设置GPB_2引脚和GPB_3引脚功能为I2C传输引脚*/
	GPB.CON = (GPB.CON & ~(0xF<<12)) | 0x3<<12;			 	//设置GPB_3引脚功能为I2C_5_SCL
	GPB.CON = (GPB.CON & ~(0xF<<8))  | 0x3<<8;				//设置GPB_2引脚功能为I2C_5_SDA

	uart_init(); 											//初始化串口
	MPU6050_Init();											//初始化MPU6050

	printf("\n********** I2C test!! ***********\n");
	while(1)
	{
		zvalue_h = iic_read(SlaveAddress, GYRO_ZOUT_H);		//获取MPU6050-Z轴角速度高字节
		zvalue_l = iic_read(SlaveAddress, GYRO_ZOUT_L);		//获取MPU6050-Z轴角速度低字节
		zvalue  =  (zvalue_h<<8)|zvalue_l;					//获取MPU6050-Z轴角速度

		printf(" GYRO--Z  :Hex: %d	\n", zvalue);			//打印MPU6050-Z轴角速度
		mydelay_ms(100);
	}
	return 0;
}


7 练习

综合项目:
实时监测开发板的放置状态,当监测到开发板水平放置时,每隔一分钟向终端上打印一次当前的时间以及开发板的状态
如:“2023-04-05 23:45:00 Status: Normal”
当监测到开发板发生倾斜时,每隔一秒钟向终端上打印一次当前的时间以及开发板的状态
如:“2023-04-05 23:45:00 Status: Warning”
同时让蜂鸣器产生“滴滴”的警报声,在警报状态下,若按下Key2按键,解除蜂鸣器的警报声
提示:
开发板水平静止放置时MPU6050的Z轴上的加速度应该等于重力加速度的值(9.8m/s2),而其X轴和Y轴上的加速度应该等于0
当开发板发生倾斜时MPU6050的Z轴上的加速度的分量会减小,而其X轴和Y轴上的加速度分量会增大
我们可以以此来判断开发板是否发生倾斜


#include "exynos_4412.h"

/****************MPU6050内部寄存器地址****************/

#define	SMPLRT_DIV		0x19	//陀螺仪采样率,典型值:0x07(125Hz)
#define	CONFIG			0x1A	//低通滤波频率,典型值:0x06(5Hz)
#define	GYRO_CONFIG		0x1B	//陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define	ACCEL_CONFIG	0x1C	//加速计自检、测量范围及高通滤波频率,典型值:0x18(不自检,2G,5Hz)
#define	ACCEL_XOUT_H	0x3B
#define	ACCEL_XOUT_L	0x3C
#define	ACCEL_YOUT_H	0x3D
#define	ACCEL_YOUT_L	0x3E
#define	ACCEL_ZOUT_H	0x3F
#define	ACCEL_ZOUT_L	0x40
#define	TEMP_OUT_H		0x41
#define	TEMP_OUT_L		0x42
#define	GYRO_XOUT_H		0x43
#define	GYRO_XOUT_L		0x44
#define	GYRO_YOUT_H		0x45
#define	GYRO_YOUT_L		0x46
#define	GYRO_ZOUT_H		0x47
#define	GYRO_ZOUT_L		0x48
#define	PWR_MGMT_1		0x6B	//电源管理,典型值:0x00(正常启用)
#define	WHO_AM_I		0x75	//IIC地址寄存器(默认数值0x68,只读)
#define	SlaveAddress	0x68	//MPU6050-I2C地址

/************************延时函数************************/

void mydelay_ms(int time)
{
	int i,j;
	while(time--)
	{
		for(i=0;i<5;i++)
			for(j=0;j<514;j++);
	}
}

void Rtc_init(void)
{
	/*使能RTC控制*/

	RTCCON = RTCCON | 1;

	/*校准时间信息*/

	RTC.BCDYEAR = 0x023;

	RTC.BCDMON  = 0x12;

	RTC.BCDDAY  = 0x7;

	RTC.BCDWEEK = 0x31;

	RTC.BCDHOUR = 0x23;

	RTC.BCDMIN  = 0x59;

	RTC.BCDSEC  = 0x50;

	/*禁止RTC控制*/

	RTCCON = RTCCON &  (~(1));
}

void Buz_init(void)
{
	/*1.将GPD0_0引脚设置成PWM0的输出引脚*/

	GPD0.CON = GPD0.CON & (~(0xF)) | (0x2);

	/*2.设置PWM0的一级分频	一级分频倍数设置为100倍*/

	PWM.TCFG0 = PWM.TCFG0 & (~(0xFF)) | 99;

	/*2.设置PWM0的二级分频	二级分频倍数设置为1倍  递减计数器递减频率 = PLCK / (99 + 1) / 1 = 1M*/

	PWM.TCFG1 = PWM.TCFG1 & (~(0xF));

	/*4.设置PWM0为自动重装载,使其能够产生连续的脉冲信号*/

	PWM.TCON = PWM.TCON | (1 << 3);

	/*5.设置PWM0的频率为1000HZ*/

	PWM.TCNTB0 = 1000;

	/*6.设置PWM0的占空比为60%*/

	PWM.TCMPB0 = 600;

	/*7.将TCNTB0中的值手动装载到递减计数器*/

	PWM.TCON = PWM.TCON | (1 << 1);

	/*8.关闭手动更新*/

	PWM.TCON = PWM.TCON & (~(1 << 1));

	/*9.使能PWM0,递减计数器开始递减*/

	PWM.TCON = PWM.TCON | 1;
}

void Led_on(int num)

{

	switch(num)

	{

		case 2:

			GPX2.DAT = GPX2.DAT | (1 << 7);

		case 3:

			GPX1.DAT = GPX1.DAT | (1 << 0);

		case 4:

			GPF3.DAT = GPF3.DAT | (1 << 4);

		case 5:

			GPF3.DAT = GPF3.DAT | (1 << 5);

		default:

			break;

	}

}



void Led_off(int num)

{

	switch(num)

	{

		case 2:

			GPX2.DAT = GPX2.DAT & ~(1 << 7);

		case 3:

			GPX1.DAT = GPX1.DAT & ~(1 << 0);

		case 4:

			GPF3.DAT = GPF3.DAT & ~(1 << 4);

		case 5:

			GPF3.DAT = GPF3.DAT & ~(1 << 5);

		default:

			break;

	}

}



void Led_init(void)

{

	GPX2.CON = GPX2.CON & (~(0xF << 28)) | (0x1 << 28); //LED2 GPX2_7 output

	//GPX1.CON = GPX1.CON & (~0xF) | 0x1;                 //LED3 GPX1_0 output

	//GPF3.CON = GPF3.CON & (~(0xF << 16)) | (0x1 << 16); //LED4 GPF3_4 output

	//GPF3.CON = GPF3.CON & (~(0xF << 20)) | (0x1 << 20); //LED5 GPF3_5 output



	Led_off(2);

}



void Key_init(void)

{

	//GPIO X1_1 input

	GPX1.CON = GPX1.CON & (~(0xf << 4));

}

/**********************************************************************
 * 函数功能:I2C向特定地址写一个字节
 * 输入参数:
 * 		slave_addr: I2C从机地址
 * 			  addr: 芯片内部特定地址
 * 			  data:写入的数据
**********************************************************************/

void iic_write (unsigned char slave_addr, unsigned char addr, unsigned char data)
{
	/*对时钟源进行512倍预分频  打开IIC中断(每次完成一个字节的收发后中断标志位会自动置位)*/
	I2C5.I2CCON = I2C5.I2CCON | (1<<6) | (1<<5);

	/*设置IIC模式为主机发送模式  使能IIC发送和接收*/
	I2C5.I2CSTAT = 0xd0;
	/*将第一个字节的数据写入发送寄存器  即从机地址和读写位(MPU6050-I2C地址+写位0)*/
	I2C5.I2CDS = slave_addr<<1;
	/*设置IIC模式为主机发送模式  发送起始信号启用总线  使能IIC发送和接收*/
	I2C5.I2CSTAT = 0xf0;

	/*等待从机接受完一个字节后产生应答信号(应答后中断挂起位自动置位)*/
	while(!(I2C5.I2CCON & (1<<4)));

	/*将要发送的第二个字节数据(即MPU6050内部寄存器的地址)写入发送寄存器*/
	I2C5.I2CDS = addr;
	/*清除中断挂起标志位  开始下一个字节的发送*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));
	/*等待从机接受完一个字节后产生应答信号(应答后中断挂起位自动置位)*/
	while(!(I2C5.I2CCON & (1<<4)));

	/*将要发送的第三个字节数据(即要写入到MPU6050内部指定的寄存器中的数据)写入发送寄存器*/
	I2C5.I2CDS = data;
	/*清除中断挂起标志位  开始下一个字节的发送*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));
	/*等待从机接受完一个字节后产生应答信号(应答后中断挂起位自动置位)*/
	while(!(I2C5.I2CCON & (1<<4)));

	/*发送停止信号  结束本次通信*/
	I2C5.I2CSTAT = 0xD0;
	/*清除中断挂起标志位*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));
	/*延时*/
	mydelay_ms(10);
}

/**********************************************************************
 * 函数功能:I2C从特定地址读取1个字节的数据
 * 输入参数:         slave_addr: I2C从机地址
 * 			       addr: 芯片内部特定地址
 * 返回参数: unsigned char: 读取的数值
**********************************************************************/

unsigned char iic_read(unsigned char slave_addr, unsigned char addr)
{

	unsigned char data = 0;

	/*对时钟源进行512倍预分频  打开IIC中断(每次完成一个字节的收发后中断标志位会自动置位)*/
	I2C5.I2CCON = I2C5.I2CCON | (1<<6) | (1<<5);

	/*设置IIC模式为主机发送模式  使能IIC发送和接收*/
	I2C5.I2CSTAT = 0xd0;
	/*将第一个字节的数据写入发送寄存器  即从机地址和读写位(MPU6050-I2C地址+写位0)*/
	I2C5.I2CDS = slave_addr<<1;
	/*设置IIC模式为主机发送模式  发送起始信号启用总线  使能IIC发送和接收*/
	I2C5.I2CSTAT = 0xf0;
	/*等待从机接受完一个字节后产生应答信号(应答后中断挂起位自动置位)*/
	while(!(I2C5.I2CCON & (1<<4)));

	/*将要发送的第二个字节数据(即要读取的MPU6050内部寄存器的地址)写入发送寄存器*/
	I2C5.I2CDS = addr;
	/*清除中断挂起标志位  开始下一个字节的发送*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));
	/*等待从机接受完一个字节后产生应答信号(应答后中断挂起位自动置位)*/
	while(!(I2C5.I2CCON & (1<<4)));

	/*清除中断挂起标志位  重新开始一次通信  改变数据传送方向*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));

	/*将第一个字节的数据写入发送寄存器  即从机地址和读写位(MPU6050-I2C地址+读位1)*/
	I2C5.I2CDS = slave_addr << 1 | 0x01;
	/*设置IIC为主机接收模式  发送起始信号  使能IIC收发*/
	I2C5.I2CSTAT = 0xb0;
	/*等待从机接收到数据后应答*/
	while(!(I2C5.I2CCON & (1<<4)));


	/*禁止主机应答信号(即开启非应答  因为只接收一个字节)  清除中断标志位*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<7))&(~(1<<4));
	/*等待接收从机发来的数据*/
	while(!(I2C5.I2CCON & (1<<4)));
	/*将从机发来的数据读取*/
	data = I2C5.I2CDS;

	/*直接发起停止信号结束本次通信*/
	I2C5.I2CSTAT = 0x90;
	/*清除中断挂起标志位*/
	I2C5.I2CCON = I2C5.I2CCON & (~(1<<4));
	/*延时等待停止信号稳定*/
	mydelay_ms(10);

	return data;

}


/**********************************************************************
 * 函数功能:MPU6050初始化
**********************************************************************/

void MPU6050_Init ()
{
	iic_write(SlaveAddress, PWR_MGMT_1, 0x00); 		//设置使用内部时钟8M
	iic_write(SlaveAddress, SMPLRT_DIV, 0x07);		//设置陀螺仪采样率
	iic_write(SlaveAddress, CONFIG, 0x06);			//设置数字低通滤波器
	iic_write(SlaveAddress, GYRO_CONFIG, 0x18);		//设置陀螺仪量程+-2000度/s
	iic_write(SlaveAddress, ACCEL_CONFIG, 0x0);		//设置加速度量程+-2g
}



/**********************************************************************
 * 函数功能:主函数
 **********************************************************************/

int main(void)
{

	unsigned char zvalue_h,zvalue_l,xvalue_h,xvalue_l,yvalue_h,yvalue_l;						//存储读取结果
	short int zvalue,xvalue,yvalue;
	int alarm = 0; 
	
	Rtc_init();
	Led_init();
	Key_init();
	Buz_init();

	/*设置GPB_2引脚和GPB_3引脚功能为I2C传输引脚*/
	GPB.CON = (GPB.CON & ~(0xF<<12)) | 0x3<<12;			 	//设置GPB_3引脚功能为I2C_5_SCL
	GPB.CON = (GPB.CON & ~(0xF<<8))  | 0x3<<8;				//设置GPB_2引脚功能为I2C_5_SDA

	uart_init(); 											//初始化串口
	MPU6050_Init();											//初始化MPU6050

	printf("\n********** I2C test!! ***********\n");
	while(1)
	{
		zvalue_h = iic_read(SlaveAddress, ACCEL_ZOUT_H);		//获取MPU6050-Z轴角速度高字节
		zvalue_l = iic_read(SlaveAddress, ACCEL_ZOUT_H);		//获取MPU6050-Z轴角速度低字节
		zvalue  =  (zvalue_h<<8)|zvalue_l;					//获取MPU6050-Z轴角速度
		xvalue_h = iic_read(SlaveAddress, ACCEL_XOUT_H);		//获取MPU6050-x轴角速度高字节
		xvalue_l = iic_read(SlaveAddress, ACCEL_XOUT_H);		//获取MPU6050-x轴角速度低字节
		xvalue  =  (xvalue_h<<8)|xvalue_l;					//获取MPU6050-x轴角速度
		yvalue_h = iic_read(SlaveAddress, ACCEL_YOUT_H);		//获取MPU6050-y轴角速度高字节
		yvalue_l = iic_read(SlaveAddress, ACCEL_YOUT_H);		//获取MPU6050-y轴角速度低字节
		yvalue  =  (yvalue_h<<8)|yvalue_l;					//获取MPU6050-y轴角速度

		if(!(GPX1.DAT & ( 1 << 1)))

		{

			//等待松手

			while(!(GPX1.DAT & (1 << 1)));

			printf("key press\n");

			alarm = 0;

		

		}


		if( xvalue>10 || xvalue < -10 || yvalue >10 || yvalue<-10 ||zvalue < 13480)

		{

			Led_on(2);

			alarm = 1;

		}
	
		if(alarm == 1)
		{
			printf("20%x-%x-%x %x %x:%x:%x,Status:Warning\n",RTC.BCDYEAR, RTC.BCDMON, RTC.BCDWEEK, RTC.BCDDAY, RTC.BCDHOUR, RTC.BCDMIN, RTC.BCDSEC);
			PWM.TCON = PWM.TCON | 1;

			mydelay_ms(500);

			PWM.TCON = PWM.TCON & (~(1));

			mydelay_ms(500);
		}
		else
		{		
			Led_off(2);
			PWM.TCON = PWM.TCON & (~(1));

			printf("20%x-%x-%x %x %x:%x:%x,Status:Normal\n",RTC.BCDYEAR, RTC.BCDMON, RTC.BCDWEEK, RTC.BCDDAY, RTC.BCDHOUR, RTC.BCDMIN, RTC.BCDSEC);	
			mydelay_ms(1000);
		}
		printf(" x:%d,y:%d,z:%d	\n", xvalue,yvalue,zvalue);			//打印MPU6050-Z轴角速度
		
		//mydelay_ms(100);
	}
	return 0;
}


  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

4IOT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值