Tutorial: Ultrasonic Ranging with the Freedom Board


Question: What makes 8 times ‘beep’, but I cannot hear it?

Answer: My ultrasonic range finder :-)

FRDM-KL25Z with HC-SR04

FRDM-KL25Z with HC-SR04

What I have added to my FRDM-KL25Z board is an ultrasonic distance sensor, measuring distances up to 4 meters.

HC-SR04 Ultrasonic Sensor

The HC-SR04 sensor is a 4 pin sensor, at an incredible price point. I have mine from Play-Zone, but I have seen offers in the internet for around $6 too.

HC-SR04 Front Side

HC-SR04 Front Side

The backside features all the electronics to which simply usage of the sensor:

HC-SR04 Back Side

HC-SR04 Back Side

With simple I mean, it only needs 4 pins:

  1. Vcc (+5V DC supply)
  2. Trig (TTL input, to trigger a measurement)
  3. Echo (TTL output, pulse proportional to distance)
  4. GND (ground)

Note: There is a similar module on the market: the Parallax Ping))) or Seedstudio one which only use 3 pins (Vcc, Trig+Echo, GND). While this saves a pin, it makes usage a big more complicated as I would have to switch between output and input on a single pin. So I prefer the 4 pin variant.

Using the sensor is simple:

HC-SR04 Timing Diagram

HC-SR04 Timing Diagram

  1. Send a 10 us pulse on Trig
  2. In reaction to this, the sensor will send 8 sonic bursts to measure the distance
  3. After sending the burst, the sensor will raise the Echo signal until it receives the echo back. That means the length of the Echo signal corresponds to time the burst was travelling forward and echoed back.

Below is a snapshot with a logic analyzer:

HC-SR04 Timing

HC-SR04 Timing

After the 10 us Trigger signal, the sensor sends the burst during ’1′ and ’2′ (around 456 us), followed by the Echo signal duration of 756 us. The 756 us corresponds to the time it took for the burst to come back.

The speed of sound is about 340 m per second (depends on temperature and air relative humidity). A good approximation is 29 us per cm (or 58 us per centimeter as it is for back and forward). With the above example, the 756 us would result in 756/29/2 = 13 cm distance.

:idea: For decimal system challenged engineers: instead of a divider of 58, use a divider of 148 to get the result in inch instead of centimeter.

Hardware Connection

I’m using a breadboard for easy wiring and connection.

Breadboard Wiring with Freedom Board, Sensor, LCD and Logic Analycer

Breadboard Wiring with Freedom Board, Sensor, LCD and Logic analyzer

To visualize the measurement, I’m using the 2×16 Character display I have used in my earlier post. Of course a LCD is optional. I used the same wiring as before:

Signals with Labels

Signals with Labels

=================================================================
 SIGNAL LIST
-----------------------------------------------------------------
SIGNAL-NAME [DIR]        => PIN-NAME [PIN-NUMBER]
-----------------------------------------------------------------
DB4_D4 [I/O]             => TSI0_CH5/PTA4/I2C1_SDA/TPM0_CH1/NMI_b [30]
DB5_D5 [I/O]             => PTA5/USB_CLKIN/TPM0_CH2 [31]
DB6_D6 [I/O]             => CMP0_IN2/PTC8/I2C0_SCL/TPM0_CH4 [65]
DB7_D7 [I/O]             => CMP0_IN3/PTC9/I2C0_SDA/TPM0_CH5 [66]
E_D10 [Output]           => PTD0/SPI0_PCS0/TPM0_CH0 [73]
LED_BLUE [Output]        => ADC0_SE5b/PTD1/SPI0_SCK/TPM0_CH1 [74]
LED_GREEN [Output]       => TSI0_CH12/PTB19/TPM2_CH1 [54]
LED_RED [Output]         => TSI0_CH11/PTB18/TPM2_CH0 [53]
RS_D8 [Output]           => PTA13/TPM1_CH1 [33]
RW_D9 [Output]           => ADC0_SE6b/PTD5/SPI1_SCK/UART2_TX/TPM0_CH5 [78]
US_Echo_D2 [Input]       => PTD4/LLWU_P14/SPI1_PCS0/UART2_RX/TPM0_CH4 [77]
US_Trig_D3 [Output]      => PTA12/TPM1_CH0 [32]
=================================================================

What I need is the supply voltage, ground, an output pin (Trig) and an input pin to measure the signal (Echo).

