BNO055传感器的角度测评与JY901角度对比

项目场景:

由于想要自己做一个小小四轴,然后看了很多大佬的代码,但是不太理解关于 滤波,姿态解算,四元素结算这些。然后就想着找一下有没有什么芯片之列的可以直接输出角度,就可以直接跳过姿态解算了。再万能的某宝上找到了一些模块,我这里买了两个模块想试一下。一个是BNO055一个可以直接输出角度的芯片,另一个是JY901,这是一个可以输出角度的传感器模块。


问题总结:

BNO055的芯片。这个芯片可以直接输出角度,再度娘上也找到了相关的资料,但是好像用的人并不多,找到驱动程序。然后就只能自己对着芯片手册一个一个写了。看了一下可以用串口,IIC(感觉这个芯片里面好像自带一个单片机)。我这用的是IIC驱动的。由于这里调了好几天,所以有连接STM32的,STM8的。最后使用的STM8硬件IIC才成功的。

STM32调试:

1.硬件连接

STM32F103C8T6连接,我这里IIC连接的是PB6,PB7。然后还有两根电源线。(几根彩色的小线是逻辑分析仪的,调试采集用的。)
数据手册的IIC地址
实物连接图

2.软件调试

软件调试时候问题就出来了,用的模拟IIC,硬件IIC问题太多,不想折腾。然后就看数据手册,找寄存器打算先通信上。但是就是采集不到数据,代码如下循环采集0x00,0x01两个寄存器,寄存器值如下图:
数据手册截图
代码就循环采集 0x00,0x01寄存器:

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 
	SysTick_Config(7200);//0.1ms
	LED_Init();
  IIC_GPIO_Config();
	GPIO_ResetBits(GPIOB,GPIO_Pin_8);
	delay_ms(500);
	GPIO_SetBits(GPIOB,GPIO_Pin_8);
	delay_ms(800);
	
	while(1)
	{ 
		delay_ms(500);
		Single_ReadI2C( 0x29<<1,  0x00);
		delay_ms(500);
		Single_ReadI2C( 0x29<<1,  0x01);
	}
}

3.问题总结


下图为逻辑分析仪采集的波形:
STM32采集波形

问题出来了,逻辑分析仪一看。SCL波形全乱了。怀疑线没接好,万用表测一遍没什么问题。怀疑上拉电阻弱了,换了4.7K,2K都不行。剩下的就只能是波形有问题了。等待应答时间,IIC速度都调了就是不行。


STM8调试:

STM32调试不成功怀疑STM32驱动能力不足,更换为STM8采集。

1.硬件连接

我这里用的STM3S003,首先用的是模拟IIC连接的SCL连接PB4,SDA连接PB5。然后电源线与地线,同样来连接逻辑分析仪调试。

2.软件调试

开始用的还是模拟IIC一样的现象,下面的是STM8模拟IIC采集的波形:
STM8模拟IIC波形
然后就放弃模拟IIC开始使用硬件IIC,然后一次成功。采集波形看下图:
STM8硬件IIC采集

STM8硬件IIC程序:

#include "stm8s.h"
#define WAKE_PIN_1 GPIOA->ODR|=0x08
#define WAKE_PIN_0 GPIOA->ODR&=0xF7 

#define SDA_IN  GPIOB->DDR&=0xDF;GPIOB->CR1&=0xDF;
#define SCL_IN  GPIOB->DDR&=0xEF;GPIOB->CR1&=0xEF;


#define SDA_FLAOTING  GPIOB->CR1&=0xDF
#define SCL_FLAOTING  GPIOB->CR1&=0xEF

