STM32L010のI2Cスレーブモードで超音波距離センサーHC-SR04の値をマスターで受信する。





x I2Cのプルアップも必要
x 超音波は、測定に時間が掛るからウェートに注意　高速連続読みは、不可 60msぐらいは、みたほうがいい
x スレーブの値は、1個前の値　I2Cではよくある作り　気になる人は、空読み


目的
I2Cのテスト
距離センサーのI2C化
I2C間通信の応用
超音波距離センサーHC-SR04を使い距離を測る。


![o_con350.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/c3013771-d227-fd1d-55e9-093113777aa3.jpeg)


忙しい人よう


https://os.mbed.com/users/caa45040/code/i2c_slave_HC_SR04_010_1/


バイナリー


https://os.mbed.com/users/caa45040/code/f303_h_p1//file/a047b389adfd/i2c_slave_HC_SR04_010_BIN/


スレーブのプログラム

mbed2リビジョン130


```c++


//i2c_slave_ir_length_010_1


#include "mbed.h"


//10の割り算 0から1028までは、正しい。主に0から999
#define DIV10(n) ((n*205)>>11)


#define HIGH 1
DigitalOut TRIG(PA_6);
DigitalIn  ECHO(PA_5);


//タイマーの設定
Timer t;

unsigned long times; //測定時間
int distance;        //長さ


//PA_5のオン時間をusで測る　今のところ引数は、無効
int pulseIn(int pin1,int pu1,int timeout1)
{

    t.reset();//タイマーの開始

    //timeout1 = 32000000;
    timeout1 = 100000;    //28ms
    //timeout1 = 1000;   //degbu

    //while(PA_5 == 0) {}

loop_s1:
    timeout1--;
    //                            5432109876543210
    if (     (~(GPIOA->IDR))  & 0b0000000000100000     ) {
        if ( timeout1 ) {
            goto loop_s1;
        }
    }


    int sd = t.read_us();//測定開始

    //timeout1 = 32000000;
    timeout1 = 100000;     //28ms
    //timeout1 = 1000;   //degbu

    //while(PA_5 != 0) {}

loop_in1:
    timeout1--;
    //                      5432109876543210
    if (   (GPIOA->IDR) & 0b0000000000100000   ) {
        if( timeout1 ) {
            goto loop_in1;
        }
    }

 
    return(t.read_us()-sd);//測定終了

}//pulseIn



/*
DigitalOut TX(PB_1);

//仮想シリアルへの一文字出力 1200bps
int pc_putc(char ch)
{
    TX=1;
    TX=0;//Start
    wait_us(832);

    for(int ii=0; ii<8; ii++) { //Data x 8
        TX=(ch>>ii)&1;
        wait_us(832);
    }; //for

    TX=1;//Stop
    wait_us(832);

    return(0);
} //pc_putc
*/


unsigned char b=200; //マスターに返す値

//I2Cの初期化
I2CSlave slave(PA_10, PA_9); //010

//メインルーチン
int main()
{

    //タイマーの開始
    t.start();

    //GPIOの初期化
    TRIG = 0;

    //TX=1; //ポートの初期化

    char buf[10];//I2Cバッファー

    //I2Cスレーブのアドレスの設定
    slave.address(0x10);

    //無限ループ
    while(1) {

        //I2Cの状態の読み出し(ポーリング)
        while(  slave.receive()  == I2CSlave::ReadAddressed   ) {};

        //b = 40; //debug
        buf[0] = b;

        //I2Cマスターに送信する
        slave.write(buf,1);

        /*

                //I2Cスレーブの送信データの表示 num debug
                int d = b; //buf[0];
                char data_read[3]; //バッファーの定義
                data_read[3] = 0;
                data_read[2] = '0' + (  d - (DIV10(d) * 10)  );  // '0'+(d%10)
                d = DIV10(d);
                data_read[1] = '0' + (  d - (DIV10(d) * 10)  );  // '0'+(d%10)
                data_read[0] = '0' +  DIV10(d);                  // '0'+(d/10)
                pc_putc(data_read[0]);
                pc_putc(data_read[1]);
                pc_putc(data_read[2]);
                pc_putc('\r');
                pc_putc('\n');
        */

        // 超音波を発生させる
        TRIG=1;
        wait_us(10);
        TRIG=0;

        // 超音波を受け取る
        times = pulseIn( 5, HIGH,2000000);

        //times = (unsigned long)7700/2; //debug

        //distance = (int)(times * 0.017);
        distance = (int)((times * ((unsigned long)(17))) / 100);


        if(distance <= 60   ) {
            distance = 60;
        }
        if(distance >= 800 ) {
            distance = 800;
        }

        if ( distance <= 199 ) {

            b = distance - 60;

        } else {

            b = (unsigned char)(   DIV10(distance)-20+140 );

        }


        //0.5秒の待ち
        //wait_ms(500);

    }//while

}//main


//容量削減
void error(const char* format, ...) {}







```


マスターのプログラム

mbed2リビジョン125



```c++




//i2c_master_ir_length_031_1

#include "mbed.h"

//I2C i2c(I2C_SDA, I2C_SCL); //767
//I2C i2c(dp5, dp27); //1114
I2C i2c(PA_10, PA_9); //010


//Serial pc(USBTX, USBRX); // tx, rx
//Serial pc(SERIAL_TX, SERIAL_RX); //767
RawSerial pc(PA_2, PA_3); //010

//#define S5851A 0x48
#define ADDR        (0x10)   //  address

int main() {

    char data_read[8]; //バッファー

    //無限ループ
    while(1){

        //dataの読み込み
        i2c.read(ADDR, data_read,1,false);

        //データの保存
        int b =  data_read[0]; //dataの転記
        if(b >= 200) {b = 200;}
        if(b <= 0)   {b = 0;  }
        
        
        //レンジ圧縮で140でレンジ切り替え
        int l;
        if( b <= 139 ) {
            l = b + 60;
        } else {
            l = ((int)(b - 140 + 20)) * 10;
        }  
        

        //画面に表示
        //pc.printf("Read : %x\r\n",l);
        //pc.printf("Read : %d\r\n",l);
        pc.printf("%d\r\n",l);

        //0.5秒待つ
        wait_ms(500);

    }//while

}//main

//容量削減
void error(const char* format, ...){}






```





関連 Arduinoのマスタープログラム



```c++



//i2c_master_HC_SR04_UNO_1

//インクルド
#include <Arduino.h>
#include <Wire.h>

//初期化
void setup()
{

  //シリアルポートの初期化(9600bps)
  Serial.begin(9600);

  //I2Cの初期化
  Wire.begin(); //UNO

} //setup


//メインループ
void loop()
{

  int  l;                //距離
  unsigned char b = 200; //レンジ圧縮の値

  //I2C読み込み
  Wire.requestFrom(8, 1);
  while(Wire.available())  { // 要求より短いデータが来る可能性あり
    b = Wire.read();         // 1バイトを受信
  }//while

  //レンジ圧縮をして8ビット(256)に収める
  //60mm から　200mmまでは、1mm単位
  //60mm = 0 , 200mm = 140
  //200mm から　800mmまでは、1cm単位
  //200mm =140 ,  800mm = 200
  if( b <= 139 ) {
    l = b + 60;
  } else {
    l = ((int)(b - 140 + 20)) * 10;
  }//endif

  //距離の表示
  Serial.print("800,");
  Serial.print( l ); //UNO
  Serial.print(",0");
  Serial.println(" ");
  delay(500); // 0.5秒の待ち

} //loop




```