Exynos_4412——IIC控制器和MPU6050

目录

一、Exynos_4412下的IIC控制器

二、IIC寄存器

三、MPU6050原理

MPU6050

MPU6050的主要参数

MPU6050通信接口

MPU6050官方芯片手册 

 MPU6050寄存器

四、MPU6050寄存器读写时序

向MPU6050写一个字节数据

向MPU6050读一个字节数据

五、IIC编程

六、小项目


Exynos_4412——IIC总线概述_宇努力学习的博客-CSDN博客

一、Exynos_4412下的IIC控制器

 4412有四个IIC,如果要使用需要配置四个寄存器;

I2CCON  配置一些功能

I2CSTAT   控制一些功能、显示一些状态

I2CDS     发送和接收数据

I2CADD   当4142作为从机时需要一个地址,这个寄存器用于设置地址

极少数IIC的地址是10位的,标准模式下最快速度是100K,快速模式下可以达到400k,支持主机发送主机接收,从机发送从机接收,支持中断和轮询

 

 

主机发送模式下4412的工作过程

 

主机接收模式下的4412工作流程

由于主控很少作为从机另外两个模式就不看了

二、IIC寄存器

 

【7】接收到一个字节数据后是否产生应答信号   1产生   0不产生

【6】分频,影响IIC的通信速度。

【5】中断的开关,IIC在接收和发送一个信号后都会产生一个中断信号通知你

【4】当中断产生这位自动置1,在处理完中断信号后要写成0

【3:0】影响IIC的通信速度,改变时钟频率

 

【7:6】模式选择

【5】起始和停止信号

【4】就是总线收发的开关

【3:0】只能读,表示IIC的状态

 

 

滤波器和延时用不上就不设置了 

三、MPU6050原理

MPU6050

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

MPU6050的主要参数

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

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

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

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

    可编程设置低功耗模式

    可编程设置采样频率

     ... ...

MPU6050通信接口

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

 

MPU6050官方芯片手册 

 

 

 

 MPU6050寄存器

 

 

我们主要是使用4412而不是MPU6050,会常用的几个寄存器就行:

 

