This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CCS/MSP432P401R: Timer A - Capture Mode for ultrasonic sensor HC-SR04

Part Number: MSP432P401R
Other Parts Discussed in Thread: 4460

Tool/software: Code Composer Studio

Hello, 

I am attempting to get measurements from my HCSR04 in centimeters. I've implemented the code from  with the fix of changing line 44 and 45. I added in the line printf("Measure 1 %i \n",meas1); to print out measurements as they are received. Below if a sample of what I get outputted holding an object about 10 cm from the sensor:

Measure 1 10516
Measure 1 49666
Measure 1 22997
Measure 1 63764
Measure 1 36141
Measure 1 9821
Measure 1 37
Measure 1 39586
Measure 1 13812
Measure 1 52755
Measure 1 27588
Measure 1 16081
Measure 1 56333
Measure 1 29705
Measure 1 3162
Measure 1 43098
Measure 1 16457
Measure 1 56342
Measure 1 30565
Measure 1 4821
Measure 1 44672
Measure 1 33393
Measure 1 7650
Measure 1 41721
Measure 1 41357
Measure 1 61195
Measure 1 50128
Measure 1 24761
Measure 1 64427
Measure 1 37530
Measure 1 11928
Measure 1 52452
Measure 1 23292
Measure 1 64951
Measure 1 38758
Measure 1 12566
Measure 1 51407
Measure 1 42480
Measure 1 17720
Measure 1 55112
Measure 1 29513
Measure 1 19707
Measure 1 58576
Measure 1 32103
Measure 1 7040
Measure 1 61467
Measure 1 20642
Measure 1 10391
Measure 1 65068
Measure 1 53756
Measure 1 42393
Measure 1 32610
Measure 1 56912
Measure 1 44669
Measure 1 34054
Measure 1 58689
Measure 1 32883
Measure 1 57672
Measure 1 32669
Measure 1 21598
Measure 1 62080
Measure 1 51102
Measure 1 24315
Measure 1 14081
Measure 1 7423
Measure 1 62643
Measure 1 51311
Measure 1 10443
Measure 1 49979
Measure 1 25411
Measure 1 63454
Measure 1 36915
Measure 1 11794
Measure 1 1642
Measure 1 41995
Measure 1 30202
Measure 1 4146
Measure 1 28636
Measure 1 3008
Measure 1 28608
Measure 1 16239
Measure 1 57237
Measure 1 31123
Measure 1 4064
Measure 1 43718
Measure 1 16956
Measure 1 8475
Measure 1 47844
Measure 1 21287
Measure 1 62099
Measure 1 35635
Measure 1 9989
Measure 1 49772
Measure 1 22966
Measure 1 12083
Measure 1 51187
Measure 1 12165
Measure 1 48357
Measure 1 38766
Measure 1 13215
Measure 1 53292
Measure 1 41796
Measure 1 16191
Measure 1 6029
Measure 1 45661
Measure 1 33639
Measure 1 8928
Measure 1 47028
Measure 1 20769
Measure 1 30260
Measure 1 5155
Measure 1 59807
Measure 1 33075
Measure 1 6982
Measure 1 46236
Measure 1 19808
Measure 1 59112
Measure 1 48377
Measure 1 24050
Measure 1 62639
Measure 1 36904
Measure 1 10630
Measure 1 50163
Measure 1 40678
Measure 1 13810
Measure 1 2941
Measure 1 43707
Measure 1 508
Measure 1 40329
Measure 1 30067
Measure 1 3223
Measure 1 45106
Measure 1 18391
Measure 1 58720
Measure 1 15376
Measure 1 38896
Measure 1 28896
Measure 1 37443
Measure 1 47298
Measure 1 21295
Measure 1 44301
Measure 1 34421
Measure 1 10353
Measure 1 47977
Measure 1 23231
Measure 1 63549
Measure 1 20008
Measure 1 62980
Measure 1 18836
Measure 1 58631
Measure 1 32945
Measure 1 7535
Measure 1 46705
Measure 1 20056
Measure 1 59798
Measure 1 33938
Measure 1 44482
Measure 1 53768
Measure 1 26863
Measure 1 15714
Measure 1 53144
Measure 1 13426
Measure 1 2403
Measure 1 56815
Measure 1 30923
Measure 1 7210
Measure 1 59372
Measure 1 34530
Measure 1 8179
Measure 1 46241
Measure 1 22025
Measure 1 11576
Measure 1 50009
Measure 1 39510
Measure 1 14232
Measure 1 23814
Measure 1 12365
Measure 1 52560
Measure 1 40939
Measure 1 15436
Measure 1 4944
Measure 1 43761
Measure 1 17465
Measure 1 26234
Measure 1 65208
Measure 1 39756
Measure 1 28576
Measure 1 4460
Measure 1 27612
Measure 1 3189
Measure 1 40341
Measure 1 1059
Measure 1 54404
Measure 1 27501
Measure 1 2366
Measure 1 40652
Measure 1 30642
Measure 1 5696
Measure 1 42805
Measure 1 18367
Measure 1 58656
Measure 1 30799
Measure 1 7123
Measure 1 59539
Measure 1 49710
Measure 1 9022
Measure 1 49493
Measure 1 22652
Measure 1 46298
Measure 1 20796
Measure 1 59382
Measure 1 33907
Measure 1 8443
Measure 1 60975
Measure 1 50529
Measure 1 8925
Measure 1 64678
Measure 1 39850
Measure 1 61871
Measure 1 38358
Measure 1 26183
Measure 1 1066
Measure 1 54269
Measure 1 29408
Measure 1 55468
Measure 1 10911
Measure 1 20796
Measure 1 45038
Measure 1 34744
Measure 1 23529
Measure 1 65463
Measure 1 38229
Measure 1 61480
Measure 1 35773
Measure 1 9138
Measure 1 50486
Measure 1 22753
Measure 1 12731
Measure 1 52889
Measure 1 42543
Measure 1 16379
Measure 1 4386
Measure 1 59805
Measure 1 33237
Measure 1 21977
Measure 1 11702
Measure 1 50661
Measure 1 23999
Measure 1 63920
Measure 1 40205
Measure 1 10802
Measure 1 51300
Measure 1 41671
Measure 1 14204
Measure 1 54636
Measure 1 43874
Measure 1 20759
Measure 1 7471
Measure 1 47403
Measure 1 20973
Measure 1 10180
Measure 1 49847
Measure 1 39346
Measure 1 14048
Measure 1 52678
Measure 1 11390
Measure 1 65283
Measure 1 40751
Measure 1 63600
Measure 1 37479
Measure 1 11514
Measure 1 20259
Measure 1 45668

