完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
这一次用iic简单的读取lsm303的加速度数据,对于中断等不做操作;一,硬件连接 如图的连接,I2C的两根信号都通过R6,R7上拉,通过这点可知与LSM303的通信波特率是400khz。 二,获取数据 1,使用最新的freedom-e-sdk,freedom-e-sdk GitHub仓库,最新的sdk支持iic和pwm库函数开发,而且提供freertos的模板例程。在此基础上开发iic十分方便。 2,首先初始化开发板的iic接口,并通过iic接口配置lsm303的寄存器,设置加速度计的工作模式和输出速率(reg1_a寄存器),这里我设置的是普通模式,输出速率为400hz: //reg1中是reg1_a寄存器的地址及写入的值 char reg1[2]={0x20,0x77}; //初始化iic为master 波特率400khz metal_i2c_init(i2c, I2C_BAUDRATE, METAL_I2C_MASTER); //写控制寄存器reg1_A 普通模式,400hz输出,使能x,y,z轴加速度计 metal_i2c_write(i2c, ACCELEROMETER_I2C_ADDR, 2,reg1 , METAL_I2C_STOP_ENABLE); 然后创建一个定时时间为dt的任务,在这个任务里,我们读取lsm303加速度的输出寄存器的高位数据,比较对精度要求不高的话可以忽略低位数据。然后将数据进行积分处理得到速度和路程。这个项目里我不需要y轴数据所以没有读取。 /* * 由于普通模式有效数据10位,且数据为左对齐,只读取高位寄存器 * 将数据进行积分处理 */ static void prvAccelerTask(void *pvParameters) { TickType_t xNextWakeTime; char * pcMessage = "start accelertaskrn"; (void)pvParameters; //out_add中的值是加速度计OUT_X_H_A,OUT_Z_H_A寄存器的地址, static char out_addr[2]={0x29,0x2d},buff[2]={0}; //延时时间,同时也是时间的微分dt 单位是ms Motor.dt=20; xNextWakeTime = xTaskGetTickCount(); write(STDOUT_FILENO,pcMessage,strlen(pcMessage)); while(1) { //进入临界段,防止通信被打断 taskENTER_CRITICAL(); //分别读取OUT_X_H_A,OUT_Z_H_A高位寄存器 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对象 lsm303.acc_x_raw=buff[0]; lsm303.acc_z_raw=buff[1]; //对原生数据处理,转化成加速度,速度,位移 sensor_data_process(); taskEXIT_CRITICAL(); write(1,pcMessage,strlen(pcMessage)); vTaskDelayUntil( &xNextWakeTime, pdMS_TO_TICKS( Motor.dt ) ); } } 这就是配置的寄存器; 我设置的是400hz,所以代码里写入的值是0x77,其实也不必太高,过高会影响精度。 以下是不同模式下,输出数据的有效位数,普通模式下,输出10位数据,再看看输出寄存器的描述,大概的意思就是输出的数据是左对齐的二进制补码。那就在处理数据时要解析出原码。至于不了解左对齐是什么的可以点我。 三,处理数据 上面得到的数据是原始的,原生态无污染的,要加工成加速度数据,也就是单位为m/s^2的数据。要计算实际的加速度,需要乘以一个比例系数,在开发文档称为灵敏度,灵敏度与加速度计工作模式与full scal(缩放)有关,缩放的配置在reg4_a寄存器,默认是0,也就是±2g。所以可知我配置的灵敏度为3.9mg。详细如下图: 因为板子是倾斜约45°放的,所以要得到水平的加速度需要经过直角坐标转换。 lsm303.acc_x_real=(int)lsm303.acc_x_raw*4*39;乘4是因为普通模式输出10位数据,而我只读了高八位,舍弃了低二位,所以要左移2位,也就是乘4,39就是灵敏度。经过单位换算,得到的加速度单位是100ug /* * 处理lsm303读取的数据,获取速度,距离 */ void sensor_data_process() { //如果raw是负数的话需要取绝对值,乘以灵敏度,再将符号返回 if(lsm303.acc_x_raw&0x80) { lsm303.acc_x_raw =-lsm303.acc_x_raw; lsm303.acc_x_real=(int)lsm303.acc_x_raw*4*39; lsm303.acc_x_real=-lsm303.acc_x_real; } else lsm303.acc_x_real=(int)lsm303.acc_x_raw*4*39; if(lsm303.acc_z_raw&0x80) { lsm303.acc_z_raw =-lsm303.acc_z_raw; lsm303.acc_z_real=(int)lsm303.acc_z_raw*4*39; lsm303.acc_z_real=-lsm303.acc_z_real; } else lsm303.acc_z_real=(int)lsm303.acc_z_raw*4*39; //x=8112 z=-6552 滤除重力 lsm303.acc_x_filter=lsm303.acc_x_real-8112; lsm303.acc_z_filter=6552+lsm303.acc_z_real; //lsm303.acc_x_filter=lsm303.acc_x_filter & ~0x000000ff; //lsm303.acc_z_filter=lsm303.acc_z_filter & ~0x000000ff; //加速度分解到水平方向 sinθ=2/3 cosθ=3/4 Motor.acc=(lsm303.acc_x_filter*2/3+lsm303.acc_z_filter*3/4)/100;//cm/s^2 //加速度,速度积分 Motor.speed=Motor.speed+Motor.acc*Motor.dt/100;//mm Motor.distance=Motor.distance+Motor.speed*Motor.dt/100;//0.1mm } 三,小结 这种简单粗暴的用加速度双重积分出距离其实非常不准确,积分误差会随时间而增加,需要其他方式进行校准。 |
|
|
|
只有小组成员才能发言,加入小组>>
3272 浏览 9 评论
2948 浏览 16 评论
3449 浏览 1 评论
8969 浏览 16 评论
4042 浏览 18 评论
1085浏览 3评论
563浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
557浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2295浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1850浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-13 21:10 , Processed in 1.044386 second(s), Total 50, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号