1+ // https://uglyduck.vajn.icu/ep/archive/2014/01/Making_a_better_HC_SR04_Echo_Locator.html
2+
3+ // HC-SR04 driver (single instance only)
4+ // range: 2-6m (depending on variant)
5+ // reporting rate: 100ms
6+ // trigger pin high pulse >= 8us --> echo high pulse
7+
8+ #pragma once
9+
10+ #include " rdr.h"
11+ #include " ../hal/hal.h"
12+ #include < Arduino.h> // micros, pinMode, digitalWrite, attachInterrupt
13+
14+ #define SR04_TRIG_US 100 // minimum length of trigger pulse
15+ #define SR04_TIMEOUT_US 60000 // echo timeout 60 ms ~= 10 meter, this is also the appoximate sample rate
16+
17+ static uint8_t _RdrGizmoSR04_irq_pin_echo = 0 ;
18+ static volatile uint32_t _RdrGizmoSR04_irq_echo_ts1 = 0 ;
19+ static volatile uint32_t _RdrGizmoSR04_irq_echo_ts2 = 0 ;
20+
21+ static void _RdrGizmoSR04_irq () {
22+ if (digitalRead (_RdrGizmoSR04_irq_pin_echo) == HIGH) {
23+ _RdrGizmoSR04_irq_echo_ts1 = micros ();
24+ }else {
25+ _RdrGizmoSR04_irq_echo_ts2 = micros ();
26+ }
27+ }
28+
29+
30+ class RdrGizmoSR04 : public RdrGizmo {
31+ protected:
32+ enum class state_enum { TRIG_START, TRIG_END, ECHO_WAIT, INTERVAL_WAIT};
33+ state_enum state = state_enum::TRIG_START;
34+ uint8_t pin_trig = 0 ;
35+ uint32_t state_ts = 0 ;
36+ int *dist = nullptr ;
37+
38+ RdrGizmoSR04 () {} // private constructor
39+
40+ public:
41+ static RdrGizmoSR04* create (int * dist, int pin_trig, int pin_echo) {
42+ if (!dist || pin_trig < 0 || pin_echo < 0 ) return nullptr ;
43+ pinMode (pin_trig, OUTPUT);
44+ digitalWrite (pin_trig, LOW);
45+ pinMode (pin_echo, INPUT);
46+ attachInterrupt (digitalPinToInterrupt (pin_echo), _RdrGizmoSR04_irq, CHANGE);
47+
48+ // setup gizmo
49+ auto gizmo = new RdrGizmoSR04 ();
50+ _RdrGizmoSR04_irq_pin_echo = pin_echo;
51+ gizmo->pin_trig = pin_trig;
52+ gizmo->dist = dist;
53+ return gizmo;
54+ }
55+
56+ bool update () override {
57+ switch (state) {
58+ case state_enum::TRIG_START:
59+ // note: send trigger pulse regardless of echo pin state, is this wise???
60+ digitalWrite (pin_trig, HIGH);
61+ state_ts = micros ();
62+ state = state_enum::TRIG_END;
63+ break ;
64+ case state_enum::TRIG_END:
65+ if (micros () - state_ts > SR04_TRIG_US) {
66+ _RdrGizmoSR04_irq_echo_ts1 = 0 ;
67+ _RdrGizmoSR04_irq_echo_ts2 = 0 ;
68+ digitalWrite (pin_trig, LOW);
69+ state_ts = micros ();
70+ state = state_enum::ECHO_WAIT;
71+ }
72+ break ;
73+ case state_enum::ECHO_WAIT:
74+ if (_RdrGizmoSR04_irq_echo_ts2 && _RdrGizmoSR04_irq_echo_ts1) {
75+ // got echo
76+ *dist = (_RdrGizmoSR04_irq_echo_ts2 - _RdrGizmoSR04_irq_echo_ts1) * 171 / 1000 ; // integer math echo_us -> dist_mm with speed of sound 342 m/s
77+ state = state_enum::INTERVAL_WAIT;
78+ // Serial.printf("ECHO %d\n",*dist);
79+ return true ;
80+ }
81+ // fall thru
82+ case state_enum::INTERVAL_WAIT:
83+ if (micros () - state_ts > SR04_TIMEOUT_US) {
84+ // if(state == state_enum::ECHO_WAIT) Serial.printf("SR04 TIMEOUT\n");
85+ state = state_enum::TRIG_START;
86+ }
87+ break ;
88+ }
89+ return false ;
90+ }
91+
92+ };
0 commit comments