-2

当检测到距离小于 1m 的物体时,我试图通过简单地打开 LED 来控制这个 HC-SR4 超声波传感器。我使用 TIM2 作为触发信号(引脚 PB10),使用 TIM4 接收回波信号(引脚 PB6)。LED 连接到引脚 PB7。当我加载下面的代码时,LED 只是打开,不管有没有物体,它只是打开。

知道我哪里出错了吗?

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


// switch from HSE to HSI clock 16MHz
void HSI_config(){

RCC->CR |= RCC_CR_HSION; // Turn On HSI oscillator
RCC->CFGR |= RCC_CFGR_SW; // Select HSI clock
RCC->CFGR |= RCC_CFGR_SWS_HSI;
RCC->CR |= RCC_CR_HSIRDY; // wait for HSI stabilize
}

// Configure GPIO Port B
void GPIO_config(){

    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 << (2*6));     // Clear bit 12 & 13 Alternate function mode 
    GPIOB->MODER   |=   0x02 << (2*6);              // set as Alternate function mode 
    GPIOB->OSPEEDR &=   ~(0x03<< (2*6));            // 40 MHz  speed 
    GPIOB->OSPEEDR |=   0x03<< (2*6);               // 40 MHz  speed 
    GPIOB->PUPDR &=         ~(1<<6);                            // NO PULL-UP PULL-DOWN 
    GPIOB->OTYPER &=        ~(1<<6);                            // PUSH-PULL 
    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 TIM4 FOR RECEIVING INPUT SIGNAL
void TIM4_Enable(){
    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->CCER |= TIM_CCER_CC1E;                                // ENABLE COUNTER CAPTURE
    TIM4->DIER |= TIM_DIER_CC1IE;                               // ENABLE CH1 CAPTURE/COMPARE INTERRUPT
    NVIC_SetPriority(TIM4_IRQn, 1);                         // SET PRIORITY TO 1
    NVIC_EnableIRQ(TIM4_IRQn);                                  //ENABLE TIM4 INTERRUPT IN NVIC
}

// CONFIGURE TIM2 FOR SENDING OUTPUT SIGNAL
void TIM2_Enable(){
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;                 // ENABLE TIM2 CLOCK
    TIM2->PSC = 15;                                                         // 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 downcounting counter direction
    TIM2->CR1 |= TIM_CR1_CEN;                                       // Enable Counter
}


    //Initialize the float variables.
    volatile uint8_t timespan = 0;                              // Total pulse width
    volatile uint8_t lastcounter = 0;                           // Timer counter value of the last event
    volatile uint8_t newcounter = 0;                            // Timer counter value of the current event
    volatile uint8_t overflow = 0;                              // Count the number of overflows
    volatile uint8_t PulseEnd = 0;                              // Declare end of pulse

void Echo_TIM4_IRQHandler(){

    if ((TIM4->SR & TIM_SR_UIF) != 0){                  // Check the update even flag
        overflow = overflow + 1;                                    // 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
    PulseEnd = 1;
}

}

void setSysTick(void){
    // ---------- SysTick timer (1ms) -------- //
    if (SysTick_Config(SystemCoreClock / 1000)) {
        // Capture error
        while (1){};
    }
}

    volatile uint32_t msTicks;      //counts 1ms timeTicks
void SysTick_Handler(void) {
    msTicks++;
}

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



    int main(void){

            float Distance = 0.0f;                                              // actual distance in cm
            int Pulsesent = 0;

    HSI_config();
    setSysTick();
    GPIO_config();
    TIM4_Enable();
    Echo_TIM4_IRQHandler();

while(1){

if (Pulsesent == 0) {
    (Pulsesent = 1);
        TIM2_Enable();
}

if(Pulsesent && PulseEnd){
            Pulsesent = 0;

        if(overflow == 1){
                timespan = 0;
            }
            else {
                Distance = (timespan / 58) ;
            }
            Delay(1);
        }   
    if (Distance <= 100){

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

        }   

    }   

}
4

3 回答 3

1

无论变量状态如何,寄存器 GPIOB->BSRRL 只会复位 GPIOB 位为 1。GPIOB->BSRRL 是 32 位寄存器的低 16 位。当位为“1”时,高 16 位将设置 GPIOB 引脚。

因此,要关闭 LED,您需要类似于 GPIOB->BSRRH = (1<<7); 的东西。(但这会让 Barny 感到不安,非常具体,没有便携性,需要了解连接到芯片的硬件......等等)

于 2017-07-21T22:39:20.620 回答
1

