HC-SR04P读数错误
HC-SR04P reading errors
在我的项目中,我需要测量长达 3-4 米的距离,因此我使用连接到 ESP32 开发板的 HC-SR04P 传感器。
代码是在没有任何第三方库的情况下编写的(尽管受到非常简单的 HC-SR04 arduino 库的启发),在纯 C 中,在从 ESP32 eclipse IDF 插件创建的项目中;没有额外的库或 arduino 代码;只是 RTOS。
当设备启动并且测量非常准确时,一切正常,但过了一段时间(不能确切地说出是什么触发了这个),sensor/devboard 电路(不能说是哪个)开始表现异常: 在 TRIG 脉冲之后,ECHO 引脚在合理的 1 秒超时内没有变为高电平,并且不执行任何测量。
一旦发生这种情况,除非reboot/power开启,否则不会再次执行新的测量;看起来有些事情发生了,不知何故,传感器或通信代码出现故障。
几点观察:
- 传感器是在 3.3V 供电的正确版本。
- HC-SR04P 将 GPIO2 和 GPIO4 用于 TRIG 和 ECHO。
- 不需要频繁测量,因此测量任务的计时器为 30 秒。
- 开机,一切正常
- 通过开发板微动开关复位后,一切正常。
- 当超时时,重新初始化传感器(设置GPIO等),但没有任何反应;仍然超时。
作为参考,计时功能如下(HCSR04_Info 结构仅包含引脚和测量数据);每 30 秒从定时任务中调用它。
uint32_t hcsr04_timing(HCSR04_Info* pDevice)
{
// TRIG pulse for 10ms
gpio_set_level(pDevice->trig, 1);
ets_delay_us(10);
gpio_set_level(pDevice->trig, 0);
pDevice->startMicros = esp_timer_get_time();
// wait for the echo pin HIGH or timeout
while ((!gpio_get_level(pDevice->echo)) && (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout);
if (!gpio_get_level(pDevice->echo)) {
pDevice->status = STATUS_OFFLINE;
ESP_LOGE(TAG, "hcsr04_timing timeout (1)");
return 0;
}
pDevice->startMicros = esp_timer_get_time();
// wait for the echo pin LOW or timeout
while ((gpio_get_level(pDevice->echo)) && (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout);
if (gpio_get_level(pDevice->echo)) {
pDevice->status = STATUS_OFFLINE;
ESP_LOGE(TAG, "hcsr04_timing timeout (2)");
return 0;
}
pDevice->status = STATUS_ONLINE;
pDevice->endMicros = esp_timer_get_time();
return pDevice->endMicros - pDevice->startMicros;
}
感谢任何帮助。谢谢。
这不会产生 10 毫秒的脉冲;这是10我们。最终可能会使您的设备进入未确定状态。
// TRIG pulse for 10ms
gpio_set_level(pDevice->trig, 1);
ets_delay_us(10);
gpio_set_level(pDevice->trig, 0);
定义ets_delay_us()
的头文件中的注释说:In FreeRTOS task, please call FreeRTOS apis.
无论如何,如果在 Arduino-land 中,请使用 delay(10)
;或 vTaskDelay(pdMS_TO_TICKS(10))
如果在 FreeRTOS 领域。
根据 campescassiano 关于溢出的建议,解决方案终于出现了。在问题的确切意义上并不是真正的溢出,但密切相关。
终于是代码中的一个愚蠢的错误,所以如果合适请关闭或删除问题。
问题是 pDevice->startMicros
被定义为 uint32_t
(可能是因为 copy/paste 或坏习惯错误),而 esp_timer_get_time()
returns微秒作为 uint64_t
.
所以它 'overflows' 在启动后大约 1h 11m 34s(大约 232 微秒),并且超时计算停止,因为 (esp_timer_get_time() - pDevice->startMicros)
将显然是 uint64_t
.
因为 (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout
在 1h 11m 34s 之后总是 false,所以在获得 ECHO 输入之前循环中断。
在我的项目中,我需要测量长达 3-4 米的距离,因此我使用连接到 ESP32 开发板的 HC-SR04P 传感器。
代码是在没有任何第三方库的情况下编写的(尽管受到非常简单的 HC-SR04 arduino 库的启发),在纯 C 中,在从 ESP32 eclipse IDF 插件创建的项目中;没有额外的库或 arduino 代码;只是 RTOS。
当设备启动并且测量非常准确时,一切正常,但过了一段时间(不能确切地说出是什么触发了这个),sensor/devboard 电路(不能说是哪个)开始表现异常: 在 TRIG 脉冲之后,ECHO 引脚在合理的 1 秒超时内没有变为高电平,并且不执行任何测量。
一旦发生这种情况,除非reboot/power开启,否则不会再次执行新的测量;看起来有些事情发生了,不知何故,传感器或通信代码出现故障。
几点观察:
- 传感器是在 3.3V 供电的正确版本。
- HC-SR04P 将 GPIO2 和 GPIO4 用于 TRIG 和 ECHO。
- 不需要频繁测量,因此测量任务的计时器为 30 秒。
- 开机,一切正常
- 通过开发板微动开关复位后,一切正常。
- 当超时时,重新初始化传感器(设置GPIO等),但没有任何反应;仍然超时。
作为参考,计时功能如下(HCSR04_Info 结构仅包含引脚和测量数据);每 30 秒从定时任务中调用它。
uint32_t hcsr04_timing(HCSR04_Info* pDevice)
{
// TRIG pulse for 10ms
gpio_set_level(pDevice->trig, 1);
ets_delay_us(10);
gpio_set_level(pDevice->trig, 0);
pDevice->startMicros = esp_timer_get_time();
// wait for the echo pin HIGH or timeout
while ((!gpio_get_level(pDevice->echo)) && (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout);
if (!gpio_get_level(pDevice->echo)) {
pDevice->status = STATUS_OFFLINE;
ESP_LOGE(TAG, "hcsr04_timing timeout (1)");
return 0;
}
pDevice->startMicros = esp_timer_get_time();
// wait for the echo pin LOW or timeout
while ((gpio_get_level(pDevice->echo)) && (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout);
if (gpio_get_level(pDevice->echo)) {
pDevice->status = STATUS_OFFLINE;
ESP_LOGE(TAG, "hcsr04_timing timeout (2)");
return 0;
}
pDevice->status = STATUS_ONLINE;
pDevice->endMicros = esp_timer_get_time();
return pDevice->endMicros - pDevice->startMicros;
}
感谢任何帮助。谢谢。
这不会产生 10 毫秒的脉冲;这是10我们。最终可能会使您的设备进入未确定状态。
// TRIG pulse for 10ms
gpio_set_level(pDevice->trig, 1);
ets_delay_us(10);
gpio_set_level(pDevice->trig, 0);
定义ets_delay_us()
的头文件中的注释说:In FreeRTOS task, please call FreeRTOS apis.
无论如何,如果在 Arduino-land 中,请使用 delay(10)
;或 vTaskDelay(pdMS_TO_TICKS(10))
如果在 FreeRTOS 领域。
根据 campescassiano 关于溢出的建议,解决方案终于出现了。在问题的确切意义上并不是真正的溢出,但密切相关。
终于是代码中的一个愚蠢的错误,所以如果合适请关闭或删除问题。
问题是 pDevice->startMicros
被定义为 uint32_t
(可能是因为 copy/paste 或坏习惯错误),而 esp_timer_get_time()
returns微秒作为 uint64_t
.
所以它 'overflows' 在启动后大约 1h 11m 34s(大约 232 微秒),并且超时计算停止,因为 (esp_timer_get_time() - pDevice->startMicros)
将显然是 uint64_t
.
因为 (esp_timer_get_time() - pDevice->startMicros) <= pDevice->timeout
在 1h 11m 34s 之后总是 false,所以在获得 ECHO 输入之前循环中断。