Solved - PING alternative HC-SR04 coding problem!

Jorge PJorge P Posts: 385
edited 2018-01-20 - 13:20:12 in Propeller 1
Hi all, it's been quite a while since I used the propeller and I've run into a coding problem while trying to get the HC-SR04 working. Here is my code so far, some of it borrowed from other locations.

I have it running but either my timing is wrong or my distance calculations are wrong.

HC-SR04 Product Page
HC-SR04 datasheet

I am getting unexpected measurement results and modified the code somewhat while trying to figure it out.

Thanks in advance.
{{
  Sparkfun's HC-SR04 Ultrasonic Sensor on the Propeller :)

  I've only seen this in C code for the Propeller so here it is
  in SPIN.


}}
CON
        _clkmode = xtal1 + pll16x
        _xinfreq = 5_000_000

        TRIG   = 1  ' Connected to P1
        ECHO   = 0  ' Connected to P0

        HIGH   = 1
        LOW    = 0

        INPUT  = 0
        OUTPUT = 1

        MAX_DIST = 23_200

        DEBUG = 1            ' 1 = true, 0 = false

        ' from Timing.spin
        _10us = 1_000_000 /        10                         ' Divisor for 10 us
        _1ms  = 1_000_000 /     1_000                         ' Divisor for 1 ms
        _1s   = 1_000_000 / 1_000_000                         ' Divisor for 1 s

        ' from dualPing.spin
        TO_IN_std = 74_641  ' std atmosphere speed of sound, us per inch traveled @ 59F air temperature
        TO_CM_std = 29_386  ' std atmosphere speed of sound, us per cm traveled @ 59F air temperature

OBJ
        pst : "Parallax Serial Terminal"


VAR
        LONG pulse_Start
        LONG pulse_Stop

        ' from Timing.spin
        LONG delay
        LONG syncpoint
        LONG clkcycles

        

PUB Main | Microseconds, Distance, cnt1, cnt2
    waitcnt(clkfreq * 5 + cnt)
    pst.start(115200)

    ' set pin directions
    OUTA[TRIG] := HIGH        ' Direction not set but set the state low
    DIRA[TRIG] := OUTPUT      ' Set to Output
    OUTA[TRIG] := LOW         ' Ensure it is still Low
    
    DIRA[ECHO] := INPUT       ' Set the echo input

    IF DEBUG == 1
      pst.Str(STRING("Directions Set, ready for testing!"))
      NL

    REPEAT
      ' main loop
      OUTA[TRIG] := HIGH
      pause10us(1)
      OUTA[TRIG] := LOW
      WAITPNE(0, |< ECHO, 0)
      cnt1 := CNT
      WAITPEQ(0, |< ECHO, 0)
      cnt2 := CNT
      Microseconds := (||(cnt1 - cnt2) / (CLKFREQ / 1_000_000)) >> 1
      if DEBUG == 1
        pst.Home
        pst.ClearEnd
        pst.Dec(Microseconds)
        pst.Str(STRING(" us. "))
      Distance := Microseconds / 58

      IF DEBUG == 1
        pst.Dec(Distance)
        pst.Str(STRING(" cm."))

      pause1ms(100)


PUB Inches(ms) : Distance
''Measure object distance in inches

  Distance := ms * 1_000 / TO_IN                                        ' Distance In Inches
                                                                                 
                                                                                 
PUB Centimeters(ms) : Distance                                                  
''Measure object distance in centimeters
                                              
  Distance := Millimeters(ms) / 10                                             ' Distance In Centimeters
                                                                                 
                                                                                 
PUB Millimeters(ms) : Distance                                                  
''Measure object distance in millimeters
                                              
  Distance := ms * 10_000 / TO_CM                                       ' Distance In Millimeters