void delay_10ms(char cFirstTime)
{
  unsigned short i;
  while(cFirstTime)
  {
    i=26380;
    while(i--);
    cFirstTime--;
  }
}
void IIC_Init(void)
{
  uint8_t i;
  WAKE_PIN_0;
  GPIOB->ODR = GPIO_PIN_4|GPIO_PIN_5;//OD ¸ß
  GPIOB->DDR = GPIO_PIN_4|GPIO_PIN_5;//out
  for(i=0;i<10;i++)
 {
    GPIOB->ODR &=~ GPIO_PIN_4;
    delay_10ms(1);
    GPIOB->ODR |= GPIO_PIN_4;
    delay_10ms(1);
 }
  GPIOB->DDR=0;
  CLK->PCKENR1|=0x01;
  I2C->CR1=0; 
  I2C->CR2 |= I2C_CR2_SWRST;
  I2C->CR2 &= (uint8_t)(~I2C_CR2_SWRST);
  
  I2C->FREQR=16;
//I2C->CCRL=0x06;
//I2C->CCRH=0x80;

I2C->CCRL=0x0D;
I2C->CCRH=0x80;

  I2C->TRISER=0x04;/
  /* Enable I2C */
  I2C->CR1 |= I2C_CR1_PE;  
}

uint8_t i2c_CheckDevice(uint8_t _Address)
{
  uint16_t time_out=0;
  if ((I2C->SR3 & 0x02)==0)
  {
    I2C->CR2 |= 0x01; 
    while(!(I2C->SR1 & 0x01)); 
    I2C->DR = _Address;
    while(!(I2C->SR1 & 0x02)) 
    {
      time_out++;
      if(time_out>2000)
      {     
        return 0;
      }
    }
    
    I2C->CR2 |= 0x02;  //ֹͣλ²úÉústop
    return 1;
  }
  return 0;    // I2C×ÜÏßÒì³£ 
}
#define I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED 0x0302
#define I2C_EVENT_MASTER_BYTE_RECEIVED 0x0340

ErrorStatus I2C_CheckEvent(uint16_t I2C_Event)
{
  __IO uint16_t lastevent=0;
  *((uint8_t*)&lastevent+1)=I2C->SR1&(*((uint8_t*)&I2C_Event+1));
  *(uint8_t*)&lastevent=I2C->SR3&(*(uint8_t*)&I2C_Event);
  if(lastevent==I2C_Event)
  {
    //SUCCESS: last event is equal to I2C_EVENT
    return SUCCESS;
  }
  else
  {
    //ERROR: last event is different from I2C_EVENT
    return ERROR;
  }  
}

void IIC_Wite_Reg(uint8_t IIC_ADDR,uint8_t REG_ADDR,uint8_t DATA)
{
  while(I2C->SR3 & 0x02);
  I2C->CR2 |= 0x01; 
  while(!(I2C->SR1 & 0x01)); 
  I2C->DR = IIC_ADDR;
  while(!(I2C->SR1 & 0x02)); 
  I2C->SR1; 
  I2C->SR3; 
  I2C->DR = REG_ADDR;
  while(!(I2C->SR1 & 0x84));   
  I2C->DR = DATA;
  while(!(I2C->SR1 & 0x84));
  I2C->CR2 |= 0x02;
}
void IIC_Wite_Nums(uint8_t IIC_ADDR,uint8_t REG_ADDR,uint8_t *data, uint8_t length)
{
  uint8_t i; 
  
    while(I2C->SR3 & 0x02);
    I2C->CR2 |= 0x01;
    while(!(I2C->SR1 & 0x01));  
    I2C->DR = IIC_ADDR;
    while(!(I2C->SR1 & 0x02));  
    I2C->SR1;
    I2C->SR3; 
    I2C->DR = REG_ADDR;
    for(i=0;i<length;i++)
    {      
      while(!(I2C->SR1 & 0x80));
      I2C->DR = data[i];
    }
    while(!(I2C->SR1 & 0x84)); 
    I2C->CR2 |= 0x02;      
}
void IIC_Read(uint8_t IIC_ADDR,uint8_t REG_ADDR)
{  
  while(I2C->SR3 & 0x02);  
  I2C->CR2 |= 0x01; 
  while(!(I2C->SR1 & 0x01)); 
  I2C->DR = IIC_ADDR;
  while(!(I2C->SR1 & 0x02));  
  I2C->SR1; 
  I2C->SR3; 
  I2C->DR = REG_ADDR;
  while(!(I2C->SR1 & 0x84));  
  
  I2C->CR2 |= 0x01;  
  while(!(I2C->SR1 & 0x01)); 
  I2C->DR = IIC_ADDR+1;
  while (!I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); 
}
uint8_t IIC_Read_Reg(uint8_t IIC_ADDR,uint8_t REG_ADDR)
{ 
  
IIC_Read(IIC_ADDR,REG_ADDR);
  I2C->CR2 &= ~0x04; //nask     
  I2C->CR2 |= 0x02; 
  while((I2C->SR1 & 0x40)==0);
  REG_ADDR=I2C->DR;
  
  
  return REG_ADDR;
}
void IIC_Read_Nums(uint8_t IIC_ADDR,uint8_t REG_ADDR,uint8_t *data, uint8_t length)
{ 
  IIC_Read(IIC_ADDR,REG_ADDR);
  I2C->CR2 |= 0x04; //ask 
  while(length)
  {
    if(length==1)
    {
      I2C->CR2 &= ~0x04;
      I2C->CR2 |= 0x02;   
    }
    if(I2C->SR1 & 0x40)
    {
      *data=I2C->DR;
      data++;
      length--;
    }
  }
}
void SimulaIICWriteBytes(unsigned char dev, unsigned short reg, unsigned char length, unsigned char* data)
{
    uint8_t i;
    while(I2C->SR3 & 0x02);  
    I2C->CR2 |= 0x01;
    while(!(I2C->SR1 & 0x01));  
    I2C->DR = dev;
    while(!(I2C->SR1 & 0x02)); 
    I2C->SR1;
    I2C->SR3; 
    I2C->DR = reg;
    for(i=0;i<length;i++)
    {      
      while(!(I2C->SR1 & 0x80));  
      I2C->DR = data[(i<<1)+1];
    }
    while(!(I2C->SR1 & 0x84));  
    I2C->CR2 |= 0x02;     
}
void SimulaIICReadBytes(unsigned char dev, unsigned short reg, unsigned char length, unsigned char *data)
{
  IIC_Read(dev,reg);
  I2C->CR2 |= 0x04; //ask 
  while(length)
  {
    if(length==1)
    {
      I2C->CR2 &= ~0x04;     
      I2C->CR2 |= 0x02; 
    }
    if(I2C->SR1 & 0x40)
    {
      data++;
      *data=I2C->DR;
      data++;
      length--;
    }
  }
}

