本文是树莓派爱好者投稿文章,授权树莓派爱好者基地发放,请勿转载!否则承担相应法律责任!
本文作者 微信公众号:制造技术研究社 如果对作者有兴趣或者对本文有什么异议或者疑问可以与作者联系沟通。
本文的打赏收入将全部转给作者,同时欢迎各位树莓派的爱好者在树莓派爱好者基地投稿,给大家分享你的好经验和教程!!!稿件可以发送给下面的邮箱!让我们一起共建树莓派生态圈
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);
}