Interfaz HC-SR04 Sensor ultrasónico con STM32L

1

Estoy tratando de controlar este sensor ultrasónico HC-SR4 simplemente ENCENDIENDO un LED cuando se detecta un objeto cercano a 100 cm. Estoy usando TIM2 para la señal de activación (Pin PB10), y TIM4 para recibir la señal de Echo (Pin PB6). y el LED está conectado al Pin PB7. cuando cargo el código a continuación, el LED simplemente se enciende, ya sea que haya un objeto o no, simplemente está ENCENDIDO.

#include <stdio.h>
#include "stm32l1xx.h"                  // Keil::Device:Startup

        //Initialize the timers variables.
    volatile int timespan = 0;      // Total pulse width
    volatile int lastcounter = 0;   // Timer counter value of the last event
    volatile int newcounter = 0;    // Timer counter value of the current event
    volatile int overflow = 0;      // Count the number of overflows

    void SetHSI(void);           
    void Delay(int);
    void GPIO_config(void);
    void TIM2_Trigger(void);
    void TIM4_Init(void);
    void TIM4_Echo_Read(void);
    void LED (void);


        int main(void){

            SetHSI();
            GPIO_config();
            TIM2_Trigger();
            TIM4_Init();


          while(1){

             TIM4_Echo_Read();
             LED();

             Delay(100);
      }
   }

void Delay(int x){
    //input milliseconds, delay that number of milliseconds
    int a,b;
    for(a=0; a<x; a++){
        for(b=0; b<1000; b++){
        }
    }
}

  //set HSI as SystemCoreClock (HSE is not populated on STM32L-Discovery board)//

void SetHSI(void) {

// Turn on HSI (16MHz)
RCC->CR |= RCC_CR_HSION;
// Wait until HSI is ready
while( (RCC->CR & RCC_CR_HSIRDY) == 0);
// Select HSI as system clock
RCC->CFGR &= ~RCC_CFGR_SW_HSI;
RCC->CFGR |= RCC_CFGR_SW_HSI;
while( (RCC->CFGR & RCC_CFGR_SWS)!=RCC_CFGR_SWS_HSI ); // Wait till HSI
}

// Configure GPIO Port B
void GPIO_config(void){

    RCC->AHBRSTR |= RCC_AHBRSTR_GPIOBRST;   // Reset GPIOB clock 
    RCC->AHBRSTR &= ~RCC_AHBRSTR_GPIOBRST;  // Clear Reset 
    RCC->AHBENR |= RCC_AHBENR_GPIOBEN;      // Enable GPIOB clock 

    //PB6 Echo Pin
    GPIOB->MODER   &=   ~(0x03 << 12);    // Clear bit 12 & 13 Alternate function mode 
    GPIOB->MODER   |=   (0x02 << 12);    // set as Alternate function mode 
    GPIOB->OSPEEDR &=   ~(0x03<< 12);   // 40 MHz  speed 
    GPIOB->OSPEEDR |=   (0x03<< 12);    // 40 MHz  speed 
    GPIOB->PUPDR &=         ~(0X3<<12); // NO PULL-UP PULL-DOWN 
    GPIOB->OTYPER &=        ~(1<<6);    // PUSH-PULL 
    GPIOB->AFR[0] &= ~GPIO_AFRL_AFRL6;  // Clear pin 6 for alternate function
    GPIOB->AFR[0] |=        0x2 << (4*6);   // set PB pin 6 as AF2 (TIM4_CH1) 

//PB10 Pluse Generating Pin
    GPIOB->MODER   &=   ~(0x03 << (2*10));  // Clear bit 12 & 13 Alternate function mode 
    GPIOB->MODER   |=   0x02 << (2*10);     // set as Alternate function mode 
    GPIOB->OSPEEDR &=   ~(0x03<< (2*10));   // 40 MHz  speed 
    GPIOB->OSPEEDR |=   0x03<< (2*10);      // 40 MHz  speed 
    GPIOB->PUPDR &=         ~(1<<10);       // NO PULL-UP PULL-DOWN 
    GPIOB->OTYPER &=        ~(1<<10);       // PUSH-PULL 
    GPIOB->AFR[1] |=        0x1 << (4*2);   // set PB pin 10 as AF1 (TIM2_CH3) 

//PB7 LED ON/OFF
    GPIOB->MODER   |=   GPIO_MODER_MODER7_0;   // General purpose output mode
  GPIOB->OSPEEDR |=   GPIO_OSPEEDER_OSPEEDR7;  // Max High speed 50MHz


}

