stm32 国产QMC5883L 进口HMC5883 三轴电子指南针加速度传感器

QMC5883L源于Honeywell的HMC5883L,是一款表面贴装的集成了信号处理电路的三轴磁性传感器,应用场景主要包括罗盘、导航、无人机、机器人和手持设备等一些高精度的场合。

QMC5883L上电后默认为待命模式。此状态下,寄存器值将会通过一个超低功耗的LDO保持,对任意寄存器的读写操作都将会唤醒I2C总线接口。内部时钟被停止,同时也不会进行磁场测量。

以下是QMC5883L的寄存器列表:

00H~05H是数据寄存器,分别存放的是三轴传感器的X、Y和Z轴的值,每两个寄存器构成一个轴的高低字节,表示范围:-32768~32768。

06H是状态寄存器,当传感器数据已测量完毕并准备好DRDY位被置“1”,数据寄存器一旦被读取,DRDY位将被置“0”。OVL是溢出位,当有任意一个轴的测量值超过范围,OVL将被置“1”,当下一次测量不超测量范围时,OVL将会被置“0”。当处于连续模式下测量数据被跳过时DOR被置“1”,而当数据寄存器被读写后置“0”。

07H~08H存放的是QMC5883L内置的温度传感器的输出数据。这里需要注意的是温度传感器的增益出厂前校正过,但偏移没有得到补偿,所以,温度传感器测得的相对值是准确的。温度系数100 LSB/℃。

09H~0AH是QMC5883L的控制寄存器。09H设置工作模式(MODE)、数据输出更新频率(ODR)、传感器测量范围(RNG)以及过采样率(OSR)。0AH设置中断使能(INT_ENB)、点翻转使能(POL_PNT)以及软复位(SOFT_RST)。09H寄存器的设置如下图所示:

Figure 8 09H寄存器设置

INT_ENB被置“0”时,中断引脚(即DRDY)将被使能,置“1”时中断被禁止。

ROL_PNT被置“0”时,I2C总线接口将不会自动在00H~06H间翻转,置“1”时自动翻转。

SOFT_RST被置“1”时对QMC5883L进行软复位,软复位可以发生于任何模式下的任何时段,软复位发生后所有寄存器将会被置默认值。

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

0DH是器件标识寄存器,其值为0xFF。
 

STM32程序如下,已调试通过

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) //0x80  1000 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[i]=I2C_Read_Byte(1); //  1   代表 ACK
	}

	IIC_buf[len-1]=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();
}
 

 void  Init_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[xyz_count]=x;
	y_temp[xyz_count]=y;
	z_temp[xyz_count]=z;
	
	
	angledot[0]= atan2((double)y,(double)x) * (180 / 3.14159265) + 180; // angle in degrees
	angledot[1]= atan2((double)z,(double)x) * (180 / 3.14159265) + 180; // angle in degrees
	angledot[2]= atan2((double)y,(double)z) * (180 / 3.14159265) + 180; // angle in degrees
	chip_ID=hmc_read_reg(0x0d);
}

芯片比较难手焊,我把PCB焊盘和芯片底部焊盘都镀锡,然后用风枪吹,一次焊接成功。

猜你喜欢

转载自blog.csdn.net/gd1984812/article/details/106946391