nRF52实践:BLE下mpu6050驱动

·  阅读 41

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第29天,点击查看活动详情

本文介绍在 BLE 协议栈下如何读写mpu6050。

接口介绍

mpu 6050 使用 twi 接口。该接口有多种实现API。twi_master_transfernrf_drv_twi_tx

在SDK目录components\drivers_ext\mpu6050中有对应驱动的实现。

寄存器

寄存器说明可参考文章MPU6050寄存器介绍。 本节简单罗列出寄存器,重要的稍加说明。

陀螺仪采样率分频寄存器(0X19)

1.png

配置寄存器(0X1A)

2.png

低3字节的DLPF(低通滤波器)表示。

陀螺仪配置寄存器(0X1B)

3.png

FS_SEL(Bit3~Bit4)决定了陀螺仪的量程。一般使用2000度/秒(正负),对应的值为3。由于ADC为16比特,因此灵敏度为65536/4000=16.384度/秒(LSB)。

加速度传感器配置寄存器(0X1C)

4.png

和陀螺仪类似,AFS_SEL(Bit3~Bit4)决定了加速度的量程。一般设置为2g(正负),对应的值为0。由于ADC为16比特,因此灵敏度为65536/4=16384LSB/g。

FIFO使能寄存器(0X23)

5.png

加速度传感器数据输出寄存器(0X3B~0X40)

6.png

加速度数据共6个寄存器,分别输出X、Y、Z轴的加速度值,高字节在前,低字节在后,读取时需要注意。

温度传感器数据输出寄存器(0X41~0X42)

7.png

温度数据共2个寄存器,分别为高字节和低字节,读取时要使用附带的公式进行转换,否则数据不正确。

陀螺仪数据输出寄存器(0X43~0X48)

8.png

和加速度数据类似,陀螺仪也为6个寄存器,分别输出X、Y、Z轴的值,高字节在前,低字节在后,读取时需要注意。

电源管理寄存器1(0X6B)

9.png

电源管理寄存器2(0X6C)

10.png

数值转换

加速度计换算:

假定加速度计量程为-2~+2。数字-32767对应-2g,32767对应2g。把32767除以2,得到16384, 即为灵敏度。将读到的数值除以16384,可得到加速度的数值。如读到的数值为1000,则对应的加速度数据是1000/16384=0.061g。g为加速度的单位(1g等于9.8米每平方秒)。在水平静止时,Z轴的加速度为1g(对应数值为16384),X、Y轴为0。

加速度计换算:

假定陀螺仪角速度量程为-2000~+2000。MPU6050输出数据为16位带符号数,数据类型为int16,范围为-32767~32767。最小值-32767对应-2000度/秒,32767对应2000度/秒。用32767除以2000,就可以得到16.40, 其即为灵敏度。因此,把陀螺仪数值除以16.40,即得到对应的角速度数值。如读到的数值为1000,则对应的角速度为1000/16.40=61度每秒。在一些姿态计算中,需要将角度值换算成弧度值。360度对应弧度是2Pi,则1度换算成弧度为:2Pi/360=(2*3.1415926)/360=0.0174532,用倒数表示就是:1/57.30。

小结:陀螺仪角速度量程为-2000~+2000范围时,可以通过下面的公式转换:

gyro_x/(16.40 * 57.30)=gyro_x * 0.001064   // gyro_x 为陀螺仪 X 轴原始数据
复制代码

接口实现

nRF52832 使用 TWI0 与 pmu6050 通信。

输出数据方面,使用结构体封装,将加速度、温度、陀螺仪数据一并读取,因为这些寄存器都是连接的。

初始化

MPU6050的总线地址如下:

  • AD0为低电平:0x68
  • AD0为高电平:0x69

板子上AD0连接的是低电平,因此地址为0x68。

初始化twi0:

​
static volatile bool m_xfer_done = false;
// TWI0
static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(0);
​
//TWI事件处理函数
void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context)
{
    //判断TWI事件类型
      switch (p_event->type)
    {
      case NRF_DRV_TWI_EVT_DONE:
          m_xfer_done = true;
          break;
      default:
          break;
    }
}
//TWI初始化
void twi_master_init(void)
{
    ret_code_t err_code;
    const nrf_drv_twi_config_t twi_config = {
       .scl                = TWI_SCL_M,
       .sda                = TWI_SDA_M,
       .frequency          = NRF_DRV_TWI_FREQ_100K,
       .interrupt_priority = APP_IRQ_PRIORITY_HIGH,
       .clear_bus_init     = false
    };
​
    err_code = nrf_drv_twi_init(&m_twi, &twi_config, twi_handler, NULL);
    APP_ERROR_CHECK(err_code);
    nrf_drv_twi_enable(&m_twi);
}
复制代码

imu寄存器读写及初始化:

