LSM303AGR姿态传感器 risc-v Sifive learn inventor基础之硬件i2c与LSM303AGR通信

目录

  1. Sifive Learn Inventor 基础之gpio 按键中断
  2. Sifive learn inventor基础之串口&操作寄存器
  3. Sifive learn inventor基础之硬件pwm&寄存器
  4. risc-v Sifive learn inventor基础之硬件i2c与LSM303AGR通信

这一次用iic简单的读取lsm303的加速度数据,对于中断等不做操作;

一,硬件连接

如图的连接,I2C的两根信号都通过R6,R7上拉,通过这点可知与LSM303的通信波特率是400khz。
在这里插入图片描述

二,获取数据

1,使用最新的freedom-e-sdk,freedom-e-sdk GitHub仓库,最新的sdk支持iic和pwm库函数开发,而且提供freertos的模板例程。在此基础上开发iic十分方便。
2,先搞到一个可以每1秒打印字符串的任务,表示rtos正在运行,然后创建读取lsm303的任务,在任务里我们先初始化iic接口,设置加速度计的工作模式和输出速率,这里我设置的是普通模式,输出速率为400hz。

/*
 * out_addr 是加速度计x,z轴高位输出寄存器
 * buff用来缓存读取的数据
 * reg1的第一元素是reg1_a寄存器的地址,该寄存器配置工作模式,输出速率;第二个元素是写入寄存器的值
 */
static void prvAccelerTask(void *pvParameters)
{
	TickType_t xNextWakeTime;
	const char * const pcMessage = "ACCELER\r\n";
	(void)pvParameters;

	static unsigned char out_addr[2]={0x29,0x2d},buff[2]={0},reg1[2]={0x20,0x77};
	//延时时间,同时也是时间的微分
	Motor.dt=200;
	xNextWakeTime = xTaskGetTickCount();
	metal_i2c_init(i2c, I2C_BAUDRATE, METAL_I2C_MASTER);
	//配置为普通模式,400hz输出,使能x,y,z
	metal_i2c_write(i2c, ACCELEROMETER_I2C_ADDR, 2,reg1 , METAL_I2C_STOP_ENABLE);
	while(1){
		write(STDOUT_FILENO,pcMessage,strlen(pcMessage));
		taskENTER_CRITICAL();
		metal_i2c_write(i2c, ACCELEROMETER_I2C_ADDR, 1,out_addr , METAL_I2C_STOP_DISABLE);
		metal_i2c_read(i2c, ACCELEROMETER_I2C_ADDR, 1,buff , METAL_I2C_STOP_ENABLE);
		metal_i2c_write(i2c, ACCELEROMETER_I2C_ADDR, 1,&out_addr[1] , METAL_I2C_STOP_DISABLE);
		metal_i2c_read(i2c, ACCELEROMETER_I2C_ADDR, 1,&buff[1] , METAL_I2C_STOP_ENABLE);
		lsm303.acc_x_raw=buff[0];
		lsm303.acc_z_raw=buff[1];
		//对原生数据处理,转化成加速度,速度,位移
		sensor_data_process();
		taskEXIT_CRITICAL();
		vTaskDelayUntil( &xNextWakeTime, pdMS_TO_TICKS( Motor.dt ) );
	}
}

这就是配置的寄存器;
在这里插入图片描述
我设置的是400hz,所以代码里写入的值是0x77,其实也不必太高,过高会影响精度。
在这里插入图片描述
以下是不同模式下,输出数据的有效位数,普通模式下,输出10位数据,再看看输出寄存器的描述,大概的意思就是输出的数据是左对齐的二进制补码。那就在处理数据时要解析出原码。至于不了解左对齐是什么的可以点我。
在这里插入图片描述
在这里插入图片描述

三,处理数据

上面得到的数据是原始的,原生态无污染的,要转化成加速度数据,也就是单位为g的数据。首先需要解得二进制数据的原码,这时候还要乘上一个比例系数文档称为灵敏度的数据,才能表示真实的加速度数据。灵敏度与加速度计工作模式与full scal(缩放)有关,缩放的配置在reg4_a寄存器,默认是0,也就是±2g。所以可知我配置的灵敏度为3.9mg。
在这里插入图片描述
在这里插入图片描述
**因为板子是倾斜约45°放的,所以我的加速度需要经过直角坐标的转换才能得到水平的加速度。这里Motor.acc=(temp[0]0.66+temp[1]0.75)43900;得到的就是真实加速度数据,单位是ug,乘4是因为普通模式输出10位数据,而我只读了高八位,舍弃了低二位,所以要乘2^2,3900就是灵敏度。

void sensor_data_process()
{
	unsigned char temp[2]={0};
	//获取原码数据
	if(lsm303.acc_x_raw>>7){
		temp[0]=(~lsm303.acc_x_raw);
		temp[0]|=(1<<7);
	}
	else {
		temp[0]=(~lsm303.acc_x_raw);
		temp[0]&=~(1<<7);
	}
	if(lsm303.acc_z_raw>>7){
		temp[1]=(~lsm303.acc_z_raw);
		temp[1]|=(1<<7);
	}
	else {
		temp[1]=(~lsm303.acc_z_raw);
		temp[1]&=~(1<<7);
	}
	lsm303.acc_x_comple=temp[0];
	lsm303.acc_z_comple=temp[1];
	//剔除重力分量的影响,77和-87分别是静止状态下的x,z输出
	temp[0]=77-temp[0];
	temp[1]=-(87+temp[1]);
	//滤掉微小的抖动
	temp[0]&=~0x07;
	temp[1]&=~0x07;

	lsm303.acc_x_filter=temp[0];
	lsm303.acc_z_filter=temp[1];

	//乘以三角系数得到水平方向的加速度
	//sinθ=0.66 cosθ=0.75
	Motor.acc=(temp[0]*0.66+temp[1]*0.75)*4*3900;//ug
	//加速度积分
	Motor.speed+=Motor.acc*Motor.dt;
	//速度积分
	Motor.distance+=Motor.speed*Motor.dt;
}

三,小结

这种简单粗暴的用加速度双重积分出距离其实非常不准确,积分误差会随时间而增加,需要其他方式进行校准。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44821644/article/details/106796337