'from dualPing.spin
PUB calibrate(Tamb)
    ''Adjust Ping))) calibration constants to reflect ambient 
    ''temperature impact on speed of sound (temperature assumed to be °F)
    Tamb += 460
    TO_IN := TO_IN_std * (^^(Tamb * 1_000_000)) / (^^518_690_000)
    TO_CM := TO_IN * TO_CM_std / TO_IN_std

'From Timing.spin
PUB pause10us(period)
    '' Pause execution for period (in units of 10 us)
    clkcycles := ((CLKFREQ / _10us * period) - 4296) #> 381    ' Calculate 10 us time unit
    WAITCNT(clkcycles + CNT)                                   ' Wait for designated time

'From Timing.spin
PUB pause1ms(period)
    '' Pause execution for period (in units of 1 ms).
    clkcycles := ((CLKFREQ / _1ms * period) - 4296) #> 381     ' Calculate 1 ms time unit
    WAITCNT(clkcycles + CNT)                                   ' Wait for designated time
  
'From Timing.spin
PUB pause1s(period)
    '' Pause execution for period (in units of 1 sec).
    clkcycles := ((CLKFREQ / _1s * period) - 4296) #> 381      ' Calculate 1 s time unit
    WAITCNT(clkcycles + CNT)                                   ' Wait for designated time

'From Timing.spin  
PUB marksync10us(period)
    delay := (CLKFREQ / _10us * period) #> 381                 ' Calculate 10 us time unit 
    syncpoint := CNT

'From Timing.spin  
PUB waitsync
    WAITCNT(syncpoint += delay)

    
PRI NL
    pst.NewLine

PRI CLS
    pst.Clear

DAT
'-----------[ Predefined variables and constants ]-----------------------------
        TO_IN         LONG      74_641                  '
        TO_CM         LONG      29_386        
Jorge P.

