树莓派和HMC5883(QMC5883)的使用方法

本文是树莓派爱好者投稿文章,授权树莓派爱好者基地发放,请勿转载!否则承担相应法律责任!

本文作者 微信公众号:制造技术研究社 如果对作者有兴趣或者对本文有什么异议或者疑问可以与作者联系沟通。

本文的打赏收入将全部转给作者,同时欢迎各位树莓派的爱好者在树莓派爱好者基地投稿,给大家分享你的好经验和教程!!!稿件可以发送给下面的邮箱!让我们一起共建树莓派生态圈

HMC5883是霍尼韦尔公司生产的一款地磁场检测芯片,其国产替代产品为QMC5883。这两种芯片基本相似,QMC 5883也是号称得到了霍尼韦尔公司的授权。
两款芯片在外观上没有明显的区别,本人在某宝上购买的QMC系列芯片上居然堂而皇之写着HMC5883,如果两者搞混了,就难得出正确结果。
网上有很多采用单片机虚拟i2c总线读取数据的例程,也有采用Python读取i2c总线数据的例子,但是如何利用linux系统中直接用C语言来读取数据的例子比较少,而且不是全面。很多专业的linux系统书籍中偏重于介绍如何编写i2c总线驱动程序,较少介绍如何直接利用系统中现有的命令读取数据。
本文主要介绍如何利用树莓派(Linux系统,3B+和4B+型号都通用)下读取5883系列传感器的数据,直接调用Linux系统中的指令来读取i2c总线上的数据。

硬件连接

首先HMC 5883模块具有4个引脚,Vcc、GND、SCL和SDA,分别连接到树莓派对应的引脚,Vcc接树莓派的5V电源即可,SCL和SDA接到i2c-1总线上(注意,请不要接到0号i2c总线上,需要进行另外设置才能打开该总线)。

开启总线,安装i2ctool工具

连接成功之后,首先要打开i2c总线,在树莓系统默认中是关闭i2c总线的,可以通过raspi-config配置界面中的interface开启(enable)i2c总线。
开启总线后,还需要安装i2ctool工具,才方便调试i2c总线,这是一个很小的工具。在控制台输入:
sudo apt-get install i2c-tools命令即可安装i2c-tools。
安装完成后可以使用i2cdetect -l查看i2c总线开启情况:


使用i2cdetect -y 1命令即可扫描接在总线上的所有I2C设备,并打印出该设备的I2C总线地址。


这时,显示了该总线上挂载了一个设备,地址为0x0d,0x0d(二进制为0000 1101)是QMC 5883的7位地址,(注意:HMC 5883的7位地址是0x1e,这是两种芯片的第一处不同。)
数据手册上会说到8位地址,8位地址是这样计算的:将7位地址左移1位,读地址为末位加1,则对应的8位地址为0x1b(二进制为0001 1011 ),写地址为末位加0,则对应的8位地址为0x1A(二进制为0001 1010 )。但是利用linux系统自带的驱动程序不需要使用8位地址,7位地址就足够了。
另外微信公众号“制造技术研究社”觉得几个有用的指令是:
1、查看数据:i2cdump -f -y 1 0x0d 查看0d地址下所有地址上的数据
2、写寄存器:i2cset -f -y 1 0x0d 0x09 0x01 设置相应寄存器的数值,这里是向地址为0x0d设备下的0x09地址写入0x01这个数据。

QMC 5883和HMC 5883的芯片设置

