MSP430F5529 with ultrasonic HC-SR04

Thread Starter

Alejofnb

Joined Dec 24, 2019
20
Hi, i'm trying to use the common ultrasonic sensor HC-SR04 for detecting objects by measuring its distance to the sensor and, if the distance between the object and this sensor is lower than 20 cm, i should warn with the green led on launchap and a buzzer that object is closer than it has to be. As much closer the object is from the sensor (starting to count when distance is lower than 20 cm as i said before), the tone of the buzzer increase proportionally (using PWM). So my problem is that i don't know why my program stops at delay_cycles. Don't know if it is because the sensor isn't detecting my hand approaching as i have programmed in a wrong way, not considering something.. or if the delay_cycles (intrinsec function in TI) is wrong. I appreciate all suggestions and if anyone see any issue in my code, please let me know it. Thanks beforehand!

C:
#include <msp430.h>
#include <stdint.h>

uint16_t volatile contador_milisegundos; // miliseconds counter
uint32_t volatile start_time = 0; // start time of ECHO pulse
uint32_t volatile end_time = 0; // end time of ECHO pulse
uint16_t volatile distancia_cm = 0; // distance measured

#define HZ 16000000UL // 16MHz MCLK


void Inicializacion_Relojes(void) // to use the SMCLK --> 16 MHz
{
        __bis_SR_register(SCG0); // Disable the FLL control loop
    UCSCTL0 = 0x0000; // Ponemos el DCOx y MODx al minimo posible
    UCSCTL1 = DCORSEL_5; // Seleccionamos un rango de operación del DCO range de 16MHz
    UCSCTL2 = FLLD_0 | 487; // Poniendo FLLD_0 hacemos tomamos como 1 el divisor de la frecuencia de entrada del cristal de cuarzo y 487 es el valor multiplicador de FLLN
    // (N + 1) * (FLLRef/n) = Fdcomsp430
    // (487 + 1) * (32768/1) = 16MHz
    UCSCTL3 = 0; // FLL SELREF = XT1CLK y divisor de FLL = 1 (FLLREFDIV = FLLREFCLK/1)
    UCSCTL4 |= SELA_0 | SELS_4 | SELM_4; // Tomamos ACLK = XT1CLK (Cuarzo externo de 2^15 bits); SMCLK = MCLK = DCOCLKDIV (DCO interno de 16 MHz)
    UCSCTL5 |= DIVA_0 | DIVS_0; // Divisor para SMCLK = f(SMCLK)/1; ACLK = f(ACLK)/1
    __bic_SR_register(SCG0); // Enable the FLL control loop
}

void init_pines_ultrasonidos(void)
{
    P1DIR &= ~BIT1; // Pin ECHO as input
    P1SEL |= BIT1; // mode Capture Input Signal (CCI0A)
    P3DIR |= BIT7; // Pin TRIGGER as output
    P3SEL &= ~BIT7; // Gpio pin
    P3SEL &= ~BIT7; // Pin TRIGGER low
}

void pin_buzzer(void) // pin P3.6 as TB0.6 --> P3DIR.6 = 1; P3SEL.6 = 1 (see Table 6-48 Datasheet MSP430F5529)
{
    P3SEL |= BIT6; // P3.6 as alternative function (para Timer TB0.6 según datasheet MSP430F5529)
    P3DIR |= BIT6; // Pin as buzzer output
    P4SEL &= ~BIT7; // Pin GPIO
    P4DIR |= BIT7; // como salida (Led2, verde)
    P4OUT &= ~BIT7; // led inicialmente apagado
}

void delay_ms(uint16_t tiempo_milisegundos) // Function for delay of miliseconds --> SMCLK
{
    contador_milisegundos = 0;
    TA1CTL |= MC_1; // UP MODE
    TA1CCTL0 |= CCIE;
    while(contador_milisegundos < tiempo_milisegundos);
    TA1CTL &= ~MC_3; // stop the timer
}

void TimerA0_capture(void) // Timer for capturing ECHO signal of ultrasonic sensor --> TA0.0 en modo Capture Input (CCI0A)
{
    TA0CCTL0 |= CM_3 | SCS | CCIS_0 | CAP | CCIE; // CM_3: Capture both rising and falling edges of signal; CCIS_0: CCIxA --> Capture/Compare in TimerA; CAP: enable capture mode; CCIE: enable interrupciones
    TA0CTL |= TASSEL_2 | MC_2 | ID_0 | TACLR; // TASSEL_2: SMCLK; MC_2: Continuous Mode; ID_0: f(SMCLK)/1; TACLR: Reset Timer
}

