gandong 发表于 2020-7-19 16:13

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位被置&ldquo;1&rdquo;,数据寄存器一旦被读取,DRDY位将被置&ldquo;0&rdquo;。OVL是溢出位,当有任意一个轴的测量值超过范围,OVL将被置&ldquo;1&rdquo;,当下一次测量不超测量范围时,OVL将会被置&ldquo;0&rdquo;。当处于连续模式下测量数据被跳过时DOR被置&ldquo;1&rdquo;,而当数据寄存器被读写后置&ldquo;0&rdquo;。</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被置&ldquo;0&rdquo;时,中断引脚(即DRDY)将被使能,置&ldquo;1&rdquo;时中断被禁止。</p>

<p>ROL_PNT被置&ldquo;0&rdquo;时,I2C总线接口将不会自动在00H~06H间翻转,置&ldquo;1&rdquo;时自动翻转。</p>

<p>SOFT_RST被置&ldquo;1&rdquo;时对QMC5883L进行软复位,软复位可以发生于任何模式下的任何时段,软复位发生后所有寄存器将会被置默认值。</p>

<p>0BH控制QMC5883L的设置/复位时间,推荐值是设定为0x01。</p>

<p>0DH是器件标识寄存器,其值为0xFF。<br />
&nbsp;</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,&amp;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,&amp;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,&amp;GPIO_InitStructure);
}

//产生起始信号
void I2C_Start(void)
{
        u16 i;
        I2C_SDA_OUT();
       
        I2C_SDA_H;
        I2C_SCL_H;
        for(i=0;i&lt;5000;i++);
        I2C_SDA_L;
        for(i=0;i&lt;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&lt;6000;i++);
   I2C_SDA_H;
   for(i=0;i&lt;6000;i++);
}

//主机产生应答信号ACK
void I2C_Ack(void)
{
   u16 i;
   I2C_SCL_L;
   I2C_SDA_OUT();
   I2C_SDA_L;
   for(i=0;i&lt;2000;i++);
   I2C_SCL_H;
   for(i=0;i&lt;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&lt;2000;i++);
   I2C_SCL_H;
   for(i=0;i&lt;5000;i++);
   I2C_SCL_L;
}
//等待从机应答信号
//返回值:1 接收应答失败
//                  0 接收应答成功
u8 I2C_Wait_Ack(void)
{
        u8 tempTime=0;
        u16 i;
        I2C_SDA_H;
        for(i=0;i&lt;1000;i++);
        I2C_SDA_IN();

        //I2C_SDA_H;
        //for(i=0;i&lt;1000;i++);
        I2C_SCL_H;
        for(i=0;i&lt;1000;i++);

        while(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA))
        {
                tempTime++;
                if(tempTime&gt;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&lt;8;i++)
        {
                if((txd&amp;0x80)&gt;0) //0x801000 0000
                        I2C_SDA_H;
                else
                        I2C_SDA_L;

                txd&lt;&lt;=1;
                I2C_SCL_H;
                for(j=0;j&lt;2000;j++);
                I2C_SCL_L;
                for(j=0;j&lt;2000;j++);
        }
}

//I2C 读取一个字节

u8 IIC_Read_Byte(void )
{
        unsigned char i,receive=0;
        u16 j;
        I2C_SDA_IN();//SDA设置为输入
    for(i=0;i&lt;8;i++ )
        {
      I2C_SCL_L;
      for(j=0;j&lt;5000;j++);
                I2C_SCL_H;
      receive&lt;&lt;=1;
      if(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA))receive++;   
                for(j=0;j&lt;5000;j++);
    }
        return receive;
}
u8 I2C_Read_Byte(u8 ack)
{
   u8 i=0,receive=0;
   u16 j;
   I2C_SDA_IN();
   for(i=0;i&lt;8;i++)
   {
                   I2C_SCL_L;
                for(j=0;j&lt;2000;j++);
                I2C_SCL_H;
                receive&lt;&lt;=1;
                if(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA))
                   receive++;
                for(j=0;j&lt;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&lt;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)&lt;&lt;8) | (hmc_read_reg(DATAX_L)); //Combine MSB and LSB of X Data output register
        y=((int16_t)hmc_read_reg(DATAY_M)&lt;&lt;8) | (hmc_read_reg(DATAY_L)); //Combine MSB and LSB of Y Data output register       
        z=((int16_t)hmc_read_reg(DATAZ_M)&lt;&lt;8) | (hmc_read_reg(DATAZ_L)); //Combine MSB and LSB of Z Data output register
       
        if(x&gt;0x7fff) x=0x1ffff-x;               
        else x=0xffff+x;
       
        if(y&gt;0x7fff) y=0x1ffff-y;               
        else y=0xffff+y;
       
        if(z&gt;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>

zxopenljx 发表于 2021-4-18 18:13

<p>谢谢分享</p>

xiaoxin66 发表于 2021-12-22 09:50

<p>很好的知识,有种豁然开朗的感觉,感谢楼主分享。</p>
页: [1]
查看完整版本: stm32 国产QMC5883L 进口HMC5883 三轴电子指南针加速度传感器