HMC5883L是一种IIC通信的电子罗盘芯片,输出与北的角度偏差,数值是0-360度,靠西方向增长,可以理解为逆时针为正。配合GPS模块简直就是四轴飞行器的铁杆标配。驱动分为驱动IIC和转换角度两块。
1.驱动IIC
void IIC_IO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); //ê1?üGPIOBê±?ó
GPIO_InitStructure.GPIO_Pin = GPIO_SCL|GPIO_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //í?íìê?3?
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(IIC_PERIPH, &GPIO_InitStructure);
GPIO_SetBits(IIC_PERIPH,GPIO_Pin_8|GPIO_Pin_9); //PB6,PB7 ê?3???
}
void i2c_Start(void)
{
/* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */
SDA_OUT();
IIC_SDA = 1;
delay_us(10);
IIC_SCL = 1;
delay_us(10);
IIC_SDA = 0;
delay_us(10);
IIC_SCL = 0;
delay_us(10);
}
void i2c_Stop(void)
{
/* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */
SDA_OUT();
IIC_SDA = 0;
delay_us(10);
IIC_SCL = 1;
delay_us(10);
IIC_SDA = 1;
}
void i2c_SendByte(u8 _ucByte)
{
u8 i;
SDA_OUT();
/* 先发送字节的高位bit7 */
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)
{
IIC_SDA = 1;
}
else
{
IIC_SDA = 0;
}
delay_us(10);
IIC_SCL = 1;
delay_us(10);
IIC_SCL = 0;
if (i == 7)
{
IIC_SDA = 1; // 释放总线
}
_ucByte <<= 1; /* 左移一个bit */
delay_us(10);
}
}
u8 i2c_ReadByte(void)
{
u8 i;
u8 value;
IIC_SDA = 1;
SDA_IN();
/* 读到第1个bit为数据的bit7 */
value = 0;
for (i = 0; i < 8; i++)
{
value <<= 1;
IIC_SCL = 1;
delay_us(10);
if (READ_SDA)
{
value++;
}
IIC_SCL = 0;
delay_us(10);
}
return value;
}
u8 i2c_WaitAck(void)
{
u8 re;
SDA_IN();
IIC_SDA = 1; /* CPU释放SDA总线 */
delay_us(10);
IIC_SCL = 1; /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
delay_us(10);
if (READ_SDA) /* CPU读取SDA口线状态 */
{
re = 1;
}
else
{
re = 0;
}
IIC_SCL = 0;
delay_us(10);
return re;
}
void i2c_Ack(void)
{
SDA_OUT();
IIC_SDA = 0; /* CPU驱动SDA = 0 */
delay_us(10);
IIC_SCL = 1; /* CPU产生1个时钟 */
delay_us(10);
IIC_SCL = 0;
delay_us(10);
IIC_SDA = 1; /* CPU释放SDA总线 */
}
void i2c_NAck(void)
{
SDA_OUT();
IIC_SDA = 1; /* CPU驱动SDA = 1 */
delay_us(10);
IIC_SCL = 1; /* CPU产生1个时钟 */
delay_us(10);
IIC_SCL = 0;
delay_us(10);
}
void HMC5883L_Init()
{
IIC_IO_Init();
//i2c_CheckDevice(HMC5883L_Write_Address);
i2c_Start();
i2c_SendByte(HMC5883L_Write_Address);
i2c_WaitAck();
i2c_SendByte(0x00);
i2c_WaitAck();
i2c_SendByte(0x70);
i2c_WaitAck();
i2c_SendByte(0x01);
i2c_WaitAck();
i2c_SendByte(0xe0);
i2c_WaitAck();
i2c_SendByte(0x02);
i2c_WaitAck();
i2c_SendByte(0x01);
i2c_Stop();
}
总结:都是常规的IIC设置,注意延时长短。宏定义了一些东西,参数如下
#define SDA_IN() {GPIOB->CRH&=0XFFFFFF0F;GPIOB->CRH|=(u32)8<<4;}
#define SDA_OUT() {GPIOB->CRH&=0XFFFFFF0F;GPIOB->CRH|=(u32)3<<4;}
#define IIC_SCL PBout(8) //SCL
#define IIC_SDA PBout(9) //SDA
#define GPIO_SCL GPIO_Pin_8
#define GPIO_SDA GPIO_Pin_9
#define IIC_PERIPH GPIOB
#define READ_SDA PBin(9)
SDA_IN()和SDA_OUT()是直接操作寄存器,IO口地址是0XFFFFFF0F,(u32)8中的8是输入模式,左移4是移到当前IO的寄存器设置地址(1x4)
2.转换角度
int x,y,z,X,Y,Z;
float Get_Current_Angle()
{
u8 i;
u8 a[6];
float Curent_Angle;
HMC5883L_Init();
i2c_Start();
i2c_SendByte(HMC5883L_Write_Address);
i2c_WaitAck();
i2c_SendByte(0x03);
i2c_WaitAck();
i2c_Start();
i2c_SendByte(HMC5883L_Read_Address);
i2c_WaitAck();
for(i=0;i<6;i++)
{
a[i] = i2c_ReadByte();
if(i==5)
{
i2c_NAck();
}
else
{
i2c_Ack();
}
}
i2c_Stop();
x=a[0];
x=x<<8;
x=x|a[1];
y=a[2];
y=y<<8;
y=y|a[3];
z=a[4];
z=z<<8;
z=z|a[5];
if(x>32768)
{
x = -(0xFFFF - x + 1);
}
if(y>32768)
{
y = -(0xFFFF - y + 1);
}
if(z>32768)
{
z = -(0xFFFF - z + 1);
}
X = (s16)x; //x分量
Y = (s16)y; //y分量
Z = (s16)z; //z分量
Curent_Angle = (atan2(Y,X) * (180 / 3.14159265) + 180); //实际水平角度
return Curent_Angle;
}
这个实际上就是数据处理函数,只要IIC初始化OK直接copy过来就能用上。函数返回的直接是和北偏离的度数,指南针就做好了。现在手机上自带罗盘,一般打开地图点位置模式就能看到箭头方向。