bool mpu6050_register_write(uint8_t register_address, uint8_t value)
{
    ret_code_t err_code;
    uint8_t tx_buf[MPU6050_ADDRESS_LEN+1];
​
    tx_buf[0] = register_address;
    tx_buf[1] = value;
    m_xfer_done = false;
    err_code = nrf_drv_twi_tx(&m_twi, MPU6050_ADDRESS, tx_buf, MPU6050_ADDRESS_LEN+1, false);
    while (m_xfer_done == false) { }
      if (NRF_SUCCESS != err_code)
    {
        return false;
    }
        return true;    
}
​
bool mpu6050_register_read(uint8_t register_address, uint8_t * destination, uint8_t number_of_bytes)
{
    ret_code_t err_code;
​
    m_xfer_done = false;
    err_code = nrf_drv_twi_tx(&m_twi, MPU6050_ADDRESS, &register_address, 1, true);
    while (m_xfer_done == false) { }
    if (NRF_SUCCESS != err_code)
    {
        return false;
    }
​
    m_xfer_done = false;
    err_code = nrf_drv_twi_rx(&m_twi, MPU6050_ADDRESS, destination, number_of_bytes);
    while (m_xfer_done == false) { }
    if (NRF_SUCCESS != err_code)
    {
        return false;
    }
    return true;
}
​
bool mpu6050_verify_product_id(void)
{
    uint8_t who_am_i;
​
    if (mpu6050_register_read(ADDRESS_WHO_AM_I, &who_am_i, 1))
    {
        if (who_am_i != MPU6050_WHO_AM_I)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    else
    {
        return false;
    }
}
​
bool mpu6050_init(void)
{
    if(mpu6050_verify_product_id() == false)
    {
        return false;
    }
​
    //唤醒MPU6050
    (void)mpu6050_register_write(MPU_PWR_MGMT1_REG , 0x00); 
​
    (void)mpu6050_register_write(MPU_SAMPLE_RATE_REG, 0x07); //设置采样率 1KHz 
    (void)mpu6050_register_write(MPU_CFG_REG, 0x06); //设置低通滤波器,截止频率是1K,带宽是5K                            
    (void)mpu6050_register_write(MPU_INT_EN_REG, 0x00); //关闭中断    
    (void)mpu6050_register_write(MPU_GYRO_CFG_REG, 0x18); //陀螺仪自检及测量范围,不自检,2000deg/s
    (void)mpu6050_register_write(MPU_ACCEL_CFG_REG, 0x00); //加速度传感器量程 2G,不自检          
​
    return true;
}
复制代码

数据读取

结构体定义:

#pragma pack(push)
#pragma pack(1)
typedef struct imuinfo_tt {
  int16_t acc_x;
  int16_t acc_y;
  int16_t acc_z;
  int16_t temp;
  int16_t gyro_x;
  int16_t gyro_y;
  int16_t gyro_z;
} imuinfo_t;
​
typedef struct imuinfod_tt {
  double acc_x;
  double acc_y;
  double acc_z;
  double temp;
  double gyro_x;
  double gyro_y;
  double gyro_z;
} imuinfod_t;
​
typedef struct imuangle_tt {
  double angle_x;
  double angle_y;
  double angle_z;
} imuangle_t;#pragma pack(pop)
​
int mpu6050_readraw(imuinfo_t* info)
{
    bool ret = false;
    // ret = mpu6050_register_read(MPU6050_ACC_OUT, (uint8_t *)&info, sizeof(imuinfo_t));
​
    uint8_t buf[14] = {0};
​
    ret = mpu6050_register_read(MPU6050_ACC_OUT, buf, sizeof(buf));
    if (ret == false) return -1;
​
    info->acc_x  = (buf[0] << 8) | buf[1];
    info->acc_y  = (buf[2] << 8) | buf[3];
    info->acc_z  = (buf[4] << 8) | buf[5];
    info->temp = (buf[6] << 8) | buf[7];
    info->gyro_x = (buf[8] << 8) | buf[9];
    info->gyro_y = (buf[10] << 8) | buf[11];
    info->gyro_z = (buf[12] << 8) | buf[13];
​
   return 0;
}
​
int mpu6050_readrawbuff(int16_t* info)
{
    bool ret = false;
​
    uint8_t buf[14] = {0};
    ret = mpu6050_register_read(MPU6050_ACC_OUT, (uint8_t*)&buf, sizeof(buf));
    if (ret == false) return -1;
​
    info[0] = (buf[0] << 8) | buf[1];
    info[1] = (buf[2] << 8) | buf[3];
    info[2] = (buf[4] << 8) | buf[5];
    info[3] = (buf[6] << 8) | buf[7];
    info[4] = (buf[8] << 8) | buf[9];
    info[5] = (buf[10] << 8) | buf[11];
    info[6] = (buf[12] << 8) | buf[13];
​
   return 0;
}
复制代码

注意,mpu6050_readrawbuff接口主要为了后续校准作准备。

分类:
后端
标签:
收藏成功!
已添加到「」, 点击更改