Synchronous and asynchronous library for ultrasonic distance measurement for the device HC-SR04 with error handling functionality (out of range detection, HW error detection). Main features: "echo" puls duration measurement, distance measurement from "echo" pulse duration, detection of "echo" signal malfunction, timeout detection, detection of measured values outside reliable limits (min, max)

Dependents:   TEST_Dist_lib

Distance_HC_SR04.cpp

Committer:
dzoni
Date:
2018-04-13
Revision:
12:5bf5a7e62c5d
Parent:
11:12f9cb7d88f3

File content as of revision 12:5bf5a7e62c5d:

#include "Distance_HC_SR04.h"

/**
 * Applied rules: 0, 1, 
 */

/** Create Distance_HC_SR04 instance. Set FSM to IDLE state.
 *
 */
Distance_HC_SR04::Distance_HC_SR04(PinName trig, PinName echo, uint32_t tout_us, float coeff,
        uint32_t tmin_us, uint32_t tmax_us) :
        _trig(trig), _echo(echo), _tout_us(tout_us), _coeff(coeff), _tmin_us(tmin_us), _tmax_us(tmax_us)
{
    _trig = 0;
    _state = IDLE;
}

/** Measure and return "echo" pulse duration in synchronous blocking mode.
 *
 * New measurement is started and the code waits for measurement completion or timeout.
 *
 * @param void -
 * @returns
 *   uint32_t value of distance > 0 in case of a success, 0 in case of an error
 */    
uint32_t Distance_HC_SR04::measureTicks(void)
{
    reset();
    trigger();

    while (STARTED == _state)
    {
        ;
    }

    _echo.rise(NULL);
    _echo.fall(NULL);
    _timeout.detach();

    switch (_state)
    {
        case COMPLETED:
            break;

        default:
            _ticks_us = 0;
            break;
    }

    return _ticks_us;
}

/** Measure and return the distance in synchronous blocking mode.
 *
 * New measurement is started and the code waits for measurement completion or timeout.
 *
 * @param void -
 * @returns
 *   float value of distance > 0.0f in case of a success, 0.0f in case of an error
 */    
float Distance_HC_SR04::measureDistance(void)
{
    return measureTicks()*_coeff;
}

/** Reset whole device and prepare for triggering of the next measurement in asynchronous non-blocking mode. 
 *
 *  FSM set to IDLE state.
 *
 */
void Distance_HC_SR04::reset(void)
{
    _state = IDLE;
    _echo.rise(NULL);
    _echo.fall(NULL);
    _timeout.detach();
    _timer.stop();
    _timer.reset();
}

/** Start the measurement in asynchronous non-blocking mode.
 * 
 *  Generates pulse on "trig" output and checks proper value of "echo" signal. Sets FSM STATE and exits.
 *
 *  If "echo" is low right after "trig" pulse is generated, sets FSM state to "STARTED".
 *  In other case FSM sate is set to "ERROR_SIG".
 *
 */
void Distance_HC_SR04::trigger(void)
{
    if (IDLE == _state && 0 == _echo)
    {
        _trig = 1;
        wait_us(TRIG_PULSE_US);
        _trig = 0;
        if (0 == _echo) {
            _state = STARTED;
            _timeout.attach_us(this, &Distance_HC_SR04::_tout, TIMEOUT_DELAY_US);
            _echo.rise(this, &Distance_HC_SR04::_rising);
            _echo.fall(this, &Distance_HC_SR04::_falling);

            return;
        }
    }

    if (IDLE == _state) {
        _state = ERROR_SIG;
        _ticks_us = 0;
    }

    return;
}

/** Returns a state of measurement FSM in asynchronous non-blocking mode.
 *
 *  This function is used in asynchronous non-blocking mode.
 *
 * @returns
 *   Distance_HC_SR04_state FSM state value.
 */
Distance_HC_SR04_state Distance_HC_SR04::getState(void)
{
   return _state;
}

/** Return measured duration of "echo" pulse in "COMPLETED" state. Use in asynchronous non-blocking mode.
 *
 *  New measurement is not started. Uses result from last measurement.
 *
 * @returns
 *   uint32_t Measured duration of "echo" pulse in microseconds.
 */
uint32_t Distance_HC_SR04::getTicks(void)
{
    return _ticks_us;
}

/** Return distance of the obstacle. Use in asynchronous non-blocking mode.
 *
 *  New measurement is not started. Uses result from last measurement.
 *
 * @returns
 *   float Distance in milimiters calculated from measured duration of "echo" pulse.
 */
float Distance_HC_SR04::getDistance(void)
{
    return _ticks_us * _coeff;
}

/** Return actual value of coefficient used to calculate distance from "echo" pulse duration.
 *
 * @returns
 *   float Value of the coefficient used to multiply time in microseconds to get distance in mm.
 */
float Distance_HC_SR04::getCoeff(void)
{
    return _coeff;
}

/** Set the actual value of coefficient used to calculate distance from "echo" pulse duration.
 *
 * @param coeff Coeficient for multiplication with pulse duration in microseconds
 * @returns
 *   void -
 */    
void Distance_HC_SR04::setCoeff(float coeff)
{
    _coeff = coeff;
}

/** Timeout callback function (private).
 *
 * @param void -
 * @returns
 *   void -
 */    
void Distance_HC_SR04::_tout(void) {
    if (STARTED == _state)
        _state = TIMEOUT;
}

/** Rising edge callback function (private).
 *
 * @param void -
 * @returns
 *   void -
 */    
void Distance_HC_SR04::_rising(void) {
    if (STARTED == _state) {
        _timer.start();
    }
}

/** Falling edge callback function (private).
 *
 * @param void -
 * @returns
 *   void -
 */    
void Distance_HC_SR04::_falling(void) {
    if (STARTED == _state) {
        _timer.stop();
        _ticks_us = _timer.read_us();

        if (_ticks_us < _tmin_us)
        {
            _ticks_us = 0;
            _state = OUT_OF_RANGE_MIN;
        } else if (_ticks_us > _tmax_us)
        {
            _ticks_us = 0;
            _state = OUT_OF_RANGE_MAX;
        } else
        {
            _state = COMPLETED;
        }
    }
}