void init_TimerA1_ms(void) // for delay
{
    TA1CCR0 = 16000-1; // pulses for 1 milisecond
    TA1CTL |= TASSEL_2 | MC_0; // SMCLK, Freq: 16 MHz; MC_1: Stop Mode
}

void TimerB0_PWM(void) // Timer for monitoring PWM of buzzer
{
    TB0CCR0 = 249; // Período de PWM: 250 pulsos --> 4kHz (o 0,25 ms) --> 1000 pulses/ms · 0,25 ms (inverse of 4kHz) = 250 - 1 = 249.
    TB0CCTL6 |= OUTMOD_7; // Modo CCR6: PWM Reset/Set --> increasing CCR6 value will also increase Duty Cycle --> more buzzer amplitude
    TB0CCR6 = 0; // Duty Cycle inicial: 0 %. TB0.6 --> TB0CCR6.
    TB0CTL |= TASSEL_2 | ID_0 | MC_1 | TACLR; // TASSEL_2: SMCLK; ID_2: Divisor freq --> f(SMCLK)/1; MC_1: Up Mode
}

void main()
{
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
    Inicializacion_Relojes();
    init_pines_ultrasonidos();
    pin_buzzer_and_LED();
    TimerA0_capture();
    init_TimerA1_ms();
    TimerB0_PWM();
    __enable_interrupt();
    while(1){
        P3OUT |= BIT7; // generate pulse TRIGGER
        __delay_cycles(10*HZ/1000000UL); // pulse of 10 us in TRIGGER pin for obtaining the measures (see datasheet HC-SR04)
        P3OUT &= ~BIT7; // disable TRIGGER pulse
        delay_ms(100); // delay over 60 ms measurement cycle in order to prevent trigger signal to the echo signal (see Datasheet HC-SR04)
        if(distancia_cm < 20 && distancia_cm != 0){ // if distance between object and the sensor is lower than 20 cm and also different from zero..
            P4OUT |= BIT7; // LED green ON
            TB0CCR6 = 0; // Reset value of Timer that decides the final PWM value
            TB0CCR6 += 249 - (distancia_cm * 12); // Aumentamos la frecuencia del tono del buzzer conforme estamos más cerca del objeto (a menor distancia)
        }
    }
}


#pragma vector=TIMER1_A0_VECTOR
__interrupt void timer1_A0_ISR(void)
{
    contador_milisegundos++;
    TA1CCTL0 &= ~CCIFG;
}

#pragma vector=TIMER0_A0_VECTOR // ISR de Capture Signal TA0.0
__interrupt void Timer0_A0(void)
{
    if(TA0CCTL0 & CCI){ // Read the CCI bit (ECHO signal) --> CCI reflects the state of Captura pin --> ECHO signal
        start_time = TA0CCR0; //takes first time measure in us
    }
    else{
        end_time = TA0CCR0; //takes second time measure in us
        distancia_cm = (end_time - start_time)/58; // to obtain distance in centimeters: (time in us/58) --> (see Datasheet HC-SR04)
    }
    TA0CTL &= ~TAIFG;
}
Mod edit: code tags
 
Last edited by a moderator:

MrChips

Joined Oct 2, 2009
30,712
Check this out:

__delay_cycles(10*HZ/1000000UL); // pulse of 10 us in TRIGGER pin for obtaining the measures (see datasheet HC-SR04)

Look up the data type for value in _delay_cycles( value) .
I suspect it could be unit16_t or uint32_t. In any case, make sure that the calculation does not exceed the range of the data type.
 

Irving

Joined Jan 30, 2016
3,845
From TI documentation : "The __delay_cycles intrinsic inserts code to consume precisely the number of specified cycles with no
side effects. The number of cycles delayed must be a compile-time constant"

So add line at top:
#define 10uS_delay 10*HZ/1000000UL

Then use:

__delay_cycles(10us_delay)
 

Thread Starter

Alejofnb