// CONFIGURE TIM2 FOR SENDING OUTPUT SIGNAL
void TIM2_Trigger(void){
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // ENABLE TIM2 CLOCK
    TIM2->PSC = 159;                    // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK
    TIM2->ARR = 0XFFFF;         // SET MAX PULSE WIDTH OF 65536us FOR 16-BIT TIMER

    TIM2->CCMR2 |= TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2; // 111: PWM mode 1 
    TIM2->CCMR2 |= TIM_CCMR2_OC3PE;         // CH3 Output Preload Enable
    TIM2->CR1 |= TIM_CR1_ARPE;              // Auto-reload Prelaod Enable
    TIM2->CCER |= TIM_CCER_CC3E;            // Enable Output for CH3
    TIM2->EGR |= TIM_EGR_UG;                // Force Update
    TIM2->SR &= ~TIM_SR_UIF;                // Clear the Update Flag
    TIM2->DIER |= TIM_DIER_UIE;             // Enable Interrupt on Update
    TIM2->CR1 &= ~TIM_CR1_DIR;              // Set upcounting counter direction
    TIM2->CCR3 &= ~(TIM_CCR3_CCR3);         // Clear CCR3 (Channel 3) 
    TIM2->CCR3 |= 0x1;                      // Load the register 
    TIM2->CR1 |= TIM_CR1_CEN;               // Enable the counter
}


// CONFIGURE TIM4 FOR RECEIVING INPUT SIGNAL
void TIM4_Init(void){
    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;         // ENABLE TIM4 CLOCK
    TIM4->PSC = 15;                             // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK
    TIM4->ARR = 0xFFFF;                         // SET MAX PULSE WIDTH OF 65536us FOR 16-BIT TIMER
    TIM4->CCMR1 &= ~TIM_CCMR1_CC1S;             // CLEAR CAPTURE/COMPARE REGISTER
    TIM4->CCMR1 |= 0X1;                         // SELECT CH1 INPUTE CAPTURE 
    TIM4->CCMR1 &= ~TIM_CCMR1_IC1F;             // DISABLE DIGITAL FILTERING
    TIM4->CCER |= (1<<1 | 1<<3);                // SELECT BOTH RISING AND FALLING EDGE DETECTION CC1P & CC1NP
    TIM4->CCMR1 &= ~(TIM_CCMR1_IC1PSC);         // INPUT PRESCALER 0 TO CAPTURE EACH VALID EDGE
    TIM4->DIER |= TIM_DIER_UIE;                 // UPDATE INTERRUPT ENABLE
    TIM4->CCER |= TIM_CCER_CC1E;                // ENABLE COUNTER CAPTURE
    TIM4->DIER |= TIM_DIER_CC1IE;               // ENABLE CH1 CAPTURE/COMPARE INTERRUPT
    TIM4->CR1 |= TIM_CR1_CEN;                   // Enable the counter
    NVIC_SetPriority(TIM4_IRQn, 1);             // SET PRIORITY TO 1
    NVIC_EnableIRQ(TIM4_IRQn);                  //ENABLE TIM4 INTERRUPT IN NVIC


}

void TIM4_Echo_Read(void){

    if ((TIM4->SR & TIM_SR_UIF) != 0){          // Check the update event flag
        overflow++;                             // if UIF = 1, increment overflow counter
        TIM4->SR &= ~TIM_SR_UIF;                // clear UIF
    }
    if ((TIM4->SR & TIM_SR_CC1IF) != 0){        // Check capture event flag 
    newcounter = TIM4->CCR1;                    // read capture value, store as newcounter
    timespan = (newcounter - lastcounter)+(65536 * overflow); // calculate the total pulse width
    lastcounter = newcounter;                   // save the value of newcounter as lastcounter to be used for the next cycle
    overflow = 0;                               // clear overflow counter
    }

}

void LED (void){

    int Distance;               // actual distance in cm
    Distance = (timespan / 58);

    if (Distance <= 100){

        GPIOB->BSRRL = (1<<7);
    }
        else {
        GPIOB->BSRRH = (1<<7);

        }   
    }

Estos son los resultados cuando ejecuto el depurador:

1 / Newcounter lee el valor CCR1. (por ejemplo, 0X000000000001AD2E), el intervalo de tiempo carga el valor de la ecuación, y la Carga de distancia el valor de la ecuación (intervalo de tiempo / 58).

2 / El valor de Distancia siempre es mucho mayor que 100, incluso si hay un objeto a 50 cm de distancia. En general, los valores no reflejan la condición real.

Sin mencionar que el LED está de forma extraña ENCENDIDO todo el tiempo, aunque los resultados anteriores deberían resultar en un LED APAGADO.

Puedo ver el LED conectado al pin Echo (PB6) parpadeando, lo que creo que significa que se está recibiendo una señal continua.

