STM32L010と超音波距離センサーHC-SR04でソフトウェアシリアルバイナリ通信




目的
I2Cだと約20cmから約30cmと伝送距離が短いので
シリアルを使い伝送距離(約2mから3m)を延ばす。



![o_con386.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/41f1896b-4d33-7596-b1c1-7dc58b12eb37.jpeg)




STM32L010のスレーブ



```c++



//ser_slave_HC_SR04_010_1


#include "mbed.h"


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


DigitalOut TX(PA_2);
DigitalIn  RX(PA_3);

#define UART_DELAY 101 //  1/9600 98-105


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

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

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

    return(0);
} //pc_putc


#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


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

//プロトタイプ宣言
void rx_Event();


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

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

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

    //GPIOの初期化
    TRIG = 0;


    int input_bk;
    int input;

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


        //開始信号の入力
        input = RX;

        //エッジ検出　信号が変わる
        //立ち上がり、立下りの検出
        if (input != input_bk) {

            //立下り
            if ( input == 0 ) {
                wait_ms(2); //空読み時間

                //b = '0';
                //putcNS(b);
                rx_Event();
            }//end if

        }//end if

        //信号の保存
        input_bk = input;

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

    }//while

}//main


void rx_Event()
{

    //ソフトウェアシリアルから距離を出力
    pc_putc(b);

    /*
        //I2Cスレーブの送信データの表示 num debug
        int d = b; //buf[0];
        //int d = b; //+ 60;
        //int d = ir_length;
        char data_read[4]; //バッファーの定義
        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
    //times = 1177;//debug 1ms 20.0cm
    //times = 942;//debug 1ms 16.0cm



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




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


    if ( distance <= 199 ) {

        b = distance - 60;

    } else {

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

    }//endif


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

}//rx_Event


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






```



Arduino UNOのマスター




```c++




#include <Arduino.h>

#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX


//初期化
void setup()
{

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

  //ソフトウェアシリアルの初期化
  mySerial.begin(9600);

} //setup


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

  int  l; //距離
  unsigned char b = 200;

  //読み込み
  mySerial.print("S");delay(5); //トリガーを投げる
  while( mySerial.available() ){
    //Serial.println( mySerial.available() );//debug
    b = mySerial.read();//受信
    //Serial.println( b );//debug
  }//while  
  if( b <= 0   ) b=0;
  if( b >= 200 ) b=200;

  //レンジ圧縮 140までは、mm 140からは、cm
  if( b <= 139 ) {
    l = b + 60;
  } else {
    l = ((int)(b - 140 + 20)) * 10;
  }

  Serial.print("800,");

  Serial.print( l ); //UNO

  Serial.print(",0");
  Serial.println(" ");

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

} //loop





```