組み込みコンテストの予備調査 - (3) 外部超音波距離センサー

測距機能を使用するため、外部測距センサーに慣れ、測距精度を検討する必要があります。

ヒント: 記事を作成した後、目次を自動的に生成できます。生成方法は、右側のヘルプドキュメントを参照してください。


序文

ペリフェラルの場合は、まず mounriver Studio を使用してペリフェラル ライブラリを追加し、関連関数を記述してメイン プログラムで測距関数を完成させる方法を学ぶ必要があります。

1.超音波センサー HC-SR04

外部超音波は、振動周波数が 20KHZ を超える機械波です。高周波、短波長、回折現象が少なく、指向性が良く、光線のように指向性を持って伝播できるという特徴があり、大学生、エンジニア、技術者、電子愛好家などに広く使用されています。

新バージョン HC-SR04 の性能は旧バージョン HC-SRO4 および US-015 をはるかに上回り、測距精度が旧バージョン HC-SRO4 および US-015 よりも高くなると、測距範囲がさらに遠くなります。一般的な超音波測距モジュールをはるかに上回る最大6メートル。CS-100A超音波測距SOCチップを使用し、高性能、工業用グレード、広電圧、低価格、通常の超音波測距モジュールのわずか半分の価格で、性能は通常の超音波測距モジュールをはるかに上回ります。性能はUS-025と同じで、両方ともCS100Aチップを採用しており、インターフェースは完全な互換性があります。
ここでは拡張インターフェースのPD10とPD11を選択します。

超音波 HC-SR04 モジュール:
VCC --> VCC
GND --> GND
Trig --> PD10
Echo --> PD11

2. 動作原理

Trig (トリガー) ピンは、超音波パルスをトリガーするために使用されます。

エコー 反射信号を受信すると、ピンはパルスを生成します。パルスの長さは、送信信号の検出に必要な時間に比例します。

少なくとも 10 µS (10 マイクロ秒) の持続時間のパルスがトリガー ピンに印加されると、すべてが始まります。これに応答して、センサーは 40 KHz で 8 パルスの音響パルスを発します。したがって、8 パルス パターンにより、受信機は周囲の超音波ノイズから送信パターンを区別できるようになります。

8 つの超音波パルスが送信機から離れて空気中を伝わります。同時に、エコー ピンが High になり、エコー信号の始まりが形成され始めます。

これらのパルスが反射されない場合 (つまり、最大距離内に障害物がない場合)、エコー信号は 38 ミリ秒 (38 ms) 後にタイムアウトし、Low に戻ります。したがって、38 ミリ秒のパルスは、センサーの範囲内に障害物がないことを示します。
ここに画像の説明を挿入
パルスが反射して戻ってくると、信号を受信した後に Echo ピンが Low になります。これにより、信号の受信にかかる時間に応じて、幅が 150 μS ~ 25 mS の間で変化するパルスが生成されます。
したがって、障害物がない場合には取得される応答パルスの長さは38msであるのに対し、障害物がある場合には取得される応答パルスの長さは150μSから25mSまで変化します。
ここに画像の説明を挿入
概要: 距離 = 高レベル時間 * 音速 (340M/S)/2;

3.MRS追加ライブラリファイル

1. 新しい .c および .h ファイルを作成します

MRS を開き、CH32V307VCT6 プロジェクトを作成し、左側の CH32V307VCT6 列に新しいハードウェア フォルダーを作成し、新しいフォルダーを右クリックして HC-SR04 という名前を付け、新しいヘッダー ファイル、ソース ファイルを右クリックします。
ここに画像の説明を挿入
新しいヘッダー ファイルを追加するには、ヘッダー ファイルのアドレス指定パスに追加する必要があります。メニュー バー - プロジェクト - プロパティ設定ボタンをクリックし、ポップアップ ページで、下図に示すように、緑色のプラス記号をクリックして追加します。パス。
ここに画像の説明を挿入

2. .c 関数を書く

具体的な考え方は、1 つの IO ポートを Trig としてプッシュプル出力として設定し、1 つの IO ポートを Echo としてプルダウン入力として設定するだけでよいということです。これは、Echo がエコー信号を受信すると、それが Low から設定されるためです。レベルを高レベルに設定するため、Echo のデフォルト設定は低電力です。距離 = 高レベル時間 * 音速 (340M/S)/2;
最初に SysTick ソフトウェアを使用して制御トリガーを遅延させて高レベルを送信し、次にエコー信号を待ちます。エコーが信号を受信するとタイマーが開始されますが、私たちのプログラムは、タイマー内で実行されているものは同じタイマー TIM2 を使用しており、信号を受信した後にタイマーをクリアする必要があります。次に、レベル持続時間を取得し、距離を計算し、タイマーを再度リセットしてタイマーを開始すると、次のタイマー割り込みが正常にトリガーされます。
(1) タイマ機能
コードを次のように記述します。

#include "debug.h"                  // Device header
//初始化定时器,采用基本定时器6,
void Timer_Init(void)
{
    
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);        //启用TIM3时钟

    TIM_InternalClockConfig(TIM6);                              //设置TIM3使用内部时钟

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;          //定义结构体,配置定时器
    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置1分频(不分频)
    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //设置计数模式为向上计数
    TIM_TimeBaseInitStructure.TIM_Period = 10 - 1;          //设置最大计数值,达到最大值触发更新事件,因为从0开始计数,所以计数10次是10-1,每10微秒触发一次
    TIM_TimeBaseInitStructure.TIM_Prescaler = 72 - 1;           //设置时钟预分频,72-1就是每 时钟频率(72Mhz)/72=1000000 个时钟周期计数器加1,每1微秒+1
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;        //重复计数器(高级定时器才有,所以设置0)
    TIM_TimeBaseInit(TIM6, &TIM_TimeBaseInitStructure);         //初始化TIM6定时器

    TIM_ClearFlag(TIM6, TIM_FLAG_Update);           //清除更新中断标志位
    TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);      //开启更新中断

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);             //设置中断优先级分组

    NVIC_InitTypeDef NVIC_InitStructure;                        //定义结构体,配置中断优先级
    NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;             //指定中断通道
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;             //中断使能
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //设置抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;          //设置响应优先级
    NVIC_Init(&NVIC_InitStructure);                             // https://blog.zeruns.tech

    TIM_Cmd(TIM6, ENABLE);                          //开启定时器
}