¿Pensamientos?

P.S Debería haber usado float para Distancia, sin embargo, debido al problema del depurador, lo reemplacé con int, hasta que resolví los problemas mencionados anteriormente.

    
pregunta lightworks

1 respuesta

4

Me gustaría compartir el código actualizado, que realmente funciona (no se necesita una biblioteca):

#include <stdio.h>
#include "stm32l1xx.h"                  // Keil::Device:Startup

        //Initialize the timers variables.
    volatile int timespan = 0;                              // Total pulse width
    volatile int lastcounter = 0;                           // Timer counter value of the last event
    volatile int newcounter = 0;                            // Timer counter value of the current event
    volatile int overflow = 0;                              // Count the number of overflows


    void SysTick_Handler(void);
    void SetHSI(void);
    void LED_GPIO(void);    
    void TIM4_C1_Init(void);
    void TIM2_C3_Init(void);
    void TIM4_IRQHandler(void);
    void LED (void);

        void setSysTick(void){
    // ---------- SysTick timer (1ms) -------- //
    if (SysTick_Config(SystemCoreClock / 1000)) {
    while (1);  // Capture error
    }
}
    volatile uint32_t msTicks=0; //counts 1ms timeTicks 
    void SysTick_Handler(void) {
    msTicks++;
}

static void Delay(__IO uint32_t dlyTicks){ 
  uint32_t curTicks; 
    curTicks = msTicks;
    while ((msTicks - curTicks) < dlyTicks);
}

        int main(void){
          SysTick_Handler();
            setSysTick();
            SetHSI();                             
            LED_GPIO();

            TIM2_C3_Init();
            TIM4_C1_Init();
while(1){

    LED();

Delay(100);
    }
}

/*----------------------------------------------------------------------------
  set HSI as SystemCoreClock (HSE is not populated on STM32L-Discovery board)
 *----------------------------------------------------------------------------*/
void SetHSI(void) {

// Turn on HSI (16MHz)
RCC->CR |= RCC_CR_HSION;
// Wait until HSI is ready
while( (RCC->CR & RCC_CR_HSIRDY) == 0);
// Select HSI as system clock
RCC->CFGR &= ~RCC_CFGR_SW_HSI;
RCC->CFGR |= RCC_CFGR_SW_HSI;
while( (RCC->CFGR & RCC_CFGR_SWS)!=RCC_CFGR_SWS_HSI ); // Wait till HSI
}

// Configure GPIO Port B
void LED_GPIO(void){


    RCC->AHBENR |= RCC_AHBENR_GPIOBEN;        // Enable GPIOB clock 

//PB7 LED ON/OFF
    GPIOB->MODER   |=   GPIO_MODER_MODER7_0;     // General purpose output mode
  GPIOB->OSPEEDR |=   GPIO_OSPEEDER_OSPEEDR7;  // Max High speed 50MHz


}

// CONFIGURE TIM2 FOR SENDING OUTPUT SIGNAL
void TIM2_C3_Init(void){

    RCC->AHBENR |= RCC_AHBENR_GPIOBEN;        // Enable GPIOB clock 

//PB10 Pluse Generating Pin
    GPIOB->MODER   &=   ~(0x03 << (2*10));     // Clear bit 12 & 13 Alternate function mode 
    GPIOB->MODER   |=   0x02 << (2*10);                 // set as Alternate function mode 
    GPIOB->OSPEEDR &=   ~(0x03<< (2*10));           // 40 MHz  speed 
    GPIOB->OSPEEDR |=   0x03<< (2*10);              // 40 MHz  speed 
    GPIOB->PUPDR &=         ~(1<<10);                           // NO PULL-UP PULL-DOWN 
    GPIOB->OTYPER &=        ~(1<<10);                           // PUSH-PULL 
    GPIOB->AFR[1] |=        0x1 << (4*2);                   // set PB pin 10 as AF1 (TIM2_CH3)

    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;                 // ENABLE TIM2 CLOCK
    TIM2->PSC = 159;                                                        // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK
    TIM2->ARR = 0XFFFF;                                                 // SET MAX PULSE WIDTH OF 65536us FOR 16-BIT TIMER
    TIM2->CR1 |= TIM_CR1_DIR;                                       // Set downcounting counter direction
    TIM2->CCMR2 &= ~(TIM_CCMR2_OC3M);                       // Clear OC3M (Channel 3)
  TIM2->CCMR2 |= TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2;
    TIM2->CCMR2 |= TIM_CCMR2_OC3PE;                         // CH3 Output Preload Enable
    TIM2->CR1 |= TIM_CR1_ARPE;                                  // Auto-reload Prelaod Enable
    TIM2->CCER |= TIM_CCER_CC3E;                                // Enable Output for CH3
    TIM2->EGR |= TIM_EGR_UG;                                        // Force Update
    TIM2->SR &= ~TIM_SR_UIF;                                        // Clear the Update Flag
    TIM2->DIER |= TIM_DIER_UIE;                                 // Enable Interrupt on Update
    TIM2->CCR3 &= ~(TIM_CCR3_CCR3);                     // Clear CCR3 (Channel 3) 
    TIM2->CCR3 |= 0x1;                                            // Load the register 
    TIM2->CR1 |= TIM_CR1_CEN;                           // Enable the counter
}