/****************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地址

三轴加速度三轴角速度和温度的传感器值可通过这些寄存器读取

 

它的IIC地址有两个一个0x68一个0x69,他的地址由ADO决定

 

所以他的地址是0x68,为了避免冲突所以可以改地址。

四、MPU6050寄存器读写时序

MPU6050 在设计的时候只能作为从机

向MPU6050写一个字节数据

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

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

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

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

5.从机发送应答信号

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

7.从机发送应答信号
8.主机发送停止信号

向MPU6050读一个字节数据

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

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

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

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

5.从机发送应答信号

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

7.主机发送从机地址(MPU6050的地址)及读写方向(读)
8.从机(MPU6050)发送应答信号

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

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

11.主机发送停止信号

五、IIC编程

算一下延时

4412的工作频率是200M-1.4G 

 

 找了半天没找到,这个时钟频率是可以配置的,然后在手册中并没有关于4412的指令周期和时钟周期关系的描述。所以没法算这个浪费CPU资源的延时具体是几,老师给了一毫秒的延时函数,先拿来直接用吧,等以后知道这些数据了再来算一算。

开始写程序吧;


#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;
}


 

 

由于没有校准也没设置滤波所以正常情况下不是0正常应该是0的,然后逆时针是正数顺时针是负数 。

六、小项目

综合项目:
实时监测开发板的放置状态,当监测到开发板水平放置时,每隔一分钟向终端上打印一次当前的时间以及开发板的状态
如:“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++);
	}
}

/**********************************************************************
 * 函数功能: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
}

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

void RTC_Init()
{
	//使能RTC控制
    RTCCON = RTCCON | 1;
    //校准时间
    RTC.BCDYEAR = 0x023; //000000100011  2023
    RTC.BCDMON  = 0x1;   //1
    RTC.BCDDAY  = 0x8;   //8
    RTC.BCDWEEK = 0x7;   //星期
    RTC.BCDHOUR = 0x11;  //11
    RTC.BCDMIN  = 0x32;  //32
    RTC.BCDSEC  = 0x50;  //50s
 
    //关闭RTC控制
    RTCCON = RTCCON & 0;
 
}

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

void BEEP_Init()
{
    //GPD0_0设置PWM0输出功能
    GPD0.CON = GPD0.CON & (~(0xF)) | (0x2);
    //PWM0一级分频  100倍
    PWM.TCFG0 = PWM.TCFG0 & (~(0xFF)) | (99);
    //PWM0二级分频  1倍  PCLk/(99+1)/(0+1) = 1MHz
    PWM.TCFG1 = PWM.TCFG1 & (~(0xF));
    //设置PWM0自动重装 
    PWM.TCON = PWM.TCON | (1<<3);
    //设置周期 1000
    PWM.TCNTB0 = 1000;
    //占空比 60%
    PWM.TCMPB0 = 600;
    //手动装载
    PWM.TCON = PWM.TCON | (1 << 1);
    //关闭手动装载
    PWM.TCON = PWM.TCON & (~(1 << 1));
    //使能PWM0
    PWM.TCON = PWM.TCON | 1;
}

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

int main(void)
{
	//存储读取结果
	unsigned char zvalue_h,zvalue_l,xvalue_h,xvalue_l,yvalue_h,yvalue_l;						
	short int zvalue,xvalue,yvalue;

	/*设置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
	RTC_Init();													//RTC初始化
	BEEP_Init();												//BEEP初始化

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

		xvalue_h = iic_read(SlaveAddress, ACCEL_XOUT_H);		//获取MPU6050-Z轴加速度高字节
		xvalue_l = iic_read(SlaveAddress, ACCEL_XOUT_L);		//获取MPU6050-Z轴加速度低字节
		xvalue  =  (xvalue_h<<8)|xvalue_l;						//获取MPU6050-Z轴加速度

		yvalue_h = iic_read(SlaveAddress, ACCEL_YOUT_H);		//获取MPU6050-Z轴加速度高字节
		yvalue_l = iic_read(SlaveAddress, ACCEL_YOUT_L);		//获取MPU6050-Z轴加速度低字节
		yvalue  =  (yvalue_h<<8)|yvalue_l;						//获取MPU6050-Z轴加速度

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


先试试打印加速度

可以打印。

但是蜂鸣器一直响,关闭蜂鸣器,打印三个轴看看

 

桌面不平,所以数值上有差异我就用这个作为水平面的数据了。

加速度的量程要改一下改成16G才能读到正确值,但是我们不需要读取正确值,我们需要的是变化量 ,倾斜开发板的加速度是很小的,正常这种测试应该用角速度的,可能老师想锻炼一下我们用加速度,所以我们就用最小量程也就是最高精度的加速度来做倾斜检测,不对正常应该是结合使用的,角速度转完就没有了,加速度只要倾斜就是一直改变的。所以我们设置一个报警区间当Z小于一个值,X或Y大于一个值时发出警告:

我设置它Z小于19000X或Y大于1000时发出警告,对了还有反方向呢

设置的好像太苛刻了,不动的时候就开响

 

这次没问题了,但是开始会响一下就当提示音了。

 

完整的修改好的代码如下:


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

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

void RTC_Init()
{
	//使能RTC控制
    RTCCON = RTCCON | 1;
    //校准时间
    RTC.BCDYEAR = 0x023; //000000100011  2023
    RTC.BCDMON  = 0x1;   //1
    RTC.BCDDAY  = 0x8;   //8
    RTC.BCDWEEK = 0x7;   //星期
    RTC.BCDHOUR = 0x11;  //11
    RTC.BCDMIN  = 0x32;  //32
    RTC.BCDSEC  = 0x50;  //50s
 
    //关闭RTC控制
    RTCCON = RTCCON & 0;
 
}

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

void BEEP_Init()
{
    //GPD0_0设置PWM0输出功能
    GPD0.CON = GPD0.CON & (~(0xF)) | (0x2);
    //PWM0一级分频  100倍
    PWM.TCFG0 = PWM.TCFG0 & (~(0xFF)) | (99);
    //PWM0二级分频  1倍  PCLk/(99+1)/(0+1) = 1MHz
    PWM.TCFG1 = PWM.TCFG1 & (~(0xF));
    //设置PWM0自动重装 
    PWM.TCON = PWM.TCON | (1<<3);
    //设置周期 1000
    PWM.TCNTB0 = 1000;
    //占空比 60%
    PWM.TCMPB0 = 600;
    //手动装载
    PWM.TCON = PWM.TCON | (1 << 1);
    //关闭手动装载
    PWM.TCON = PWM.TCON & (~(1 << 1));
    //使能PWM0
    PWM.TCON = PWM.TCON | 1;
}

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

int main(void)
{
	//存储读取结果
	unsigned char zvalue_h,zvalue_l,xvalue_h,xvalue_l,yvalue_h,yvalue_l;						
	short int zvalue,xvalue,yvalue;

	/*设置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
	RTC_Init();													//RTC初始化
	BEEP_Init();												//BEEP初始化

	printf("\n********** I2C test!! ***********\n");
	PWM.TCON = PWM.TCON & (~(1));								//关闭BEEP
	while(1)
	{
		zvalue_h = iic_read(SlaveAddress, ACCEL_ZOUT_H);		//获取MPU6050-Z轴加速度高字节
		zvalue_l = iic_read(SlaveAddress, ACCEL_ZOUT_L);		//获取MPU6050-Z轴加速度低字节
		zvalue  =  (zvalue_h<<8)|zvalue_l;						//获取MPU6050-Z轴加速度

		xvalue_h = iic_read(SlaveAddress, ACCEL_XOUT_H);		//获取MPU6050-Z轴加速度高字节
		xvalue_l = iic_read(SlaveAddress, ACCEL_XOUT_L);		//获取MPU6050-Z轴加速度低字节
		xvalue  =  (xvalue_h<<8)|xvalue_l;						//获取MPU6050-Z轴加速度

		yvalue_h = iic_read(SlaveAddress, ACCEL_YOUT_H);		//获取MPU6050-Z轴加速度高字节
		yvalue_l = iic_read(SlaveAddress, ACCEL_YOUT_L);		//获取MPU6050-Z轴加速度低字节
		yvalue  =  (yvalue_h<<8)|yvalue_l;						//获取MPU6050-Z轴加速度

#if 1		
		if(zvalue < 19000 & ((xvalue > 1200) | (yvalue > 1200) | (xvalue < 500) | (yvalue < 100)))
		{
			printf("20%x-%x-%x %x %x:%x:%x  Status: Warning\n",RTC.BCDYEAR,RTC.BCDMON,RTC.BCDDAY,RTC.BCDWEEK,RTC.BCDHOUR,RTC.BCDMIN,RTC.BCDSEC);
	        PWM.TCON = PWM.TCON | 1;
			mydelay_ms(500);
			PWM.TCON = PWM.TCON & (~(1));
			mydelay_ms(490);
		}else{
			printf("20%x-%x-%x %x %x:%x:%x  Status: Normal\n",RTC.BCDYEAR,RTC.BCDMON,RTC.BCDDAY,RTC.BCDWEEK,RTC.BCDHOUR,RTC.BCDMIN,RTC.BCDSEC);
			PWM.TCON = PWM.TCON & (~(1));
			mydelay_ms(100);
		}
#endif
		//printf("X: %d  Y: %d  Z: %d\n", xvalue, yvalue ,zvalue);//打印MPU6050-x,y,Z轴加速度
		//mydelay_ms(100);
	}
	return 0;
}


  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

宇努力学习

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

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

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

打赏作者

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

抵扣说明:

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

余额充值