MAG3110(可替代hmc5883l的磁力计) stm32f1xx调试心得附源代码(以后可能会陆续更新四轴相关的传感器,欢迎关注)
MAG3110 stm32f1xx调试心得附源代码(硬件iic和模拟iic ,融合程序尽量使用模拟iic,否则硬件iic有bug,难受)MAG3110简介这些无需多说,数据手册百度得到。使用步骤:一 首先初始化iic,硬件iic调用函数 I2C_Configuration();具体引脚配置自行解决二 对MAG3110初始化 :1 ,进入 MAG3110_Standby(); sta...
MAG3110 stm32f1xx调试心得附源代码(硬件iic和模拟iic ,融合程序尽量使用模拟iic,否则硬件iic有bug,难受)
MAG3110简介
这些无需多说,数据手册百度得到。
使用步骤:
一 首先初始化iic,硬件iic调用函数 I2C_Configuration(); 具体引脚配置自行解决
二 对MAG3110初始化 :
1 ,进入 MAG3110_Standby(); standby 模式 (具体standby模式数据手册有给,写那个寄存器,以及写某个值)(如果不懂用iic给寄存器写值,可能后面你就看不太懂了,但是可以直接copy后面的代码)
2 , 配置相关寄存器, I2C_WriteOneByte(I2C1,MAG3110_IIC_ADDRESS,CTRL_REG1, DATA_RATE_5MS);
I2C_WriteOneByte(I2C1,MAG3110_IIC_ADDRESS,0x11, 0x00);
3 , MAG3110_Active();(同standby模式一样,给某个寄存器写值,就能使模块active,具体见数据手册或者后面代码)
三 读数据:
1 ,在初始化之后,需要读一个名为WHO_AM_I_REG的寄存器,如果读出的数据是 0xC4 ,则才为初始化成功。否则初始化失败
2, 初始化完毕之后,需要读0x00地址的值,读出的值与0x08按位与运算
&0x08,如果为真则说明数据准备就绪,可以读出。
3 ,读取数据,读出x,y,z轴的高低数据然后合并,作为三轴的磁通量。
硬件iic
以下是c文件,借用24c02
#include "24C02.h"
/*******************************************************************************
* Function Name : I2C_Configuration
* Description :
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void I2C_Configuration(void)
{
I2C_InitTypeDef I2C_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO , ENABLE);
/* Configure I2C1 pins: PB6->SCL and PB7->SDA */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
I2C_DeInit(I2C1);
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = 0x1C;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 400000;
I2C_Cmd(I2C1, ENABLE);
I2C_Init(I2C1, &I2C_InitStructure);
I2C_AcknowledgeConfig(I2C1, ENABLE);
}
/*******************************************************************************
* Function Name : I2C_delay
* Description :
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
static void I2C_delay(uint16_t cnt)
{
while(cnt--);
}
/*******************************************************************************
* Function Name : I2C_AcknowledgePolling
* Description :
* Input : I2C_TypeDef * , uint8_t
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
static void I2C_AcknowledgePolling(I2C_TypeDef *I2Cx,uint8_t I2C_Addr)
{
vu16 SR1_Tmp;
do
{
I2C_GenerateSTART(I2Cx, ENABLE);
SR1_Tmp = I2C_ReadRegister(I2Cx, I2C_Register_SR1);
#ifdef AT24C01A
I2C_Send7bitAddress(I2Cx, I2C_Addr, I2C_Direction_Transmitter);
#else
I2C_Send7bitAddress(I2Cx, 0, I2C_Direction_Transmitter);
#endif
}while(!(I2C_ReadRegister(I2Cx, I2C_Register_SR1) & 0x0002));
I2C_ClearFlag(I2Cx, I2C_FLAG_AF);
I2C_GenerateSTOP(I2Cx, ENABLE);
}
/*******************************************************************************
* Function Name : I2C_Read
* Description :
* Input :
* Output :
* Return :
* Attention : None
*******************************************************************************/
uchar I2C_Read(I2C_TypeDef *I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t *buf,uint16_t num)
{
uchar buffer1;
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
I2C_AcknowledgeConfig(I2Cx, ENABLE);
I2C_GenerateSTART(I2Cx, ENABLE);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2Cx, I2C_Addr, I2C_Direction_Transmitter);
while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2Cx, addr);
while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTART(I2Cx, ENABLE);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2Cx, I2C_Addr, I2C_Direction_Receiver);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
while (num)
{
if(num==1)
{
I2C_AcknowledgeConfig(I2Cx, DISABLE);
I2C_GenerateSTOP(I2Cx, ENABLE);
}
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED)); /* EV7 */
buffer1 = I2C_ReceiveData(I2Cx);
// buf++;
/* Decrement the read bytes counter */
num--;
}
I2C_AcknowledgeConfig(I2Cx, ENABLE);
return buffer1;
}
/*******************************************************************************
* Function Name : I2C_WriteOneByte
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
uint8_t I2C_WriteOneByte(I2C_TypeDef *I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t value)
{
while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
// I2C_AcknowledgeConfig(I2Cx, ENABLE);
I2C_GenerateSTART(I2Cx, ENABLE);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2Cx, I2C_Addr, I2C_Direction_Transmitter);
while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2Cx, addr);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_SendData(I2Cx, value);
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
I2C_GenerateSTOP(I2Cx, ENABLE);
I2C_AcknowledgePolling(I2Cx,I2C_Addr);
I2C_delay(1000);
return 0;
}
/*******************************************************************************
* Function Name : I2C_Write
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
uint8_t I2C_Write(I2C_TypeDef *I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t *buf,uint16_t num)
{
uint8_t err=0;
while(num--)
{
if(I2C_WriteOneByte(I2Cx, I2C_Addr,addr++,*buf++))
{
err++;
}
}
if(err)
return 1;
else
return 0;
}
/*********************************************************\
* Put MAG3110Q into Active Mode
\*********************************************************/
void MAG3110_Active ()
{
byte n;
n = I2C_Read(I2C1,MAG3110_IIC_ADDRESS,CTRL_REG1,0,1);
I2C_WriteOneByte(I2C1,MAG3110_IIC_ADDRESS,CTRL_REG1,n&0XFC|ACTIVE_MASK);
}
/*********************************************************\
* Put MAG3110Q into Standby Mode
\*********************************************************/
void MAG3110_Standby (void)
{
byte n;
n = I2C_Read(I2C1,MAG3110_IIC_ADDRESS,CTRL_REG1,0,1);
I2C_WriteOneByte(I2C1,MAG3110_IIC_ADDRESS,CTRL_REG1, n&0xFC|STANDBY_MASK);
}
/*********************************************************\
* Initialize MAG3110Q
\*********************************************************/
void MAG3110_Init (void)
{
MAG3110_Standby();
I2C_WriteOneByte(I2C1,MAG3110_IIC_ADDRESS,CTRL_REG1, DATA_RATE_5MS);
I2C_WriteOneByte(I2C1,MAG3110_IIC_ADDRESS,0x11, 0x00);
MAG3110_Active();
}
以下是24c02的头文件 :
#ifndef __24C02_H
#define __24C02_H
#define uchar unsigned char
#define uint unsigned int
#define byte unsigned char
#define word unsigned int
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#define byte unsigned char
/* Private define ------------------------------------------------------------*/
#define AT24C01A
//#define AT24C01
#define MAG3110_IIC_ADDRESS 0x1C
/***********************************************************************************************
**
** Variable type definition: BIT_FIELD
*/
typedef union
{
byte Byte;
struct {
byte _0 :1;
byte _1 :1;
byte _2 :1;
byte _3 :1;
byte _4 :1;
byte _5 :1;
byte _6 :1;
byte _7 :1;
} Bit;
} BIT_FIELD;
/***********************************************************************************************
**
** Variable type definition: tword
*/
typedef union
{
word mword;
struct
{
byte hi;
byte lo;
} mbyte;
} tword;
/***********************************************************************************************
**
** MAG3110Q Sensor Internal Registers
*/
enum
{
MAG3110_STATUS_00 = 0, // 0x00
MAG3110_OUT_X_MSB, // 0x01
MAG3110_OUT_X_LSB, // 0x02
MAG3110_OUT_Y_MSB, // 0x03
MAG3110_OUT_Y_LSB, // 0x04
MAG3110_OUT_Z_MSB, // 0x05
MAG3110_OUT_Z_LSB, // 0x06
MAG3110_WHO_AM_I, // 0x07
MAG3110_SYSMOD, // 0x08
MAG3110_OFF_X_MSB, // 0x09
MAG3110_OFF_X_LSB, // 0x0A
MAG3110_OFF_Y_MSB, // 0x0B
MAG3110_OFF_Y_LSB, // 0x0C
MAG3110_OFF_Z_MSB, // 0x0D
MAG3110_OFF_Z_LSB, // 0x0E
MAG3110_DIE_TEMP, // 0x0f
MAG3110_CTRL_REG1, // 0x10
MAG3110_CTRL_REG2, // 0x11
};
/*
** STATUS Registers
*/
#define STATUS_00_REG 0x00
//
#define ZYXOW_BIT Bit._7
#define ZOW_BIT Bit._6
#define YOR_BIT Bit._5
#define XOR_BIT Bit._4
#define ZYXDR_BIT Bit._3
#define ZDR_BIT Bit._2
#define YDR_BIT Bit._1
#define XDR_BIT Bit._0
//
#define ZYXOW_MASK 0x80
#define ZOW_MASK 0x40
#define YOR_MASK 0x20
#define XOR_MASK 0x10
#define ZYXDR_MASK 0x08
#define ZDR_MASK 0x04
#define YDR_MASK 0x02
#define XDR_MASK 0x01
/*
** XYZ Data Registers
*/
#define OUT_X_MSB_REG 0x01
#define OUT_X_LSB_REG 0x02
#define OUT_Y_MSB_REG 0x03
#define OUT_Y_LSB_REG 0x04
#define OUT_Z_MSB_REG 0x05
#define OUT_Z_LSB_REG 0x06
/*
** WHO_AM_I Device ID Register
*/
#define WHO_AM_I_REG 0x07
#define MAG3110Q_ID 0xC4
/*
** SYSMOD System Mode Register
*/
#define SYSMOD_REG 0x08
//
#define SYSMOD1_BIT Bit._1
#define SYSMOD0_BIT Bit._0
//
#define SYSMOD1_MASK 0x02
#define SYSMOD0_MASK 0x01
#define SYSMOD_MASK 0x03
#define STANDBY_MASK 0x00
#define ACTIVE_MASK 0x01
#define CORRECT_MASK 0x02
/*
** INT_SOURCE System Interrupt Status Register
*/
#define INT_SOURCE_REG 0x0C
//
#define SRC_ASLP_BIT Bit._7
#define SRC_FIFO_BIT Bit._6
#define SRC_TRANS_BIT Bit._5
#define SRC_LNDPRT_BIT Bit._4
#define SRC_PULSE_BIT Bit._3
#define SRC_FF_MT_1_BIT Bit._2
#define SRC_FF_MT_2_BIT Bit._1
#define SRC_DRDY_BIT Bit._0
//
#define SRC_ASLP_MASK 0x80
#define SRC_FIFO_MASK 0x40
#define SRC_TRANS_MASK 0x20
#define SRC_LNDPRT_MASK 0x10
#define SRC_PULSE_MASK 0x08
#define SRC_FF_MT_1_MASK 0x04
#define SRC_FF_MT_2_MASK 0x02
#define SRC_DRDY_MASK 0x01
/*
** XYZ Offset Correction Registers
*/
#define OFF_X_MSB 0x09
#define OFF_X_LSB 0x0A
#define OFF_Y_MSB 0x0B
#define OFF_Y_LSB 0x0C
#define OFF_Z_MSB 0x0D
#define OFF_Z_LSB 0x0E
#define DIE_TEMP 0x0F
/*
** CTRL_REG1 System Control 1 Register
*/
#define CTRL_REG1 0x10
//
#define DR2_BIT Bit._7
#define DR1_BIT Bit._6
#define DR0_BIT Bit._5
#define OS1_BIT Bit._4
#define OS0_BIT Bit._3
#define FR_BIT Bit._2
#define TM_BIT Bit._1
#define AC_BIT Bit._0
//
#define DR2_MASK 0x80
#define DR1_MASK 0x40
#define DR0_MASK 0x20
#define OS1_MASK 0x10
#define OS0_MASK 0x08
#define FR_MASK 0x04
#define TM_MASK 0x02
#define AC_MASK 0x01
#define ASLP_RATE_MASK 0xC0
#define DR_MASK 0x38
//
#define ASLP_RATE_20MS 0x00
#define ASLP_RATE_80MS ASLP_RATE0_MASK
#define ASLP_RATE_160MS ASLP_RATE1_MASK
#define ASLP_RATE_640MS ASLP_RATE1_MASK+ASLP_RATE0_MASK
//
#define DATA_RATE_1250US 0x00
#define DATA_RATE_2500US DR0_MASK
#define DATA_RATE_5MS DR1_MASK
#define DATA_RATE_10MS DR1_MASK+DR0_MASK
#define DATA_RATE_20MS DR2_MASK
#define DATA_RATE_80MS DR2_MASK+DR0_MASK
#define DATA_RATE_160MS DR2_MASK+DR1_MASK
#define DATA_RATE_640MS DR2_MASK+DR1_MASK+DR0_MASK
/*
** CTRL_REG2 System Control 2 Register
*/
#define CTRL_REG2 0x11
//
#define AUTO_MRST_EN_BIT Bit._7
#define RAW_BIT Bit._5
#define MAG_RST_BIT Bit._4
//
#define AUTO_MRST_EN_MASK 0x80
#define RAW_MASK 0x20
#define MAG_RST_MASK 0x10
/* Private function prototypes -----------------------------------------------*/
void I2C_Configuration(void);
uchar I2C_Read(I2C_TypeDef *I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t *buf,uint16_t num);
uint8_t I2C_Write(I2C_TypeDef *I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t *buf,uint16_t num);
uint8_t I2C_WriteOneByte(I2C_TypeDef *I2Cx,uint8_t I2C_Addr,uint8_t addr,uint8_t value);
void MAG3110_Init(void);
void MAG3110_Standby(void);
void MAG3110_Active(void);
#endif
以下是main.c文件
#include "stm32f10x.h"
#include "24C02.h"
#include <string.h>
#include <stdio.h>
#include <math.h>
#include "usart.h"
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
/* Private function prototypes -----------------------------------------------*/
void GPIO_Configuration(void);
long MAG3110_DataProcess (int MAG3110_XData,int MAG3110_YData);
void MAG3110_STD(void);
/*******************************************************************************
* Function Name : Delay
* Description : Delay Time
* Input : - nCount: Delay Time
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void Delay (uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
float MAG3110_XOFF=0,MAG3110_YOFF=0;
long MAG3110_XMax=0,MAG3110_YMax=0,MAG3110_XMin=0,MAG3110_YMin=0;
long MAG3110_XData=0,MAG3110_YData=0,MAG3110_ZData=0;
long ang;
/*******************************************************************************
* Function Name : main
* Description : Main program
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
int main(void)
{
int i;
//GPIO_Configuration();
uart_init(115200);
I2C_Configuration();
printf("\r\n****************************************************************\r\n");
MAG3110_Init(); //初始化MAG3110
/*******************************************************************************
芯片数据校正,写入的数值:校正后的数值=校正前的数值-写入的数值。用于读出数据过大超出65535。
应该将数值控制在0~3000之间最佳。
//
// I2C_WriteOneByte(I2C1,MAG3110_IIC_ADDRESS,OFF_X_MSB, 0xef);
// I2C_WriteOneByte(I2C1,MAG3110_IIC_ADDRESS,OFF_X_LSB, 0xff);
// I2C_WriteOneByte(I2C1,MAG3110_IIC_ADDRESS,OFF_Y_MSB, 0XF0);
// I2C_WriteOneByte(I2C1,MAG3110_IIC_ADDRESS,OFF_Y_LSB, 0x00);
*******************************************************************************/
i= I2C_Read(I2C1,MAG3110_IIC_ADDRESS,WHO_AM_I_REG,0,1);
if (i == MAG3110Q_ID) //确认初始化是否成功
{
printf("ID:MAG3110Q,OK!\n ");
}
else //初始化失败
{
printf("ID not identified,FAILED!\n");
//for(;;);//初始化失败,停止在这里
}
while(1)
{
Delay(0xfffff);
Delay(0xfffff);
i=I2C_Read(I2C1,MAG3110_IIC_ADDRESS,STATUS_00_REG,0,1);
if(i&ZYXDR_MASK) //数据就绪
{
MAG3110_STD(); //读取MAG3110数据,标定中值,数据处理
MAG3110_XData=~MAG3110_XData;
MAG3110_YData=~MAG3110_YData;
MAG3110_XData-=0xffff0000;
MAG3110_YData-=0xffff0000;
MAG3110_ZData-=0xffff0000;
if(MAG3110_XData>=0xf000)
{
MAG3110_XData-=0xf000;
}
if(MAG3110_YData>=0xf000)
{
MAG3110_YData-=0xf000;
}
if(MAG3110_ZData>=0xf000)
{
MAG3110_ZData-=0xf000;
}
if(MAG3110_XData>=0x500)
{
MAG3110_XData=MAG3110_XData-0xfff;
}
if(MAG3110_YData>=0x500)
{
MAG3110_YData=MAG3110_YData-0xfff;
}
if(MAG3110_ZData>=0x500)
{
MAG3110_ZData=MAG3110_ZData-0xfff;
}
// MAG3110_XData/=1.32299;
MAG3110_XOFF=-116.5;
MAG3110_YOFF=-83.5;
ang=atan2((double)(MAG3110_YData*0.99701+MAG3110_YOFF),(double)MAG3110_XData+MAG3110_XOFF) * (180 / 3.14159265) +180;
printf("The data needs to be calibrated, turning a lap");
printf("\r\n\r\n");
printf("\r\nPoint to the south angle:%d°\r\n",ang);
}
else //数据未就绪
{
printf("ID Failed!\n");
}
}
}
long MAG3110_DataProcess (int MAG3110_XData,int MAG3110_YData)
{
uint16_t MAG3110_Ang;
MAG3110_XData -= MAG3110_XOFF;
MAG3110_YData -= MAG3110_YOFF;
if (MAG3110_XData == 0)
{
if (MAG3110_YData>0)
{
MAG3110_Ang= 90;
} else{
MAG3110_Ang = 270;
}
}
else if (MAG3110_YData == 0)
{
if (MAG3110_XData>0)
{
MAG3110_Ang= 0;
}else{
MAG3110_Ang= 180;
}
}
else if ((MAG3110_XData > 0) && (MAG3110_YData > 0))
{
MAG3110_Ang = (atan ( ( (float)MAG3110_YData) / ( (float) MAG3110_XData ) ) )* 180 / 3.14;
}
else if ((MAG3110_XData < 0) && (MAG3110_YData > 0))
{
MAG3110_XData = -MAG3110_XData;
MAG3110_Ang = 180-(atan ( ( (float)MAG3110_YData) / ( (float)MAG3110_XData ) ) ) * 180 / 3.14;
}
else if ((MAG3110_XData < 0) && (MAG3110_YData < 0))
{
MAG3110_XData = -MAG3110_XData;
MAG3110_YData = -MAG3110_YData;
MAG3110_Ang = (atan ( ( (float)MAG3110_YData) / ( (float) MAG3110_XData ) ) )* 180 / 3.14 + 180;
}
else if ((MAG3110_XData > 0) && (MAG3110_YData < 0))
{
MAG3110_YData = -MAG3110_YData;
MAG3110_Ang = 360-(atan ( ( (float)MAG3110_YData) / ( (float)MAG3110_XData ) ) ) * 180 / 3.14;
}
return MAG3110_Ang;
}
/*************************************************************************/
void MAG3110_STD(void)
// 此函数需多次执行以保证旋转一圈中
{
// 能够采集到真实的最大值和最小值
tword wx, wy, wz;
static uint8_t First_Flag=0;
wx.mbyte.hi = I2C_Read(I2C1,MAG3110_IIC_ADDRESS,OUT_X_MSB_REG,0,1); //读取X轴高字节
wx.mbyte.lo = I2C_Read(I2C1,MAG3110_IIC_ADDRESS,OUT_X_LSB_REG,0,1);//读取X轴低字节
wy.mbyte.hi = I2C_Read(I2C1,MAG3110_IIC_ADDRESS,OUT_Y_MSB_REG,0,1);//读取Y轴高字节
wy.mbyte.lo = I2C_Read(I2C1,MAG3110_IIC_ADDRESS,OUT_Y_LSB_REG,0,1); //读取Y轴低字节
wz.mbyte.hi = I2C_Read(I2C1,MAG3110_IIC_ADDRESS,OUT_Z_MSB_REG,0,1);//读取Z轴高字节
wz.mbyte.lo = I2C_Read(I2C1,MAG3110_IIC_ADDRESS,OUT_Z_LSB_REG,0,1); //读取Z轴低字节
printf("X:%d ",wx.mbyte.hi*256+wx.mbyte.lo);
printf("Y:%d ",wy.mbyte.hi*256+wy.mbyte.lo);
printf("Z:%d ",wz.mbyte.hi*256+wz.mbyte.lo);
MAG3110_XData=wx.mbyte.hi*256+wx.mbyte.lo;
MAG3110_YData=wy.mbyte.hi*256+wy.mbyte.lo;
MAG3110_ZData=wz.mbyte.hi*256+wz.mbyte.lo;
if (!First_Flag)
{
MAG3110_XMax = MAG3110_XData;
MAG3110_XMin = MAG3110_XData;
MAG3110_YMax = MAG3110_YData;
MAG3110_YMin = MAG3110_YData;
First_Flag = 1;
}
if (MAG3110_XData > MAG3110_XMax)
{
MAG3110_XMax = MAG3110_XData;
}
else if (MAG3110_XData < MAG3110_XMin)
{
MAG3110_XMin = MAG3110_XData;
}
if (MAG3110_YData > MAG3110_YMax)
{
MAG3110_YMax = MAG3110_YData;
}
else if (MAG3110_YData < MAG3110_YMin)
{
MAG3110_YMin = MAG3110_YData;
}
MAG3110_XOFF = (MAG3110_XMax + MAG3110_XMin) / 2;
MAG3110_YOFF = (MAG3110_YMax + MAG3110_YMin) / 2;
ang=MAG3110_DataProcess(wx.mbyte.hi*256+wx.mbyte.lo,wy.mbyte.hi*256+wy.mbyte.lo);
}
/*******************************************************************************
* Function Name : GPIO_Configuration
* Description : Configure GPIO Pin
* Input : None
* Output : None
* Return : None
* Attention : None
*******************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC , ENABLE);
/**
* LED1 -> PC9 , LED2 -> PC10 , LED3 -> PC11 , LED4 -> PC12
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* Infinite loop */
while (1)
{
}
}
#endif
以上硬件iic是我从淘宝的模块资料里面拷贝的,有些删改。删改在数据处理的地方,对MAG3110数据处理或者数据输出有疑惑的可以直接看最下面,有我对数据的分析,当然以上代码可以直接单个使用,测试有效,可以和手机上的指南针媲美,但是只是水平放置的时候,(侵权联系删除)
**
模拟iic(需要包含正点原子的myiic.h才可以使用,使用PB6,7)
代码我是写在定时器中断里面的,需要另作修改的可以拷贝出代码出来,自行修改
以下是timer.c文件 (源代码是我从我的飞控代码上面拷贝过来的,需要的自行修改)
#include "timer.h"
#include "led.h"
#include "24C02.h"
#include "math.h"
#include "stdio.h"
#include "myiic.h"
#include "delay.h"
#include "MS5611.h"
float MAG3110_XOFF=0,MAG3110_YOFF=0,MAG3110_ZOFF=0;
long MAG3110_XMax=0,MAG3110_YMax=0,MAG3110_XMin=0,MAG3110_YMin=0;
long MAG3110_XData=0,MAG3110_YData=0,MAG3110_ZData=0;
long ang;
long MAG3110_DataProcess (int MAG3110_XData,int MAG3110_YData);
void MAG3110_STD(void);
float pitch,roll,yaw;
float altitude=0;
float xdata,ydata;
void TIM2_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能
//定时器TIM2初始化
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM2中断,允许更新中断
//中断优先级NVIC设置
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //TIM2中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //初始化NVIC寄存器
TIM_Cmd(TIM2, ENABLE); //使能TIMx
}
//定时器2中断服务程序
void TIM2_IRQHandler(void) //TIM2中断
{
int i;
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查TIM2更新中断发生与否
{
i=Read_MAG3110(STATUS_00_REG);
if(i&ZYXDR_MASK) //数据就绪
{
MAG3110_STD(); //读取MAG3110数据,标定中值,数据处理
MAG3110_XData=~MAG3110_XData;
MAG3110_YData=~MAG3110_YData;
MAG3110_XData-=0xffff0000;
MAG3110_YData-=0xffff0000;
MAG3110_ZData-=0xffff0000;
if(MAG3110_XData>=0xf000)
{
MAG3110_XData-=0xf000;
}
if(MAG3110_YData>=0xf000)
{
MAG3110_YData-=0xf000;
}
if(MAG3110_ZData>=0xf000)
{
MAG3110_ZData-=0xf000;
}
if(MAG3110_XData>=0xe00)
{
MAG3110_XData=MAG3110_XData-0xfff;
}
if(MAG3110_YData>=0xe00)
{
MAG3110_YData=MAG3110_YData-0xfff;
}
if(MAG3110_ZData>=0xe00)
{
MAG3110_ZData=MAG3110_ZData-0xfff;
}
// // MAG3110_XData/=1.32299;
MAG3110_XOFF=-116.5;
MAG3110_YOFF=-83.5;
MAG3110_ZOFF=440;
MAG3110_XData=MAG3110_XData+MAG3110_XOFF;
MAG3110_YData=MAG3110_YData+MAG3110_YOFF;//*0.99701
MAG3110_ZData=MAG3110_YData-MAG3110_ZOFF;
xdata=(float)(MAG3110_XData*cos(pitch*3.1415925/180)+MAG3110_YData*sin(roll*3.1415925/180)*sin(pitch*3.1415925/180)-MAG3110_ZData*cos(roll*3.1415925/180)*sin(pitch*3.1415925/180));
ydata=(float)(MAG3110_YData*cos(roll*3.1415925/180)+MAG3110_ZData*sin(roll*3.1415925/180));
//ydata=(float)(MAG3110_YData*cos(pitch)+MAG3110_XData*sin(roll)*sin(pitch)-MAG3110_ZData*cos(roll)*sin(pitch));
// xdata=(float)(MAG3110_XData*cos(roll)+MAG3110_ZData*sin(roll));
ang=atan2((double)(ydata),(double)xdata) * (180 / 3.14159265) ;
// printf(" x = %f ,y = %f z =%ld , ANG = %ld \r\n",xdata,ydata,MAG3110_ZData,ang); // 130 750
}
else //数据未就绪
{
}
MS561101BA_GetTemperature();//获取温度
MS561101BA_getPressure(); //获取大气压
altitude = 5716*(float)(Pressure/101325.0)*(Pressure/101325.0) - 18885*(float)(Pressure/101325.0) + 13181; ///获取气压通过定时器中断来读,每20ms读取一次
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除TIMx更新中断标志
LED1=!LED1;
}
}
long MAG3110_DataProcess (int MAG3110_XData,int MAG3110_YData)
{
uint16_t MAG3110_Ang;
MAG3110_XData -= MAG3110_XOFF;
MAG3110_YData -= MAG3110_YOFF;
if (MAG3110_XData == 0)
{
if (MAG3110_YData>0)
{
MAG3110_Ang= 90;
} else{
MAG3110_Ang = 270;
}
}
else if (MAG3110_YData == 0)
{
if (MAG3110_XData>0)
{
MAG3110_Ang= 0;
}else{
MAG3110_Ang= 180;
}
}
else if ((MAG3110_XData > 0) && (MAG3110_YData > 0))
{
MAG3110_Ang = (atan ( ( (float)MAG3110_YData) / ( (float) MAG3110_XData ) ) )* 180 / 3.14;
}
else if ((MAG3110_XData < 0) && (MAG3110_YData > 0))
{
MAG3110_XData = -MAG3110_XData;
MAG3110_Ang = 180-(atan ( ( (float)MAG3110_YData) / ( (float)MAG3110_XData ) ) ) * 180 / 3.14;
}
else if ((MAG3110_XData < 0) && (MAG3110_YData < 0))
{
MAG3110_XData = -MAG3110_XData;
MAG3110_YData = -MAG3110_YData;
MAG3110_Ang = (atan ( ( (float)MAG3110_YData) / ( (float) MAG3110_XData ) ) )* 180 / 3.14 + 180;
}
else if ((MAG3110_XData > 0) && (MAG3110_YData < 0))
{
MAG3110_YData = -MAG3110_YData;
MAG3110_Ang = 360-(atan ( ( (float)MAG3110_YData) / ( (float)MAG3110_XData ) ) ) * 180 / 3.14;
}
return MAG3110_Ang;
}
/*************************************************************************/
void MAG3110_STD(void)
// 此函数需多次执行以保证旋转一圈中
{
// 能够采集到真实的最大值和最小值
tword wx, wy, wz;
static uint8_t First_Flag=0;
wx.mbyte.hi = Read_MAG3110(OUT_X_MSB_REG); //读取X轴高字节
wx.mbyte.lo = Read_MAG3110(OUT_X_LSB_REG);//读取X轴低字节
wy.mbyte.hi = Read_MAG3110(OUT_Y_MSB_REG);//读取Y轴高字节
wy.mbyte.lo = Read_MAG3110(OUT_Y_LSB_REG); //读取Y轴低字节
wz.mbyte.hi = Read_MAG3110(OUT_Z_MSB_REG);//读取Z轴高字节
wz.mbyte.lo = Read_MAG3110(OUT_Z_LSB_REG); //读取Z轴低字节
MAG3110_XData=wx.mbyte.hi*256+wx.mbyte.lo;
MAG3110_YData=wy.mbyte.hi*256+wy.mbyte.lo;
MAG3110_ZData=wz.mbyte.hi*256+wz.mbyte.lo;
if (!First_Flag)
{
MAG3110_XMax = MAG3110_XData;
MAG3110_XMin = MAG3110_XData;
MAG3110_YMax = MAG3110_YData;
MAG3110_YMin = MAG3110_YData;
First_Flag = 1;
}
if (MAG3110_XData > MAG3110_XMax)
{
MAG3110_XMax = MAG3110_XData;
}
else if (MAG3110_XData < MAG3110_XMin)
{
MAG3110_XMin = MAG3110_XData;
}
if (MAG3110_YData > MAG3110_YMax)
{
MAG3110_YMax = MAG3110_YData;
}
else if (MAG3110_YData < MAG3110_YMin)
{
MAG3110_YMin = MAG3110_YData;
}
MAG3110_XOFF = (MAG3110_XMax + MAG3110_XMin) / 2;
MAG3110_YOFF = (MAG3110_YMax + MAG3110_YMin) / 2;
ang=MAG3110_DataProcess(wx.mbyte.hi*256+wx.mbyte.lo,wy.mbyte.hi*256+wy.mbyte.lo);
}
以下是timer.h文件
#ifndef __TIMER_H
#define __TIMER_H
#include "sys.h"
extern long MAG3110_XData,MAG3110_YData,MAG3110_ZData,ang;
extern float altitude;
extern float pitch,roll,yaw;
void TIM2_Int_Init(u16 arr,u16 psc);
#endif
(说明一下,以上中出现的变量pitch,yaw,roll是陀螺仪的输出数据,单位是角度制的,有陀螺仪的朋友可以把你的陀螺仪输出变量赋值给这三个,便可以在定时器中断里面计算航向角来稳定yaw了。这个可以抬起角度,但是会有一定影响,偏差在几度到十度的样子。)
主程序里面,在main 和while (1)中间需要插入初始化代码
IIC_Init();
printf("\r\n****************************************************************\r\n");
MAG3110_Init(); //初始化MAG3110
i= Read_MAG3110(WHO_AM_I_REG);
if (i == MAG3110Q_ID) //确认初始化是否成功
{
printf("ID:MAG3110Q,OK!\n ");
}
else //初始化失败
{
printf("ID not identified,FAILED!\n");
//for(;;);//初始化失败,停止在这里
}//i在这里没有定义,需要自己 int 一个 i出来就够了
while(1)里面可以跑空循环,因为我写在了定时器中断里面,或者while(1)里面干其他事情都可以。
数据输出和分析
问题分析:
在刚开始按照淘宝客服给的代码,直接移植过去,发现出现之前和hmc5883l一样的问题,那就是有一个轴的输出变化不大,或者根本没变化,但是有一个轴数据正常。(就论x, y轴而言)。
问题解决过程
对mag3110的输出,我按照数据手册上面的提示,对x,y,z三轴都施加了一个自测模式,具体见数据手册上面,有对相关寄存器的配置。并且同时开启了yaw模式。这时候,x,y轴的数据开始出现巨大的变化,按照所学知识,磁通量的确应该在垂直的时候发生巨大变化,但是变化不至于这么明显。查了下手册,数据在寄存器的存储,是用二进制的补码形式存在,并且按照adc的规则,最高位不是数据位,而是符号位才对。
所以在debug的时候,使用16进制显示,这时候才发现了问题。
我对x,y轴水平旋转一周收集了数据,如下图所示:
首先需要明白磁北和地北的区别,有一个夹角。
其次,原本16位的数据,应该是0xabcd 这种格式的数据,但是最高位被用去做了符号位,所以只能是0 或 F,图片中收集到的数据的确如此,证明了我的猜想。朋友们可以仔细看看数据跟随方位的变化,是有规律可循的。
再看下图,这是对x,y轴的增减做的分析,
这时候更能看出问题来了,可以看见x轴增加到最大或者减少到最小,跟y轴的恰好有90读的夹角。
所以在验证的猜想之后,在原有数据处理的基础上,我首先取补码,然后去掉最高位的0xffff0000,我的方法是如果带有符号位的,把它的符号位的0xf000减去,就得到了数据位。但是不能直接把人家的符号莫名其妙去掉把。所以后面如果大于0xe00的数,就是负数,需要再减去一个0xfff。所以刚开始总结的规律,它是从0xffff 往下减才得到的。所以只要知道那些几万的数据,是从0xffff往下减的,就有很多方法可以做了。我的是先去掉符号位,再用数据减去0xfff,其实有很多方法可以实现,我的其实方法很烂。
看不懂我的方法的,其实想明白,去掉因为补码导致的最高位变成0xffffxxxx 的类型,减去0xffff0000,就是后面的数据,而数据,如果大于了0xf000,那么就是说明它是个负数,并且如果算绝对值,它是和0xfffff的差值,而不是就是0xfxxx。
举个例子,0xff2e,其实值应该是0xff2e-0xffff才对,而不是debug显示出来的几万的数值。
MAG3110_XData=~MAG3110_XData;
MAG3110_YData=~MAG3110_YData;
MAG3110_XData-=0xffff0000;
MAG3110_YData-=0xffff0000;
MAG3110_ZData-=0xffff0000; //去掉因为补码导致的最高位置f
if(MAG3110_XData>=0xf000)
{
MAG3110_XData-=0xf000;
}
if(MAG3110_YData>=0xf000)
{
MAG3110_YData-=0xf000;
}
if(MAG3110_ZData>=0xf000)
{
MAG3110_ZData-=0xf000;
}
if(MAG3110_XData>=0xe00)
{
MAG3110_XData=MAG3110_XData-0xfff;
}
if(MAG3110_YData>=0xe00)
{
MAG3110_YData=MAG3110_YData-0xfff;
}
if(MAG3110_ZData>=0xe00)
{
MAG3110_ZData=MAG3110_ZData-0xfff;
}//得到真正的数据值
// // MAG3110_XData/=1.32299;
MAG3110_XOFF=-116.5;
MAG3110_YOFF=-83.5;
MAG3110_ZOFF=440; //这里是我所得到的修正值,旋转机体得到。
MAG3110_XData=MAG3110_XData+MAG3110_XOFF;
MAG3110_YData=MAG3110_YData+MAG3110_YOFF;//*0.99701
MAG3110_ZData=MAG3110_YData-MAG3110_ZOFF;
xdata=(float)(MAG3110_XData*cos(pitch*3.1415925/180)+MAG3110_YData*sin(roll*3.1415925/180)*sin(pitch*3.1415925/180)-MAG3110_ZData*cos(roll*3.1415925/180)*sin(pitch*3.1415925/180));
ydata=(float)(MAG3110_YData*cos(roll*3.1415925/180)+MAG3110_ZData*sin(roll*3.1415925/180)); //用陀螺仪数据融合输出。
最后再次说下数据不能正常输出的问题:
一 ,首先你可以调节一下配置寄存器2?比如配置上yaw模式,以及三个轴的自检。直到你观察到你的数据会随着你转动90°大幅变化,比如从几万变成了个位数,那就是数据输出没问题。
二,配置上三轴自检后,三轴的数据应该都是保持在6w多的幅度,随后把它关闭之后,在一个轴和磁感线平行的时候,应该也能达到6w多的数值,如果正交,可以变成个位数甚至0.
三,如果以上两步都行的话,那说明没有问题,源码里面我是关闭了yaw模式,感兴趣的也可以开启yaw模式看会怎么样。
(我目前在搞飞控相关的东西,如果感兴趣diy四轴飞行器的可以关注下我,我会更新下其他相关的传感器,以及相应的pid,或者adrc算法,以及卡尔曼滤波算法,欢迎各位捧个人场!)
如果不能解决的,可以私我,如果在的话我会帮你看一下的,虽然不一定能弄出来。淘宝上面的货真假不一,hmc5883l 和qmc5883l鱼龙混杂,mag3110也是乱七八糟的。
www.waveshare.net/wiki/MAG3110_Board (此链接是淘宝客服发给的,可以参考参考,内有代码,硬件iic代码,以及数据手册,侵权删)
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)