The HC-SR04 uses TTL (5V) supply voltage and logic levels. The FRDM-KL25Z processor is a 3.3V one, but the board provides 5V on the header. The HC-SR04 can use 3.3V levels on the Trig signal, but provides a 5V signal on the Echo pin. To get the signal to the 3.3V level, I use a simple voltage divider with a 27k Ohm and 15k Ohm resistor:

ge Divider with two resistors

Voltage Divider with two resistors

Voltage Divider Detail

Voltage Divider Detail

CodeWarrior Project

With the wizard (File > New Bareboard Project) I create a new project for the KL25Z and Processor Expert. I need two things:

  1. Create a 10 us pulse on the Trig (Trigger) pin
  2. Measure the echo on the Echo pin

Trigger

For the Trigger pin I add a BitIO_LDD component to my project:

BitIO_LDD Component

BitIO_LDD Component

I configure it as Output pin on PTA12:

Trigger Properties

Trigger Properties

Additionally I add the Wait component to the project:

Wait Component

Wait Component

Generating the 10 us pulse now is trivial:

TRIG_SetVal(trigDevice);
WAIT1_Waitus(10);
TRIG_ClrVal(trigDevice);

Wait! There is some more infrastructure needed, such as this trigDevice handle. More on this below.

Echo Pulse Measurement

To measure the echo, I add a TimerUnit_LDD component:

TimerUnit_LDD added

TimerUnit_LDD added

That component shows errors for now, because I need to configure it for my needs. What I want is a timer measuring the echo signal. For this I need to set up a timer which starts counting on the echo raising edge, and stops at the falling edge. For this I need a timer channel.

I add a new channel using the ‘+’ icon:

Adding Timer Unit Channel

Adding Timer Unit Channel

For this I’m selecting the TPM0_CNT as counter and configure the channel for ‘capture’:

:idea: You will understand later on why I have selected this particular counter.

Using TPM0_CNT and Capture Mode

Using TPM0_CNT and Capture Mode

As I have connected the Echo signal on PTD4, I need to use that pin as ‘Capture input pin’:

PTD4 as input capture pin

PTD4 as input capture pin

As hinted by the pin name (PTD4/LLWU_P14/SPI1_PCS0/UART2_RX/TPM0_CH4), this pin is available on TPM0_CH4, so I need to configure this as capture device:

selected capture device

selected capture device

:idea: Now you see why I have selected TPM0_CNT above as Counter device. I admit: that’s not something easy to know about, because this KL25Z has mirades of pin and mapping configuration (called Pin Muxing) :-(. One way is to guess what is behind from the pin names (this is what I try first). Otherwise you need to read through the device reference manual (which is very time-consuming). I wish these devices would be much less complicated and easier to use….

I want to get an interrupt for both the raising edge and falling edge of the Echo signal: I enable interrupts and configure it for both edges. And I give the signal a nice name:

Interrupt Settings

Interrupt Settings

That’s not enough: I need to enable interrupts for the counter too:

Enabled Interrupts for Counter

Enabled Interrupts for Counter

Counter Frequency

I still have errors showing up for my Timer/Counter: I need to configure the counter frequency: This is the clock which is used for my counter. In principle: the higher the frequency, the more precise the measurement will be. As always: a good balance is required. First, I configure the counter frequency:

Configuring the counter frequency

Configuring the counter frequency

The first thing to do is to disable ‘Auto select timing’:

Disabling Auto Select timing

Disabling Auto Select timing

:idea: Processor Expert usually chooses good default values, but fails (for whatever reason?) to do this properly for timers on the ARM platform. So as solution I always disable auto-select-timing and explicitly make my choice. Maybe better that way anyway :-)

I make a gut guess and select a 2.x MHz clock from the list (double-click to assign it):

Selected clock frequency

Selected clock frequency

Counter Overrun

There one thing to consider: when will the counter overflow? I keep in mind that with the speed of sound, around 4 meters distance means 400*58us makes 23.5 ms Echo signal pulse. So I need to make sure that for this distance, my counter does *not* overflow. I can check this in the ‘Overrun period’ settings:

Overrun period

Overrun period

Deselecting ‘auto select timing’ again will show the overrun period time:

Overrun period

Overrun period

So my timer will overrun after 25 ms, so I’m fine :-)