加速度,角速度,角度,磁场数据采集。

char Sensor_GetValue(unsigned char *data,unsigned char ucTick)
{
  if(sQUIT_TIME>0)return 0;
  IIC_Read_Nums( 0X29<<1, 0x08, data, 24);
  IIC_Read_Nums( 0X29<<1, 0x35, &ucCalibaration, 1);
  
  sQUIT_TIME=2;
  return 1;
}

然后数据解算

 Acc[0] = ((short)ucTemp[1]<<8)|ucTemp[0];
  Acc[1] = ((short)ucTemp[3]<<8)|ucTemp[2];
  Acc[2] = ((short)ucTemp[5]<<8)|ucTemp[4];
  
  Mag[0] = ((short)ucTemp[7]<<8)|ucTemp[6];
  Mag[1] = ((short)ucTemp[9]<<8)|ucTemp[8];
  Mag[2] = ((short)ucTemp[11]<<8)|ucTemp[10];
  
  Gyro[0] = ((short)ucTemp[13]<<8)|ucTemp[12];
  Gyro[1] = ((short)ucTemp[15]<<8)|ucTemp[14];
  Gyro[2] = ((short)ucTemp[17]<<8)|ucTemp[16];
  
  Ang[2] = (float)(((short)ucTemp[19]<<8)|ucTemp[18])/16.0;
  Ang[0] = (float)(((short)ucTemp[21]<<8)|ucTemp[20])/16.0;
  Ang[1] = (float)(((short)ucTemp[23]<<8)|ucTemp[22])/16.0;

然后串口打印就可以了。

3.问题分析

问题应该出在模拟IIC的时序误差上。有些芯片对IIC时序要求较高,模拟IIC的时序无法达到要求。

精度对比

简单的通过数据手册和淘宝上的资料对比了一下,感觉BNO055这个输出的精度不是很高。然后JY901的感觉精度还可以。贴一个精度对比图。
BNO055分辨率
在这里插入图片描述
JY901的精度
在这里插入图片描述
感觉JY901的精度还可以,接下来打算研究一下这个小模块。

猜你喜欢

转载自blog.csdn.net/weixin_40905871/article/details/108445060