ラズベリーパイに二次元のコンパスセンサーHMC-6352を接続します。
このHMC-6352の出力は0〜3600までの0.1度間隔の方位を出力します。
// #################################################################
/* RaspberryPiのGPIOのI2Cに二次元のコンパスセンサーHMC-6352を接続する ★Raspberry Pi 接続図 GPIO PCA9306 HMC6352 (*注) pull-up 4.7kΩ ________________ _____________ 1 2 | | | | | 3.3v● ●__5v__| ● ● □ □ ●5V |__________________| | | _______ ___ __|__|_____●SCL SDA● ● | ● ● | |___________|______ ___ _____|_____●SDA | | | SCL● ●_G__ | ● ● ●G |_________|_| | | | ● ● | ● ● | 7 8 |_______________|___ ___________| PCA9306 :I2Cバス用双方向電圧レベル変換モジュール HMC6352 :デジタルコンパスモジュール *注)HMC6352は3.3vでも動作します。今回はRaspberryPiとコンパスを ケーブル(10m)で接続した為、5V変換とプルアップが必要となりました。 ★Raspberry Piのi2cドライバ ドライバを追加する 「/etc/modules」ファイルの最下段 snd-bcm2835 i2c-dev ← この行を追加 ★ブラックリストから削除する 「/etc/modprobe.d/raspi-blacklist.conf」ファイル # blacklist spi and i2c by default (many users don't need them) blacklist spi-bcm2708 #blacklist i2c-bcm2708 ← この行をコメントアウト ★上記の設定後Raspberry piを再起動 ★ i2cツールのインストール #apt-get install i2c-tools i2cデバイスのアドレスを調べる #i2cdetect -y 0 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- #i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- 21 -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- チャンネル1(/dev/i2c-1)のアドレス0x21に接続されている。 // ########################################################################## HMC-6352コンパスについて ・デバイスアドレスについて デフォルトのアドレスは「0x42」であり、識別されるアドレス「0x42」を 1ビット右にシフトした0x21である。 ・モード切替について Standbyモード: マスターデバイスから「A」(0x41)を送信することで方位を計測開始し データを読み取る Queryモード: 一旦「A」を送信後データを読み取る毎に自動的に計測/出力する Continuousモード: 設定した周期(1Hz,5Hz,10Hz,20Hz)で連続的に計測/出力した結果を読み取る ・モード切替方法 RAM書き込み用コマンド「G」(0x47)、書き込み先(レジスタ)の「0x74」、そして設定内容の [0x72」を送信する Bit 7=0 Bits 6 and 5((Continuous Mode Measurement Rate)0xx0 0000 bit6 bit5 Description 0 0 1Hz Measurement Rate 0 1 5Hz Measurement Rate 1 0 10Hz Measurement Rate 1 1 20Hz Measurement Rate Bit 4 (Periodic Set/Reset), 0=Off, 1=On Bit 3 = 0 Bit 2 = 0 Bits 1 and 0 (Operational Mode Value) bit1 bit0 Description 0 0 Standby Mode 0 1 Query Mode 1 0 Continuous Mode 1 1 Not Allowed The total bit format for the Operational Mode Byte is shown below: +---------+---------+---------+-------+----+----+---------+---------+ |Bit7(MSB)| Bit6 | Bit5 |Bit4 |Bit3|Bit2|Bit1 |Bit0(LSB)| |0 | M.Rate_H| M.Rate_L|Per.S/R|0 |0 |Op Mode_H|Op Mode_L| +---------+---------+---------+-------+----+----+---------+---------+ 0x50:Standbyモード(デフォルト) 0x51:Queryモード 0x52:Continuousモード(10Hz,Periodic Set/Reset=ON) 0x72:Continuousモード(20Hz,Periodic Set/Reset=ON) ############################################################################# */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <linux/i2c-dev.h> #include <fcntl.h> #include <sys/ioctl.h> // _nanosleep で使用 #include <sys/time.h> #include <time.h> struct tm *timeObject; #define MD_Standby 0x50 // HMC6352 command #define MD_Query 0x51 // HMC6352 command #define MD_Cont_10 0x52 // HMC6352 command #define MD_Cont_20 0x72 // HMC6352 command int I2c_FP = -1; // ファイルディスクリプタ。 //char *I2c_FileName = "/dev/i2c-0"; // I2Cドライバファイル名。 char *I2c_FileName = "/dev/i2c-1"; // I2Cドライバファイル名。 unsigned char I2c_wbuf[10],I2c_rbuf[10]; // バッファ。 int I2c_Address = 0x21; // I2C のアドレス。右1bitシフト。 //extern int close_6352(int fp); extern int setup_6352_mode(unsigned char mode); extern int get_6352_Standby(void); extern int enter_6352_Calibretion(void); extern int exit_6352_Calibretion(void); // ########################################################################## // ########################################################################## int32_t main(void){ int32_t ret; // #####Standby Mode で読み込み ret = setup_6352_mode(MD_Standby); if(ret < 0){ printf("MD_Standby setup error!!\n"); return; } ret = get_6352_Standby(); // close してある if(ret < 0){ printf("MD_Standby read error!!\n"); // return; } printf("Standby Mode read data=%d\n",ret); // 0〜3600の値 // #####Continuous Mode で読み込み ret = setup_6352_mode(MD_Cont_20); if(ret < 0){ printf("Continuous setup error!!\n"); return; } // ##### ret = get_6352_Continuous(); if(ret < 0){ printf("Continuous read error!!\n"); close(I2c_FP); return; } printf("Continuous Mode read-1 data=%d\n",ret); // 0〜3600の値 // ##### 連続read ret = get_6352_Continuous(); if(ret < 0){ printf("Continuous read error!!\n"); close(I2c_FP); return; } printf("Continuous Mode read-2 data=%d\n",ret); // 0〜3600の値 close(I2c_FP); return; // ####################################### // ##### キャリブレーション ############## /* ret = enter_6352_Calibretion(); if(ret < 0){ printf("Continuous read error!!\n"); return; } _nanosleep(10,0); // 10秒 delay // ##### コンパスを1周以上回す ######### ret = exit_6352_Calibretion(); */ // ####################################### // ####################################### } // ########################################################################## // ########################################################################## // ########################################################################## int close_6352(int fp){ close(fp); } // ########################################################################## // ########################################################################## // ########################################################################## int setup_6352_mode(unsigned char mode){ // 注意 closeしていない! int ret; I2c_wbuf[0] = 0x47; // RAM書き込み用コマンド I2c_wbuf[1] = 0x74; // レジスタアドレス I2c_wbuf[2] = mode; // モード // #####################################33 // I2CポートをRead/Write属性でオープン。 if(I2c_FP < 0)I2c_FP = open(I2c_FileName, O_RDWR); if(I2c_FP < 0)return(-1); // ######################################################### // 通信先アドレスの設定。 if (ioctl(I2c_FP, I2C_SLAVE, I2c_Address) < 0){ close(I2c_FP); return(-2); } // ######################################################### ret = write(I2c_FP,I2c_wbuf,3); // close(I2c_FP); if(ret < 0)return(-3); _nanosleep(0,70000); // 70us delay return(I2c_FP); } // ########################################################################## // ########################################################################## // ########################################################################## int get_6352_Continuous(void){ // int i,ret; if(I2c_FP < 0)I2c_FP = open(I2c_FileName, O_RDWR); if(I2c_FP < 0){ return(-1); } for(i = 0 ; i < 20 ; i++){ ret =read(I2c_FP, I2c_rbuf, 2); if(ret >= 0) break; } if(ret < 0){ return(ret); } return((I2c_rbuf[0] << 8) + I2c_rbuf[1]); } // ########################################################################## // ########################################################################## // ########################################################################## int get_6352_Standby(void){ int ret; // ######################################################### if(I2c_FP < 0)I2c_FP = open(I2c_FileName, O_RDWR); // I2CをR/W属性でopen if(I2c_FP < 0)return(-1); // I2CをR/W属性でopen // ######################################################### if (ioctl(I2c_FP, I2C_SLAVE, I2c_Address) < 0){ // 通信先アドレスの設定。 close(I2c_FP); I2c_FP = -1; return(-2); } // ######################################################### I2c_wbuf[0] = 0x41; ret = write(I2c_FP, I2c_wbuf,1); if(ret < 0){ close(I2c_FP); I2c_FP = -1; return(-3); } _nanosleep(0,6000000); // 6000us delay ret =read(I2c_FP, I2c_rbuf, 2); if(ret < 0){ close(I2c_FP); I2c_FP = -1; return(ret); } close(I2c_FP); I2c_FP = -1; return((I2c_rbuf[0] << 8) + I2c_rbuf[1]); } // ########################################################################## // ########################################################################## // ########################################################################## int enter_6352_Calibretion(void){ int ret; // ######################################################### if(I2c_FP < 0)I2c_FP = open(I2c_FileName, O_RDWR); // I2CをR/W属性でopen if(I2c_FP < 0)return(-1);// I2CをR/W属性でopen // ######################################################### if (ioctl(I2c_FP, I2C_SLAVE, I2c_Address) < 0){ // 通信先アドレスの設定。 close(I2c_FP); I2c_FP = -1; return(-2); } // ######################################################### I2c_wbuf[0] = 0x43; // Enter User Calibration ret = write(I2c_FP, I2c_wbuf,1); if(ret < 0){ close(I2c_FP); I2c_FP = -1; return(-3); } close(I2c_FP); I2c_FP = -1; _nanosleep(0,10000); // 10us delay return(0); } // ########################################################################## // ########################################################################## // ########################################################################## int exit_6352_Calibretion(void){ int ret; // ######################################################### if((I2c_FP = open(I2c_FileName, O_RDWR)) < 0)return(-1);// I2CをR/W属性でopen // ######################################################### if (ioctl(I2c_FP, I2C_SLAVE, I2c_Address) < 0){ // 通信先アドレスの設定。 close(I2c_FP); I2c_FP = -1; return(-2); } // ######################################################### I2c_wbuf[0] = 0x45; // Exit User Calibration ret = write(I2c_FP, I2c_wbuf,1); if(ret < 0){ close(I2c_FP); I2c_FP = -1; return(-3); } close(I2c_FP); I2c_FP = -1; _nanosleep(0,14000000); // 14000us delay return(0); } /**/ // ############################################################################ // ############################################################################ int32_t _nanosleep(int32_t sec, int32_t nsec){ struct timespec req, rem; req.tv_sec = sec; req.tv_nsec = nsec; rem.tv_sec = 0; rem.tv_nsec = 0; while(nanosleep(&req, &rem)){ if(errno == EINTR){ req.tv_sec = rem.tv_sec; req.tv_nsec = rem.tv_nsec; }else{ perror("nanosleep error"); return -1; } } return 0; }