Next, I need to enable two methods I want to use. I need to read the counter value, and I need to reset it. As such, I enable the two methods (right-click on the method name and select ‘Toggle Enable/Disable’):

Enabled TimerUnit_LDD Methods

Enabled TimerUnit_LDD Methods

I notice the two events called:

  • OnCounterRestart() is called when there is a restart/overflow of the counter
  • OnChannel() is called for every interrupt of my channel. Remember that I have it configured for creating an interrupt/event for both raising and falling edge.

State Machine

I’m using a state machine to go through the different measurement phases:

State Diagram

State Diagram

  • Idle: Sensor is idle
  • Triggered: we sent the trigger signal to the sensor
  • Measure: we received raising edge of echo signal and are measuring
  • Overflow: Counter overflow happened (see above)
  • Finished: received falling echo signal edge and we have captured the echo signal time

Another way is to show the different states on the timing diagram (without the Overflow case):

Timing and State Diagram

Timing and State Diagram

With this in mind, the implementation is pretty straight forward. First, an enumeration for the state machine states:

typedef enum {
  ECHO_IDLE, /* device not used */
  ECHO_TRIGGERED, /* started trigger pulse */
  ECHO_MEASURE, /* measuring echo pulse */
  ECHO_OVERFLOW, /* measurement took too long */
  ECHO_FINISHED /* measurement finished */
} US_EchoState;

Next the data structure to keep all my data:

typedef struct {
  LDD_TDeviceData *trigDevice; /* device handle for the Trigger pin */
  LDD_TDeviceData *echoDevice; /* input capture device handle (echo pin) */
  volatile US_EchoState state; /* state */
  TU1_TValueType capture; /* input capture value */
} US_DeviceType;

static US_DeviceType usDevice; /* device handle for the ultrasonic device */

And here is how it gets initialized:

void US_Init(void) {
  usDevice.state = ECHO_IDLE;
  usDevice.capture = 0;
  usDevice.trigDevice = TRIG_Init(NULL);
  usDevice.echoDevice = TU1_Init(&usDevice);
}

Event Handlers

Notice the call to TU1_Init() where I pass a pointer to my data structure: That way I get a nice handle passed from the Processor Expert event routines (in events.c) I can use for my own routines.
Remember that I get interrupts for raising and falling edge, and for overflow.
I handle that in Events.c:

/*
** ===================================================================
**     Event       :  TU1_OnChannel0 (module Events)
**
**     Component   :  TU1 [TimerUnit_LDD]
**     Description :
**         Called if compare register match the counter registers or
**         capture register has a new content. OnChannel0 event and
**         Timer unit must be enabled. See  and
**          methods. This event is available only if a
**          is enabled.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * UserDataPtr     - Pointer to the user or
**                           RTOS specific data. The pointer passed as
**                           the parameter of Init method.
**     Returns     : Nothing
** ===================================================================
*/
void TU1_OnChannel0(LDD_TUserData *UserDataPtr)
{
  US_EventEchoCapture(UserDataPtr);
}

/*
** ===================================================================
**     Event       :  TU1_OnCounterRestart (module Events)
**
**     Component   :  TU1 [TimerUnit_LDD]
**     Description :
**         Called if counter overflow/underflow or counter is
**         reinitialized by modulo or compare register matching.
**         OnCounterRestart event and Timer unit must be enabled. See
**          and  methods. This event is
**         available only if a  is enabled.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * UserDataPtr     - Pointer to the user or
**                           RTOS specific data. The pointer passed as
**                           the parameter of Init method.
**     Returns     : Nothing
** ===================================================================
*/
void TU1_OnCounterRestart(LDD_TUserData *UserDataPtr)
{
  US_EventEchoOverflow(UserDataPtr);
}

In case of Overflow I simply set the state machine to the overflow state:

void US_EventEchoOverflow(LDD_TUserData *UserDataPtr) {
  US_DeviceType *ptr = (US_DeviceType*)UserDataPtr;

  ptr->state = ECHO_OVERFLOW;
}

While in the interrupt/event for raising or falling edge, I reset the counter value at raising edge, or read out the counter value at falling edge:

  US_DeviceType *ptr = (US_DeviceType*)UserDataPtr;

  if (ptr->state==ECHO_TRIGGERED) { /* 1st edge, this is the raising edge, start measurement */
    TU1_ResetCounter(ptr->echoDevice);
    ptr->state = ECHO_MEASURE;
  } else if (ptr->state==ECHO_MEASURE) { /* 2nd edge, this is the falling edge: use measurement */
    (void)TU1_GetCaptureValue(ptr->echoDevice, 0, &ptr->capture);
    ptr->state = ECHO_FINISHED;
  }

