关于mpu6050六轴传感器例程中一些位操作

2 篇文章 1 订阅
1 篇文章 0 订阅

起因

最近在学习stm32开发板,最近学习到了需要IIC通信MPU6050六轴传感器,看了正点原子的例程,发现其中有很多位操作不是很理解。经过补习了一番C语言,总结了一些位操作的知识。

接下来直接贴代码+讲解操作

1.

void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
	SDA_OUT(); 	    
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1; 	  
		delay_us(2);   //对TEA5767这三个延时都是必须的
		IIC_SCL=1;
		delay_us(2); 
		IIC_SCL=0;	
		delay_us(2);
    }	 
} 	    

首先让我们看一下这个函数,里面多次用到了IIC_SDA=(txd&0x80)>>7; 这个方法,0x80实际上就是二进制的10000000,txd&0x80就是取txd低八位的最高位(如果不能理解就先向下看), 此时的“>>7”是将结果右移七位,若txd = 10010110, 那么结果就是 00000001;这里的操作是取变量txd的最高位,然后通过循环将txd的值赋给IIC_SDA。因为IIC通信是从最高位开始读取,所以要进行这样一部操作。

2.

u8 IIC_Read_Byte(unsigned char ack)
{
	unsigned char i,receive=0;
	SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
	{
        IIC_SCL=0; 
        delay_us(2);
		IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
		delay_us(1); 
    }					 
    if (!ack)
        IIC_NAck();//发送nACK
    else
        
		IIC_Ack(); //发送ACK   
    return receive;
}

这个函数应该比较好理解
receive<<=1;
if(READ_SDA)receive++;
READ_SDA是在IO上直接读取到的数据0/1
如果SDA = 1 的话,receive则会+1,反之则不操作,相当于对最低位进行赋值。
之后再将receive左移一位,达成逐位赋值的效果。

3.

u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{ 
 	IIC_Start(); 
	IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令	
	if(IIC_Wait_Ack())	//等待应答
	{
		IIC_Stop();		 
		return 1;		
	}
    IIC_Send_Byte(reg);	//写寄存器地址
    IIC_Wait_Ack();		//等待应答
    IIC_Start();
	IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令	
    IIC_Wait_Ack();		//等待应答 
	while(len)
	{
		if(len==1)*buf=IIC_Read_Byte(0);//读数据,发送nACK 
		else *buf=IIC_Read_Byte(1);		//读数据,发送ACK  
		len--;
		buf++; 
	}    
    IIC_Stop();	//产生一个停止条件 
	return 0;	
}

首先看IIC_Send_Byte((addr<<1)|0); 这句,因为寄存器内最低位为设置读/写,所以要将addr左移一位并对最低位赋值 x|0x|1

在这里我要说一下这个指针 *buf

u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz) 
{
    u8 buf[6],res;  
	res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
	if(res==0)
	{
		*gx=((u16)buf[0]<<8)|buf[1];  
		*gy=((u16)buf[2]<<8)|buf[3];  
		*gz=((u16)buf[4]<<8)|buf[5];
	} 	
    return res;;
}

例程中调用的时候是这么写的

res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);

首先为什么len的入口参数为6,因为我们读取了三个数据,gx,gy,gy,
由于每一个都是16位,所以要分高低位分别读取,所以len为6。
其次
*gx=((u16)buf[0]<<8)|buf[1];
*gy=((u16)buf[2]<<8)|buf[3];
*gz=((u16)buf[4]<<8)|buf[5];
为什么这么写
在read_len函数中我们将所有的值都赋给了 *buf这个指针,正确来讲是赋给了 *buf指针所指的内存区域,
*buf每+1就会指向距离现在位置8byte距离的下一个内存区域,(u8 *buf)
所以进行上述操作,就可以将read到的每一个8byte大小的数据,通过指针 *buf 从内存空间依次获取,重新组装,从而得到我们需要的u16大小的gx,gy,gz的值了。

4.