QMC 5883需要设置0x09,0x0B、0x20、0x21这四个寄存器的内容,其中0x0B是置位复位的周期,默认值为0x01, 0x09是控制寄存器,bit0和bit1控制采样模式,分别为连续模式和等待模式,00是等待,01是连续模式,bit2和bit3是采集速率,bit4和bit5是测量范围,00为正负2高斯,01为正负8高斯,bit6,bit7是过采样率,这里是说多采集一些数据,得平均值的意思,这里可以不管。总之0x09的默认配置为0x0d或者0x1d。总结以上,QMC 5883需要配置的寄存器为:(值得吐槽的是,0x20和0x21寄存器是一定需要设置的,但是这个点在datasheet里面居然没有说明!)
芯片地址0x09数据为=0x0d/0x1d;
芯片地址0x0B数据为= 0x01;
芯片地址0x20数据为= 0x40;
芯片地址0x21数据为= 0x01;
根据测试的需求,很明显需要先配置这四个寄存器。
而对于HMC 5883需要配置3个寄存器,也就是i2c设备的头三个地址0x00、0x01、0x02,分别被称为配置寄存器A、配置寄存器B,模式寄存器,配置寄存器A设置过采样率和测试频率,配置寄存器B设置增益大小(放大系数、检测数据和磁场值的转换系数);模式寄存器是设置采样模式。
详细的配置说明可以参见数据手册,也可以联系微信公众号:“制造技术研究社”,留言获得。
总之,HMC 5883的配置参数可以按照以下内容:

define HMC5883_CRA 0x14 采样频率30Hz

define HMC5883_CRB 0xe0 测量范围正负8.1高斯

define HMC5883_MR 0x00 连续测量模式

QMC 5883和HMC 5883的测量数据

QMC 5883的数据存储在0x00-0x05连续6个地址,0x00是x方向的低8位数据,0x01是x方向的高8位数据;0x02是Y方向的低8位数据,0x03是Y方向的高8位数据;0x04是Z方向的低8位数据,0x05是Z方向的高8位数据;
HMC 5883的数据存储在0x03-0x08连续6个地址,顺序为XZY,(这又是不同点),0x03是x方向的高8位数据,0x04是x方向的高8位数据(高低次序也不同),其余类推。
所以只要将这些数据读取出来,就可以实现对磁场的测量。

调用linux驱动程度读取数据

以上全部为准备知识,只有清楚认识了5883系列芯片,才能正确读写芯片。虽然网上有些利用wringPi程序来读取i2c总线的方法,但是没有关于如何采用C语言编程读写芯片的例子,下面以QMC 5883的读取程序为例,详细讲解如何用C语言调用i2c总线驱动程序。
首先C语言头文件要包含基本输入输出函数stdio.h、
io控制头文件<sys/ioctl.h>
标准库函数<unistd.h>
文件控制头文件 <fcntl.h>
Linux下的i2c驱动头文件<linux/i2c.h>
Linux下的i2c设备头文件<linux/i2c-dev.h>
其次,定义一些产生的地址常数,
其中#define QMC5883 "/dev/i2c-1"是linux系统的特色,将所有的设备看作挂载的路径,

define Gain 12000 是配置数据和磁场值的转换系数,在文末解释了如何计算磁场和系数。

第三部分 i2c读写函数及流程
在检测之前,先要将配置数据写入设备中,以写入0x09寄存器和0x0B寄存器为例,

首先获得文件ID,
int fd=open(QMC5883,O_RDWR);
通过open函数,就获得了文件的ID,其中O_RDWR是系统自定义的宏,表示以读写模式打开文件,open( )函数的返回值是一个大于0的数,被称之为文件ID(file_ID),如果返回值为0,或者负数,说明读写文件出现了问题。
在后面的程序中,只要调用file_ID,就可以实现了对接口的调用。
注意,在读取结束,要close文件。

第二步是定义一个数组QMC5883_init_config_1[4],
QMC5883_init_config_1[4]={0x09,QMC5883_0x09,0x00,QMC5883_0x0B};
数组的第一个值是0x09,表示i2c设备的子地址(寄存器的地址),就是说在从第9个地址开始写入,顺序将后面的数据写入设备,该数组后面的数据就是需要配置的值,分别为0x0d、0x00、0x01,执行该指令后,linux系统驱动程序会在0x09地址之后,陆续写入这3个数,(其中地址0x0A的数据不需要写入,这里写进去只是为了方便。)

接着定义另一个数组,配置其他寄存器
QMC5883_init_config_2[3]={0x20,QMC5883_0x20,QMC5883_0x21};
完成了四个寄存器的配置,接下来将读写指针调回到数据地址的首地址,
定义一个无符号数suba,unsigned char suba=0 这个数的指针提出来,写入文件,读写指针就回到了0x00位置。

