本文是樹莓派愛好者投稿文章,授權樹莓派愛好者基地發放,請勿轉載!否則承擔相應法律責任!
本文作者 微信公眾號:制造技術研究社 如果對作者有興趣或者對本文有什么異議或者疑問可以與作者聯系溝通。
本文的打賞收入將全部轉給作者,同時歡迎各位樹莓派的愛好者在樹莓派愛好者基地投稿,給大家分享你的好經驗和教程?。?!稿件可以發送給下面的郵箱!讓我們一起共建樹莓派生態圈
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是過采樣率,這里是說多采集一些數據,得平均值的意思,這里可以不管??傊?x09的默認配置為0x0d或者0x1d。總結以上,QMC 5883需要配置的寄存器為:(值得吐槽的是,0x20和0x21寄存器是一定需要設置的,但是這個點在datasheet里面居然沒有說明?。?br>
芯片地址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);
}