0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

e2studio开发磁力计LIS2MDL(2)----电子罗盘

嵌入式单片机MCU开发 来源:嵌入式单片机MCU开发 作者:嵌入式单片机MCU开 2024-05-16 17:00 次阅读

概述

本文将介绍如何使用 LIS2MDL 传感器来读取数据来转化为指南针。 地磁场强度范围约为 23,000 至 66,000 nT ,并且可以建模为磁偶极子,其场线起源于地球地理南部附近的点,并终止于磁场附近的点。磁场具有七个分量,如图 所示。x,y和z分别表示北分量,东分量和垂直分量的磁场强度。H代表总水平强度,F代表磁场的总强度,而D和I分别代表磁偏角和磁倾角。

最近在弄ST和瑞萨RA的课程,需要样片的可以加群申请:615061293 。

使用硬件

视频教学

[https://www.bilibili.com/video/BV1zi4y1q7Sr/]

样品申请

[https://www.wjx.top/vm/OhcKxJk.aspx#]

源码下载

[https://download.csdn.net/download/qq_24312945/88722925]

环境磁场建模

尽管可以选择七个不同的元素来处理给定点的磁场,但并非所有元素都是进行定位的理想选择。X,Y 和 Z 的三个元素是从磁力计获得的基本值,而其他四个元素是使用这些元素来计算的。前三个元素随移动设备方位角的改变而偏离,因此,对于许多基于磁场的室内定位系统通常假设以固定方位工作,行人可以更改方向,但不能更改设备方位。
在大地坐标系的水平面上,假设磁北和x轴的夹角为a, x方向的磁分量是Mx,y方向的分量是My,则
ɑ=arctan(My/Mx)
这是电子罗盘定向的基本原理。实际应用中,电子罗盘不能总是保持在水平面上,如下图所示一样存在俯仰角和横滚角。将罗盘坐标系下的 z轴向下, 3个轴的磁分量投影到水平面上可以得到Xh,Yh,相应的磁感应值:
Xh=Xcosф+Ysinфsinθ - Zsinфcosθ
Yh=Ycosθ + Zsinθ
相应的
ɑ=arctan(Yh/Xh)

Angle_XY=atan2( (magnetic_mG[1]-Xoffset),(magnetic_mG[0]-Yoffset) ) * (180/3.14159265)+180;//计算角度
                Angle_XZ=atan2( (magnetic_mG[2]-Zoffset),(magnetic_mG[0]-Yoffset) ) * (180/3.14159265)+180;//计算角度
                Angle_YZ=atan2( (magnetic_mG[2]-Zoffset),(magnetic_mG[1]-Yoffset) ) * (180/3.14159265)+180;//计算角度

消除硬铁误差

电子罗盘有两种工作模式,一种是正常工作模式,另一种是出厂设置模式,这种出场设置模式就是为了消除硬铁干扰。硬铁干扰产生于永久磁铁,和被磁化的金属,或罗盘平台上的钢。这些干扰会保持大小恒定,与罗盘的相对位置固定,而与罗盘指向无关。所以当罗盘安装好后,它周围的硬铁干扰就几乎不会改变了,只要对罗盘做一次准确的标定,就能很轻松的消除这项干扰。
硬铁干扰在罗盘输出的每个轴向加了一个定值,输出曲线图的圆心被移动了,对于航向的影响则是一个周期性的误差,如下图所示在理想状态时,在 360 度范围内,传感器输出极值分别为 ymax ymin xmax xmin 坐标原点为O,受到硬铁干扰后,极值变为 y’max ,y’min , x’max , x’max , 坐标原点变为O’ 。要消除硬铁干扰,可以将罗盘和平台旋转一周,得
到圆上的足够的点再得到圆心偏移。

具体操作过程如下:接通电源后,将罗盘匀速旋转,使微控制器采集 360 °范围内的数据,通过数值比较,找出 x 、 y 方向的极值,得出偏移坐标 O’, 即电桥的偏置电压,并将此电压值保存,每次罗盘读数时都会减去此偏移。实际上,本设计在方位角的计算过程就是此过程,所以在计算方位角的同时已经消除了硬铁干扰。这种方法也可以消除由于温度漂移产生的误差。

软铁干扰

软铁干扰来源于地球磁场和罗盘附近的任何磁性材料之间的相互作用,同硬铁材料一样,软金属也干扰地球的磁力线,不同点是,软磁的干扰程度,与罗盘的方向有关。对软铁干扰的校正,比较复杂,下面讨论采用霍尼韦尔公司的 Michal.J.Caruso 提出椭圆假设的误差补偿原理进行误差补偿的方法 。

根据 Michal.J.Caruso 的研究,罗盘在理想的没有任何干扰的磁场水平面里作圆形旋转时,磁力计的显示应该呈现上图的状态,其中圆中心在 0,0 点处,每个计数代表 67微高斯,在 X 和 Y 平面中的地球磁场强度值读到 2800 个计数,约为 190 毫高斯,根据下面公式可以对每个读数确定一个方位角。

如果将磁力计安装在有发动机或者其他铁磁材料的环境中,圆形旋转时,磁力计的显示应该下图的状态。

这里的图形不是一个圆 ( 有点椭圆 ) ,而它偏移 0,0 点为 -480 和 -795 个计数,这偏移和椭圆效应是干扰磁场对地球磁场作用的结果。通过确定两个定标因数 Xsf 和 Ysf 可以将椭圆改为圆。随后计算偏移值 Xoff 和 Yoff, 将圆中心定在 0,0 原点,用下面公式来计算 Y,X 值。

X 值 =Xsf×X 读数 +Xoff
Y 值 =Ysf×Y 读数 +Yoff

这里的定标因数 Xsf 和 Ysf 可由下述方法获得。
①将罗盘在水平面做旋转运动
②找出 X 和 Y 读数的最大值和最小值
③用这四个数值确定 X 和 Y 定标因数 (Xsf , Ysf) ,以及零偏移值 (Xoff , Yoff)

Xsf=1 或 (Y 最大 -Y 最小 )/2(X 最大 -Y 最小 )

以较大的数值为准

Ysf=1 或 (X 最大 -Y 最小 )/2(Y 最大 -Y 最小 )

以较大的数值为准

Xoff=[(X 最大 -X 最小 ) /2-X 最大 ]×Xsf
Yoff=[(Y 最大 -Y 最小 ) /2-Y 最大 ]×Ysf

演示

主程序

在主程序中添加开机校准。

#include "hal_data.h"

#include < stdio.h >
#include "lis2mdl_reg.h"

fsp_err_t err = FSP_SUCCESS;
volatile bool uart_send_complete_flag = false;
void user_uart_callback (uart_callback_args_t * p_args)
{
    if(p_args- >event == UART_EVENT_TX_COMPLETE)
    {
        uart_send_complete_flag = true;
    }
}


/* Callback function */
i2c_master_event_t i2c_event = I2C_MASTER_EVENT_ABORTED;
uint32_t  timeout_ms = 100000;
void sci_i2c_master_callback(i2c_master_callback_args_t *p_args)
{
    i2c_event = I2C_MASTER_EVENT_ABORTED;
    if (NULL != p_args)
    {
        /* capture callback event for validating the i2c transfer event*/
        i2c_event = p_args- >event;
    }
}



#ifdef __GNUC__                                 //串口重定向
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
        err = R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);
        if(FSP_SUCCESS != err) __BKPT();
        while(uart_send_complete_flag == false){}
        uart_send_complete_flag = false;
        return ch;
}

int _write(int fd,char *pBuffer,int size)
{
    for(int i=0;i< size;i++)
    {
        __io_putchar(*pBuffer++);
    }
    return size;
}

FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER


#define SENSOR_BUS g_i2c_master0_ctrl

/* Private macro -------------------------------------------------------------*/
#define    BOOT_TIME        20 //ms

/* Private variables ---------------------------------------------------------*/
static int16_t data_raw_magnetic[3];
static int16_t data_raw_temperature;
static float magnetic_mG[3];
static float temperature_degC;
static uint8_t whoamI, rst;
static uint8_t tx_buffer[1000];

/* Extern variables ----------------------------------------------------------*/

/* Private functions ---------------------------------------------------------*/
/*
 *   WARNING:
 *   Functions declare in this section are defined at the end of this file
 *   and are strictly related to the hardware platform used.
 *
 */
static int32_t platform_write(void *handle, uint8_t reg, const uint8_t *bufp,
                              uint16_t len);
static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp,
                             uint16_t len);