Clearly these numbers are not in cm, nor are they a consistent reading. In the script meas1 is an integer so that's what I attempted to print it as. Is there a conversion I am missing?

  • If you're talking about the code at 

    https://e2e.ti.com/support/microcontrollers/msp430/f/166/t/607119

    It looks as though he hadn't quite finished with it.

    Those values are in units of SMCLK ticks where SMCLK=3MHz (333nsec). meas1 isn't all that useful in itself, what's interesting is the pulse width, which is the difference ((meas2-meas1)&0xFFFF), which goes into a formula in the data sheet. I (vaguely) recall that formula needs usec, so you'll need to divide by 3.

  • Thank you, yes that is the code I was referring to. 

    My problem now is that I am never detecting a falling edge so I don't enter the else loop and get a meas2. Is there something else I have to wire or code to detect P2IN&0x10? Here is the interrupt loop for reference:

    void TA0_N_IRQHandler(void)
    {
        int rising  = 0;
        Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE,
                TIMER_A_CAPTURECOMPARE_REGISTER_1);
        if(P2IN&0x10) rising=1; else rising=0;
        if(rising) // Start
        {
            meas1 = Timer_A_getCaptureCompareCount(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1);
        }
        else
        {
            meas2 = Timer_A_getCaptureCompareCount(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1);
        }
    }
  • > TIMER_A_CAPTUREMODE_RISING_EDGE,          // Rising Edge and falling

    I suspect he intended:

    > TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE, // Rising Edge and falling

  • With that fix I'm getting both rising and falling measurements. The data sheet has this conversion formula:

    Test distance = (high level time×velocity of sound (340M/S) / 2,

    I do the conversion in my code with these lines:

    int diff=((meas2-meas1)&0xFFFF);
    //int distCM=(diff/3000000)*340/2;
    int distCM=(diff*170)/3000000;
    printf("Distance: %i cm \n",distCM);

    I am only getting values between 0-3cm whether I hold the sensor still or move it back and forth. The inconsistency in values holding it still make me believe my issue is not conversion. Also, there is a lot of lagging in the code and when I pause it, it's usually in the delay loop.

    Here's and example what I get with holding still or moving the sensor:

    Measure 2 19599

    Distance: 1 cm

    Measure 1 40528

    Distance: 2 cm

    Measure 2 32299

    Distance: 3 cm

    Measure 1 7705

    Distance: 1 cm

    Measure 2 29517

    Distance: 1 cm

    Measure 2 54117

    Distance: 2 cm

    Measure 1 9145

    Distance: 2 cm

    Measure 2 59060

    Distance: 2 cm

    Measure 1 32526

    Distance: 1 cm

    Measure 2 32498

    Distance: 3 cm

    Measure 1 22439

    Distance: 0 cm

    Measure 2 11283

    Distance: 3 cm

    Measure 1 59847

  • 1) The first datasheet I found suggested the formula cm = usec/58, i.e. 1 cm is 58 usec. This is the same formula as you're using, but in a simpler form. Since each tick is 1/3 usec, it would be cm = ticks/3/58. I mention this since your formula is probably truncating based on the large (3M) divisor. I suggest you use the simpler formula for now.

    2) Your code seems to produce a result after every capture, which doesn't look quite right. After you send the pulse, you should get two captures and only then can you produce a useful result. As a result I suspect you're getting very large (false)  differences which (just barely) make it through the truncation in (1). Where in the code did you insert the arithmetic?

    3) The Delay function uses a for() loop for a delay, which is notoriously unreliable. I suggest you get rid of all the Delay calls and replace them with something like:

    #define  HZ   24000000UL    // 24MHz from CS_DCO_FREQUENCY_24

    __delay_cycles(HZ/2);     // delay for a half-second.

  • Thanks for helping me work through this. After implementing your three suggestions this is what my code looks like now:

    #include "driverlib.h"
    #include <stdint.h>
    
    #define  HZ   24000000UL    // 24MHz from CS_DCO_FREQUENCY_24
    
    /* Timer_A Continuous Mode Configuration Parameter */
    const Timer_A_ContinuousModeConfig continuousModeConfig =
    {
            TIMER_A_CLOCKSOURCE_SMCLK,           // SMCLK Clock Source
            TIMER_A_CLOCKSOURCE_DIVIDER_1,       // SMCLK/1 = 3MHz
            TIMER_A_TAIE_INTERRUPT_DISABLE,      // Disable Timer ISR
            TIMER_A_SKIP_CLEAR                   // Skup Clear Counter
    };
    
    /* Timer_A Capture Mode Configuration Parameter */
    const Timer_A_CaptureModeConfig captureModeConfig =
    {
            TIMER_A_CAPTURECOMPARE_REGISTER_1,        // CC Register 2
            TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE, // Rising Edge and falling TIMER_A_CAPTUREMODE_RISING_EDGE,          // Rising Edge and falling
            TIMER_A_CAPTURE_INPUTSELECT_CCIxA,        // CCIxA Input Select
            TIMER_A_CAPTURE_SYNCHRONOUS,              // Synchronized Capture
            TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE,  // Enable interrupt
            TIMER_A_OUTPUTMODE_OUTBITVALUE            // Output bit value
    };
    
    int meas1 = 0;
    int meas2 = 0;
    int meas1Count=0;
    int takeVal=0;
    
    int main(void)
    {
        /* Stop watchdog timer */
        MAP_WDT_A_holdTimer();
    
        CS_setDCOCenteredFrequency(CS_DCO_FREQUENCY_24);                    // 24000000 Hz
    
        CS_initClockSignal(CS_MCLK,  CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1); // 24000000 Hz
        CS_initClockSignal(CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_8); //  3000000 Hz
    
        /* Configuring P2.4 as peripheral input for capture */
        GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2, GPIO_PIN4, GPIO_PRIMARY_MODULE_FUNCTION);
        GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN5);
    
        /* Configuring Capture Mode */
        Timer_A_initCapture(TIMER_A0_BASE, &captureModeConfig);
    
        /* Configuring Continuous Mode */
        Timer_A_configureContinuousMode(TIMER_A0_BASE, &continuousModeConfig);
    
        /* Enabling interrupts */
        Interrupt_enableInterrupt(INT_TA0_N);
        Interrupt_enableMaster();
    
        /* Starting the Timer32 */
        Timer32_initModule(TIMER32_0_BASE, TIMER32_PRESCALER_1, TIMER32_32BIT, TIMER32_PERIODIC_MODE);
        Timer32_disableInterrupt(TIMER32_0_BASE);
        Timer32_setCount(TIMER32_0_BASE, 1);
        Timer32_startTimer(TIMER32_0_BASE, true);
    
        /* Starting the Timer_A0 in continuous mode */
        Timer_A_startCounter(TIMER_A0_BASE, TIMER_A_CONTINUOUS_MODE);
        while(1)
        {
            GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN5);
            Timer32_setCount(TIMER32_0_BASE, 24 * 10);
            while (Timer32_getValue(TIMER32_0_BASE) > 0); // Wait 10us
            GPIO_setOutputLowOnPin(GPIO_PORT_P1, GPIO_PIN5);                //software delays
            __delay_cycles(HZ/2);     // delay for a half-second.
    //        __delay_cycles(HZ/2);     // delay for a half-second.
    //        __delay_cycles(HZ/2);     // delay for a half-second.
    //        __delay_cycles(HZ/2);     // delay for a half-second.
    //        __delay_cycles(HZ/2);     // delay for a half-second.
    //        __delay_cycles(HZ/2);     // delay for a half-second.
    
            if (takeVal==1){
                takeVal=0;
                int diff=((meas2-meas1)&0xFFFF);
                //int distCM=(diff/3000000)*340/2;
                //int distCM=(diff*170)/3000000;
                int distCM=(diff/3)/58;
                printf("Distance: %i cm \n",distCM);
            }
    
        }
    }
    
    void TA0_N_IRQHandler(void)
    {
        int rising  = 0;
    
        Timer_A_clearCaptureCompareInterrupt(TIMER_A0_BASE,
                TIMER_A_CAPTURECOMPARE_REGISTER_1);
    
        if(P2IN&0x10) rising=1; else rising=0;
    
        if(rising) // Start
        {
            meas1 = Timer_A_getCaptureCompareCount(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1);
            printf("Measure 1 %i \n",meas1);
            meas1Count=1;
        }
        else
        {
            meas2 = Timer_A_getCaptureCompareCount(TIMER_A0_BASE, TIMER_A_CAPTURECOMPARE_REGISTER_1);
            printf("Measure 2 %i \n",meas2);
            if (meas1Count==1){ //if meas1 has been collected
                meas1Count=0; //reset meas1 count
                takeVal=1; //flag for conversion
            }
        }
    }
    

    When I comment out the meas1 and meas2 prints this is a typical output:

    Distance: 0 cm 
    Distance: 137 cm 
    Distance: 147 cm 
    Distance: 144 cm 
    Distance: 135 cm 
    Distance: 227 cm 
    Distance: 136 cm 
    Distance: 222 cm 
    Distance: 131 cm 
    Distance: 133 cm 
    Distance: 134 cm 
    Distance: 129 cm 
    Distance: 228 cm 
    Distance: 237 cm 
    Distance: 135 cm
    

    When I keep the print statement in this is a typical output:

    Measure 1 1 
    Measure 2 11537 
    Distance: 66 cm 
    Measure 1 47626 
    Measure 2 55703 
    Distance: 46 cm 
    Measure 1 27494 
    Measure 2 29699 
    Measure 1 23192 
    Measure 2 65385 
    Measure 1 8440 
    Measure 2 16585 
    Measure 1 24577 
    Measure 2 32799 
    Measure 2 427 
    Measure 1 59435 
    Measure 2 1113 
    Measure 2 33962 
    Measure 1 43383 
    Measure 1 10885 
    Measure 2 2588 
    Measure 1 61997 
    Measure 1 45161 
    Measure 1 27988 
    Measure 1 11263 
    Measure 2 3016 
    Measure 2 51416 
    Measure 2 33972 
    Measure 2 43254 
    Measure 2 26443 
    Measure 1 35817 
    Measure 1 33857 
    Measure 1 1960 
    Measure 1 345 
    Measure 1 48697 
    Measure 1 31889 
    Measure 2 53372 
    Measure 1 63311 
    Measure 1 15686 
    Measure 1 48716 
    Measure 2 40190 
    Measure 2 23186 
    Measure 1 32531 
    Measure 2 39627 
    Measure 1 33550 
    Measure 2 55807 
    Measure 2 53844 
    Measure 1 13498 
    Measure 1 62052 
    Measure 1 44944 
    Measure 1 12568 
    Measure 1 45714 
    Measure 1 13870 
    Measure 1 46865 
    Measure 2 4102 
    Measure 2 52800 
    Measure 1 60952 
    Measure 2 18678 
    Measure 2 51661 
    Distance: 323 cm 
    

    I've been playing around with how many half second delays to add to the code in an attempt to get more consistent/reliable measurements. Is there a more methodical method than guess and check? Also, I know print statements slow down the code, but I don't know why there would be multiple rising measurements and falling measurements in a row.

    Distance: 0 cm
    Distance: 137 cm
    Distance: 147 cm
    Distance: 144 cm
    Distance: 135 cm
    Distance: 227 cm
    Distance: 136 cm
    Distance: 222 cm
    Distance: 131 cm
    Distance: 133 cm
    Distance: 134 cm
    Distance: 129 cm
    Distance: 228 cm
    Distance: 237 cm
    Distance: 135 cm

  • I wonder if you're getting extra echos; I don't know if the HCS04 masks those out, but only the first one is interesting. I suggest:

    1) Don't delay (after the output pulse) waiting for the result, rather start looking immediately. I.e. remove the delays and replace the

    > if (takeval==1)

    with

    > while (takeval==0) /*EMPTY*/; // spin until the first pulse

    (The subsequent curly braces are then redundant.)

    2) Declare "takeval" as "volatile"

    3) Remove the printf()-s from the ISR. They will distort the timing if you get more than one pulse.

    4) After you've captured and displayed the result, put in a delay until things quiet down. How long? 400cm*58usec=23.2msec. The data sheet recommends waiting for at least 60msec. To make this readable, you'll probably want something closer to that half-second.

**Attention** This is a public forum