測距機能を使用するため、外部測距センサーに慣れ、測距精度を検討する必要があります。
ヒント: 記事を作成した後、目次を自動的に生成できます。生成方法は、右側のヘルプドキュメントを参照してください。
序文
ペリフェラルの場合は、まず 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 ライブラリを参照して、最も基本的なアプリケーション例のみを示します。