戻る

二次元のコンパスセンサーHMC-6352を接続する           2013.9.26

ラズベリーパイに二次元のコンパスセンサー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;
}


トップに戻る