废话,可以跳过

前段时间买了一个GY87_10轴陀螺仪模块,就是这个货

read-normal-img

刚开始以为这个模块也就是把三个传感器集成在了一起, 结果买回来才发现QMC5883L是连接在MPU6050的备用iic上, 并不能直接使用,要先把备用iic连接到主iic上, 就是这样

read-normal-img

这就引发了一个问题,我比较喜欢用dmp解算,因为6050自带的dmp航向角几乎很少偏移,就算一直转圈圈,偏移得也很少, 可dmp需要独占iic总线(dmp-mpu6050内部), 也就是两个只能二选一, 自己用融合算法之类的,都打不到dmp的效果,(不借助磁力计的情况下,yaw偏差都很大),所以才买了GY-95T九轴传感器

正文

买模块自带的arduino程序并不能用在esp32上,表面上看起来就只有串口初始化的差异,实际上坑有点多,比如温度一直不准, 自己照着说明书写的一个程序,花了我一晚上

废话不多说,上代码  硬件连接是10,和11 这个用的是串口直接输出数据

#include <Arduino.h>

typedef struct
{
  int16_t roll;
  int16_t pitch;
  int16_t yaw;
  uint8_t leve;
  int16_t temp;
} gy;

// 定义 UART 对象,这里使用 UART2
HardwareSerial mySerial(2);
byte add = 0xa4;
byte len = 0, start_reg = 0;
unsigned char Re_buf[35], counter = 0;
unsigned char sign = 0;
gy my_95Q;

// 计算校验和
byte calculateChecksum(unsigned char *data, int length)
{
  byte sum = 0;
  for (int i = 0; i < length; i++)
  {
    sum += data[i];
  }
  return sum & 0xFF;
}

// 发送写寄存器指令
void writeRegister(byte reg, byte value)
{
  unsigned char frame[5] = {add, 0x06, reg, value, 0};
  frame[4] = calculateChecksum(frame, 4);
  for (int i = 0; i < 5; i++)
  {
    mySerial.write(frame[i]);
  }
}

// 发送读寄存器指令
void readRegisters(byte startReg, byte numRegs)
{
  unsigned char frame[5] = {add, 0x03, startReg, numRegs, 0};
  frame[4] = calculateChecksum(frame, 4);
  for (int i = 0; i < 5; i++)
  {
    mySerial.write(frame[i]);
  }
}

// 计算相对于起始地址的偏移量
byte calculateOffset(byte startReg, byte targetReg)
{
  return targetReg - startReg;
}

void setup()
{
  Serial.begin(115200);
  mySerial.begin(115200, SERIAL_8N1, 10, 11); // rx tx

  // 设置输出模式为查询模式
  writeRegister(0x03, 1);
}