With this I reset the counter on the raising edge, and get the counter value at the falling edge. Then I set the state to ‘finished’: this will be the state I wait for (polling) we will see later.

Measure!

I have implemented a function which sends the trigger, and then waits until the measurement has been finished:

uint16_t US_Measure_us(void) {
  uint16_t us;

  /* send 10us pulse on TRIG line. */
  TRIG_SetVal(usDevice.trigDevice);
  WAIT1_Waitus(10);
  usDevice.state = ECHO_TRIGGERED;
  TRIG_ClrVal(usDevice.trigDevice);
  while(usDevice.state!=ECHO_FINISHED) {
    /* measure echo pulse */
    if (usDevice.state==ECHO_OVERFLOW) { /* measurement took too long? */
      usDevice.state = ECHO_IDLE;
      return 0; /* no echo, error case */
    }
  }
  us = (usDevice.capture*1000UL)/(TU1_CNT_INP_FREQ_U_0/1000);
  return us;
}

It sends the 10 us trigger and then waits for the finished state. In case of overflow (no echo received), I simply return a value of zero.

The function returns the measured echo time in microseconds. To deal with different timer frequencies, the macro TU1_CNT_INP_FREQ_U_0 is used which is generated by Processor Expert.

Calculating to Distance

Usually I’m not interested in the echo time, but rather in the distance itself. For this I have created a utility function to transform the echo time (microsecond) into centimeter distance:

static uint16_t calcAirspeed_dms(uint8_t temperatureCelsius) {
  /* Return the airspeed depending on the temperature, in deci-meter per second */
  unsigned int airspeed; /* decimeters per second */

  airspeed = 3313 + (6 * temperatureCelsius); /* dry air, 0% humidity, see http://en.wikipedia.org/wiki/Speed_of_sound */
  airspeed -= (airspeed/100)*15; /* factor in ~15% for a relative humidity of ~40% */
  return airspeed;
}

uint16_t US_usToCentimeters(uint16_t microseconds, uint8_t temperatureCelsius) {
  return (microseconds*100UL)/calcAirspeed_dms(temperatureCelsius)/2; /* 2 because of two way */
}

:idea: Speed of sound depends on factors like temperature, relative humidity and above sea level (media density). The above function is not counting in everything, but is accurate enough for me.

Example Application

Now using it is pretty simple: from my main routine I intialize my drivers, and then periodically call the function to measure the distance. To make things visual, I show values on a LCD plus show with the RGB LED the distance:

static void Measure(void) {
  uint16_t us, cm;
  uint8_t buf[8];

  us = US_Measure_us();
  UTIL1_Num16uToStrFormatted(buf, sizeof(buf), us, ' ', 5);
  LCD1_GotoXY(1,5);
  LCD1_WriteString((char*)buf);

  cm = US_usToCentimeters(us, 22);
  UTIL1_Num16uToStrFormatted(buf, sizeof(buf), cm, ' ', 5);
  LCD1_GotoXY(2,5);
  LCD1_WriteString((char*)buf);

  LEDR_Put(cm<10); /* red LED if object closer than 10 cm */
  LEDB_Put(cm>=10&&cm<=100); /* blue LED if object is in 10..100 cm range */
  LEDG_Put(cm>100); /* blue LED if object is in 10..100 cm range */
}

/*lint -save  -e970 Disable MISRA rule (6.3) checking. */
int main(void)
/*lint -restore Enable MISRA rule (6.3) checking. */
{
  /* Write your local variable definition here */

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
  PE_low_level_init();
  /*** End of Processor Expert internal initialization.                    ***/

  /* Write your code here */
  US_Init();
  LCD1_Clear();
  LCD1_WriteLineStr(1, "us: ");
  LCD1_WriteLineStr(2, "cm: ");
  for(;;) {
    Measure();
    WAIT1_Waitms(50); /* wait at least for 50 ms until the next measurement to avoid echos */
  }

  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/
  /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/
  #ifdef PEX_RTOS_START
    PEX_RTOS_START();                  /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
  #endif
  /*** End of RTOS startup code.  ***/
  /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
  for(;;){}
  /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

:idea: If you do not have a LCD, simply strip off the LCD code :-).