Comments

  • Is the logic protocol the same as Ping?

    Ping idles low and asserts high.
  • VonSzarvas wrote: »
    Is the logic protocol the same as Ping? Ping idles low and asserts high.

    Yes, according to its datasheet it is.

    And just to clarify, I am getting results but I can only detect readings between 2 and 6 centimeters. it should be more between 2 and 400 according to the specifications so I think some timing calculations, I have are off, which should be more apparent to someone with more experienced with spin than I am.

    Jorge P.
  • Oops was a bad hole on the breadboard, code works fine :/ I checked all 10 units and they work with this code! I used a ruler to test the distance measurement and it seems to be calculated from the HC-SR04 units PCB and not from the Ultrasonic sensors. Got readings out to 1,000mm then I couldn't read the screen of pst.
    {{
      Sparkfun's HC-SR04 Ultrasonic Sensor on the Propeller :)
    
      I've only seen this in C code for the Propeller so here it is
      in SPIN.
    
    
    }}
    CON
            _clkmode = xtal1 + pll16x
            _xinfreq = 5_000_000
    
            TRIG   = 1  ' Connected to P1
            ECHO   = 0  ' Connected to P0
    
            HIGH   = 1
            LOW    = 0
    
            INPUT  = 0
            OUTPUT = 1
    
            MAX_DIST = 23_200
    
            DEBUG = 1            ' 1 = true, 0 = false
    
            ' from Timing.spin
            _10us = 1_000_000 /        10                         ' Divisor for 10 us
            _1ms  = 1_000_000 /     1_000                         ' Divisor for 1 ms
            _1s   = 1_000_000 / 1_000_000                         ' Divisor for 1 s
    
            ' from dualPing.spin
            TO_IN_std = 74_641  ' std atmosphere speed of sound, us per inch traveled @ 59F air temperature
            TO_CM_std = 29_386  ' std atmosphere speed of sound, us per cm traveled @ 59F air temperature
    
    OBJ
            pst : "Parallax Serial Terminal"
    
    
    VAR
            LONG pulse_Start
            LONG pulse_Stop
    
            ' from Timing.spin
            LONG delay
            LONG syncpoint
            LONG clkcycles
    
            
    
    PUB Main | Microseconds, Distance, cnt1, cnt2
        waitcnt(clkfreq * 5 + cnt)
        pst.start(115200)
    
        ' set pin directions
        OUTA[TRIG] := HIGH        ' Direction not set but set the state low
        DIRA[TRIG] := OUTPUT      ' Set to Output
        OUTA[TRIG] := LOW         ' Ensure it is still Low
        
        DIRA[ECHO] := INPUT       ' Set the echo input
    
        IF DEBUG == 1
          pst.Str(STRING("Directions Set, ready for testing!"))
          NL
    
        REPEAT
          ' main loop
          OUTA[TRIG] := HIGH
          pause10us(1)
          OUTA[TRIG] := LOW
          WAITPNE(0, |< ECHO, 0)
          cnt1 := CNT
          WAITPEQ(0, |< ECHO, 0)
          cnt2 := CNT
          Microseconds := (||(cnt1 - cnt2) / (CLKFREQ / 1_000_000)) >> 1
          if DEBUG == 1
            pst.Home
            pst.ClearEnd
            pst.Dec(Microseconds)
            pst.Str(STRING(" us. "))
          Distance := Millimeters(Microseconds)
    
          IF DEBUG == 1
            pst.Dec(Distance)
            pst.Str(STRING(" mm."))
    
          pause1ms(100)
    
    
    PUB Inches(ms) : Distance
    ''Measure object distance in inches
    
      Distance := ms * 1_000 / TO_IN                                        ' Distance In Inches
                                                                                     
                                                                                     
    PUB Centimeters(ms) : Distance                                                  
    ''Measure object distance in centimeters
                                                  
      Distance := Millimeters(ms) / 10                                             ' Distance In Centimeters
                                                                                     
                                                                                     
    PUB Millimeters(ms) : Distance                                                  
    ''Measure object distance in millimeters
                                                  
      Distance := ms * 10_000 / TO_CM                                       ' Distance In Millimeters
    
    
    'from dualPing.spin
    PUB calibrate(Tamb)
        ''Adjust Ping))) calibration constants to reflect ambient 
        ''temperature impact on speed of sound (temperature assumed to be °F)
        Tamb += 460
        TO_IN := TO_IN_std * (^^(Tamb * 1_000_000)) / (^^518_690_000)
        TO_CM := TO_IN * TO_CM_std / TO_IN_std
    
    'From Timing.spin
    PUB pause10us(period)
        '' Pause execution for period (in units of 10 us)
        clkcycles := ((CLKFREQ / _10us * period) - 4296) #> 381    ' Calculate 10 us time unit
        WAITCNT(clkcycles + CNT)                                   ' Wait for designated time
    
    'From Timing.spin
    PUB pause1ms(period)
        '' Pause execution for period (in units of 1 ms).
        clkcycles := ((CLKFREQ / _1ms * period) - 4296) #> 381     ' Calculate 1 ms time unit
        WAITCNT(clkcycles + CNT)                                   ' Wait for designated time
      
    'From Timing.spin
    PUB pause1s(period)
        '' Pause execution for period (in units of 1 sec).
        clkcycles := ((CLKFREQ / _1s * period) - 4296) #> 381      ' Calculate 1 s time unit
        WAITCNT(clkcycles + CNT)                                   ' Wait for designated time
    
    'From Timing.spin  
    PUB marksync10us(period)
        delay := (CLKFREQ / _10us * period) #> 381                 ' Calculate 10 us time unit 
        syncpoint := CNT
    
    'From Timing.spin  
    PUB waitsync
        WAITCNT(syncpoint += delay)
    
        
    PRI NL
        pst.NewLine
    
    PRI CLS
        pst.Clear
    
    DAT
    '-----------[ Predefined variables and constants ]-----------------------------
            TO_IN         LONG      74_641                  '
            TO_CM         LONG      29_386        
    
    Jorge P.
Sign In or Register to comment.