void usart1_report_imu(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz,short roll,short pitch,short yaw)
{
	u8 tbuf[28]; 
	u8 i;
	for(i=0;i<28;i++)tbuf[i]=0;//清0
	tbuf[0]=(aacx>>8)&0XFF;
	tbuf[1]=aacx&0XFF;
	tbuf[2]=(aacy>>8)&0XFF;
	tbuf[3]=aacy&0XFF;
	tbuf[4]=(aacz>>8)&0XFF;
	tbuf[5]=aacz&0XFF; 
	tbuf[6]=(gyrox>>8)&0XFF;
	tbuf[7]=gyrox&0XFF;
	tbuf[8]=(gyroy>>8)&0XFF;
	tbuf[9]=gyroy&0XFF;
	tbuf[10]=(gyroz>>8)&0XFF;
	tbuf[11]=gyroz&0XFF;	
	tbuf[18]=(roll>>8)&0XFF;
	tbuf[19]=roll&0XFF;
	tbuf[20]=(pitch>>8)&0XFF;
	tbuf[21]=pitch&0XFF;
	tbuf[22]=(yaw>>8)&0XFF;
	tbuf[23]=yaw&0XFF;
	usart1_niming_report(0XAF,tbuf,28);//飞控显示帧,0XAF
} 

最后是这个函数,里面有这样一个操作:

tbuf[0]=(aacx>>8)&0XFF;
tbuf[1]=aacx&0XFF;

这里tbuf[0]为高八位,tbuf[1]为第八位, 以此类推。
这里我要说一下为什么要 &0XFF,(&11111111);
accy等变量都是16位数据,而对一个变量进行&0xFF操作就是取它的低八位
让一个16位的变量最终返回的值为一个八位数据
之前的IIC_SDA=(txd&0x80)>>7; 也有着异曲同工之处,

至此就是我对例程中的一些奇葩操作的理解了。

  • 10
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MPU6050是一种六轴传感器,它包含三轴的加速度传感器和三轴的陀螺仪(角速度传感器)。它可以用于测量物体的加速度和角速度,常用于姿态测量、运动控制和导航等应用领域。 以下是使用MPU6050六轴传感器的示例代码: ```python import smbus import math # MPU6050的I2C地址 MPU6050_ADDR = 0x68 # 加速度计的灵敏度范围 ACCEL_RANGE_2G = 0x00 ACCEL_RANGE_4G = 0x08 ACCEL_RANGE_8G = 0x10 ACCEL_RANGE_16G = 0x18 # 陀螺仪的灵敏度范围 GYRO_RANGE_250DEG = 0x00 GYRO_RANGE_500DEG = 0x08 GYRO_RANGE_1000DEG = 0x10 GYRO_RANGE_2000DEG = 0x18 # 初始化I2C总线 bus = smbus.SMBus(1) # 设置加速度计和陀螺仪的灵敏度范围 bus.write_byte_data(MPU6050_ADDR, 0x1C, ACCEL_RANGE_2G) bus.write_byte_data(MPU6050_ADDR, 0x1B, GYRO_RANGE_250DEG) # 读取加速度计和陀螺仪的原始数据 accel_x = bus.read_word_data(MPU6050_ADDR, 0x3B) accel_y = bus.read_word_data(MPU6050_ADDR, 0x3D) accel_z = bus.read_word_data(MPU6050_ADDR, 0x3F) gyro_x = bus.read_word_data(MPU6050_ADDR, 0x43) gyro_y = bus.read_word_data(MPU6050_ADDR, 0x45) gyro_z = bus.read_word_data(MPU6050_ADDR, 0x47) # 将原始数据转换为加速度和角速度的物理值 accel_scale = 16384.0 # 加速度计的比例因子 gyro_scale = 131.0 # 陀螺仪的比例因子 accel_x = accel_x / accel_scale accel_y = accel_y / accel_scale accel_z = accel_z / accel_scale gyro_x = gyro_x / gyro_scale gyro_y = gyro_y / gyro_scale gyro_z = gyro_z / gyro_scale # 计算加速度的合成值 accel = math.sqrt(accel_x**2 + accel_y**2 + accel_z**2) # 计算陀螺仪的合成值 gyro = math.sqrt(gyro_x**2 + gyro_y**2 + gyro_z**2) # 打印结果 print("加速度:", accel) print("角速度:", gyro) ``` 这段代码使用Python的smbus库通过I2C总线与MPU6050进行通信,读取加速度计和陀螺仪的原始数据,并将其转换为物理值。最后打印出加速度和角速度的合成值。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值