Devantech SRF-04

Anyone developed driver code for this Sonar sensor, that needs a digital equivalent junction for the Parallax “Pulse in” to measure the time between an output trigger pulse from a pin and a return pulse on another?

The sensor work by sending a very small pulse on a pin and then measuring the time it takes for P1 to go high. The problem here that this requires very tight timing. NETMF is not very well suited for such tight timing. The response can be between 200uS and 18mS.

So, the way you will do this is by:

  1. set an output port for P0
  2. set an interrupt port for P1
  3. read the system tick (in 100nS)
  4. Make the output pin high and then back low
  5. in the pin interrupt handler, read the interrupt time-stamp and subtract from step 3.

Ofcourse this would be much easier to use if GHI adds a built in support for such feature but since we do not see it very important, we do not have current plans on adding such feature.

@ Gus, I have built and tested your recommendation with an SRF-05 sensor. I only read the ticks in the interrupt routine done.
It works well see the code:


using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;

namespace srf05
{
    public class Program
    {
        static long ticks;
  
        public static void Main()
        {
            new Thread(() => flashOnboardLed(200)).Start();
            TristatePort srfo = new TristatePort((Cpu.Pin)FEZ_Pin.Interrupt.Di7, false, false, Port.ResistorMode.Disabled);
            InterruptPort srfi = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di4, false, Port.ResistorMode.PullUp,
                                                                                          Port.InterruptMode.InterruptEdgeBoth);
            srfi.OnInterrupt += new NativeEventHandler(srfi_OnInterrupt);
 
            if (!srfo.Active)
                srfo.Active = true; // make pin output 
            long distance;
            while (true)
            {
                srfo.Write(true);
                srfo.Write(false);
                Thread.Sleep(50);
                if (ticks < 300000)
                {
                    distance = ticks / 580;
                    Debug.Print(distance.ToString());
                }
                ticks = 0;
            }
        }

        static void srfi_OnInterrupt(uint port, uint state, DateTime time)
        {
            if (ticks == 0)
                ticks = time.Ticks;
            else
                ticks = time.Ticks - ticks;
        }

        public static void flashOnboardLed(object flashTime)
        {
            OutputPort led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false);
            while (true)
            {
                led.Write(!led.Read());
                Thread.Sleep((int)flashTime);
            }
        }      
    }
}

The sensor works however SRF-04 fashion.
In the SRF-05 mode is only one pin is used. I am not succeeded in the tristate port is also an interrupt to continue.
But is it possible?

Good job on making it work.

Doing this with one pin can be tricky. I think you can use interrupts with tristate ports but I never used it before.

@ Gus, I can not do to declare a TristatePort so that when input generates an interrupt. I have therefore tried to go bad solution which, however that works. This solution is not my preference because of the overhead.


using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GHIElectronics.NETMF.FEZ;

namespace srf05
{
    public class Program
    {
        static InterruptPort srfi; 
        static long ticks;
  
        public static void Main()
        {
            new Thread(() => flashOnboardLed(200)).Start();
            long distance;
            while (true)
            {
                OutputPort srfo = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.Di4, false);
                srfo.Write(true);
                srfo.Write(false);
                srfo.Dispose();

                srfi = new InterruptPort((Cpu.Pin)FEZ_Pin.Interrupt.Di4, false, Port.ResistorMode.PullUp,
                                                                                       Port.InterruptMode.InterruptEdgeBoth);
                srfi.OnInterrupt += new NativeEventHandler(srfi_OnInterrupt);
                Thread.Sleep(50);
                if (ticks < 300000)
                {
                    distance = ticks / 580;
                    Debug.Print(distance.ToString());
                }
                ticks = 0;
                srfi.Dispose();
            }
        }

        static void srfi_OnInterrupt(uint port, uint state, DateTime time)
        {
            if (ticks == 0)
                ticks = time.Ticks; 
            else
                ticks = time.Ticks - ticks; 
        }

        public static void flashOnboardLed(object flashTime)
        {
            OutputPort led = new OutputPort((Cpu.Pin)FEZ_Pin.Digital.LED, false);
            while (true)
            {
                led.Write(!led.Read());
                Thread.Sleep((int)flashTime);
            }
        }      
    }
}

Can you give me a hint how to declare a tristateport so it can generate an interrupt input mode.