Exynos_4412——IIC控制器和MPU6050

news2024/11/18 14:26:43

目录

一、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;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/148231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux内核中断子系统

查看中断控制相关的设备树节点 *********************gpiof控制器*************************pinctrl: pin-controller50002000 {#address-cells <1>;#size-cells <1>;compatible "st,stm32mp157-pinctrl";interrupt-parent <&exti>;gpiof…

数据结构与算法三【树】

二叉树性质 满二叉树 深度为k&#xff0c;有2k−12^{k}-12k−1个结点的二叉树&#xff0c;为满二叉树。 完全二叉树 完全二叉树的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面…

【jQuery】常用API——jQuery选择器

一、 jQuery基础选择器原生JS获取元素方式很多&#xff0c;很杂&#xff0c;而且兼容性情况不一致&#xff0c;因此jQuery给我们做了封装&#xff0c;使荻取元素统一标准。$(“选择器”); //里面选择器直接写CSS选择器即可&#xff0c;但是要加号<script src"../jquery…

Ubuntu18.04系统 部署python3.9.0 源码编译安装及pip配置全过程记录

1.Ubuntu系统镜像下载和基本配置 1.1 镜像下载 镜像下载&#xff1a;https://cn.ubuntu.com/download/desktop 1.2 配置静态IP 配置固定IP方式&#xff1a; Ubuntu18之前在/etc/network/interfaces进行配置&#xff0c;Ubuntu18及之后版本在/etc/netplan/*.yaml进行配置&am…

Node.JS(1)

目录 命令行窗口&#xff08;cmd窗口、小黑屏、终端、shell&#xff09; 环境变量 命令行窗口&#xff08;cmd窗口、小黑屏、终端、shell&#xff09; winR快捷键-->cmd 常用指令 dir 列出当前目录下的所有文件 cd 目录名 进入到指定的目录 md 目录名 创建一个文件…

redis安装和使用说明

Redis安装说明大多数企业都是基于Linux服务器来部署项目&#xff0c;而且Redis官方也没有提供Windows版本的安装包。因此课程中我们会基于Linux系统来安装Redis.此处选择的Linux版本为CentOS 7.Redis的官方网站地址&#xff1a;https://redis.io/1.单机安装Redis1.1.安装Redis依…

数字验证学习笔记——SystemVerilog芯片验证23 ——数据采样

一、数据采样 当你coverpoint指定采样一个变量或表达式时&#xff0c;SV会创建很多“仓&#xff08;bin&#xff09;”来记录每个数值被捕捉到的次数。这些bin是衡量功能覆盖率的基本单位。covergroup中可以定义多个coverpoint&#xff0c;coverpoint中可以自定义多个cover bi…

SAP灵活工作流场景模板创建

目录 1. 创建流程对象容器 2. 编辑模板中的灵活块 3. 设置工作流启动事件 4. 设置工作流运行时事件 5. 设置工作流输出结果&#xff08;可选&#xff09; 6. 工作流控制类 7. 创建流程活动 8. 创建流程条件 9. 代理规则 9. 值帮助 10. 参考时间 11. 电子邮件模版 …

[ AWS - SAA ] 解决方案架构师之设计弹性架构 - 选择可靠的弹性存储(如何选择 SSD vs. HDD)

本系列博文会围绕AWS Well-Architected 和六大支柱进行讲解&#xff0c;这些领域的内容对成为AWS亚马逊云科技上的 解决方案架构师&#xff08;SAA&#xff09; 非常重要。 本文主要介绍AWS亚马逊云中&#xff0c;关于弹性架构设计中存储设备的一些讲解。 本文的部分内容适用于…

哈希切割 + 位图 + 布隆过滤器 —— 海量数据面试题

目录 题目一&#xff1a;给一个超过100G大小的log file, log中存着IP地址, 设计算法找到出现次数最多的IP地址&#xff1f; 哈希切割 题目二&#xff1a;给定100亿个整数&#xff0c;设计算法找到只出现一次的整数&#xff1f; 解法一&#xff1a;哈希切割 解法二&#xf…

【论文精读】Guided-MVS

今天读的是一篇发表在IROS2022上的MVS文章&#xff1a;Multi-View Guided Multi-View Stereo&#xff0c;作者是来自于意大利University of Bologna的Matteo Poggi。 论文链接&#xff1a;arxiv 代码链接&#xff1a;https://github.com/andreaconti/multi-view-guided-multi-v…

SpringCloud Netflix复习之OpenFeign

文章目录写作背景Feign核心组件介绍Encoder和DecoderLoggerContractFeign.Builder上手实战开启FeignClient调用请求日志给FeignClient注入自定义拦截器Feign支持文件上传配置Feign开启Gzip压缩Feign配置超时时间Feign整合Ribbon支持负载均衡核心源码部分FeignClient注入到Sprin…

【Qt】通过创建ui界面类成员变量的方式显示窗体

【Qt】通过创建ui界面类成员变量的方式显示窗体1、背景2、实例3、验证1、背景 将.ui 文件转化为.h 头文件参考&#xff1a; 【Qt】将QtDesigner生成的.ui文件转化为.h头文件 https://jn10010537.blog.csdn.net/article/details/128589666其生成的.h头文件的显示&#xff0c;如…

HQChart实战教程56-限制指标周期

HQChart实战教程56-限制指标周期 指标周期范围效果图增加周期限制步骤1. 创建系统指标Condition.PeriodCONDITION_PERIOD 枚举说明提示信息提示信息配色实例源码指标周期范围 有些指标我们需要限制它的周期, 如指标A它只能对日线周期有效, 分时周期时无效的, 所有在切换到分…

Apache Hive 使用

Apache Hive 使用使用beeline 连接Apache Hive查看数据库使用或进入数据库创建表查看数据表上传数据数据操纵语言&#xff08;DML&#xff09;查询语句函数数学函数条件函数) 使用beeline 连接Apache Hive /export/server/apache-hive-3.1.2-bin/bin/beelinebeeline> ! co…

C51单片机基础之4G模块

一、4G模块初识EC03-DNC是亿佰特公司推出的 LTE CAT1 数传模块产品&#xff0c; 该产品软件功能完善&#xff0c; 覆盖绝大多数常规应用场景&#xff0c; EC03-DNC 是为实现串口设备与网络服务&#xff0c;通过网络相互传输数据而开发的产品 &#xff0c; 该产品是一款带分集接…

Linux 计算机网络 从 ping 来初窥计算机网络

Linux 计算机网络 从 ping 来初窥计算机网络 在上一章节《计算机网络从零到一》我们重点讲解了整个网络的形成&#xff0c;以及物理层、数据链路层、网络层这三层的形成以及他们所解决的问题&#xff0c;而本章节主要讲解 ping 命令在 Linux 中到底发生了一些什么。 ping 简介…

学习open62541 --- [73] 数据源造成无法监测变量的问题解决

本人最近遇到一个问题&#xff1a;给一个变量添加数据源后&#xff0c;使用监测项去监测变量变化&#xff0c;如果采样时间为0&#xff0c;会发现无法监测到变量的变化。 本文讲述这种情况的发生原因以及解决办法。 一 Server例子 首先准备server例子&#xff0c;如下&#x…

WSL 下载服务器加速

网络下载加速&#xff0c;这里使用修改 hosts 文件 &#xff0c;地址映射 方法&#xff0c;所有网址适用&#xff0c;这里以 WSL 下载服务器为例子 命令 wsl -l -o 访问的地址&#xff1a; https://raw.githubusercontent.com/microsoft/WSL/master/distributions/Distributi…

Java设计模式中组合模式是什么/树形结构怎么组合或显示存储,编程怎么实现树形结构

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 5.7 组合模式 5.7.1 概述 又名整体模式&#xff0c;是用于把一组相似的对象当作一个单一的对象依据树形结构来组合对象&#xff0c;用来表示部分以及整体层次属于…