??本周主要工作是在项目上,抽空做了一个跟本课题相关的电路板,之前用开发板来做测试,MPU6050和QMC5883L都是用杜邦线连接的,导致接线很乱,也不美观,当然也不符合“捷联”的定义。
??下面是电路的原理图和PCB,因为已经购买了MPU6050和QMC5883L模块,所以直接使用这些模块来做,不再设计外围电路(不是懒,主要是这个电路板做测试使用,后续做课题看不会用这中比较low的MEMS传感器)。
??本次设计的电路有以下几个特点:
??下面是相关的部分代码:
??ICM20602的代码可参考博客:STM32Cube高效开发教程<基础篇>(十四)----SPI通信及ICM20602软件开发,本博客后续的资源链接中也会包含ICM20602的代码。
??MPU6050.c:
#include "mpu6050.h"
#include "stm32f1xx_hal.h"
uint8_t addressMPU6050;
int16_t adcAccel_MPU6050[3]={0},adcGyro_MPU6050[3]={0};
//初始化MPU6050
//返回值:0,成功
// 其他,错误代码
uint8_t MPU_Init(void)
{
// MPU_IIC_Init();//初始化IIC总线
MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80); //复位MPU6050
HAL_Delay(100);
MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00); //唤醒MPU6050
MPU_Set_Gyro_Fsr(3); //陀螺仪传感器,±2000dps
MPU_Set_Accel_Fsr(0); //加速度传感器,±2g
MPU_Set_Rate(50); //设置采样率50Hz
MPU_Write_Byte(MPU_INT_EN_REG,0X00); //关闭所有中断
MPU_Write_Byte(MPU_USER_CTRL_REG,0X00); //I2C主模式关闭
MPU_Write_Byte(MPU_FIFO_EN_REG,0X00); //关闭FIFO
MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80); //INT引脚低电平有效
addressMPU6050=MPU_Read_Byte(MPU_DEVICE_ID_REG);
if(addressMPU6050==MPU_ADDR)//器件ID正确
{
MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01); //设置CLKSEL,PLL X轴为参考
MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00); //加速度与陀螺仪都工作
MPU_Set_Rate(50); //设置采样率为50Hz
}else return 1;
// MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01); //设置CLKSEL,PLL X轴为参考
// MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00); //加速度与陀螺仪都工作
// MPU_Set_Rate(50); //设置采样率为50Hz
MPU_IIC_SCL_HIG;
MPU_IIC_SDA_HIG;
return 0;
}
//设置MPU6050陀螺仪传感器满量程范围
//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
//返回值:0,设置成功
// 其他,设置失败
uint8_t MPU_Set_Gyro_Fsr(uint8_t fsr)
{
return MPU_Write_Byte(MPU_GYRO_CFG_REG,fsr<<3);//设置陀螺仪满量程范围
}
//设置MPU6050加速度传感器满量程范围
//fsr:0,±2g;1,±4g;2,±8g;3,±16g
//返回值:0,设置成功
// 其他,设置失败
uint8_t MPU_Set_Accel_Fsr(uint8_t fsr)
{
return MPU_Write_Byte(MPU_ACCEL_CFG_REG,fsr<<3);//设置加速度传感器满量程范围
}
//设置MPU6050的数字低通滤波器
//lpf:数字低通滤波频率(Hz)
//返回值:0,设置成功
// 其他,设置失败
uint8_t MPU_Set_LPF(uint16_t lpf)
{
uint8_t data=0;
if(lpf>=188)data=1;
else if(lpf>=98)data=2;
else if(lpf>=42)data=3;
else if(lpf>=20)data=4;
else if(lpf>=10)data=5;
else data=6;
return MPU_Write_Byte(MPU_CFG_REG,data);//设置数字低通滤波器
}
//设置MPU6050的采样率(假定Fs=1KHz)
//rate:4~1000(Hz)
//返回值:0,设置成功
// 其他,设置失败
uint8_t MPU_Set_Rate(uint16_t rate)
{
uint8_t data;
if(rate>1000)rate=1000;
if(rate<4)rate=4;
data=1000/rate-1;
data=MPU_Write_Byte(MPU_SAMPLE_RATE_REG,data); //设置数字低通滤波器
return MPU_Set_LPF(rate/2); //自动设置LPF为采样率的一半
}
//得到温度值
//返回值:温度值(扩大了100倍)
short MPU_Get_Temperature(void)
{
uint8_t buf[2];
short raw;
float temp;
MPU_Read_Len(MPU_ADDR,MPU_TEMP_OUTH_REG,2,buf);
raw=((uint16_t)buf[0]<<8)|buf[1];
temp=36.53+((double)raw)/340;
return temp*100;;
}
//得到陀螺仪值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
// 其他,错误代码
uint8_t MPU_Get_Gyroscope(short *gx,short *gy,short *gz)
{
uint8_t buf[6],res;
res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
if(res==0)
{
*gx=((uint16_t)buf[0]<<8)|buf[1];
*gy=((uint16_t)buf[2]<<8)|buf[3];
*gz=((uint16_t)buf[4]<<8)|buf[5];
adcGyro_MPU6050[0]=(buf[0]<<8)|buf[1];
adcGyro_MPU6050[1]=(buf[2]<<8)|buf[3];
adcGyro_MPU6050[2]=(buf[4]<<8)|buf[5];
}
return res;;
}
//得到加速度值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
// 其他,错误代码
uint8_t MPU_Get_Accelerometer(short *ax,short *ay,short *az)
{
uint8_t buf[6],res;
res=MPU_Read_Len(MPU_ADDR,MPU_ACCEL_XOUTH_REG,6,buf);
if(res==0)
{
*ax=((uint16_t)buf[0]<<8)|buf[1];
*ay=((uint16_t)buf[2]<<8)|buf[3];
*az=((uint16_t)buf[4]<<8)|buf[5];
adcAccel_MPU6050[0]=(buf[0]<<8)|buf[1];
adcAccel_MPU6050[1]=(buf[2]<<8)|buf[3];
adcAccel_MPU6050[2]=(buf[4]<<8)|buf[5];
}
return res;
}
??QMC5883L.c
// 模拟IIC发送单字节时序
uint8_t QMC5883L_SendByte(uint8_t Sim_i2c_data)
{
uint8_t i;
SDA1_OUT();
QMC5883L_SCL_LOW;
for(i=0; i<8; i++)
{
if(Sim_i2c_data&0x80) QMC5883L_SDA_HIG;
else QMC5883L_SDA_LOW;
Sim_i2c_data<<=1;
QMC5883L_NOP;
QMC5883L_SCL_HIG;
QMC5883L_NOP;
QMC5883L_SCL_LOW;
QMC5883L_NOP;
}
return QMC5883L_READY;
}
// 模拟IIC发送单字节时序
uint8_t QMC5883L_ReceiveByte(void)
{
uint8_t i,Sim_i2c_data;
SDA1_IN();
//QMC5883L_SDA_HIG;
// QMC5883L_SCL_LOW;
Sim_i2c_data=0;
for(i=0; i<8; i++)
{
QMC5883L_SCL_LOW;
QMC5883L_NOP;
QMC5883L_SCL_HIG;
// QMC5883L_NOP;
Sim_i2c_data<<=1;
SDA_Pin_State = QMC5883L_SDA_STATE;
if(QMC5883L_SDA_STATE) Sim_i2c_data|=0x01;
// QMC5883L_SCL_LOW;
QMC5883L_NOP;
}
QMC5883L_SendNACK();
return Sim_i2c_data;
}
// 模拟IIC读单字节,带应答
uint8_t QMC5883L_ReceiveByte_WithACK(void)
{
uint8_t i,Sim_i2c_data;
SDA1_IN();
//QMC5883L_SDA_HIG;
// QMC5883L_SCL_LOW;
Sim_i2c_data=0;
for(i=0; i<8; i++)
{
QMC5883L_SCL_LOW;
QMC5883L_NOP;
QMC5883L_SCL_HIG;
// QMC5883L_NOP;
Sim_i2c_data<<=1;
if(QMC5883L_SDA_STATE) Sim_i2c_data|=0x01;
// QMC5883L_SCL_LOW;
QMC5883L_NOP;
}
QMC5883L_SendACK();
return Sim_i2c_data;
}
// 模拟IIC的多字节读
uint8_t QMC5883L_Read8(uint8_t moni_dev_addr, uint8_t moni_reg_addr, uint8_t moni_i2c_len, uint8_t *moni_i2c_data_buf)
{
QMC5883L_START();
QMC5883L_SendByte(moni_dev_addr << 1 | WRITE );
QMC5883L_Wait_Ack();
QMC5883L_SendByte(moni_reg_addr);
QMC5883L_Wait_Ack();
//QMC5883L_STOP();
QMC5883L_START();
QMC5883L_SendByte(moni_dev_addr <<1 | READ );
QMC5883L_Wait_Ack();
while (moni_i2c_len)
{
if (moni_i2c_len==1) *moni_i2c_data_buf =QMC5883L_ReceiveByte();
else *moni_i2c_data_buf =QMC5883L_ReceiveByte_WithACK();
moni_i2c_data_buf++;
moni_i2c_len--;
}
QMC5883L_STOP();
return 0x00;
}
// 模拟IIC的多字节写
int8_t QMC5883L_Write8(uint8_t moni_dev_addr, uint8_t moni_reg_addr, uint8_t moni_i2c_len, uint8_t *moni_i2c_data_buf)
{
uint8_t i;
QMC5883L_START();
QMC5883L_SendByte(moni_dev_addr << 1 | WRITE); // 写指令
QMC5883L_Wait_Ack();
QMC5883L_SendByte(moni_reg_addr);
QMC5883L_Wait_Ack();
//QMC5883L_START();
for (i=0; i<moni_i2c_len; i++)
{
QMC5883L_SendByte(moni_i2c_data_buf[i]);
QMC5883L_Wait_Ack();
}
QMC5883L_STOP();
return 0;
}
uint8_t highByte(uint16_t value)
{
uint8_t ret;
value = value>>8;
ret = (uint8_t)value;
return ret;
}
uint8_t lowByte(uint16_t value)
{
uint8_t ret;
value = value&0x00ff;
ret = (uint8_t)value;
return ret;
}
// 读一个字节
uint8_t readOneByte(uint8_t in_adr)
{
uint8_t retVal = -1;
QMC5883L_Read8(QMC5883L_ADDR,in_adr,1,&retVal);
QMC5883L_NOP;
return retVal;
}
// 读两个字节
uint16_t readTwoBytes(uint8_t in_adr_hi, uint8_t in_adr_lo)
{
uint16_t retVal = -1;
uint8_t low=0,high=0;
/* Read Low Byte */
low = readOneByte(in_adr_lo);
/* Read High Byte */
high = readOneByte(in_adr_hi);
//printf("high:%d,low:%d ",high,low);
retVal = high << 8;
retVal = retVal | low;
//printf("retVal:%d\r\n",retVal);
return retVal;
}
// 写一个字节
void writeOneByte(uint8_t adr_in, uint8_t dat_in)
{
uint8_t dat = dat_in;
QMC5883L_Write8(QMC5883L_ADDR,adr_in,1,&dat);
}
// 获取地址
int16_t getAddress()
{
return QMC5883L_ADDR;
}
//************************写入单字节数据***************************
//初始化QMC5883,根据需要请参考pdf进行修改****
void Init_QMC5883()
{
uint8_t addrVale;
addrVale = 0x1D;
QMC5883L_Write8(QMC5883L_ADDR,CONTROL_REG_1,1,&addrVale); //控制寄存器配置
addrVale = 0x01;
QMC5883L_Write8(QMC5883L_ADDR,SET_RESET_REG,1,&addrVale); //设置清除时间寄存器
}
void GetMagValue(void)
{
QMC5883L_Read8(QMC5883L_ADDR,XOUT_L,6,Buff);
MagnetRawAd[0] = ((int16_t)Buff[1] << 8) | Buff[0];
MagnetRawAd[1] = ((int16_t)Buff[3] << 8) | Buff[2];
MagnetRawAd[2] = ((int16_t)Buff[5] << 8) | Buff[4];
}
??QMC5883L.h
#ifndef __MD_AS5600_H
#define __MD_AS5600_H
#include "stm32f1xx_hal.h" //这个需要根据不同的芯片类型进行变换
#include "main.h"
// QMC地址
#define QMC5883L_ADDR 0x0D
// 三轴磁力计输出寄存器
#define XOUT_L 0x00
#define XOUT_H 0x01
#define YOUT_L 0x02
#define YOUT_H 0x03
#define ZOUT_L 0x04
#define ZOUT_H 0x05
// 状态寄存器
#define STATUS 0x06
// 温度输出寄存器
#define TEMP_L 0x07
#define TEMP_H 0x08
// 控制寄存器
#define CONTROL_REG_1 0x09
#define CONTROL_REG_2 0x0A
// SET/RESET,推荐写入0x01
#define SET_RESET_REG 0x0B
// 芯片ID号
#define CHIP_ID 0x0D
#define QMC5883L_SCL_LOW HAL_GPIO_WritePin(QMC_SCL_GPIO_Port,QMC_SCL_Pin,GPIO_PIN_RESET)
#define QMC5883L_SCL_HIG HAL_GPIO_WritePin(QMC_SCL_GPIO_Port,QMC_SCL_Pin,GPIO_PIN_SET)
#define QMC5883L_SDA_LOW HAL_GPIO_WritePin(QMC_SDA_GPIO_Port,QMC_SDA_Pin,GPIO_PIN_RESET)
#define QMC5883L_SDA_HIG HAL_GPIO_WritePin(QMC_SDA_GPIO_Port,QMC_SDA_Pin,GPIO_PIN_SET)
//#define Sim_I2C1_SDA_STATE (IIC_SDA_GPIO_Port->IDR &= (IIC_SDA_Pin))
#define QMC5883L_SDA_STATE (QMC_SDA_GPIO_Port->IDR &= (QMC_SDA_Pin))
//#define QMC5883L_SDA_STATE HAL_GPIO_ReadPin(QMC_SDA_GPIO_Port,QMC_SDA_Pin)
#define QMC5883L_DELAY QMC5883L_Delay(100000)
#define QMC5883L_NOP QMC5883L_Delay(1000) //25
#define QMC5883L_READY 0x00
#define QMC5883L_BUS_BUSY 0x01
#define QMC5883L_BUS_ERROR 0x02
#define QMC5883L_NACK 0x00
#define QMC5883L_ACK 0x01
#define SDA_Pin_Num 1
#define WRITE 0x00
#define READ 0x01
extern uint16_t rawdata;
extern float degress ;
extern int16_t MagnetRawAd[3]; // 磁力计数据
void SDA1_IN ( void );
void SDA1_OUT ( void );
void QMC5883L_Delay(uint32_t delay);
uint8_t QMC5883L_START(void);
void QMC5883L_STOP(void);
unsigned char QMC5883L_Wait_Ack(void);
void QMC5883L_SendACK(void);
void QMC5883L_SendNACK(void);
uint8_t QMC5883L_SendByte(uint8_t Sim_i2c_data);
uint8_t QMC5883L_ReceiveByte(void);
uint8_t QMC5883L_ReceiveByte_WithACK(void);
uint8_t QMC5883L_Read8(uint8_t moni_dev_addr, uint8_t moni_reg_addr, uint8_t moni_i2c_len, uint8_t *moni_i2c_data_buf);
int8_t QMC5883L_Write8(uint8_t moni_dev_addr, uint8_t moni_reg_addr, uint8_t moni_i2c_len, uint8_t *moni_i2c_data_buf);
uint8_t highByte(uint16_t value);
uint8_t lowByte(uint16_t value);
uint8_t readOneByte(uint8_t in_adr);
uint16_t readTwoBytes(uint8_t in_adr_hi, uint8_t in_adr_lo);
void writeOneByte(uint8_t adr_in, uint8_t dat_in);
int16_t getAddress();
void Init_QMC5883();
void GetMagValue(void);
#endif
??有关QMC5883L芯片会在假期之后更新一篇,讲解IIC通信以及该芯片,后续会补充上链接。
??资源正在审核中,后续会放上链接…
课题学习(一)----静态测量
课题学习(二)----倾角和方位角的动态测量方法(基于磁场的测量系统)
课题学习(三)----倾角和方位角的动态测量方法(基于陀螺仪的测量系统)
课题学习(四)----四元数解法
课题学习(五)----阅读论文《抗差自适应滤波的导向钻具动态姿态测量方法》
课题学习(六)----安装误差校准、实验方法
课题学习(七)----粘滑运动的动态算法
课题学习(八)----卡尔曼滤波动态求解倾角、方位角
课题学习(九)----阅读《导向钻井工具姿态动态测量的自适应滤波方法》论文笔记
课题学习(十)----阅读《基于数据融合的近钻头井眼轨迹参数动态测量方法》论文笔记
课题学习(十一)----阅读《Attitude Determination with Magnetometers and Accelerometers to Use in Satellite》
课题学习(十二)----阅读《Extension of a Two-Step Calibration Methodology to Include Nonorthogonal Sensor Axes》
课题学习(十三)----阅读《Calibration of Strapdown Magnetometers in Magnetic Field Domain》论文笔记
课题学习(十四)----三轴加速度计+三轴陀螺仪传感器-ICM20602
课题学习(十五)----阅读《测斜仪旋转姿态测量信号处理方法》论文
课题学习(十六)----阅读《Continuous Wellbore Surveying While Drilling Utilizing MEMS Gyroscopes Based…》论文
课题学习(十七)----姿态更新的四元数算法总结