The other thing to consider: inside the main() loop I use a delay of 50 ms: In case of an echo it will take about 25 ms for the echo to arrive: with 50 ms I will be calm for some time until I send another ‘ping’.

And here is a short video to see everything in action:

Summary

Once getting through the concept and principles, it is rather easy to use an ultrasonic range sensor like the HC-SR04. Setting up the input capture/counter is the most tricky part. But I think with the concepts and steps outlined above, this should work out pretty good for any other microcontroller, especially if used with CodeWarrior and Processor Expert.

The project shown above is available here.

If you are looking for improvements, here are some ideas:

  • properly calculate in the humidity and air density.
  • Using a temperature sensor to factor in the current air temperature.
  • Averaging the samples.
  • Dynamic measurement time, adaptive to the distance found to save battery energy.
  • Using an RTOS like FreeRTOS. Especially to reduce the ‘busy waiting’ time and to do something useful during that time.
  • Shell support (e.g. FSShell) to show values on a console, including setting of calibration values.
  • Create a Processor Expert Component for it.
  • As the ultrasonic beam is rather focused: add a pan a tilt servo to it to ‘explore’ more.
  • Adding more sensors and actuators to use it for a robot application :-)

Happy Ultrasonic-Sounding :-)

About these ads

51 thoughts on “Tutorial: Ultrasonic Ranging with the Freedom Board

      • I tried the same in my Freedom board and failed :’( , It would be great for you to do a tutorial on this, when you can, no pressure :)

      • Hi Alex,
        well, I thought that this *is* already a tutorial? Maybe one of your settings is wrong? Could you try the project (link at the end of the tutorial). You might simply remove the LCD code, and if you use the same pins, then it should work for you as well.
        Hope this helps,
        Erich

  1. Hi Erich,

    Thanks for the above. It may save someone’s life some day (remote chance). I have been pondering how to impliment an emergency stop circuit on a device I have been designing with the FRDM board.

    I think using the above idea to detect if someone (or part of someone) is in a dangerous place is a good idea.

    Thank you.

    • You are welcome. Just keep in mind that the ultrasonic beam is rather small and focused. To cover a larger area it is necessary to move the beam around, or to use multiple sensors. Depending on your application: in robotics (I mean big industrial robots) they are using in many cases a ‘laser curtain’: multiple laser beams to form a curtain to detect if something/someone is moving into the danger zone. That’s simpler and more reliable than ultrasonic in my view.

  2. Pingback: The Freedom Robot | MCU on Eclipse

  3. Hi,
    After reading your posts I ordered one FRDM-KL25Z and started to have fun:)
    Can you please help me with this application:
    First of all the compiled code provided is not loading properly. (No LCD attached but the RGB indication should have worked)
    Downloaded the project.
    Removed the LCD component.
    Recompiled the code.
    After recompiling and loading the RED led stays always on.
    Added ConsoleIO component and printf(“time is:%u\n”, us); after us = US_Measure_us(); so I can read the values on my PC.
    Now the I can see that us has some values as I move an object in front of the sensor but they are like:27, 24, 21,18,15,12, 9 and only at very close range(5 cm). If the object is farther away then the us value displayed is always 12.
    Some representation problem? Missing some bits from the uint16_t?

    Thank you.
    Cristian

      • Hi,
        thank you for the quick answer,
        -No logic analyzer, maybe will borrow a scope.
        -Will check the setup again tomorrow
        -When trying to load the precompiled code provided by you (Freedom_HC-SR04.hex) the green led near the pemicro chip acts strangely (series of 7 or 8 rapid blinks, pause, then blinks again). Something is wrong with that code?
        -I am not mistreating that bird, that baby entered my house and just before relieving it I took a snapshot :) They are little owls.The whole family lives right under my roof.
        Something like this:
        http://www.beleefdelente.nl/vogel/steenuil

      • Nice birds, indeed!
        I suggest that you check as well the wiring:Make sure you have that voltage divider in place, plus everything connected to the right pins on the Freedom board.
        And it could be possible as well that your ultrasonic module is not working properly. I assume you are using the HC-SR04? Because there might be different types of modules around.

  4. Hi!
    Problem Solved!
    The HC-SR04 module was defective! Replaced it and now the application works nicely :)
    Maybe some people are used to it, but I discovered today: The PicKit2 programmer has a Logic Tool function which is very useful.
    Still 2 problems remain:
    1-The code provided by you Erich has the Flash image format set as “ihex” and I cannot load it into the FRDM-KL25Z. I have to set it as “srec” and rebuild the project. Also the LCD component has to be removed if LCD module not available.
    2-Measuring the Trig signal I noticed it is 120us long, not 10us as expected. Trying to decrease the argument of the WAIT1_Waitus(10); function I can only obtain 3 us for WAIT1_Waitus(5) and no other values in between. Why could this happen?

    Keep up the good work!

    Cristian

    • Hi John, yes, I do not see why this should be a problem. All what you need is an output pin plus an input pin. And of course adopt the driver/software for the PIC.

  5. I’m now learning PIC am newbie. I know very little about PIC
    I have a project, and I have to measure the distance from this sensor (HC-SR04) using PIC18F4550.
    Do you know any tutorial to learn how to do?

  6. Pingback: Tracked Robot Update: Ultrasonic, Line Sensor and Shell with SMAC 802.15.4 | MCU on Eclipse

  7. Pingback: Mini Sumo Robot with Proximity Sensors | MCU on Eclipse

  8. Hello,
    First, sorry my english.
    My name is Fernando, I from Brazil. Congratulation foi job.
    I wonder if it is possible to add an additional ultrasonic sensor using the same component TimerUnit_LDD. And how do I?

    Thank you

    • Hi Fernando,
      thanks :-)
      no worries about English: mine is not perfect too ;-)
      I think it should be possible to add another sensor, but I have not done this. Would need to try first myself. Sure the same time base could be used to measure the signal.

      • Thank you for the reply!
        This, put two sensors, however, he only reads a sensor, the other gives error in this part:

        while (usDevice.state! = ECHO_FINISHED) {
        if (usDevice.state == ECHO_OVERFLOW) {
        usDevice.state = ECHO_IDLE;
        return 0; / * ERROR * /
        }
        }

        The second sensor enters if and returns 0. I had to declare another variable of type “static US_DeviceType” you know if you need to set something before you start using?

  9. Thank you for the reply!
    This, put two sensors, however, he only reads a sensor, the other gives error in this part:

    while (usDevice.state! = ECHO_FINISHED) {
    if (usDevice.state == ECHO_OVERFLOW) {
    usDevice.state = ECHO_IDLE;
    return 0; / * ERROR * /
    }
    }

    The second sensor enters if and returns 0. I had to declare another variable of type “static US_DeviceType” you know if you need to set something before you start using?

  10. Hi Erich,

    Great tutorial- been really helpful so far! I am new to programming and have a couple of questions.

    With the code, what header file should be used?

    Should the code you have given on this page be in one .c source file or a different file for each section?

    Thank you for your help

    Jonny

  11. Erich,
    First off, thank you so much for all your tutorials. I’ve been playing with the Kinetis boards for some hobby projects over the last year and your tutorials and insights have been invaluable.

    I’ve modified your code to use 4 sensors. I added three additional channels to the timer unit. I also added function pointers for the trigger pin functions to your US_DeviceType struct and then created another struct (US_Devices) that holds an array of 4 US_DeviceType structs and a counter. In the init function I set the function pointers for each sensor to the appropriate pin function. Then I modified your code to loop through the 4 sensors updating the counter in the struct using the counter and pin function pointers in the struct pointer passed to the events. Theoretically it should be usable for any number of sensors.

    I’ve posted it to GitHub so others can use it if they like.

    https://github.com/madseumas/Kinetis/tree/master/Ultrasonic

    It has some other code from FreeRTOS; I keep the US sensors in their own task since US_Measure blocks and I send off the results to another task via a queue.

    At some point I’d like to get it so I can fire the sensors in pairs (front/back and left/right) at the same time, but since the timer unit’s overflow event fires for all 4 channels without indicating which channel overflowed I’m not sure yet how to go about that.

    I’m a relative C newb so I wouldn’t be surprised if there are any bugs I haven’t caught yet.

    Once again thank you so much for all of your tutorials!

  12. Hi Erich,
    Thank for your great work. I have some troubles with load your ready code to CodeWarrior and programm to board.
    Can you tell how can I do it properly ?
    (sorry for that simple issue but I’m a newbie ;P)
    Best regards

  13. Pingback: Programmable Ultrasonic Sensor Shield for FRDM Board | MCU on Eclipse

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s