stm32 国产QMC5883L 进口HMC5883 三轴电子指南针加速度传感器
<p>QMC5883L源于Honeywell的HMC5883L,是一款表面贴装的集成了信号处理电路的三轴磁性传感器,应用场景主要包括罗盘、导航、无人机、机器人和手持设备等一些高精度的场合。</p><p>QMC5883L上电后默认为待命模式。此状态下,寄存器值将会通过一个超低功耗的LDO保持,对任意寄存器的读写操作都将会唤醒I2C总线接口。内部时钟被停止,同时也不会进行磁场测量。</p>
<p>以下是QMC5883L的寄存器列表:</p>
<p>00H~05H是数据寄存器,分别存放的是三轴传感器的X、Y和Z轴的值,每两个寄存器构成一个轴的高低字节,表示范围:-32768~32768。</p>
<p>06H是状态寄存器,当传感器数据已测量完毕并准备好DRDY位被置“1”,数据寄存器一旦被读取,DRDY位将被置“0”。OVL是溢出位,当有任意一个轴的测量值超过范围,OVL将被置“1”,当下一次测量不超测量范围时,OVL将会被置“0”。当处于连续模式下测量数据被跳过时DOR被置“1”,而当数据寄存器被读写后置“0”。</p>
<p>07H~08H存放的是QMC5883L内置的温度传感器的输出数据。这里需要注意的是温度传感器的增益出厂前校正过,但偏移没有得到补偿,所以,温度传感器测得的相对值是准确的。温度系数100 LSB/℃。</p>
<p>09H~0AH是QMC5883L的控制寄存器。09H设置工作模式(MODE)、数据输出更新频率(ODR)、传感器测量范围(RNG)以及过采样率(OSR)。0AH设置中断使能(INT_ENB)、点翻转使能(POL_PNT)以及软复位(SOFT_RST)。09H寄存器的设置如下图所示:</p>
<p>Figure 8 09H寄存器设置</p>
<p>INT_ENB被置“0”时,中断引脚(即DRDY)将被使能,置“1”时中断被禁止。</p>
<p>ROL_PNT被置“0”时,I2C总线接口将不会自动在00H~06H间翻转,置“1”时自动翻转。</p>
<p>SOFT_RST被置“1”时对QMC5883L进行软复位,软复位可以发生于任何模式下的任何时段,软复位发生后所有寄存器将会被置默认值。</p>
<p>0BH控制QMC5883L的设置/复位时间,推荐值是设定为0x01。</p>
<p>0DH是器件标识寄存器,其值为0xFF。<br />
</p>
<p>STM32程序如下,已调试通过</p>
<pre>
<code>void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;
GPIO_Init(GPIOB,&GPIO_InitStructure);
I2C_SCL_H;
I2C_SDA_H;
}
void I2C_SDA_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
void I2C_SDA_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
//产生起始信号
void I2C_Start(void)
{
u16 i;
I2C_SDA_OUT();
I2C_SDA_H;
I2C_SCL_H;
for(i=0;i<5000;i++);
I2C_SDA_L;
for(i=0;i<6000;i++);
I2C_SCL_L;
}
//产生停止信号
void I2C_Stop(void)
{
u16 i;
I2C_SDA_OUT();
// I2C_SCL_L;
I2C_SDA_L;
I2C_SCL_H;
for(i=0;i<6000;i++);
I2C_SDA_H;
for(i=0;i<6000;i++);
}
//主机产生应答信号ACK
void I2C_Ack(void)
{
u16 i;
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_L;
for(i=0;i<2000;i++);
I2C_SCL_H;
for(i=0;i<5000;i++);
I2C_SCL_L;
}
//主机不产生应答信号NACK
void I2C_NAck(void)
{
u16 i;
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_H;
for(i=0;i<2000;i++);
I2C_SCL_H;
for(i=0;i<5000;i++);
I2C_SCL_L;
}
//等待从机应答信号
//返回值:1 接收应答失败
// 0 接收应答成功
u8 I2C_Wait_Ack(void)
{
u8 tempTime=0;
u16 i;
I2C_SDA_H;
for(i=0;i<1000;i++);
I2C_SDA_IN();
//I2C_SDA_H;
//for(i=0;i<1000;i++);
I2C_SCL_H;
for(i=0;i<1000;i++);
while(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA))
{
tempTime++;
if(tempTime>250)
{
//I2C_Stop();
return 1;
}
}
I2C_SCL_L;
return 0;
}
//I2C 发送一个字节
void I2C_Send_Byte(u8 txd)
{
u8 i=0;
u16 j;
I2C_SDA_OUT();
I2C_SCL_L;//拉低时钟开始数据传输
for(i=0;i<8;i++)
{
if((txd&0x80)>0) //0x801000 0000
I2C_SDA_H;
else
I2C_SDA_L;
txd<<=1;
I2C_SCL_H;
for(j=0;j<2000;j++);
I2C_SCL_L;
for(j=0;j<2000;j++);
}
}
//I2C 读取一个字节
u8 IIC_Read_Byte(void )
{
unsigned char i,receive=0;
u16 j;
I2C_SDA_IN();//SDA设置为输入
for(i=0;i<8;i++ )
{
I2C_SCL_L;
for(j=0;j<5000;j++);
I2C_SCL_H;
receive<<=1;
if(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA))receive++;
for(j=0;j<5000;j++);
}
return receive;
}
u8 I2C_Read_Byte(u8 ack)
{
u8 i=0,receive=0;
u16 j;
I2C_SDA_IN();
for(i=0;i<8;i++)
{
I2C_SCL_L;
for(j=0;j<2000;j++);
I2C_SCL_H;
receive<<=1;
if(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA))
receive++;
for(j=0;j<1000;j++);
}
if(ack==0)
I2C_NAck();
else
I2C_Ack();
return receive;
}
//********??????????*************************
//unsigned char Single_Read_HMC5883(unsigned char REG_Address)
unsigned char Single_Read(unsigned char SlaveAddress,unsigned char REG_Address)
{unsigned char REG_data;
I2C_Start(); //????
I2C_Send_Byte(SlaveAddress); //??????+???
I2C_Send_Byte(REG_Address); //????????,?0??
I2C_Start(); //????
I2C_Send_Byte(SlaveAddress+1); //??????+???
REG_data=I2C_Read_Byte(1); //???????
I2C_Ack();
I2C_Stop(); //????
return REG_data;
}
void IIC_Read(u8 IcAddr,u8 DtAddr,u8 len)
{
u8 i=0;
I2C_Start();
I2C_Send_Byte(IcAddr);//器件地址+数据地址
I2C_Wait_Ack();
I2C_Send_Byte(DtAddr);//双字节是数据地址低位
I2C_Wait_Ack();
I2C_Start();
I2C_Send_Byte(IcAddr+0x01);
I2C_Wait_Ack();
for(i=0;i<len-1;i++)
{
IIC_buf=I2C_Read_Byte(1); //1 代表 ACK
}
IIC_buf=I2C_Read_Byte(0); //0代表 NACK
I2C_Stop();
}
void IIC_Write(u8 IcAddr,u8 DtAddr,u8 dt)
{
I2C_Start();
I2C_Send_Byte(IcAddr);//器件地址+数据地址
I2C_Wait_Ack();
I2C_Send_Byte(DtAddr);//双字节是数据地址低位
I2C_Wait_Ack();
I2C_Send_Byte(dt);
I2C_Wait_Ack();
I2C_Stop();
}
voidInit_HMC5883L(void)
{
IIC_Write(HMC5883L_Addr,0x09,0x1d); //
IIC_Write(HMC5883L_Addr,0x0A,0x41);
IIC_Write(HMC5883L_Addr,0x0b,0x01); //
}
//******************************************************
void hmc_write_reg(u8 reg,u8 data)
{
I2C_Start();
I2C_Send_Byte(WRITE_ADDRESS);
I2C_Wait_Ack();
I2C_Send_Byte(reg);
I2C_Wait_Ack();
I2C_Send_Byte(data);
I2C_Wait_Ack();
I2C_Stop();
//delay_ms(5);
}
u8 hmc_read_reg(u8 reg)
{
u8 data;
I2C_Start();
I2C_Send_Byte(WRITE_ADDRESS);
I2C_Wait_Ack();
I2C_Send_Byte(reg);
I2C_Wait_Ack();
I2C_Stop();
I2C_Start();
I2C_Send_Byte(READ_ADDRESS);
I2C_Wait_Ack();
data=IIC_Read_Byte();
I2C_NAck();
I2C_Stop();
return data;
}
void hmc_read_XYZ(short int *data)
{
x=((int16_t)hmc_read_reg(DATAX_M)<<8) | (hmc_read_reg(DATAX_L)); //Combine MSB and LSB of X Data output register
y=((int16_t)hmc_read_reg(DATAY_M)<<8) | (hmc_read_reg(DATAY_L)); //Combine MSB and LSB of Y Data output register
z=((int16_t)hmc_read_reg(DATAZ_M)<<8) | (hmc_read_reg(DATAZ_L)); //Combine MSB and LSB of Z Data output register
if(x>0x7fff) x=0x1ffff-x;
else x=0xffff+x;
if(y>0x7fff) y=0x1ffff-y;
else y=0xffff+y;
if(z>0x7fff) z=0x1ffff-z;
else z=0xffff+z;
x_temp=x;
y_temp=y;
z_temp=z;
angledot= atan2((double)y,(double)x) * (180 / 3.14159265) + 180; // angle in degrees
angledot= atan2((double)z,(double)x) * (180 / 3.14159265) + 180; // angle in degrees
angledot= atan2((double)y,(double)z) * (180 / 3.14159265) + 180; // angle in degrees
chip_ID=hmc_read_reg(0x0d);
}
</code></pre>
<p>芯片比较难手焊,我把PCB焊盘和芯片底部焊盘都镀锡,然后用风枪吹,一次焊接成功。</p>
<p>谢谢分享</p>
<p>很好的知识,有种豁然开朗的感觉,感谢楼主分享。</p>
页:
[1]