Writing a program that computes the distance using an ultrasonic sensor

Hello

First of all, I`ve been spending way to many hours trying to figure this out, so I decided to open this ticket. I am new to microcontrollers in general and the Nordic Semiconductor infocenter is above my level understanding. I gave this post the tag of Health and Safety as I am loosing my mind over this minor issue.

I am using SEGGER Embedded Studio.

The controller I am using is a nRF52840 DK.

The ultrasonic sensor I am using is a HC-SR04.

As the ultrasonic sensor either returns a 0.0 value or a 1.0 value, I need to calculate the time from when the `echo` (input pin) is high (1.0) to when it is low (0.0). I have confirmed that the everything works using the nRF52840 as input (5V and trigger pin) and an Arduino as output (echo pin, terminal gave distance in cm), due to the Arduino being much simpler to implement. However, for my project I need to use the nRF due to the BLE thingy.

I have looked into many different tutorials using APP_TIMER, drv_clock and simple_timer. Everything I have looked into is either for the wrong controller, outdated, gives insufficient implementation info or gives errors in my compiler which I cant figure out how to fix.

All I need is a simple timer, my dream scenario looks like this:  #include <super_simple_timer> and then time_start, time_stop and printf(time). However, I understand that more code is needed.

Is there a very simple example code for this, and please do tell what libraries to include, and if there are any changes in the sdk_config.h.

Thanks!

This is what my simple sensor-setup looks like:

This is kind of what my code is going to look like, just need to take a closer look after I hopefully get the timer to work:

#include <stdbool.h>
#include <stdint.h>
#include "nrf_delay.h"
#include "nrf_log.h"
#include "boards.h"
#include "nrf_gpio.h"


#define trig 25 // Output pin
#define echo 11 // Input pin

int main() {
    nrf_gpio_cfg_output(trig);
    nrf_gpio_cfg_input(echo, NRF_GPIO_PIN_NOPULL);


    while(true) {
        // Clear the trig pin
        nrf_gpio_pin_clear(trig);
        nrf_delay_ms(2);


        // Sets the trig pin for 10 ms
        nrf_gpio_pin_set(trig);
        nrf_delay_ms(10);
        nrf_gpio_pin_clear(trig);
    
        // Start the timer here
    
        while(nrf_gpio_pin_read(echo) == 1) {
            //Wait for the input pin to go back to zero
            if (nrf_gpio_pin_read(echo) == 0) {
                //Stop the timer
                break
            }
        }
    // Calculates the distance using the timer and the speed of sound.
    float distance = timer_value *0.034 / 2;
    printf("%f", distance);
    }
}

  • I finally did it!

    This does the trick, but it is messy and probably tons of room for improvement. As the existing tutorials are very lacking if you`re not already familiar with microcontrollers, segger and just a genius in general, I hope this will be of some help to someone out there, sometime.

    Note that this is not optimal at all, I am not even sure if everything I talk about here is needed for it to function, it is probably overkill, but I just got it to work and want to share it.

    I used this tutorial: http://electronut.in/nrf51-hcsr04/.  It also includes tons of BLE code that we do not want, as that is next level stuff. Here is how I did it:

    1. Follow the link at the bottom for the GitHub complete source-code: https://github.com/electronut/nRF51-hcsr04-test

    2. In the "config" folder on GitHub, open the "nrf_drv_config.h". Copy and paste everything here and paste it into the bottom of your "sdk_config.h" folder inside your project.

    You also need to paste some more stuff. Follow this link: https://devzone.nordicsemi.com/guides/short-range-guides/b/software-development-kit/posts/application-timer-tutorial?pi864299341=2&pi628=2

    Scroll down to "Add required files and includes". From the two windows with codes, the one for "app_timer" and the one for the "clock"-thing, copy and paste all of this into your "sdk_config.h".

    3. In your Project in Segger, you also need to add a file called "app_timer.c". Here`s how: Right-click on your Project name in segger --> Add Existing File --> Navigate to your nRF52 folder (that is where you have folder such as examples, external, config, components, etc.) --> Open Components --> Libraries --> Timer --> And choose "app_timer.c".

    4. Copy everything in the main.c file into your own main.c file. Then you have to remove all the BLE code. This was tricky, but here`s what it looks like for me atm and it`s working (as mentioned earlier, the code can be way cleaner):

    #include <stdbool.h>
    #include <stdint.h>
    #include <stdint.h>
    #include <string.h>
    #include "nrf_delay.h"
    #include "nrf_log.h"
    #include "boards.h"
    #include "nrf_gpio.h"
    #include "app_util_platform.h"
    #include "nordic_common.h"
    #include "nrf.h"
    #include "nrf_gpiote.h"
    #include "nrf_drv_gpiote.h"
    #include "nrf51_bitfields.h"
    #include "app_timer.h"
    //
    #define pinTrig 25 // Output pin
    #define pinEcho 11 // Input pin


    // counter
    static volatile uint32_t tCount = 0;

    // count to us (micro seconds) conversion factor
    // set in start_timer()
    static volatile float countToUs = 1;

    // set up and start Timer1
    void start_timer(void)
    {
    NRF_TIMER1->MODE = TIMER_MODE_MODE_Timer;
    NRF_TIMER1->TASKS_CLEAR = 1;

    uint8_t prescaler = 0;
    NRF_TIMER1->PRESCALER = prescaler;
    NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_16Bit;

    uint16_t comp1 = 500;
    // set compare
    NRF_TIMER1->CC[1] = comp1;

    // set conversion factor
    countToUs = 0.0625*comp1*(1 << prescaler);

    printf("timer tick = %f us\n", countToUs);

    // enable compare 1
    NRF_TIMER1->INTENSET =
    (TIMER_INTENSET_COMPARE1_Enabled << TIMER_INTENSET_COMPARE1_Pos);

    // use the shorts register to clear compare 1
    NRF_TIMER1->SHORTS = (TIMER_SHORTS_COMPARE1_CLEAR_Enabled <<
    TIMER_SHORTS_COMPARE1_CLEAR_Pos);

    // enable IRQ
    NVIC_EnableIRQ(TIMER1_IRQn);

    // start timer
    NRF_TIMER1->TASKS_START = 1;
    }

    void TIMER1_IRQHandler(void)
    {
    if (NRF_TIMER1->EVENTS_COMPARE[1] &&
    NRF_TIMER1->INTENSET & TIMER_INTENSET_COMPARE1_Msk) {

    // clear compare register event
    NRF_TIMER1->EVENTS_COMPARE[1] = 0;

    // increment count
    tCount++;
    }
    }

    bool getDistance(float* dist)
    {
    nrf_gpio_pin_clear(pinTrig);
    nrf_delay_us(20);
    nrf_gpio_pin_set(pinTrig);
    nrf_delay_us(12);
    nrf_gpio_pin_clear(pinTrig);
    nrf_delay_us(20);


    while(!nrf_gpio_pin_read(pinEcho));
    // reset counter
    tCount = 0;
    // wait till Echo pin goes low
    while(nrf_gpio_pin_read(pinEcho));

    float duration = countToUs*tCount;

    float distance = duration*0.017;

    if(distance < 400.0) {

    // save
    *dist = distance;

    return true;
    }
    else {
    return false;
    }
    }

    int main() {

    // set up timers
    app_timer_init();

    start_timer();

    // prints to serial port
    printf("starting...\n");

    // set up HC-SR04 pins
    nrf_gpio_pin_dir_set(pinTrig, NRF_GPIO_PIN_DIR_OUTPUT);
    nrf_gpio_pin_dir_set(pinEcho, NRF_GPIO_PIN_DIR_INPUT);


    // main loop:
    while(1) {

    // get HC-SR04 distance
    float dist;
    if(getDistance(&dist)) {

    // enable to print to serial port
    printf("dist = %f cm\n", dist);

    }

    // delay
    nrf_delay_ms(250);
    }
    }

    Good luck!

Related