/*
void TIM3_IRQHandler(void)          //更新中断函数
{
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)        //获取TIM3定时器的更新中断标志位
    {

        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);         //清除更新中断标志位
    }
}*/


#ifndef __TIMER_H
#define __TIMER_H

void Timer_Init(void);

#endif

(2) HC-SR04の初期化およびレンジング関数の書き込み

#include "debug.h"
#include "stdio.h"
#include "ch32v30x.h"

#define Echo GPIO_Pin_10   //HC-SR04模块的Echo脚接GPIOD10
#define Trig GPIO_Pin_11    //HC-SR04模块的Trig脚接GPIOD11

uint64_t time=0;            //声明变量,用来计时
uint64_t time_end=0;        //声明变量,存储回波信号时间

void HC_SR04_Init(void)
{
    
      
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);    //启用GPIOB的外设时钟
    GPIO_InitTypeDef GPIO_InitStructure;                    //定义结构体
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        //设置GPIO口为推挽输出
    GPIO_InitStructure.GPIO_Pin = Trig;                     //设置GPIO口5
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //设置GPIO口速度50Mhz
    GPIO_Init(GPIOD,&GPIO_InitStructure);                   //初始化GPIOB

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;           //设置GPIO口为下拉输入模式
    GPIO_InitStructure.GPIO_Pin = Echo;                     //设置GPIO口6
    GPIO_Init(GPIOD,&GPIO_InitStructure);                   //初始化GPIOB
    GPIO_WriteBit(GPIOD,GPIO_Pin_10,0);                      //输出低电平,让回应信号先保持低电平状态
    Delay_Us(15); //延时15微秒
}

int16_t sonar_mm(void)                                  //测距并返回单位为毫米的距离结果
{
    
    
    uint32_t Distance,Distance_mm = 0;
    GPIO_WriteBit(GPIOB,Trig,1);                        //输出高电平
    Delay_Us(15);                                       //延时15微秒
    GPIO_WriteBit(GPIOB,Trig,0);                        //输出低电平
    while(GPIO_ReadInputDataBit(GPIOB,Echo)==0);        //等待低电平结束
    time=0;                                             //计时清零
    while(GPIO_ReadInputDataBit(GPIOB,Echo)==1);        //等待高电平结束
    time_end=time;                                      //记录结束时的时间
    if(time_end/100<38)                                 //判断是否小于38毫秒,大于38毫秒的就是超时,直接调到下面返回0
    {
    
    
        Distance=(time_end*346)/2;                      //计算距离,25°C空气中的音速为346m/s
        Distance_mm=Distance/100;                       //因为上面的time_end的单位是10微秒,所以要得出单位为毫米的距离结果,还得除以100
    }
    return Distance_mm;                                 //返回测距结果
}

float sonar(void)                                       //测距并返回单位为米的距离结果
{
    
    
    uint32_t Distance,Distance_mm = 0;
    float Distance_m=0;
    GPIO_WriteBit(GPIOB,Trig,1);                    //输出高电平
    Delay_Us(15);
    GPIO_WriteBit(GPIOB,Trig,0);                    //输出低电平
    while(GPIO_ReadInputDataBit(GPIOB,Echo)==0);
    time=0;
    while(GPIO_ReadInputDataBit(GPIOB,Echo)==1);
    time_end=time;
    if(time_end/100<38)
    {
    
    
        Distance=(time_end*346)/2;
        Distance_mm=Distance/100;
        Distance_m=Distance_mm/1000;
    }
    return Distance_m;
}

void TIM3_IRQHandler(void)          //更新中断函数,用来计时,每10微秒变量time加1
{
    
    
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)        //获取TIM3定时器的更新中断标志位
    {
    
    
        time++;
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);         //清除更新中断标志位
    }
}

#ifndef __HCSR04_H
#define __HCSR04_H

void HC_SR04_Init(void);
int16_t sonar_mm(void);
float sonar(void);

#endif

(3) メインプログラムの作成
ここで実現したいのは、単位としてミリメートルを使用し、測定された距離をシリアルポートを使用して出力することです。

#include "debug.h"
#include "timer_6.h"
#include "HC-SR04.h"
/* Global typedef */

/* Global define */

/* Global Variable */


/*********************************************************************
 * @fn      main
 *
 * @brief   Main program.
 *
 * @return  none
 */
int main(void)
{
    
    
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	SystemCoreClockUpdate();
	Delay_Init();
	USART_Printf_Init(115200);	


	Timer_Init();
	HC_SR04_Init();
	//printf( "ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
	//printf("This is printf example\r\n");

	while(1)
    {
    
    
	float distance = sonar_mm();
	printf("distance:%f\r\n",distance);

	}
}

要約する

現時点では、プロジェクトではより複雑な測距スキームを使用する必要があるため、この記事では、他の有名な HC-SR04 ライブラリを参照して、最も基本的なアプリケーション例のみを示します。

おすすめ

転載: blog.csdn.net/qq_53092944/article/details/130122806