static void tx_com(uint8_t *tx_buffer, uint16_t len);
static void platform_delay(uint32_t ms);
static void platform_init(void);






/*******************************************************************************************************************//**
 * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function
 * is called by main() when no RTOS is used.
 **********************************************************************************************************************/
void hal_entry(void)
{
    /* TODO: add your own code here */


    /* Open the transfer instance with initial configuration. */
       err = R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
       assert(FSP_SUCCESS == err);

       printf("hello world!n");

       R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_14, BSP_IO_LEVEL_HIGH);
       /* Initialize the I2C module */
       err = R_IIC_MASTER_Open(&g_i2c_master0_ctrl, &g_i2c_master0_cfg);
       /* Handle any errors. This function should be defined by the user. */
       assert(FSP_SUCCESS == err);

       /* Initialize mems driver interface */
       stmdev_ctx_t dev_ctx;
       dev_ctx.write_reg = platform_write;
       dev_ctx.read_reg = platform_read;
       dev_ctx.handle = &SENSOR_BUS;

       /* Wait sensor boot time */
       platform_delay(BOOT_TIME);

       /* Check device ID */
       lis2mdl_device_id_get(&dev_ctx, &whoamI);
       printf("LIS2MDL_ID=0x%x,whoamI=0x%xn",LIS2MDL_ID,whoamI);
       if (whoamI != LIS2MDL_ID)
         while (1) {
           /* manage here device not found */
         }

       /* Restore default configuration */
       lis2mdl_reset_set(&dev_ctx, PROPERTY_ENABLE);

       do {
         lis2mdl_reset_get(&dev_ctx, &rst);
       } while (rst);

       /* Enable Block Data Update */
       lis2mdl_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);
       /* Set Output Data Rate */
       lis2mdl_data_rate_set(&dev_ctx, LIS2MDL_ODR_10Hz);
       /* Set / Reset sensor mode */
       lis2mdl_set_rst_mode_set(&dev_ctx, LIS2MDL_SENS_OFF_CANC_EVERY_ODR);
       /* Enable temperature compensation */
       lis2mdl_offset_temp_comp_set(&dev_ctx, PROPERTY_ENABLE);
       /* Set device in continuous mode */
       lis2mdl_operating_mode_set(&dev_ctx, LIS2MDL_CONTINUOUS_MODE);

       int Xmax=0,Xmin=0;
       int Ymax=0,Ymin=0;
       int Zmax=0,Zmin=0;

       int i=0;

       int Xoffset,Yoffset,Zoffset;
       float angle;
       static float Angle_XY;
       static float Angle_XZ;
       static float Angle_YZ;
       static float Xsf;
       static float Ysf;
       static float Zsf;
       while (1)
       {

         uint8_t reg;
         /* Read output only if new value is available */
         lis2mdl_mag_data_ready_get(&dev_ctx, ®);

         if (reg) {
           /* Read magnetic field data */
           memset(data_raw_magnetic, 0x00, 3 * sizeof(int16_t));
           lis2mdl_magnetic_raw_get(&dev_ctx, data_raw_magnetic);
           magnetic_mG[0] = lis2mdl_from_lsb_to_mgauss(data_raw_magnetic[0]);
           magnetic_mG[1] = lis2mdl_from_lsb_to_mgauss(data_raw_magnetic[1]);
           magnetic_mG[2] = lis2mdl_from_lsb_to_mgauss(data_raw_magnetic[2]);
//           printf("Magnetic field [mG]:%4.2ft%4.2ft%4.2frn",magnetic_mG[0], magnetic_mG[1], magnetic_mG[2]);

//           /* Read temperature data */
//           memset(&data_raw_temperature, 0x00, sizeof(int16_t));
//           lis2mdl_temperature_raw_get(&dev_ctx, &data_raw_temperature);
//           temperature_degC = lis2mdl_from_lsb_to_celsius(data_raw_temperature);
//           printf("Temperature [degC]:%6.2frn",temperature_degC);

           printf("i=%d,Magnetic field [mG]:%4.2ft%4.2ft%4.2frn",i,magnetic_mG[0], magnetic_mG[1], magnetic_mG[2]);
                  if(i< 500)
                  {
                      i++;
                      if(magnetic_mG[0]< Xmin)
                          Xmin=magnetic_mG[0];
                      else if(magnetic_mG[0] >Xmax)
                          Xmax=magnetic_mG[0];


                      if(magnetic_mG[1]< Ymin)
                          Ymin=magnetic_mG[1];
                      else if(magnetic_mG[1] >Ymax)
                          Ymax=magnetic_mG[1];

                          if(magnetic_mG[2]< Zmin)
                          Zmin=magnetic_mG[2];
                      else if(magnetic_mG[2] >Zmax)
                          Zmax=magnetic_mG[2];
                  }
                  else if(i==500)
                  {
                      i++;


                      Xsf = (Ymax - Ymin) / (Xmax - Xmin);
                      Ysf = (Xmax - Xmin) / (Ymax - Ymin);
                      if (Xsf < 1)
                              Xsf = 1;
                      if (Ysf < 1)
                              Ysf = 1;

                      Xoffset=( (Xmax-Xmin)/2 - Xmax) *Xsf;
                      Yoffset=( (Ymax-Ymin)/2 - Ymax) *Ysf;
      //              Zoffset=( (Zmax-Zmin)/2 - Zmax) *Xsf;

                  }
                  else
                  {
                      Angle_XY=atan2( (magnetic_mG[1]-Yoffset),(magnetic_mG[0]-Xoffset) ) * (180/3.14159265)+180;//计算角度
                      printf("Angle_XY=%3.2fn",Angle_XY);
      //              Angle_XZ=atan2( (magnetic_mG[2]-Zoffset),(magnetic_mG[0]-Xoffset) ) * (180/3.14159265)+180;//计算角度
      //              Angle_YZ=atan2( (magnetic_mG[2]-Zoffset),(magnetic_mG[1]-Yoffset) ) * (180/3.14159265)+180;//计算角度
      //              printf("Angle_XY=%3.2f,Angle_XZ=%3.2f,Angle_YZ=%3.2fn",Angle_XY,Angle_XZ,Angle_YZ);
                  }
         }
         R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);
       }






