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





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


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


![o_con344.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e8ca5010-f8a8-68f0-880b-4d2b30ce762d.jpeg)


![o_con345.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/56c7ac3e-9dea-90b4-ae17-20c3e5ffb971.jpeg)

-346

![o_con346.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/5a17ef3b-ad59-6e46-fa1a-b8c00943d1c2.jpeg)



![o_con398.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/f3b7aac1-31c6-9274-8054-b22baad030e8.jpeg)




レンジ圧縮の値の一覧

200の値に6cmから80cmまでを都合よく割り当てる
20cmでレンジ切り替えが発生する。

![o_con388.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/e77bb30c-82fe-069b-9b78-033439f340d2.jpeg)



OB(オプションビット)関連
NRST_MODE →　2

![o_con389.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/2cb9b860-b3be-183c-e6a1-c6b7841eaf18.jpeg)

![o_con390.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/aa151fb0-2c31-a871-cc21-0228705244a4.jpeg)


![o_con391.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/a4e5db9d-6edb-6c56-d2bd-25a5c31eadcf.jpeg)


忙しい人よう　バイナリー
環境構築してコンパイルなんかしている暇がない!!
STM32G031J6M6のI2Cスレーブ用のバイナリー
フォーマットは、インテルヘキサ

https://os.mbed.com/users/caa45040/code/f303_h_p1//file/80158340a5dd/i2c_slave_HC_SR04_031_BIN/



![o_con393.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/8b3075d4-d79f-2a54-4397-26bc9281de02.jpeg)



![o_con394.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/5af9ec8b-9466-58cc-17b4-d9c578d76855.jpeg)


![o_con395.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/cb4b9798-e2f7-abc4-fdad-af1c475b6074.jpeg)


![o_con396.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/d75ff2c8-b6d5-4461-6c11-c903ba2ad44c.jpeg)



関連 Arduinoのマスター


https://qiita.com/caa45040/items/a5bda8060367fea08e4a


いろいろ　
現在2022/4/23 16:45 ちょうどいいから　めし　いってくるわ
取得に時間がかかるからI2C系は、少なくてお値段が高いわ!!
光系の赤外線も音系の超音波もmm単位で精度は、さして変わらないが
反応速度と範囲の切れが赤外線の方が優れている
超音波は、ふわっとしている

超音波の処理を割り込みでやろうとすると処理が複雑になるわ
タイム割り込みで裏で一定間隔で取りに行って
値をどこかに格納しておけば、
いつでも値を使えるわ

1/100秒で10ms , 50ヘルツで20ms , 3.4mで0.01秒(10ms)
1/10秒(100ms)ぐらいで裏で割り込みをかけて値は、随時、変数から
ちょつと　がんばつて　みるか
●複数の場合は、干渉の問題が出るからこれは、これでOK
●単独使用の場合は、常時スレーブで超音波の距離測定
をしてI2C割り込みで最新の値を返す。loop文に測定を書くだけ
●もしくは、マスターで50msぐらいで割り込みを掛けて値を取りに行く



●stm32l010スレーブのmbedの時は、1msぐらいの割り込みでI2Cのチェックして最新の値を返す。
mainで常時、超音波測定
●もしくは、マスターで50msぐらいで割り込みを掛けて値を取りに行く

まず先に光系の赤外線のSTM32L010のスレーブを作るか?


sTM32G031スレーブのプログラム


```c++


//i2c_slave_HC_SR04_031_1


#include <Arduino.h>
#include <Wire.h>


#define TRIG PA0
#define ECHO PB7

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


void setup() {

  pinMode(TRIG, OUTPUT); digitalWrite(TRIG, LOW);
  pinMode(ECHO, INPUT);

  //I2Cの初期化
  Wire.begin(PA12, PA11); //stm32g031
  
  Wire.begin(8);// Slave ID #8
  Wire.onRequest(requestEvent);

}//setup


byte b=200; // ((s-140)*10)+200 -> 800


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


void loop() {
}//loop


void requestEvent() {

  Wire.write(b);


  // 超音波を発生させる
  digitalWrite(TRIG, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG, LOW);

  // 超音波を受け取る
  times = pulseIn(ECHO, HIGH,2000000);
  //times = (unsigned long)(7700/2); //debug 650cm

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


  //レンジ圧縮をして8ビット(256)に収める
  //60mm から　200mmまでは、1mm単位
  //60mm = 0 , 200mm = 140
  //200mm から　800mmまでは、1cm単位
  //200mm =140 ,  800mm = 200

  //オーバーの値を丸める
  if( distance >= 800 ){ distance = 800;}
  if( distance <= 60  ){ distance = 60 ;}

  // 200mmより　小さいか?
  if ( distance <= 199 ) {

  b = distance - 60;

  } else {

  b = (byte)( DIV10(distance)-20+140 );//DIV10(x)==x/10
  
  }

  //b = 200;//debug
  
}//requestEvent




```


STM32G031マスタープログラム




```c++



//i2c_master_HC_SR04_031_1

#include <Arduino.h>
#include <Wire.h>

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

#define in7      PA0  // 4pin

#define DW   digitalWrite

#define UART_DELAY 102   //  9600bps ok 031


//仮想シリアルへの一文字出力 9600bps
int pc_putc(char ch) {

  DW(in7, HIGH);

  DW(in7, LOW);//START
  delayMicroseconds(UART_DELAY);

  for (int ii = 0; ii < 8; ii++) {
    DW(in7, (ch >> ii) & 1  );
    delayMicroseconds(UART_DELAY);
  }//for

  DW(in7, HIGH);//Stop
  delayMicroseconds(UART_DELAY);

  return (0);

}//pc_putc


//文字列の表示
int pc_printf(char *str1) {

  //文字の中身がゼロか
  while (*str1) {

    //一文字出力
    pc_putc(*str1 ++);

  } //while

  //戻り値
  return (0);

}//pc_printf


//初期化
void setup()
{

  //ポートをhiにする 初期化
  pinMode(in7, OUTPUT);
  DW(in7, HIGH);

  //I2Cの初期化
  Wire.begin(PA12, PA11); //stm32g031

} //setup


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

  char data_read[8]; //バッファー
  int  l;
  unsigned char b = 200;

  //読み込み
  Wire.requestFrom(8, 1);

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

  if( b <= 139 ) {
    l = b + 60;
  } else {
    l = ((int)(b - 140 + 20)) * 10;
  }

  //前の0を削る
  //  012  add
  // [123] data
  int yy;
  if      (l >= 100) {yy = 0;}
  else if (l >= 10)  {yy = 1;}
  else               {yy = 2;}

  //表示
  data_read[3] = 0;
  data_read[2] = '0' + (  l - (DIV10(l) * 10)  );  // '0'+(b%10)
  l = DIV10(l);
  data_read[1] = '0' + (  l - (DIV10(l) * 10)  );  // '0'+(b%10)
  data_read[0] = '0' +  DIV10(l);                  // '0'+(s/10)

  pc_printf("800,");

  pc_printf( ((char *)(data_read + yy )) ); //031

  pc_printf(",0");
  pc_printf("\r\n");

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

} //loop




```



関連 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





```