您的代码是多么混乱,而不仅仅是您的布局,您使用全局变量的“逻辑”似乎完全是 foobar。我认为你必须付出一些巨大的努力来整理你的代码设计,从经验丰富的嵌入式软件工程师那里获得建议。想一想:这是一小段代码,你无法让它工作,所以用你目前的开发方法,你将如何让复杂的东西工作——你需要改变你的方法。

与您看到的症状直接相关的代码的至少一个问题是,当您直接调用 TIM4 中断处理程序PulseEnd时,您的全局变量之一被设置为副作用- 为什么?main()也许要初始化全局变量?不要这样!- 并且永远不会在此代码中的任何地方重置。

然后,第一次进入while(1)立即设置为 1 的循环PulseSent,测试if (PulseSent && PulseEnd)当然是正确的,并且您的代码立即认为已检测到回声,而timespan可能仍为 0,肯定小于 5800(您除以timespan随机幻数 58 得到Distance,然后与Distance100 进行比较以决定 LED 应亮还是灭)。但是,这不是您唯一的问题,例如timespanauint8_t表示它是一个 8 位变量(类型名称中有提示),只能在 0-255 范围内,但您尝试timespan从两个可能是 16 位的计时器计数器之间的差异,因为您添加了 65536 的可能溢出。所以基本上您的代码总是立即认为有来自小于 100 单位距离的回声,此外距离永远不会超过 255/58(4 位和一点),因此即使回声计时工作得更好,也永远不会超过 100,因此 LED 始终上。

不知道为什么你有代码要处理overflowmain()而且你正在修改 main 和 TIM4 isr 中的溢出这一事实是一个危险信号,有可能出现神秘/瞬态/罕见/不可追踪/致命问题的气味,我注意到当overflow==1(但不是如果溢出> 1,并且不能有效地溢出为 1,因为它正在由 TIM4 中断代码递增?)然后Distance不会重新计算,但随后的代码然后用于Distance点亮/熄灭 LED。这散发出更多的逻辑问题。

newcounter也是lastcounteruint8_t,但计数器是 16 位的,不是吗?值得检查。您是否在启用警告的情况下运行编译器,您应该能够让它告诉您何时必须通过赋值将表达式转换为更具限制性的类型(例如 C192 警告?)。如果你没有打开警告,你应该,你应该注意它们。事实上,打开 -Wall 或任何等效的 keil,并检查每个警告,最好通过更正代码来消除它。如果您无法更改代码以消除奇怪的警告。并确保在每次添加大量代码时检查警告中的更改。当然,最容易看到从零警告到 >0 警告的变化,因此这是(或应该是)消除所有警告的另一个动机。

看不到任何代码似乎可以处理没有回声响应的情况(如果超声波传感器损坏或断开连接也可能发生这种情况)。似乎您的代码(一旦 PulseEnd 问题得到解决)如果没有得到回声,就不会再试一次,不确定。

因为 PulseEnd 永远不会被重置,所以您的代码会尽可能快地向超声波测距仪发送 TIM2 脉冲 - 好吧,被延迟(1)减慢,我猜这是 1 毫秒的延迟 - 所以取决于硬件,不清楚它是否是真的会得到回声响应。如果您查看传感器的输出信号,您会看到。

我已经计算出你的幻数 58 的来源,并假设 TIM4 以 10KHz 的频率运行,空气中的声速为 340m/s,到目标的距离为 1m(因此脉冲必须行进 2m)需要 5.882ms。如果计算必须是整数,则似乎您通过将 58.82 向下舍入到 58 嵌入了 1.4% 的缩放误差(即 1.4 厘米,目标范围为 100 厘米)(但不是因为距离被声明为浮动)那么使用 59 只有 0.3% 的缩放误差,但是你可以很容易地用浮点数进行计算并且误差很小。我猜测存储在 PSC 中的幻数 15 设置了计时器速度。我讨厌神奇的数字。

无论如何,当/如果你真的必须在这样的复杂舞蹈中使用全局变量时,开发一个与其他人坐下来回顾你正在做的事情的过程,并在一些纸上写下变量如何在初始化之间相互作用,main()和中断例程,并严格意识到对其处理的任何更改都意味着您需要坐下来在一张新纸上再次练习该舞蹈,指的是它过去是如何工作的,这在以前的纸上写下. 并尽最大努力开发单元测试,至少让您有一定程度的信心,即在 main() 中更改代码后,它仍然有机会在接近真实硬件之前工作,正如您所发现的那样,可能很难理解实际发生了什么。

于 2017-07-21T08:06:53.243 回答
0

我想分享实际有效的更新代码(不需要库):

#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);

        }   
    }
于 2017-08-12T06:38:05.147 回答