HC-SR04超声波测距模块是一种常见的功能模块,它可提供2cm-400cm的非接触式距离检测功能,测距精度可达高到3mm;模块包括超声波发射器、接收器与控制电路,见图1所示。

图1 超声波测距模块
该模块的特点如下:
1)典型工作用电压:5V
2)超小静态工作电流:小于5mA
3)精度可达0.3cm
4)盲区接近2cm
该模块共有4个引脚,即:VCC(5V)、 Trig(控制端)、 Echo(接收端)、地(GND)。
超声波测距是通过不断检测超声波发射后遇到障碍物所反射的回波, 从而测出发射和接收回波的时间差Δt , 然后求出距离S 。在速度v 已知的情况下,距离S 的计算,公式如下:S = vΔt/ 2在空气中,常温下超声波的传播速度是334 米/秒,但其传播速度V 易受空气中温度、湿度、压强等因素的影响,其中受温度的影响较大,如温度每升高1 ℃, 声速增加约0. 6 米/ 秒。因此在测距精度要求很高的情况下, 应通过温度补偿的方法对传播速度加以校正。已知现场环境温度T 时, 超声波传播速度V 的计算公式如下:
V = 331. 5+0.607T
这样, 只要测得超声波发射和接收回波的时间差Δt 以及现场环境温度T,就可以精确计算出发射点到障碍物之间的距离。

图2 信号时序关系
在使用WT9932C61-TINY的情况下,其引脚连接关系为:
TRIG---IO2
ECHO---IO1
具体的程序内容为:
#define HC_SR04_TRIG_GPIO 2
#define HC_SR04_ECHO_GPIO 1
#define EXAMPLE_GPTIMER_RESOLUTION_HZ 1000000 // 1MHz, 1 tick = 1us
typedef struct {
gptimer_handle_t gptimer;
TaskHandle_t task_to_notify;
gpio_num_t echo_gpio;
} gpio_callback_user_data_t;
static void hc_sr04_echo_callback(void *user_data)
{
static uint64_t cap_val_end_of_sample = 0;
static uint64_t cap_val_begin_of_sample = 0;
gpio_callback_user_data_t *callback_user_data = (gpio_callback_user_data_t *)user_data;
gpio_num_t echo_gpio = callback_user_data->echo_gpio;
TaskHandle_t task_to_notify = callback_user_data->task_to_notify;
gptimer_handle_t gptimer = callback_user_data->gptimer;
if (gpio_get_level(echo_gpio) == 1) {
gptimer_get_captured_count(gptimer, &cap_val_begin_of_sample);
cap_val_end_of_sample = cap_val_begin_of_sample;
} else {
gptimer_get_captured_count(gptimer, &cap_val_end_of_sample);
uint32_t tof_ticks = (uint32_t)(cap_val_end_of_sample - cap_val_begin_of_sample);
xTaskNotifyFromISR(task_to_notify, tof_ticks, eSetValueWithOverwrite, NULL);
}
}
static void gen_trig_output(void)
{
gpio_set_level(HC_SR04_TRIG_GPIO, 1);
esp_rom_delay_us(10);
gpio_set_level(HC_SR04_TRIG_GPIO, 0);
}
void app_main(void)
{
ESP_LOGI(TAG, "Configure trig gpio");
gpio_config_t trig_io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pin_bit_mask = 1ULL << HC_SR04_TRIG_GPIO,
};
ESP_ERROR_CHECK(gpio_config(&trig_io_conf));
ESP_ERROR_CHECK(gpio_set_level(HC_SR04_TRIG_GPIO, 0));
ESP_LOGI(TAG, "Configure echo gpio");
gpio_config_t echo_io_conf = {
.mode = GPIO_MODE_INPUT,
.intr_type = GPIO_INTR_ANYEDGE,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pin_bit_mask = 1ULL << HC_SR04_ECHO_GPIO,
};
ESP_ERROR_CHECK(gpio_config(&echo_io_conf));
ESP_LOGI(TAG, "Create etm event handle for echo gpio");
esp_etm_event_handle_t gpio_event = NULL;
gpio_etm_event_config_t gpio_event_config = {
.edge = GPIO_ETM_EVENT_EDGE_ANY,
};
ESP_ERROR_CHECK(gpio_new_etm_event(&gpio_event_config, &gpio_event));
ESP_ERROR_CHECK(gpio_etm_event_bind_gpio(gpio_event, HC_SR04_ECHO_GPIO));
ESP_LOGI(TAG, "Create gptimer handle");
gptimer_handle_t gptimer = NULL;
gptimer_config_t timer_config = {
.clk_src = GPTIMER_CLK_SRC_DEFAULT,
.direction = GPTIMER_COUNT_UP,
.resolution_hz = EXAMPLE_GPTIMER_RESOLUTION_HZ,
};
ESP_ERROR_CHECK(gptimer_new_timer(&timer_config, &gptimer));
ESP_LOGI(TAG, "Get gptimer etm task handle (capture)");
esp_etm_task_handle_t gptimer_capture_task = NULL;
gptimer_etm_task_config_t gptimer_etm_task_conf = {
.task_type = GPTIMER_ETM_TASK_CAPTURE,
};
ESP_ERROR_CHECK(gptimer_new_etm_task(gptimer, &gptimer_etm_task_conf, &gptimer_capture_task));
ESP_LOGI(TAG, "Create ETM channel then connect gpio event and gptimer task");
esp_etm_channel_handle_t etm_chan = NULL;
esp_etm_channel_config_t etm_chan_config = {};
ESP_ERROR_CHECK(esp_etm_new_channel(&etm_chan_config, &etm_chan));
ESP_ERROR_CHECK(esp_etm_channel_connect(etm_chan, gpio_event, gptimer_capture_task));
ESP_LOGI(TAG, "Install GPIO edge interrupt");
ESP_ERROR_CHECK(gpio_install_isr_service(0));
gpio_callback_user_data_t callback_user_data = {
.gptimer = gptimer,
.echo_gpio = HC_SR04_ECHO_GPIO,
.task_to_notify = xTaskGetCurrentTaskHandle(),
};
ESP_ERROR_CHECK(gpio_isr_handler_add(HC_SR04_ECHO_GPIO, hc_sr04_echo_callback, &callback_user_data));
ESP_LOGI(TAG, "Enable etm channel and gptimer");
ESP_ERROR_CHECK(esp_etm_channel_enable(etm_chan));
ESP_ERROR_CHECK(gptimer_enable(gptimer));
ESP_ERROR_CHECK(esp_etm_dump(stdout));
ESP_LOGI(TAG, "Start gptimer");
ESP_ERROR_CHECK(gptimer_start(gptimer));
uint32_t tof_ticks;
while (1) {
gen_trig_output();
if (xTaskNotifyWait(0x00, ULONG_MAX, &tof_ticks, pdMS_TO_TICKS(1000)) == pdTRUE) {
if (tof_ticks > 35000) {
continue;
}
float distance = (float) tof_ticks / 58.0f;
ESP_LOGI(TAG, "Measured distance: %.2fcm", distance);
}
vTaskDelay(pdMS_TO_TICKS(500));
}
}经程序编译和下载,其结果如图3和图4所示。

图3 编译结果

图4 完成下载
在探头朝向屋顶时,其检测结果如图5所示。

图5 屋顶距离
在进行物距检测时,见图6和图7所示,检测结果与实际距离基本一致。

图6 物距检测

图7 检测结果
我要赚赏金