第三步是读取数据,
读取数据的函数为read(),其格式和write()很相似
unsigned char QMC5883_read_data[6];
read(fd,QMC5883_read_data,8);
XYZ三个方向的数据分别存在连续的6个地址内,将低8位(LSB)的数据左移8位,再和高8位“求或运算”就得到了测量的磁场数据。
最后将数据显示出来就可以了。

在这里插入图片描述
在这里插入图片描述

注:这里通过while循环,实现连续不断的测量,想要中止的话,按下Ctrl+C跳出循环,中止程序即可。
HMC 5883的读写方式也与此类似,可以对照写出程序,也可以联系微信公众号“制造技术研究社”,进一步交流相关内容。
总结:
读写5883系列传感器,关键是掌握linux系统下设备的读写,首先要掌握传感器的配置内容,其次一定要注意各个地址的区别,在正确的地址读写正确的内容。
附1:磁场的计算
传感器测出的数据为一个整型数据hpx,当测量范围为2Guass的时候,增益系数为12 000,那么磁场值为hpx/12000(Guass)
注意,磁场强度的单位为A/m,在空气中,A/m和高斯的转换关系为1高斯=79.62A/m,可以继续转换为磁场强度作为单位。
注意二:整型数和实数之间还要注意数据类型的转换。
附2:源代码

/************************************************/
/* *Magnetic testing Program                                                */
/* Edit by: Doctor Han in HFUT                                             */
/* Date:2019.12.23                                                                  */
/************************************************/

#include <stdio.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#define QMC5883 "/dev/i2c-1"
#define QMC5883_ADDR 0x0d  //adress
#define QMC5883_0x0B 0x01            //set/reset period
#define QMC5883_0x20 0x40             //unkown configration
#define QMC5883_0x21 0x01             //unkown configration
#define QMC5883_0x09 0x0d             //Configration

#define Gain 12000

int main()
{
      //printf("Testing by QMC5883L (From i2c Bus)\n");
      int fd=open(QMC5883,O_RDWR);
      int i;
      int Num=1;
      unsigned char QMC5883_init_config_1[4]={0x09,QMC5883_0x09,0x00,QMC5883_0x0B};
      unsigned char QMC5883_init_config_2[3]={0x20,QMC5883_0x20,QMC5883_0x21};
      unsigned char suba=0;
      unsigned char QMC5883_read_data[6];
      //unsigned char QMC5883_write_data_buff[4]={0,QMC5883_CRA,QMC5883_CRB,QMC5883_MR};
      double Hx,Hy,Hz,Temp;
      short int  hpx,hpy,hpz,temp;

      if(fd<0)
      {
             printf("Open QMC5883 failed\n");      
      }

      if(ioctl(fd,I2C_SLAVE_FORCE,QMC5883_ADDR)<0)
      {    
             printf("Address fault\n");
             close(fd);
      }

      //while(1)
      //{
             write(fd,QMC5883_init_config_1,4);
             write(fd,QMC5883_init_config_2,3);
             write(fd,&suba,1);
             read(fd,QMC5883_read_data,8);  
             hpx=*QMC5883_read_data;
             hpx=*(QMC5883_read_data+1)<<8|hpx;
             hpy=*(QMC5883_read_data+2);
             hpy=*(QMC5883_read_data+3)<<8|hpy;
             hpz=*(QMC5883_read_data+4);
             hpz=*(QMC5883_read_data+5)<<8|hpz;
             printf("No=%d ",Num);
             //printf("Hx=%d ;Hy=%d ;Hz=%d \n",hpx,hpy,hpz);
             Hx=hpx*79.61/Gain;
             Hy=hpy*79.61/Gain;
             Hz=hpz*79.61/Gain;
             Temp=temp*1.00/100;
             Num=Num+1;
             printf("Hx=%f A/m; Hy=%f A/m; Hz=%f A/m;\n",Hx,Hy,Hz);

      //}
      return 0;
             close(fd);
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容