MPU6050是什么交通违章 SlaveAddress怎么确定

谈一谈 MPU6050 姿态融合(转) - KOKRO
文章转载请注明来源!
姿态角(Euler角)pitch yaw roll飞行器的姿态角并不是指哪个角度,是三个角度的统称。它们是:俯仰、滚转、偏航。你可以想象是飞机围绕XYZ三个轴分别转动形成的夹角。地面坐标系(earth-surface inertial reference frame)Sg--------OXgYgZg①在地面上选一点Og②使Xg轴在水平面内并指向某一方向③Zg轴垂直于地面并指向地心(重力方向)④Yg轴在水平面内垂直于Xg轴,其指向按右手定则确定机体坐标系(Aircraft-body coordinate frame)Sb-------OXYZ①原点O取在飞机质心处,坐标系与飞机固连②x轴在飞机对称平面内并平行于飞机的设计轴线指向机头③y轴垂直于飞机对称平面指向机身右方④z轴在飞机对称平面内,与x轴垂直并指向机身下方欧拉角/姿态角(Euler Angle)机体坐标系与地面坐标系的关系是三个Euler角,反应了飞机相对地面的姿态。俯仰角θ(pitch):机体坐标系X轴与水平面的夹角。当X轴的正半轴位于过坐标原点的水平面之上(抬头)时,俯仰角为正,否则为负。偏航角ψ(yaw):机体坐标系xb轴在水平面上投影与地面坐标系xg轴(在水平面上,指向目标为正)之间的夹角,由xg轴逆时针转至机体xb的投影线时,偏航角为正,即机头右偏航为正,反之为负。滚转角Φ(roll):机体坐标系zb轴与通过机体xb轴的铅垂面间的夹角,机体向右滚为正,反之为负。首先要明确,MPU6050 是一款姿态传感器,使用它就是为了得到待测物体(如四轴、平衡小车) x、y、z 轴的倾角(俯仰角 Pitch、滚转角 Roll、偏航角 Yaw) 。我们通过 I2C 读取到 MPU6050 的六个数据(三轴加速度 AD 值、三轴角速度 AD 值)经过姿态融合后就可以得到 Pitch、Roll、Yaw 角。本帖主要介绍三种姿态融合算法:四元数法 、一阶互补算法和卡尔曼滤波算法。一、四元数法关于四元数的一些概念和计算就不写上来了,我也不懂。我能告诉你的是:通过下面的算法,可以把六个数据转化成四元数(q0、q1、q2、q3),然后四元数转化成欧拉角(P、R、Y 角)。虽然 MPU6050 自带的 DMP库可以直接输出四元数,减轻 STM32 的运算负担, 这里在此没有使用,因为我是用 STM32 的硬件 I2C 读取 MPU6050 数据的( ... 4&page=1#pid3625735),DMP库需要对 I2C 函数进行修改,如 DMP 库中的 I2C 写:i2c_write(st.hw-&addr, st.reg-&pwr_mgmt_1, 1, &(data[0]));有4个输入变量,而 STM32 硬件 I2C 的 I2C 写为:void MPU6050_I2C_ByteWrite(u8 slaveAddr, u8 pBuffer, u8 writeAddr),只有 3 个输入量(这之间的差异好像是由于 MPU6050 的 DMP 库是针对 MSP430 单片机写的),所以必须进行修改,但是改固件库是一件很痛苦的事,你们应该都懂。当然,如果你用模拟 I2C 的话,是容易实现的,网上的 DMP 移植几乎都是基于模拟 I2C 的。复制代码#include&math.h&
#include &stm32f10x.h&
//---------------------------------------------------------------------------------------------------
// 变量定义
#define Kp 100.0f
// 比例增益支配率收敛到加速度计/磁强计
#define Ki 0.002f
// 积分增益支配率的陀螺仪偏见的衔接
#define halfT 0.001f
// 采样周期的一半
float q0 = 1, q1 = 0, q2 = 0, q3 = 0;
// 四元数的元素,代表估计方向
float exInt = 0, eyInt = 0, ezInt = 0;
// 按比例缩小积分误差
float Yaw,Pitch,R
//偏航角,俯仰角,翻滚角
void IMUupdate(float gx, float gy, float gz, float ax, float ay, float az)
float vx, vy,
float ex, ey,
// 测量正常化
norm = sqrt(ax*ax + ay*ay + az*az);
// 估计方向的重力
vx = 2*(q1*q3 - q0*q2);
vy = 2*(q0*q1 + q2*q3);
vz = q0*q0 - q1*q1 - q2*q2 + q3*q3;
// 错误的领域和方向传感器测量参考方向之间的交叉乘积的总和
ex = (ay*vz - az*vy);
ey = (az*vx - ax*vz);
ez = (ax*vy - ay*vx);
// 积分误差比例积分增益
exInt = exInt + ex*Ki;
eyInt = eyInt + ey*Ki;
ezInt = ezInt + ez*Ki;
// 调整后的陀螺仪测量
gx = gx + Kp*ex + exI
gy = gy + Kp*ey + eyI
gz = gz + Kp*ez + ezI
// 整合四元数率和正常化
q0 = q0 + (-q1*gx - q2*gy - q3*gz)*halfT;
q1 = q1 + (q0*gx + q2*gz - q3*gy)*halfT;
q2 = q2 + (q0*gy - q1*gz + q3*gx)*halfT;
q3 = q3 + (q0*gz + q1*gy - q2*gx)*halfT;
// 正常化四元
norm = sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
= asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch ,转换为度数
Roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // rollv
//Yaw = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3;
//此处没有价值,注掉
}要注意的的是,四元数算法输出的是三个量 Pitch、Roll 和 Yaw,运算量很大。而像平衡小车这样的例子只需要一个角(Pitch 或 Roll )就可以满足工作要求,个人觉得做平衡小车最好不用四元数法。二、一阶互补算法MPU6050 可以输出三轴的加速度和角速度。通过加速度和角速度都可以得到 Pitch 和 Roll 角(加速度不能得到 Yaw 角),就是说有两组 Pitch、Roll 角,到底应该选哪组呢?别急,先分析一下。MPU6050 的加速度计和陀螺仪各有优缺点,三轴的加速度值没有累积误差,且通过算 tan()
可以得到倾角,但是它包含的噪声太多(因为待测物运动时会产生加速度,电机运行时振动会产生加速度等),不能直接使用;陀螺仪对外界振动影响小,精度高,通过对角速度积分可以得到倾角,但是会产生累积误差。所以,不能单独使用 MPU6050 的加速度计或陀螺仪来得到倾角,需要互补。一阶互补算法的思想就是给加速度和陀螺仪不同的权值,把它们结合到一起,进行修正。得到 Pitch 角的程序如下:复制代码//一阶互补滤波
float K1 =0.1; // 对加速度计取值的权重
float dt=0.001;//注意:dt的取值为滤波器采样时间
angle_ax=atan(ax/az)*57.3;
//加速度得到的角度
gy=(float)gyo[1]/7510.0;
//陀螺仪得到的角速度
Pitch = yijiehubu(angle_ax,gy);
float yijiehubu(float angle_m, float gyro_m)//采集后计算的角度和角加速度
angle = K1 * angle_m + (1-K1) * (angle + gyro_m * dt);
}互补算法只能得到一个倾角,这在平衡车项目中够用了,而在四轴飞行器设计中还需要 Roll 和 Yaw,就需要两个 互补算法,我是这样写的,注意变量不要搞混:复制代码
//一阶互补滤波
float K1 =0.1; // 对加速度计取值的权重
float dt=0.001;//注意:dt的取值为滤波器采样时间
float angle_P,angle_R;
float yijiehubu_P(float angle_m, float gyro_m)//采集后计算的角度和角加速度
angle_P = K1 * angle_m + (1-K1) * (angle_P + gyro_m * dt);
return angle_P;
float yijiehubu_R(float angle_m, float gyro_m)//采集后计算的角度和角加速度
angle_R = K1 * angle_m + (1-K1) * (angle_R + gyro_m * dt);
return angle_R;
}单靠 MPU6050 无法准确得到 Yaw 角,需要和地磁传感器结合使用。三、卡尔曼滤波其实卡尔曼滤波和一阶互补有些相似,输入也是一样的。卡尔曼原理以及什么5个公式等等的,我也不太懂,就不写了,感兴趣的话可以上网查。在此给出具体程序,和一阶互补算法一样,每次卡尔曼滤波只能得到一个方向的角度。复制代码#include&math.h&
#include &stm32f10x.h&
#include &Kalman_Filter.h&
//卡尔曼滤波参数与函数
float dt=0.001;//注意:dt的取值为kalman滤波器采样时间
float angle, angle_//角度和角速度
float P[2][2] = {{ 1, 0 },
{ 0, 1 }};
float Pdot[4] ={ 0,0,0,0};
float Q_angle=0.001, Q_gyro=0.005; //角度数据置信度,角速度数据置信度
float R_angle=0.5 ,C_0 = 1;
float q_bias, angle_err, PCt_0, PCt_1, E, K_0, K_1, t_0, t_1;
//卡尔曼滤波
float Kalman_Filter(float angle_m, float gyro_m)//angleAx 和 gyroGy
angle+=(gyro_m-q_bias) *
angle_err = angle_m -
Pdot[0]=Q_angle - P[0][1] - P[1][0];
Pdot[1]=- P[1][1];
Pdot[2]=- P[1][1];
Pdot[3]=Q_
P[0][0] += Pdot[0] *
P[0][1] += Pdot[1] *
P[1][0] += Pdot[2] *
P[1][1] += Pdot[3] *
PCt_0 = C_0 * P[0][0];
PCt_1 = C_0 * P[1][0];
E = R_angle + C_0 * PCt_0;
K_0 = PCt_0 / E;
K_1 = PCt_1 / E;
t_0 = PCt_0;
t_1 = C_0 * P[0][1];
P[0][0] -= K_0 * t_0;
P[0][1] -= K_0 * t_1;
P[1][0] -= K_1 * t_0;
P[1][1] -= K_1 * t_1;
angle += K_0 * angle_ //最优角度
q_bias += K_1 * angle_
angle_dot = gyro_m-q_//最优角速度
return angle;
}作个总结:三种融合算法都能够输出姿态角(Pitch 和 Roll ),一次四元数法可以输出 P、R、Y 三个倾角,计算量比较大。一阶互补和卡尔曼滤波每次只能输出一个轴的姿态角。转自
本文基于《》许可协议授权
文章链接:https://www.kokro.me/index.php/archives/71/ (转载时请注明本文出处及文章链接)姿态角(Euler角)pitch yaw roll飞行器的姿态角并不是指哪个角度,是三个角度的统称。它们是:俯仰、滚转、偏航。你可以想象是飞机围绕XYZ三个轴分别转动形成的夹角。地面坐标系(earth-surface inertial reference frame)Sg--------OXgYgZg&ignore_js_op&&①在地面上选一点Og②使Xg轴在水平面内并指向某一方向③Zg轴垂直于地面并指向地心(重力方向)④Yg轴在水平面内垂直于Xg轴,其指向按右手定则确定机体坐标系(Aircraft-body coordinate frame)Sb-------OXYZ&ignore_js_op&&①原点O取在飞机质心处,坐标系与飞机固连②x轴在飞机对称平面内并平行于飞机的设计轴线指向机头③y轴垂直于飞机对称平面指向机身右方④z轴在飞机对称平面内,与x轴垂直并指向机身下方欧拉角/姿态角(Euler Angle)&ignore_js_op&&&ignore_js_op&&机体坐标系与地面坐标系的关系是三个Euler角,反应了飞机相对地面的姿态。俯仰角&(pitch):机体坐标系X轴与水平面的夹角。当X轴的正半轴位于过坐标原点的水平面之上(抬头)时,俯仰角为正,否则为负。&ignore_js_op&&偏航角&(yaw):机体坐标系xb轴在水平面上投影与地面坐标系xg轴(在水平面上,指向目标为正)之间的夹角,由xg轴逆时针转至机体xb的投影线时,偏航角为正,即机头右偏航为正,反之为负。&ignore_js_op&&滚转角&P(roll):机体坐标系zb轴与通过机体xb轴的铅垂面间的夹角,机体向右滚为正,反之为负。&ignore_js_op&
首先要明确,MPU6050 是一款姿态传感器,使用它就是为了得到待测物体(如四轴、平衡小车) x、y、z 轴的倾角(俯仰角 Pitch、滚转角 Roll、偏航角 Yaw) 。我们通过 I2C 读取到 MPU6050 的六个数据(三轴加速度 AD 值、三轴角速度 AD 值)经过姿态融合后就可以得到 Pitch、Roll、Yaw 角。
本帖主要介绍三种姿态融合算法:四元数法 、一阶互补算法和卡尔曼滤波算法。
一、四元数法
关于四元数的一些概念和计算就不写上来了,我也不懂。我能告诉你的是:通过下面的算法,可以把六个数据转化成四元数(q0、q1、q2、q3),然后四元数转化成欧拉角(P、R、Y 角)。
& & & & 虽然 MPU6050 自带的 DMP库可以直接输出四元数,减轻 STM32 的运算负担, 这里在此没有使用,因为我是用 STM32 的硬件 I2C 读取 MPU6050 数据的(),DMP库需要对 I2C 函数进行修改,如 DMP 库中的 I2C 写:i2c_write(st.hw-&addr, st.reg-&pwr_mgmt_1, 1, &(data[0]));有4个输入变量,而 STM32 硬件 I2C 的 I2C 写为:void MPU6050_I2C_ByteWrite(u8 slaveAddr, u8 pBuffer, u8 writeAddr),只有 3 个输入量(这之间的差异好像是由于 MPU6050 的 DMP 库是针对 MSP430&写的),所以必须进行修改,但是改固件库是一件很痛苦的事,你们应该都懂。当然,如果你用模拟 I2C 的话,是容易实现的,网上的 DMP 移植几乎都是基于模拟 I2C 的。
#include&math.h&
#include "stm32f10x.h"
//---------------------------------------------------------------------------------------------------
// 变量定义
#define Kp 100.0f& && && && && && && && &// 比例增益支配率收敛到加速度计/磁强计
#define Ki 0.002f& && && && && & // 积分增益支配率的陀螺仪偏见的衔接
#define halfT 0.001f& && && && && & // 采样周期的一半
float q0 = 1, q1 = 0, q2 = 0, q3 = 0;& && && & // 四元数的元素,代表估计方向
float exInt = 0, eyInt = 0, ezInt = 0;& && &&&// 按比例缩小积分误差
float Yaw,Pitch,R&&//偏航角,俯仰角,翻滚角
void IMUupdate(float gx, float gy, float gz, float ax, float ay, float az)
& && &&&float vx, vy,
& && &&&float ex, ey,&&
& && &&&// 测量正常化
& && &&&norm = sqrt(ax*ax + ay*ay + az*az);& && &
& && &&&ax = ax /& && && && && && & //单位化
& && &&&ay = ay /
& && &&&az = az /& && &
& && &&&// 估计方向的重力
& && &&&vx = 2*(q1*q3 - q0*q2);
& && &&&vy = 2*(q0*q1 + q2*q3);
& && &&&vz = q0*q0 - q1*q1 - q2*q2 + q3*q3;
& && &&&// 错误的领域和方向传感器测量参考方向之间的交叉乘积的总和
& && &&&ex = (ay*vz - az*vy);
& && &&&ey = (az*vx - ax*vz);
& && &&&ez = (ax*vy - ay*vx);
& && &&&// 积分误差比例积分增益
& && &&&exInt = exInt + ex*Ki;
& && &&&eyInt = eyInt + ey*Ki;
& && &&&ezInt = ezInt + ez*Ki;
& && &&&// 调整后的陀螺仪测量
& && &&&gx = gx + Kp*ex + exI
& && &&&gy = gy + Kp*ey + eyI
& && &&&gz = gz + Kp*ez + ezI
& && &&&// 整合四元数率和正常化
& && &&&q0 = q0 + (-q1*gx - q2*gy - q3*gz)*halfT;
& && &&&q1 = q1 + (q0*gx + q2*gz - q3*gy)*halfT;
& && &&&q2 = q2 + (q0*gy - q1*gz + q3*gx)*halfT;
& && &&&q3 = q3 + (q0*gz + q1*gy - q2*gx)*halfT;&&
& && &&&// 正常化四元
& && &&&norm = sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
& && &&&q0 = q0 /
& && &&&q1 = q1 /
& && &&&q2 = q2 /
& && &&&q3 = q3 /
& && &&&Pitch&&= asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch ,转换为度数
& && &&&Roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // rollv
& && &&&//Yaw = atan2(2*(q1*q2 + q0*q3),q0*q0+q1*q1-q2*q2-q3*q3) * 57.3;& && && && && & //此处没有价值,注掉
& & & 要注意的的是,四元数算法输出的是三个量 Pitch、Roll 和 Yaw,运算量很大。而像平衡小车这样的例子只需要一个角(Pitch 或 Roll )就可以满足工作要求,个人觉得做平衡小车最好不用四元数法。
二、一阶互补算法
& & & &MPU6050 可以输出三轴的加速度和角速度。通过加速度和角速度都可以得到 Pitch 和 Roll 角(加速度不能得到 Yaw 角),就是说有两组 Pitch、Roll 角,到底应该选哪组呢?别急,先分析一下。MPU6050 的加速度计和陀螺仪各有优缺点,三轴的加速度值没有累积误差,且通过算 tan()&&可以得到倾角,但是它包含的噪声太多(因为待测物运动时会产生加速度,电机运行时振动会产生加速度等),不能直接使用;陀螺仪对外界振动影响小,精度高,通过对角速度积分可以得到倾角,但是会产生累积误差。所以,不能单独使用 MPU6050 的加速度计或陀螺仪来得到倾角,需要互补。一阶互补算法的思想就是给加速度和陀螺仪不同的权值,把它们结合到一起,进行修正。得到 Pitch 角的程序如下:
//一阶互补滤波
float K1 =0.1; // 对加速度计取值的权重
float dt=0.001;//注意:dt的取值为滤波器采样时间
angle_ax=atan(ax/az)*57.3;& &&&//加速度得到的角度
gy=(float)gyo[1]/7510.0;& && & //陀螺仪得到的角速度
Pitch = yijiehubu(angle_ax,gy);
float yijiehubu(float angle_m, float gyro_m)//采集后计算的角度和角加速度
& &&&angle = K1 * angle_m + (1-K1) * (angle + gyro_m * dt);
& & 互补算法只能得到一个倾角,这在平衡车项目中够用了,而在四轴飞行器设计中还需要 Roll 和 Yaw,就需要两个 互补算法,我是这样写的,注意变量不要搞混:
//一阶互补滤波
float K1 =0.1; // 对加速度计取值的权重
float dt=0.001;//注意:dt的取值为滤波器采样时间
float angle_P,angle_R;
float yijiehubu_P(float angle_m, float gyro_m)//采集后计算的角度和角加速度
& &&&angle_P = K1 * angle_m + (1-K1) * (angle_P + gyro_m * dt);
& && && &return angle_P;
float yijiehubu_R(float angle_m, float gyro_m)//采集后计算的角度和角加速度
& &&&angle_R = K1 * angle_m + (1-K1) * (angle_R + gyro_m * dt);
& && && &return angle_R;
单靠 MPU6050 无法准确得到 Yaw 角,需要和地磁传感器结合使用。
三、卡尔曼滤波
& & & 其实卡尔曼滤波和一阶互补有些相似,输入也是一样的。卡尔曼原理以及什么5个公式等等的,我也不太懂,就不写了,感兴趣的话可以上网查。在此给出具体程序,和一阶互补算法一样,每次卡尔曼滤波只能得到一个方向的角度。
#include&math.h&
#include "stm32f10x.h"
#include "Kalman_Filter.h"
//卡尔曼滤波参数与函数
float dt=0.001;//注意:dt的取值为kalman滤波器采样时间
float angle, angle_//角度和角速度
float P[2][2] = {{ 1, 0 },
& && && && && &&&{ 0, 1 }};
float Pdot[4] ={ 0,0,0,0};
float Q_angle=0.001, Q_gyro=0.005; //角度数据置信度,角速度数据置信度
float R_angle=0.5 ,C_0 = 1;
float q_bias, angle_err, PCt_0, PCt_1, E, K_0, K_1, t_0, t_1;
//卡尔曼滤波
float Kalman_Filter(float angle_m, float gyro_m)//angleAx 和 gyroGy
& && &&&angle+=(gyro_m-q_bias) *
& && &&&angle_err = angle_m -
& && &&&Pdot[0]=Q_angle - P[0][1] - P[1][0];
& && &&&Pdot[1]=- P[1][1];
& && &&&Pdot[2]=- P[1][1];
& && &&&Pdot[3]=Q_
& && &&&P[0][0] += Pdot[0] *
& && &&&P[0][1] += Pdot[1] *
& && &&&P[1][0] += Pdot[2] *
& && &&&P[1][1] += Pdot[3] *
& && &&&PCt_0 = C_0 * P[0][0];
& && &&&PCt_1 = C_0 * P[1][0];
& && &&&E = R_angle + C_0 * PCt_0;
& && &&&K_0 = PCt_0 / E;
& && &&&K_1 = PCt_1 / E;
& && &&&t_0 = PCt_0;
& && &&&t_1 = C_0 * P[0][1];
& && &&&P[0][0] -= K_0 * t_0;
& && &&&P[0][1] -= K_0 * t_1;
& && &&&P[1][0] -= K_1 * t_0;
& && &&&P[1][1] -= K_1 * t_1;
& && &&&angle += K_0 * angle_ //最优角度
& && &&&q_bias += K_1 * angle_
& && &&&angle_dot = gyro_m-q_//最优角速度
& && &&&return angle;
& & & 作个总结:三种融合算法都能够输出姿态角(Pitch 和 Roll ),一次四元数法可以输出 P、R、Y 三个倾角,计算量比较大。一阶互补和卡尔曼滤波每次只能输出一个轴的姿态角。
阅读(...) 评论()MPU6050使用_百度文库
您的浏览器Javascript被禁用,需开启后体验完整功能,
享专业文档下载特权
&赠共享文档下载特权
&100W篇文档免费专享
&每天抽奖多种福利
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
MPU6050使用
&&MPU6050使用
阅读已结束,下载本文需要
定制HR最喜欢的简历
下载文档到电脑,同时保存到云知识,更方便管理
加入VIP
还剩9页未读,
定制HR最喜欢的简历
你可能喜欢I2C(Inter-Integrated Circuit)总线(也称 IIC 或 I2C) 是有PHILIPS公司开发的两线式串行总线,用于连接微控制器及外围设备,是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少、控制方式简单、器件封装形式小、通信速率较高等优点。
Exynos4412精简指令集微处理器支持4个IIC总线控制器。为了能使连接在总线上的主和从设备之间传输数据,专用的数据线SDA和时钟信号线SCL被使用,他们都是双向的。
如果工作在多主机的IIC总线模式,多个4412处理器将从从机那接收数据或发送数据给从机。在IIC总线上的主机端4412会启动或终止一个数据传输。4412的IIC总线控制器会用一个标准的IIC总线仲裁机制去实现多主机和多从机传输数据。
通过控制如下寄存器以实现IIC总线上的多主机操作:控制寄存器:
状态寄存器:
Tx/Rx数据偏移寄存器:
地址寄存器:
如果I2C总线空闲,那么SCL和SDA信号线将都为高电平。在SCL为高电平期间,如果SDA有由高到低电平的跳变,那么将启动一个起始信号,如果SDA有由低到高电平的跳变,将启动一个结束信号。
主机端的设备总是提供起始和停止信号的一端。在起始信号被发出后,一个数据字节的前7位被当作地址通过SDA线被传输。这个地制值决定了总线上的主设备将要选择那个从设备作为传输对象,bit8决定传输数据的方向(是读还是写)。
I2C总线上的数据(即在SDA上传输的数据)都是以8位字节传输的,在总线上传输操作的过程中,对发送或接收的数据字节数是没有限制的。I2C总线上的主/从设备发送数据总是以一个数据的最高位开始传输(即MSB方式),传输完一个字节后,应答信号紧接其后。二、I2C总线接口特性
9个通道多主、从I2C总线接口。其中8个通道作为普通接口(即I2C0、I2C1....),1个通道作为HDMI的专用接口。
7位地址模式。
串行,8位单向或双向的数据传输。
在标准模式中,每秒最多可以传输100k位,即12.5kB的数据量。
在快速模式中,每秒最多可以传输400k位,即50kB的数据量。
支持主机端发送、接收,从机端发送、接收操作。
支持中断和查询方式。三、框图
从上图可以看出,4412提供4个寄存器来完成所有的IIC操作。SDA线上的数据从IICDS寄存器经过移位寄存器发出,或通过移位寄存器传入IICDS寄器;IICADD寄存器中保存4412当做从机时的地址;IICCON、IICSTAT两个寄存器用来控制或标识各种状态,比如选择工作工作模式,发出S信号、P信号,决定是否发出ACK信号,检测是否接收到ACK信号。
四、I2C总线接口操作
针对4412处理器的I2C总线接口,具备4种操作模式:
1 -- 主机发送模式
2 -- 主机接收模式
3 -- 从机发送模式
4 -- 从机接收模式
下面将描述这些操作模式之间的功能关系:
0、数据有效性
SDA线上的数据必须在时钟的高电平周期保持稳定。数据线的高或低电平状态IIC位传输数据的有效性在SCL线的时钟信号是低电平才能改变。
开始和停止条件
当4412的I2C接口空闲时,它往往工作在从机模式。或者说,4412的的i2c接口在SDA线上察觉到一个起始信号之前它应该工作在从机模式。当控制器改变4412的i2c接口的工作模式为主机模式后,SDA线上发起数据传输并且控制器会产生SCL时钟信号。
开始条件通过SDA线进行串行的字节传输,一个停止信号终止数据传输,停止信号是指SCL在高电平器件SDA线有从低到高电平的跳变,主机端产生起始和停止条件。当主、从设备产生一个起始信号后,I2C总线将进入忙状态。这里需要说明的是上述主从设备都有可能作为主机端。
当一个主机发送了一个起始信号后,它也应该发送一个从机地址以通知总线上的从设备。这个地址字节的低7位表示从设备地址,最高位表示传输数据的方向,即主机将要进行读还是写。当最高位是0时,它将发起一个写操作(发送操作);当最高位是1时,它将发起一个读数据的请求(接收操作)。
主机端发起一个结束信号以完成传输操作,如果主机端想在总线上继续进行数据的传输,它将发出另外一个起始信号和从设备地址。用这样的方式,它们可以用各种各样的格式进行读写操作。
下图为起始和停止信号:
下面先提前讲一下具体应用中如何启动和恢复IIC的传输
启动或恢复4412的I2C传输有以下两种方法。
1) 当IICCON[4]即中断状态位为0时,通过写IICSTAT寄存器启动I2C操作。有以下两种情况。
1--在主机模式,令IICSTAT[5:4]等于0b11,将发出S信号和IICDS寄存器的数据(寻址),令IICSTAT[5:4]等于0b01,将发出P信号。
2--在从机模式,令IICSTAT[4]等于1将等待其他主机发出S信号及地址信息。
2)当IICCON[4]即中断状态为1时,表示I2C操作被暂停。在这期间设置好其他寄存器之后,向IICCON[4]写入0即可恢复I2C操作。所谓“设置其他寄存器”,有以下三种情况:
1--对于主机模式,可以按照上面1的方法写IICSTAT寄存器,恢复I2C操作后即可发出S信号和IICDS寄存器的值(寻址),或发出P信号。
2--对于发送器,可以将下一个要发送的数据写入IICDS寄存器中,恢复I2C操作后即可发出这个数据。
3--对于接收器,可以从IICDS寄存器读出接收到的数据。最后向IICCON[4]写入0的同时,设置IICCON[7]以决定是否在接收到下一个数据后是否发出ACK信号。
数据传输格式
放到SDA线上的所有字节数据的长度应该为8位,在每次传输数据时,对传输数据量没有限制。在起始信号后的第一个数据字节应该包含地址字段,当4412的I2C接口被设置为主模式时,地址字节应该有控制器端发出。在每个字节后,应该有一个应答位。
如果从机要完成一些其他功能后(例如一个内部中断服务程序)才能继续接收或发送下一个字节,从机可以拉低SCL迫使主机进入等待状态。当从机准备好接收下一个数据并释放SCL后,数据传输继续。如果主机在传输数据期间也需要完成一些其他功能(例如一个内部中断服务程序)也可以拉低SCL以占住总线。
下面的图中将说明数据传输格式:
上图中说明,在传输完每个字节数据后,都会有一个应带信号,这个应答信号在第9个时钟周期。具体过程如下(注意下面描述的读写过程都是针对Tiny4412处理器而言,当有具体的I2C设备与4412相连时,数据表示什么需要看具体的I2C设备,4412是不知道数据的含义的):
写过程:主机发送一个起始信号S→发送从机7位地址和1位方向,方向位表示写→主机释放SDA线方便从机给回应→有从机匹配到地址,拉低SDA线作为ACK→主机重新获得SDA传输8位数据→主机释放SDA线方便从机给回应→从机收到数据拉低SDA线作为ACK告诉主机数据接收成功→主机发出停止信号。
读过程:主机发送一个起始信号S→发送从机7位地址和1位方向,方向位表示读→主机释放SDA线方便从机给回应→有从机匹配到地址,拉低SDA线作为ACK→从机继续占用SDA线,用SDA传输8位数据给主机→从机释放SDA线(拉高)方便主机给回应→主机接收到数据→主机获得SDA线控制并拉低SDA线作为ACK告诉从机数据接收成功→主机发出停止信号。
注意:在具体的I2C通信时,要看I2C设备才能确定读写时序,比如下面即将描述的第七大点中的示例,读写EEPROM中就会说道具体的数据含义,读写过程。
3. 应答信号的传输
为了完成一个字节数据的传输,接收方将发送一个应答位给发送方。应答信号出现在SCL线上的时钟周期中的第九个时钟周期,为了发送或接收1个字节的数据,主机端会产生8个时钟周期,为了传输一个ACK位,主机端需要产生一个时钟脉冲。
ACK时钟脉冲到来之际,发送方会在SDA线上设置高电平以释放SDA线。在ACK时钟脉冲之间,接收方会驱动和保持SDA线为低电平,这发生在第9个时钟脉冲为高电平期间。 应答信号为低电平时,规定为有效应答位(ACK简称应答位),表示接收器已经成功地接收了该字节;应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 对于反馈有效应答位ACK的要求是,接收器在第9个时钟脉冲之前的低电平期间将SDA线拉低,并且确保在该时钟的高电平期间为稳定的低电平。如果接收器是主控器,则在它收到最后一个字节后,发送一个NACK信号(即不发出ACK信号),以通知被控发送器结束数据发送,并释放SDA线,以便主控接收器发送一个停止信号P。
4. 读写操作
当I2C控制器在发送模式下发送数据后,I2C总线接口将等待直到移位寄存器(I2CDS)接收到一个数据。在往此寄存器写入一个新数据前,SCL线应该保持为低电平,写完数据后,I2C控制器将释放SCL线。当前正在传输的数据传输完成后,4412会捕捉到一个中断,然后cpu将开始往I2CDS寄存器中写入一个新的数据。
当I2C控制器在接收模式下接收到数据后,I2C总线接口将等待直到I2CDS寄存器被读。在读到新数据之前,SCL线会被保持为低电平,读到数据后I2C控制器将释放掉SCL线。一个新数据接收完成后,4412将收到一个中断,cpu收到这个中断请求后,它将从I2CDS寄存器中读取数据。
5. 总线仲裁机制
总线上可能挂接有多个器件,有时会发生两个或多个主器件同时想占用总线的情况,这种情况叫做总线竞争。I2C总线具有多主控能力,可以对发生在SDA线上的总线竞争进行仲裁,其仲裁原则是这样的:当多个主器件同时想占用总线时,如果某个主器件发送高电平,而另一个主器件发送低电平,则发送电平与此时SDA总线电平不符的那个器件将自动关闭其输出级。总线竞争的仲裁是在两个层次上进行的。首先是地址位的比较,如果主器件寻址同一个从器件,则进入数据位的比较,从而确保了竞争仲裁的可靠性。由于是利用I2C总线上的信息进行仲裁,因此不会造成信息的丢失。
6. 终止条件
当一个从接收者不能识别从地址时,它将保持SDA线为高电平。在这样的情况下,主机会产生一个停止信号并且取消数据的传输。当终止传输产生后,主机端接收器会通过取消ACK的产生以告诉从机端发送器结束发送操作。这将在主机端接收器接收到从机端发送器发送的最后一个字节之后发生,为了让主机端产生一个停止条件,从机端发送者将释放SDA线。
7. 配置I2C总线
如果要设置I2C总线中SCL时钟信号的频率,可以在I2CCON寄存器中设置4位分频器的值。I2C总线接口地址值存放在I2C总线地址寄存器(I2CADD)中,默认值未知。
8. 每种模式下的操作流程图
在I2C总线上执行任何的收发Tx/Rx操作前,应该做如下配置:
(1)在I2CADD寄存器中写入从设备地址
(2)设置I2CCON控制寄存器
a. 使能中断
b. 定义SCL频率
(3)设置I2CSTAT寄存器以使能串行输出
下图为主设备发送模式
下图为主设备接收模式
下图为从设备发送模式
下图为从设备接收
1-- I2C总线控制寄存器
IICCON寄存器用于控制是否发出ACK信号、设置发送器的时钟、开启I2C中断,并标识中断是否发生
使用IICCON寄存器时,有如下注意事项
1)、发送模式的时钟频率由位[6]、位[3:0]联合决定。另外,当IICCON[6]=0时,IICCON[3:0]不能取0或1。
2)、位[4]用来标识是否有I2C中断发生,读出为0时标识没有中断发生,读出为1时标识有中断发生。当此位为1时,SCL线被拉低,此时所以I2C传输停止;如果要继续传输,需写入0清除它。中断在以下3中情况下发生:
1 -- 当发送地址信息或接收到一个从机地址并且吻合时;
2 -- 当总线仲裁失败时;
3 -- 当发送/接收完一个字节的数据(包括响应位)时;
3)、基于SDA、SCL线上时间特性的考虑,要发送数据时,先将数据写入IICDS寄存器,然后再清除中断。
4)、如果IICCON[5]=0,IICCON[4]将不能正常工作,所以,即使不使用I2C中断,也要将IICCON[5]设为1.
2 -- I2C状态寄存器
IICSTAT寄存器用于选择I2C接口的工作模式,发出S信号、P信号,使能接收/发送功能,并标识各种状态,比如总线仲裁是否成功、作为从机时是否被寻址、是否接收到0地址、是否接收到ACK信号等。
3 -- I2C数据发送/接收移位寄存器
下面是个IIC总线实例:
用IIC总线实现CPU与MPU-6050的数据查询
具体代码如下:#include "exynos_4412.h"
//****************************************
MPU6050内部地址
//****************************************
#define SMPLRT_DIV
//陀螺仪采样率,典型值:0x07(125Hz)
#define CONFIG
//低通滤波频率,典型值:0x06(5Hz)
#define GYRO_CONFIG
//陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG
//加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz)
#define ACCEL_XOUT_H
#define ACCEL_XOUT_L
#define ACCEL_YOUT_H
#define ACCEL_YOUT_L
#define ACCEL_ZOUT_H
#define ACCEL_ZOUT_L
#define TEMP_OUT_H
#define TEMP_OUT_L
#define GYRO_XOUT_H
#define GYRO_XOUT_L
#define GYRO_YOUT_H
#define GYRO_YOUT_L
#define GYRO_ZOUT_H
#define GYRO_ZOUT_L
#define PWR_MGMT_1
//电源管理,典型值:0x00(正常启用)
#define WHO_AM_I
//IIC地址寄存器(默认数值0x68,只读)
#define SlaveAddress
//IIC写入时的地址字节数据,+1为读取
void mydelay_ms(int time)
while(time--)
for (i = 0; i & 5; i++)
for (j = 0; j & 514; j++);
/**********************************************************************
iic read a byte program body
* @param[in]
slave_addr, addr, &data
**********************************************************************/
void iic_read(unsigned char slave_addr, unsigned char addr, unsigned char *data)
I2C5.I2CDS = slave_ //将从机地址写入I2CDS寄存器中
I2C5.I2CCON = (1 && 7)|(1 && 6)|(1 && 5); //设置时钟并使能中断
I2C5.I2CSTAT = 0xf0; //[7:6]设置为0b11,主机发送模式;
//往[5:4]位写0b11,即产生启动信号,发出IICDS寄存器中的地址
while(!(I2C5.I2CCON & (1 && 4))); // 等待传输结束,传输结束后,I2CCON [4]位为1,标识有中断发生;
// 此位为1时,SCL线被拉低,此时I2C传输停止;
I2C5.I2CDS = //写命令值
I2C5.I2CCON = I2C5.I2CCON & (~(1 && 4)); // I2CCON [4]位清0,继续传输
while(!(I2C5.I2CCON & (1 && 4))); // 等待传输结束
I2C5.I2CSTAT = 0xD0; // I2CSTAT[5:4]位写0b01,发出停止信号
I2C5.I2CDS = slave_addr | 1; //表示要读出数据
I2C5.I2CCON = (1 && 7)|(1 && 6) |(1 && 5) ; //设置时钟并使能中断
I2C5.I2CSTAT = 0xb0; //[7:6]位0b10,主机接收模式;
//往[5:4]位写0b11,即产生启动信号,发出IICDS寄存器中的地址
//I2C5.I2CCON = I2C5.I2CCON & (~(1 && 4));
while(!(I2C5.I2CCON & (1 && 4))); //等待传输结束,接收数据
I2C5.I2CCON &= ~((1&&7)|(1 && 4)); // I2CCON [4]位清0,继续传输,接收数据,
// 主机接收器接收到最后一字节数据后,不发出应答信号 no ack
// 从机发送器释放SDA线,以允许主机发出P信号,停止传输;
while(!(I2C5.I2CCON & (1 && 4)));
// 等待传输结束
*data = I2C5.I2CDS;
I2C5.I2CSTAT = 0x90;
I2C5.I2CCON &= ~(1&&4);
/*clean interrupt pending bit
/**********************************************************************
iic write a byte program body
* @param[in] slave_addr, addr, data
**********************************************************************/
void iic_write (unsigned char slave_addr, unsigned char addr, unsigned char data)
I2C5.I2CDS = slave_
I2C5.I2CCON = (1 && 7)|(1 && 6)|(1 && 5) ;
I2C5.I2CSTAT = 0xf0;
while(!(I2C5.I2CCON & (1 && 4)));
I2C5.I2CDS =
I2C5.I2CCON = I2C5.I2CCON & (~(1 && 4));
while(!(I2C5.I2CCON & (1 && 4)));
I2C5.I2CDS =
I2C5.I2CCON = I2C5.I2CCON & (~(1 && 4));
while(!(I2C5.I2CCON & (1 && 4)));
I2C5.I2CSTAT = 0xd0;
I2C5.I2CCON = I2C5.I2CCON & (~(1 && 4));
mydelay_ms(10);
void MPU6050_Init ()
iic_write(SlaveAddress, PWR_MGMT_1, 0x00);
iic_write(SlaveAddress, SMPLRT_DIV, 0x07);
iic_write(SlaveAddress, CONFIG, 0x06);
iic_write(SlaveAddress, GYRO_CONFIG, 0x18);
iic_write(SlaveAddress, ACCEL_CONFIG, 0x01);
int get_data(unsigned char addr)
char data_h, data_l;
iic_read(SlaveAddress, addr, &data_h);
iic_read(SlaveAddress, addr+1, &data_l);
return (data_h&&8)|data_l;
裸机代码,不同于LINUX 应用层, 一定加循环控制
int main(void)
GPB.CON = (GPB.CON & ~(0xff&&8)) | 0x33&&8; // GPBCON[3], I2C_5_SCL GPBCON[2], I2C_5_SDA
mydelay_ms(100);
uart_init();
/*---------------------------------------------------------------------*/
I2C5.I2CSTAT = 0xD0;
I2C5.I2CCON &= ~(1&&4);
/*clean interrupt pending bit
/*---------------------------------------------------------------------*/
mydelay_ms(100);
MPU6050_Init();
mydelay_ms(100);
printf("\n********** I2C test!! ***********\n");
data = get_data(GYRO_ZOUT_H);
printf(" GYRO --& Z &---:Hex: %x", data);
data = get_data(GYRO_XOUT_H);
printf(" GYRO --& X &---:Hex: %x", data);
printf("\n");
mydelay_ms(1000);
实验结果如下:
********** I2C test!! ***********
GYRO --& Z &---:Hex: 1c GYRO --& X &---:Hex: feda
GYRO --& Z &---:Hex: fefc GYRO --& X &---:Hex: fed6
GYRO --& Z &---:Hex: fefe GYRO --& X &---:Hex: fed6
GYRO --& Z &---:Hex: fefe GYRO --& X &---:Hex: fedc
GYRO --& Z &---:Hex: fefe GYRO --& X &---:Hex: feda
GYRO --& Z &---:Hex: fefc GYRO --& X &---:Hex: fed6
GYRO --& Z &---:Hex: fefe GYRO --& X &---:Hex: feda
GYRO --& Z &---:Hex: fcf2 GYRO --& X &---:Hex: 202
GYRO --& Z &---:Hex: ec GYRO --& X &---:Hex: faa0
GYRO --& Z &---:Hex: 4c GYRO --& X &---:Hex: e
GYRO --& Z &---:Hex: fe GYRO --& X &---:Hex: fed8
GYRO --& Z &---:Hex: 0 GYRO --& X &---:Hex: fede
GYRO --& Z &---:Hex: 0 GYRO --& X &---:Hex: feda
Exynos4412启动过程分析
Exynos4412 所用外存 —— eMMC
Exynos4412裸机开发——中断处理
4412裸机开发
没有更多推荐了,}

我要回帖

更多关于 依玲服饰6050 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信