#if BSP_TZ_SECURE_BUILD
    /* Enter non-secure code */
    R_BSP_NonSecureEnter();
#endif
}

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 传感器
    +关注

    关注

    2537

    文章

    48878

    浏览量

    743669
  • 电子罗盘
    +关注

    关注

    1

    文章

    121

    浏览量

    23176
  • 磁力计
    +关注

    关注

    1

    文章

    60

    浏览量

    20662
收藏 人收藏

    评论

    相关推荐

    磁力计LIS2MDL开发(1)----轮询获取磁力计数据

    本文将介绍如何使用 LIS2MDL 传感器来读取数据。主要步骤包括初始化传感器接口、验证设备ID、配置传感器的数据输出率和滤波器,以及通过轮询方式持续读取磁力数据和温度数据。读取到的数据会被转换为适当的单位并通过串行通信输出。
    的头像 发表于 12-18 10:56 979次阅读
    <b class='flag-5'>磁力计</b><b class='flag-5'>LIS2MDL</b><b class='flag-5'>开发</b>(1)----轮询获取<b class='flag-5'>磁力计</b>数据

    磁力计LIS2MDL开发(2)----电子罗盘

    本文将介绍如何使用 LIS2MDL 传感器来读取数据来转化为指南针。
    的头像 发表于 12-18 11:01 939次阅读
    <b class='flag-5'>磁力计</b><b class='flag-5'>LIS2MDL</b><b class='flag-5'>开发</b>(2)----<b class='flag-5'>电子</b><b class='flag-5'>罗盘</b>

    e2studio开发磁力计LIS2MDL(1)----轮询获取磁力计数据

    本文将介绍如何使用 LIS2MDL 传感器来读取数据。主要步骤包括初始化传感器接口、验证设备ID、配置传感器的数据输出率和滤波器,以及通过轮询方式持续读取磁力数据和温度数据。读取到的数据会被转换
    的头像 发表于 05-16 16:54 795次阅读
    <b class='flag-5'>e2studio</b><b class='flag-5'>开发</b><b class='flag-5'>磁力计</b><b class='flag-5'>LIS2MDL</b>(1)----轮询获取<b class='flag-5'>磁力计</b>数据

    有没有办法用LIS2MDL检测溢出?

    问候我正在使用LIS2MDL为教育市场构建磁场传感器。当测量的磁场超过最大允许值时,我注意到LIS2MDL返回不可预测的数据而不是0x7fff(32767)或0x8000(-32768)。有没有
    发表于 09-25 17:16

    LSM9DS1磁力计的自检是否与LIS3MDL相同

    我正在尝试在LSM9DS1传感器上测试磁力计。我可以应用与LIS3MDL指南针相同的自测范围值来检查LSM9DS1吗?事实是LSM9DS1中的磁力计似乎是LIS3MDL(寄存器的相同文
    发表于 10-09 11:43

    LIS2MDL上设置新阈值后是否需要最少时间?

    嗨,我试图在LIS2MDL上动态配置中断阈值。似乎有时在设置新阈值后,旧阈值仍然有效并导致输出引脚上的中断转换。在LIS2MDL上设置新阈值后是否需要最少(稳定)时间?谢谢。以上来自于谷歌翻译以下
    发表于 03-04 14:44

    LIS2MDL偏移取消问题

    这是他们的初始化代码: i2c_LIS2MDL_Read_8Bit(LIS2MDL_WHO_AM_I,&amp; b); i2c_LIS2MDL
    发表于 03-29 09:57

    如何在LIS3MDL磁力计传感器中禁用DRDY和INT输出

    你好,如何在LIS3MDL磁力计传感器中禁用DRDY和INT输出。 #lis3mdl以上来自于谷歌翻译以下为原文 Hello,How to disable DRDY and INT outputs in
    发表于 04-17 14:17

    无法将LIS2MDL置于低功耗模式

    你好,我在传感器集线器模式下使用LSM6DSL和LIS2MDL,使用IKS01A2中的示例我已经设法激活LIS2MDL并从中读取数据。我目前的问题是我无法将LIS2MDL置于低功耗模式
    发表于 04-26 14:39

    LIS3MDL三轴磁力计能满足磁通密度为0.23高斯的应用程序吗

    我正在研究在具有高频振荡磁场的应用中使用 LIS3MDL 3 轴磁力计。我查看了 LIS3MDL 的数据表,它似乎满足我检查过的大多数要求。我的应用程序的磁通密度为 0.23 高斯,处于磁力计
    发表于 12-14 08:31

    用于生成每个输出样本的样本数量而言LIS3mdl磁力计的操作模式有何不同?

    就用于生成每个输出样本的样本数量而言,LIS3mdl 磁力计的操作模式有何不同?例如,我发现在 ISM303DAC 中,用于生成的样本数输出样本在低功耗模式下比在低功耗模式下使用的数量少四倍高分辨率
    发表于 01-06 07:31

    LIS2MDL轴标签是否指示正轴方向?

    LIS2MDL 数据表的图 2 显示了磁力计轴方向的下图。但是,完全不清楚它们是否标记了轴的正方向。如果他们确实用 X/Y/Z 标签标记了正方向,它就会有一个左手方向(违反所有惯例)。轴标签是否指示正轴方向?这是左手坐标系吗?
    发表于 01-09 08:56

    STLIS2MDL磁力计传感器相关的使用信息和应用提示

    LIS2MDL是系统级封装的3D数字磁力计,具有数字I²C和3线SPI串口标准输出,在高分辨率模式下功耗200 µA,在低功耗模式下功耗不超过50 µA(在20 Hz输出数据速率下)。由于磁力计具有超低噪声性能,始终具有低功耗特
    发表于 09-06 08:24

    LIS2MDL磁力计传感器相关资料

    LIS2MDL进行配置,使其产生用于磁场检测的中断信号,并自动补偿由较高应用层提供的硬铁偏移。LIS2MDL的ST软件支持包括驱动、倾斜补偿的电子罗盘、动态
    发表于 09-13 07:48

    LIS2MDL 3D数字磁力计应用笔记

    电子发烧友网站提供《LIS2MDL 3D数字磁力计应用笔记.pdf》资料免费下载
    发表于 07-31 10:12 4次下载
    <b class='flag-5'>LIS2MDL</b> 3D数字<b class='flag-5'>磁力计</b>应用笔记