项目场景:
由于想要自己做一个小小四轴,然后看了很多大佬的代码,但是不太理解关于 滤波,姿态解算,四元素结算这些。然后就想着找一下有没有什么芯片之列的可以直接输出角度,就可以直接跳过姿态解算了。再万能的某宝上找到了一些模块,我这里买了两个模块想试一下。一个是BNO055一个可以直接输出角度的芯片,另一个是JY901,这是一个可以输出角度的传感器模块。
问题总结:
BNO055的芯片。这个芯片可以直接输出角度,再度娘上也找到了相关的资料,但是好像用的人并不多,找到驱动程序。然后就只能自己对着芯片手册一个一个写了。看了一下可以用串口,IIC(感觉这个芯片里面好像自带一个单片机)。我这用的是IIC驱动的。由于这里调了好几天,所以有连接STM32的,STM8的。最后使用的STM8硬件IIC才成功的。
STM32调试:
1.硬件连接
STM32F103C8T6连接,我这里IIC连接的是PB6,PB7。然后还有两根电源线。(几根彩色的小线是逻辑分析仪的,调试采集用的。)
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.问题总结
下图为逻辑分析仪采集的波形:
问题出来了,逻辑分析仪一看。SCL波形全乱了。怀疑线没接好,万用表测一遍没什么问题。怀疑上拉电阻弱了,换了4.7K,2K都不行。剩下的就只能是波形有问题了。等待应答时间,IIC速度都调了就是不行。
STM8调试:
STM32调试不成功怀疑STM32驱动能力不足,更换为STM8采集。
1.硬件连接
我这里用的STM3S003,首先用的是模拟IIC连接的SCL连接PB4,SDA连接PB5。然后电源线与地线,同样来连接逻辑分析仪调试。
2.软件调试
开始用的还是模拟IIC一样的现象,下面的是STM8模拟IIC采集的波形:
然后就放弃模拟IIC开始使用硬件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的精度还可以,接下来打算研究一下这个小模块。