// CONFIGURE TIM4 FOR RECEIVING INPUT SIGNAL
void TIM4_C1_Init(void){
    RCC->AHBENR |= RCC_AHBENR_GPIOBEN;        // Enable GPIOB clock 
    GPIOB->MODER   &=   ~(0x03 << 12);     // Clear bit 12 & 13 Alternate function mode 
    GPIOB->MODER   |=   (0x02 << 12);               // set as Alternate function mode 
    GPIOB->OSPEEDR &=   ~(0x03<< 12);           // 40 MHz  speed 
    GPIOB->OSPEEDR |=   (0x03<< 12);                // 40 MHz  speed 
    GPIOB->PUPDR &=         ~(0X3<<12);                         // NO PULL-UP PULL-DOWN 
    GPIOB->OTYPER &=        ~(1<<6);                            // PUSH-PULL 
    GPIOB->AFR[0] &= ~GPIO_AFRL_AFRL6;  // Clear pin 6 for alternate function
    GPIOB->AFR[0] |=        0x2 << (4*6);                   // set PB pin 6 as AF2 (TIM4_CH1) 

    RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;                 // ENABLE TIM4 CLOCK
    TIM4->PSC = 15;                                     // SET APPROPRAIT PRESCALER TO SLOW DOWN THE CLOCK                                              
    TIM4->CCMR1 &= ~TIM_CCMR1_CC1S;                         // CLEAR CAPTURE/COMPARE REGISTER
    TIM4->CCMR1 |= 0X1;                                                 // SELECT CH1 INPUTE CAPTURE 
    TIM4->CCMR1 &= ~TIM_CCMR1_IC1F;                         // DISABLE DIGITAL FILTERING
    TIM4->CCER |= (1<<1 | 1<<3);                                // SELECT BOTH RISING AND FALLING EDGE DETECTION CC1P & CC1NP
    TIM4->CCMR1 &= ~(TIM_CCMR1_IC1PSC);                 // INPUT PRESCALER 0 TO CAPTURE EACH VALID EDGE
    TIM4->CCER |= TIM_CCER_CC1E;                                // ENABLE COUNTER CAPTURE
    TIM4->DIER |= TIM_DIER_CC1IE;                               // ENABLE CH1 CAPTURE/COMPARE INTERRUPT
    TIM4->DIER |= TIM_DIER_CC1DE;   
    TIM4->DIER |= TIM_DIER_UIE;                                 // UPDATE INTERRUPT ENABLE
    TIM4->CR1 &= ~TIM_CR1_DIR;                                      // Set downcounting counter direction
    TIM4->CR1 |= TIM_CR1_CEN;                                       // Enable the counter
    NVIC_SetPriority(TIM4_IRQn, 1);                         // SET PRIORITY TO 1
    NVIC_EnableIRQ(TIM4_IRQn);                                  //ENABLE TIM4 INTERRUPT IN NVIC


}

void TIM4_IRQHandler(void){

    if ((TIM4->SR & TIM_SR_UIF) != 0){                  // Check the update event flag
        overflow++;                                 // if UIF = 1, increment overflow counter
        TIM4->SR &= ~TIM_SR_UIF;                                    // clear UIF
    }
    if ((TIM4->SR & TIM_SR_CC1IF) != 0){                // Check capture event flag 
    newcounter = TIM4->CCR1;                                        // read capture value, store as newcounter
    timespan = (newcounter - lastcounter)+(65536 * overflow);   // calculate the total pulse width
    lastcounter = newcounter;                               // save the value of newcounter as lastcounter to be used for the next cycle
    overflow = 0;                                                       // clear overflow counter
    }

}

void LED (void){

    float Distance;                                             // actual distance in cm
    Distance = (timespan / 58.0);

    if (Distance > 0.0 && Distance <= 100.0){

        GPIOB->BSRRL = (1<<7);
    }
        else {
        GPIOB->BSRRH = (1<<7);

        }   
    }
    
respondido por el lightworks

Lea otras preguntas en las etiquetas