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

本文来自 制造技术研究社 的投稿。
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控制头文件
标准库函数
文件控制头文件
Linux下的i2c驱动头文件 Linux下的i2c设备头文件 其次,定义一些产生的地址常数,
其中#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);
}


坐沙发

发表评论

你的邮件地址不会公开


*