STM32L010で超音波距離センサーHC-SR04 ソフトウェアシリアル出力


x センサーからの値を取得失敗すると無限ループで暴走する　修正済み


目的
超音波距離センサーのテスト


![o_con326.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/01a39e08-3fe4-8101-f6e3-6a2ddf367264.jpeg)



![o_con328.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/1fd209fd-1acf-0b41-95ab-fd3969c48590.jpeg)

![o_con329.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/cd9567cd-1b4d-9fc3-9cc6-ec9e39ac136e.jpeg)


![o_con330.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/1ddb422d-aa21-a8ce-9c1a-9ad848ab1115.jpeg)



いろいろ
取得失敗対策をしないと致命的
カウンターからデクリメントして0でループぬけが
ソフトでやるなら最適だか初期カウンター値が不明

クロックは、内部RCを使っているが精度がどのくらいなのか不明
RCは、温度に比例するから温度で補正してあげればいいが定数が不明

六畳間で遊ぶ事を考えると約90cm X 4 = 約360cm
約3～4mでようが足りる
1秒間に340m , 0.1秒に34m , 0.01秒に3.4m
10mS X 2(往復) = 20mSでようが足りる
カウントアップしてオーバーフローして0で抜ける?

32Mカウントぐらいにセットしておけば論理値1秒でカウントアップする


メインプログラム



```c++



//ser_s_HC_SR04_010_2

#include "mbed.h"

#include "SER_9600_010_1.h"

#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;}
    }



    //led1 = 1;//debug

    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;}
    }

    //led1 = 0;//debug

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


}//pulseIn


//メイン関数
int main()
{

    //シリアルの初期化
    pc.baudNS(9600);

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

    //GPIOの初期化
    TRIG = 0;

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

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

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

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

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



        //データの表示

        //前の0を削る
        //  0123  add
        // [1234] data
        int yy;
        if     (distance >= 1000) {yy = 0;}
        else if (distance >= 100) {yy = 1;}
        else if (distance >= 10)  {yy = 2;}
        else                      {yy = 3;}
        
        pc.printNS( (char *)(ch_hex_a(distance)+yy) );
        //pc.printNS(  distance );
        pc.printNS( "\r\n" );

        wait_ms(500);

    }//loop

}//main

//void error(const char* format, ...) {}



```






SER_9600_010_1.hのプログラム



```c++


//SER_9600_010.h

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

char ch_hex_a_b[16];
char *ch_hex_a(int x)
{

    ch_hex_a_b[4] = 0;

    if       ( x >= 9000 ) {x = x - 9000; ch_hex_a_b[0] = '9';
    } else if( x >= 8000 ) {x = x - 8000; ch_hex_a_b[0] = '8';
    } else if( x >= 7000 ) {x = x - 7000; ch_hex_a_b[0] = '7';
    } else if( x >= 6000 ) {x = x - 6000; ch_hex_a_b[0] = '6';
    } else if( x >= 5000 ) {x = x - 5000; ch_hex_a_b[0] = '5';
    } else if( x >= 4000 ) {x = x - 4000; ch_hex_a_b[0] = '4';
    } else if( x >= 3000 ) {x = x - 3000; ch_hex_a_b[0] = '3';
    } else if( x >= 2000 ) {x = x - 2000; ch_hex_a_b[0] = '2';
    } else if( x >= 1000 ) {x = x - 1000; ch_hex_a_b[0] = '1';
    } else                 {              ch_hex_a_b[0] = '0';
    }//if

    ch_hex_a_b[3] = '0' + (  x - (DIV10(x) * 10)  );  // 3  <- 120 - 123
    x = DIV10(x);                                     // 12 <= 123 / 10
    ch_hex_a_b[2] = '0' + (  x - (DIV10(x) * 10)  );  // 2  <- 12 - 10
    ch_hex_a_b[1] = '0' +  DIV10(x);                  // 1  <- 12 / 10

    return(ch_hex_a_b);

} //ch_hex_a


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

DigitalOut TX(PA_2);

//クラスの定義
struct _pc
{
  void baudNS(int sp);      //メソッドの宣言
  int  putcNS(char ch);      //メソッドの宣言
  int  printNS(char *str1);  //メソッドの宣言
  int  printNS(int num);     //メソッドの宣言 オーバーロード
};


//ポートをhiにする 初期化
//メソッドの定義
void _pc::baudNS(int sp)
{
  TX=1;
  wait_ms(1);
}//baudNS


//仮想シリアルへの一文字出力 9600bps
//メソッドの定義
int _pc::putcNS(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);
}//putcNS


//文字列の表示
//メソッドの定義
int _pc::printNS(char *str1)
{
    //文字の中身がゼロか
    while(*str1) {

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

    } //while

    //戻り値
    return(0);  
}//printNS


//文字列の表示 オーバーロード 4桁
//メソッドの定義
int _pc::printNS(int num)
{
    if(num < 0) { putcNS('-'); num = 0 - num;   }
    
    char *str1 = ch_hex_a(num);
    
    //文字の中身がゼロか
    while(*str1) {

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

    } //while

    //戻り値
    return(0);  
}//printNS


//実体の作成
_pc pc;




```



タイムアウト修正前


```c++



//ser_s_HC_SR04_010_1

//SER_LB_9600_010_1

#include "mbed.h"

#include "SER_9600_010_1.h"

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

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

unsigned long times;
int distance;


//in1のオン時間をusで測る　今のところ引数は、無効
int pulseIn(int pin1,int pu1,int timeout1)
{
    t.reset();//タイマーの開始

///    //while(in1 != 0) {}
///
///    loop_ins:
///    //                      5432109876543210
///    if (   (GPIOA->IDR) & 0b0000000000100000   ) { goto loop_ins;}
///
///    //while(in1 == 0) {}

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

    //led1 = 1;//debug

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


    //while(in1 != 0) {}

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

    //led1 = 0;//debug

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


}//pulseIn


//メイン関数
int main()
{

    //シリアルの初期化
    pc.baudNS(9600);

    t.start();

    TRIG = 0;

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


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

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

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



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



        //データの表示
        //String thisString9 = String( distance );
        //pc.printNS( (char *)thisString9.c_str() );

        //前の0を削る
        //  0123  add
        // [1234] data
        int yy = 0;
        if     (distance >= 1000) {
            yy = 0;
        } else if (distance >= 100) {
            yy = 1;
        } else if (distance >= 10)  {
            yy = 2;
        } else                      {
            yy = 3;
        }

        pc.printNS( (char *)(ch_hex_a(distance)+yy) );
        //pc.printNS(  distance );
        pc.printNS( "\r\n" );

        wait_ms(500);

    }//loop

}//main

//void error(const char* format, ...) {}





```