Joined Dec 24, 2019
20
Okey, seems like i have fixed the problem of the delay_cycles by creating my own function (also using delay_cycles, but avoiding issues that you told me like having a value that possibly overflows and so on. But what i have now is that doesn't seem like ultrasonic sensor is detecting my hand as approaching it because it never goes into the if-condition in the main function...
The 'new' code is that one:
C:
#include <msp430.h>
#include <stdint.h>

uint16_t volatile contador_milisegundos; // miliseconds counter
uint32_t volatile start_time = 0; // start time of ECHO pulse
uint32_t volatile end_time = 0; // end time of ECHO pulse
uint16_t volatile distancia_cm = 0; // distance measured


void Inicializacion_Relojes(void) // to use the SMCLK --> 16 MHz
{
        __bis_SR_register(SCG0); // Disable the FLL control loop
    UCSCTL0 = 0x0000; // Ponemos el DCOx y MODx al minimo posible
    UCSCTL1 = DCORSEL_5; // Seleccionamos un rango de operación del DCO range de 16MHz
    UCSCTL2 = FLLD_0 | 487; // Poniendo FLLD_0 hacemos tomamos como 1 el divisor de la frecuencia de entrada del cristal de cuarzo y 487 es el valor multiplicador de FLLN
    // (N + 1) * (FLLRef/n) = Fdcomsp430
    // (487 + 1) * (32768/1) = 16MHz
    UCSCTL3 = 0; // FLL SELREF = XT1CLK y divisor de FLL = 1 (FLLREFDIV = FLLREFCLK/1)
    UCSCTL4 |= SELA_0 | SELS_4 | SELM_4; // Tomamos ACLK = XT1CLK (Cuarzo externo de 2^15 bits); SMCLK = MCLK = DCOCLKDIV (DCO interno de 16 MHz)
    UCSCTL5 |= DIVA_0 | DIVS_0; // Divisor para SMCLK = f(SMCLK)/1; ACLK = f(ACLK)/1
    __bic_SR_register(SCG0); // Enable the FLL control loop
}

void init_pines_ultrasonidos(void)
{
    P1DIR &= ~BIT1; // Pin ECHO as input
    P1SEL |= BIT1; // mode Capture Input Signal (CCI0A)
    P3DIR |= BIT7; // Pin TRIGGER as output
    P3SEL &= ~BIT7; // Gpio pin
    P3SEL &= ~BIT7; // Pin TRIGGER low
}

void pin_buzzer_and_LED(void) // pin P3.6 as TB0.6 --> P3DIR.6 = 1; P3SEL.6 = 1 (see Table 6-48 Datasheet MSP430F5529)
{
    P3SEL |= BIT6; // P3.6 as alternative function (para Timer TB0.6 según datasheet MSP430F5529)
    P3DIR |= BIT6; // Pin as buzzer output
    P4SEL &= ~BIT7; // Pin GPIO
    P4DIR |= BIT7; // como salida (Led2, verde)
    P4OUT &= ~BIT7; // led inicialmente apagado
}

void delay_ms(uint16_t tiempo_milisegundos) // Function for delay of miliseconds --> SMCLK
{
    contador_milisegundos = 0;
    TA1CTL |= MC_1; // UP MODE
    TA1CCTL0 |= CCIE;
    while(contador_milisegundos < tiempo_milisegundos);
    TA1CTL &= ~MC_3; // stop the timer
}

void delay_us(uint16_t tiempo_microsegundos) // Function for delay of microseconds -- SMCLK a 16 MHz
{
    while(tiempo_microsegundos){
        __delay_cycles(16); // value of16 becuase we working on 16 MHz
        tiempo_microsegundos--;
    }
}

void TimerA0_capture(void) // Timer for capturing ECHO signal of ultrasonic sensor --> TA0.0 en modo Capture Input (CCI0A)
{
    TA0CCTL0 |= CM_3 | SCS | CCIS_0 | CAP | CCIE; // CM_3: Capture both rising and falling edges of signal; CCIS_0: CCIxA --> Capture/Compare in TimerA; CAP: enable capture mode; CCIE: enable interrupciones
    TA0CTL |= TASSEL_2 | MC_2 | ID_0 | TACLR; // TASSEL_2: SMCLK; MC_2: Continuous Mode; ID_0: f(SMCLK)/1; TACLR: Reset Timer
}

void init_TimerA1_ms(void) // for delay
{
    TA1CCR0 = 16000-1; // pulses for 1 milisecond
    TA1CCTL0 |= CCIE;
    TA1CTL |= TASSEL_2 | MC_0; // SMCLK, Freq: 16 MHz; MC_1: Stop Mode
}

void TimerB0_PWM(void) // Timer for monitoring PWM of buzzer
{
    TB0CCR0 = 249; // Período de PWM: 250 pulsos --> 4kHz (o 0,25 ms) --> 1000 pulses/ms · 0,25 ms (inverse of 4kHz) = 250 - 1 = 249.
    TB0CCTL6 |= OUTMOD_7; // Modo CCR6: PWM Reset/Set --> increasing CCR6 value will also increase Duty Cycle --> more buzzer amplitude
    TB0CCR6 = 0; // Duty Cycle inicial: 0 %. TB0.6 --> TB0CCR6.
    TB0CTL |= TASSEL_2 | ID_0 | MC_1 | TACLR; // TASSEL_2: SMCLK; ID_2: Divisor freq --> f(SMCLK)/1; MC_1: Up Mode
}

void main()
{
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
    Inicializacion_Relojes();
    init_pines_ultrasonidos();
    pin_buzzer_and_LED();
    TimerA0_capture();
    init_TimerA1_ms();
    TimerB0_PWM();
    __enable_interrupt();
    while(1){
        P3OUT |= BIT7; // generate pulse TRIGGER
        delay_us(10); // pulse of 10 us in TRIGGER pin for obtaining the measures (see datasheet HC-SR04)
        P3OUT &= ~BIT7; // disable TRIGGER pulse
        delay_ms(100); // delay over 60 ms measurement cycle in order to prevent trigger signal to the echo signal (see Datasheet HC-SR04)
        if(distancia_cm < 20 && distancia_cm != 0){ // if distance between object and the sensor is lower than 20 cm and also different from zero..
            P4OUT |= BIT7; // LED green ON
            TB0CCR6 = 0; // Reset value of Timer that decides the final PWM value
            TB0CCR6 += 249 - (distancia_cm * 12); // Aumentamos la frecuencia del tono del buzzer conforme estamos más cerca del objeto (a menor distancia)
        }
    }
}


#pragma vector=TIMER1_A0_VECTOR
__interrupt void timer1_A0_ISR(void)
{
    contador_milisegundos++;
    TA1CCTL0 &= ~CCIFG;
}

#pragma vector=TIMER0_A0_VECTOR // ISR de Capture Signal TA0.0
__interrupt void Timer0_A0(void)
{
    if(TA0CCTL0 & CCI){ // Read the CCI bit (ECHO signal) --> CCI reflects the state of Captura pin --> ECHO signal
        start_time = TA0CCR0; //takes first time measure in us
    }
    else{
        end_time = TA0CCR0; //takes second time measure in us
        distancia_cm = (end_time - start_time)/58; // to obtain distance in centimeters: (time in us/58) --> (see Datasheet HC-SR04)
    }
    TA0CTL &= ~TAIFG;
}
Moderators note : used code tags AGAIN
 
Last edited by a moderator:

Irving

Joined Jan 30, 2016
3,845
If I read your code right, you're using P1.1 to capture timer0 times at start and end of echo pulse. Do you have a scope and are you seeing an echo pulse?
 

Thread Starter

Alejofnb

Joined Dec 24, 2019
20
If I read your code right, you're using P1.1 to capture timer0 times at start and end of echo pulse. Do you have a scope and are you seeing an echo pulse?
That could be perfect, but unfortunately not. I don't have any scope to see what i get... But thanks for advice!
 

Irving

Joined Jan 30, 2016
3,845
Are you getting any value for distance or is it always 0? Do you know if the timer interrupt is working?

If it's always 0 what you need to do is write some code that tests when P1. 1 changes state the rest of the code is working. Is P1.1 an interrupt, or is timer0 polling it on the timer interrupt? we need to simulate an echo to check your code.

Your code sends a pulse out to trigger the sensor, waits 100mS, and then looks to see if an echo pulse was captured. If you configure another output and connect that to P1.1 you can temporarily replace your 100mS delay with something like:

Delay(50mS)
Pulse High
Delay(10mS) or some suitable time
Pulse Low
Delay(the remaining time)

If your P1.1 input is configured right then you should get a value for distance.
 

mckenney

Joined Nov 10, 2018
125
When I run this code (I enabled the P1.1 pullup) on my Launchpad I get captures from the P1.1 button just fine. You should re-check your wiring.

How do you tell that you aren't getting captures? Do you (not) reach a breakpoint set in the ISR? Or are you relying on the P4.7 LED? You might try connecting the ECHO to the low side of the P1.0 LED jumper (JP8) and standing pretty far away. A 20ms pulse is pretty short, but you might be able to see it, and it's a quick experiment.

Most of the HC-SR04-s I know about are 5V. How are you powering this? Are you using voltage translators to connect to the (3.3V) pins?
 

Irving

Joined Jan 30, 2016
3,845
When I run this code (I enabled the P1.1 pullup) on my Launchpad I get captures from the P1.1 button just fine. You should re-check your wiring.

How do you tell that you aren't getting captures? Do you (not) reach a breakpoint set in the ISR? Or are you relying on the P4.7 LED? You might try connecting the ECHO to the low side of the P1.0 LED jumper (JP8) and standing pretty far away. A 20ms pulse is pretty short, but you might be able to see it, and it's a quick experiment.

Most of the HC-SR04-s I know about are 5V. How are you powering this? Are you using voltage translators to connect to the (3.3V) pins?
So much easier with some hardware in front of you! It's a while since I had a Launchpad, a few projects back now. I suspect this is a hardware problem but verifying it is tricky. Since you've clarified the code works in principle, either there's a hardware problem or the range of values being validated by the if statement in line #95 is wrong...
 

Thread Starter

Alejofnb

Joined Dec 24, 2019
20
When I run this code (I enabled the P1.1 pullup) on my Launchpad I get captures from the P1.1 button just fine. You should re-check your wiring.

How do you tell that you aren't getting captures? Do you (not) reach a breakpoint set in the ISR? Or are you relying on the P4.7 LED? You might try connecting the ECHO to the low side of the P1.0 LED jumper (JP8) and standing pretty far away. A 20ms pulse is pretty short, but you might be able to see it, and it's a quick experiment.

Most of the HC-SR04-s I know about are 5V. How are you powering this? Are you using voltage translators to connect to the (3.3V) pins?
My HW connection is, having the 5V supply voltage on a Launchpad, I set a male-female wire into the (+) connection on protoboard. Vcc pin and ECHO pin of the HC-SR04 are both connected with a 1Kohm resistor in series to (+) on the protoboard. Trigger pin of HC-SR04 is directly connected with a wire to P3.7 on Launchpad and finally both Gnd (The launchpad one and the HC-SR04) are connected. I think my problem could be fixed if I connect both Vcc and ECHO pins to 3.3V of Launchpad instead of 5V.
 

Irving

Joined Jan 30, 2016
3,845
Not sure I understood that, but if I did understand you correctly, the 1k in the Vcc line will stop the HC-SR04 from working. Its a 5v device, requiring 15mA, with 1k inline its getting no volts. Take the resistor out.Drectly connect 5v to HC-SR04 +,

Echo is a TTL output, but the exact voltage is not specified on datasheet. Move the 1k resistor between ECHO and P1.1 , put a 1.8k (or 2 x 1k in series) from P1.1 to ground.
 

Thread Starter

Alejofnb

Joined Dec 24, 2019
20
Not sure I understood that, but if I did understand you correctly, the 1k in the Vcc line will stop the HC-SR04 from working. Its a 5v device, requiring 15mA, with 1k inline its getting no volts. Take the resistor out.Drectly connect 5v to HC-SR04 +,

Echo is a TTL output, but the exact voltage is not specified on datasheet. Move the 1k resistor between ECHO and P1.1 , put a 1.8k (or 2 x 1k in series) from P1.1 to ground.
Thanks for your repply. I've fixed HW issues as i understood in a wrong manner.
 

Thread Starter

Alejofnb

Joined Dec 24, 2019
20
Is it working now?
Not yet, i found that pin P1.1 is a button pin, so i cannot connect any wire through a 1k resistor to ECHO pin and i'va changed to pin P1.2 instead, which also has Capture input signal function. But seems like the program is trapped somewhere in delay function.
 

MrChips

Joined Oct 2, 2009
30,712
If you are trying to debug, program flow will always get trapped in delay function.
That is what delay function does.

Use breakpoints instead, or use a spare pin and output a test pulse.
Oops. Sorry, I forgot that you don't have a scope. In that case, use a spare output pin and flash an LED for 1ms.
 

Irving

Joined Jan 30, 2016
3,845
Or get a cheap usb logic analyzer off eBay, like this.

I bought one a while back and it's surprisingly useful "in the field" when I don't have other tools to hand. It lives in the same pouch as my Fluke87.
 

Thread Starter

Alejofnb

Joined Dec 24, 2019
20
Or get a cheap usb logic analyzer off eBay, like this.

I bought one a while back and it's surprisingly useful "in the field" when I don't have other tools to hand. It lives in the same pouch as my Fluke87.
Wow, thanks! I will take a look. Finally seems like the project is working, at least i get some distance value different from zero. But as i have made a few changes into the code because pin in P1.1 there is a push button and i change the Capture signal input to P1.2 (which also has the capture function). The issue now is that i get distance values that i shouldn't get, like my hand is 30 cm in front of the sensor and the distance value (as i see by debugging) is 140 cm. So i don't know really why this is happening.
 
Top