void loop()
{
  static unsigned long lastDataTime = millis();   // 记录上次接收到数据的时间
  static unsigned long lastPromptTime = millis(); // 记录上次显示提示信息的时间

  memset(&my_95Q, 0, sizeof(my_95Q)); // 初始化结构体

  // 可动态设置起始地址和寄存器数量->>>>>>>>> 要确保读取的数据包含需要的数据,否则会下标地址溢出
  byte newStartReg = 0x08; // 这里可以修改起始地址
  byte newNumRegs = 0x1B;  // 这里可以修改寄存器数量
  readRegisters(newStartReg, newNumRegs);

  if (mySerial.available() > 0)
  {
    lastDataTime = millis(); // 更新上次接收到数据的时间
    unsigned char i = 0, sum = 0;
    while (mySerial.available())
    {
      if (counter >= sizeof(Re_buf))
      {
        counter = 0;
        continue;
      }
      Re_buf[counter] = (unsigned char)mySerial.read();

      switch (counter)
      {
      case 0:
        if (Re_buf[0] != add)
        {
          counter = 0;
          continue;
        }
        break;
      case 1:
        if (Re_buf[1] != 0x03)
        {
          counter = 0;
          continue;
        }
        break;
      case 2:
        start_reg = Re_buf[2];
        break;
      case 3:
        len = Re_buf[3];
        break;
      default:
        if (len + 5 == counter)
        {
          sign = 1;
        }
        break;
      }

      if (sign)
      {
        sign = 0;
        for (i = 0; i < counter - 1; i++)
          sum += Re_buf[i];
        if (sum == Re_buf[counter - 1])
        {
          if (start_reg == newStartReg)
          {
            memset(&my_95Q, 0, sizeof(my_95Q)); // 初始化结构体

            // 分别解析欧拉角
            byte rollOffset = calculateOffset(newStartReg, 0x14);
            my_95Q.roll = (Re_buf[4 + rollOffset + 1] << 8) | Re_buf[4 + rollOffset];

            byte pitchOffset = calculateOffset(newStartReg, 0x16);
            my_95Q.pitch = (Re_buf[4 + pitchOffset + 1] << 8) | Re_buf[4 + pitchOffset];

            byte yawOffset = calculateOffset(newStartReg, 0x18);
            my_95Q.yaw = (Re_buf[4 + yawOffset + 1] << 8) | Re_buf[4 + yawOffset];

            // 解析 leve
            byte leveOffset = calculateOffset(newStartReg, 0x1A);
            my_95Q.leve = Re_buf[4 + leveOffset];

            // 解析温度数据
            byte tempLOffset = calculateOffset(newStartReg, 0x1B);
            byte tempHOffset = calculateOffset(newStartReg, 0x1C);
            my_95Q.temp = (Re_buf[4 + tempHOffset] << 8) | Re_buf[4 + tempLOffset];
          }
          Serial.print("roll:");
          Serial.print((float)my_95Q.roll / 100);
          Serial.print(",pitch:");
          Serial.print((float)my_95Q.pitch / 100);
          Serial.print(",yaw:");
          Serial.print((float)my_95Q.yaw / 100);
          Serial.print(",leve:");
          Serial.print(my_95Q.leve);
          Serial.print(",temp:");
          Serial.print((float)my_95Q.temp / 100);
          Serial.println();
        }
        else
        {
          // Serial.println("Checksum error!");
        }
        counter = 0;
      }
      else
        counter++;
    }
  }
  else
  {
    if (millis() - lastDataTime > 1000 && millis() - lastPromptTime > 1000)
    {
      Serial.println("No data received. Waiting for data...");
      lastPromptTime = millis(); // 更新上次显示提示信息的时间
    }
  }
  delay(10);
}

下面这个是iic连接的,这个是基于店家给的资料改的,毕竟iic的比较简单,温度读取没弄好,不想折腾了,反正我一般只用串口,因为店家的调试软件也只支持串口

#include <Wire.h>

#define uint16_t unsigned int
#define iic_add 0xa4 >> 1
typedef struct
{

  int16_t roll;
  int16_t pitch;
  int16_t yaw;
  uint8_t leve;
  int16_t temp;

} gy;
unsigned char Re_buf;
unsigned char sign = 0;
gy my_95Q;
uint16_t delay_t = 0;
byte ready_Ok = 0;
void setup()
{
  byte td = 1;
  Wire.begin(12, 13, 100000); // 设置SDA为11,SCL为10,波特率为100kHz
  Serial.begin(115200);
  delay(100);
  iic_read(0x02, &td, 1);
  switch (td)
  {
  case 0:
    delay_t = 100;
    break;
  case 1:
    delay_t = 20;
    break;
  case 2:
    delay_t = 10;
    break;
  case 3:
    delay_t = 5;
    break;
  }
  delay(delay_t);
  attachInterrupt(0, Exti, RISING);
}
void loop()
{
  unsigned char data[16] = {0};

  //   if(ready_Ok)
  {
    iic_read(0x14, data, 9);
    memcpy(&my_95Q, data, 9);
    Serial.print("roll: ");
    Serial.print(my_95Q.roll / 100);
    Serial.print(",pitch: ");
    Serial.print(my_95Q.pitch / 100);
    Serial.print(",yaw:");
    Serial.print(my_95Q.yaw / 100);
    Serial.print(",leve:");
    Serial.println((float)my_95Q.leve);
    ready_Ok = 0;
  }

  delay(delay_t);
}
void Exti()
{
  if (!ready_Ok)
    ready_Ok = 1; // 数据更新标志
}
void iic_read(unsigned char add, unsigned char *data, unsigned char len)
{
  byte j = 0;
  Wire.beginTransmission(iic_add);
  Wire.write(add);
  Wire.endTransmission(false);
  Wire.requestFrom(iic_add, (int)len);
  for (j = 0; j < len; j++)
    *data++ = Wire.read();
}
void iic_write(char add, unsigned char data)
{
  Wire.beginTransmission(iic_add);
  Wire.write((uint8_t)add);
  Wire.write((uint8_t)data);
  Wire.endTransmission();
}

我已经踩了好多坑了,不希望还有小伙伴再踩同样的坑

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